xref: /llvm-project/lldb/source/Commands/CommandObjectFrame.cpp (revision 213b454698ed53fc00203d0ea7be34f46dd0858d)
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/DataVisualization.h"
17 #include "lldb/Core/Debugger.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                     {
209                         if (frame_idx == 0)
210                         {
211                             //If you are already at the bottom of the stack, then just warn and don't reset the frame.
212                             result.AppendError("Already at the bottom of the stack");
213                             result.SetStatus(eReturnStatusFailed);
214                             return false;
215                         }
216                         else
217                             frame_idx = 0;
218                     }
219                 }
220                 else if (m_options.relative_frame_offset > 0)
221                 {
222                     if (num_frames - frame_idx > m_options.relative_frame_offset)
223                         frame_idx += m_options.relative_frame_offset;
224                     else
225                     {
226                         if (frame_idx == num_frames - 1)
227                         {
228                             //If we are already at the top of the stack, just warn and don't reset the frame.
229                             result.AppendError("Already at the top of the stack");
230                             result.SetStatus(eReturnStatusFailed);
231                             return false;
232                         }
233                         else
234                             frame_idx = num_frames - 1;
235                     }
236                 }
237             }
238             else
239             {
240                 if (command.GetArgumentCount() == 1)
241                 {
242                     const char *frame_idx_cstr = command.GetArgumentAtIndex(0);
243                     frame_idx = Args::StringToUInt32 (frame_idx_cstr, UINT32_MAX, 0);
244                 }
245                 else
246                 {
247                     result.AppendError ("invalid arguments.\n");
248                     m_options.GenerateOptionUsage (result.GetErrorStream(), this);
249                 }
250             }
251 
252             if (frame_idx < num_frames)
253             {
254                 exe_ctx.thread->SetSelectedFrameByIndex (frame_idx);
255                 exe_ctx.frame = exe_ctx.thread->GetSelectedFrame ().get();
256 
257                 if (exe_ctx.frame)
258                 {
259                     bool already_shown = false;
260                     SymbolContext frame_sc(exe_ctx.frame->GetSymbolContext(eSymbolContextLineEntry));
261                     if (m_interpreter.GetDebugger().GetUseExternalEditor() && frame_sc.line_entry.file && frame_sc.line_entry.line != 0)
262                     {
263                         already_shown = Host::OpenFileInExternalEditor (frame_sc.line_entry.file, frame_sc.line_entry.line);
264                     }
265 
266                     bool show_frame_info = true;
267                     bool show_source = !already_shown;
268                     uint32_t source_lines_before = 3;
269                     uint32_t source_lines_after = 3;
270                     if (exe_ctx.frame->GetStatus(result.GetOutputStream(),
271                                                  show_frame_info,
272                                                  show_source,
273                                                  source_lines_before,
274                                                  source_lines_after))
275                     {
276                         result.SetStatus (eReturnStatusSuccessFinishResult);
277                         return result.Succeeded();
278                     }
279                 }
280             }
281             result.AppendErrorWithFormat ("Frame index (%u) out of range.\n", frame_idx);
282         }
283         else
284         {
285             result.AppendError ("no current thread");
286         }
287         result.SetStatus (eReturnStatusFailed);
288         return false;
289     }
290 protected:
291 
292     CommandOptions m_options;
293 };
294 
295 OptionDefinition
296 CommandObjectFrameSelect::CommandOptions::g_option_table[] =
297 {
298 { LLDB_OPT_SET_1, false, "relative", 'r', required_argument, NULL, 0, eArgTypeOffset, "A relative frame index offset from the current frame index."},
299 { 0, false, NULL, 0, 0, NULL, NULL, eArgTypeNone, NULL }
300 };
301 
302 #pragma mark CommandObjectFrameVariable
303 //----------------------------------------------------------------------
304 // List images with associated information
305 //----------------------------------------------------------------------
306 class CommandObjectFrameVariable : public CommandObject
307 {
308 public:
309 
310     class OptionGroupFrameVariable : public OptionGroup
311     {
312     public:
313 
314         OptionGroupFrameVariable ()
315         {
316         }
317 
318         virtual
319         ~OptionGroupFrameVariable ()
320         {
321         }
322 
323         virtual uint32_t
324         GetNumDefinitions ();
325 
326         virtual const OptionDefinition*
327         GetDefinitions ()
328         {
329             return g_option_table;
330         }
331 
332         virtual Error
333         SetOptionValue (CommandInterpreter &interpreter,
334                         uint32_t option_idx,
335                         const char *option_arg)
336         {
337             Error error;
338             char short_option = (char) g_option_table[option_idx].short_option;
339             switch (short_option)
340             {
341             case 'r':   use_regex    = true;  break;
342             case 'a':   show_args    = false; break;
343             case 'l':   show_locals  = false; break;
344             case 'g':   show_globals = true;  break;
345             case 'c':   show_decl    = true;  break;
346             case 'f':   error = Args::StringToFormat(option_arg, format, NULL); break;
347             case 'G':
348                 globals.push_back(ConstString (option_arg));
349                 break;
350             case 's':
351                 show_scope = true;
352                 break;
353 
354             default:
355                 error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option);
356                 break;
357             }
358 
359             return error;
360         }
361 
362         virtual void
363         OptionParsingStarting (CommandInterpreter &interpreter)
364         {
365             show_args     = true;
366             show_decl     = false;
367             format        = eFormatDefault;
368             show_globals  = false;
369             show_locals   = true;
370             use_regex     = false;
371             show_scope    = false;
372             globals.clear();
373         }
374 
375         // Options table: Required for subclasses of Options.
376 
377         static OptionDefinition g_option_table[];
378 
379         bool use_regex:1,
380              show_args:1,
381              show_locals:1,
382              show_globals:1,
383              show_scope:1,
384              show_decl:1;
385         lldb::Format format; // The format to use when dumping variables or children of variables
386         std::vector<ConstString> globals;
387         // Instance variables to hold the values for command options.
388     };
389 
390     CommandObjectFrameVariable (CommandInterpreter &interpreter) :
391         CommandObject (interpreter,
392                        "frame variable",
393                        "Show frame variables. All argument and local variables "
394                        "that are in scope will be shown when no arguments are given. "
395                        "If any arguments are specified, they can be names of "
396                        "argument, local, file static and file global variables. "
397                        "Children of aggregate variables can be specified such as "
398                        "'var->child.x'.",
399                        NULL,
400                        eFlagProcessMustBeLaunched | eFlagProcessMustBePaused),
401         m_option_group (interpreter),
402         m_option_variable(true), // Include the frame specific options by passing "true"
403         m_varobj_options()
404     {
405         CommandArgumentEntry arg;
406         CommandArgumentData var_name_arg;
407 
408         // Define the first (and only) variant of this arg.
409         var_name_arg.arg_type = eArgTypeVarName;
410         var_name_arg.arg_repetition = eArgRepeatStar;
411 
412         // There is only one variant this argument could be; put it into the argument entry.
413         arg.push_back (var_name_arg);
414 
415         // Push the data for the first argument into the m_arguments vector.
416         m_arguments.push_back (arg);
417 
418         m_option_group.Append (&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
419         m_option_group.Append (&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
420         m_option_group.Finalize();
421     }
422 
423     virtual
424     ~CommandObjectFrameVariable ()
425     {
426     }
427 
428     virtual
429     Options *
430     GetOptions ()
431     {
432         return &m_option_group;
433     }
434 
435 
436     virtual bool
437     Execute
438     (
439         Args& command,
440         CommandReturnObject &result
441     )
442     {
443         ExecutionContext exe_ctx(m_interpreter.GetExecutionContext());
444         if (exe_ctx.frame == NULL)
445         {
446             result.AppendError ("you must be stopped in a valid stack frame to view frame variables.");
447             result.SetStatus (eReturnStatusFailed);
448             return false;
449         }
450         else
451         {
452             Stream &s = result.GetOutputStream();
453 
454             bool get_file_globals = true;
455 
456             // Be careful about the stack frame, if any summary formatter runs code, it might clear the StackFrameList
457             // for the thread.  So hold onto a shared pointer to the frame so it stays alive.
458 
459             StackFrameSP frame_sp = exe_ctx.frame->GetSP();
460 
461             VariableList *variable_list = frame_sp->GetVariableList (get_file_globals);
462 
463             VariableSP var_sp;
464             ValueObjectSP valobj_sp;
465 
466             const char *name_cstr = NULL;
467             size_t idx;
468 
469             SummaryFormatSP summary_format_sp;
470             if (!m_option_variable.summary.empty())
471                 DataVisualization::NamedSummaryFormats::Get(ConstString(m_option_variable.summary.c_str()), summary_format_sp);
472 
473             ValueObject::DumpValueObjectOptions options;
474 
475             options.SetPointerDepth(m_varobj_options.ptr_depth)
476                    .SetMaximumDepth(m_varobj_options.max_depth)
477                    .SetShowTypes(m_varobj_options.show_types)
478                    .SetShowLocation(m_varobj_options.show_location)
479                    .SetUseObjectiveC(m_varobj_options.use_objc)
480                    .SetUseDynamicType(m_varobj_options.use_dynamic)
481                    .SetUseSyntheticValue((lldb::SyntheticValueType)m_varobj_options.use_synth)
482                    .SetFlatOutput(m_varobj_options.flat_output)
483                    .SetOmitSummaryDepth(m_varobj_options.no_summary_depth)
484                    .SetIgnoreCap(m_varobj_options.ignore_cap);
485 
486             if (m_varobj_options.be_raw)
487                 options.SetRawDisplay(true);
488 
489             if (variable_list)
490             {
491                 if (command.GetArgumentCount() > 0)
492                 {
493                     VariableList regex_var_list;
494 
495                     // If we have any args to the variable command, we will make
496                     // variable objects from them...
497                     for (idx = 0; (name_cstr = command.GetArgumentAtIndex(idx)) != NULL; ++idx)
498                     {
499                         if (m_option_variable.use_regex)
500                         {
501                             const uint32_t regex_start_index = regex_var_list.GetSize();
502                             RegularExpression regex (name_cstr);
503                             if (regex.Compile(name_cstr))
504                             {
505                                 size_t num_matches = 0;
506                                 const size_t num_new_regex_vars = variable_list->AppendVariablesIfUnique(regex,
507                                                                                                          regex_var_list,
508                                                                                                          num_matches);
509                                 if (num_new_regex_vars > 0)
510                                 {
511                                     for (uint32_t regex_idx = regex_start_index, end_index = regex_var_list.GetSize();
512                                          regex_idx < end_index;
513                                          ++regex_idx)
514                                     {
515                                         var_sp = regex_var_list.GetVariableAtIndex (regex_idx);
516                                         if (var_sp)
517                                         {
518                                             valobj_sp = frame_sp->GetValueObjectForFrameVariable (var_sp, m_varobj_options.use_dynamic);
519                                             if (valobj_sp)
520                                             {
521                                                 if (m_option_variable.format != eFormatDefault)
522                                                     valobj_sp->SetFormat (m_option_variable.format);
523 
524                                                 if (m_option_variable.show_decl && var_sp->GetDeclaration ().GetFile())
525                                                 {
526                                                     bool show_fullpaths = false;
527                                                     bool show_module = true;
528                                                     if (var_sp->DumpDeclaration(&s, show_fullpaths, show_module))
529                                                         s.PutCString (": ");
530                                                 }
531                                                 if (summary_format_sp)
532                                                     valobj_sp->SetCustomSummaryFormat(summary_format_sp);
533                                                 ValueObject::DumpValueObject (result.GetOutputStream(),
534                                                                               valobj_sp.get(),
535                                                                               options);
536                                             }
537                                         }
538                                     }
539                                 }
540                                 else if (num_matches == 0)
541                                 {
542                                     result.GetErrorStream().Printf ("error: no variables matched the regular expression '%s'.\n", name_cstr);
543                                 }
544                             }
545                             else
546                             {
547                                 char regex_error[1024];
548                                 if (regex.GetErrorAsCString(regex_error, sizeof(regex_error)))
549                                     result.GetErrorStream().Printf ("error: %s\n", regex_error);
550                                 else
551                                     result.GetErrorStream().Printf ("error: unkown regex error when compiling '%s'\n", name_cstr);
552                             }
553                         }
554                         else
555                         {
556                             Error error;
557                             uint32_t expr_path_options = StackFrame::eExpressionPathOptionCheckPtrVsMember;
558                             lldb::VariableSP var_sp;
559                             valobj_sp = frame_sp->GetValueForVariableExpressionPath (name_cstr,
560                                                                                           m_varobj_options.use_dynamic,
561                                                                                           expr_path_options,
562                                                                                           var_sp,
563                                                                                           error);
564                             if (valobj_sp)
565                             {
566                                 if (m_option_variable.format != eFormatDefault)
567                                     valobj_sp->SetFormat (m_option_variable.format);
568                                 if (m_option_variable.show_decl && var_sp && var_sp->GetDeclaration ().GetFile())
569                                 {
570                                     var_sp->GetDeclaration ().DumpStopContext (&s, false);
571                                     s.PutCString (": ");
572                                 }
573                                 if (summary_format_sp)
574                                     valobj_sp->SetCustomSummaryFormat(summary_format_sp);
575                                 ValueObject::DumpValueObject (result.GetOutputStream(),
576                                                               valobj_sp.get(),
577                                                               valobj_sp->GetParent() ? name_cstr : NULL,
578                                                               options);
579                             }
580                             else
581                             {
582                                 const char *error_cstr = error.AsCString(NULL);
583                                 if (error_cstr)
584                                     result.GetErrorStream().Printf("error: %s\n", error_cstr);
585                                 else
586                                     result.GetErrorStream().Printf ("error: unable to find any variable expression path that matches '%s'\n", name_cstr);
587                             }
588                         }
589                     }
590                 }
591                 else
592                 {
593                     const uint32_t num_variables = variable_list->GetSize();
594 
595                     if (num_variables > 0)
596                     {
597                         for (uint32_t i=0; i<num_variables; i++)
598                         {
599                             var_sp = variable_list->GetVariableAtIndex(i);
600 
601                             bool dump_variable = true;
602 
603                             switch (var_sp->GetScope())
604                             {
605                             case eValueTypeVariableGlobal:
606                                 dump_variable = m_option_variable.show_globals;
607                                 if (dump_variable && m_option_variable.show_scope)
608                                     s.PutCString("GLOBAL: ");
609                                 break;
610 
611                             case eValueTypeVariableStatic:
612                                 dump_variable = m_option_variable.show_globals;
613                                 if (dump_variable && m_option_variable.show_scope)
614                                     s.PutCString("STATIC: ");
615                                 break;
616 
617                             case eValueTypeVariableArgument:
618                                 dump_variable = m_option_variable.show_args;
619                                 if (dump_variable && m_option_variable.show_scope)
620                                     s.PutCString("   ARG: ");
621                                 break;
622 
623                             case eValueTypeVariableLocal:
624                                 dump_variable = m_option_variable.show_locals;
625                                 if (dump_variable && m_option_variable.show_scope)
626                                     s.PutCString(" LOCAL: ");
627                                 break;
628 
629                             default:
630                                 break;
631                             }
632 
633                             if (dump_variable)
634                             {
635 
636                                 // Use the variable object code to make sure we are
637                                 // using the same APIs as the the public API will be
638                                 // using...
639                                 valobj_sp = frame_sp->GetValueObjectForFrameVariable (var_sp,
640                                                                                            m_varobj_options.use_dynamic);
641                                 if (valobj_sp)
642                                 {
643                                     if (m_option_variable.format != eFormatDefault)
644                                         valobj_sp->SetFormat (m_option_variable.format);
645 
646                                     // When dumping all variables, don't print any variables
647                                     // that are not in scope to avoid extra unneeded output
648                                     if (valobj_sp->IsInScope ())
649                                     {
650                                         if (m_option_variable.show_decl && var_sp->GetDeclaration ().GetFile())
651                                         {
652                                             var_sp->GetDeclaration ().DumpStopContext (&s, false);
653                                             s.PutCString (": ");
654                                         }
655                                         if (summary_format_sp)
656                                             valobj_sp->SetCustomSummaryFormat(summary_format_sp);
657                                         ValueObject::DumpValueObject (result.GetOutputStream(),
658                                                                       valobj_sp.get(),
659                                                                       name_cstr,
660                                                                       options);
661                                     }
662                                 }
663                             }
664                         }
665                     }
666                 }
667                 result.SetStatus (eReturnStatusSuccessFinishResult);
668             }
669         }
670 
671         if (m_interpreter.TruncationWarningNecessary())
672         {
673             result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(),
674                                             m_cmd_name.c_str());
675             m_interpreter.TruncationWarningGiven();
676         }
677 
678         return result.Succeeded();
679     }
680 protected:
681 
682     OptionGroupOptions m_option_group;
683     OptionGroupVariable m_option_variable;
684     OptionGroupValueObjectDisplay m_varobj_options;
685 };
686 
687 
688 #pragma mark CommandObjectMultiwordFrame
689 
690 //-------------------------------------------------------------------------
691 // CommandObjectMultiwordFrame
692 //-------------------------------------------------------------------------
693 
694 CommandObjectMultiwordFrame::CommandObjectMultiwordFrame (CommandInterpreter &interpreter) :
695     CommandObjectMultiword (interpreter,
696                             "frame",
697                             "A set of commands for operating on the current thread's frames.",
698                             "frame <subcommand> [<subcommand-options>]")
699 {
700     LoadSubCommand ("info",   CommandObjectSP (new CommandObjectFrameInfo (interpreter)));
701     LoadSubCommand ("select", CommandObjectSP (new CommandObjectFrameSelect (interpreter)));
702     LoadSubCommand ("variable", CommandObjectSP (new CommandObjectFrameVariable (interpreter)));
703 }
704 
705 CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame ()
706 {
707 }
708 
709