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