CommandObjectSource.cpp revision 269024
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/SectionLoadList.h" 32#include "lldb/Target/TargetList.h" 33#include "lldb/Interpreter/CommandCompletions.h" 34#include "lldb/Interpreter/Options.h" 35 36using namespace lldb; 37using namespace lldb_private; 38 39//------------------------------------------------------------------------- 40// CommandObjectSourceInfo 41//------------------------------------------------------------------------- 42 43class 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 = Args::StringToUInt32 (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 105public: 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 126protected: 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 138OptionDefinition 139CommandObjectSourceInfo::CommandOptions::g_option_table[] = 140{ 141{ LLDB_OPT_SET_1, false, "line", 'l', OptionParser::eRequiredArgument, NULL, 0, eArgTypeLineNum, "The line number at which to start the display source."}, 142{ LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, NULL, CommandCompletions::eSourceFileCompletion, eArgTypeFilename, "The file from which to display source."}, 143{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL } 144}; 145 146#pragma mark CommandObjectSourceList 147//------------------------------------------------------------------------- 148// CommandObjectSourceList 149//------------------------------------------------------------------------- 150 151class 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 = Args::StringToUInt32 (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 = Args::StringToUInt32 (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 250public: 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 300protected: 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 SearchFilter 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 SearchFilter 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 sc.DumpStopContext(&result.GetOutputStream(), 693 m_exe_ctx.GetBestExecutionContextScope(), 694 sc.line_entry.range.GetBaseAddress(), 695 show_fullpaths, 696 show_module, 697 show_inlined_frames); 698 result.GetOutputStream().EOL(); 699 700 if (m_options.num_lines == 0) 701 m_options.num_lines = 10; 702 703 size_t lines_to_back_up = m_options.num_lines >= 10 ? 5 : m_options.num_lines/2; 704 705 target->GetSourceManager().DisplaySourceLinesWithLineNumbers (sc.comp_unit, 706 sc.line_entry.line, 707 lines_to_back_up, 708 m_options.num_lines - lines_to_back_up, 709 "->", 710 &result.GetOutputStream(), 711 GetBreakpointLocations ()); 712 result.SetStatus (eReturnStatusSuccessFinishResult); 713 } 714 } 715 } 716 else if (m_options.file_name.empty()) 717 { 718 // Last valid source manager context, or the current frame if no 719 // valid last context in source manager. 720 // One little trick here, if you type the exact same list command twice in a row, it is 721 // more likely because you typed it once, then typed it again 722 if (m_options.start_line == 0) 723 { 724 if (target->GetSourceManager().DisplayMoreWithLineNumbers (&result.GetOutputStream(), 725 m_options.num_lines, 726 m_options.reverse, 727 GetBreakpointLocations ())) 728 { 729 result.SetStatus (eReturnStatusSuccessFinishResult); 730 } 731 } 732 else 733 { 734 if (m_options.num_lines == 0) 735 m_options.num_lines = 10; 736 737 if (m_options.show_bp_locs) 738 { 739 SourceManager::FileSP last_file_sp (target->GetSourceManager().GetLastFile ()); 740 if (last_file_sp) 741 { 742 const bool show_inlines = true; 743 m_breakpoint_locations.Reset (last_file_sp->GetFileSpec(), 0, show_inlines); 744 SearchFilter target_search_filter (target->shared_from_this()); 745 target_search_filter.Search (m_breakpoint_locations); 746 } 747 } 748 else 749 m_breakpoint_locations.Clear(); 750 751 if (target->GetSourceManager().DisplaySourceLinesWithLineNumbersUsingLastFile( 752 m_options.start_line, // Line to display 753 m_options.num_lines, // Lines after line to 754 UINT32_MAX, // Don't mark "line" 755 "", // Don't mark "line" 756 &result.GetOutputStream(), 757 GetBreakpointLocations ())) 758 { 759 result.SetStatus (eReturnStatusSuccessFinishResult); 760 } 761 762 } 763 } 764 else 765 { 766 const char *filename = m_options.file_name.c_str(); 767 768 bool check_inlines = false; 769 SymbolContextList sc_list; 770 size_t num_matches = 0; 771 772 if (m_options.modules.size() > 0) 773 { 774 ModuleList matching_modules; 775 for (size_t i = 0, e = m_options.modules.size(); i < e; ++i) 776 { 777 FileSpec module_file_spec(m_options.modules[i].c_str(), false); 778 if (module_file_spec) 779 { 780 ModuleSpec module_spec (module_file_spec); 781 matching_modules.Clear(); 782 target->GetImages().FindModules (module_spec, matching_modules); 783 num_matches += matching_modules.ResolveSymbolContextForFilePath (filename, 784 0, 785 check_inlines, 786 eSymbolContextModule | eSymbolContextCompUnit, 787 sc_list); 788 } 789 } 790 } 791 else 792 { 793 num_matches = target->GetImages().ResolveSymbolContextForFilePath (filename, 794 0, 795 check_inlines, 796 eSymbolContextModule | eSymbolContextCompUnit, 797 sc_list); 798 } 799 800 if (num_matches == 0) 801 { 802 result.AppendErrorWithFormat("Could not find source file \"%s\".\n", 803 m_options.file_name.c_str()); 804 result.SetStatus (eReturnStatusFailed); 805 return false; 806 } 807 808 if (num_matches > 1) 809 { 810 bool got_multiple = false; 811 FileSpec *test_cu_spec = NULL; 812 813 for (unsigned i = 0; i < num_matches; i++) 814 { 815 SymbolContext sc; 816 sc_list.GetContextAtIndex(i, sc); 817 if (sc.comp_unit) 818 { 819 if (test_cu_spec) 820 { 821 if (test_cu_spec != static_cast<FileSpec *> (sc.comp_unit)) 822 got_multiple = true; 823 break; 824 } 825 else 826 test_cu_spec = sc.comp_unit; 827 } 828 } 829 if (got_multiple) 830 { 831 result.AppendErrorWithFormat("Multiple source files found matching: \"%s.\"\n", 832 m_options.file_name.c_str()); 833 result.SetStatus (eReturnStatusFailed); 834 return false; 835 } 836 } 837 838 SymbolContext sc; 839 if (sc_list.GetContextAtIndex(0, sc)) 840 { 841 if (sc.comp_unit) 842 { 843 if (m_options.show_bp_locs) 844 { 845 const bool show_inlines = true; 846 m_breakpoint_locations.Reset (*sc.comp_unit, 0, show_inlines); 847 SearchFilter target_search_filter (target->shared_from_this()); 848 target_search_filter.Search (m_breakpoint_locations); 849 } 850 else 851 m_breakpoint_locations.Clear(); 852 853 if (m_options.num_lines == 0) 854 m_options.num_lines = 10; 855 856 target->GetSourceManager().DisplaySourceLinesWithLineNumbers (sc.comp_unit, 857 m_options.start_line, 858 0, 859 m_options.num_lines, 860 "", 861 &result.GetOutputStream(), 862 GetBreakpointLocations ()); 863 864 result.SetStatus (eReturnStatusSuccessFinishResult); 865 } 866 else 867 { 868 result.AppendErrorWithFormat("No comp unit found for: \"%s.\"\n", 869 m_options.file_name.c_str()); 870 result.SetStatus (eReturnStatusFailed); 871 return false; 872 } 873 } 874 } 875 return result.Succeeded(); 876 } 877 878 const SymbolContextList * 879 GetBreakpointLocations () 880 { 881 if (m_breakpoint_locations.GetFileLineMatches().GetSize() > 0) 882 return &m_breakpoint_locations.GetFileLineMatches(); 883 return NULL; 884 } 885 CommandOptions m_options; 886 FileLineResolver m_breakpoint_locations; 887 std::string m_reverse_name; 888 889}; 890 891OptionDefinition 892CommandObjectSourceList::CommandOptions::g_option_table[] = 893{ 894{ LLDB_OPT_SET_ALL, false, "count", 'c', OptionParser::eRequiredArgument, NULL, 0, eArgTypeCount, "The number of source lines to display."}, 895{ LLDB_OPT_SET_1 | 896 LLDB_OPT_SET_2 , false, "shlib", 's', OptionParser::eRequiredArgument, NULL, CommandCompletions::eModuleCompletion, eArgTypeShlibName, "Look up the source file in the given shared library."}, 897{ LLDB_OPT_SET_ALL, false, "show-breakpoints", 'b', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Show the line table locations from the debug information that indicate valid places to set source level breakpoints."}, 898{ LLDB_OPT_SET_1 , false, "file", 'f', OptionParser::eRequiredArgument, NULL, CommandCompletions::eSourceFileCompletion, eArgTypeFilename, "The file from which to display source."}, 899{ LLDB_OPT_SET_1 , false, "line", 'l', OptionParser::eRequiredArgument, NULL, 0, eArgTypeLineNum, "The line number at which to start the display source."}, 900{ LLDB_OPT_SET_2 , false, "name", 'n', OptionParser::eRequiredArgument, NULL, CommandCompletions::eSymbolCompletion, eArgTypeSymbol, "The name of a function whose source to display."}, 901{ LLDB_OPT_SET_3 , false, "address",'a', OptionParser::eRequiredArgument, NULL, 0, eArgTypeAddressOrExpression, "Lookup the address and display the source information for the corresponding file and line."}, 902{ LLDB_OPT_SET_4, false, "reverse", 'r', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Reverse the listing to look backwards from the last displayed block of source."}, 903{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL } 904}; 905 906#pragma mark CommandObjectMultiwordSource 907 908//------------------------------------------------------------------------- 909// CommandObjectMultiwordSource 910//------------------------------------------------------------------------- 911 912CommandObjectMultiwordSource::CommandObjectMultiwordSource (CommandInterpreter &interpreter) : 913 CommandObjectMultiword (interpreter, 914 "source", 915 "A set of commands for accessing source file information", 916 "source <subcommand> [<subcommand-options>]") 917{ 918 // "source info" isn't implemented yet... 919 //LoadSubCommand ("info", CommandObjectSP (new CommandObjectSourceInfo (interpreter))); 920 LoadSubCommand ("list", CommandObjectSP (new CommandObjectSourceList (interpreter))); 921} 922 923CommandObjectMultiwordSource::~CommandObjectMultiwordSource () 924{ 925} 926 927