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