xref: /llvm-project/lldb/source/Commands/CommandObjectFrame.cpp (revision c482a1929490ca2bcba5060d99a06b06bf3edac9)
1 //===-- CommandObjectFrame.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 "CommandObjectFrame.h"
11 
12 // C Includes
13 // C++ Includes
14 // Other libraries and framework includes
15 // Project includes
16 #include "lldb/Core/Debugger.h"
17 #include "lldb/Core/FormatManager.h"
18 #include "lldb/Core/Module.h"
19 #include "lldb/Core/StreamFile.h"
20 #include "lldb/Core/Timer.h"
21 #include "lldb/Core/Value.h"
22 #include "lldb/Core/ValueObject.h"
23 #include "lldb/Core/ValueObjectVariable.h"
24 #include "lldb/Host/Host.h"
25 #include "lldb/Interpreter/Args.h"
26 #include "lldb/Interpreter/CommandInterpreter.h"
27 #include "lldb/Interpreter/CommandReturnObject.h"
28 #include "lldb/Interpreter/Options.h"
29 #include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
30 #include "lldb/Interpreter/OptionGroupVariable.h"
31 #include "lldb/Symbol/ClangASTType.h"
32 #include "lldb/Symbol/ClangASTContext.h"
33 #include "lldb/Symbol/ObjectFile.h"
34 #include "lldb/Symbol/SymbolContext.h"
35 #include "lldb/Symbol/Type.h"
36 #include "lldb/Symbol/Variable.h"
37 #include "lldb/Symbol/VariableList.h"
38 #include "lldb/Target/Process.h"
39 #include "lldb/Target/StackFrame.h"
40 #include "lldb/Target/Thread.h"
41 #include "lldb/Target/Target.h"
42 
43 using namespace lldb;
44 using namespace lldb_private;
45 
46 #pragma mark CommandObjectFrameInfo
47 
48 //-------------------------------------------------------------------------
49 // CommandObjectFrameInfo
50 //-------------------------------------------------------------------------
51 
52 class CommandObjectFrameInfo : public CommandObject
53 {
54 public:
55 
56     CommandObjectFrameInfo (CommandInterpreter &interpreter) :
57         CommandObject (interpreter,
58                        "frame info",
59                        "List information about the currently selected frame in the current thread.",
60                        "frame info",
61                        eFlagProcessMustBeLaunched | eFlagProcessMustBePaused)
62     {
63     }
64 
65     ~CommandObjectFrameInfo ()
66     {
67     }
68 
69     bool
70     Execute (Args& command,
71              CommandReturnObject &result)
72     {
73         ExecutionContext exe_ctx(m_interpreter.GetExecutionContext());
74         if (exe_ctx.frame)
75         {
76             exe_ctx.frame->DumpUsingSettingsFormat (&result.GetOutputStream());
77             result.SetStatus (eReturnStatusSuccessFinishResult);
78         }
79         else
80         {
81             result.AppendError ("no current frame");
82             result.SetStatus (eReturnStatusFailed);
83         }
84         return result.Succeeded();
85     }
86 };
87 
88 #pragma mark CommandObjectFrameSelect
89 
90 //-------------------------------------------------------------------------
91 // CommandObjectFrameSelect
92 //-------------------------------------------------------------------------
93 
94 class CommandObjectFrameSelect : public CommandObject
95 {
96 public:
97 
98    class CommandOptions : public Options
99     {
100     public:
101 
102         CommandOptions (CommandInterpreter &interpreter) :
103             Options(interpreter)
104         {
105             OptionParsingStarting ();
106         }
107 
108         virtual
109         ~CommandOptions ()
110         {
111         }
112 
113         virtual Error
114         SetOptionValue (uint32_t option_idx, const char *option_arg)
115         {
116             Error error;
117             bool success = false;
118             char short_option = (char) m_getopt_table[option_idx].val;
119             switch (short_option)
120             {
121             case 'r':
122                 relative_frame_offset = Args::StringToSInt32 (option_arg, INT32_MIN, 0, &success);
123                 if (!success)
124                     error.SetErrorStringWithFormat ("invalid frame offset argument '%s'.\n", option_arg);
125                 break;
126 
127             default:
128                 error.SetErrorStringWithFormat ("Invalid short option character '%c'.\n", short_option);
129                 break;
130             }
131 
132             return error;
133         }
134 
135         void
136         OptionParsingStarting ()
137         {
138             relative_frame_offset = INT32_MIN;
139         }
140 
141         const OptionDefinition*
142         GetDefinitions ()
143         {
144             return g_option_table;
145         }
146 
147         // Options table: Required for subclasses of Options.
148 
149         static OptionDefinition g_option_table[];
150         int32_t relative_frame_offset;
151     };
152 
153     CommandObjectFrameSelect (CommandInterpreter &interpreter) :
154         CommandObject (interpreter,
155                        "frame select",
156                        "Select a frame by index from within the current thread and make it the current frame.",
157                        NULL,
158                        eFlagProcessMustBeLaunched | eFlagProcessMustBePaused),
159         m_options (interpreter)
160     {
161         CommandArgumentEntry arg;
162         CommandArgumentData index_arg;
163 
164         // Define the first (and only) variant of this arg.
165         index_arg.arg_type = eArgTypeFrameIndex;
166         index_arg.arg_repetition = eArgRepeatOptional;
167 
168         // There is only one variant this argument could be; put it into the argument entry.
169         arg.push_back (index_arg);
170 
171         // Push the data for the first argument into the m_arguments vector.
172         m_arguments.push_back (arg);
173     }
174 
175     ~CommandObjectFrameSelect ()
176     {
177     }
178 
179     virtual
180     Options *
181     GetOptions ()
182     {
183         return &m_options;
184     }
185 
186 
187     bool
188     Execute (Args& command,
189              CommandReturnObject &result)
190     {
191         ExecutionContext exe_ctx (m_interpreter.GetExecutionContext());
192         if (exe_ctx.thread)
193         {
194             const uint32_t num_frames = exe_ctx.thread->GetStackFrameCount();
195             uint32_t frame_idx = UINT32_MAX;
196             if (m_options.relative_frame_offset != INT32_MIN)
197             {
198                 // The one and only argument is a signed relative frame index
199                 frame_idx = exe_ctx.thread->GetSelectedFrameIndex ();
200                 if (frame_idx == UINT32_MAX)
201                     frame_idx = 0;
202 
203                 if (m_options.relative_frame_offset < 0)
204                 {
205                     if (frame_idx >= -m_options.relative_frame_offset)
206                         frame_idx += m_options.relative_frame_offset;
207                     else
208                         frame_idx = 0;
209                 }
210                 else if (m_options.relative_frame_offset > 0)
211                 {
212                     if (num_frames - frame_idx > m_options.relative_frame_offset)
213                         frame_idx += m_options.relative_frame_offset;
214                     else
215                         frame_idx = num_frames - 1;
216                 }
217             }
218             else
219             {
220                 if (command.GetArgumentCount() == 1)
221                 {
222                     const char *frame_idx_cstr = command.GetArgumentAtIndex(0);
223                     frame_idx = Args::StringToUInt32 (frame_idx_cstr, UINT32_MAX, 0);
224                 }
225                 else
226                 {
227                     result.AppendError ("invalid arguments.\n");
228                     m_options.GenerateOptionUsage (result.GetErrorStream(), this);
229                 }
230             }
231 
232             if (frame_idx < num_frames)
233             {
234                 exe_ctx.thread->SetSelectedFrameByIndex (frame_idx);
235                 exe_ctx.frame = exe_ctx.thread->GetSelectedFrame ().get();
236 
237                 if (exe_ctx.frame)
238                 {
239                     bool already_shown = false;
240                     SymbolContext frame_sc(exe_ctx.frame->GetSymbolContext(eSymbolContextLineEntry));
241                     if (m_interpreter.GetDebugger().GetUseExternalEditor() && frame_sc.line_entry.file && frame_sc.line_entry.line != 0)
242                     {
243                         already_shown = Host::OpenFileInExternalEditor (frame_sc.line_entry.file, frame_sc.line_entry.line);
244                     }
245 
246                     bool show_frame_info = true;
247                     bool show_source = !already_shown;
248                     uint32_t source_lines_before = 3;
249                     uint32_t source_lines_after = 3;
250                     if (exe_ctx.frame->GetStatus(result.GetOutputStream(),
251                                                  show_frame_info,
252                                                  show_source,
253                                                  source_lines_before,
254                                                  source_lines_after))
255                     {
256                         result.SetStatus (eReturnStatusSuccessFinishResult);
257                         return result.Succeeded();
258                     }
259                 }
260             }
261             result.AppendErrorWithFormat ("Frame index (%u) out of range.\n", frame_idx);
262         }
263         else
264         {
265             result.AppendError ("no current thread");
266         }
267         result.SetStatus (eReturnStatusFailed);
268         return false;
269     }
270 protected:
271 
272     CommandOptions m_options;
273 };
274 
275 OptionDefinition
276 CommandObjectFrameSelect::CommandOptions::g_option_table[] =
277 {
278 { LLDB_OPT_SET_1, false, "relative", 'r', required_argument, NULL, 0, eArgTypeOffset, "A relative frame index offset from the current frame index."},
279 { 0, false, NULL, 0, 0, NULL, NULL, eArgTypeNone, NULL }
280 };
281 
282 #pragma mark CommandObjectFrameVariable
283 //----------------------------------------------------------------------
284 // List images with associated information
285 //----------------------------------------------------------------------
286 class CommandObjectFrameVariable : public CommandObject
287 {
288 public:
289 
290     class OptionGroupFrameVariable : public OptionGroup
291     {
292     public:
293 
294         OptionGroupFrameVariable ()
295         {
296         }
297 
298         virtual
299         ~OptionGroupFrameVariable ()
300         {
301         }
302 
303         virtual uint32_t
304         GetNumDefinitions ();
305 
306         virtual const OptionDefinition*
307         GetDefinitions ()
308         {
309             return g_option_table;
310         }
311 
312         virtual Error
313         SetOptionValue (CommandInterpreter &interpreter,
314                         uint32_t option_idx,
315                         const char *option_arg)
316         {
317             Error error;
318             char short_option = (char) g_option_table[option_idx].short_option;
319             switch (short_option)
320             {
321             case 'r':   use_regex    = true;  break;
322             case 'a':   show_args    = false; break;
323             case 'l':   show_locals  = false; break;
324             case 'g':   show_globals = true;  break;
325             case 'c':   show_decl    = true;  break;
326             case 'f':   error = Args::StringToFormat(option_arg, format, NULL); break;
327             case 'G':
328                 globals.push_back(ConstString (option_arg));
329                 break;
330             case 's':
331                 show_scope = true;
332                 break;
333 
334             default:
335                 error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option);
336                 break;
337             }
338 
339             return error;
340         }
341 
342         virtual void
343         OptionParsingStarting (CommandInterpreter &interpreter)
344         {
345             show_args     = true;
346             show_decl     = false;
347             format        = eFormatDefault;
348             show_globals  = false;
349             show_locals   = true;
350             use_regex     = false;
351             show_scope    = false;
352             globals.clear();
353         }
354 
355         // Options table: Required for subclasses of Options.
356 
357         static OptionDefinition g_option_table[];
358 
359         bool use_regex:1,
360              show_args:1,
361              show_locals:1,
362              show_globals:1,
363              show_scope:1,
364              show_decl:1;
365         lldb::Format format; // The format to use when dumping variables or children of variables
366         std::vector<ConstString> globals;
367         // Instance variables to hold the values for command options.
368     };
369 
370     CommandObjectFrameVariable (CommandInterpreter &interpreter) :
371         CommandObject (interpreter,
372                        "frame variable",
373                        "Show frame variables. All argument and local variables "
374                        "that are in scope will be shown when no arguments are given. "
375                        "If any arguments are specified, they can be names of "
376                        "argument, local, file static and file global variables. "
377                        "Children of aggregate variables can be specified such as "
378                        "'var->child.x'.",
379                        NULL,
380                        eFlagProcessMustBeLaunched | eFlagProcessMustBePaused),
381         m_option_group (interpreter),
382         m_option_variable(true), // Include the frame specific options by passing "true"
383         m_varobj_options()
384     {
385         CommandArgumentEntry arg;
386         CommandArgumentData var_name_arg;
387 
388         // Define the first (and only) variant of this arg.
389         var_name_arg.arg_type = eArgTypeVarName;
390         var_name_arg.arg_repetition = eArgRepeatStar;
391 
392         // There is only one variant this argument could be; put it into the argument entry.
393         arg.push_back (var_name_arg);
394 
395         // Push the data for the first argument into the m_arguments vector.
396         m_arguments.push_back (arg);
397 
398         m_option_group.Append (&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
399         m_option_group.Append (&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
400         m_option_group.Finalize();
401     }
402 
403     virtual
404     ~CommandObjectFrameVariable ()
405     {
406     }
407 
408     virtual
409     Options *
410     GetOptions ()
411     {
412         return &m_option_group;
413     }
414 
415 
416     virtual bool
417     Execute
418     (
419         Args& command,
420         CommandReturnObject &result
421     )
422     {
423         ExecutionContext exe_ctx(m_interpreter.GetExecutionContext());
424         if (exe_ctx.frame == NULL)
425         {
426             result.AppendError ("you must be stopped in a valid stack frame to view frame variables.");
427             result.SetStatus (eReturnStatusFailed);
428             return false;
429         }
430         else
431         {
432             Stream &s = result.GetOutputStream();
433 
434             bool get_file_globals = true;
435             VariableList *variable_list = exe_ctx.frame->GetVariableList (get_file_globals);
436 
437             VariableSP var_sp;
438             ValueObjectSP valobj_sp;
439 
440             const char *name_cstr = NULL;
441             size_t idx;
442 
443             SummaryFormatSP summary_format_sp;
444             if (!m_option_variable.summary.empty())
445                 DataVisualization::NamedSummaryFormats::Get(ConstString(m_option_variable.summary.c_str()), summary_format_sp);
446 
447             ValueObject::DumpValueObjectOptions options;
448 
449             options.SetPointerDepth(m_varobj_options.ptr_depth)
450                    .SetMaximumDepth(m_varobj_options.max_depth)
451                    .SetShowTypes(m_varobj_options.show_types)
452                    .SetShowLocation(m_varobj_options.show_location)
453                    .SetUseObjectiveC(m_varobj_options.use_objc)
454                    .SetUseDynamicType(m_varobj_options.use_dynamic)
455                    .SetUseSyntheticValue((lldb::SyntheticValueType)m_varobj_options.use_synth)
456                    .SetFlatOutput(m_varobj_options.flat_output)
457                    .SetOmitSummaryDepth(m_varobj_options.no_summary_depth)
458                    .SetIgnoreCap(m_varobj_options.ignore_cap);
459 
460             if (m_varobj_options.be_raw)
461                 options.SetRawDisplay(true);
462 
463             if (variable_list)
464             {
465                 if (command.GetArgumentCount() > 0)
466                 {
467                     VariableList regex_var_list;
468 
469                     // If we have any args to the variable command, we will make
470                     // variable objects from them...
471                     for (idx = 0; (name_cstr = command.GetArgumentAtIndex(idx)) != NULL; ++idx)
472                     {
473                         if (m_option_variable.use_regex)
474                         {
475                             const uint32_t regex_start_index = regex_var_list.GetSize();
476                             RegularExpression regex (name_cstr);
477                             if (regex.Compile(name_cstr))
478                             {
479                                 size_t num_matches = 0;
480                                 const size_t num_new_regex_vars = variable_list->AppendVariablesIfUnique(regex,
481                                                                                                          regex_var_list,
482                                                                                                          num_matches);
483                                 if (num_new_regex_vars > 0)
484                                 {
485                                     for (uint32_t regex_idx = regex_start_index, end_index = regex_var_list.GetSize();
486                                          regex_idx < end_index;
487                                          ++regex_idx)
488                                     {
489                                         var_sp = regex_var_list.GetVariableAtIndex (regex_idx);
490                                         if (var_sp)
491                                         {
492                                             valobj_sp = exe_ctx.frame->GetValueObjectForFrameVariable (var_sp, m_varobj_options.use_dynamic);
493                                             if (valobj_sp)
494                                             {
495                                                 if (m_option_variable.format != eFormatDefault)
496                                                     valobj_sp->SetFormat (m_option_variable.format);
497 
498                                                 if (m_option_variable.show_decl && var_sp->GetDeclaration ().GetFile())
499                                                 {
500                                                     bool show_fullpaths = false;
501                                                     bool show_module = true;
502                                                     if (var_sp->DumpDeclaration(&s, show_fullpaths, show_module))
503                                                         s.PutCString (": ");
504                                                 }
505                                                 if (summary_format_sp)
506                                                     valobj_sp->SetCustomSummaryFormat(summary_format_sp);
507                                                 ValueObject::DumpValueObject (result.GetOutputStream(),
508                                                                               valobj_sp.get(),
509                                                                               options);
510                                             }
511                                         }
512                                     }
513                                 }
514                                 else if (num_matches == 0)
515                                 {
516                                     result.GetErrorStream().Printf ("error: no variables matched the regular expression '%s'.\n", name_cstr);
517                                 }
518                             }
519                             else
520                             {
521                                 char regex_error[1024];
522                                 if (regex.GetErrorAsCString(regex_error, sizeof(regex_error)))
523                                     result.GetErrorStream().Printf ("error: %s\n", regex_error);
524                                 else
525                                     result.GetErrorStream().Printf ("error: unkown regex error when compiling '%s'\n", name_cstr);
526                             }
527                         }
528                         else
529                         {
530                             Error error;
531                             uint32_t expr_path_options = StackFrame::eExpressionPathOptionCheckPtrVsMember;
532                             lldb::VariableSP var_sp;
533                             valobj_sp = exe_ctx.frame->GetValueForVariableExpressionPath (name_cstr,
534                                                                                           m_varobj_options.use_dynamic,
535                                                                                           expr_path_options,
536                                                                                           var_sp,
537                                                                                           error);
538                             if (valobj_sp)
539                             {
540                                 if (m_option_variable.format != eFormatDefault)
541                                     valobj_sp->SetFormat (m_option_variable.format);
542                                 if (m_option_variable.show_decl && var_sp && var_sp->GetDeclaration ().GetFile())
543                                 {
544                                     var_sp->GetDeclaration ().DumpStopContext (&s, false);
545                                     s.PutCString (": ");
546                                 }
547                                 if (summary_format_sp)
548                                     valobj_sp->SetCustomSummaryFormat(summary_format_sp);
549                                 ValueObject::DumpValueObject (result.GetOutputStream(),
550                                                               valobj_sp.get(),
551                                                               valobj_sp->GetParent() ? name_cstr : NULL,
552                                                               options);
553                             }
554                             else
555                             {
556                                 const char *error_cstr = error.AsCString(NULL);
557                                 if (error_cstr)
558                                     result.GetErrorStream().Printf("error: %s\n", error_cstr);
559                                 else
560                                     result.GetErrorStream().Printf ("error: unable to find any variable expression path that matches '%s'\n", name_cstr);
561                             }
562                         }
563                     }
564                 }
565                 else
566                 {
567                     const uint32_t num_variables = variable_list->GetSize();
568 
569                     if (num_variables > 0)
570                     {
571                         for (uint32_t i=0; i<num_variables; i++)
572                         {
573                             var_sp = variable_list->GetVariableAtIndex(i);
574 
575                             bool dump_variable = true;
576 
577                             switch (var_sp->GetScope())
578                             {
579                             case eValueTypeVariableGlobal:
580                                 dump_variable = m_option_variable.show_globals;
581                                 if (dump_variable && m_option_variable.show_scope)
582                                     s.PutCString("GLOBAL: ");
583                                 break;
584 
585                             case eValueTypeVariableStatic:
586                                 dump_variable = m_option_variable.show_globals;
587                                 if (dump_variable && m_option_variable.show_scope)
588                                     s.PutCString("STATIC: ");
589                                 break;
590 
591                             case eValueTypeVariableArgument:
592                                 dump_variable = m_option_variable.show_args;
593                                 if (dump_variable && m_option_variable.show_scope)
594                                     s.PutCString("   ARG: ");
595                                 break;
596 
597                             case eValueTypeVariableLocal:
598                                 dump_variable = m_option_variable.show_locals;
599                                 if (dump_variable && m_option_variable.show_scope)
600                                     s.PutCString(" LOCAL: ");
601                                 break;
602 
603                             default:
604                                 break;
605                             }
606 
607                             if (dump_variable)
608                             {
609 
610                                 // Use the variable object code to make sure we are
611                                 // using the same APIs as the the public API will be
612                                 // using...
613                                 valobj_sp = exe_ctx.frame->GetValueObjectForFrameVariable (var_sp,
614                                                                                            m_varobj_options.use_dynamic);
615                                 if (valobj_sp)
616                                 {
617                                     if (m_option_variable.format != eFormatDefault)
618                                         valobj_sp->SetFormat (m_option_variable.format);
619 
620                                     // When dumping all variables, don't print any variables
621                                     // that are not in scope to avoid extra unneeded output
622                                     if (valobj_sp->IsInScope ())
623                                     {
624                                         if (m_option_variable.show_decl && var_sp->GetDeclaration ().GetFile())
625                                         {
626                                             var_sp->GetDeclaration ().DumpStopContext (&s, false);
627                                             s.PutCString (": ");
628                                         }
629                                         if (summary_format_sp)
630                                             valobj_sp->SetCustomSummaryFormat(summary_format_sp);
631                                         ValueObject::DumpValueObject (result.GetOutputStream(),
632                                                                       valobj_sp.get(),
633                                                                       name_cstr,
634                                                                       options);
635                                     }
636                                 }
637                             }
638                         }
639                     }
640                 }
641                 result.SetStatus (eReturnStatusSuccessFinishResult);
642             }
643         }
644 
645         if (m_interpreter.TruncationWarningNecessary())
646         {
647             result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(),
648                                             m_cmd_name.c_str());
649             m_interpreter.TruncationWarningGiven();
650         }
651 
652         return result.Succeeded();
653     }
654 protected:
655 
656     OptionGroupOptions m_option_group;
657     OptionGroupVariable m_option_variable;
658     OptionGroupValueObjectDisplay m_varobj_options;
659 };
660 
661 
662 #pragma mark CommandObjectMultiwordFrame
663 
664 //-------------------------------------------------------------------------
665 // CommandObjectMultiwordFrame
666 //-------------------------------------------------------------------------
667 
668 CommandObjectMultiwordFrame::CommandObjectMultiwordFrame (CommandInterpreter &interpreter) :
669     CommandObjectMultiword (interpreter,
670                             "frame",
671                             "A set of commands for operating on the current thread's frames.",
672                             "frame <subcommand> [<subcommand-options>]")
673 {
674     LoadSubCommand ("info",   CommandObjectSP (new CommandObjectFrameInfo (interpreter)));
675     LoadSubCommand ("select", CommandObjectSP (new CommandObjectFrameSelect (interpreter)));
676     LoadSubCommand ("variable", CommandObjectSP (new CommandObjectFrameVariable (interpreter)));
677 }
678 
679 CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame ()
680 {
681 }
682 
683