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 "CommandObjectSource.h"
11 
12 // C Includes
13 // C++ Includes
14 // Other libraries and framework includes
15 // Project includes
16 #include "lldb/Interpreter/Args.h"
17 #include "lldb/Core/Debugger.h"
18 #include "lldb/Interpreter/CommandInterpreter.h"
19 #include "lldb/Interpreter/CommandReturnObject.h"
20 #include "lldb/Core/FileSpec.h"
21 #include "lldb/Target/Process.h"
22 #include "lldb/Core/SourceManager.h"
23 #include "lldb/Target/TargetList.h"
24 #include "lldb/Interpreter/CommandCompletions.h"
25 #include "lldb/Interpreter/Options.h"
26 
27 using namespace lldb;
28 using namespace lldb_private;
29 
30 //-------------------------------------------------------------------------
31 // CommandObjectSourceList
32 //-------------------------------------------------------------------------
33 
34 class CommandObjectSourceInfo : public CommandObject
35 {
36 
37     class CommandOptions : public Options
38     {
39     public:
40         CommandOptions () :
41             Options()
42         {
43         }
44 
45         ~CommandOptions ()
46         {
47         }
48 
49         Error
50         SetOptionValue (int option_idx, const char *option_arg)
51         {
52             Error error;
53             const char short_option = g_option_table[option_idx].short_option;
54             switch (short_option)
55             {
56             case 'l':
57                 start_line = Args::StringToUInt32 (option_arg, 0);
58                 if (start_line == 0)
59                     error.SetErrorStringWithFormat("Invalid line number: '%s'.\n", option_arg);
60                 break;
61 
62              case 'f':
63                 file_name = option_arg;
64                 break;
65 
66            default:
67                 error.SetErrorStringWithFormat("Unrecognized short option '%c'.\n", short_option);
68                 break;
69             }
70 
71             return error;
72         }
73 
74         void
75         ResetOptionValues ()
76         {
77             Options::ResetOptionValues();
78 
79             file_spec.Clear();
80             file_name.clear();
81             start_line = 0;
82         }
83 
84         const lldb::OptionDefinition*
85         GetDefinitions ()
86         {
87             return g_option_table;
88         }
89         static lldb::OptionDefinition g_option_table[];
90 
91         // Instance variables to hold the values for command options.
92         FileSpec file_spec;
93         std::string file_name;
94         uint32_t start_line;
95 
96     };
97 
98 public:
99     CommandObjectSourceInfo() :
100         CommandObject ("source info",
101                          "Display info on the source lines from the current executable's debug info.",
102                          "source info [<cmd-options>]")
103     {
104     }
105 
106     ~CommandObjectSourceInfo ()
107     {
108     }
109 
110 
111     Options *
112     GetOptions ()
113     {
114         return &m_options;
115     }
116 
117 
118     bool
119     Execute
120     (
121         CommandInterpreter &interpreter,
122         Args& args,
123         CommandReturnObject &result
124     )
125     {
126         result.AppendError ("Not yet implemented");
127         result.SetStatus (eReturnStatusFailed);
128         return false;
129     }
130 protected:
131     CommandOptions m_options;
132 };
133 
134 lldb::OptionDefinition
135 CommandObjectSourceInfo::CommandOptions::g_option_table[] =
136 {
137 { LLDB_OPT_SET_1, false, "line",       'l', required_argument, NULL, 0, "<line>",    "The line number at which to start the display source."},
138 { LLDB_OPT_SET_1, false, "file",       'f', required_argument, NULL, CommandCompletions::eSourceFileCompletion, "<file>",    "The file from which to display source."},
139 { 0, false, NULL, 0, 0, NULL, 0, NULL, NULL }
140 };
141 
142 #pragma mark CommandObjectSourceList
143 //-------------------------------------------------------------------------
144 // CommandObjectSourceList
145 //-------------------------------------------------------------------------
146 
147 class CommandObjectSourceList : public CommandObject
148 {
149 
150     class CommandOptions : public Options
151     {
152     public:
153         CommandOptions () :
154             Options()
155         {
156         }
157 
158         ~CommandOptions ()
159         {
160         }
161 
162         Error
163         SetOptionValue (int option_idx, const char *option_arg)
164         {
165             Error error;
166             const char short_option = g_option_table[option_idx].short_option;
167             switch (short_option)
168             {
169             case 'l':
170                 start_line = Args::StringToUInt32 (option_arg, 0);
171                 if (start_line == 0)
172                     error.SetErrorStringWithFormat("Invalid line number: '%s'.\n", option_arg);
173                 break;
174 
175             case 'n':
176                 num_lines = Args::StringToUInt32 (option_arg, 0);
177                 if (num_lines == 0)
178                     error.SetErrorStringWithFormat("Invalid line count: '%s'.\n", option_arg);
179                 break;
180 
181              case 'f':
182                 file_name = option_arg;
183                 break;
184 
185            default:
186                 error.SetErrorStringWithFormat("Unrecognized short option '%c'.\n", short_option);
187                 break;
188             }
189 
190             return error;
191         }
192 
193         void
194         ResetOptionValues ()
195         {
196             Options::ResetOptionValues();
197 
198             file_spec.Clear();
199             file_name.clear();
200             start_line = 0;
201             num_lines = 10;
202         }
203 
204         const lldb::OptionDefinition*
205         GetDefinitions ()
206         {
207             return g_option_table;
208         }
209         static lldb::OptionDefinition g_option_table[];
210 
211         // Instance variables to hold the values for command options.
212         FileSpec file_spec;
213         std::string file_name;
214         uint32_t start_line;
215         uint32_t num_lines;
216 
217     };
218 
219 public:
220     CommandObjectSourceList() :
221         CommandObject ("source list",
222                          "Display source files from the current executable's debug info.",
223                          "source list [<cmd-options>] [<filename>]")
224     {
225     }
226 
227     ~CommandObjectSourceList ()
228     {
229     }
230 
231 
232     Options *
233     GetOptions ()
234     {
235         return &m_options;
236     }
237 
238 
239     bool
240     Execute
241     (
242         CommandInterpreter &interpreter,
243         Args& args,
244         CommandReturnObject &result
245     )
246     {
247         const int argc = args.GetArgumentCount();
248 
249         if (argc != 0)
250         {
251             result.AppendErrorWithFormat("'%s' takes no arguments, only flags.\n", GetCommandName());
252             result.SetStatus (eReturnStatusFailed);
253         }
254 
255         ExecutionContext exe_ctx(interpreter.GetDebugger().GetExecutionContext());
256         if (m_options.file_name.empty())
257         {
258             // Last valid source manager context, or the current frame if no
259             // valid last context in source manager.
260             // One little trick here, if you type the exact same list command twice in a row, it is
261             // more likely because you typed it once, then typed it again
262             if (m_options.start_line == 0)
263             {
264                 if (interpreter.GetDebugger().GetSourceManager().DisplayMoreWithLineNumbers (&result.GetOutputStream()))
265                 {
266                     result.SetStatus (eReturnStatusSuccessFinishResult);
267                 }
268             }
269             else
270             {
271                 if (interpreter.GetDebugger().GetSourceManager().DisplaySourceLinesWithLineNumbersUsingLastFile(
272                             m_options.start_line,   // Line to display
273                             0,                      // Lines before line to display
274                             m_options.num_lines,    // Lines after line to display
275                             "",                     // Don't mark "line"
276                             &result.GetOutputStream()))
277                 {
278                     result.SetStatus (eReturnStatusSuccessFinishResult);
279                 }
280 
281             }
282         }
283         else
284         {
285             const char *filename = m_options.file_name.c_str();
286             Target *target = interpreter.GetDebugger().GetCurrentTarget().get();
287             if (target == NULL)
288             {
289                 result.AppendError ("invalid target, set executable file using 'file' command");
290                 result.SetStatus (eReturnStatusFailed);
291                 return false;
292             }
293 
294 
295             bool check_inlines = false;
296             SymbolContextList sc_list;
297             size_t num_matches = target->GetImages().ResolveSymbolContextForFilePath (filename,
298                                                                                       0,
299                                                                                       check_inlines,
300                                                                                       eSymbolContextModule | eSymbolContextCompUnit,
301                                                                                       sc_list);
302             if (num_matches > 0)
303             {
304                 SymbolContext sc;
305                 if (sc_list.GetContextAtIndex(0, sc))
306                 {
307                     if (sc.comp_unit)
308                     {
309                         interpreter.GetDebugger().GetSourceManager().DisplaySourceLinesWithLineNumbers (sc.comp_unit,
310                                                                                                          m_options.start_line,   // Line to display
311                                                                                                          0,                      // Lines before line to display
312                                                                                                          m_options.num_lines,    // Lines after line to display
313                                                                                                          "",                     // Don't mark "line"
314                                                                                                          &result.GetOutputStream());
315 
316                         result.SetStatus (eReturnStatusSuccessFinishResult);
317 
318                     }
319                 }
320             }
321         }
322 
323         return result.Succeeded();
324     }
325 
326     virtual const char *GetRepeatCommand (Args &current_command_args, uint32_t index)
327     {
328         return m_cmd_name.c_str();
329     }
330 
331 protected:
332     CommandOptions m_options;
333 
334 };
335 
336 lldb::OptionDefinition
337 CommandObjectSourceList::CommandOptions::g_option_table[] =
338 {
339 { LLDB_OPT_SET_1, false, "line",       'l', required_argument, NULL, 0, "<line>",    "The line number at which to start the display source."},
340 { LLDB_OPT_SET_1, false, "file",       'f', required_argument, NULL, CommandCompletions::eSourceFileCompletion, "<file>",    "The file from which to display source."},
341 { LLDB_OPT_SET_1, false, "count",      'n', required_argument, NULL, 0, "<count>",   "The number of source lines to display."},
342 { 0, false, NULL, 0, 0, NULL, 0, NULL, NULL }
343 };
344 
345 #pragma mark CommandObjectMultiwordSource
346 
347 //-------------------------------------------------------------------------
348 // CommandObjectMultiwordSource
349 //-------------------------------------------------------------------------
350 
351 CommandObjectMultiwordSource::CommandObjectMultiwordSource (CommandInterpreter &interpreter) :
352     CommandObjectMultiword ("source",
353                             "Commands for accessing source file information",
354                             "source <subcommand> [<subcommand-options>]")
355 {
356     LoadSubCommand (interpreter, "info",   CommandObjectSP (new CommandObjectSourceInfo ()));
357     LoadSubCommand (interpreter, "list",   CommandObjectSP (new CommandObjectSourceList ()));
358 }
359 
360 CommandObjectMultiwordSource::~CommandObjectMultiwordSource ()
361 {
362 }
363 
364