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