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/Target/Process.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 = Args::StringToUInt32 (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', required_argument, NULL, 0, eArgTypeLineNum,    "The line number at which to start the display source."},
140 { LLDB_OPT_SET_1, false, "file",       'f', required_argument, NULL, CommandCompletions::eSourceFileCompletion, eArgTypeFilename,    "The file from which to display source."},
141 { 0, false, NULL, 0, 0, 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 = Args::StringToUInt32 (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 = Args::StringToUInt32 (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                              eFlagRequiresTarget),
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                 SearchFilter 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     bool
443     DoExecute (Args& command, CommandReturnObject &result)
444     {
445         const size_t argc = command.GetArgumentCount();
446 
447         if (argc != 0)
448         {
449             result.AppendErrorWithFormat("'%s' takes no arguments, only flags.\n", GetCommandName());
450             result.SetStatus (eReturnStatusFailed);
451             return false;
452         }
453 
454         Target *target = m_exe_ctx.GetTargetPtr();
455 
456         SymbolContextList sc_list;
457         if (!m_options.symbol_name.empty())
458         {
459             // Displaying the source for a symbol:
460             ConstString name(m_options.symbol_name.c_str());
461             bool include_symbols = false;
462             bool include_inlines = true;
463             bool append = true;
464             size_t num_matches = 0;
465 
466             if (m_options.num_lines == 0)
467                 m_options.num_lines = 10;
468 
469             const size_t num_modules = m_options.modules.size();
470             if (num_modules > 0)
471             {
472                 ModuleList matching_modules;
473                 for (size_t i = 0; i < num_modules; ++i)
474                 {
475                     FileSpec module_file_spec(m_options.modules[i].c_str(), false);
476                     if (module_file_spec)
477                     {
478                         ModuleSpec module_spec (module_file_spec);
479                         matching_modules.Clear();
480                         target->GetImages().FindModules (module_spec, matching_modules);
481                         num_matches += matching_modules.FindFunctions (name, eFunctionNameTypeAuto, include_symbols, include_inlines, append, sc_list);
482                     }
483                 }
484             }
485             else
486             {
487                 num_matches = target->GetImages().FindFunctions (name, eFunctionNameTypeAuto, include_symbols, include_inlines, append, sc_list);
488             }
489 
490             SymbolContext sc;
491 
492             if (num_matches == 0)
493             {
494                 result.AppendErrorWithFormat("Could not find function named: \"%s\".\n", m_options.symbol_name.c_str());
495                 result.SetStatus (eReturnStatusFailed);
496                 return false;
497             }
498 
499             if (num_matches > 1)
500             {
501                 std::set<SourceInfo> source_match_set;
502 
503                 bool displayed_something = false;
504                 for (size_t i = 0; i < num_matches; i++)
505                 {
506                     sc_list.GetContextAtIndex (i, sc);
507                     SourceInfo source_info (sc.GetFunctionName(),
508                                             sc.GetFunctionStartLineEntry());
509 
510                     if (source_info.IsValid())
511                     {
512                         if (source_match_set.find(source_info) == source_match_set.end())
513                         {
514                             source_match_set.insert(source_info);
515                             if (DisplayFunctionSource (sc, source_info, result))
516                                 displayed_something = true;
517                         }
518                     }
519                 }
520 
521                 if (displayed_something)
522                     result.SetStatus (eReturnStatusSuccessFinishResult);
523                 else
524                     result.SetStatus (eReturnStatusFailed);
525             }
526             else
527             {
528                 sc_list.GetContextAtIndex (0, sc);
529                 SourceInfo source_info;
530 
531                 if (DisplayFunctionSource (sc, source_info, result))
532                 {
533                     result.SetStatus (eReturnStatusSuccessFinishResult);
534                 }
535                 else
536                 {
537                     result.SetStatus (eReturnStatusFailed);
538                 }
539             }
540             return result.Succeeded();
541         }
542         else if (m_options.address != LLDB_INVALID_ADDRESS)
543         {
544             SymbolContext sc;
545             Address so_addr;
546             StreamString error_strm;
547 
548             if (target->GetSectionLoadList().IsEmpty())
549             {
550                 // The target isn't loaded yet, we need to lookup the file address
551                 // in all modules
552                 const ModuleList &module_list = target->GetImages();
553                 const size_t num_modules = module_list.GetSize();
554                 for (size_t i=0; i<num_modules; ++i)
555                 {
556                     ModuleSP module_sp (module_list.GetModuleAtIndex(i));
557                     if (module_sp && module_sp->ResolveFileAddress(m_options.address, so_addr))
558                     {
559                         sc.Clear(true);
560                         if (module_sp->ResolveSymbolContextForAddress (so_addr, eSymbolContextEverything, sc) & eSymbolContextLineEntry)
561                             sc_list.Append(sc);
562                     }
563                 }
564 
565                 if (sc_list.GetSize() == 0)
566                 {
567                     result.AppendErrorWithFormat("no modules have source information for file address 0x%" PRIx64 ".\n",
568                                                  m_options.address);
569                     result.SetStatus (eReturnStatusFailed);
570                     return false;
571                 }
572             }
573             else
574             {
575                 // The target has some things loaded, resolve this address to a
576                 // compile unit + file + line and display
577                 if (target->GetSectionLoadList().ResolveLoadAddress (m_options.address, so_addr))
578                 {
579                     ModuleSP module_sp (so_addr.GetModule());
580                     if (module_sp)
581                     {
582                         sc.Clear(true);
583                         if (module_sp->ResolveSymbolContextForAddress (so_addr, eSymbolContextEverything, sc) & eSymbolContextLineEntry)
584                         {
585                             sc_list.Append(sc);
586                         }
587                         else
588                         {
589                             so_addr.Dump(&error_strm, NULL, Address::DumpStyleModuleWithFileAddress);
590                             result.AppendErrorWithFormat("address resolves to %s, but there is no line table information available for this address.\n",
591                                                          error_strm.GetData());
592                             result.SetStatus (eReturnStatusFailed);
593                             return false;
594                         }
595                     }
596                 }
597 
598                 if (sc_list.GetSize() == 0)
599                 {
600                     result.AppendErrorWithFormat("no modules contain load address 0x%" PRIx64 ".\n", m_options.address);
601                     result.SetStatus (eReturnStatusFailed);
602                     return false;
603                 }
604             }
605             uint32_t num_matches = sc_list.GetSize();
606             for (uint32_t i=0; i<num_matches; ++i)
607             {
608                 sc_list.GetContextAtIndex(i, sc);
609                 if (sc.comp_unit)
610                 {
611                     if (m_options.show_bp_locs)
612                     {
613                         m_breakpoint_locations.Clear();
614                         const bool show_inlines = true;
615                         m_breakpoint_locations.Reset (*sc.comp_unit, 0, show_inlines);
616                         SearchFilter target_search_filter (target->shared_from_this());
617                         target_search_filter.Search (m_breakpoint_locations);
618                     }
619 
620                     bool show_fullpaths = true;
621                     bool show_module = true;
622                     bool show_inlined_frames = true;
623                     sc.DumpStopContext(&result.GetOutputStream(),
624                                        m_exe_ctx.GetBestExecutionContextScope(),
625                                        sc.line_entry.range.GetBaseAddress(),
626                                        show_fullpaths,
627                                        show_module,
628                                        show_inlined_frames);
629                     result.GetOutputStream().EOL();
630 
631                     if (m_options.num_lines == 0)
632                         m_options.num_lines = 10;
633 
634                     size_t lines_to_back_up = m_options.num_lines >= 10 ? 5 : m_options.num_lines/2;
635 
636                     target->GetSourceManager().DisplaySourceLinesWithLineNumbers (sc.comp_unit,
637                                                                                   sc.line_entry.line,
638                                                                                   lines_to_back_up,
639                                                                                   m_options.num_lines - lines_to_back_up,
640                                                                                   "->",
641                                                                                   &result.GetOutputStream(),
642                                                                                   GetBreakpointLocations ());
643                     result.SetStatus (eReturnStatusSuccessFinishResult);
644                 }
645             }
646         }
647         else if (m_options.file_name.empty())
648         {
649             // Last valid source manager context, or the current frame if no
650             // valid last context in source manager.
651             // One little trick here, if you type the exact same list command twice in a row, it is
652             // more likely because you typed it once, then typed it again
653             if (m_options.start_line == 0)
654             {
655                 if (target->GetSourceManager().DisplayMoreWithLineNumbers (&result.GetOutputStream(),
656                                                                            m_options.num_lines,
657                                                                            m_options.reverse,
658                                                                            GetBreakpointLocations ()))
659                 {
660                     result.SetStatus (eReturnStatusSuccessFinishResult);
661                 }
662             }
663             else
664             {
665                 if (m_options.num_lines == 0)
666                     m_options.num_lines = 10;
667 
668                 if (m_options.show_bp_locs)
669                 {
670                     SourceManager::FileSP last_file_sp (target->GetSourceManager().GetLastFile ());
671                     if (last_file_sp)
672                     {
673                         const bool show_inlines = true;
674                         m_breakpoint_locations.Reset (last_file_sp->GetFileSpec(), 0, show_inlines);
675                         SearchFilter target_search_filter (target->shared_from_this());
676                         target_search_filter.Search (m_breakpoint_locations);
677                     }
678                 }
679                 else
680                     m_breakpoint_locations.Clear();
681 
682                 if (target->GetSourceManager().DisplaySourceLinesWithLineNumbersUsingLastFile(
683                             m_options.start_line,   // Line to display
684                             m_options.num_lines,    // Lines after line to
685                             UINT32_MAX,             // Don't mark "line"
686                             "",                     // Don't mark "line"
687                             &result.GetOutputStream(),
688                             GetBreakpointLocations ()))
689                 {
690                     result.SetStatus (eReturnStatusSuccessFinishResult);
691                 }
692 
693             }
694         }
695         else
696         {
697             const char *filename = m_options.file_name.c_str();
698 
699             bool check_inlines = false;
700             SymbolContextList sc_list;
701             size_t num_matches = 0;
702 
703             if (m_options.modules.size() > 0)
704             {
705                 ModuleList matching_modules;
706                 for (size_t i = 0, e = m_options.modules.size(); i < e; ++i)
707                 {
708                     FileSpec module_file_spec(m_options.modules[i].c_str(), false);
709                     if (module_file_spec)
710                     {
711                         ModuleSpec module_spec (module_file_spec);
712                         matching_modules.Clear();
713                         target->GetImages().FindModules (module_spec, matching_modules);
714                         num_matches += matching_modules.ResolveSymbolContextForFilePath (filename,
715                                                                                          0,
716                                                                                          check_inlines,
717                                                                                          eSymbolContextModule | eSymbolContextCompUnit,
718                                                                                          sc_list);
719                     }
720                 }
721             }
722             else
723             {
724                 num_matches = target->GetImages().ResolveSymbolContextForFilePath (filename,
725                                                                                    0,
726                                                                                    check_inlines,
727                                                                                    eSymbolContextModule | eSymbolContextCompUnit,
728                                                                                    sc_list);
729             }
730 
731             if (num_matches == 0)
732             {
733                 result.AppendErrorWithFormat("Could not find source file \"%s\".\n",
734                                              m_options.file_name.c_str());
735                 result.SetStatus (eReturnStatusFailed);
736                 return false;
737             }
738 
739             if (num_matches > 1)
740             {
741                 SymbolContext sc;
742                 bool got_multiple = false;
743                 FileSpec *test_cu_spec = NULL;
744 
745                 for (unsigned i = 0; i < num_matches; i++)
746                 {
747                     sc_list.GetContextAtIndex(i, sc);
748                     if (sc.comp_unit)
749                     {
750                         if (test_cu_spec)
751                         {
752                             if (test_cu_spec != static_cast<FileSpec *> (sc.comp_unit))
753                                 got_multiple = true;
754                                 break;
755                         }
756                         else
757                             test_cu_spec = sc.comp_unit;
758                     }
759                 }
760                 if (got_multiple)
761                 {
762                     result.AppendErrorWithFormat("Multiple source files found matching: \"%s.\"\n",
763                                                  m_options.file_name.c_str());
764                     result.SetStatus (eReturnStatusFailed);
765                     return false;
766                 }
767             }
768 
769             SymbolContext sc;
770             if (sc_list.GetContextAtIndex(0, sc))
771             {
772                 if (sc.comp_unit)
773                 {
774                     if (m_options.show_bp_locs)
775                     {
776                         const bool show_inlines = true;
777                         m_breakpoint_locations.Reset (*sc.comp_unit, 0, show_inlines);
778                         SearchFilter target_search_filter (target->shared_from_this());
779                         target_search_filter.Search (m_breakpoint_locations);
780                     }
781                     else
782                         m_breakpoint_locations.Clear();
783 
784                     if (m_options.num_lines == 0)
785                         m_options.num_lines = 10;
786 
787                     target->GetSourceManager().DisplaySourceLinesWithLineNumbers (sc.comp_unit,
788                                                                                   m_options.start_line,
789                                                                                   0,
790                                                                                   m_options.num_lines,
791                                                                                   "",
792                                                                                   &result.GetOutputStream(),
793                                                                                   GetBreakpointLocations ());
794 
795                     result.SetStatus (eReturnStatusSuccessFinishResult);
796                 }
797                 else
798                 {
799                     result.AppendErrorWithFormat("No comp unit found for: \"%s.\"\n",
800                                                  m_options.file_name.c_str());
801                     result.SetStatus (eReturnStatusFailed);
802                     return false;
803                 }
804             }
805         }
806         return result.Succeeded();
807     }
808 
809     const SymbolContextList *
810     GetBreakpointLocations ()
811     {
812         if (m_breakpoint_locations.GetFileLineMatches().GetSize() > 0)
813             return &m_breakpoint_locations.GetFileLineMatches();
814         return NULL;
815     }
816     CommandOptions m_options;
817     FileLineResolver m_breakpoint_locations;
818     std::string    m_reverse_name;
819 
820 };
821 
822 OptionDefinition
823 CommandObjectSourceList::CommandOptions::g_option_table[] =
824 {
825 { LLDB_OPT_SET_ALL, false, "count",  'c', required_argument, NULL, 0, eArgTypeCount,   "The number of source lines to display."},
826 { LLDB_OPT_SET_1  |
827   LLDB_OPT_SET_2  , false, "shlib",  's', required_argument, NULL, CommandCompletions::eModuleCompletion, eArgTypeShlibName, "Look up the source file in the given shared library."},
828 { 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."},
829 { LLDB_OPT_SET_1  , false, "file",   'f', required_argument, NULL, CommandCompletions::eSourceFileCompletion, eArgTypeFilename,    "The file from which to display source."},
830 { LLDB_OPT_SET_1  , false, "line",   'l', required_argument, NULL, 0, eArgTypeLineNum,    "The line number at which to start the display source."},
831 { LLDB_OPT_SET_2  , false, "name",   'n', required_argument, NULL, CommandCompletions::eSymbolCompletion, eArgTypeSymbol,    "The name of a function whose source to display."},
832 { 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."},
833 { 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."},
834 { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
835 };
836 
837 #pragma mark CommandObjectMultiwordSource
838 
839 //-------------------------------------------------------------------------
840 // CommandObjectMultiwordSource
841 //-------------------------------------------------------------------------
842 
843 CommandObjectMultiwordSource::CommandObjectMultiwordSource (CommandInterpreter &interpreter) :
844     CommandObjectMultiword (interpreter,
845                             "source",
846                             "A set of commands for accessing source file information",
847                             "source <subcommand> [<subcommand-options>]")
848 {
849     // "source info" isn't implemented yet...
850     //LoadSubCommand ("info",   CommandObjectSP (new CommandObjectSourceInfo (interpreter)));
851     LoadSubCommand ("list",   CommandObjectSP (new CommandObjectSourceList (interpreter)));
852 }
853 
854 CommandObjectMultiwordSource::~CommandObjectMultiwordSource ()
855 {
856 }
857 
858