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