1 //===-- CommandObjectSource.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 "CommandObjectSource.h" 11 12 // C Includes 13 // C++ Includes 14 // Other libraries and framework includes 15 // Project includes 16 #include "lldb/Core/Debugger.h" 17 #include "lldb/Core/FileLineResolver.h" 18 #include "lldb/Core/Module.h" 19 #include "lldb/Core/ModuleSpec.h" 20 #include "lldb/Core/SourceManager.h" 21 #include "lldb/Interpreter/CommandInterpreter.h" 22 #include "lldb/Interpreter/CommandReturnObject.h" 23 #include "lldb/Host/FileSpec.h" 24 #include "lldb/Host/StringConvert.h" 25 #include "lldb/Symbol/CompileUnit.h" 26 #include "lldb/Symbol/Function.h" 27 #include "lldb/Symbol/Symbol.h" 28 #include "lldb/Target/Process.h" 29 #include "lldb/Target/SectionLoadList.h" 30 #include "lldb/Target/StackFrame.h" 31 #include "lldb/Target/TargetList.h" 32 #include "lldb/Interpreter/CommandCompletions.h" 33 #include "lldb/Interpreter/Options.h" 34 35 using namespace lldb; 36 using namespace lldb_private; 37 38 #pragma mark CommandObjectSourceInfo 39 //---------------------------------------------------------------------- 40 // CommandObjectSourceInfo - debug line entries dumping command 41 //---------------------------------------------------------------------- 42 43 class CommandObjectSourceInfo : public CommandObjectParsed 44 { 45 class CommandOptions : public Options 46 { 47 public: 48 CommandOptions (CommandInterpreter &interpreter) : Options(interpreter) {} 49 50 ~CommandOptions() override = default; 51 52 Error 53 SetOptionValue (uint32_t option_idx, const char *option_arg) override 54 { 55 Error error; 56 const int short_option = g_option_table[option_idx].short_option; 57 switch (short_option) 58 { 59 case 'l': 60 start_line = StringConvert::ToUInt32(option_arg, 0); 61 if (start_line == 0) 62 error.SetErrorStringWithFormat("invalid line number: '%s'", option_arg); 63 break; 64 65 case 'e': 66 end_line = StringConvert::ToUInt32(option_arg, 0); 67 if (end_line == 0) 68 error.SetErrorStringWithFormat("invalid line number: '%s'", option_arg); 69 break; 70 71 case 'c': 72 num_lines = StringConvert::ToUInt32(option_arg, 0); 73 if (num_lines == 0) 74 error.SetErrorStringWithFormat("invalid line count: '%s'", option_arg); 75 break; 76 77 case 'f': 78 file_name = option_arg; 79 break; 80 81 case 'n': 82 symbol_name = option_arg; 83 break; 84 85 case 'a': 86 { 87 ExecutionContext exe_ctx(m_interpreter.GetExecutionContext()); 88 address = Args::StringToAddress(&exe_ctx, option_arg, LLDB_INVALID_ADDRESS, &error); 89 } 90 break; 91 case 's': 92 modules.push_back(std::string(option_arg)); 93 break; 94 default: 95 error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option); 96 break; 97 } 98 99 return error; 100 } 101 102 void 103 OptionParsingStarting () override 104 { 105 file_spec.Clear(); 106 file_name.clear(); 107 symbol_name.clear(); 108 address = LLDB_INVALID_ADDRESS; 109 start_line = 0; 110 end_line = 0; 111 num_lines = 0; 112 modules.clear(); 113 } 114 115 const OptionDefinition * 116 GetDefinitions () override 117 { 118 return g_option_table; 119 } 120 121 static OptionDefinition g_option_table[]; 122 123 // Instance variables to hold the values for command options. 124 FileSpec file_spec; 125 std::string file_name; 126 std::string symbol_name; 127 lldb::addr_t address; 128 uint32_t start_line; 129 uint32_t end_line; 130 uint32_t num_lines; 131 STLStringArray modules; 132 }; 133 134 public: 135 CommandObjectSourceInfo(CommandInterpreter &interpreter) 136 : CommandObjectParsed(interpreter, "source info", "Display source line information for the current target " 137 "process. Defaults to instruction pointer in current stack " 138 "frame.", 139 nullptr, eCommandRequiresTarget), 140 m_options(interpreter) 141 { 142 } 143 144 ~CommandObjectSourceInfo() override = default; 145 146 Options * 147 GetOptions () override 148 { 149 return &m_options; 150 } 151 152 protected: 153 // Dump the line entries in each symbol context. 154 // Return the number of entries found. 155 // If module_list is set, only dump lines contained in one of the modules. 156 // If file_spec is set, only dump lines in the file. 157 // If the start_line option was specified, don't print lines less than start_line. 158 // If the end_line option was specified, don't print lines greater than end_line. 159 // If the num_lines option was specified, dont print more than num_lines entries. 160 uint32_t 161 DumpLinesInSymbolContexts (Stream &strm, const SymbolContextList &sc_list, 162 const ModuleList &module_list, const FileSpec &file_spec) 163 { 164 uint32_t start_line = m_options.start_line; 165 uint32_t end_line = m_options.end_line; 166 uint32_t num_lines = m_options.num_lines; 167 Target *target = m_exe_ctx.GetTargetPtr(); 168 169 uint32_t num_matches = 0; 170 bool has_path = false; 171 if (file_spec) 172 { 173 assert(file_spec.GetFilename().AsCString()); 174 has_path = (file_spec.GetDirectory().AsCString() != nullptr); 175 } 176 177 // Dump all the line entries for the file in the list. 178 ConstString last_module_file_name; 179 uint32_t num_scs = sc_list.GetSize(); 180 for (uint32_t i = 0; i < num_scs; ++i) 181 { 182 SymbolContext sc; 183 sc_list.GetContextAtIndex(i, sc); 184 if (sc.comp_unit) 185 { 186 Module *module = sc.module_sp.get(); 187 CompileUnit *cu = sc.comp_unit; 188 const LineEntry &line_entry = sc.line_entry; 189 assert(module && cu); 190 191 // Are we looking for specific modules, files or lines? 192 if (module_list.GetSize() && module_list.GetIndexForModule(module) == LLDB_INVALID_INDEX32) 193 continue; 194 if (file_spec && !lldb_private::FileSpec::Equal(file_spec, line_entry.file, has_path)) 195 continue; 196 if (start_line > 0 && line_entry.line < start_line) 197 continue; 198 if (end_line > 0 && line_entry.line > end_line) 199 continue; 200 if (num_lines > 0 && num_matches > num_lines) 201 continue; 202 203 // Print a new header if the module changed. 204 const ConstString &module_file_name = module->GetFileSpec().GetFilename(); 205 assert(module_file_name); 206 if (module_file_name != last_module_file_name) 207 { 208 if (num_matches > 0) 209 strm << "\n\n"; 210 strm << "Lines found in module `" << module_file_name << "\n"; 211 } 212 // Dump the line entry. 213 line_entry.GetDescription(&strm, lldb::eDescriptionLevelBrief, cu, 214 target, /*show_address_only=*/false); 215 strm << "\n"; 216 last_module_file_name = module_file_name; 217 num_matches++; 218 } 219 } 220 return num_matches; 221 } 222 223 // Dump the requested line entries for the file in the compilation unit. 224 // Return the number of entries found. 225 // If module_list is set, only dump lines contained in one of the modules. 226 // If the start_line option was specified, don't print lines less than start_line. 227 // If the end_line option was specified, don't print lines greater than end_line. 228 // If the num_lines option was specified, dont print more than num_lines entries. 229 uint32_t 230 DumpFileLinesInCompUnit (Stream &strm, Module *module, CompileUnit *cu, const FileSpec &file_spec) 231 { 232 uint32_t start_line = m_options.start_line; 233 uint32_t end_line = m_options.end_line; 234 uint32_t num_lines = m_options.num_lines; 235 Target *target = m_exe_ctx.GetTargetPtr(); 236 237 uint32_t num_matches = 0; 238 assert(module); 239 if (cu) 240 { 241 assert(file_spec.GetFilename().AsCString()); 242 bool has_path = (file_spec.GetDirectory().AsCString() != nullptr); 243 const FileSpecList &cu_file_list = cu->GetSupportFiles(); 244 size_t file_idx = cu_file_list.FindFileIndex(0, file_spec, has_path); 245 if (file_idx != UINT32_MAX) 246 { 247 // Update the file to how it appears in the CU. 248 const FileSpec &cu_file_spec = cu_file_list.GetFileSpecAtIndex(file_idx); 249 250 // Dump all matching lines at or above start_line for the file in the CU. 251 const ConstString &file_spec_name = file_spec.GetFilename(); 252 const ConstString &module_file_name = module->GetFileSpec().GetFilename(); 253 bool cu_header_printed = false; 254 uint32_t line = start_line; 255 while (true) 256 { 257 LineEntry line_entry; 258 259 // Find the lowest index of a line entry with a line equal to 260 // or higher than 'line'. 261 uint32_t start_idx = 0; 262 start_idx = cu->FindLineEntry(start_idx, line, &cu_file_spec, 263 /*exact=*/false, &line_entry); 264 if (start_idx == UINT32_MAX) 265 // No more line entries for our file in this CU. 266 break; 267 268 if (end_line > 0 && line_entry.line > end_line) 269 break; 270 271 // Loop through to find any other entries for this line, dumping each. 272 line = line_entry.line; 273 do 274 { 275 num_matches++; 276 if (num_lines > 0 && num_matches > num_lines) 277 break; 278 assert(lldb_private::FileSpec::Equal(cu_file_spec, line_entry.file, has_path)); 279 if (!cu_header_printed) 280 { 281 if (num_matches > 0) 282 strm << "\n\n"; 283 strm << "Lines found for file " << file_spec_name 284 << " in compilation unit " << cu->GetFilename() 285 << " in `" << module_file_name << "\n"; 286 cu_header_printed = true; 287 } 288 line_entry.GetDescription(&strm, lldb::eDescriptionLevelBrief, cu, 289 target, /*show_address_only=*/false); 290 strm << "\n"; 291 292 // Anymore after this one? 293 start_idx++; 294 start_idx = cu->FindLineEntry(start_idx, line, &cu_file_spec, 295 /*exact=*/true, &line_entry); 296 } while (start_idx != UINT32_MAX); 297 298 // Try the next higher line, starting over at start_idx 0. 299 line++; 300 } 301 } 302 } 303 return num_matches; 304 } 305 306 // Dump the requested line entries for the file in the module. 307 // Return the number of entries found. 308 // If module_list is set, only dump lines contained in one of the modules. 309 // If the start_line option was specified, don't print lines less than start_line. 310 // If the end_line option was specified, don't print lines greater than end_line. 311 // If the num_lines option was specified, dont print more than num_lines entries. 312 uint32_t 313 DumpFileLinesInModule (Stream &strm, Module *module, const FileSpec &file_spec) 314 { 315 uint32_t num_matches = 0; 316 if (module) 317 { 318 // Look through all the compilation units (CUs) in this module for ones that 319 // contain lines of code from this source file. 320 for (size_t i = 0; i < module->GetNumCompileUnits(); i++) 321 { 322 // Look for a matching source file in this CU. 323 CompUnitSP cu_sp(module->GetCompileUnitAtIndex(i)); 324 if (cu_sp) 325 { 326 num_matches += DumpFileLinesInCompUnit(strm, module, cu_sp.get(), file_spec); 327 } 328 } 329 } 330 return num_matches; 331 } 332 333 // Given an address and a list of modules, append the symbol contexts of all line entries 334 // containing the address found in the modules and return the count of matches. If none 335 // is found, return an error in 'error_strm'. 336 size_t 337 GetSymbolContextsForAddress (const ModuleList &module_list, lldb::addr_t addr, 338 SymbolContextList &sc_list, StreamString &error_strm) 339 { 340 Address so_addr; 341 size_t num_matches = 0; 342 assert(module_list.GetSize() > 0); 343 Target *target = m_exe_ctx.GetTargetPtr(); 344 if (target->GetSectionLoadList().IsEmpty()) 345 { 346 // The target isn't loaded yet, we need to lookup the file address in 347 // all modules. Note: the module list option does not apply to addresses. 348 const size_t num_modules = module_list.GetSize(); 349 for (size_t i = 0; i < num_modules; ++i) 350 { 351 ModuleSP module_sp(module_list.GetModuleAtIndex(i)); 352 if (!module_sp) 353 continue; 354 if (module_sp->ResolveFileAddress(addr, so_addr)) 355 { 356 SymbolContext sc; 357 sc.Clear(true); 358 if (module_sp->ResolveSymbolContextForAddress(so_addr, eSymbolContextEverything, sc) & 359 eSymbolContextLineEntry) 360 { 361 sc_list.AppendIfUnique(sc, /*merge_symbol_into_function=*/false); 362 ++num_matches; 363 } 364 } 365 } 366 if (num_matches == 0) 367 error_strm.Printf("Source information for file address 0x%" PRIx64 368 " not found in any modules.\n", addr); 369 } 370 else 371 { 372 // The target has some things loaded, resolve this address to a 373 // compile unit + file + line and display 374 if (target->GetSectionLoadList().ResolveLoadAddress(addr, so_addr)) 375 { 376 ModuleSP module_sp(so_addr.GetModule()); 377 // Check to make sure this module is in our list. 378 if (module_sp && 379 module_list.GetIndexForModule(module_sp.get()) != LLDB_INVALID_INDEX32) 380 { 381 SymbolContext sc; 382 sc.Clear(true); 383 if (module_sp->ResolveSymbolContextForAddress(so_addr, eSymbolContextEverything, sc) & 384 eSymbolContextLineEntry) 385 { 386 sc_list.AppendIfUnique(sc, /*merge_symbol_into_function=*/false); 387 ++num_matches; 388 } 389 else 390 { 391 StreamString addr_strm; 392 so_addr.Dump(&addr_strm, nullptr, Address::DumpStyleModuleWithFileAddress); 393 error_strm.Printf("Address 0x%" PRIx64 " resolves to %s, but there is" 394 " no source information available for this address.\n", 395 addr, addr_strm.GetData()); 396 } 397 } 398 else 399 { 400 StreamString addr_strm; 401 so_addr.Dump(&addr_strm, nullptr, Address::DumpStyleModuleWithFileAddress); 402 error_strm.Printf("Address 0x%" PRIx64 " resolves to %s, but it cannot" 403 " be found in any modules.\n", 404 addr, addr_strm.GetData()); 405 } 406 } 407 else 408 error_strm.Printf("Unable to resolve address 0x%" PRIx64 ".\n", addr); 409 } 410 return num_matches; 411 } 412 413 // Dump the line entries found in functions matching the name specified in the option. 414 bool 415 DumpLinesInFunctions (CommandReturnObject &result) 416 { 417 SymbolContextList sc_list_funcs; 418 ConstString name(m_options.symbol_name.c_str()); 419 SymbolContextList sc_list_lines; 420 Target *target = m_exe_ctx.GetTargetPtr(); 421 uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize(); 422 423 // Note: module_list can't be const& because FindFunctionSymbols isn't const. 424 ModuleList module_list = (m_module_list.GetSize() > 0) ? 425 m_module_list : target->GetImages(); 426 size_t num_matches = module_list.FindFunctions(name, 427 eFunctionNameTypeAuto, 428 /*include_symbols=*/false, 429 /*include_inlines=*/true, 430 /*append=*/true, 431 sc_list_funcs); 432 if (!num_matches) 433 { 434 // If we didn't find any functions with that name, try searching for 435 // symbols that line up exactly with function addresses. 436 SymbolContextList sc_list_symbols; 437 size_t num_symbol_matches = module_list.FindFunctionSymbols(name, 438 eFunctionNameTypeAuto, 439 sc_list_symbols); 440 for (size_t i = 0; i < num_symbol_matches; i++) 441 { 442 SymbolContext sc; 443 sc_list_symbols.GetContextAtIndex(i, sc); 444 if (sc.symbol && sc.symbol->ValueIsAddress()) 445 { 446 const Address &base_address = sc.symbol->GetAddressRef(); 447 Function *function = base_address.CalculateSymbolContextFunction(); 448 if (function) 449 { 450 sc_list_funcs.Append(SymbolContext(function)); 451 num_matches++; 452 } 453 } 454 } 455 } 456 if (num_matches == 0) 457 { 458 result.AppendErrorWithFormat("Could not find function named \'%s\'.\n", 459 m_options.symbol_name.c_str()); 460 return false; 461 } 462 for (size_t i = 0; i < num_matches; i++) 463 { 464 SymbolContext sc; 465 sc_list_funcs.GetContextAtIndex(i, sc); 466 bool context_found_for_symbol = false; 467 // Loop through all the ranges in the function. 468 AddressRange range; 469 for (uint32_t r = 0; 470 sc.GetAddressRange(eSymbolContextEverything, 471 r, 472 /*use_inline_block_range=*/true, 473 range); 474 ++r) 475 { 476 // Append the symbol contexts for each address in the range to sc_list_lines. 477 const Address &base_address = range.GetBaseAddress(); 478 const addr_t size = range.GetByteSize(); 479 lldb::addr_t start_addr = base_address.GetLoadAddress(target); 480 if (start_addr == LLDB_INVALID_ADDRESS) 481 start_addr = base_address.GetFileAddress(); 482 lldb::addr_t end_addr = start_addr + size; 483 for (lldb::addr_t addr = start_addr; addr < end_addr; addr += addr_byte_size) 484 { 485 StreamString error_strm; 486 if (!GetSymbolContextsForAddress(module_list, addr, sc_list_lines, error_strm)) 487 result.AppendWarningWithFormat("in symbol '%s': %s", 488 sc.GetFunctionName().AsCString(), 489 error_strm.GetData()); 490 else 491 context_found_for_symbol = true; 492 } 493 } 494 if (!context_found_for_symbol) 495 result.AppendWarningWithFormat("Unable to find line information" 496 " for matching symbol '%s'.\n", 497 sc.GetFunctionName().AsCString()); 498 } 499 if (sc_list_lines.GetSize() == 0) 500 { 501 result.AppendErrorWithFormat("No line information could be found" 502 " for any symbols matching '%s'.\n", 503 name.AsCString()); 504 return false; 505 } 506 FileSpec file_spec; 507 if (!DumpLinesInSymbolContexts(result.GetOutputStream(), 508 sc_list_lines, module_list, file_spec)) 509 { 510 result.AppendErrorWithFormat("Unable to dump line information for symbol '%s'.\n", 511 name.AsCString()); 512 return false; 513 } 514 return true; 515 } 516 517 // Dump the line entries found for the address specified in the option. 518 bool 519 DumpLinesForAddress (CommandReturnObject &result) 520 { 521 Target *target = m_exe_ctx.GetTargetPtr(); 522 SymbolContextList sc_list; 523 524 StreamString error_strm; 525 if (!GetSymbolContextsForAddress(target->GetImages(), m_options.address, sc_list, error_strm)) 526 { 527 result.AppendErrorWithFormat("%s.\n", error_strm.GetData()); 528 return false; 529 } 530 ModuleList module_list; 531 FileSpec file_spec; 532 if (!DumpLinesInSymbolContexts(result.GetOutputStream(), 533 sc_list, module_list, file_spec)) 534 { 535 result.AppendErrorWithFormat("No modules contain load address 0x%" PRIx64 ".\n", 536 m_options.address); 537 return false; 538 } 539 return true; 540 } 541 542 // Dump the line entries found in the file specified in the option. 543 bool 544 DumpLinesForFile (CommandReturnObject &result) 545 { 546 FileSpec file_spec(m_options.file_name, false); 547 const char *filename = m_options.file_name.c_str(); 548 Target *target = m_exe_ctx.GetTargetPtr(); 549 const ModuleList &module_list = (m_module_list.GetSize() > 0) ? 550 m_module_list : target->GetImages(); 551 552 bool displayed_something = false; 553 const size_t num_modules = module_list.GetSize(); 554 for (uint32_t i = 0; i < num_modules; ++i) 555 { 556 // Dump lines for this module. 557 Module *module = module_list.GetModulePointerAtIndex(i); 558 assert(module); 559 if (DumpFileLinesInModule(result.GetOutputStream(), module, file_spec)) 560 displayed_something = true; 561 } 562 if (!displayed_something) 563 { 564 result.AppendErrorWithFormat("No source filenames matched '%s'.\n", filename); 565 return false; 566 } 567 return true; 568 } 569 570 // Dump the line entries for the current frame. 571 bool 572 DumpLinesForFrame (CommandReturnObject &result) 573 { 574 StackFrame *cur_frame = m_exe_ctx.GetFramePtr(); 575 if (cur_frame == nullptr) 576 { 577 result.AppendError("No selected frame to use to find the default source."); 578 return false; 579 } 580 else if (!cur_frame->HasDebugInformation()) 581 { 582 result.AppendError("No debug info for the selected frame."); 583 return false; 584 } 585 else 586 { 587 const SymbolContext &sc = cur_frame->GetSymbolContext(eSymbolContextLineEntry); 588 SymbolContextList sc_list; 589 sc_list.Append(sc); 590 ModuleList module_list; 591 FileSpec file_spec; 592 if (!DumpLinesInSymbolContexts(result.GetOutputStream(), sc_list, module_list, file_spec)) 593 { 594 result.AppendError("No source line info available for the selected frame."); 595 return false; 596 } 597 } 598 return true; 599 } 600 601 bool 602 DoExecute (Args &command, CommandReturnObject &result) override 603 { 604 const size_t argc = command.GetArgumentCount(); 605 606 if (argc != 0) 607 { 608 result.AppendErrorWithFormat("'%s' takes no arguments, only flags.\n", 609 GetCommandName()); 610 result.SetStatus(eReturnStatusFailed); 611 return false; 612 } 613 614 Target *target = m_exe_ctx.GetTargetPtr(); 615 if (target == nullptr) 616 { 617 target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 618 if (target == nullptr) 619 { 620 result.AppendError("invalid target, create a debug target using the " 621 "'target create' command."); 622 result.SetStatus(eReturnStatusFailed); 623 return false; 624 } 625 } 626 627 uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize(); 628 result.GetOutputStream().SetAddressByteSize(addr_byte_size); 629 result.GetErrorStream().SetAddressByteSize(addr_byte_size); 630 631 // Collect the list of modules to search. 632 m_module_list.Clear(); 633 if (!m_options.modules.empty()) 634 { 635 for (size_t i = 0, e = m_options.modules.size(); i < e; ++i) 636 { 637 FileSpec module_file_spec(m_options.modules[i].c_str(), false); 638 if (module_file_spec) 639 { 640 ModuleSpec module_spec(module_file_spec); 641 if (target->GetImages().FindModules(module_spec, m_module_list) == 0) 642 result.AppendWarningWithFormat("No module found for '%s'.\n", 643 m_options.modules[i].c_str()); 644 } 645 } 646 if (!m_module_list.GetSize()) 647 { 648 result.AppendError("No modules match the input."); 649 result.SetStatus(eReturnStatusFailed); 650 return false; 651 } 652 } 653 else if (target->GetImages().GetSize() == 0) 654 { 655 result.AppendError("The target has no associated executable images."); 656 result.SetStatus(eReturnStatusFailed); 657 return false; 658 } 659 660 // Check the arguments to see what lines we should dump. 661 if (!m_options.symbol_name.empty()) 662 { 663 // Print lines for symbol. 664 if (DumpLinesInFunctions(result)) 665 result.SetStatus(eReturnStatusSuccessFinishResult); 666 else 667 result.SetStatus(eReturnStatusFailed); 668 } 669 else if (m_options.address != LLDB_INVALID_ADDRESS) 670 { 671 // Print lines for an address. 672 if (DumpLinesForAddress(result)) 673 result.SetStatus(eReturnStatusSuccessFinishResult); 674 else 675 result.SetStatus(eReturnStatusFailed); 676 } 677 else if (!m_options.file_name.empty()) 678 { 679 // Dump lines for a file. 680 if (DumpLinesForFile(result)) 681 result.SetStatus(eReturnStatusSuccessFinishResult); 682 else 683 result.SetStatus(eReturnStatusFailed); 684 } 685 else 686 { 687 // Dump the line for the current frame. 688 if (DumpLinesForFrame(result)) 689 result.SetStatus(eReturnStatusSuccessFinishResult); 690 else 691 result.SetStatus(eReturnStatusFailed); 692 } 693 return result.Succeeded(); 694 } 695 696 CommandOptions m_options; 697 ModuleList m_module_list; 698 }; 699 700 OptionDefinition CommandObjectSourceInfo::CommandOptions::g_option_table[] = { 701 {LLDB_OPT_SET_ALL, false, "count", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeCount, 702 "The number of line entries to display."}, 703 {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "shlib", 's', OptionParser::eRequiredArgument, nullptr, nullptr, 704 CommandCompletions::eModuleCompletion, eArgTypeShlibName, 705 "Look up the source in the given module or shared library (can be " 706 "specified more than once)."}, 707 {LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, nullptr, nullptr, 708 CommandCompletions::eSourceFileCompletion, eArgTypeFilename, "The file from which to display source."}, 709 {LLDB_OPT_SET_1, false, "line", 'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeLineNum, 710 "The line number at which to start the displaying lines."}, 711 {LLDB_OPT_SET_1, false, "end-line", 'e', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeLineNum, 712 "The line number at which to stop displaying lines."}, 713 {LLDB_OPT_SET_2, false, "name", 'n', OptionParser::eRequiredArgument, nullptr, nullptr, 714 CommandCompletions::eSymbolCompletion, eArgTypeSymbol, "The name of a function whose source to display."}, 715 {LLDB_OPT_SET_3, false, "address", 'a', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeAddressOrExpression, 716 "Lookup the address and display the source information for the " 717 "corresponding file and line."}, 718 {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr} 719 }; 720 721 #pragma mark CommandObjectSourceList 722 //------------------------------------------------------------------------- 723 // CommandObjectSourceList 724 //------------------------------------------------------------------------- 725 726 class CommandObjectSourceList : public CommandObjectParsed 727 { 728 class CommandOptions : public Options 729 { 730 public: 731 CommandOptions (CommandInterpreter &interpreter) : 732 Options(interpreter) 733 { 734 } 735 736 ~CommandOptions() override = default; 737 738 Error 739 SetOptionValue (uint32_t option_idx, const char *option_arg) override 740 { 741 Error error; 742 const int short_option = g_option_table[option_idx].short_option; 743 switch (short_option) 744 { 745 case 'l': 746 start_line = StringConvert::ToUInt32 (option_arg, 0); 747 if (start_line == 0) 748 error.SetErrorStringWithFormat("invalid line number: '%s'", option_arg); 749 break; 750 751 case 'c': 752 num_lines = StringConvert::ToUInt32 (option_arg, 0); 753 if (num_lines == 0) 754 error.SetErrorStringWithFormat("invalid line count: '%s'", option_arg); 755 break; 756 757 case 'f': 758 file_name = option_arg; 759 break; 760 761 case 'n': 762 symbol_name = option_arg; 763 break; 764 765 case 'a': 766 { 767 ExecutionContext exe_ctx (m_interpreter.GetExecutionContext()); 768 address = Args::StringToAddress(&exe_ctx, option_arg, LLDB_INVALID_ADDRESS, &error); 769 } 770 break; 771 case 's': 772 modules.push_back (std::string (option_arg)); 773 break; 774 775 case 'b': 776 show_bp_locs = true; 777 break; 778 case 'r': 779 reverse = true; 780 break; 781 default: 782 error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option); 783 break; 784 } 785 786 return error; 787 } 788 789 void 790 OptionParsingStarting () override 791 { 792 file_spec.Clear(); 793 file_name.clear(); 794 symbol_name.clear(); 795 address = LLDB_INVALID_ADDRESS; 796 start_line = 0; 797 num_lines = 0; 798 show_bp_locs = false; 799 reverse = false; 800 modules.clear(); 801 } 802 803 const OptionDefinition* 804 GetDefinitions () override 805 { 806 return g_option_table; 807 } 808 809 static OptionDefinition g_option_table[]; 810 811 // Instance variables to hold the values for command options. 812 FileSpec file_spec; 813 std::string file_name; 814 std::string symbol_name; 815 lldb::addr_t address; 816 uint32_t start_line; 817 uint32_t num_lines; 818 STLStringArray modules; 819 bool show_bp_locs; 820 bool reverse; 821 }; 822 823 public: 824 CommandObjectSourceList(CommandInterpreter &interpreter) 825 : CommandObjectParsed(interpreter, "source list", 826 "Display source code for the current target process as specified by options.", nullptr, 827 eCommandRequiresTarget), 828 m_options(interpreter) 829 { 830 } 831 832 ~CommandObjectSourceList() override = default; 833 834 Options * 835 GetOptions () override 836 { 837 return &m_options; 838 } 839 840 const char * 841 GetRepeatCommand (Args ¤t_command_args, uint32_t index) override 842 { 843 // This is kind of gross, but the command hasn't been parsed yet so we can't look at the option 844 // values for this invocation... I have to scan the arguments directly. 845 size_t num_args = current_command_args.GetArgumentCount(); 846 bool is_reverse = false; 847 for (size_t i = 0; i < num_args; i++) 848 { 849 const char *arg = current_command_args.GetArgumentAtIndex(i); 850 if (arg && (strcmp(arg, "-r") == 0 || strcmp(arg, "--reverse") == 0)) 851 { 852 is_reverse = true; 853 } 854 } 855 if (is_reverse) 856 { 857 if (m_reverse_name.empty()) 858 { 859 m_reverse_name = m_cmd_name; 860 m_reverse_name.append (" -r"); 861 } 862 return m_reverse_name.c_str(); 863 } 864 else 865 return m_cmd_name.c_str(); 866 } 867 868 protected: 869 struct SourceInfo 870 { 871 ConstString function; 872 LineEntry line_entry; 873 874 SourceInfo (const ConstString &name, const LineEntry &line_entry) : 875 function(name), 876 line_entry(line_entry) 877 { 878 } 879 880 SourceInfo () : 881 function(), 882 line_entry() 883 { 884 } 885 886 bool 887 IsValid () const 888 { 889 return (bool)function && line_entry.IsValid(); 890 } 891 892 bool 893 operator == (const SourceInfo &rhs) const 894 { 895 return function == rhs.function && 896 line_entry.original_file == rhs.line_entry.original_file && 897 line_entry.line == rhs.line_entry.line; 898 } 899 900 bool 901 operator != (const SourceInfo &rhs) const 902 { 903 return function != rhs.function || 904 line_entry.original_file != rhs.line_entry.original_file || 905 line_entry.line != rhs.line_entry.line; 906 } 907 908 bool 909 operator < (const SourceInfo &rhs) const 910 { 911 if (function.GetCString() < rhs.function.GetCString()) 912 return true; 913 if (line_entry.file.GetDirectory().GetCString() < rhs.line_entry.file.GetDirectory().GetCString()) 914 return true; 915 if (line_entry.file.GetFilename().GetCString() < rhs.line_entry.file.GetFilename().GetCString()) 916 return true; 917 if (line_entry.line < rhs.line_entry.line) 918 return true; 919 return false; 920 } 921 }; 922 923 size_t 924 DisplayFunctionSource (const SymbolContext &sc, 925 SourceInfo &source_info, 926 CommandReturnObject &result) 927 { 928 if (!source_info.IsValid()) 929 { 930 source_info.function = sc.GetFunctionName(); 931 source_info.line_entry = sc.GetFunctionStartLineEntry(); 932 } 933 934 if (sc.function) 935 { 936 Target *target = m_exe_ctx.GetTargetPtr(); 937 938 FileSpec start_file; 939 uint32_t start_line; 940 uint32_t end_line; 941 FileSpec end_file; 942 943 if (sc.block == nullptr) 944 { 945 // Not an inlined function 946 sc.function->GetStartLineSourceInfo (start_file, start_line); 947 if (start_line == 0) 948 { 949 result.AppendErrorWithFormat("Could not find line information for start of function: \"%s\".\n", source_info.function.GetCString()); 950 result.SetStatus (eReturnStatusFailed); 951 return 0; 952 } 953 sc.function->GetEndLineSourceInfo (end_file, end_line); 954 } 955 else 956 { 957 // We have an inlined function 958 start_file = source_info.line_entry.file; 959 start_line = source_info.line_entry.line; 960 end_line = start_line + m_options.num_lines; 961 } 962 963 // This is a little hacky, but the first line table entry for a function points to the "{" that 964 // starts the function block. It would be nice to actually get the function 965 // declaration in there too. So back up a bit, but not further than what you're going to display. 966 uint32_t extra_lines; 967 if (m_options.num_lines >= 10) 968 extra_lines = 5; 969 else 970 extra_lines = m_options.num_lines/2; 971 uint32_t line_no; 972 if (start_line <= extra_lines) 973 line_no = 1; 974 else 975 line_no = start_line - extra_lines; 976 977 // For fun, if the function is shorter than the number of lines we're supposed to display, 978 // only display the function... 979 if (end_line != 0) 980 { 981 if (m_options.num_lines > end_line - line_no) 982 m_options.num_lines = end_line - line_no + extra_lines; 983 } 984 985 m_breakpoint_locations.Clear(); 986 987 if (m_options.show_bp_locs) 988 { 989 const bool show_inlines = true; 990 m_breakpoint_locations.Reset (start_file, 0, show_inlines); 991 SearchFilterForUnconstrainedSearches target_search_filter (m_exe_ctx.GetTargetSP()); 992 target_search_filter.Search (m_breakpoint_locations); 993 } 994 995 result.AppendMessageWithFormat("File: %s\n", start_file.GetPath().c_str()); 996 return target->GetSourceManager().DisplaySourceLinesWithLineNumbers (start_file, 997 line_no, 998 0, 999 m_options.num_lines, 1000 "", 1001 &result.GetOutputStream(), 1002 GetBreakpointLocations ()); 1003 } 1004 else 1005 { 1006 result.AppendErrorWithFormat("Could not find function info for: \"%s\".\n", m_options.symbol_name.c_str()); 1007 } 1008 return 0; 1009 } 1010 1011 // From Jim: The FindMatchingFunctions / FindMatchingFunctionSymbols functions 1012 // "take a possibly empty vector of strings which are names of modules, and 1013 // run the two search functions on the subset of the full module list that 1014 // matches the strings in the input vector". If we wanted to put these somewhere, 1015 // there should probably be a module-filter-list that can be passed to the 1016 // various ModuleList::Find* calls, which would either be a vector of string 1017 // names or a ModuleSpecList. 1018 size_t FindMatchingFunctions (Target *target, const ConstString &name, SymbolContextList& sc_list) 1019 { 1020 // Displaying the source for a symbol: 1021 bool include_inlines = true; 1022 bool append = true; 1023 bool include_symbols = false; 1024 size_t num_matches = 0; 1025 1026 if (m_options.num_lines == 0) 1027 m_options.num_lines = 10; 1028 1029 const size_t num_modules = m_options.modules.size(); 1030 if (num_modules > 0) 1031 { 1032 ModuleList matching_modules; 1033 for (size_t i = 0; i < num_modules; ++i) 1034 { 1035 FileSpec module_file_spec(m_options.modules[i].c_str(), false); 1036 if (module_file_spec) 1037 { 1038 ModuleSpec module_spec (module_file_spec); 1039 matching_modules.Clear(); 1040 target->GetImages().FindModules (module_spec, matching_modules); 1041 num_matches += matching_modules.FindFunctions (name, eFunctionNameTypeAuto, include_symbols, include_inlines, append, sc_list); 1042 } 1043 } 1044 } 1045 else 1046 { 1047 num_matches = target->GetImages().FindFunctions (name, eFunctionNameTypeAuto, include_symbols, include_inlines, append, sc_list); 1048 } 1049 return num_matches; 1050 } 1051 1052 size_t FindMatchingFunctionSymbols (Target *target, const ConstString &name, SymbolContextList& sc_list) 1053 { 1054 size_t num_matches = 0; 1055 const size_t num_modules = m_options.modules.size(); 1056 if (num_modules > 0) 1057 { 1058 ModuleList matching_modules; 1059 for (size_t i = 0; i < num_modules; ++i) 1060 { 1061 FileSpec module_file_spec(m_options.modules[i].c_str(), false); 1062 if (module_file_spec) 1063 { 1064 ModuleSpec module_spec (module_file_spec); 1065 matching_modules.Clear(); 1066 target->GetImages().FindModules (module_spec, matching_modules); 1067 num_matches += matching_modules.FindFunctionSymbols (name, eFunctionNameTypeAuto, sc_list); 1068 } 1069 } 1070 } 1071 else 1072 { 1073 num_matches = target->GetImages().FindFunctionSymbols (name, eFunctionNameTypeAuto, sc_list); 1074 } 1075 return num_matches; 1076 } 1077 1078 bool 1079 DoExecute (Args& command, CommandReturnObject &result) override 1080 { 1081 const size_t argc = command.GetArgumentCount(); 1082 1083 if (argc != 0) 1084 { 1085 result.AppendErrorWithFormat("'%s' takes no arguments, only flags.\n", GetCommandName()); 1086 result.SetStatus (eReturnStatusFailed); 1087 return false; 1088 } 1089 1090 Target *target = m_exe_ctx.GetTargetPtr(); 1091 1092 if (!m_options.symbol_name.empty()) 1093 { 1094 SymbolContextList sc_list; 1095 ConstString name(m_options.symbol_name.c_str()); 1096 1097 // Displaying the source for a symbol. Search for function named name. 1098 size_t num_matches = FindMatchingFunctions (target, name, sc_list); 1099 if (!num_matches) 1100 { 1101 // If we didn't find any functions with that name, try searching for symbols 1102 // that line up exactly with function addresses. 1103 SymbolContextList sc_list_symbols; 1104 size_t num_symbol_matches = FindMatchingFunctionSymbols (target, name, sc_list_symbols); 1105 for (size_t i = 0; i < num_symbol_matches; i++) 1106 { 1107 SymbolContext sc; 1108 sc_list_symbols.GetContextAtIndex (i, sc); 1109 if (sc.symbol && sc.symbol->ValueIsAddress()) 1110 { 1111 const Address &base_address = sc.symbol->GetAddressRef(); 1112 Function *function = base_address.CalculateSymbolContextFunction(); 1113 if (function) 1114 { 1115 sc_list.Append (SymbolContext(function)); 1116 num_matches++; 1117 break; 1118 } 1119 } 1120 } 1121 } 1122 1123 if (num_matches == 0) 1124 { 1125 result.AppendErrorWithFormat("Could not find function named: \"%s\".\n", m_options.symbol_name.c_str()); 1126 result.SetStatus (eReturnStatusFailed); 1127 return false; 1128 } 1129 1130 if (num_matches > 1) 1131 { 1132 std::set<SourceInfo> source_match_set; 1133 1134 bool displayed_something = false; 1135 for (size_t i = 0; i < num_matches; i++) 1136 { 1137 SymbolContext sc; 1138 sc_list.GetContextAtIndex (i, sc); 1139 SourceInfo source_info (sc.GetFunctionName(), 1140 sc.GetFunctionStartLineEntry()); 1141 1142 if (source_info.IsValid()) 1143 { 1144 if (source_match_set.find(source_info) == source_match_set.end()) 1145 { 1146 source_match_set.insert(source_info); 1147 if (DisplayFunctionSource (sc, source_info, result)) 1148 displayed_something = true; 1149 } 1150 } 1151 } 1152 1153 if (displayed_something) 1154 result.SetStatus (eReturnStatusSuccessFinishResult); 1155 else 1156 result.SetStatus (eReturnStatusFailed); 1157 } 1158 else 1159 { 1160 SymbolContext sc; 1161 sc_list.GetContextAtIndex (0, sc); 1162 SourceInfo source_info; 1163 1164 if (DisplayFunctionSource (sc, source_info, result)) 1165 { 1166 result.SetStatus (eReturnStatusSuccessFinishResult); 1167 } 1168 else 1169 { 1170 result.SetStatus (eReturnStatusFailed); 1171 } 1172 } 1173 return result.Succeeded(); 1174 } 1175 else if (m_options.address != LLDB_INVALID_ADDRESS) 1176 { 1177 Address so_addr; 1178 StreamString error_strm; 1179 SymbolContextList sc_list; 1180 1181 if (target->GetSectionLoadList().IsEmpty()) 1182 { 1183 // The target isn't loaded yet, we need to lookup the file address 1184 // in all modules 1185 const ModuleList &module_list = target->GetImages(); 1186 const size_t num_modules = module_list.GetSize(); 1187 for (size_t i = 0; i < num_modules; ++i) 1188 { 1189 ModuleSP module_sp (module_list.GetModuleAtIndex(i)); 1190 if (module_sp && module_sp->ResolveFileAddress(m_options.address, so_addr)) 1191 { 1192 SymbolContext sc; 1193 sc.Clear(true); 1194 if (module_sp->ResolveSymbolContextForAddress (so_addr, eSymbolContextEverything, sc) & eSymbolContextLineEntry) 1195 sc_list.Append(sc); 1196 } 1197 } 1198 1199 if (sc_list.GetSize() == 0) 1200 { 1201 result.AppendErrorWithFormat("no modules have source information for file address 0x%" PRIx64 ".\n", 1202 m_options.address); 1203 result.SetStatus (eReturnStatusFailed); 1204 return false; 1205 } 1206 } 1207 else 1208 { 1209 // The target has some things loaded, resolve this address to a 1210 // compile unit + file + line and display 1211 if (target->GetSectionLoadList().ResolveLoadAddress (m_options.address, so_addr)) 1212 { 1213 ModuleSP module_sp (so_addr.GetModule()); 1214 if (module_sp) 1215 { 1216 SymbolContext sc; 1217 sc.Clear(true); 1218 if (module_sp->ResolveSymbolContextForAddress (so_addr, eSymbolContextEverything, sc) & eSymbolContextLineEntry) 1219 { 1220 sc_list.Append(sc); 1221 } 1222 else 1223 { 1224 so_addr.Dump(&error_strm, nullptr, Address::DumpStyleModuleWithFileAddress); 1225 result.AppendErrorWithFormat("address resolves to %s, but there is no line table information available for this address.\n", 1226 error_strm.GetData()); 1227 result.SetStatus (eReturnStatusFailed); 1228 return false; 1229 } 1230 } 1231 } 1232 1233 if (sc_list.GetSize() == 0) 1234 { 1235 result.AppendErrorWithFormat("no modules contain load address 0x%" PRIx64 ".\n", m_options.address); 1236 result.SetStatus (eReturnStatusFailed); 1237 return false; 1238 } 1239 } 1240 uint32_t num_matches = sc_list.GetSize(); 1241 for (uint32_t i = 0; i < num_matches; ++i) 1242 { 1243 SymbolContext sc; 1244 sc_list.GetContextAtIndex(i, sc); 1245 if (sc.comp_unit) 1246 { 1247 if (m_options.show_bp_locs) 1248 { 1249 m_breakpoint_locations.Clear(); 1250 const bool show_inlines = true; 1251 m_breakpoint_locations.Reset (*sc.comp_unit, 0, show_inlines); 1252 SearchFilterForUnconstrainedSearches target_search_filter (target->shared_from_this()); 1253 target_search_filter.Search (m_breakpoint_locations); 1254 } 1255 1256 bool show_fullpaths = true; 1257 bool show_module = true; 1258 bool show_inlined_frames = true; 1259 const bool show_function_arguments = true; 1260 const bool show_function_name = true; 1261 sc.DumpStopContext(&result.GetOutputStream(), 1262 m_exe_ctx.GetBestExecutionContextScope(), 1263 sc.line_entry.range.GetBaseAddress(), 1264 show_fullpaths, 1265 show_module, 1266 show_inlined_frames, 1267 show_function_arguments, 1268 show_function_name); 1269 result.GetOutputStream().EOL(); 1270 1271 if (m_options.num_lines == 0) 1272 m_options.num_lines = 10; 1273 1274 size_t lines_to_back_up = m_options.num_lines >= 10 ? 5 : m_options.num_lines/2; 1275 1276 target->GetSourceManager().DisplaySourceLinesWithLineNumbers (sc.comp_unit, 1277 sc.line_entry.line, 1278 lines_to_back_up, 1279 m_options.num_lines - lines_to_back_up, 1280 "->", 1281 &result.GetOutputStream(), 1282 GetBreakpointLocations ()); 1283 result.SetStatus (eReturnStatusSuccessFinishResult); 1284 } 1285 } 1286 } 1287 else if (m_options.file_name.empty()) 1288 { 1289 // Last valid source manager context, or the current frame if no 1290 // valid last context in source manager. 1291 // One little trick here, if you type the exact same list command twice in a row, it is 1292 // more likely because you typed it once, then typed it again 1293 if (m_options.start_line == 0) 1294 { 1295 if (target->GetSourceManager().DisplayMoreWithLineNumbers (&result.GetOutputStream(), 1296 m_options.num_lines, 1297 m_options.reverse, 1298 GetBreakpointLocations ())) 1299 { 1300 result.SetStatus (eReturnStatusSuccessFinishResult); 1301 } 1302 } 1303 else 1304 { 1305 if (m_options.num_lines == 0) 1306 m_options.num_lines = 10; 1307 1308 if (m_options.show_bp_locs) 1309 { 1310 SourceManager::FileSP last_file_sp (target->GetSourceManager().GetLastFile ()); 1311 if (last_file_sp) 1312 { 1313 const bool show_inlines = true; 1314 m_breakpoint_locations.Reset (last_file_sp->GetFileSpec(), 0, show_inlines); 1315 SearchFilterForUnconstrainedSearches target_search_filter (target->shared_from_this()); 1316 target_search_filter.Search (m_breakpoint_locations); 1317 } 1318 } 1319 else 1320 m_breakpoint_locations.Clear(); 1321 1322 if (target->GetSourceManager().DisplaySourceLinesWithLineNumbersUsingLastFile( 1323 m_options.start_line, // Line to display 1324 m_options.num_lines, // Lines after line to 1325 UINT32_MAX, // Don't mark "line" 1326 "", // Don't mark "line" 1327 &result.GetOutputStream(), 1328 GetBreakpointLocations ())) 1329 { 1330 result.SetStatus (eReturnStatusSuccessFinishResult); 1331 } 1332 } 1333 } 1334 else 1335 { 1336 const char *filename = m_options.file_name.c_str(); 1337 1338 bool check_inlines = false; 1339 SymbolContextList sc_list; 1340 size_t num_matches = 0; 1341 1342 if (!m_options.modules.empty()) 1343 { 1344 ModuleList matching_modules; 1345 for (size_t i = 0, e = m_options.modules.size(); i < e; ++i) 1346 { 1347 FileSpec module_file_spec(m_options.modules[i].c_str(), false); 1348 if (module_file_spec) 1349 { 1350 ModuleSpec module_spec (module_file_spec); 1351 matching_modules.Clear(); 1352 target->GetImages().FindModules (module_spec, matching_modules); 1353 num_matches += matching_modules.ResolveSymbolContextForFilePath (filename, 1354 0, 1355 check_inlines, 1356 eSymbolContextModule | eSymbolContextCompUnit, 1357 sc_list); 1358 } 1359 } 1360 } 1361 else 1362 { 1363 num_matches = target->GetImages().ResolveSymbolContextForFilePath (filename, 1364 0, 1365 check_inlines, 1366 eSymbolContextModule | eSymbolContextCompUnit, 1367 sc_list); 1368 } 1369 1370 if (num_matches == 0) 1371 { 1372 result.AppendErrorWithFormat("Could not find source file \"%s\".\n", 1373 m_options.file_name.c_str()); 1374 result.SetStatus (eReturnStatusFailed); 1375 return false; 1376 } 1377 1378 if (num_matches > 1) 1379 { 1380 bool got_multiple = false; 1381 FileSpec *test_cu_spec = nullptr; 1382 1383 for (unsigned i = 0; i < num_matches; i++) 1384 { 1385 SymbolContext sc; 1386 sc_list.GetContextAtIndex(i, sc); 1387 if (sc.comp_unit) 1388 { 1389 if (test_cu_spec) 1390 { 1391 if (test_cu_spec != static_cast<FileSpec *> (sc.comp_unit)) 1392 got_multiple = true; 1393 break; 1394 } 1395 else 1396 test_cu_spec = sc.comp_unit; 1397 } 1398 } 1399 if (got_multiple) 1400 { 1401 result.AppendErrorWithFormat("Multiple source files found matching: \"%s.\"\n", 1402 m_options.file_name.c_str()); 1403 result.SetStatus (eReturnStatusFailed); 1404 return false; 1405 } 1406 } 1407 1408 SymbolContext sc; 1409 if (sc_list.GetContextAtIndex(0, sc)) 1410 { 1411 if (sc.comp_unit) 1412 { 1413 if (m_options.show_bp_locs) 1414 { 1415 const bool show_inlines = true; 1416 m_breakpoint_locations.Reset (*sc.comp_unit, 0, show_inlines); 1417 SearchFilterForUnconstrainedSearches target_search_filter (target->shared_from_this()); 1418 target_search_filter.Search (m_breakpoint_locations); 1419 } 1420 else 1421 m_breakpoint_locations.Clear(); 1422 1423 if (m_options.num_lines == 0) 1424 m_options.num_lines = 10; 1425 1426 target->GetSourceManager().DisplaySourceLinesWithLineNumbers (sc.comp_unit, 1427 m_options.start_line, 1428 0, 1429 m_options.num_lines, 1430 "", 1431 &result.GetOutputStream(), 1432 GetBreakpointLocations ()); 1433 1434 result.SetStatus (eReturnStatusSuccessFinishResult); 1435 } 1436 else 1437 { 1438 result.AppendErrorWithFormat("No comp unit found for: \"%s.\"\n", 1439 m_options.file_name.c_str()); 1440 result.SetStatus (eReturnStatusFailed); 1441 return false; 1442 } 1443 } 1444 } 1445 return result.Succeeded(); 1446 } 1447 1448 const SymbolContextList * 1449 GetBreakpointLocations () 1450 { 1451 if (m_breakpoint_locations.GetFileLineMatches().GetSize() > 0) 1452 return &m_breakpoint_locations.GetFileLineMatches(); 1453 return nullptr; 1454 } 1455 1456 CommandOptions m_options; 1457 FileLineResolver m_breakpoint_locations; 1458 std::string m_reverse_name; 1459 }; 1460 1461 OptionDefinition 1462 CommandObjectSourceList::CommandOptions::g_option_table[] = 1463 { 1464 { LLDB_OPT_SET_ALL, false, "count", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeCount, "The number of source lines to display."}, 1465 { LLDB_OPT_SET_1 | 1466 LLDB_OPT_SET_2 , false, "shlib", 's', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eModuleCompletion, eArgTypeShlibName, "Look up the source file in the given shared library."}, 1467 { LLDB_OPT_SET_ALL, false, "show-breakpoints", 'b', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Show the line table locations from the debug information that indicate valid places to set source level breakpoints."}, 1468 { LLDB_OPT_SET_1 , false, "file", 'f', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eSourceFileCompletion, eArgTypeFilename, "The file from which to display source."}, 1469 { LLDB_OPT_SET_1 , false, "line", 'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeLineNum, "The line number at which to start the display source."}, 1470 { LLDB_OPT_SET_2 , false, "name", 'n', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eSymbolCompletion, eArgTypeSymbol, "The name of a function whose source to display."}, 1471 { LLDB_OPT_SET_3 , false, "address",'a', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeAddressOrExpression, "Lookup the address and display the source information for the corresponding file and line."}, 1472 { LLDB_OPT_SET_4, false, "reverse", 'r', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Reverse the listing to look backwards from the last displayed block of source."}, 1473 { 0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr } 1474 }; 1475 1476 #pragma mark CommandObjectMultiwordSource 1477 //------------------------------------------------------------------------- 1478 // CommandObjectMultiwordSource 1479 //------------------------------------------------------------------------- 1480 1481 CommandObjectMultiwordSource::CommandObjectMultiwordSource(CommandInterpreter &interpreter) 1482 : CommandObjectMultiword( 1483 interpreter, "source", 1484 "Commands for examining source code described by debug information for the current target process.", 1485 "source <subcommand> [<subcommand-options>]") 1486 { 1487 LoadSubCommand ("info", CommandObjectSP (new CommandObjectSourceInfo (interpreter))); 1488 LoadSubCommand ("list", CommandObjectSP (new CommandObjectSourceList (interpreter))); 1489 } 1490 1491 CommandObjectMultiwordSource::~CommandObjectMultiwordSource() = default; 1492