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