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 // If file_sp is no good or it points to a non-existent file, reset it. 87 if (!file_sp || !file_sp->GetFileSpec().Exists()) 88 { 89 file_sp.reset (new File (file_spec, target_sp.get())); 90 91 if (debugger_sp) 92 debugger_sp->GetSourceFileCache().AddSourceFile(file_sp); 93 } 94 return file_sp; 95 } 96 97 size_t 98 SourceManager::DisplaySourceLinesWithLineNumbersUsingLastFile (uint32_t start_line, 99 uint32_t count, 100 uint32_t curr_line, 101 const char* current_line_cstr, 102 Stream *s, 103 const SymbolContextList *bp_locs) 104 { 105 if (count == 0) 106 return 0; 107 size_t return_value = 0; 108 if (start_line == 0) 109 { 110 if (m_last_line != 0 && m_last_line != UINT32_MAX) 111 start_line = m_last_line + m_last_count; 112 else 113 start_line = 1; 114 } 115 116 if (!m_default_set) 117 { 118 FileSpec tmp_spec; 119 uint32_t tmp_line; 120 GetDefaultFileAndLine(tmp_spec, tmp_line); 121 } 122 123 m_last_line = start_line; 124 m_last_count = count; 125 126 if (m_last_file_sp.get()) 127 { 128 const uint32_t end_line = start_line + count - 1; 129 for (uint32_t line = start_line; line <= end_line; ++line) 130 { 131 if (!m_last_file_sp->LineIsValid (line)) 132 { 133 m_last_line = UINT32_MAX; 134 break; 135 } 136 137 char prefix[32] = ""; 138 if (bp_locs) 139 { 140 uint32_t bp_count = bp_locs->NumLineEntriesWithLine (line); 141 142 if (bp_count > 0) 143 ::snprintf (prefix, sizeof (prefix), "[%u] ", bp_count); 144 else 145 ::snprintf (prefix, sizeof (prefix), " "); 146 } 147 148 return_value += s->Printf("%s%2.2s %-4u\t", 149 prefix, 150 line == curr_line ? current_line_cstr : "", 151 line); 152 size_t this_line_size = m_last_file_sp->DisplaySourceLines (line, 0, 0, s); 153 if (this_line_size == 0) 154 { 155 m_last_line = UINT32_MAX; 156 break; 157 } 158 else 159 return_value += this_line_size; 160 } 161 } 162 return return_value; 163 } 164 165 size_t 166 SourceManager::DisplaySourceLinesWithLineNumbers 167 ( 168 const FileSpec &file_spec, 169 uint32_t line, 170 uint32_t context_before, 171 uint32_t context_after, 172 const char* current_line_cstr, 173 Stream *s, 174 const SymbolContextList *bp_locs 175 ) 176 { 177 FileSP file_sp (GetFile (file_spec)); 178 179 uint32_t start_line; 180 uint32_t count = context_before + context_after + 1; 181 if (line > context_before) 182 start_line = line - context_before; 183 else 184 start_line = 1; 185 186 if (m_last_file_sp.get() != file_sp.get()) 187 { 188 if (line == 0) 189 m_last_line = 0; 190 m_last_file_sp = file_sp; 191 } 192 return DisplaySourceLinesWithLineNumbersUsingLastFile (start_line, count, line, current_line_cstr, s, bp_locs); 193 } 194 195 size_t 196 SourceManager::DisplayMoreWithLineNumbers (Stream *s, 197 uint32_t count, 198 bool reverse, 199 const SymbolContextList *bp_locs) 200 { 201 // If we get called before anybody has set a default file and line, then try to figure it out here. 202 const bool have_default_file_line = m_last_file_sp && m_last_line > 0; 203 if (!m_default_set) 204 { 205 FileSpec tmp_spec; 206 uint32_t tmp_line; 207 GetDefaultFileAndLine(tmp_spec, tmp_line); 208 } 209 210 if (m_last_file_sp) 211 { 212 if (m_last_line == UINT32_MAX) 213 return 0; 214 215 if (reverse && m_last_line == 1) 216 return 0; 217 218 if (count > 0) 219 m_last_count = count; 220 else if (m_last_count == 0) 221 m_last_count = 10; 222 223 if (m_last_line > 0) 224 { 225 if (reverse) 226 { 227 // If this is the first time we've done a reverse, then back up one more time so we end 228 // up showing the chunk before the last one we've shown: 229 if (m_last_line > m_last_count) 230 m_last_line -= m_last_count; 231 else 232 m_last_line = 1; 233 } 234 else if (have_default_file_line) 235 m_last_line += m_last_count; 236 } 237 else 238 m_last_line = 1; 239 240 return DisplaySourceLinesWithLineNumbersUsingLastFile (m_last_line, m_last_count, UINT32_MAX, "", s, bp_locs); 241 } 242 return 0; 243 } 244 245 bool 246 SourceManager::SetDefaultFileAndLine (const FileSpec &file_spec, uint32_t line) 247 { 248 FileSP old_file_sp = m_last_file_sp; 249 m_last_file_sp = GetFile (file_spec); 250 251 m_default_set = true; 252 if (m_last_file_sp) 253 { 254 m_last_line = line; 255 return true; 256 } 257 else 258 { 259 m_last_file_sp = old_file_sp; 260 return false; 261 } 262 } 263 264 bool 265 SourceManager::GetDefaultFileAndLine (FileSpec &file_spec, uint32_t &line) 266 { 267 if (m_last_file_sp) 268 { 269 file_spec = m_last_file_sp->GetFileSpec(); 270 line = m_last_line; 271 return true; 272 } 273 else if (!m_default_set) 274 { 275 TargetSP target_sp (m_target_wp.lock()); 276 277 if (target_sp) 278 { 279 // If nobody has set the default file and line then try here. If there's no executable, then we 280 // will try again later when there is one. Otherwise, if we can't find it we won't look again, 281 // somebody will have to set it (for instance when we stop somewhere...) 282 Module *executable_ptr = target_sp->GetExecutableModulePointer(); 283 if (executable_ptr) 284 { 285 SymbolContextList sc_list; 286 ConstString main_name("main"); 287 bool symbols_okay = false; // Force it to be a debug symbol. 288 bool inlines_okay = true; 289 bool append = false; 290 size_t num_matches = executable_ptr->FindFunctions (main_name, 291 NULL, 292 lldb::eFunctionNameTypeBase, 293 inlines_okay, 294 symbols_okay, 295 append, 296 sc_list); 297 for (size_t idx = 0; idx < num_matches; idx++) 298 { 299 SymbolContext sc; 300 sc_list.GetContextAtIndex(idx, sc); 301 if (sc.function) 302 { 303 lldb_private::LineEntry line_entry; 304 if (sc.function->GetAddressRange().GetBaseAddress().CalculateSymbolContextLineEntry (line_entry)) 305 { 306 SetDefaultFileAndLine (line_entry.file, 307 line_entry.line); 308 file_spec = m_last_file_sp->GetFileSpec(); 309 line = m_last_line; 310 return true; 311 } 312 } 313 } 314 } 315 } 316 } 317 return false; 318 } 319 320 void 321 SourceManager::FindLinesMatchingRegex (FileSpec &file_spec, 322 RegularExpression& regex, 323 uint32_t start_line, 324 uint32_t end_line, 325 std::vector<uint32_t> &match_lines) 326 { 327 match_lines.clear(); 328 FileSP file_sp = GetFile (file_spec); 329 if (!file_sp) 330 return; 331 return file_sp->FindLinesMatchingRegex (regex, start_line, end_line, match_lines); 332 } 333 334 SourceManager::File::File(const FileSpec &file_spec, Target *target) : 335 m_file_spec_orig (file_spec), 336 m_file_spec(file_spec), 337 m_mod_time (file_spec.GetModificationTime()), 338 m_source_map_mod_id (0), 339 m_data_sp(), 340 m_offsets() 341 { 342 if (!m_mod_time.IsValid()) 343 { 344 if (target) 345 { 346 m_source_map_mod_id = target->GetSourcePathMap().GetModificationID(); 347 348 if (!file_spec.GetDirectory() && file_spec.GetFilename()) 349 { 350 // If this is just a file name, lets see if we can find it in the target: 351 bool check_inlines = false; 352 SymbolContextList sc_list; 353 size_t num_matches = target->GetImages().ResolveSymbolContextForFilePath (file_spec.GetFilename().AsCString(), 354 0, 355 check_inlines, 356 lldb::eSymbolContextModule | lldb::eSymbolContextCompUnit, 357 sc_list); 358 bool got_multiple = false; 359 if (num_matches != 0) 360 { 361 if (num_matches > 1) 362 { 363 SymbolContext sc; 364 FileSpec *test_cu_spec = NULL; 365 366 for (unsigned i = 0; i < num_matches; i++) 367 { 368 sc_list.GetContextAtIndex(i, sc); 369 if (sc.comp_unit) 370 { 371 if (test_cu_spec) 372 { 373 if (test_cu_spec != static_cast<FileSpec *> (sc.comp_unit)) 374 got_multiple = true; 375 break; 376 } 377 else 378 test_cu_spec = sc.comp_unit; 379 } 380 } 381 } 382 if (!got_multiple) 383 { 384 SymbolContext sc; 385 sc_list.GetContextAtIndex (0, sc); 386 m_file_spec = sc.comp_unit; 387 m_mod_time = m_file_spec.GetModificationTime(); 388 } 389 } 390 } 391 // Try remapping if m_file_spec does not correspond to an existing file. 392 if (!m_file_spec.Exists()) 393 { 394 FileSpec new_file_spec; 395 // Check target specific source remappings first, then fall back to 396 // modules objects can have individual path remappings that were detected 397 // when the debug info for a module was found. 398 // then 399 if (target->GetSourcePathMap().FindFile (m_file_spec, new_file_spec) || 400 target->GetImages().FindSourceFile (m_file_spec, new_file_spec)) 401 { 402 m_file_spec = new_file_spec; 403 m_mod_time = m_file_spec.GetModificationTime(); 404 } 405 } 406 } 407 } 408 409 if (m_mod_time.IsValid()) 410 m_data_sp = m_file_spec.ReadFileContents (); 411 } 412 413 SourceManager::File::~File() 414 { 415 } 416 417 uint32_t 418 SourceManager::File::GetLineOffset (uint32_t line) 419 { 420 if (line == 0) 421 return UINT32_MAX; 422 423 if (line == 1) 424 return 0; 425 426 if (CalculateLineOffsets (line)) 427 { 428 if (line < m_offsets.size()) 429 return m_offsets[line - 1]; // yes we want "line - 1" in the index 430 } 431 return UINT32_MAX; 432 } 433 434 uint32_t 435 SourceManager::File::GetNumLines () 436 { 437 CalculateLineOffsets(); 438 return m_offsets.size(); 439 } 440 441 const char * 442 SourceManager::File::PeekLineData (uint32_t line) 443 { 444 if (!LineIsValid(line)) 445 return NULL; 446 447 size_t line_offset = GetLineOffset (line); 448 if (line_offset < m_data_sp->GetByteSize()) 449 return (const char *)m_data_sp->GetBytes() + line_offset; 450 return NULL; 451 } 452 453 uint32_t 454 SourceManager::File::GetLineLength (uint32_t line, bool include_newline_chars) 455 { 456 if (!LineIsValid(line)) 457 return false; 458 459 size_t start_offset = GetLineOffset (line); 460 size_t end_offset = GetLineOffset (line + 1); 461 if (end_offset == UINT32_MAX) 462 end_offset = m_data_sp->GetByteSize(); 463 464 if (end_offset > start_offset) 465 { 466 uint32_t length = end_offset - start_offset; 467 if (include_newline_chars == false) 468 { 469 const char *line_start = (const char *)m_data_sp->GetBytes() + start_offset; 470 while (length > 0) 471 { 472 const char last_char = line_start[length-1]; 473 if ((last_char == '\r') || (last_char == '\n')) 474 --length; 475 else 476 break; 477 } 478 } 479 return length; 480 } 481 return 0; 482 } 483 484 bool 485 SourceManager::File::LineIsValid (uint32_t line) 486 { 487 if (line == 0) 488 return false; 489 490 if (CalculateLineOffsets (line)) 491 return line < m_offsets.size(); 492 return false; 493 } 494 495 size_t 496 SourceManager::File::DisplaySourceLines (uint32_t line, uint32_t context_before, uint32_t context_after, Stream *s) 497 { 498 // TODO: use host API to sign up for file modifications to anything in our 499 // source cache and only update when we determine a file has been updated. 500 // For now we check each time we want to display info for the file. 501 TimeValue curr_mod_time (m_file_spec.GetModificationTime()); 502 503 if (curr_mod_time.IsValid() && m_mod_time != curr_mod_time) 504 { 505 m_mod_time = curr_mod_time; 506 m_data_sp = m_file_spec.ReadFileContents (); 507 m_offsets.clear(); 508 } 509 510 // Sanity check m_data_sp before proceeding. 511 if (!m_data_sp) 512 return 0; 513 514 const uint32_t start_line = line <= context_before ? 1 : line - context_before; 515 const uint32_t start_line_offset = GetLineOffset (start_line); 516 if (start_line_offset != UINT32_MAX) 517 { 518 const uint32_t end_line = line + context_after; 519 uint32_t end_line_offset = GetLineOffset (end_line + 1); 520 if (end_line_offset == UINT32_MAX) 521 end_line_offset = m_data_sp->GetByteSize(); 522 523 assert (start_line_offset <= end_line_offset); 524 size_t bytes_written = 0; 525 if (start_line_offset < end_line_offset) 526 { 527 size_t count = end_line_offset - start_line_offset; 528 const uint8_t *cstr = m_data_sp->GetBytes() + start_line_offset; 529 bytes_written = s->Write(cstr, count); 530 if (!is_newline_char(cstr[count-1])) 531 bytes_written += s->EOL(); 532 } 533 return bytes_written; 534 } 535 return 0; 536 } 537 538 void 539 SourceManager::File::FindLinesMatchingRegex (RegularExpression& regex, uint32_t start_line, uint32_t end_line, std::vector<uint32_t> &match_lines) 540 { 541 TimeValue curr_mod_time (m_file_spec.GetModificationTime()); 542 if (m_mod_time != curr_mod_time) 543 { 544 m_mod_time = curr_mod_time; 545 m_data_sp = m_file_spec.ReadFileContents (); 546 m_offsets.clear(); 547 } 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