xref: /llvm-project/lldb/source/Commands/CommandObjectFrame.cpp (revision 405fe67f1424284173459575b1081f42935c50fd)
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/Interpreter/Args.h"
24 #include "lldb/Interpreter/CommandInterpreter.h"
25 #include "lldb/Interpreter/CommandReturnObject.h"
26 #include "lldb/Interpreter/Options.h"
27 #include "lldb/Symbol/ClangASTType.h"
28 #include "lldb/Symbol/ClangASTContext.h"
29 #include "lldb/Symbol/ObjectFile.h"
30 #include "lldb/Symbol/SymbolContext.h"
31 #include "lldb/Symbol/Type.h"
32 #include "lldb/Symbol/Variable.h"
33 #include "lldb/Symbol/VariableList.h"
34 #include "lldb/Target/Process.h"
35 #include "lldb/Target/StackFrame.h"
36 #include "lldb/Target/Thread.h"
37 #include "lldb/Target/Target.h"
38 
39 #include "CommandObjectThread.h"
40 
41 using namespace lldb;
42 using namespace lldb_private;
43 
44 #pragma mark CommandObjectFrameInfo
45 
46 //-------------------------------------------------------------------------
47 // CommandObjectFrameInfo
48 //-------------------------------------------------------------------------
49 
50 class CommandObjectFrameInfo : public CommandObject
51 {
52 public:
53 
54     CommandObjectFrameInfo (CommandInterpreter &interpreter) :
55         CommandObject (interpreter,
56                        "frame info",
57                        "List information about the currently selected frame in the current thread.",
58                        "frame info",
59                        eFlagProcessMustBeLaunched | eFlagProcessMustBePaused)
60     {
61     }
62 
63     ~CommandObjectFrameInfo ()
64     {
65     }
66 
67     bool
68     Execute (Args& command,
69              CommandReturnObject &result)
70     {
71         ExecutionContext exe_ctx(m_interpreter.GetDebugger().GetExecutionContext());
72         if (exe_ctx.frame)
73         {
74             exe_ctx.frame->DumpUsingSettingsFormat (&result.GetOutputStream());
75             result.GetOutputStream().EOL();
76             result.SetStatus (eReturnStatusSuccessFinishResult);
77         }
78         else
79         {
80             result.AppendError ("no current frame");
81             result.SetStatus (eReturnStatusFailed);
82         }
83         return result.Succeeded();
84     }
85 };
86 
87 #pragma mark CommandObjectFrameSelect
88 
89 //-------------------------------------------------------------------------
90 // CommandObjectFrameSelect
91 //-------------------------------------------------------------------------
92 
93 class CommandObjectFrameSelect : public CommandObject
94 {
95 public:
96 
97     CommandObjectFrameSelect (CommandInterpreter &interpreter) :
98         CommandObject (interpreter,
99                        "frame select",
100                        "Select a frame by index from within the current thread and make it the current frame.",
101                        NULL,
102                        eFlagProcessMustBeLaunched | eFlagProcessMustBePaused)
103     {
104         CommandArgumentEntry arg;
105         CommandArgumentData index_arg;
106 
107         // Define the first (and only) variant of this arg.
108         index_arg.arg_type = eArgTypeFrameIndex;
109         index_arg.arg_repetition = eArgRepeatPlain;
110 
111         // There is only one variant this argument could be; put it into the argument entry.
112         arg.push_back (index_arg);
113 
114         // Push the data for the first argument into the m_arguments vector.
115         m_arguments.push_back (arg);
116     }
117 
118     ~CommandObjectFrameSelect ()
119     {
120     }
121 
122     bool
123     Execute (Args& command,
124              CommandReturnObject &result)
125     {
126         ExecutionContext exe_ctx (m_interpreter.GetDebugger().GetExecutionContext());
127         if (exe_ctx.thread)
128         {
129             if (command.GetArgumentCount() == 1)
130             {
131                 const char *frame_idx_cstr = command.GetArgumentAtIndex(0);
132 
133                 const uint32_t num_frames = exe_ctx.thread->GetStackFrameCount();
134                 const uint32_t frame_idx = Args::StringToUInt32 (frame_idx_cstr, UINT32_MAX, 0);
135                 if (frame_idx < num_frames)
136                 {
137                     exe_ctx.thread->SetSelectedFrameByIndex (frame_idx);
138                     exe_ctx.frame = exe_ctx.thread->GetSelectedFrame ().get();
139 
140                     if (exe_ctx.frame)
141                     {
142                         bool already_shown = false;
143                         SymbolContext frame_sc(exe_ctx.frame->GetSymbolContext(eSymbolContextLineEntry));
144                         if (m_interpreter.GetDebugger().GetUseExternalEditor() && frame_sc.line_entry.file && frame_sc.line_entry.line != 0)
145                         {
146                             already_shown = Host::OpenFileInExternalEditor (frame_sc.line_entry.file, frame_sc.line_entry.line);
147                         }
148 
149                         if (DisplayFrameForExecutionContext (exe_ctx.thread,
150                                                              exe_ctx.frame,
151                                                              m_interpreter,
152                                                              result.GetOutputStream(),
153                                                              true,
154                                                              !already_shown,
155                                                              3,
156                                                              3))
157                         {
158                             result.SetStatus (eReturnStatusSuccessFinishResult);
159                             return result.Succeeded();
160                         }
161                     }
162                 }
163                 if (frame_idx == UINT32_MAX)
164                     result.AppendErrorWithFormat ("Invalid frame index: %s.\n", frame_idx_cstr);
165                 else
166                     result.AppendErrorWithFormat ("Frame index (%u) out of range.\n", frame_idx);
167             }
168             else
169             {
170                 result.AppendError ("invalid arguments");
171                 result.AppendErrorWithFormat ("Usage: %s\n", m_cmd_syntax.c_str());
172             }
173         }
174         else
175         {
176             result.AppendError ("no current thread");
177         }
178         result.SetStatus (eReturnStatusFailed);
179         return false;
180     }
181 };
182 
183 #pragma mark CommandObjectFrameVariable
184 //----------------------------------------------------------------------
185 // List images with associated information
186 //----------------------------------------------------------------------
187 class CommandObjectFrameVariable : public CommandObject
188 {
189 public:
190 
191     class CommandOptions : public Options
192     {
193     public:
194 
195         CommandOptions () :
196             Options()
197         {
198             ResetOptionValues ();
199         }
200 
201         virtual
202         ~CommandOptions ()
203         {
204         }
205 
206         virtual Error
207         SetOptionValue (int option_idx, const char *option_arg)
208         {
209             Error error;
210             bool success;
211             char short_option = (char) m_getopt_table[option_idx].val;
212             switch (short_option)
213             {
214             case 'o':   use_objc     = true;  break;
215             case 'n':   name = option_arg;    break;
216             case 'r':   use_regex    = true;  break;
217             case 'a':   show_args    = false; break;
218             case 'l':   show_locals  = false; break;
219             case 'g':   show_globals = true;  break;
220             case 't':   show_types   = false; break;
221             case 'y':   show_summary = false; break;
222             case 'L':   show_location= true;  break;
223             case 'c':   show_decl    = true;  break;
224             case 'D':   debug        = true;  break;
225             case 'd':
226                 max_depth = Args::StringToUInt32 (option_arg, UINT32_MAX, 0, &success);
227                 if (!success)
228                     error.SetErrorStringWithFormat("Invalid max depth '%s'.\n", option_arg);
229                 break;
230 
231             case 'p':
232                 ptr_depth = Args::StringToUInt32 (option_arg, 0, 0, &success);
233                 if (!success)
234                     error.SetErrorStringWithFormat("Invalid pointer depth '%s'.\n", option_arg);
235                 break;
236 
237             case 'G':
238                 globals.push_back(ConstString (option_arg));
239                 break;
240 
241             case 's':
242                 show_scope = true;
243                 break;
244 
245             default:
246                 error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option);
247                 break;
248             }
249 
250             return error;
251         }
252 
253         void
254         ResetOptionValues ()
255         {
256             Options::ResetOptionValues();
257 
258             name.clear();
259             use_objc      = false;
260             use_regex     = false;
261             show_args     = true;
262             show_locals   = true;
263             show_globals  = false;
264             show_types    = true;
265             show_scope    = false;
266             show_summary  = true;
267             show_location = false;
268             show_decl     = false;
269             debug         = false;
270             max_depth     = UINT32_MAX;
271             ptr_depth     = 0;
272             globals.clear();
273         }
274 
275         const lldb::OptionDefinition*
276         GetDefinitions ()
277         {
278             return g_option_table;
279         }
280 
281         // Options table: Required for subclasses of Options.
282 
283         static lldb::OptionDefinition g_option_table[];
284         std::string name;
285         bool use_objc:1,
286              use_regex:1,
287              show_args:1,
288              show_locals:1,
289              show_globals:1,
290              show_types:1,
291              show_scope:1,
292              show_summary:1,
293              show_location:1,
294              show_decl:1,
295              debug:1;
296         uint32_t max_depth; // The depth to print when dumping concrete (not pointers) aggreate values
297         uint32_t ptr_depth; // The default depth that is dumped when we find pointers
298         std::vector<ConstString> globals;
299         // Instance variables to hold the values for command options.
300     };
301 
302     CommandObjectFrameVariable (CommandInterpreter &interpreter) :
303         CommandObject (interpreter,
304                        "frame variable",
305                        "Show frame variables. All argument and local variables "
306                        "that are in scope will be shown when no arguments are given. "
307                        "If any arguments are specified, they can be names of "
308                        "argument, local, file static and file global variables."
309                        "Children of aggregate variables can be specified such as "
310                        "'var->child.x'.",
311                        NULL)
312     {
313         CommandArgumentEntry arg;
314         CommandArgumentData var_name_arg;
315 
316         // Define the first (and only) variant of this arg.
317         var_name_arg.arg_type = eArgTypeVarName;
318         var_name_arg.arg_repetition = eArgRepeatStar;
319 
320         // There is only one variant this argument could be; put it into the argument entry.
321         arg.push_back (var_name_arg);
322 
323         // Push the data for the first argument into the m_arguments vector.
324         m_arguments.push_back (arg);
325     }
326 
327     virtual
328     ~CommandObjectFrameVariable ()
329     {
330     }
331 
332     virtual
333     Options *
334     GetOptions ()
335     {
336         return &m_options;
337     }
338 
339     void
340     DumpValueObject (CommandReturnObject &result,
341                      ExecutionContextScope *exe_scope,
342                      ValueObject *valobj,
343                      const char *root_valobj_name,
344                      uint32_t ptr_depth,
345                      uint32_t curr_depth,
346                      uint32_t max_depth,
347                      bool use_objc,
348                      bool scope_already_checked)
349     {
350         if (valobj)
351         {
352             Stream &s = result.GetOutputStream();
353 
354             //const char *loc_cstr = valobj->GetLocationAsCString();
355             if (m_options.show_location)
356             {
357                 s.Printf("%s: ", valobj->GetLocationAsCString(exe_scope));
358             }
359             if (m_options.debug)
360                 s.Printf ("%p ValueObject{%u} ", valobj, valobj->GetID());
361 
362             s.Indent();
363 
364             if (m_options.show_types)
365                 s.Printf("(%s) ", valobj->GetTypeName().AsCString());
366 
367             const char *name_cstr = root_valobj_name ? root_valobj_name : valobj->GetName().AsCString("");
368             s.Printf ("%s = ", name_cstr);
369 
370             if (!scope_already_checked && !valobj->IsInScope(exe_scope->CalculateStackFrame()))
371             {
372                 s.PutCString("error: out of scope");
373                 return;
374             }
375 
376             const char *val_cstr = valobj->GetValueAsCString(exe_scope);
377             const char *err_cstr = valobj->GetError().AsCString();
378 
379             if (err_cstr)
380             {
381                 s.Printf ("error: %s", err_cstr);
382             }
383             else
384             {
385                 const char *sum_cstr = valobj->GetSummaryAsCString(exe_scope);
386 
387                 const bool is_aggregate = ClangASTContext::IsAggregateType (valobj->GetClangType());
388 
389                 if (val_cstr)
390                     s.PutCString(val_cstr);
391 
392                 if (sum_cstr)
393                     s.Printf(" %s", sum_cstr);
394 
395                 if (use_objc)
396                 {
397                     const char *object_desc = valobj->GetObjectDescription(exe_scope);
398                     if (object_desc)
399                         s.Printf("\n%s\n", object_desc);
400                     else
401                         s.Printf ("No description available.\n");
402                     return;
403                 }
404 
405 
406                 if (curr_depth < max_depth)
407                 {
408                     if (is_aggregate)
409                         s.PutChar('{');
410 
411                     bool is_ptr_or_ref = ClangASTContext::IsPointerOrReferenceType (valobj->GetClangType());
412 
413                     if (is_ptr_or_ref && ptr_depth == 0)
414                         return;
415 
416                     const uint32_t num_children = valobj->GetNumChildren();
417                     if (num_children)
418                     {
419                         s.IndentMore();
420                         for (uint32_t idx=0; idx<num_children; ++idx)
421                         {
422                             ValueObjectSP child_sp(valobj->GetChildAtIndex(idx, true));
423                             if (child_sp.get())
424                             {
425                                 s.EOL();
426                                 DumpValueObject (result,
427                                                  exe_scope,
428                                                  child_sp.get(),
429                                                  NULL,
430                                                  is_ptr_or_ref ? ptr_depth - 1 : ptr_depth,
431                                                  curr_depth + 1,
432                                                  max_depth,
433                                                  false,
434                                                  true);
435                                 if (idx + 1 < num_children)
436                                     s.PutChar(',');
437                             }
438                         }
439                         s.IndentLess();
440                     }
441                     if (is_aggregate)
442                     {
443                         s.EOL();
444                         s.Indent("}");
445                     }
446                 }
447                 else
448                 {
449                     if (is_aggregate)
450                     {
451                         s.PutCString("{...}");
452                     }
453                 }
454 
455             }
456         }
457     }
458 
459     virtual bool
460     Execute
461     (
462         Args& command,
463         CommandReturnObject &result
464     )
465     {
466         ExecutionContext exe_ctx(m_interpreter.GetDebugger().GetExecutionContext());
467         if (exe_ctx.frame == NULL)
468         {
469             result.AppendError ("you must be stopped in a valid stack frame to view frame variables.");
470             result.SetStatus (eReturnStatusFailed);
471             return false;
472         }
473         else
474         {
475             Stream &s = result.GetOutputStream();
476 
477             bool get_file_globals = true;
478             VariableList *variable_list = exe_ctx.frame->GetVariableList (get_file_globals);
479 
480             VariableSP var_sp;
481             ValueObjectSP valobj_sp;
482             //ValueObjectList &valobj_list = exe_ctx.frame->GetValueObjectList();
483             const char *name_cstr = NULL;
484             size_t idx;
485             if (!m_options.globals.empty())
486             {
487                 uint32_t fail_count = 0;
488                 if (exe_ctx.target)
489                 {
490                     const size_t num_globals = m_options.globals.size();
491                     for (idx = 0; idx < num_globals; ++idx)
492                     {
493                         VariableList global_var_list;
494                         const uint32_t num_matching_globals = exe_ctx.target->GetImages().FindGlobalVariables (m_options.globals[idx], true, UINT32_MAX, global_var_list);
495 
496                         if (num_matching_globals == 0)
497                         {
498                             ++fail_count;
499                             result.GetErrorStream().Printf ("error: can't find global variable '%s'\n", m_options.globals[idx].AsCString());
500                         }
501                         else
502                         {
503                             for (uint32_t global_idx=0; global_idx<num_matching_globals; ++global_idx)
504                             {
505                                 var_sp = global_var_list.GetVariableAtIndex(global_idx);
506                                 if (var_sp)
507                                 {
508                                     valobj_sp = exe_ctx.frame->GetValueObjectForFrameVariable (var_sp);
509                                     if (!valobj_sp)
510                                         valobj_sp = exe_ctx.frame->TrackGlobalVariable (var_sp);
511 
512                                     if (valobj_sp)
513                                     {
514                                         if (m_options.show_decl && var_sp->GetDeclaration ().GetFile())
515                                         {
516                                             var_sp->GetDeclaration ().DumpStopContext (&s, false);
517                                             s.PutCString (": ");
518                                         }
519 
520                                         DumpValueObject (result,
521                                                          exe_ctx.frame,
522                                                          valobj_sp.get(),
523                                                          name_cstr,
524                                                          m_options.ptr_depth,
525                                                          0,
526                                                          m_options.max_depth,
527                                                          m_options.use_objc,
528                                                          false);
529 
530                                         s.EOL();
531                                     }
532                                 }
533                             }
534                         }
535                     }
536                 }
537                 if (fail_count)
538                     result.SetStatus (eReturnStatusFailed);
539             }
540             else if (variable_list)
541             {
542                 if (command.GetArgumentCount() > 0)
543                 {
544                     // If we have any args to the variable command, we will make
545                     // variable objects from them...
546                     for (idx = 0; (name_cstr = command.GetArgumentAtIndex(idx)) != NULL; ++idx)
547                     {
548                         uint32_t ptr_depth = m_options.ptr_depth;
549                         // If first character is a '*', then show pointer contents
550                         if (name_cstr[0] == '*')
551                         {
552                             ++ptr_depth;
553                             name_cstr++; // Skip the '*'
554                         }
555 
556                         std::string var_path (name_cstr);
557                         size_t separator_idx = var_path.find_first_of(".-[");
558 
559                         ConstString name_const_string;
560                         if (separator_idx == std::string::npos)
561                             name_const_string.SetCString (var_path.c_str());
562                         else
563                             name_const_string.SetCStringWithLength (var_path.c_str(), separator_idx);
564 
565                         var_sp = variable_list->FindVariable(name_const_string);
566                         if (var_sp)
567                         {
568                             valobj_sp = exe_ctx.frame->GetValueObjectForFrameVariable (var_sp);
569 
570                             var_path.erase (0, name_const_string.GetLength ());
571                             // We are dumping at least one child
572                             while (separator_idx != std::string::npos)
573                             {
574                                 // Calculate the next separator index ahead of time
575                                 ValueObjectSP child_valobj_sp;
576                                 const char separator_type = var_path[0];
577                                 switch (separator_type)
578                                 {
579 
580                                 case '-':
581                                     if (var_path.size() >= 2 && var_path[1] != '>')
582                                     {
583                                         result.GetErrorStream().Printf ("error: invalid character in variable path starting at '%s'\n",
584                                                                         var_path.c_str());
585                                         var_path.clear();
586                                         valobj_sp.reset();
587                                         break;
588                                     }
589                                     var_path.erase (0, 1); // Remove the '-'
590                                     // Fall through
591                                 case '.':
592                                     {
593                                         var_path.erase (0, 1); // Remove the '.' or '>'
594                                         separator_idx = var_path.find_first_of(".-[");
595                                         ConstString child_name;
596                                         if (separator_idx == std::string::npos)
597                                             child_name.SetCString (var_path.c_str());
598                                         else
599                                             child_name.SetCStringWithLength(var_path.c_str(), separator_idx);
600 
601                                         child_valobj_sp = valobj_sp->GetChildMemberWithName (child_name, true);
602                                         if (!child_valobj_sp)
603                                         {
604                                             result.GetErrorStream().Printf ("error: can't find child of '%s' named '%s'\n",
605                                                                             valobj_sp->GetName().AsCString(),
606                                                                             child_name.GetCString());
607                                             var_path.clear();
608                                             valobj_sp.reset();
609                                             break;
610                                         }
611                                         // Remove the child name from the path
612                                         var_path.erase(0, child_name.GetLength());
613                                     }
614                                     break;
615 
616                                 case '[':
617                                     // Array member access, or treating pointer as an array
618                                     if (var_path.size() > 2) // Need at least two brackets and a number
619                                     {
620                                         char *end = NULL;
621                                         int32_t child_index = ::strtol (&var_path[1], &end, 0);
622                                         if (end && *end == ']')
623                                         {
624 
625                                             if (valobj_sp->IsPointerType ())
626                                             {
627                                                 child_valobj_sp = valobj_sp->GetSyntheticArrayMemberFromPointer (child_index, true);
628                                             }
629                                             else
630                                             {
631                                                 child_valobj_sp = valobj_sp->GetChildAtIndex (child_index, true);
632                                             }
633 
634                                             if (!child_valobj_sp)
635                                             {
636                                                 result.GetErrorStream().Printf ("error: invalid array index %u in '%s'\n",
637                                                                                 child_index,
638                                                                                 valobj_sp->GetName().AsCString());
639                                                 var_path.clear();
640                                                 valobj_sp.reset();
641                                                 break;
642                                             }
643 
644                                             // Erase the array member specification '[%i]' where %i is the array index
645                                             var_path.erase(0, (end - var_path.c_str()) + 1);
646                                             separator_idx = var_path.find_first_of(".-[");
647 
648                                             // Break out early from the switch since we were able to find the child member
649                                             break;
650                                         }
651                                     }
652                                     result.GetErrorStream().Printf ("error: invalid array member specification for '%s' starting at '%s'\n",
653                                                                     valobj_sp->GetName().AsCString(),
654                                                                     var_path.c_str());
655                                     var_path.clear();
656                                     valobj_sp.reset();
657                                     break;
658 
659                                     break;
660 
661                                 default:
662                                     result.GetErrorStream().Printf ("error: invalid character in variable path starting at '%s'\n",
663                                                                         var_path.c_str());
664                                     var_path.clear();
665                                     valobj_sp.reset();
666                                     separator_idx = std::string::npos;
667                                     break;
668                                 }
669 
670                                 if (child_valobj_sp)
671                                     valobj_sp = child_valobj_sp;
672 
673                                 if (var_path.empty())
674                                     break;
675 
676                             }
677 
678                             if (valobj_sp)
679                             {
680                                 if (m_options.show_decl && var_sp->GetDeclaration ().GetFile())
681                                 {
682                                     var_sp->GetDeclaration ().DumpStopContext (&s, false);
683                                     s.PutCString (": ");
684                                 }
685 
686                                 DumpValueObject (result,
687                                                  exe_ctx.frame,
688                                                  valobj_sp.get(),
689                                                  name_cstr,
690                                                  ptr_depth,
691                                                  0,
692                                                  m_options.max_depth,
693                                                  m_options.use_objc,
694                                                  false);
695 
696                                 s.EOL();
697                             }
698                         }
699                         else
700                         {
701                             result.GetErrorStream().Printf ("error: unable to find any variables named '%s'\n", name_cstr);
702                             var_path.clear();
703                         }
704                     }
705                 }
706                 else
707                 {
708                     const uint32_t num_variables = variable_list->GetSize();
709 
710                     if (num_variables > 0)
711                     {
712                         for (uint32_t i=0; i<num_variables; i++)
713                         {
714                             VariableSP var_sp (variable_list->GetVariableAtIndex(i));
715                             bool dump_variable = true;
716 
717                             switch (var_sp->GetScope())
718                             {
719                             case eValueTypeVariableGlobal:
720                                 dump_variable = m_options.show_globals;
721                                 if (dump_variable && m_options.show_scope)
722                                     s.PutCString("GLOBAL: ");
723                                 break;
724 
725                             case eValueTypeVariableStatic:
726                                 dump_variable = m_options.show_globals;
727                                 if (dump_variable && m_options.show_scope)
728                                     s.PutCString("STATIC: ");
729                                 break;
730 
731                             case eValueTypeVariableArgument:
732                                 dump_variable = m_options.show_args;
733                                 if (dump_variable && m_options.show_scope)
734                                     s.PutCString("   ARG: ");
735                                 break;
736 
737                             case eValueTypeVariableLocal:
738                                 dump_variable = m_options.show_locals;
739                                 if (dump_variable && m_options.show_scope)
740                                     s.PutCString(" LOCAL: ");
741                                 break;
742 
743                             default:
744                                 break;
745                             }
746 
747                             if (dump_variable)
748                             {
749 
750                                 // Use the variable object code to make sure we are
751                                 // using the same APIs as the the public API will be
752                                 // using...
753                                 valobj_sp = exe_ctx.frame->GetValueObjectForFrameVariable (var_sp);
754                                 if (valobj_sp)
755                                 {
756                                     // When dumping all variables, don't print any variables
757                                     // that are not in scope to avoid extra unneeded output
758                                     if (valobj_sp->IsInScope (exe_ctx.frame))
759                                     {
760                                         if (m_options.show_decl && var_sp->GetDeclaration ().GetFile())
761                                         {
762                                             var_sp->GetDeclaration ().DumpStopContext (&s, false);
763                                             s.PutCString (": ");
764                                         }
765                                         DumpValueObject (result,
766                                                          exe_ctx.frame,
767                                                          valobj_sp.get(),
768                                                          name_cstr,
769                                                          m_options.ptr_depth,
770                                                          0,
771                                                          m_options.max_depth,
772                                                          m_options.use_objc,
773                                                          true);
774 
775                                         s.EOL();
776                                     }
777                                 }
778                             }
779                         }
780                     }
781                 }
782                 result.SetStatus (eReturnStatusSuccessFinishResult);
783             }
784         }
785         return result.Succeeded();
786     }
787 protected:
788 
789     CommandOptions m_options;
790 };
791 
792 lldb::OptionDefinition
793 CommandObjectFrameVariable::CommandOptions::g_option_table[] =
794 {
795 { LLDB_OPT_SET_1, false, "debug",      'D', no_argument,       NULL, 0, eArgTypeNone,    "Enable verbose debug information."},
796 { LLDB_OPT_SET_1, false, "depth",      'd', required_argument, NULL, 0, eArgTypeCount,   "Set the max recurse depth when dumping aggregate types (default is infinity)."},
797 { LLDB_OPT_SET_1, false, "show-globals",'g', no_argument,      NULL, 0, eArgTypeNone,    "Show the current frame source file global and static variables."},
798 { LLDB_OPT_SET_1, false, "find-global",'G', required_argument, NULL, 0, eArgTypeVarName, "Find a global variable by name (which might not be in the current stack frame source file)."},
799 { LLDB_OPT_SET_1, false, "location",   'L', no_argument,       NULL, 0, eArgTypeNone,    "Show variable location information."},
800 { LLDB_OPT_SET_1, false, "show-declaration", 'c', no_argument, NULL, 0, eArgTypeNone,    "Show variable declaration information (source file and line where the variable was declared)."},
801 { LLDB_OPT_SET_1, false, "name",       'n', required_argument, NULL, 0, eArgTypeVarName, "Lookup a variable by name or regex (--regex) for the current execution context."},
802 { LLDB_OPT_SET_1, false, "no-args",    'a', no_argument,       NULL, 0, eArgTypeNone,    "Omit function arguments."},
803 { LLDB_OPT_SET_1, false, "no-locals",  'l', no_argument,       NULL, 0, eArgTypeNone,    "Omit local variables."},
804 { LLDB_OPT_SET_1, false, "no-types",   't', no_argument,       NULL, 0, eArgTypeNone,    "Omit variable type names."},
805 { LLDB_OPT_SET_1, false, "no-summary", 'y', no_argument,       NULL, 0, eArgTypeNone,    "Omit summary information."},
806 { LLDB_OPT_SET_1, false, "scope",      's', no_argument,       NULL, 0, eArgTypeNone,    "Show variable scope (argument, local, global, static)."},
807 { LLDB_OPT_SET_1, false, "objc",       'o', no_argument,       NULL, 0, eArgTypeNone,    "When looking up a variable by name (--name), print as an Objective-C object."},
808 { LLDB_OPT_SET_1, false, "ptr-depth",  'p', required_argument, NULL, 0, eArgTypeCount,   "The number of pointers to be traversed when dumping values (default is zero)."},
809 { LLDB_OPT_SET_1, false, "regex",      'r', no_argument,       NULL, 0, eArgTypeCount,    "The <name> argument for name lookups are regular expressions."},
810 { 0, false, NULL, 0, 0, NULL, NULL, eArgTypeNone, NULL }
811 };
812 #pragma mark CommandObjectMultiwordFrame
813 
814 //-------------------------------------------------------------------------
815 // CommandObjectMultiwordFrame
816 //-------------------------------------------------------------------------
817 
818 CommandObjectMultiwordFrame::CommandObjectMultiwordFrame (CommandInterpreter &interpreter) :
819     CommandObjectMultiword (interpreter,
820                             "frame",
821                             "A set of commands for operating on the current thread's frames.",
822                             "frame <subcommand> [<subcommand-options>]")
823 {
824     LoadSubCommand ("info",   CommandObjectSP (new CommandObjectFrameInfo (interpreter)));
825     LoadSubCommand ("select", CommandObjectSP (new CommandObjectFrameSelect (interpreter)));
826     LoadSubCommand ("variable", CommandObjectSP (new CommandObjectFrameVariable (interpreter)));
827 }
828 
829 CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame ()
830 {
831 }
832 
833