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 &current_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