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