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