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