1 //===-- SourceManager.cpp ---------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "lldb/Core/SourceManager.h" 11 12 // C Includes 13 // C++ Includes 14 // Other libraries and framework includes 15 // Project includes 16 #include "lldb/Core/DataBuffer.h" 17 #include "lldb/Core/Debugger.h" 18 #include "lldb/Core/Module.h" 19 #include "lldb/Core/RegularExpression.h" 20 #include "lldb/Core/Stream.h" 21 #include "lldb/Symbol/ClangNamespaceDecl.h" 22 #include "lldb/Symbol/CompileUnit.h" 23 #include "lldb/Symbol/Function.h" 24 #include "lldb/Symbol/SymbolContext.h" 25 #include "lldb/Target/Target.h" 26 27 using namespace lldb; 28 using namespace lldb_private; 29 30 31 static inline bool is_newline_char(char ch) 32 { 33 return ch == '\n' || ch == '\r'; 34 } 35 36 37 //---------------------------------------------------------------------- 38 // SourceManager constructor 39 //---------------------------------------------------------------------- 40 SourceManager::SourceManager(const TargetSP &target_sp) : 41 m_last_file_sp (), 42 m_last_line (0), 43 m_last_count (0), 44 m_default_set(false), 45 m_target_wp (target_sp), 46 m_debugger_wp(target_sp->GetDebugger().shared_from_this()) 47 { 48 } 49 50 SourceManager::SourceManager(const DebuggerSP &debugger_sp) : 51 m_last_file_sp (), 52 m_last_line (0), 53 m_last_count (0), 54 m_default_set(false), 55 m_target_wp (), 56 m_debugger_wp (debugger_sp) 57 { 58 } 59 60 //---------------------------------------------------------------------- 61 // Destructor 62 //---------------------------------------------------------------------- 63 SourceManager::~SourceManager() 64 { 65 } 66 67 SourceManager::FileSP 68 SourceManager::GetFile (const FileSpec &file_spec) 69 { 70 bool same_as_previous = m_last_file_sp && m_last_file_sp->FileSpecMatches (file_spec); 71 72 DebuggerSP debugger_sp (m_debugger_wp.lock()); 73 FileSP file_sp; 74 if (same_as_previous) 75 file_sp = m_last_file_sp; 76 else if (debugger_sp) 77 file_sp = debugger_sp->GetSourceFileCache().FindSourceFile (file_spec); 78 79 TargetSP target_sp (m_target_wp.lock()); 80 81 // It the target source path map has been updated, get this file again so we 82 // can successfully remap the source file 83 if (target_sp && file_sp && file_sp->GetSourceMapModificationID() != target_sp->GetSourcePathMap().GetModificationID()) 84 file_sp.reset(); 85 86 // Update the file contents if needed if we found a file 87 if (file_sp) 88 file_sp->UpdateIfNeeded(); 89 90 // If file_sp is no good or it points to a non-existent file, reset it. 91 if (!file_sp || !file_sp->GetFileSpec().Exists()) 92 { 93 file_sp.reset (new File (file_spec, target_sp.get())); 94 95 if (debugger_sp) 96 debugger_sp->GetSourceFileCache().AddSourceFile(file_sp); 97 } 98 return file_sp; 99 } 100 101 size_t 102 SourceManager::DisplaySourceLinesWithLineNumbersUsingLastFile (uint32_t start_line, 103 uint32_t count, 104 uint32_t curr_line, 105 const char* current_line_cstr, 106 Stream *s, 107 const SymbolContextList *bp_locs) 108 { 109 if (count == 0) 110 return 0; 111 size_t return_value = 0; 112 if (start_line == 0) 113 { 114 if (m_last_line != 0 && m_last_line != UINT32_MAX) 115 start_line = m_last_line + m_last_count; 116 else 117 start_line = 1; 118 } 119 120 if (!m_default_set) 121 { 122 FileSpec tmp_spec; 123 uint32_t tmp_line; 124 GetDefaultFileAndLine(tmp_spec, tmp_line); 125 } 126 127 m_last_line = start_line; 128 m_last_count = count; 129 130 if (m_last_file_sp.get()) 131 { 132 const uint32_t end_line = start_line + count - 1; 133 for (uint32_t line = start_line; line <= end_line; ++line) 134 { 135 if (!m_last_file_sp->LineIsValid (line)) 136 { 137 m_last_line = UINT32_MAX; 138 break; 139 } 140 141 char prefix[32] = ""; 142 if (bp_locs) 143 { 144 uint32_t bp_count = bp_locs->NumLineEntriesWithLine (line); 145 146 if (bp_count > 0) 147 ::snprintf (prefix, sizeof (prefix), "[%u] ", bp_count); 148 else 149 ::snprintf (prefix, sizeof (prefix), " "); 150 } 151 152 return_value += s->Printf("%s%2.2s %-4u\t", 153 prefix, 154 line == curr_line ? current_line_cstr : "", 155 line); 156 size_t this_line_size = m_last_file_sp->DisplaySourceLines (line, 0, 0, s); 157 if (this_line_size == 0) 158 { 159 m_last_line = UINT32_MAX; 160 break; 161 } 162 else 163 return_value += this_line_size; 164 } 165 } 166 return return_value; 167 } 168 169 size_t 170 SourceManager::DisplaySourceLinesWithLineNumbers 171 ( 172 const FileSpec &file_spec, 173 uint32_t line, 174 uint32_t context_before, 175 uint32_t context_after, 176 const char* current_line_cstr, 177 Stream *s, 178 const SymbolContextList *bp_locs 179 ) 180 { 181 FileSP file_sp (GetFile (file_spec)); 182 183 uint32_t start_line; 184 uint32_t count = context_before + context_after + 1; 185 if (line > context_before) 186 start_line = line - context_before; 187 else 188 start_line = 1; 189 190 if (m_last_file_sp.get() != file_sp.get()) 191 { 192 if (line == 0) 193 m_last_line = 0; 194 m_last_file_sp = file_sp; 195 } 196 return DisplaySourceLinesWithLineNumbersUsingLastFile (start_line, count, line, current_line_cstr, s, bp_locs); 197 } 198 199 size_t 200 SourceManager::DisplayMoreWithLineNumbers (Stream *s, 201 uint32_t count, 202 bool reverse, 203 const SymbolContextList *bp_locs) 204 { 205 // If we get called before anybody has set a default file and line, then try to figure it out here. 206 const bool have_default_file_line = m_last_file_sp && m_last_line > 0; 207 if (!m_default_set) 208 { 209 FileSpec tmp_spec; 210 uint32_t tmp_line; 211 GetDefaultFileAndLine(tmp_spec, tmp_line); 212 } 213 214 if (m_last_file_sp) 215 { 216 if (m_last_line == UINT32_MAX) 217 return 0; 218 219 if (reverse && m_last_line == 1) 220 return 0; 221 222 if (count > 0) 223 m_last_count = count; 224 else if (m_last_count == 0) 225 m_last_count = 10; 226 227 if (m_last_line > 0) 228 { 229 if (reverse) 230 { 231 // If this is the first time we've done a reverse, then back up one more time so we end 232 // up showing the chunk before the last one we've shown: 233 if (m_last_line > m_last_count) 234 m_last_line -= m_last_count; 235 else 236 m_last_line = 1; 237 } 238 else if (have_default_file_line) 239 m_last_line += m_last_count; 240 } 241 else 242 m_last_line = 1; 243 244 return DisplaySourceLinesWithLineNumbersUsingLastFile (m_last_line, m_last_count, UINT32_MAX, "", s, bp_locs); 245 } 246 return 0; 247 } 248 249 bool 250 SourceManager::SetDefaultFileAndLine (const FileSpec &file_spec, uint32_t line) 251 { 252 FileSP old_file_sp = m_last_file_sp; 253 m_last_file_sp = GetFile (file_spec); 254 255 m_default_set = true; 256 if (m_last_file_sp) 257 { 258 m_last_line = line; 259 return true; 260 } 261 else 262 { 263 m_last_file_sp = old_file_sp; 264 return false; 265 } 266 } 267 268 bool 269 SourceManager::GetDefaultFileAndLine (FileSpec &file_spec, uint32_t &line) 270 { 271 if (m_last_file_sp) 272 { 273 file_spec = m_last_file_sp->GetFileSpec(); 274 line = m_last_line; 275 return true; 276 } 277 else if (!m_default_set) 278 { 279 TargetSP target_sp (m_target_wp.lock()); 280 281 if (target_sp) 282 { 283 // If nobody has set the default file and line then try here. If there's no executable, then we 284 // will try again later when there is one. Otherwise, if we can't find it we won't look again, 285 // somebody will have to set it (for instance when we stop somewhere...) 286 Module *executable_ptr = target_sp->GetExecutableModulePointer(); 287 if (executable_ptr) 288 { 289 SymbolContextList sc_list; 290 ConstString main_name("main"); 291 bool symbols_okay = false; // Force it to be a debug symbol. 292 bool inlines_okay = true; 293 bool append = false; 294 size_t num_matches = executable_ptr->FindFunctions (main_name, 295 NULL, 296 lldb::eFunctionNameTypeBase, 297 inlines_okay, 298 symbols_okay, 299 append, 300 sc_list); 301 for (size_t idx = 0; idx < num_matches; idx++) 302 { 303 SymbolContext sc; 304 sc_list.GetContextAtIndex(idx, sc); 305 if (sc.function) 306 { 307 lldb_private::LineEntry line_entry; 308 if (sc.function->GetAddressRange().GetBaseAddress().CalculateSymbolContextLineEntry (line_entry)) 309 { 310 SetDefaultFileAndLine (line_entry.file, 311 line_entry.line); 312 file_spec = m_last_file_sp->GetFileSpec(); 313 line = m_last_line; 314 return true; 315 } 316 } 317 } 318 } 319 } 320 } 321 return false; 322 } 323 324 void 325 SourceManager::FindLinesMatchingRegex (FileSpec &file_spec, 326 RegularExpression& regex, 327 uint32_t start_line, 328 uint32_t end_line, 329 std::vector<uint32_t> &match_lines) 330 { 331 match_lines.clear(); 332 FileSP file_sp = GetFile (file_spec); 333 if (!file_sp) 334 return; 335 return file_sp->FindLinesMatchingRegex (regex, start_line, end_line, match_lines); 336 } 337 338 SourceManager::File::File(const FileSpec &file_spec, Target *target) : 339 m_file_spec_orig (file_spec), 340 m_file_spec(file_spec), 341 m_mod_time (file_spec.GetModificationTime()), 342 m_source_map_mod_id (0), 343 m_data_sp(), 344 m_offsets() 345 { 346 if (!m_mod_time.IsValid()) 347 { 348 if (target) 349 { 350 m_source_map_mod_id = target->GetSourcePathMap().GetModificationID(); 351 352 if (!file_spec.GetDirectory() && file_spec.GetFilename()) 353 { 354 // If this is just a file name, lets see if we can find it in the target: 355 bool check_inlines = false; 356 SymbolContextList sc_list; 357 size_t num_matches = target->GetImages().ResolveSymbolContextForFilePath (file_spec.GetFilename().AsCString(), 358 0, 359 check_inlines, 360 lldb::eSymbolContextModule | lldb::eSymbolContextCompUnit, 361 sc_list); 362 bool got_multiple = false; 363 if (num_matches != 0) 364 { 365 if (num_matches > 1) 366 { 367 SymbolContext sc; 368 FileSpec *test_cu_spec = NULL; 369 370 for (unsigned i = 0; i < num_matches; i++) 371 { 372 sc_list.GetContextAtIndex(i, sc); 373 if (sc.comp_unit) 374 { 375 if (test_cu_spec) 376 { 377 if (test_cu_spec != static_cast<FileSpec *> (sc.comp_unit)) 378 got_multiple = true; 379 break; 380 } 381 else 382 test_cu_spec = sc.comp_unit; 383 } 384 } 385 } 386 if (!got_multiple) 387 { 388 SymbolContext sc; 389 sc_list.GetContextAtIndex (0, sc); 390 m_file_spec = sc.comp_unit; 391 m_mod_time = m_file_spec.GetModificationTime(); 392 } 393 } 394 } 395 // Try remapping if m_file_spec does not correspond to an existing file. 396 if (!m_file_spec.Exists()) 397 { 398 FileSpec new_file_spec; 399 // Check target specific source remappings first, then fall back to 400 // modules objects can have individual path remappings that were detected 401 // when the debug info for a module was found. 402 // then 403 if (target->GetSourcePathMap().FindFile (m_file_spec, new_file_spec) || 404 target->GetImages().FindSourceFile (m_file_spec, new_file_spec)) 405 { 406 m_file_spec = new_file_spec; 407 m_mod_time = m_file_spec.GetModificationTime(); 408 } 409 } 410 } 411 } 412 413 if (m_mod_time.IsValid()) 414 m_data_sp = m_file_spec.ReadFileContents (); 415 } 416 417 SourceManager::File::~File() 418 { 419 } 420 421 uint32_t 422 SourceManager::File::GetLineOffset (uint32_t line) 423 { 424 if (line == 0) 425 return UINT32_MAX; 426 427 if (line == 1) 428 return 0; 429 430 if (CalculateLineOffsets (line)) 431 { 432 if (line < m_offsets.size()) 433 return m_offsets[line - 1]; // yes we want "line - 1" in the index 434 } 435 return UINT32_MAX; 436 } 437 438 uint32_t 439 SourceManager::File::GetNumLines () 440 { 441 CalculateLineOffsets(); 442 return m_offsets.size(); 443 } 444 445 const char * 446 SourceManager::File::PeekLineData (uint32_t line) 447 { 448 if (!LineIsValid(line)) 449 return NULL; 450 451 size_t line_offset = GetLineOffset (line); 452 if (line_offset < m_data_sp->GetByteSize()) 453 return (const char *)m_data_sp->GetBytes() + line_offset; 454 return NULL; 455 } 456 457 uint32_t 458 SourceManager::File::GetLineLength (uint32_t line, bool include_newline_chars) 459 { 460 if (!LineIsValid(line)) 461 return false; 462 463 size_t start_offset = GetLineOffset (line); 464 size_t end_offset = GetLineOffset (line + 1); 465 if (end_offset == UINT32_MAX) 466 end_offset = m_data_sp->GetByteSize(); 467 468 if (end_offset > start_offset) 469 { 470 uint32_t length = end_offset - start_offset; 471 if (include_newline_chars == false) 472 { 473 const char *line_start = (const char *)m_data_sp->GetBytes() + start_offset; 474 while (length > 0) 475 { 476 const char last_char = line_start[length-1]; 477 if ((last_char == '\r') || (last_char == '\n')) 478 --length; 479 else 480 break; 481 } 482 } 483 return length; 484 } 485 return 0; 486 } 487 488 bool 489 SourceManager::File::LineIsValid (uint32_t line) 490 { 491 if (line == 0) 492 return false; 493 494 if (CalculateLineOffsets (line)) 495 return line < m_offsets.size(); 496 return false; 497 } 498 499 void 500 SourceManager::File::UpdateIfNeeded () 501 { 502 // TODO: use host API to sign up for file modifications to anything in our 503 // source cache and only update when we determine a file has been updated. 504 // For now we check each time we want to display info for the file. 505 TimeValue curr_mod_time (m_file_spec.GetModificationTime()); 506 507 if (curr_mod_time.IsValid() && m_mod_time != curr_mod_time) 508 { 509 m_mod_time = curr_mod_time; 510 m_data_sp = m_file_spec.ReadFileContents (); 511 m_offsets.clear(); 512 } 513 } 514 515 size_t 516 SourceManager::File::DisplaySourceLines (uint32_t line, uint32_t context_before, uint32_t context_after, Stream *s) 517 { 518 // Sanity check m_data_sp before proceeding. 519 if (!m_data_sp) 520 return 0; 521 522 const uint32_t start_line = line <= context_before ? 1 : line - context_before; 523 const uint32_t start_line_offset = GetLineOffset (start_line); 524 if (start_line_offset != UINT32_MAX) 525 { 526 const uint32_t end_line = line + context_after; 527 uint32_t end_line_offset = GetLineOffset (end_line + 1); 528 if (end_line_offset == UINT32_MAX) 529 end_line_offset = m_data_sp->GetByteSize(); 530 531 assert (start_line_offset <= end_line_offset); 532 size_t bytes_written = 0; 533 if (start_line_offset < end_line_offset) 534 { 535 size_t count = end_line_offset - start_line_offset; 536 const uint8_t *cstr = m_data_sp->GetBytes() + start_line_offset; 537 bytes_written = s->Write(cstr, count); 538 if (!is_newline_char(cstr[count-1])) 539 bytes_written += s->EOL(); 540 } 541 return bytes_written; 542 } 543 return 0; 544 } 545 546 void 547 SourceManager::File::FindLinesMatchingRegex (RegularExpression& regex, uint32_t start_line, uint32_t end_line, std::vector<uint32_t> &match_lines) 548 { 549 match_lines.clear(); 550 551 if (!LineIsValid(start_line) || (end_line != UINT32_MAX && !LineIsValid(end_line))) 552 return; 553 if (start_line > end_line) 554 return; 555 556 for (uint32_t line_no = start_line; line_no < end_line; line_no++) 557 { 558 std::string buffer; 559 if (!GetLine (line_no, buffer)) 560 break; 561 if (regex.Execute(buffer.c_str())) 562 { 563 match_lines.push_back(line_no); 564 } 565 } 566 } 567 568 bool 569 SourceManager::File::FileSpecMatches (const FileSpec &file_spec) 570 { 571 return FileSpec::Equal (m_file_spec, file_spec, false); 572 } 573 574 bool 575 lldb_private::operator== (const SourceManager::File &lhs, const SourceManager::File &rhs) 576 { 577 if (lhs.m_file_spec == rhs.m_file_spec) 578 { 579 if (lhs.m_mod_time.IsValid()) 580 { 581 if (rhs.m_mod_time.IsValid()) 582 return lhs.m_mod_time == rhs.m_mod_time; 583 else 584 return false; 585 } 586 else if (rhs.m_mod_time.IsValid()) 587 return false; 588 else 589 return true; 590 } 591 else 592 return false; 593 } 594 595 bool 596 SourceManager::File::CalculateLineOffsets (uint32_t line) 597 { 598 line = UINT32_MAX; // TODO: take this line out when we support partial indexing 599 if (line == UINT32_MAX) 600 { 601 // Already done? 602 if (!m_offsets.empty() && m_offsets[0] == UINT32_MAX) 603 return true; 604 605 if (m_offsets.empty()) 606 { 607 if (m_data_sp.get() == NULL) 608 return false; 609 610 const char *start = (char *)m_data_sp->GetBytes(); 611 if (start) 612 { 613 const char *end = start + m_data_sp->GetByteSize(); 614 615 // Calculate all line offsets from scratch 616 617 // Push a 1 at index zero to indicate the file has been completely indexed. 618 m_offsets.push_back(UINT32_MAX); 619 const char *s; 620 for (s = start; s < end; ++s) 621 { 622 char curr_ch = *s; 623 if (is_newline_char (curr_ch)) 624 { 625 if (s + 1 < end) 626 { 627 char next_ch = s[1]; 628 if (is_newline_char (next_ch)) 629 { 630 if (curr_ch != next_ch) 631 ++s; 632 } 633 } 634 m_offsets.push_back(s + 1 - start); 635 } 636 } 637 if (!m_offsets.empty()) 638 { 639 if (m_offsets.back() < end - start) 640 m_offsets.push_back(end - start); 641 } 642 return true; 643 } 644 } 645 else 646 { 647 // Some lines have been populated, start where we last left off 648 assert("Not implemented yet" == NULL); 649 } 650 651 } 652 else 653 { 654 // Calculate all line offsets up to "line" 655 assert("Not implemented yet" == NULL); 656 } 657 return false; 658 } 659 660 bool 661 SourceManager::File::GetLine (uint32_t line_no, std::string &buffer) 662 { 663 if (!LineIsValid(line_no)) 664 return false; 665 666 size_t start_offset = GetLineOffset (line_no); 667 size_t end_offset = GetLineOffset (line_no + 1); 668 if (end_offset == UINT32_MAX) 669 { 670 end_offset = m_data_sp->GetByteSize(); 671 } 672 buffer.assign((char *) m_data_sp->GetBytes() + start_offset, end_offset - start_offset); 673 674 return true; 675 } 676 677 void 678 SourceManager::SourceFileCache::AddSourceFile (const FileSP &file_sp) 679 { 680 FileSpec file_spec; 681 FileCache::iterator pos = m_file_cache.find(file_spec); 682 if (pos == m_file_cache.end()) 683 m_file_cache[file_spec] = file_sp; 684 else 685 { 686 if (file_sp != pos->second) 687 m_file_cache[file_spec] = file_sp; 688 } 689 } 690 691 SourceManager::FileSP 692 SourceManager::SourceFileCache::FindSourceFile (const FileSpec &file_spec) const 693 { 694 FileSP file_sp; 695 FileCache::const_iterator pos = m_file_cache.find(file_spec); 696 if (pos != m_file_cache.end()) 697 file_sp = pos->second; 698 return file_sp; 699 } 700 701