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