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 = 10;
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         m_options (interpreter)
255     {
256     }
257 
258     ~CommandObjectSourceList ()
259     {
260     }
261 
262 
263     Options *
264     GetOptions ()
265     {
266         return &m_options;
267     }
268 
269     virtual const char *
270     GetRepeatCommand (Args &current_command_args, uint32_t index)
271     {
272         // This is kind of gross, but the command hasn't been parsed yet so we can't look at the option
273         // values for this invocation...  I have to scan the arguments directly.
274         size_t num_args = current_command_args.GetArgumentCount();
275         bool is_reverse = false;
276         for (size_t i = 0 ; i < num_args; i++)
277         {
278             const char *arg = current_command_args.GetArgumentAtIndex(i);
279             if (arg && (strcmp(arg, "-r") == 0 || strcmp(arg, "--reverse") == 0))
280             {
281                 is_reverse = true;
282             }
283         }
284         if (is_reverse)
285         {
286             if (m_reverse_name.empty())
287             {
288                 m_reverse_name = m_cmd_name;
289                 m_reverse_name.append (" -r");
290             }
291             return m_reverse_name.c_str();
292         }
293         else
294             return m_cmd_name.c_str();
295     }
296 
297 protected:
298     bool
299     DoExecute (Args& command, CommandReturnObject &result)
300     {
301         const int argc = command.GetArgumentCount();
302 
303         if (argc != 0)
304         {
305             result.AppendErrorWithFormat("'%s' takes no arguments, only flags.\n", GetCommandName());
306             result.SetStatus (eReturnStatusFailed);
307             return false;
308         }
309 
310         ExecutionContext exe_ctx(m_interpreter.GetExecutionContext());
311         Target *target = exe_ctx.GetTargetPtr();
312 
313         if (target == NULL)
314             target = m_interpreter.GetDebugger().GetSelectedTarget().get();
315 
316         if (target == NULL)
317         {
318             result.AppendError ("invalid target, create a debug target using the 'target create' command");
319             result.SetStatus (eReturnStatusFailed);
320             return false;
321         }
322 
323         SymbolContextList sc_list;
324         if (!m_options.symbol_name.empty())
325         {
326             // Displaying the source for a symbol:
327             ConstString name(m_options.symbol_name.c_str());
328             bool include_symbols = false;
329             bool include_inlines = true;
330             bool append = true;
331             size_t num_matches = 0;
332 
333             if (m_options.modules.size() > 0)
334             {
335                 ModuleList matching_modules;
336                 for (unsigned i = 0, e = m_options.modules.size(); i != e; i++)
337                 {
338                     FileSpec module_file_spec(m_options.modules[i].c_str(), false);
339                     if (module_file_spec)
340                     {
341                         ModuleSpec module_spec (module_file_spec);
342                         matching_modules.Clear();
343                         target->GetImages().FindModules (module_spec, matching_modules);
344                         num_matches += matching_modules.FindFunctions (name, eFunctionNameTypeAuto, include_symbols, include_inlines, append, sc_list);
345                     }
346                 }
347             }
348             else
349             {
350                 num_matches = target->GetImages().FindFunctions (name, eFunctionNameTypeAuto, include_symbols, include_inlines, append, sc_list);
351             }
352 
353             SymbolContext sc;
354 
355             if (num_matches == 0)
356             {
357                 result.AppendErrorWithFormat("Could not find function named: \"%s\".\n", m_options.symbol_name.c_str());
358                 result.SetStatus (eReturnStatusFailed);
359                 return false;
360             }
361 
362             sc_list.GetContextAtIndex (0, sc);
363             FileSpec start_file;
364             uint32_t start_line;
365             uint32_t end_line;
366             FileSpec end_file;
367             if (sc.function != NULL)
368             {
369                 sc.function->GetStartLineSourceInfo (start_file, start_line);
370                 if (start_line == 0)
371                 {
372                     result.AppendErrorWithFormat("Could not find line information for start of function: \"%s\".\n", m_options.symbol_name.c_str());
373                     result.SetStatus (eReturnStatusFailed);
374                     return false;
375                 }
376                 sc.function->GetEndLineSourceInfo (end_file, end_line);
377             }
378             else
379             {
380                 result.AppendErrorWithFormat("Could not find function info for: \"%s\".\n", m_options.symbol_name.c_str());
381                 result.SetStatus (eReturnStatusFailed);
382                 return false;
383             }
384 
385             if (num_matches > 1)
386             {
387                 // This could either be because there are multiple functions of this name, in which case
388                 // we'll have to specify this further...  Or it could be because there are multiple inlined instances
389                 // of one function.  So run through the matches and if they all have the same file & line then we can just
390                 // list one.
391 
392                 bool found_multiple = false;
393 
394                 for (size_t i = 1; i < num_matches; i++)
395                 {
396                     SymbolContext scratch_sc;
397                     sc_list.GetContextAtIndex (i, scratch_sc);
398                     if (scratch_sc.function != NULL)
399                     {
400                         FileSpec scratch_file;
401                         uint32_t scratch_line;
402                         scratch_sc.function->GetStartLineSourceInfo (scratch_file, scratch_line);
403                         if (scratch_file != start_file
404                             || scratch_line != start_line)
405                         {
406                             found_multiple = true;
407                             break;
408                         }
409                     }
410                 }
411                 if (found_multiple)
412                 {
413                     StreamString s;
414                     for (size_t i = 0; i < num_matches; i++)
415                     {
416                         SymbolContext scratch_sc;
417                         sc_list.GetContextAtIndex (i, scratch_sc);
418                         if (scratch_sc.function != NULL)
419                         {
420                             s.Printf("\n%lu: ", i);
421                             scratch_sc.function->Dump (&s, true);
422                         }
423                     }
424                     result.AppendErrorWithFormat("Multiple functions found matching: %s: \n%s\n",
425                                                  m_options.symbol_name.c_str(),
426                                                  s.GetData());
427                     result.SetStatus (eReturnStatusFailed);
428                     return false;
429                 }
430             }
431 
432 
433             // This is a little hacky, but the first line table entry for a function points to the "{" that
434             // starts the function block.  It would be nice to actually get the function
435             // declaration in there too.  So back up a bit, but not further than what you're going to display.
436             size_t lines_to_back_up = m_options.num_lines >= 10 ? 5 : m_options.num_lines/2;
437             uint32_t line_no;
438             if (start_line <= lines_to_back_up)
439                 line_no = 1;
440             else
441                 line_no = start_line - lines_to_back_up;
442 
443             // For fun, if the function is shorter than the number of lines we're supposed to display,
444             // only display the function...
445             if (end_line != 0)
446             {
447                 if (m_options.num_lines > end_line - line_no)
448                     m_options.num_lines = end_line - line_no;
449             }
450 
451             char path_buf[PATH_MAX];
452             start_file.GetPath(path_buf, sizeof(path_buf));
453 
454             if (m_options.show_bp_locs)
455             {
456                 const bool show_inlines = true;
457                 m_breakpoint_locations.Reset (start_file, 0, show_inlines);
458                 SearchFilter target_search_filter (exe_ctx.GetTargetSP());
459                 target_search_filter.Search (m_breakpoint_locations);
460             }
461             else
462                 m_breakpoint_locations.Clear();
463 
464             result.AppendMessageWithFormat("File: %s.\n", path_buf);
465             target->GetSourceManager().DisplaySourceLinesWithLineNumbers (start_file,
466                                                                           line_no,
467                                                                           0,
468                                                                           m_options.num_lines,
469                                                                           "",
470                                                                           &result.GetOutputStream(),
471                                                                           GetBreakpointLocations ());
472 
473             result.SetStatus (eReturnStatusSuccessFinishResult);
474             return true;
475 
476         }
477         else if (m_options.address != LLDB_INVALID_ADDRESS)
478         {
479             SymbolContext sc;
480             Address so_addr;
481             StreamString error_strm;
482 
483             if (target->GetSectionLoadList().IsEmpty())
484             {
485                 // The target isn't loaded yet, we need to lookup the file address
486                 // in all modules
487                 const ModuleList &module_list = target->GetImages();
488                 const uint32_t num_modules = module_list.GetSize();
489                 for (uint32_t i=0; i<num_modules; ++i)
490                 {
491                     ModuleSP module_sp (module_list.GetModuleAtIndex(i));
492                     if (module_sp && module_sp->ResolveFileAddress(m_options.address, so_addr))
493                     {
494                         sc.Clear();
495                         if (module_sp->ResolveSymbolContextForAddress (so_addr, eSymbolContextEverything, sc) & eSymbolContextLineEntry)
496                             sc_list.Append(sc);
497                     }
498                 }
499 
500                 if (sc_list.GetSize() == 0)
501                 {
502                     result.AppendErrorWithFormat("no modules have source information for file address 0x%" PRIx64 ".\n",
503                                                  m_options.address);
504                     result.SetStatus (eReturnStatusFailed);
505                     return false;
506                 }
507             }
508             else
509             {
510                 // The target has some things loaded, resolve this address to a
511                 // compile unit + file + line and display
512                 if (target->GetSectionLoadList().ResolveLoadAddress (m_options.address, so_addr))
513                 {
514                     ModuleSP module_sp (so_addr.GetModule());
515                     if (module_sp)
516                     {
517                         sc.Clear();
518                         if (module_sp->ResolveSymbolContextForAddress (so_addr, eSymbolContextEverything, sc) & eSymbolContextLineEntry)
519                         {
520                             sc_list.Append(sc);
521                         }
522                         else
523                         {
524                             so_addr.Dump(&error_strm, NULL, Address::DumpStyleModuleWithFileAddress);
525                             result.AppendErrorWithFormat("address resolves to %s, but there is no line table information available for this address.\n",
526                                                          error_strm.GetData());
527                             result.SetStatus (eReturnStatusFailed);
528                             return false;
529                         }
530                     }
531                 }
532 
533                 if (sc_list.GetSize() == 0)
534                 {
535                     result.AppendErrorWithFormat("no modules contain load address 0x%" PRIx64 ".\n", m_options.address);
536                     result.SetStatus (eReturnStatusFailed);
537                     return false;
538                 }
539             }
540             uint32_t num_matches = sc_list.GetSize();
541             for (uint32_t i=0; i<num_matches; ++i)
542             {
543                 sc_list.GetContextAtIndex(i, sc);
544                 if (sc.comp_unit)
545                 {
546                     if (m_options.show_bp_locs)
547                     {
548                         m_breakpoint_locations.Clear();
549                         const bool show_inlines = true;
550                         m_breakpoint_locations.Reset (*sc.comp_unit, 0, show_inlines);
551                         SearchFilter target_search_filter (target->shared_from_this());
552                         target_search_filter.Search (m_breakpoint_locations);
553                     }
554 
555                     bool show_fullpaths = true;
556                     bool show_module = true;
557                     bool show_inlined_frames = true;
558                     sc.DumpStopContext(&result.GetOutputStream(),
559                                        exe_ctx.GetBestExecutionContextScope(),
560                                        sc.line_entry.range.GetBaseAddress(),
561                                        show_fullpaths,
562                                        show_module,
563                                        show_inlined_frames);
564                     result.GetOutputStream().EOL();
565 
566                     size_t lines_to_back_up = m_options.num_lines >= 10 ? 5 : m_options.num_lines/2;
567 
568                     target->GetSourceManager().DisplaySourceLinesWithLineNumbers (sc.comp_unit,
569                                                                                   sc.line_entry.line,
570                                                                                   lines_to_back_up,
571                                                                                   m_options.num_lines - lines_to_back_up,
572                                                                                   "->",
573                                                                                   &result.GetOutputStream(),
574                                                                                   GetBreakpointLocations ());
575                     result.SetStatus (eReturnStatusSuccessFinishResult);
576                 }
577             }
578         }
579         else if (m_options.file_name.empty())
580         {
581             // Last valid source manager context, or the current frame if no
582             // valid last context in source manager.
583             // One little trick here, if you type the exact same list command twice in a row, it is
584             // more likely because you typed it once, then typed it again
585             if (m_options.start_line == 0)
586             {
587                 if (target->GetSourceManager().DisplayMoreWithLineNumbers (&result.GetOutputStream(),
588                                                                            GetBreakpointLocations (),
589                                                                            m_options.reverse))
590                 {
591                     result.SetStatus (eReturnStatusSuccessFinishResult);
592                 }
593             }
594             else
595             {
596                 if (m_options.show_bp_locs)
597                 {
598                     SourceManager::FileSP last_file_sp (target->GetSourceManager().GetLastFile ());
599                     if (last_file_sp)
600                     {
601                         const bool show_inlines = true;
602                         m_breakpoint_locations.Reset (last_file_sp->GetFileSpec(), 0, show_inlines);
603                         SearchFilter target_search_filter (target->shared_from_this());
604                         target_search_filter.Search (m_breakpoint_locations);
605                     }
606                 }
607                 else
608                     m_breakpoint_locations.Clear();
609 
610                 if (target->GetSourceManager().DisplaySourceLinesWithLineNumbersUsingLastFile(
611                             m_options.start_line,   // Line to display
612                             0,                      // Lines before line to display
613                             m_options.num_lines,    // Lines after line to display
614                             "",                     // Don't mark "line"
615                             &result.GetOutputStream(),
616                             GetBreakpointLocations ()))
617                 {
618                     result.SetStatus (eReturnStatusSuccessFinishResult);
619                 }
620 
621             }
622         }
623         else
624         {
625             const char *filename = m_options.file_name.c_str();
626 
627             bool check_inlines = false;
628             SymbolContextList sc_list;
629             size_t num_matches = 0;
630 
631             if (m_options.modules.size() > 0)
632             {
633                 ModuleList matching_modules;
634                 for (unsigned i = 0, e = m_options.modules.size(); i != e; i++)
635                 {
636                     FileSpec module_file_spec(m_options.modules[i].c_str(), false);
637                     if (module_file_spec)
638                     {
639                         ModuleSpec module_spec (module_file_spec);
640                         matching_modules.Clear();
641                         target->GetImages().FindModules (module_spec, matching_modules);
642                         num_matches += matching_modules.ResolveSymbolContextForFilePath (filename,
643                                                                                          0,
644                                                                                          check_inlines,
645                                                                                          eSymbolContextModule | eSymbolContextCompUnit,
646                                                                                          sc_list);
647                     }
648                 }
649             }
650             else
651             {
652                 num_matches = target->GetImages().ResolveSymbolContextForFilePath (filename,
653                                                                                    0,
654                                                                                    check_inlines,
655                                                                                    eSymbolContextModule | eSymbolContextCompUnit,
656                                                                                    sc_list);
657             }
658 
659             if (num_matches == 0)
660             {
661                 result.AppendErrorWithFormat("Could not find source file \"%s\".\n",
662                                              m_options.file_name.c_str());
663                 result.SetStatus (eReturnStatusFailed);
664                 return false;
665             }
666 
667             if (num_matches > 1)
668             {
669                 SymbolContext sc;
670                 bool got_multiple = false;
671                 FileSpec *test_cu_spec = NULL;
672 
673                 for (unsigned i = 0; i < num_matches; i++)
674                 {
675                     sc_list.GetContextAtIndex(i, sc);
676                     if (sc.comp_unit)
677                     {
678                         if (test_cu_spec)
679                         {
680                             if (test_cu_spec != static_cast<FileSpec *> (sc.comp_unit))
681                                 got_multiple = true;
682                                 break;
683                         }
684                         else
685                             test_cu_spec = sc.comp_unit;
686                     }
687                 }
688                 if (got_multiple)
689                 {
690                     result.AppendErrorWithFormat("Multiple source files found matching: \"%s.\"\n",
691                                                  m_options.file_name.c_str());
692                     result.SetStatus (eReturnStatusFailed);
693                     return false;
694                 }
695             }
696 
697             SymbolContext sc;
698             if (sc_list.GetContextAtIndex(0, sc))
699             {
700                 if (sc.comp_unit)
701                 {
702                     if (m_options.show_bp_locs)
703                     {
704                         const bool show_inlines = true;
705                         m_breakpoint_locations.Reset (*sc.comp_unit, 0, show_inlines);
706                         SearchFilter target_search_filter (target->shared_from_this());
707                         target_search_filter.Search (m_breakpoint_locations);
708                     }
709                     else
710                         m_breakpoint_locations.Clear();
711 
712                     target->GetSourceManager().DisplaySourceLinesWithLineNumbers (sc.comp_unit,
713                                                                                   m_options.start_line,
714                                                                                   0,
715                                                                                   m_options.num_lines,
716                                                                                   "",
717                                                                                   &result.GetOutputStream(),
718                                                                                   GetBreakpointLocations ());
719 
720                     result.SetStatus (eReturnStatusSuccessFinishResult);
721                 }
722                 else
723                 {
724                     result.AppendErrorWithFormat("No comp unit found for: \"%s.\"\n",
725                                                  m_options.file_name.c_str());
726                     result.SetStatus (eReturnStatusFailed);
727                     return false;
728                 }
729             }
730         }
731         return result.Succeeded();
732     }
733 
734     const SymbolContextList *
735     GetBreakpointLocations ()
736     {
737         if (m_breakpoint_locations.GetFileLineMatches().GetSize() > 0)
738             return &m_breakpoint_locations.GetFileLineMatches();
739         return NULL;
740     }
741     CommandOptions m_options;
742     FileLineResolver m_breakpoint_locations;
743     std::string    m_reverse_name;
744 
745 };
746 
747 OptionDefinition
748 CommandObjectSourceList::CommandOptions::g_option_table[] =
749 {
750 { LLDB_OPT_SET_ALL, false, "count",  'c', required_argument, NULL, 0, eArgTypeCount,   "The number of source lines to display."},
751 { LLDB_OPT_SET_1  |
752   LLDB_OPT_SET_2  , false, "shlib",  's', required_argument, NULL, CommandCompletions::eModuleCompletion, eArgTypeShlibName, "Look up the source file in the given shared library."},
753 { 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."},
754 { LLDB_OPT_SET_1  , false, "file",   'f', required_argument, NULL, CommandCompletions::eSourceFileCompletion, eArgTypeFilename,    "The file from which to display source."},
755 { LLDB_OPT_SET_1  , false, "line",   'l', required_argument, NULL, 0, eArgTypeLineNum,    "The line number at which to start the display source."},
756 { LLDB_OPT_SET_2  , false, "name",   'n', required_argument, NULL, CommandCompletions::eSymbolCompletion, eArgTypeSymbol,    "The name of a function whose source to display."},
757 { LLDB_OPT_SET_3  , false, "address",'a', required_argument, NULL, 0, eArgTypeAddress, "Lookup the address and display the source information for the corresponding file and line."},
758 { 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."},
759 { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
760 };
761 
762 #pragma mark CommandObjectMultiwordSource
763 
764 //-------------------------------------------------------------------------
765 // CommandObjectMultiwordSource
766 //-------------------------------------------------------------------------
767 
768 CommandObjectMultiwordSource::CommandObjectMultiwordSource (CommandInterpreter &interpreter) :
769     CommandObjectMultiword (interpreter,
770                             "source",
771                             "A set of commands for accessing source file information",
772                             "source <subcommand> [<subcommand-options>]")
773 {
774     LoadSubCommand ("info",   CommandObjectSP (new CommandObjectSourceInfo (interpreter)));
775     LoadSubCommand ("list",   CommandObjectSP (new CommandObjectSourceList (interpreter)));
776 }
777 
778 CommandObjectMultiwordSource::~CommandObjectMultiwordSource ()
779 {
780 }
781 
782