blob: 65a95db78b5807b43aee2902532f97ba4ebd4118 [file] [log] [blame]
Chris Lattner24943d22010-06-08 16:52:24 +00001//===-- 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
Jim Ingham84cdc152010-06-15 19:49:27 +000016#include "lldb/Interpreter/Args.h"
Greg Clayton63094e02010-06-23 01:19:29 +000017#include "lldb/Core/Debugger.h"
Chris Lattner24943d22010-06-08 16:52:24 +000018#include "lldb/Interpreter/CommandInterpreter.h"
19#include "lldb/Interpreter/CommandReturnObject.h"
Jim Ingham767af882010-07-07 03:36:20 +000020#include "lldb/Core/FileSpec.h"
Chris Lattner24943d22010-06-08 16:52:24 +000021#include "lldb/Target/Process.h"
Jim Ingham767af882010-07-07 03:36:20 +000022#include "lldb/Core/SourceManager.h"
Chris Lattner24943d22010-06-08 16:52:24 +000023#include "lldb/Target/TargetList.h"
Jim Ingham767af882010-07-07 03:36:20 +000024#include "lldb/Interpreter/CommandCompletions.h"
25#include "lldb/Interpreter/Options.h"
Chris Lattner24943d22010-06-08 16:52:24 +000026
27using namespace lldb;
28using namespace lldb_private;
29
Chris Lattner24943d22010-06-08 16:52:24 +000030//-------------------------------------------------------------------------
Jim Ingham767af882010-07-07 03:36:20 +000031// CommandObjectSourceList
Chris Lattner24943d22010-06-08 16:52:24 +000032//-------------------------------------------------------------------------
33
Jim Ingham767af882010-07-07 03:36:20 +000034class CommandObjectSourceInfo : public CommandObject
Chris Lattner24943d22010-06-08 16:52:24 +000035{
Chris Lattner24943d22010-06-08 16:52:24 +000036
Jim Ingham767af882010-07-07 03:36:20 +000037 class CommandOptions : public Options
Chris Lattner24943d22010-06-08 16:52:24 +000038 {
Jim Ingham767af882010-07-07 03:36:20 +000039 public:
40 CommandOptions () :
41 Options()
Chris Lattner24943d22010-06-08 16:52:24 +000042 {
Jim Ingham767af882010-07-07 03:36:20 +000043 }
Chris Lattner24943d22010-06-08 16:52:24 +000044
Jim Ingham767af882010-07-07 03:36:20 +000045 ~CommandOptions ()
46 {
47 }
Chris Lattner24943d22010-06-08 16:52:24 +000048
Jim Ingham767af882010-07-07 03:36:20 +000049 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)
Chris Lattner24943d22010-06-08 16:52:24 +000055 {
Jim Ingham767af882010-07-07 03:36:20 +000056 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;
Chris Lattner24943d22010-06-08 16:52:24 +000061
Jim Ingham767af882010-07-07 03:36:20 +000062 case 'f':
63 file_name = option_arg;
64 break;
65
66 default:
67 error.SetErrorStringWithFormat("Unrecognized short option '%c'.\n", short_option);
68 break;
Chris Lattner24943d22010-06-08 16:52:24 +000069 }
70
Jim Ingham767af882010-07-07 03:36:20 +000071 return error;
72 }
Chris Lattner24943d22010-06-08 16:52:24 +000073
Jim Ingham767af882010-07-07 03:36:20 +000074 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
98public:
99 CommandObjectSourceInfo() :
100 CommandObject ("source info",
Caroline Ticeabb507a2010-09-08 21:06:11 +0000101 "Display information about the source lines from the current executable's debug info.",
Jim Ingham767af882010-07-07 03:36:20 +0000102 "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 }
130protected:
131 CommandOptions m_options;
132};
133
134lldb::OptionDefinition
135CommandObjectSourceInfo::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
147class 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
Jim Ingham338f7532010-08-20 01:17:07 +0000175 case 'c':
Jim Ingham767af882010-07-07 03:36:20 +0000176 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;
Jim Ingham338f7532010-08-20 01:17:07 +0000184
185 case 'n':
186 symbol_name = option_arg;
187 break;
Jim Ingham767af882010-07-07 03:36:20 +0000188
Jim Ingham338f7532010-08-20 01:17:07 +0000189 case 's':
190 m_modules.push_back (std::string (option_arg));
191 break;
Jim Ingham767af882010-07-07 03:36:20 +0000192 default:
193 error.SetErrorStringWithFormat("Unrecognized short option '%c'.\n", short_option);
194 break;
195 }
196
197 return error;
198 }
199
200 void
201 ResetOptionValues ()
202 {
203 Options::ResetOptionValues();
204
205 file_spec.Clear();
206 file_name.clear();
Jim Ingham338f7532010-08-20 01:17:07 +0000207 symbol_name.clear();
Jim Ingham767af882010-07-07 03:36:20 +0000208 start_line = 0;
209 num_lines = 10;
Jim Ingham338f7532010-08-20 01:17:07 +0000210 m_modules.clear();
Jim Ingham767af882010-07-07 03:36:20 +0000211 }
212
213 const lldb::OptionDefinition*
214 GetDefinitions ()
215 {
216 return g_option_table;
217 }
218 static lldb::OptionDefinition g_option_table[];
219
220 // Instance variables to hold the values for command options.
221 FileSpec file_spec;
222 std::string file_name;
Jim Ingham338f7532010-08-20 01:17:07 +0000223 std::string symbol_name;
Jim Ingham767af882010-07-07 03:36:20 +0000224 uint32_t start_line;
225 uint32_t num_lines;
Jim Ingham338f7532010-08-20 01:17:07 +0000226 STLStringArray m_modules;
Jim Ingham767af882010-07-07 03:36:20 +0000227 };
228
229public:
230 CommandObjectSourceList() :
231 CommandObject ("source list",
Caroline Ticeabb507a2010-09-08 21:06:11 +0000232 "Display source code (as specified) based on the current executable's debug info.",
Jim Ingham767af882010-07-07 03:36:20 +0000233 "source list [<cmd-options>] [<filename>]")
234 {
235 }
236
237 ~CommandObjectSourceList ()
238 {
239 }
240
241
242 Options *
243 GetOptions ()
244 {
245 return &m_options;
246 }
247
248
249 bool
250 Execute
251 (
252 CommandInterpreter &interpreter,
253 Args& args,
254 CommandReturnObject &result
255 )
256 {
257 const int argc = args.GetArgumentCount();
258
259 if (argc != 0)
260 {
261 result.AppendErrorWithFormat("'%s' takes no arguments, only flags.\n", GetCommandName());
262 result.SetStatus (eReturnStatusFailed);
263 }
264
265 ExecutionContext exe_ctx(interpreter.GetDebugger().GetExecutionContext());
Jim Ingham338f7532010-08-20 01:17:07 +0000266
267 if (!m_options.symbol_name.empty())
268 {
269 // Displaying the source for a symbol:
Jim Inghamc8332952010-08-26 21:32:51 +0000270 Target *target = interpreter.GetDebugger().GetSelectedTarget().get();
Jim Ingham338f7532010-08-20 01:17:07 +0000271 if (target == NULL)
272 {
273 result.AppendError ("invalid target, set executable file using 'file' command");
274 result.SetStatus (eReturnStatusFailed);
275 return false;
276 }
277
278 SymbolContextList sc_list;
279 ConstString name(m_options.symbol_name.c_str());
280 bool append = true;
281 size_t num_matches = 0;
282
283 if (m_options.m_modules.size() > 0)
284 {
285 ModuleList matching_modules;
286 for (int i = 0; i < m_options.m_modules.size(); i++)
287 {
288 FileSpec module_spec(m_options.m_modules[i].c_str());
289 if (module_spec)
290 {
291 matching_modules.Clear();
292 target->GetImages().FindModules (&module_spec, NULL, NULL, NULL, matching_modules);
293 num_matches += matching_modules.FindFunctions (name, eFunctionNameTypeBase, append, sc_list);
294 }
295 }
296 }
297 else
298 {
299 num_matches = target->GetImages().FindFunctions (name, eFunctionNameTypeBase, append, sc_list);
300 }
301
302 SymbolContext sc;
303
304 if (num_matches == 0)
305 {
306 result.AppendErrorWithFormat("Could not find function named: \"%s\".\n", m_options.symbol_name.c_str());
307 result.SetStatus (eReturnStatusFailed);
308 return false;
309 }
310
311 sc_list.GetContextAtIndex (0, sc);
312 FileSpec start_file;
313 uint32_t start_line;
314 uint32_t end_line;
315 FileSpec end_file;
316 if (sc.function != NULL)
317 {
318 sc.function->GetStartLineSourceInfo (start_file, start_line);
319 if (start_line == 0)
320 {
321 result.AppendErrorWithFormat("Could not find line information for start of function: \"%s\".\n", m_options.symbol_name.c_str());
322 result.SetStatus (eReturnStatusFailed);
323 return false;
324 }
325 sc.function->GetEndLineSourceInfo (end_file, end_line);
326 }
327 else
328 {
329 result.AppendErrorWithFormat("Could not find function info for: \"%s\".\n", m_options.symbol_name.c_str());
330 result.SetStatus (eReturnStatusFailed);
331 return false;
332 }
333
334 if (num_matches > 1)
335 {
336 // This could either be because there are multiple functions of this name, in which case
337 // we'll have to specify this further... Or it could be because there are multiple inlined instances
338 // of one function. So run through the matches and if they all have the same file & line then we can just
339 // list one.
340
341 bool found_multiple = false;
342
343 for (size_t i = 1; i < num_matches; i++)
344 {
345 SymbolContext scratch_sc;
346 sc_list.GetContextAtIndex (i, scratch_sc);
347 if (scratch_sc.function != NULL)
348 {
349 FileSpec scratch_file;
350 uint32_t scratch_line;
351 scratch_sc.function->GetStartLineSourceInfo (scratch_file, scratch_line);
352 if (scratch_file != start_file
353 || scratch_line != start_line)
354 {
355 found_multiple = true;
356 break;
357 }
358 }
359 }
360 if (found_multiple)
361 {
362 StreamString s;
363 for (size_t i = 0; i < num_matches; i++)
364 {
365 SymbolContext scratch_sc;
366 sc_list.GetContextAtIndex (i, scratch_sc);
367 if (scratch_sc.function != NULL)
368 {
369 s.Printf("\n%d: ", i);
370 scratch_sc.function->Dump (&s, true);
371 }
372 }
373 result.AppendErrorWithFormat("Multiple functions found matching: %s: \n%s\n",
374 m_options.symbol_name.c_str(),
375 s.GetData());
376 result.SetStatus (eReturnStatusFailed);
377 return false;
378 }
379 }
380
381
382 // This is a little hacky, but the first line table entry for a function points to the "{" that
383 // starts the function block. It would be nice to actually get the function
384 // declaration in there too. So back up a bit, but not further than what you're going to display.
385 size_t lines_to_back_up = m_options.num_lines >= 10 ? 5 : m_options.num_lines/2;
386 uint32_t line_no;
387 if (start_line <= lines_to_back_up)
388 line_no = 1;
389 else
390 line_no = start_line - lines_to_back_up;
391
392 // For fun, if the function is shorter than the number of lines we're supposed to display,
393 // only display the function...
394 if (end_line != 0)
395 {
396 if (m_options.num_lines > end_line - line_no)
397 m_options.num_lines = end_line - line_no;
398 }
399
400 char path_buf[PATH_MAX+1];
401 start_file.GetPath(path_buf, PATH_MAX);
402 result.AppendMessageWithFormat("File: %s.\n", path_buf);
403 interpreter.GetDebugger().GetSourceManager().DisplaySourceLinesWithLineNumbers (start_file,
404 line_no,
405 0,
406 m_options.num_lines,
407 "",
408 &result.GetOutputStream());
409
410 result.SetStatus (eReturnStatusSuccessFinishResult);
411 return true;
412
413 }
414 else if (m_options.file_name.empty())
Jim Ingham767af882010-07-07 03:36:20 +0000415 {
416 // Last valid source manager context, or the current frame if no
417 // valid last context in source manager.
418 // One little trick here, if you type the exact same list command twice in a row, it is
419 // more likely because you typed it once, then typed it again
420 if (m_options.start_line == 0)
421 {
422 if (interpreter.GetDebugger().GetSourceManager().DisplayMoreWithLineNumbers (&result.GetOutputStream()))
Chris Lattner24943d22010-06-08 16:52:24 +0000423 {
Chris Lattner24943d22010-06-08 16:52:24 +0000424 result.SetStatus (eReturnStatusSuccessFinishResult);
425 }
Jim Ingham767af882010-07-07 03:36:20 +0000426 }
427 else
428 {
429 if (interpreter.GetDebugger().GetSourceManager().DisplaySourceLinesWithLineNumbersUsingLastFile(
430 m_options.start_line, // Line to display
431 0, // Lines before line to display
432 m_options.num_lines, // Lines after line to display
433 "", // Don't mark "line"
434 &result.GetOutputStream()))
Chris Lattner24943d22010-06-08 16:52:24 +0000435 {
Jim Ingham767af882010-07-07 03:36:20 +0000436 result.SetStatus (eReturnStatusSuccessFinishResult);
Chris Lattner24943d22010-06-08 16:52:24 +0000437 }
Jim Ingham767af882010-07-07 03:36:20 +0000438
Chris Lattner24943d22010-06-08 16:52:24 +0000439 }
440 }
441 else
442 {
Jim Ingham767af882010-07-07 03:36:20 +0000443 const char *filename = m_options.file_name.c_str();
Jim Inghamc8332952010-08-26 21:32:51 +0000444 Target *target = interpreter.GetDebugger().GetSelectedTarget().get();
Jim Ingham767af882010-07-07 03:36:20 +0000445 if (target == NULL)
446 {
447 result.AppendError ("invalid target, set executable file using 'file' command");
448 result.SetStatus (eReturnStatusFailed);
449 return false;
450 }
451
452
453 bool check_inlines = false;
454 SymbolContextList sc_list;
Jim Ingham338f7532010-08-20 01:17:07 +0000455 size_t num_matches = 0;
456
457 if (m_options.m_modules.size() > 0)
Jim Ingham767af882010-07-07 03:36:20 +0000458 {
Jim Ingham338f7532010-08-20 01:17:07 +0000459 ModuleList matching_modules;
460 for (int i = 0; i < m_options.m_modules.size(); i++)
Jim Ingham767af882010-07-07 03:36:20 +0000461 {
Jim Ingham338f7532010-08-20 01:17:07 +0000462 FileSpec module_spec(m_options.m_modules[i].c_str());
463 if (module_spec)
Jim Ingham767af882010-07-07 03:36:20 +0000464 {
Jim Ingham338f7532010-08-20 01:17:07 +0000465 matching_modules.Clear();
466 target->GetImages().FindModules (&module_spec, NULL, NULL, NULL, matching_modules);
467 num_matches += matching_modules.ResolveSymbolContextForFilePath (filename,
468 0,
469 check_inlines,
470 eSymbolContextModule | eSymbolContextCompUnit,
471 sc_list);
Jim Ingham767af882010-07-07 03:36:20 +0000472 }
473 }
474 }
Jim Ingham338f7532010-08-20 01:17:07 +0000475 else
476 {
477 num_matches = target->GetImages().ResolveSymbolContextForFilePath (filename,
478 0,
479 check_inlines,
480 eSymbolContextModule | eSymbolContextCompUnit,
481 sc_list);
482 }
483
484 if (num_matches == 0)
485 {
486 result.AppendErrorWithFormat("Could not find source file \"%s\".\n",
487 m_options.file_name.c_str());
488 result.SetStatus (eReturnStatusFailed);
489 return false;
490 }
491
492 if (num_matches > 1)
493 {
494 SymbolContext sc;
495 bool got_multiple = false;
496 FileSpec *test_cu_spec = NULL;
Chris Lattner24943d22010-06-08 16:52:24 +0000497
Jim Ingham338f7532010-08-20 01:17:07 +0000498 for (int i = 0; i < num_matches; i++)
499 {
500 sc_list.GetContextAtIndex(i, sc);
501 if (sc.comp_unit)
502 {
503 if (test_cu_spec)
504 {
505 if (test_cu_spec != static_cast<FileSpec *> (sc.comp_unit))
506 got_multiple = true;
507 break;
508 }
509 else
510 test_cu_spec = sc.comp_unit;
511 }
512 }
513 if (got_multiple)
514 {
515 result.AppendErrorWithFormat("Multiple source files found matching: \"%s.\"\n",
516 m_options.file_name.c_str());
517 result.SetStatus (eReturnStatusFailed);
518 return false;
519 }
520 }
521
522 SymbolContext sc;
523 if (sc_list.GetContextAtIndex(0, sc))
524 {
525 if (sc.comp_unit)
526 {
527 interpreter.GetDebugger().GetSourceManager().DisplaySourceLinesWithLineNumbers (sc.comp_unit,
528 m_options.start_line,
529 0,
530 m_options.num_lines,
531 "",
532 &result.GetOutputStream());
533
534 result.SetStatus (eReturnStatusSuccessFinishResult);
535 }
536 else
537 {
538 result.AppendErrorWithFormat("No comp unit found for: \"%s.\"\n",
539 m_options.file_name.c_str());
540 result.SetStatus (eReturnStatusFailed);
541 return false;
542 }
543 }
544 }
Jim Ingham767af882010-07-07 03:36:20 +0000545 return result.Succeeded();
Chris Lattner24943d22010-06-08 16:52:24 +0000546 }
Jim Ingham767af882010-07-07 03:36:20 +0000547
548 virtual const char *GetRepeatCommand (Args &current_command_args, uint32_t index)
Chris Lattner24943d22010-06-08 16:52:24 +0000549 {
Jim Ingham767af882010-07-07 03:36:20 +0000550 return m_cmd_name.c_str();
Chris Lattner24943d22010-06-08 16:52:24 +0000551 }
Chris Lattner24943d22010-06-08 16:52:24 +0000552
Jim Ingham767af882010-07-07 03:36:20 +0000553protected:
554 CommandOptions m_options;
555
556};
557
558lldb::OptionDefinition
559CommandObjectSourceList::CommandOptions::g_option_table[] =
560{
Jim Ingham338f7532010-08-20 01:17:07 +0000561{ LLDB_OPT_SET_ALL, false, "count", 'c', required_argument, NULL, 0, "<count>", "The number of source lines to display."},
562{ LLDB_OPT_SET_ALL, false, "shlib", 's', required_argument, NULL, CommandCompletions::eModuleCompletion, "<shlib-name>",
563 "Look up the source file in the given shared library."},
Jim Ingham767af882010-07-07 03:36:20 +0000564{ LLDB_OPT_SET_1, false, "file", 'f', required_argument, NULL, CommandCompletions::eSourceFileCompletion, "<file>", "The file from which to display source."},
Jim Ingham338f7532010-08-20 01:17:07 +0000565{ LLDB_OPT_SET_1, false, "line", 'l', required_argument, NULL, 0, "<line>", "The line number at which to start the display source."},
566{ LLDB_OPT_SET_2, false, "name", 'n', required_argument, NULL, CommandCompletions::eSymbolCompletion, "<symbol>", "The name of a function whose source to display."},
Jim Ingham767af882010-07-07 03:36:20 +0000567{ 0, false, NULL, 0, 0, NULL, 0, NULL, NULL }
568};
569
570#pragma mark CommandObjectMultiwordSource
571
572//-------------------------------------------------------------------------
573// CommandObjectMultiwordSource
574//-------------------------------------------------------------------------
575
576CommandObjectMultiwordSource::CommandObjectMultiwordSource (CommandInterpreter &interpreter) :
577 CommandObjectMultiword ("source",
Caroline Ticec1ad82e2010-09-07 22:38:08 +0000578 "A set of commands for accessing source file information",
Jim Ingham767af882010-07-07 03:36:20 +0000579 "source <subcommand> [<subcommand-options>]")
580{
581 LoadSubCommand (interpreter, "info", CommandObjectSP (new CommandObjectSourceInfo ()));
582 LoadSubCommand (interpreter, "list", CommandObjectSP (new CommandObjectSourceList ()));
Chris Lattner24943d22010-06-08 16:52:24 +0000583}
Jim Ingham767af882010-07-07 03:36:20 +0000584
585CommandObjectMultiwordSource::~CommandObjectMultiwordSource ()
586{
587}
588