Home | History | Annotate | Download | only in Commands
      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 &current_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