xref: /llvm-project/lldb/source/Commands/CommandObjectFrame.cpp (revision 715c236577e8fb0b05a55e21999ac03b5f3cb208)
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/Module.h"
18 #include "lldb/Core/StreamFile.h"
19 #include "lldb/Core/Timer.h"
20 #include "lldb/Core/Value.h"
21 #include "lldb/Core/ValueObject.h"
22 #include "lldb/Core/ValueObjectVariable.h"
23 #include "lldb/Host/Host.h"
24 #include "lldb/Interpreter/Args.h"
25 #include "lldb/Interpreter/CommandInterpreter.h"
26 #include "lldb/Interpreter/CommandReturnObject.h"
27 #include "lldb/Interpreter/Options.h"
28 #include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
29 #include "lldb/Interpreter/OptionGroupVariable.h"
30 #include "lldb/Symbol/ClangASTType.h"
31 #include "lldb/Symbol/ClangASTContext.h"
32 #include "lldb/Symbol/ObjectFile.h"
33 #include "lldb/Symbol/SymbolContext.h"
34 #include "lldb/Symbol/Type.h"
35 #include "lldb/Symbol/Variable.h"
36 #include "lldb/Symbol/VariableList.h"
37 #include "lldb/Target/Process.h"
38 #include "lldb/Target/StackFrame.h"
39 #include "lldb/Target/Thread.h"
40 #include "lldb/Target/Target.h"
41 
42 using namespace lldb;
43 using namespace lldb_private;
44 
45 #pragma mark CommandObjectFrameInfo
46 
47 //-------------------------------------------------------------------------
48 // CommandObjectFrameInfo
49 //-------------------------------------------------------------------------
50 
51 class CommandObjectFrameInfo : public CommandObject
52 {
53 public:
54 
55     CommandObjectFrameInfo (CommandInterpreter &interpreter) :
56         CommandObject (interpreter,
57                        "frame info",
58                        "List information about the currently selected frame in the current thread.",
59                        "frame info",
60                        eFlagProcessMustBeLaunched | eFlagProcessMustBePaused)
61     {
62     }
63 
64     ~CommandObjectFrameInfo ()
65     {
66     }
67 
68     bool
69     Execute (Args& command,
70              CommandReturnObject &result)
71     {
72         ExecutionContext exe_ctx(m_interpreter.GetExecutionContext());
73         if (exe_ctx.frame)
74         {
75             exe_ctx.frame->DumpUsingSettingsFormat (&result.GetOutputStream());
76             result.GetOutputStream().EOL();
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             if (variable_list)
444             {
445                 if (command.GetArgumentCount() > 0)
446                 {
447                     VariableList regex_var_list;
448 
449                     // If we have any args to the variable command, we will make
450                     // variable objects from them...
451                     for (idx = 0; (name_cstr = command.GetArgumentAtIndex(idx)) != NULL; ++idx)
452                     {
453                         uint32_t ptr_depth = m_varobj_options.ptr_depth;
454 
455                         if (m_option_variable.use_regex)
456                         {
457                             const uint32_t regex_start_index = regex_var_list.GetSize();
458                             RegularExpression regex (name_cstr);
459                             if (regex.Compile(name_cstr))
460                             {
461                                 size_t num_matches = 0;
462                                 const size_t num_new_regex_vars = variable_list->AppendVariablesIfUnique(regex,
463                                                                                                          regex_var_list,
464                                                                                                          num_matches);
465                                 if (num_new_regex_vars > 0)
466                                 {
467                                     for (uint32_t regex_idx = regex_start_index, end_index = regex_var_list.GetSize();
468                                          regex_idx < end_index;
469                                          ++regex_idx)
470                                     {
471                                         var_sp = regex_var_list.GetVariableAtIndex (regex_idx);
472                                         if (var_sp)
473                                         {
474                                             valobj_sp = exe_ctx.frame->GetValueObjectForFrameVariable (var_sp, m_varobj_options.use_dynamic);
475                                             if (valobj_sp)
476                                             {
477                                                 if (m_option_variable.format != eFormatDefault)
478                                                     valobj_sp->SetFormat (m_option_variable.format);
479 
480                                                 if (m_option_variable.show_decl && var_sp->GetDeclaration ().GetFile())
481                                                 {
482                                                     var_sp->GetDeclaration ().DumpStopContext (&s, false);
483                                                     s.PutCString (": ");
484                                                 }
485 
486                                                 ValueObject::DumpValueObject (result.GetOutputStream(),
487                                                                               valobj_sp.get(),
488                                                                               var_sp->GetName().AsCString(),
489                                                                               m_varobj_options.ptr_depth,
490                                                                               0,
491                                                                               m_varobj_options.max_depth,
492                                                                               m_varobj_options.show_types,
493                                                                               m_varobj_options.show_location,
494                                                                               m_varobj_options.use_objc,
495                                                                               m_varobj_options.use_dynamic,
496                                                                               false,
497                                                                               m_varobj_options.flat_output);
498                                             }
499                                         }
500                                     }
501                                 }
502                                 else if (num_matches == 0)
503                                 {
504                                     result.GetErrorStream().Printf ("error: no variables matched the regular expression '%s'.\n", name_cstr);
505                                 }
506                             }
507                             else
508                             {
509                                 char regex_error[1024];
510                                 if (regex.GetErrorAsCString(regex_error, sizeof(regex_error)))
511                                     result.GetErrorStream().Printf ("error: %s\n", regex_error);
512                                 else
513                                     result.GetErrorStream().Printf ("error: unkown regex error when compiling '%s'\n", name_cstr);
514                             }
515                         }
516                         else
517                         {
518                             Error error;
519                             uint32_t expr_path_options = StackFrame::eExpressionPathOptionCheckPtrVsMember;
520                             lldb::VariableSP var_sp;
521                             valobj_sp = exe_ctx.frame->GetValueForVariableExpressionPath (name_cstr,
522                                                                                           m_varobj_options.use_dynamic,
523                                                                                           expr_path_options,
524                                                                                           var_sp,
525                                                                                           error);
526                             if (valobj_sp)
527                             {
528                                 if (m_option_variable.format != eFormatDefault)
529                                     valobj_sp->SetFormat (m_option_variable.format);
530                                 if (m_option_variable.show_decl && var_sp && var_sp->GetDeclaration ().GetFile())
531                                 {
532                                     var_sp->GetDeclaration ().DumpStopContext (&s, false);
533                                     s.PutCString (": ");
534                                 }
535                                 ValueObject::DumpValueObject (result.GetOutputStream(),
536                                                               valobj_sp.get(),
537                                                               valobj_sp->GetParent() ? name_cstr : NULL,
538                                                               ptr_depth,
539                                                               0,
540                                                               m_varobj_options.max_depth,
541                                                               m_varobj_options.show_types,
542                                                               m_varobj_options.show_location,
543                                                               m_varobj_options.use_objc,
544                                                               m_varobj_options.use_dynamic,
545                                                               false,
546                                                               m_varobj_options.flat_output);
547                             }
548                             else
549                             {
550                                 const char *error_cstr = error.AsCString(NULL);
551                                 if (error_cstr)
552                                     result.GetErrorStream().Printf("error: %s\n", error_cstr);
553                                 else
554                                     result.GetErrorStream().Printf ("error: unable to find any variable expression path that matches '%s'\n", name_cstr);
555                             }
556                         }
557                     }
558                 }
559                 else
560                 {
561                     const uint32_t num_variables = variable_list->GetSize();
562 
563                     if (num_variables > 0)
564                     {
565                         for (uint32_t i=0; i<num_variables; i++)
566                         {
567                             var_sp = variable_list->GetVariableAtIndex(i);
568 
569                             bool dump_variable = true;
570 
571                             switch (var_sp->GetScope())
572                             {
573                             case eValueTypeVariableGlobal:
574                                 dump_variable = m_option_variable.show_globals;
575                                 if (dump_variable && m_option_variable.show_scope)
576                                     s.PutCString("GLOBAL: ");
577                                 break;
578 
579                             case eValueTypeVariableStatic:
580                                 dump_variable = m_option_variable.show_globals;
581                                 if (dump_variable && m_option_variable.show_scope)
582                                     s.PutCString("STATIC: ");
583                                 break;
584 
585                             case eValueTypeVariableArgument:
586                                 dump_variable = m_option_variable.show_args;
587                                 if (dump_variable && m_option_variable.show_scope)
588                                     s.PutCString("   ARG: ");
589                                 break;
590 
591                             case eValueTypeVariableLocal:
592                                 dump_variable = m_option_variable.show_locals;
593                                 if (dump_variable && m_option_variable.show_scope)
594                                     s.PutCString(" LOCAL: ");
595                                 break;
596 
597                             default:
598                                 break;
599                             }
600 
601                             if (dump_variable)
602                             {
603 
604                                 // Use the variable object code to make sure we are
605                                 // using the same APIs as the the public API will be
606                                 // using...
607                                 valobj_sp = exe_ctx.frame->GetValueObjectForFrameVariable (var_sp,
608                                                                                            m_varobj_options.use_dynamic);
609                                 if (valobj_sp)
610                                 {
611                                     if (m_option_variable.format != eFormatDefault)
612                                         valobj_sp->SetFormat (m_option_variable.format);
613 
614                                     // When dumping all variables, don't print any variables
615                                     // that are not in scope to avoid extra unneeded output
616                                     if (valobj_sp->IsInScope ())
617                                     {
618                                         if (m_option_variable.show_decl && var_sp->GetDeclaration ().GetFile())
619                                         {
620                                             var_sp->GetDeclaration ().DumpStopContext (&s, false);
621                                             s.PutCString (": ");
622                                         }
623                                         ValueObject::DumpValueObject (result.GetOutputStream(),
624                                                                       valobj_sp.get(),
625                                                                       name_cstr,
626                                                                       m_varobj_options.ptr_depth,
627                                                                       0,
628                                                                       m_varobj_options.max_depth,
629                                                                       m_varobj_options.show_types,
630                                                                       m_varobj_options.show_location,
631                                                                       m_varobj_options.use_objc,
632                                                                       m_varobj_options.use_dynamic,
633                                                                       false,
634                                                                       m_varobj_options.flat_output);
635                                     }
636                                 }
637                             }
638                         }
639                     }
640                 }
641                 result.SetStatus (eReturnStatusSuccessFinishResult);
642             }
643         }
644         return result.Succeeded();
645     }
646 protected:
647 
648     OptionGroupOptions m_option_group;
649     OptionGroupVariable m_option_variable;
650     OptionGroupValueObjectDisplay m_varobj_options;
651 };
652 
653 
654 #pragma mark CommandObjectMultiwordFrame
655 
656 //-------------------------------------------------------------------------
657 // CommandObjectMultiwordFrame
658 //-------------------------------------------------------------------------
659 
660 CommandObjectMultiwordFrame::CommandObjectMultiwordFrame (CommandInterpreter &interpreter) :
661     CommandObjectMultiword (interpreter,
662                             "frame",
663                             "A set of commands for operating on the current thread's frames.",
664                             "frame <subcommand> [<subcommand-options>]")
665 {
666     LoadSubCommand ("info",   CommandObjectSP (new CommandObjectFrameInfo (interpreter)));
667     LoadSubCommand ("select", CommandObjectSP (new CommandObjectFrameSelect (interpreter)));
668     LoadSubCommand ("variable", CommandObjectSP (new CommandObjectFrameVariable (interpreter)));
669 }
670 
671 CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame ()
672 {
673 }
674 
675