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