]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/llvm/tools/lldb/source/Commands/CommandObjectSource.cpp
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.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 "lldb/lldb-python.h"
11
12 #include "CommandObjectSource.h"
13
14 // C Includes
15 // C++ Includes
16 // Other libraries and framework includes
17 // Project includes
18 #include "lldb/Interpreter/Args.h"
19 #include "lldb/Core/Debugger.h"
20 #include "lldb/Core/FileLineResolver.h"
21 #include "lldb/Core/Module.h"
22 #include "lldb/Core/ModuleSpec.h"
23 #include "lldb/Core/SourceManager.h"
24 #include "lldb/Interpreter/CommandInterpreter.h"
25 #include "lldb/Interpreter/CommandReturnObject.h"
26 #include "lldb/Host/FileSpec.h"
27 #include "lldb/Symbol/CompileUnit.h"
28 #include "lldb/Symbol/Function.h"
29 #include "lldb/Symbol/Symbol.h"
30 #include "lldb/Target/Process.h"
31 #include "lldb/Target/SectionLoadList.h"
32 #include "lldb/Target/TargetList.h"
33 #include "lldb/Interpreter/CommandCompletions.h"
34 #include "lldb/Interpreter/Options.h"
35
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 = Args::StringToUInt32 (option_arg, 0);
67                 if (start_line == 0)
68                     error.SetErrorStringWithFormat("invalid line number: '%s'", option_arg);
69                 break;
70
71              case 'f':
72                 file_name = option_arg;
73                 break;
74
75            default:
76                 error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option);
77                 break;
78             }
79
80             return error;
81         }
82
83         void
84         OptionParsingStarting ()
85         {
86             file_spec.Clear();
87             file_name.clear();
88             start_line = 0;
89         }
90
91         const OptionDefinition*
92         GetDefinitions ()
93         {
94             return g_option_table;
95         }
96         static OptionDefinition g_option_table[];
97
98         // Instance variables to hold the values for command options.
99         FileSpec file_spec;
100         std::string file_name;
101         uint32_t start_line;
102         
103     };
104  
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, 0, eArgTypeLineNum,    "The line number at which to start the display source."},
142 { LLDB_OPT_SET_1, false, "file",       'f', OptionParser::eRequiredArgument, NULL, CommandCompletions::eSourceFileCompletion, eArgTypeFilename,    "The file from which to display source."},
143 { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
144 };
145
146 #pragma mark CommandObjectSourceList
147 //-------------------------------------------------------------------------
148 // CommandObjectSourceList
149 //-------------------------------------------------------------------------
150
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 = Args::StringToUInt32 (option_arg, 0);
175                 if (start_line == 0)
176                     error.SetErrorStringWithFormat("invalid line number: '%s'", option_arg);
177                 break;
178
179             case 'c':
180                 num_lines = Args::StringToUInt32 (option_arg, 0);
181                 if (num_lines == 0)
182                     error.SetErrorStringWithFormat("invalid line count: '%s'", option_arg);
183                 break;
184
185             case 'f':
186                 file_name = option_arg;
187                 break;
188                 
189             case 'n':
190                 symbol_name = option_arg;
191                 break;
192
193             case 'a':
194                 {
195                     ExecutionContext exe_ctx (m_interpreter.GetExecutionContext());
196                     address = Args::StringToAddress(&exe_ctx, option_arg, LLDB_INVALID_ADDRESS, &error);
197                 }
198                 break;
199             case 's':
200                 modules.push_back (std::string (option_arg));
201                 break;
202             
203             case 'b':
204                 show_bp_locs = true;
205                 break;
206             case 'r':
207                 reverse = true;
208                 break;
209            default:
210                 error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option);
211                 break;
212             }
213
214             return error;
215         }
216
217         void
218         OptionParsingStarting ()
219         {
220             file_spec.Clear();
221             file_name.clear();
222             symbol_name.clear();
223             address = LLDB_INVALID_ADDRESS;
224             start_line = 0;
225             num_lines = 0;
226             show_bp_locs = false;
227             reverse = false;
228             modules.clear();
229         }
230
231         const OptionDefinition*
232         GetDefinitions ()
233         {
234             return g_option_table;
235         }
236         static OptionDefinition g_option_table[];
237
238         // Instance variables to hold the values for command options.
239         FileSpec file_spec;
240         std::string file_name;
241         std::string symbol_name;
242         lldb::addr_t address;
243         uint32_t start_line;
244         uint32_t num_lines;
245         STLStringArray modules;        
246         bool show_bp_locs;
247         bool reverse;
248     };
249  
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                 SearchFilter target_search_filter (m_exe_ctx.GetTargetSP());
425                 target_search_filter.Search (m_breakpoint_locations);
426             }
427             
428             result.AppendMessageWithFormat("File: %s\n", start_file.GetPath().c_str());
429             return target->GetSourceManager().DisplaySourceLinesWithLineNumbers (start_file,
430                                                                                  line_no,
431                                                                                  0,
432                                                                                  m_options.num_lines,
433                                                                                  "",
434                                                                                  &result.GetOutputStream(),
435                                                                                  GetBreakpointLocations ());
436         }
437         else
438         {
439             result.AppendErrorWithFormat("Could not find function info for: \"%s\".\n", m_options.symbol_name.c_str());
440         }
441         return 0;
442     }
443
444     // From Jim: The FindMatchingFunctions / FindMatchingFunctionSymbols functions 
445     // "take a possibly empty vector of strings which are names of modules, and
446     // run the two search functions on the subset of the full module list that
447     // matches the strings in the input vector". If we wanted to put these somewhere,
448     // there should probably be a module-filter-list that can be passed to the
449     // various ModuleList::Find* calls, which would either be a vector of string
450     // names or a ModuleSpecList.
451     size_t FindMatchingFunctions (Target *target, const ConstString &name, SymbolContextList& sc_list)
452     {
453         // Displaying the source for a symbol:
454         bool include_inlines = true;
455         bool append = true;
456         bool include_symbols = false;
457         size_t num_matches = 0;
458         
459         if (m_options.num_lines == 0)
460             m_options.num_lines = 10;
461
462         const size_t num_modules = m_options.modules.size();
463         if (num_modules > 0)
464         {
465             ModuleList matching_modules;
466             for (size_t i = 0; i < num_modules; ++i)
467             {
468                 FileSpec module_file_spec(m_options.modules[i].c_str(), false);
469                 if (module_file_spec)
470                 {
471                     ModuleSpec module_spec (module_file_spec);
472                     matching_modules.Clear();
473                     target->GetImages().FindModules (module_spec, matching_modules);
474                     num_matches += matching_modules.FindFunctions (name, eFunctionNameTypeAuto, include_symbols, include_inlines, append, sc_list);
475                 }
476             }
477         }
478         else
479         {
480             num_matches = target->GetImages().FindFunctions (name, eFunctionNameTypeAuto, include_symbols, include_inlines, append, sc_list);
481         }
482         return num_matches;
483     }
484
485     size_t FindMatchingFunctionSymbols (Target *target, const ConstString &name, SymbolContextList& sc_list)
486     {
487         size_t num_matches = 0;
488         const size_t num_modules = m_options.modules.size();
489         if (num_modules > 0)
490         {
491             ModuleList matching_modules;
492             for (size_t i = 0; i < num_modules; ++i)
493             {
494                 FileSpec module_file_spec(m_options.modules[i].c_str(), false);
495                 if (module_file_spec)
496                 {
497                     ModuleSpec module_spec (module_file_spec);
498                     matching_modules.Clear();
499                     target->GetImages().FindModules (module_spec, matching_modules);
500                     num_matches += matching_modules.FindFunctionSymbols (name, eFunctionNameTypeAuto, sc_list);
501                 }
502             }
503         }
504         else
505         {
506             num_matches = target->GetImages().FindFunctionSymbols (name, eFunctionNameTypeAuto, sc_list);
507         }
508         return num_matches;
509     }
510
511     bool
512     DoExecute (Args& command, CommandReturnObject &result)
513     {
514         const size_t argc = command.GetArgumentCount();
515
516         if (argc != 0)
517         {
518             result.AppendErrorWithFormat("'%s' takes no arguments, only flags.\n", GetCommandName());
519             result.SetStatus (eReturnStatusFailed);
520             return false;
521         }
522
523         Target *target = m_exe_ctx.GetTargetPtr();
524
525         if (!m_options.symbol_name.empty())
526         {
527             SymbolContextList sc_list;
528             ConstString name(m_options.symbol_name.c_str());
529
530             // Displaying the source for a symbol. Search for function named name.
531             size_t num_matches = FindMatchingFunctions (target, name, sc_list);
532             if (!num_matches)
533             {
534                 // If we didn't find any functions with that name, try searching for symbols
535                 // that line up exactly with function addresses.
536                 SymbolContextList sc_list_symbols;
537                 size_t num_symbol_matches = FindMatchingFunctionSymbols (target, name, sc_list_symbols);
538                 for (size_t i = 0; i < num_symbol_matches; i++)
539                 {
540                     SymbolContext sc;
541                     sc_list_symbols.GetContextAtIndex (i, sc);
542                     if (sc.symbol)
543                     {
544                         const Address &base_address = sc.symbol->GetAddress();
545                         Function *function = base_address.CalculateSymbolContextFunction();
546                         if (function)
547                         {
548                             sc_list.Append (SymbolContext(function));
549                             num_matches++;
550                             break;
551                         }
552                     }
553                 }
554             }
555
556             if (num_matches == 0)
557             {
558                 result.AppendErrorWithFormat("Could not find function named: \"%s\".\n", m_options.symbol_name.c_str());
559                 result.SetStatus (eReturnStatusFailed);
560                 return false;
561             }
562
563             if (num_matches > 1)
564             {
565                 std::set<SourceInfo> source_match_set;
566                 
567                 bool displayed_something = false;
568                 for (size_t i = 0; i < num_matches; i++)
569                 {
570                     SymbolContext sc;
571                     sc_list.GetContextAtIndex (i, sc);
572                     SourceInfo source_info (sc.GetFunctionName(),
573                                             sc.GetFunctionStartLineEntry());
574                     
575                     if (source_info.IsValid())
576                     {
577                         if (source_match_set.find(source_info) == source_match_set.end())
578                         {
579                             source_match_set.insert(source_info);
580                             if (DisplayFunctionSource (sc, source_info, result))
581                                 displayed_something = true;
582                         }
583                     }
584                 }
585                 
586                 if (displayed_something)
587                     result.SetStatus (eReturnStatusSuccessFinishResult);
588                 else
589                     result.SetStatus (eReturnStatusFailed);
590             }
591             else
592             {
593                 SymbolContext sc;
594                 sc_list.GetContextAtIndex (0, sc);
595                 SourceInfo source_info;
596                 
597                 if (DisplayFunctionSource (sc, source_info, result))
598                 {
599                     result.SetStatus (eReturnStatusSuccessFinishResult);
600                 }
601                 else
602                 {
603                     result.SetStatus (eReturnStatusFailed);
604                 }
605             }
606             return result.Succeeded();
607         }
608         else if (m_options.address != LLDB_INVALID_ADDRESS)
609         {
610             Address so_addr;
611             StreamString error_strm;
612             SymbolContextList sc_list;
613
614             if (target->GetSectionLoadList().IsEmpty())
615             {
616                 // The target isn't loaded yet, we need to lookup the file address
617                 // in all modules
618                 const ModuleList &module_list = target->GetImages();
619                 const size_t num_modules = module_list.GetSize();
620                 for (size_t i=0; i<num_modules; ++i)
621                 {
622                     ModuleSP module_sp (module_list.GetModuleAtIndex(i));
623                     if (module_sp && module_sp->ResolveFileAddress(m_options.address, so_addr))
624                     {
625                         SymbolContext sc;
626                         sc.Clear(true);
627                         if (module_sp->ResolveSymbolContextForAddress (so_addr, eSymbolContextEverything, sc) & eSymbolContextLineEntry)
628                             sc_list.Append(sc);
629                     }
630                 }
631                 
632                 if (sc_list.GetSize() == 0)
633                 {
634                     result.AppendErrorWithFormat("no modules have source information for file address 0x%" PRIx64 ".\n",
635                                                  m_options.address);
636                     result.SetStatus (eReturnStatusFailed);
637                     return false;
638                 }
639             }
640             else
641             {
642                 // The target has some things loaded, resolve this address to a
643                 // compile unit + file + line and display
644                 if (target->GetSectionLoadList().ResolveLoadAddress (m_options.address, so_addr))
645                 {
646                     ModuleSP module_sp (so_addr.GetModule());
647                     if (module_sp)
648                     {
649                         SymbolContext sc;
650                         sc.Clear(true);
651                         if (module_sp->ResolveSymbolContextForAddress (so_addr, eSymbolContextEverything, sc) & eSymbolContextLineEntry)
652                         {
653                             sc_list.Append(sc);
654                         }
655                         else
656                         {
657                             so_addr.Dump(&error_strm, NULL, Address::DumpStyleModuleWithFileAddress);
658                             result.AppendErrorWithFormat("address resolves to %s, but there is no line table information available for this address.\n",
659                                                          error_strm.GetData());
660                             result.SetStatus (eReturnStatusFailed);
661                             return false;
662                         }
663                     }
664                 }
665
666                 if (sc_list.GetSize() == 0)
667                 {
668                     result.AppendErrorWithFormat("no modules contain load address 0x%" PRIx64 ".\n", m_options.address);
669                     result.SetStatus (eReturnStatusFailed);
670                     return false;
671                 }
672             }
673             uint32_t num_matches = sc_list.GetSize();
674             for (uint32_t i=0; i<num_matches; ++i)
675             {
676                 SymbolContext sc;
677                 sc_list.GetContextAtIndex(i, sc);
678                 if (sc.comp_unit)
679                 {
680                     if (m_options.show_bp_locs)
681                     {
682                         m_breakpoint_locations.Clear();
683                         const bool show_inlines = true;
684                         m_breakpoint_locations.Reset (*sc.comp_unit, 0, show_inlines);
685                         SearchFilter target_search_filter (target->shared_from_this());
686                         target_search_filter.Search (m_breakpoint_locations);
687                     }
688                     
689                     bool show_fullpaths = true;
690                     bool show_module = true;
691                     bool show_inlined_frames = true;
692                     sc.DumpStopContext(&result.GetOutputStream(),
693                                        m_exe_ctx.GetBestExecutionContextScope(),
694                                        sc.line_entry.range.GetBaseAddress(),
695                                        show_fullpaths,
696                                        show_module,
697                                        show_inlined_frames);
698                     result.GetOutputStream().EOL();
699
700                     if (m_options.num_lines == 0)
701                         m_options.num_lines = 10;
702                     
703                     size_t lines_to_back_up = m_options.num_lines >= 10 ? 5 : m_options.num_lines/2;
704
705                     target->GetSourceManager().DisplaySourceLinesWithLineNumbers (sc.comp_unit,
706                                                                                   sc.line_entry.line,
707                                                                                   lines_to_back_up,
708                                                                                   m_options.num_lines - lines_to_back_up,
709                                                                                   "->",
710                                                                                   &result.GetOutputStream(),
711                                                                                   GetBreakpointLocations ());
712                     result.SetStatus (eReturnStatusSuccessFinishResult);
713                 }
714             }
715         }
716         else if (m_options.file_name.empty())
717         {
718             // Last valid source manager context, or the current frame if no
719             // valid last context in source manager.
720             // One little trick here, if you type the exact same list command twice in a row, it is
721             // more likely because you typed it once, then typed it again
722             if (m_options.start_line == 0)
723             {
724                 if (target->GetSourceManager().DisplayMoreWithLineNumbers (&result.GetOutputStream(),
725                                                                            m_options.num_lines,
726                                                                            m_options.reverse,
727                                                                            GetBreakpointLocations ()))
728                 {
729                     result.SetStatus (eReturnStatusSuccessFinishResult);
730                 }
731             }
732             else
733             {
734                 if (m_options.num_lines == 0)
735                     m_options.num_lines = 10;
736
737                 if (m_options.show_bp_locs)
738                 {
739                     SourceManager::FileSP last_file_sp (target->GetSourceManager().GetLastFile ());
740                     if (last_file_sp)
741                     {
742                         const bool show_inlines = true;
743                         m_breakpoint_locations.Reset (last_file_sp->GetFileSpec(), 0, show_inlines);
744                         SearchFilter target_search_filter (target->shared_from_this());
745                         target_search_filter.Search (m_breakpoint_locations);
746                     }
747                 }
748                 else
749                     m_breakpoint_locations.Clear();
750
751                 if (target->GetSourceManager().DisplaySourceLinesWithLineNumbersUsingLastFile(
752                             m_options.start_line,   // Line to display
753                             m_options.num_lines,    // Lines after line to
754                             UINT32_MAX,             // Don't mark "line"
755                             "",                     // Don't mark "line"
756                             &result.GetOutputStream(),
757                             GetBreakpointLocations ()))
758                 {
759                     result.SetStatus (eReturnStatusSuccessFinishResult);
760                 }
761
762             }
763         }
764         else
765         {
766             const char *filename = m_options.file_name.c_str();
767
768             bool check_inlines = false;
769             SymbolContextList sc_list;
770             size_t num_matches = 0;
771             
772             if (m_options.modules.size() > 0)
773             {
774                 ModuleList matching_modules;
775                 for (size_t i = 0, e = m_options.modules.size(); i < e; ++i)
776                 {
777                     FileSpec module_file_spec(m_options.modules[i].c_str(), false);
778                     if (module_file_spec)
779                     {
780                         ModuleSpec module_spec (module_file_spec);
781                         matching_modules.Clear();
782                         target->GetImages().FindModules (module_spec, matching_modules);
783                         num_matches += matching_modules.ResolveSymbolContextForFilePath (filename,
784                                                                                          0,
785                                                                                          check_inlines,
786                                                                                          eSymbolContextModule | eSymbolContextCompUnit,
787                                                                                          sc_list);
788                     }
789                 }
790             }
791             else
792             {
793                 num_matches = target->GetImages().ResolveSymbolContextForFilePath (filename,
794                                                                                    0,
795                                                                                    check_inlines,
796                                                                                    eSymbolContextModule | eSymbolContextCompUnit,
797                                                                                    sc_list);
798             }
799             
800             if (num_matches == 0)
801             {
802                 result.AppendErrorWithFormat("Could not find source file \"%s\".\n", 
803                                              m_options.file_name.c_str());
804                 result.SetStatus (eReturnStatusFailed);
805                 return false;
806             }
807             
808             if (num_matches > 1)
809             {
810                 bool got_multiple = false;
811                 FileSpec *test_cu_spec = NULL;
812
813                 for (unsigned i = 0; i < num_matches; i++)
814                 {
815                     SymbolContext sc;
816                     sc_list.GetContextAtIndex(i, sc);
817                     if (sc.comp_unit)
818                     {
819                         if (test_cu_spec)
820                         {
821                             if (test_cu_spec != static_cast<FileSpec *> (sc.comp_unit))
822                                 got_multiple = true;
823                                 break;
824                         }
825                         else
826                             test_cu_spec = sc.comp_unit;
827                     }
828                 }
829                 if (got_multiple)
830                 {
831                     result.AppendErrorWithFormat("Multiple source files found matching: \"%s.\"\n", 
832                                                  m_options.file_name.c_str());
833                     result.SetStatus (eReturnStatusFailed);
834                     return false;
835                 }
836             }
837             
838             SymbolContext sc;
839             if (sc_list.GetContextAtIndex(0, sc))
840             {
841                 if (sc.comp_unit)
842                 {
843                     if (m_options.show_bp_locs)
844                     {
845                         const bool show_inlines = true;
846                         m_breakpoint_locations.Reset (*sc.comp_unit, 0, show_inlines);
847                         SearchFilter target_search_filter (target->shared_from_this());
848                         target_search_filter.Search (m_breakpoint_locations);
849                     }
850                     else
851                         m_breakpoint_locations.Clear();
852
853                     if (m_options.num_lines == 0)
854                         m_options.num_lines = 10;
855                     
856                     target->GetSourceManager().DisplaySourceLinesWithLineNumbers (sc.comp_unit,
857                                                                                   m_options.start_line,
858                                                                                   0,
859                                                                                   m_options.num_lines,
860                                                                                   "",
861                                                                                   &result.GetOutputStream(),
862                                                                                   GetBreakpointLocations ());
863
864                     result.SetStatus (eReturnStatusSuccessFinishResult);
865                 }
866                 else
867                 {
868                     result.AppendErrorWithFormat("No comp unit found for: \"%s.\"\n", 
869                                                  m_options.file_name.c_str());
870                     result.SetStatus (eReturnStatusFailed);
871                     return false;
872                 }
873             }
874         }
875         return result.Succeeded();
876     }
877     
878     const SymbolContextList *
879     GetBreakpointLocations ()
880     {
881         if (m_breakpoint_locations.GetFileLineMatches().GetSize() > 0)
882             return &m_breakpoint_locations.GetFileLineMatches();
883         return NULL;
884     }
885     CommandOptions m_options;
886     FileLineResolver m_breakpoint_locations;
887     std::string    m_reverse_name;
888
889 };
890
891 OptionDefinition
892 CommandObjectSourceList::CommandOptions::g_option_table[] =
893 {
894 { LLDB_OPT_SET_ALL, false, "count",  'c', OptionParser::eRequiredArgument, NULL, 0, eArgTypeCount,   "The number of source lines to display."},
895 { LLDB_OPT_SET_1  |
896   LLDB_OPT_SET_2  , false, "shlib",  's', OptionParser::eRequiredArgument, NULL, CommandCompletions::eModuleCompletion, eArgTypeShlibName, "Look up the source file in the given shared library."},
897 { LLDB_OPT_SET_ALL, false, "show-breakpoints", 'b', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Show the line table locations from the debug information that indicate valid places to set source level breakpoints."},
898 { LLDB_OPT_SET_1  , false, "file",   'f', OptionParser::eRequiredArgument, NULL, CommandCompletions::eSourceFileCompletion, eArgTypeFilename,    "The file from which to display source."},
899 { LLDB_OPT_SET_1  , false, "line",   'l', OptionParser::eRequiredArgument, NULL, 0, eArgTypeLineNum,    "The line number at which to start the display source."},
900 { LLDB_OPT_SET_2  , false, "name",   'n', OptionParser::eRequiredArgument, NULL, CommandCompletions::eSymbolCompletion, eArgTypeSymbol,    "The name of a function whose source to display."},
901 { LLDB_OPT_SET_3  , false, "address",'a', OptionParser::eRequiredArgument, NULL, 0, eArgTypeAddressOrExpression, "Lookup the address and display the source information for the corresponding file and line."},
902 { LLDB_OPT_SET_4, false, "reverse", 'r', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Reverse the listing to look backwards from the last displayed block of source."},
903 { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
904 };
905
906 #pragma mark CommandObjectMultiwordSource
907
908 //-------------------------------------------------------------------------
909 // CommandObjectMultiwordSource
910 //-------------------------------------------------------------------------
911
912 CommandObjectMultiwordSource::CommandObjectMultiwordSource (CommandInterpreter &interpreter) :
913     CommandObjectMultiword (interpreter,
914                             "source",
915                             "A set of commands for accessing source file information",
916                             "source <subcommand> [<subcommand-options>]")
917 {
918     // "source info" isn't implemented yet...
919     //LoadSubCommand ("info",   CommandObjectSP (new CommandObjectSourceInfo (interpreter)));
920     LoadSubCommand ("list",   CommandObjectSP (new CommandObjectSourceList (interpreter)));
921 }
922
923 CommandObjectMultiwordSource::~CommandObjectMultiwordSource ()
924 {
925 }
926