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