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 "lldb/lldb-python.h" 11 12 #include "CommandObjectSource.h" 13 14 // C Includes 15 // C++ Includes 16 // Other libraries and framework includes 17 // Project includes 18 #include "lldb/Interpreter/Args.h" 19 #include "lldb/Core/Debugger.h" 20 #include "lldb/Core/FileLineResolver.h" 21 #include "lldb/Core/Module.h" 22 #include "lldb/Core/ModuleSpec.h" 23 #include "lldb/Core/SourceManager.h" 24 #include "lldb/Interpreter/CommandInterpreter.h" 25 #include "lldb/Interpreter/CommandReturnObject.h" 26 #include "lldb/Host/FileSpec.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/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 // CommandObjectSourceInfo 40 //------------------------------------------------------------------------- 41 42 class CommandObjectSourceInfo : public CommandObjectParsed 43 { 44 45 class CommandOptions : public Options 46 { 47 public: 48 CommandOptions (CommandInterpreter &interpreter) : 49 Options(interpreter) 50 { 51 } 52 53 ~CommandOptions () 54 { 55 } 56 57 Error 58 SetOptionValue (uint32_t option_idx, const char *option_arg) 59 { 60 Error error; 61 const int short_option = g_option_table[option_idx].short_option; 62 switch (short_option) 63 { 64 case 'l': 65 start_line = Args::StringToUInt32 (option_arg, 0); 66 if (start_line == 0) 67 error.SetErrorStringWithFormat("invalid line number: '%s'", option_arg); 68 break; 69 70 case 'f': 71 file_name = option_arg; 72 break; 73 74 default: 75 error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option); 76 break; 77 } 78 79 return error; 80 } 81 82 void 83 OptionParsingStarting () 84 { 85 file_spec.Clear(); 86 file_name.clear(); 87 start_line = 0; 88 } 89 90 const OptionDefinition* 91 GetDefinitions () 92 { 93 return g_option_table; 94 } 95 static OptionDefinition g_option_table[]; 96 97 // Instance variables to hold the values for command options. 98 FileSpec file_spec; 99 std::string file_name; 100 uint32_t start_line; 101 102 }; 103 104 public: 105 CommandObjectSourceInfo(CommandInterpreter &interpreter) : 106 CommandObjectParsed (interpreter, 107 "source info", 108 "Display information about the source lines from the current executable's debug info.", 109 "source info [<cmd-options>]"), 110 m_options (interpreter) 111 { 112 } 113 114 ~CommandObjectSourceInfo () 115 { 116 } 117 118 119 Options * 120 GetOptions () 121 { 122 return &m_options; 123 } 124 125 protected: 126 bool 127 DoExecute (Args& command, CommandReturnObject &result) 128 { 129 result.AppendError ("Not yet implemented"); 130 result.SetStatus (eReturnStatusFailed); 131 return false; 132 } 133 134 CommandOptions m_options; 135 }; 136 137 OptionDefinition 138 CommandObjectSourceInfo::CommandOptions::g_option_table[] = 139 { 140 { LLDB_OPT_SET_1, false, "line", 'l', required_argument, NULL, 0, eArgTypeLineNum, "The line number at which to start the display source."}, 141 { LLDB_OPT_SET_1, false, "file", 'f', required_argument, NULL, CommandCompletions::eSourceFileCompletion, eArgTypeFilename, "The file from which to display source."}, 142 { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL } 143 }; 144 145 #pragma mark CommandObjectSourceList 146 //------------------------------------------------------------------------- 147 // CommandObjectSourceList 148 //------------------------------------------------------------------------- 149 150 class CommandObjectSourceList : public CommandObjectParsed 151 { 152 153 class CommandOptions : public Options 154 { 155 public: 156 CommandOptions (CommandInterpreter &interpreter) : 157 Options(interpreter) 158 { 159 } 160 161 ~CommandOptions () 162 { 163 } 164 165 Error 166 SetOptionValue (uint32_t option_idx, const char *option_arg) 167 { 168 Error error; 169 const int short_option = g_option_table[option_idx].short_option; 170 switch (short_option) 171 { 172 case 'l': 173 start_line = Args::StringToUInt32 (option_arg, 0); 174 if (start_line == 0) 175 error.SetErrorStringWithFormat("invalid line number: '%s'", option_arg); 176 break; 177 178 case 'c': 179 num_lines = Args::StringToUInt32 (option_arg, 0); 180 if (num_lines == 0) 181 error.SetErrorStringWithFormat("invalid line count: '%s'", option_arg); 182 break; 183 184 case 'f': 185 file_name = option_arg; 186 break; 187 188 case 'n': 189 symbol_name = option_arg; 190 break; 191 192 case 'a': 193 { 194 ExecutionContext exe_ctx (m_interpreter.GetExecutionContext()); 195 address = Args::StringToAddress(&exe_ctx, option_arg, LLDB_INVALID_ADDRESS, &error); 196 } 197 break; 198 case 's': 199 modules.push_back (std::string (option_arg)); 200 break; 201 202 case 'b': 203 show_bp_locs = true; 204 break; 205 case 'r': 206 reverse = true; 207 break; 208 default: 209 error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option); 210 break; 211 } 212 213 return error; 214 } 215 216 void 217 OptionParsingStarting () 218 { 219 file_spec.Clear(); 220 file_name.clear(); 221 symbol_name.clear(); 222 address = LLDB_INVALID_ADDRESS; 223 start_line = 0; 224 num_lines = 0; 225 show_bp_locs = false; 226 reverse = false; 227 modules.clear(); 228 } 229 230 const OptionDefinition* 231 GetDefinitions () 232 { 233 return g_option_table; 234 } 235 static OptionDefinition g_option_table[]; 236 237 // Instance variables to hold the values for command options. 238 FileSpec file_spec; 239 std::string file_name; 240 std::string symbol_name; 241 lldb::addr_t address; 242 uint32_t start_line; 243 uint32_t num_lines; 244 STLStringArray modules; 245 bool show_bp_locs; 246 bool reverse; 247 }; 248 249 public: 250 CommandObjectSourceList(CommandInterpreter &interpreter) : 251 CommandObjectParsed (interpreter, 252 "source list", 253 "Display source code (as specified) based on the current executable's debug info.", 254 NULL, 255 eFlagRequiresTarget), 256 m_options (interpreter) 257 { 258 } 259 260 ~CommandObjectSourceList () 261 { 262 } 263 264 265 Options * 266 GetOptions () 267 { 268 return &m_options; 269 } 270 271 virtual const char * 272 GetRepeatCommand (Args ¤t_command_args, uint32_t index) 273 { 274 // This is kind of gross, but the command hasn't been parsed yet so we can't look at the option 275 // values for this invocation... I have to scan the arguments directly. 276 size_t num_args = current_command_args.GetArgumentCount(); 277 bool is_reverse = false; 278 for (size_t i = 0 ; i < num_args; i++) 279 { 280 const char *arg = current_command_args.GetArgumentAtIndex(i); 281 if (arg && (strcmp(arg, "-r") == 0 || strcmp(arg, "--reverse") == 0)) 282 { 283 is_reverse = true; 284 } 285 } 286 if (is_reverse) 287 { 288 if (m_reverse_name.empty()) 289 { 290 m_reverse_name = m_cmd_name; 291 m_reverse_name.append (" -r"); 292 } 293 return m_reverse_name.c_str(); 294 } 295 else 296 return m_cmd_name.c_str(); 297 } 298 299 protected: 300 301 struct SourceInfo 302 { 303 ConstString function; 304 LineEntry line_entry; 305 306 SourceInfo (const ConstString &name, const LineEntry &line_entry) : 307 function(name), 308 line_entry(line_entry) 309 { 310 } 311 312 SourceInfo () : 313 function(), 314 line_entry() 315 { 316 } 317 318 bool 319 IsValid () const 320 { 321 return (bool)function && line_entry.IsValid(); 322 } 323 324 bool 325 operator == (const SourceInfo &rhs) const 326 { 327 return function == rhs.function && 328 line_entry.file == rhs.line_entry.file && 329 line_entry.line == rhs.line_entry.line; 330 } 331 332 bool 333 operator != (const SourceInfo &rhs) const 334 { 335 return function != rhs.function || 336 line_entry.file != rhs.line_entry.file || 337 line_entry.line != rhs.line_entry.line; 338 } 339 340 bool 341 operator < (const SourceInfo &rhs) const 342 { 343 if (function.GetCString() < rhs.function.GetCString()) 344 return true; 345 if (line_entry.file.GetDirectory().GetCString() < rhs.line_entry.file.GetDirectory().GetCString()) 346 return true; 347 if (line_entry.file.GetFilename().GetCString() < rhs.line_entry.file.GetFilename().GetCString()) 348 return true; 349 if (line_entry.line < rhs.line_entry.line) 350 return true; 351 return false; 352 } 353 }; 354 355 size_t 356 DisplayFunctionSource (const SymbolContext &sc, 357 SourceInfo &source_info, 358 CommandReturnObject &result) 359 { 360 if (!source_info.IsValid()) 361 { 362 source_info.function = sc.GetFunctionName(); 363 source_info.line_entry = sc.GetFunctionStartLineEntry(); 364 } 365 366 if (sc.function) 367 { 368 Target *target = m_exe_ctx.GetTargetPtr(); 369 370 FileSpec start_file; 371 uint32_t start_line; 372 uint32_t end_line; 373 FileSpec end_file; 374 375 if (sc.block == NULL) 376 { 377 // Not an inlined function 378 sc.function->GetStartLineSourceInfo (start_file, start_line); 379 if (start_line == 0) 380 { 381 result.AppendErrorWithFormat("Could not find line information for start of function: \"%s\".\n", source_info.function.GetCString()); 382 result.SetStatus (eReturnStatusFailed); 383 return 0; 384 } 385 sc.function->GetEndLineSourceInfo (end_file, end_line); 386 } 387 else 388 { 389 // We have an inlined function 390 start_file = source_info.line_entry.file; 391 start_line = source_info.line_entry.line; 392 end_line = start_line + m_options.num_lines; 393 } 394 395 // This is a little hacky, but the first line table entry for a function points to the "{" that 396 // starts the function block. It would be nice to actually get the function 397 // declaration in there too. So back up a bit, but not further than what you're going to display. 398 uint32_t extra_lines; 399 if (m_options.num_lines >= 10) 400 extra_lines = 5; 401 else 402 extra_lines = m_options.num_lines/2; 403 uint32_t line_no; 404 if (start_line <= extra_lines) 405 line_no = 1; 406 else 407 line_no = start_line - extra_lines; 408 409 // For fun, if the function is shorter than the number of lines we're supposed to display, 410 // only display the function... 411 if (end_line != 0) 412 { 413 if (m_options.num_lines > end_line - line_no) 414 m_options.num_lines = end_line - line_no + extra_lines; 415 } 416 417 m_breakpoint_locations.Clear(); 418 419 if (m_options.show_bp_locs) 420 { 421 const bool show_inlines = true; 422 m_breakpoint_locations.Reset (start_file, 0, show_inlines); 423 SearchFilter target_search_filter (m_exe_ctx.GetTargetSP()); 424 target_search_filter.Search (m_breakpoint_locations); 425 } 426 427 result.AppendMessageWithFormat("File: %s\n", start_file.GetPath().c_str()); 428 return target->GetSourceManager().DisplaySourceLinesWithLineNumbers (start_file, 429 line_no, 430 0, 431 m_options.num_lines, 432 "", 433 &result.GetOutputStream(), 434 GetBreakpointLocations ()); 435 } 436 else 437 { 438 result.AppendErrorWithFormat("Could not find function info for: \"%s\".\n", m_options.symbol_name.c_str()); 439 } 440 return 0; 441 } 442 443 // From Jim: The FindMatchingFunctions / FindMatchingFunctionSymbols functions 444 // "take a possibly empty vector of strings which are names of modules, and 445 // run the two search functions on the subset of the full module list that 446 // matches the strings in the input vector". If we wanted to put these somewhere, 447 // there should probably be a module-filter-list that can be passed to the 448 // various ModuleList::Find* calls, which would either be a vector of string 449 // names or a ModuleSpecList. 450 size_t FindMatchingFunctions (Target *target, const ConstString &name, SymbolContextList& sc_list) 451 { 452 // Displaying the source for a symbol: 453 bool include_inlines = true; 454 bool append = true; 455 bool include_symbols = false; 456 size_t num_matches = 0; 457 458 if (m_options.num_lines == 0) 459 m_options.num_lines = 10; 460 461 const size_t num_modules = m_options.modules.size(); 462 if (num_modules > 0) 463 { 464 ModuleList matching_modules; 465 for (size_t i = 0; i < num_modules; ++i) 466 { 467 FileSpec module_file_spec(m_options.modules[i].c_str(), false); 468 if (module_file_spec) 469 { 470 ModuleSpec module_spec (module_file_spec); 471 matching_modules.Clear(); 472 target->GetImages().FindModules (module_spec, matching_modules); 473 num_matches += matching_modules.FindFunctions (name, eFunctionNameTypeAuto, include_symbols, include_inlines, append, sc_list); 474 } 475 } 476 } 477 else 478 { 479 num_matches = target->GetImages().FindFunctions (name, eFunctionNameTypeAuto, include_symbols, include_inlines, append, sc_list); 480 } 481 return num_matches; 482 } 483 484 size_t FindMatchingFunctionSymbols (Target *target, const ConstString &name, SymbolContextList& sc_list) 485 { 486 size_t num_matches = 0; 487 const size_t num_modules = m_options.modules.size(); 488 if (num_modules > 0) 489 { 490 ModuleList matching_modules; 491 for (size_t i = 0; i < num_modules; ++i) 492 { 493 FileSpec module_file_spec(m_options.modules[i].c_str(), false); 494 if (module_file_spec) 495 { 496 ModuleSpec module_spec (module_file_spec); 497 matching_modules.Clear(); 498 target->GetImages().FindModules (module_spec, matching_modules); 499 num_matches += matching_modules.FindFunctionSymbols (name, eFunctionNameTypeAuto, sc_list); 500 } 501 } 502 } 503 else 504 { 505 num_matches = target->GetImages().FindFunctionSymbols (name, eFunctionNameTypeAuto, sc_list); 506 } 507 return num_matches; 508 } 509 510 bool 511 DoExecute (Args& command, CommandReturnObject &result) 512 { 513 const size_t argc = command.GetArgumentCount(); 514 515 if (argc != 0) 516 { 517 result.AppendErrorWithFormat("'%s' takes no arguments, only flags.\n", GetCommandName()); 518 result.SetStatus (eReturnStatusFailed); 519 return false; 520 } 521 522 Target *target = m_exe_ctx.GetTargetPtr(); 523 524 if (!m_options.symbol_name.empty()) 525 { 526 SymbolContextList sc_list; 527 ConstString name(m_options.symbol_name.c_str()); 528 529 // Displaying the source for a symbol. Search for function named name. 530 size_t num_matches = FindMatchingFunctions (target, name, sc_list); 531 if (!num_matches) 532 { 533 // If we didn't find any functions with that name, try searching for symbols 534 // that line up exactly with function addresses. 535 SymbolContextList sc_list_symbols; 536 size_t num_symbol_matches = FindMatchingFunctionSymbols (target, name, sc_list_symbols); 537 for (size_t i = 0; i < num_symbol_matches; i++) 538 { 539 SymbolContext sc; 540 sc_list_symbols.GetContextAtIndex (i, sc); 541 if (sc.symbol) 542 { 543 const Address &base_address = sc.symbol->GetAddress(); 544 Function *function = base_address.CalculateSymbolContextFunction(); 545 if (function) 546 { 547 sc_list.Append (SymbolContext(function)); 548 num_matches++; 549 break; 550 } 551 } 552 } 553 } 554 555 if (num_matches == 0) 556 { 557 result.AppendErrorWithFormat("Could not find function named: \"%s\".\n", m_options.symbol_name.c_str()); 558 result.SetStatus (eReturnStatusFailed); 559 return false; 560 } 561 562 if (num_matches > 1) 563 { 564 std::set<SourceInfo> source_match_set; 565 566 bool displayed_something = false; 567 for (size_t i = 0; i < num_matches; i++) 568 { 569 SymbolContext sc; 570 sc_list.GetContextAtIndex (i, sc); 571 SourceInfo source_info (sc.GetFunctionName(), 572 sc.GetFunctionStartLineEntry()); 573 574 if (source_info.IsValid()) 575 { 576 if (source_match_set.find(source_info) == source_match_set.end()) 577 { 578 source_match_set.insert(source_info); 579 if (DisplayFunctionSource (sc, source_info, result)) 580 displayed_something = true; 581 } 582 } 583 } 584 585 if (displayed_something) 586 result.SetStatus (eReturnStatusSuccessFinishResult); 587 else 588 result.SetStatus (eReturnStatusFailed); 589 } 590 else 591 { 592 SymbolContext sc; 593 sc_list.GetContextAtIndex (0, sc); 594 SourceInfo source_info; 595 596 if (DisplayFunctionSource (sc, source_info, result)) 597 { 598 result.SetStatus (eReturnStatusSuccessFinishResult); 599 } 600 else 601 { 602 result.SetStatus (eReturnStatusFailed); 603 } 604 } 605 return result.Succeeded(); 606 } 607 else if (m_options.address != LLDB_INVALID_ADDRESS) 608 { 609 Address so_addr; 610 StreamString error_strm; 611 SymbolContextList sc_list; 612 613 if (target->GetSectionLoadList().IsEmpty()) 614 { 615 // The target isn't loaded yet, we need to lookup the file address 616 // in all modules 617 const ModuleList &module_list = target->GetImages(); 618 const size_t num_modules = module_list.GetSize(); 619 for (size_t i=0; i<num_modules; ++i) 620 { 621 ModuleSP module_sp (module_list.GetModuleAtIndex(i)); 622 if (module_sp && module_sp->ResolveFileAddress(m_options.address, so_addr)) 623 { 624 SymbolContext sc; 625 sc.Clear(true); 626 if (module_sp->ResolveSymbolContextForAddress (so_addr, eSymbolContextEverything, sc) & eSymbolContextLineEntry) 627 sc_list.Append(sc); 628 } 629 } 630 631 if (sc_list.GetSize() == 0) 632 { 633 result.AppendErrorWithFormat("no modules have source information for file address 0x%" PRIx64 ".\n", 634 m_options.address); 635 result.SetStatus (eReturnStatusFailed); 636 return false; 637 } 638 } 639 else 640 { 641 // The target has some things loaded, resolve this address to a 642 // compile unit + file + line and display 643 if (target->GetSectionLoadList().ResolveLoadAddress (m_options.address, so_addr)) 644 { 645 ModuleSP module_sp (so_addr.GetModule()); 646 if (module_sp) 647 { 648 SymbolContext sc; 649 sc.Clear(true); 650 if (module_sp->ResolveSymbolContextForAddress (so_addr, eSymbolContextEverything, sc) & eSymbolContextLineEntry) 651 { 652 sc_list.Append(sc); 653 } 654 else 655 { 656 so_addr.Dump(&error_strm, NULL, Address::DumpStyleModuleWithFileAddress); 657 result.AppendErrorWithFormat("address resolves to %s, but there is no line table information available for this address.\n", 658 error_strm.GetData()); 659 result.SetStatus (eReturnStatusFailed); 660 return false; 661 } 662 } 663 } 664 665 if (sc_list.GetSize() == 0) 666 { 667 result.AppendErrorWithFormat("no modules contain load address 0x%" PRIx64 ".\n", m_options.address); 668 result.SetStatus (eReturnStatusFailed); 669 return false; 670 } 671 } 672 uint32_t num_matches = sc_list.GetSize(); 673 for (uint32_t i=0; i<num_matches; ++i) 674 { 675 SymbolContext sc; 676 sc_list.GetContextAtIndex(i, sc); 677 if (sc.comp_unit) 678 { 679 if (m_options.show_bp_locs) 680 { 681 m_breakpoint_locations.Clear(); 682 const bool show_inlines = true; 683 m_breakpoint_locations.Reset (*sc.comp_unit, 0, show_inlines); 684 SearchFilter target_search_filter (target->shared_from_this()); 685 target_search_filter.Search (m_breakpoint_locations); 686 } 687 688 bool show_fullpaths = true; 689 bool show_module = true; 690 bool show_inlined_frames = true; 691 sc.DumpStopContext(&result.GetOutputStream(), 692 m_exe_ctx.GetBestExecutionContextScope(), 693 sc.line_entry.range.GetBaseAddress(), 694 show_fullpaths, 695 show_module, 696 show_inlined_frames); 697 result.GetOutputStream().EOL(); 698 699 if (m_options.num_lines == 0) 700 m_options.num_lines = 10; 701 702 size_t lines_to_back_up = m_options.num_lines >= 10 ? 5 : m_options.num_lines/2; 703 704 target->GetSourceManager().DisplaySourceLinesWithLineNumbers (sc.comp_unit, 705 sc.line_entry.line, 706 lines_to_back_up, 707 m_options.num_lines - lines_to_back_up, 708 "->", 709 &result.GetOutputStream(), 710 GetBreakpointLocations ()); 711 result.SetStatus (eReturnStatusSuccessFinishResult); 712 } 713 } 714 } 715 else if (m_options.file_name.empty()) 716 { 717 // Last valid source manager context, or the current frame if no 718 // valid last context in source manager. 719 // One little trick here, if you type the exact same list command twice in a row, it is 720 // more likely because you typed it once, then typed it again 721 if (m_options.start_line == 0) 722 { 723 if (target->GetSourceManager().DisplayMoreWithLineNumbers (&result.GetOutputStream(), 724 m_options.num_lines, 725 m_options.reverse, 726 GetBreakpointLocations ())) 727 { 728 result.SetStatus (eReturnStatusSuccessFinishResult); 729 } 730 } 731 else 732 { 733 if (m_options.num_lines == 0) 734 m_options.num_lines = 10; 735 736 if (m_options.show_bp_locs) 737 { 738 SourceManager::FileSP last_file_sp (target->GetSourceManager().GetLastFile ()); 739 if (last_file_sp) 740 { 741 const bool show_inlines = true; 742 m_breakpoint_locations.Reset (last_file_sp->GetFileSpec(), 0, show_inlines); 743 SearchFilter target_search_filter (target->shared_from_this()); 744 target_search_filter.Search (m_breakpoint_locations); 745 } 746 } 747 else 748 m_breakpoint_locations.Clear(); 749 750 if (target->GetSourceManager().DisplaySourceLinesWithLineNumbersUsingLastFile( 751 m_options.start_line, // Line to display 752 m_options.num_lines, // Lines after line to 753 UINT32_MAX, // Don't mark "line" 754 "", // Don't mark "line" 755 &result.GetOutputStream(), 756 GetBreakpointLocations ())) 757 { 758 result.SetStatus (eReturnStatusSuccessFinishResult); 759 } 760 761 } 762 } 763 else 764 { 765 const char *filename = m_options.file_name.c_str(); 766 767 bool check_inlines = false; 768 SymbolContextList sc_list; 769 size_t num_matches = 0; 770 771 if (m_options.modules.size() > 0) 772 { 773 ModuleList matching_modules; 774 for (size_t i = 0, e = m_options.modules.size(); i < e; ++i) 775 { 776 FileSpec module_file_spec(m_options.modules[i].c_str(), false); 777 if (module_file_spec) 778 { 779 ModuleSpec module_spec (module_file_spec); 780 matching_modules.Clear(); 781 target->GetImages().FindModules (module_spec, matching_modules); 782 num_matches += matching_modules.ResolveSymbolContextForFilePath (filename, 783 0, 784 check_inlines, 785 eSymbolContextModule | eSymbolContextCompUnit, 786 sc_list); 787 } 788 } 789 } 790 else 791 { 792 num_matches = target->GetImages().ResolveSymbolContextForFilePath (filename, 793 0, 794 check_inlines, 795 eSymbolContextModule | eSymbolContextCompUnit, 796 sc_list); 797 } 798 799 if (num_matches == 0) 800 { 801 result.AppendErrorWithFormat("Could not find source file \"%s\".\n", 802 m_options.file_name.c_str()); 803 result.SetStatus (eReturnStatusFailed); 804 return false; 805 } 806 807 if (num_matches > 1) 808 { 809 bool got_multiple = false; 810 FileSpec *test_cu_spec = NULL; 811 812 for (unsigned i = 0; i < num_matches; i++) 813 { 814 SymbolContext sc; 815 sc_list.GetContextAtIndex(i, sc); 816 if (sc.comp_unit) 817 { 818 if (test_cu_spec) 819 { 820 if (test_cu_spec != static_cast<FileSpec *> (sc.comp_unit)) 821 got_multiple = true; 822 break; 823 } 824 else 825 test_cu_spec = sc.comp_unit; 826 } 827 } 828 if (got_multiple) 829 { 830 result.AppendErrorWithFormat("Multiple source files found matching: \"%s.\"\n", 831 m_options.file_name.c_str()); 832 result.SetStatus (eReturnStatusFailed); 833 return false; 834 } 835 } 836 837 SymbolContext sc; 838 if (sc_list.GetContextAtIndex(0, sc)) 839 { 840 if (sc.comp_unit) 841 { 842 if (m_options.show_bp_locs) 843 { 844 const bool show_inlines = true; 845 m_breakpoint_locations.Reset (*sc.comp_unit, 0, show_inlines); 846 SearchFilter target_search_filter (target->shared_from_this()); 847 target_search_filter.Search (m_breakpoint_locations); 848 } 849 else 850 m_breakpoint_locations.Clear(); 851 852 if (m_options.num_lines == 0) 853 m_options.num_lines = 10; 854 855 target->GetSourceManager().DisplaySourceLinesWithLineNumbers (sc.comp_unit, 856 m_options.start_line, 857 0, 858 m_options.num_lines, 859 "", 860 &result.GetOutputStream(), 861 GetBreakpointLocations ()); 862 863 result.SetStatus (eReturnStatusSuccessFinishResult); 864 } 865 else 866 { 867 result.AppendErrorWithFormat("No comp unit found for: \"%s.\"\n", 868 m_options.file_name.c_str()); 869 result.SetStatus (eReturnStatusFailed); 870 return false; 871 } 872 } 873 } 874 return result.Succeeded(); 875 } 876 877 const SymbolContextList * 878 GetBreakpointLocations () 879 { 880 if (m_breakpoint_locations.GetFileLineMatches().GetSize() > 0) 881 return &m_breakpoint_locations.GetFileLineMatches(); 882 return NULL; 883 } 884 CommandOptions m_options; 885 FileLineResolver m_breakpoint_locations; 886 std::string m_reverse_name; 887 888 }; 889 890 OptionDefinition 891 CommandObjectSourceList::CommandOptions::g_option_table[] = 892 { 893 { LLDB_OPT_SET_ALL, false, "count", 'c', required_argument, NULL, 0, eArgTypeCount, "The number of source lines to display."}, 894 { LLDB_OPT_SET_1 | 895 LLDB_OPT_SET_2 , false, "shlib", 's', required_argument, NULL, CommandCompletions::eModuleCompletion, eArgTypeShlibName, "Look up the source file in the given shared library."}, 896 { LLDB_OPT_SET_ALL, false, "show-breakpoints", 'b', no_argument, NULL, 0, eArgTypeNone, "Show the line table locations from the debug information that indicate valid places to set source level breakpoints."}, 897 { LLDB_OPT_SET_1 , false, "file", 'f', required_argument, NULL, CommandCompletions::eSourceFileCompletion, eArgTypeFilename, "The file from which to display source."}, 898 { LLDB_OPT_SET_1 , false, "line", 'l', required_argument, NULL, 0, eArgTypeLineNum, "The line number at which to start the display source."}, 899 { LLDB_OPT_SET_2 , false, "name", 'n', required_argument, NULL, CommandCompletions::eSymbolCompletion, eArgTypeSymbol, "The name of a function whose source to display."}, 900 { LLDB_OPT_SET_3 , false, "address",'a', required_argument, NULL, 0, eArgTypeAddressOrExpression, "Lookup the address and display the source information for the corresponding file and line."}, 901 { LLDB_OPT_SET_4, false, "reverse", 'r', no_argument, NULL, 0, eArgTypeNone, "Reverse the listing to look backwards from the last displayed block of source."}, 902 { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL } 903 }; 904 905 #pragma mark CommandObjectMultiwordSource 906 907 //------------------------------------------------------------------------- 908 // CommandObjectMultiwordSource 909 //------------------------------------------------------------------------- 910 911 CommandObjectMultiwordSource::CommandObjectMultiwordSource (CommandInterpreter &interpreter) : 912 CommandObjectMultiword (interpreter, 913 "source", 914 "A set of commands for accessing source file information", 915 "source <subcommand> [<subcommand-options>]") 916 { 917 // "source info" isn't implemented yet... 918 //LoadSubCommand ("info", CommandObjectSP (new CommandObjectSourceInfo (interpreter))); 919 LoadSubCommand ("list", CommandObjectSP (new CommandObjectSourceList (interpreter))); 920 } 921 922 CommandObjectMultiwordSource::~CommandObjectMultiwordSource () 923 { 924 } 925 926