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 // C Includes
11 // C++ Includes
12 #include <string>
13 
14 // Other libraries and framework includes
15 // Project includes
16 #include "CommandObjectFrame.h"
17 #include "lldb/Core/Debugger.h"
18 #include "lldb/Core/Module.h"
19 #include "lldb/Core/StreamFile.h"
20 #include "lldb/Core/StreamString.h"
21 #include "lldb/Core/Timer.h"
22 #include "lldb/Core/Value.h"
23 #include "lldb/Core/ValueObject.h"
24 #include "lldb/Core/ValueObjectVariable.h"
25 #include "lldb/DataFormatters/DataVisualization.h"
26 #include "lldb/DataFormatters/ValueObjectPrinter.h"
27 #include "lldb/Host/Host.h"
28 #include "lldb/Host/StringConvert.h"
29 #include "lldb/Interpreter/Args.h"
30 #include "lldb/Interpreter/CommandInterpreter.h"
31 #include "lldb/Interpreter/CommandReturnObject.h"
32 #include "lldb/Interpreter/OptionGroupFormat.h"
33 #include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
34 #include "lldb/Interpreter/OptionGroupVariable.h"
35 #include "lldb/Interpreter/Options.h"
36 #include "lldb/Symbol/ClangASTContext.h"
37 #include "lldb/Symbol/CompilerType.h"
38 #include "lldb/Symbol/Function.h"
39 #include "lldb/Symbol/ObjectFile.h"
40 #include "lldb/Symbol/SymbolContext.h"
41 #include "lldb/Symbol/Type.h"
42 #include "lldb/Symbol/Variable.h"
43 #include "lldb/Symbol/VariableList.h"
44 #include "lldb/Target/Process.h"
45 #include "lldb/Target/StackFrame.h"
46 #include "lldb/Target/StopInfo.h"
47 #include "lldb/Target/Target.h"
48 #include "lldb/Target/Thread.h"
49 #include "lldb/Utility/LLDBAssert.h"
50 
51 using namespace lldb;
52 using namespace lldb_private;
53 
54 #pragma mark CommandObjectFrameDiagnose
55 
56 //-------------------------------------------------------------------------
57 // CommandObjectFrameInfo
58 //-------------------------------------------------------------------------
59 
60 //-------------------------------------------------------------------------
61 // CommandObjectFrameDiagnose
62 //-------------------------------------------------------------------------
63 
64 static OptionDefinition g_frame_diag_options[] = {
65     // clang-format off
66   { LLDB_OPT_SET_1, false, "register", 'r', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeRegisterName,    "A register to diagnose." },
67   { LLDB_OPT_SET_1, false, "address",  'a', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeAddress,         "An address to diagnose." },
68   { LLDB_OPT_SET_1, false, "offset",   'o', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeOffset,          "An optional offset.  Requires --register." }
69     // clang-format on
70 };
71 
72 class CommandObjectFrameDiagnose : public CommandObjectParsed {
73 public:
74   class CommandOptions : public Options {
75   public:
76     CommandOptions() : Options() { OptionParsingStarting(nullptr); }
77 
78     ~CommandOptions() override = default;
79 
80     Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
81                          ExecutionContext *execution_context) override {
82       Error error;
83       const int short_option = m_getopt_table[option_idx].val;
84       switch (short_option) {
85       case 'r':
86         reg = ConstString(option_arg);
87         break;
88 
89       case 'a': {
90         address.emplace();
91         if (option_arg.getAsInteger(0, *address)) {
92           address.reset();
93           error.SetErrorStringWithFormat("invalid address argument '%s'",
94                                          option_arg.str().c_str());
95         }
96       } break;
97 
98       case 'o': {
99         offset.emplace();
100         if (option_arg.getAsInteger(0, *offset)) {
101           offset.reset();
102           error.SetErrorStringWithFormat("invalid offset argument '%s'",
103                                          option_arg.str().c_str());
104         }
105       } break;
106 
107       default:
108         error.SetErrorStringWithFormat("invalid short option character '%c'",
109                                        short_option);
110         break;
111       }
112 
113       return error;
114     }
115 
116     void OptionParsingStarting(ExecutionContext *execution_context) override {
117       address.reset();
118       reg.reset();
119       offset.reset();
120     }
121 
122     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
123       return llvm::makeArrayRef(g_frame_diag_options);
124     }
125 
126     // Options.
127     llvm::Optional<lldb::addr_t> address;
128     llvm::Optional<ConstString> reg;
129     llvm::Optional<int64_t> offset;
130   };
131 
132   CommandObjectFrameDiagnose(CommandInterpreter &interpreter)
133       : CommandObjectParsed(interpreter, "frame diagnose",
134                             "Try to determine what path path the current stop "
135                             "location used to get to a register or address",
136                             nullptr,
137                             eCommandRequiresThread | eCommandTryTargetAPILock |
138                                 eCommandProcessMustBeLaunched |
139                                 eCommandProcessMustBePaused),
140         m_options() {
141     CommandArgumentEntry arg;
142     CommandArgumentData index_arg;
143 
144     // Define the first (and only) variant of this arg.
145     index_arg.arg_type = eArgTypeFrameIndex;
146     index_arg.arg_repetition = eArgRepeatOptional;
147 
148     // There is only one variant this argument could be; put it into the
149     // argument entry.
150     arg.push_back(index_arg);
151 
152     // Push the data for the first argument into the m_arguments vector.
153     m_arguments.push_back(arg);
154   }
155 
156   ~CommandObjectFrameDiagnose() override = default;
157 
158   Options *GetOptions() override { return &m_options; }
159 
160 protected:
161   bool DoExecute(Args &command, CommandReturnObject &result) override {
162     Thread *thread = m_exe_ctx.GetThreadPtr();
163     StackFrameSP frame_sp = thread->GetSelectedFrame();
164 
165     ValueObjectSP valobj_sp;
166 
167     if (m_options.address.hasValue()) {
168       if (m_options.reg.hasValue() || m_options.offset.hasValue()) {
169         result.AppendError(
170             "`frame diagnose --address` is incompatible with other arguments.");
171         result.SetStatus(eReturnStatusFailed);
172         return false;
173       }
174       valobj_sp = frame_sp->GuessValueForAddress(m_options.address.getValue());
175     } else if (m_options.reg.hasValue()) {
176       valobj_sp = frame_sp->GuessValueForRegisterAndOffset(
177           m_options.reg.getValue(), m_options.offset.getValueOr(0));
178     } else {
179       StopInfoSP stop_info_sp = thread->GetStopInfo();
180       if (!stop_info_sp) {
181         result.AppendError("No arguments provided, and no stop info.");
182         result.SetStatus(eReturnStatusFailed);
183         return false;
184       }
185 
186       valobj_sp = StopInfo::GetCrashingDereference(stop_info_sp);
187     }
188 
189     if (!valobj_sp) {
190       result.AppendError("No diagnosis available.");
191       result.SetStatus(eReturnStatusFailed);
192       return false;
193     }
194 
195     const bool qualify_cxx_base_classes = false;
196 
197     DumpValueObjectOptions::DeclPrintingHelper helper =
198         [&valobj_sp, qualify_cxx_base_classes](
199             ConstString type, ConstString var,
200             const DumpValueObjectOptions &opts, Stream &stream) -> bool {
201       const ValueObject::GetExpressionPathFormat format = ValueObject::
202           GetExpressionPathFormat::eGetExpressionPathFormatHonorPointers;
203       valobj_sp->GetExpressionPath(stream, qualify_cxx_base_classes, format);
204       stream.PutCString(" =");
205       return true;
206     };
207 
208     DumpValueObjectOptions options;
209     options.SetDeclPrintingHelper(helper);
210     ValueObjectPrinter printer(valobj_sp.get(), &result.GetOutputStream(),
211                                options);
212     printer.PrintValueObject();
213 
214     return true;
215   }
216 
217 protected:
218   CommandOptions m_options;
219 };
220 
221 #pragma mark CommandObjectFrameInfo
222 
223 //-------------------------------------------------------------------------
224 // CommandObjectFrameInfo
225 //-------------------------------------------------------------------------
226 
227 class CommandObjectFrameInfo : public CommandObjectParsed {
228 public:
229   CommandObjectFrameInfo(CommandInterpreter &interpreter)
230       : CommandObjectParsed(
231             interpreter, "frame info", "List information about the current "
232                                        "stack frame in the current thread.",
233             "frame info",
234             eCommandRequiresFrame | eCommandTryTargetAPILock |
235                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {}
236 
237   ~CommandObjectFrameInfo() override = default;
238 
239 protected:
240   bool DoExecute(Args &command, CommandReturnObject &result) override {
241     m_exe_ctx.GetFrameRef().DumpUsingSettingsFormat(&result.GetOutputStream());
242     result.SetStatus(eReturnStatusSuccessFinishResult);
243     return result.Succeeded();
244   }
245 };
246 
247 #pragma mark CommandObjectFrameSelect
248 
249 //-------------------------------------------------------------------------
250 // CommandObjectFrameSelect
251 //-------------------------------------------------------------------------
252 
253 static OptionDefinition g_frame_select_options[] = {
254     // clang-format off
255   { LLDB_OPT_SET_1, false, "relative", 'r', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeOffset, "A relative frame index offset from the current frame index." },
256     // clang-format on
257 };
258 
259 class CommandObjectFrameSelect : public CommandObjectParsed {
260 public:
261   class CommandOptions : public Options {
262   public:
263     CommandOptions() : Options() { OptionParsingStarting(nullptr); }
264 
265     ~CommandOptions() override = default;
266 
267     Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
268                          ExecutionContext *execution_context) override {
269       Error error;
270       const int short_option = m_getopt_table[option_idx].val;
271       switch (short_option) {
272       case 'r':
273         if (option_arg.getAsInteger(0, relative_frame_offset)) {
274           relative_frame_offset = INT32_MIN;
275           error.SetErrorStringWithFormat("invalid frame offset argument '%s'",
276                                          option_arg.str().c_str());
277         }
278         break;
279 
280       default:
281         error.SetErrorStringWithFormat("invalid short option character '%c'",
282                                        short_option);
283         break;
284       }
285 
286       return error;
287     }
288 
289     void OptionParsingStarting(ExecutionContext *execution_context) override {
290       relative_frame_offset = INT32_MIN;
291     }
292 
293     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
294       return llvm::makeArrayRef(g_frame_select_options);
295     }
296 
297     int32_t relative_frame_offset;
298   };
299 
300   CommandObjectFrameSelect(CommandInterpreter &interpreter)
301       : CommandObjectParsed(
302             interpreter, "frame select", "Select the current stack frame by "
303                                          "index from within the current thread "
304                                          "(see 'thread backtrace'.)",
305             nullptr,
306             eCommandRequiresThread | eCommandTryTargetAPILock |
307                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused),
308         m_options() {
309     CommandArgumentEntry arg;
310     CommandArgumentData index_arg;
311 
312     // Define the first (and only) variant of this arg.
313     index_arg.arg_type = eArgTypeFrameIndex;
314     index_arg.arg_repetition = eArgRepeatOptional;
315 
316     // There is only one variant this argument could be; put it into the
317     // argument entry.
318     arg.push_back(index_arg);
319 
320     // Push the data for the first argument into the m_arguments vector.
321     m_arguments.push_back(arg);
322   }
323 
324   ~CommandObjectFrameSelect() override = default;
325 
326   Options *GetOptions() override { return &m_options; }
327 
328 protected:
329   bool DoExecute(Args &command, CommandReturnObject &result) override {
330     // No need to check "thread" for validity as eCommandRequiresThread ensures
331     // it is valid
332     Thread *thread = m_exe_ctx.GetThreadPtr();
333 
334     uint32_t frame_idx = UINT32_MAX;
335     if (m_options.relative_frame_offset != INT32_MIN) {
336       // The one and only argument is a signed relative frame index
337       frame_idx = thread->GetSelectedFrameIndex();
338       if (frame_idx == UINT32_MAX)
339         frame_idx = 0;
340 
341       if (m_options.relative_frame_offset < 0) {
342         if (static_cast<int32_t>(frame_idx) >= -m_options.relative_frame_offset)
343           frame_idx += m_options.relative_frame_offset;
344         else {
345           if (frame_idx == 0) {
346             // If you are already at the bottom of the stack, then just warn and
347             // don't reset the frame.
348             result.AppendError("Already at the bottom of the stack.");
349             result.SetStatus(eReturnStatusFailed);
350             return false;
351           } else
352             frame_idx = 0;
353         }
354       } else if (m_options.relative_frame_offset > 0) {
355         // I don't want "up 20" where "20" takes you past the top of the stack
356         // to produce
357         // an error, but rather to just go to the top.  So I have to count the
358         // stack here...
359         const uint32_t num_frames = thread->GetStackFrameCount();
360         if (static_cast<int32_t>(num_frames - frame_idx) >
361             m_options.relative_frame_offset)
362           frame_idx += m_options.relative_frame_offset;
363         else {
364           if (frame_idx == num_frames - 1) {
365             // If we are already at the top of the stack, just warn and don't
366             // reset the frame.
367             result.AppendError("Already at the top of the stack.");
368             result.SetStatus(eReturnStatusFailed);
369             return false;
370           } else
371             frame_idx = num_frames - 1;
372         }
373       }
374     } else {
375       if (command.GetArgumentCount() == 1) {
376         const char *frame_idx_cstr = command.GetArgumentAtIndex(0);
377         bool success = false;
378         frame_idx =
379             StringConvert::ToUInt32(frame_idx_cstr, UINT32_MAX, 0, &success);
380         if (!success) {
381           result.AppendErrorWithFormat("invalid frame index argument '%s'.",
382                                        frame_idx_cstr);
383           result.SetStatus(eReturnStatusFailed);
384           return false;
385         }
386       } else if (command.GetArgumentCount() == 0) {
387         frame_idx = thread->GetSelectedFrameIndex();
388         if (frame_idx == UINT32_MAX) {
389           frame_idx = 0;
390         }
391       } else {
392         result.AppendErrorWithFormat(
393             "too many arguments; expected frame-index, saw '%s'.\n",
394             command.GetArgumentAtIndex(0));
395         m_options.GenerateOptionUsage(
396             result.GetErrorStream(), this,
397             GetCommandInterpreter().GetDebugger().GetTerminalWidth());
398         return false;
399       }
400     }
401 
402     bool success = thread->SetSelectedFrameByIndexNoisily(
403         frame_idx, result.GetOutputStream());
404     if (success) {
405       m_exe_ctx.SetFrameSP(thread->GetSelectedFrame());
406       result.SetStatus(eReturnStatusSuccessFinishResult);
407     } else {
408       result.AppendErrorWithFormat("Frame index (%u) out of range.\n",
409                                    frame_idx);
410       result.SetStatus(eReturnStatusFailed);
411     }
412 
413     return result.Succeeded();
414   }
415 
416 protected:
417   CommandOptions m_options;
418 };
419 
420 #pragma mark CommandObjectFrameVariable
421 //----------------------------------------------------------------------
422 // List images with associated information
423 //----------------------------------------------------------------------
424 class CommandObjectFrameVariable : public CommandObjectParsed {
425 public:
426   CommandObjectFrameVariable(CommandInterpreter &interpreter)
427       : CommandObjectParsed(
428             interpreter, "frame variable",
429             "Show variables for the current stack frame. Defaults to all "
430             "arguments and local variables in scope. Names of argument, "
431             "local, file static and file global variables can be specified. "
432             "Children of aggregate variables can be specified such as "
433             "'var->child.x'.",
434             nullptr, eCommandRequiresFrame | eCommandTryTargetAPILock |
435                          eCommandProcessMustBeLaunched |
436                          eCommandProcessMustBePaused | eCommandRequiresProcess),
437         m_option_group(),
438         m_option_variable(
439             true), // Include the frame specific options by passing "true"
440         m_option_format(eFormatDefault),
441         m_varobj_options() {
442     CommandArgumentEntry arg;
443     CommandArgumentData var_name_arg;
444 
445     // Define the first (and only) variant of this arg.
446     var_name_arg.arg_type = eArgTypeVarName;
447     var_name_arg.arg_repetition = eArgRepeatStar;
448 
449     // There is only one variant this argument could be; put it into the
450     // argument entry.
451     arg.push_back(var_name_arg);
452 
453     // Push the data for the first argument into the m_arguments vector.
454     m_arguments.push_back(arg);
455 
456     m_option_group.Append(&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
457     m_option_group.Append(&m_option_format,
458                           OptionGroupFormat::OPTION_GROUP_FORMAT |
459                               OptionGroupFormat::OPTION_GROUP_GDB_FMT,
460                           LLDB_OPT_SET_1);
461     m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
462     m_option_group.Finalize();
463   }
464 
465   ~CommandObjectFrameVariable() override = default;
466 
467   Options *GetOptions() override { return &m_option_group; }
468 
469   int HandleArgumentCompletion(Args &input, int &cursor_index,
470                                int &cursor_char_position,
471                                OptionElementVector &opt_element_vector,
472                                int match_start_point, int max_return_elements,
473                                bool &word_complete,
474                                StringList &matches) override {
475     // Arguments are the standard source file completer.
476     auto completion_str = input[cursor_index].ref;
477     completion_str = completion_str.take_front(cursor_char_position);
478 
479     CommandCompletions::InvokeCommonCompletionCallbacks(
480         GetCommandInterpreter(), CommandCompletions::eVariablePathCompletion,
481         completion_str, match_start_point, max_return_elements, nullptr,
482         word_complete, matches);
483     return matches.GetSize();
484   }
485 
486 protected:
487   llvm::StringRef GetScopeString(VariableSP var_sp) {
488     if (!var_sp)
489       return llvm::StringRef::withNullAsEmpty(nullptr);
490 
491     switch (var_sp->GetScope()) {
492     case eValueTypeVariableGlobal:
493       return "GLOBAL: ";
494     case eValueTypeVariableStatic:
495       return "STATIC: ";
496     case eValueTypeVariableArgument:
497       return "ARG: ";
498     case eValueTypeVariableLocal:
499       return "LOCAL: ";
500     case eValueTypeVariableThreadLocal:
501       return "THREAD: ";
502     default:
503       break;
504     }
505 
506     return llvm::StringRef::withNullAsEmpty(nullptr);
507   }
508 
509   bool DoExecute(Args &command, CommandReturnObject &result) override {
510     // No need to check "frame" for validity as eCommandRequiresFrame ensures it
511     // is valid
512     StackFrame *frame = m_exe_ctx.GetFramePtr();
513 
514     Stream &s = result.GetOutputStream();
515 
516     // Be careful about the stack frame, if any summary formatter runs code, it
517     // might clear the StackFrameList
518     // for the thread.  So hold onto a shared pointer to the frame so it stays
519     // alive.
520 
521     VariableList *variable_list =
522         frame->GetVariableList(m_option_variable.show_globals);
523 
524     VariableSP var_sp;
525     ValueObjectSP valobj_sp;
526 
527     const char *name_cstr = nullptr;
528     size_t idx;
529 
530     TypeSummaryImplSP summary_format_sp;
531     if (!m_option_variable.summary.IsCurrentValueEmpty())
532       DataVisualization::NamedSummaryFormats::GetSummaryFormat(
533           ConstString(m_option_variable.summary.GetCurrentValue()),
534           summary_format_sp);
535     else if (!m_option_variable.summary_string.IsCurrentValueEmpty())
536       summary_format_sp.reset(new StringSummaryFormat(
537           TypeSummaryImpl::Flags(),
538           m_option_variable.summary_string.GetCurrentValue()));
539 
540     DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(
541         eLanguageRuntimeDescriptionDisplayVerbosityFull, eFormatDefault,
542         summary_format_sp));
543 
544     const SymbolContext &sym_ctx =
545         frame->GetSymbolContext(eSymbolContextFunction);
546     if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction())
547       m_option_variable.show_globals = true;
548 
549     if (variable_list) {
550       const Format format = m_option_format.GetFormat();
551       options.SetFormat(format);
552 
553       if (!command.empty()) {
554         VariableList regex_var_list;
555 
556         // If we have any args to the variable command, we will make
557         // variable objects from them...
558         for (idx = 0; (name_cstr = command.GetArgumentAtIndex(idx)) != nullptr;
559              ++idx) {
560           if (m_option_variable.use_regex) {
561             const size_t regex_start_index = regex_var_list.GetSize();
562             llvm::StringRef name_str(name_cstr);
563             RegularExpression regex(name_str);
564             if (regex.Compile(name_str)) {
565               size_t num_matches = 0;
566               const size_t num_new_regex_vars =
567                   variable_list->AppendVariablesIfUnique(regex, regex_var_list,
568                                                          num_matches);
569               if (num_new_regex_vars > 0) {
570                 for (size_t regex_idx = regex_start_index,
571                             end_index = regex_var_list.GetSize();
572                      regex_idx < end_index; ++regex_idx) {
573                   var_sp = regex_var_list.GetVariableAtIndex(regex_idx);
574                   if (var_sp) {
575                     valobj_sp = frame->GetValueObjectForFrameVariable(
576                         var_sp, m_varobj_options.use_dynamic);
577                     if (valobj_sp) {
578                       //                                            if (format
579                       //                                            !=
580                       //                                            eFormatDefault)
581                       //                                                valobj_sp->SetFormat
582                       //                                                (format);
583 
584                       std::string scope_string;
585                       if (m_option_variable.show_scope)
586                         scope_string = GetScopeString(var_sp).str();
587 
588                       if (!scope_string.empty())
589                         s.PutCString(scope_string);
590 
591                       if (m_option_variable.show_decl &&
592                           var_sp->GetDeclaration().GetFile()) {
593                         bool show_fullpaths = false;
594                         bool show_module = true;
595                         if (var_sp->DumpDeclaration(&s, show_fullpaths,
596                                                     show_module))
597                           s.PutCString(": ");
598                       }
599                       valobj_sp->Dump(result.GetOutputStream(), options);
600                     }
601                   }
602                 }
603               } else if (num_matches == 0) {
604                 result.GetErrorStream().Printf("error: no variables matched "
605                                                "the regular expression '%s'.\n",
606                                                name_cstr);
607               }
608             } else {
609               char regex_error[1024];
610               if (regex.GetErrorAsCString(regex_error, sizeof(regex_error)))
611                 result.GetErrorStream().Printf("error: %s\n", regex_error);
612               else
613                 result.GetErrorStream().Printf(
614                     "error: unknown regex error when compiling '%s'\n",
615                     name_cstr);
616             }
617           } else // No regex, either exact variable names or variable
618                  // expressions.
619           {
620             Error error;
621             uint32_t expr_path_options =
622                 StackFrame::eExpressionPathOptionCheckPtrVsMember |
623                 StackFrame::eExpressionPathOptionsAllowDirectIVarAccess |
624                 StackFrame::eExpressionPathOptionsInspectAnonymousUnions;
625             lldb::VariableSP var_sp;
626             valobj_sp = frame->GetValueForVariableExpressionPath(
627                 name_cstr, m_varobj_options.use_dynamic, expr_path_options,
628                 var_sp, error);
629             if (valobj_sp) {
630               std::string scope_string;
631               if (m_option_variable.show_scope)
632                 scope_string = GetScopeString(var_sp).str();
633 
634               if (!scope_string.empty())
635                 s.PutCString(scope_string);
636 
637               //                            if (format != eFormatDefault)
638               //                                valobj_sp->SetFormat (format);
639               if (m_option_variable.show_decl && var_sp &&
640                   var_sp->GetDeclaration().GetFile()) {
641                 var_sp->GetDeclaration().DumpStopContext(&s, false);
642                 s.PutCString(": ");
643               }
644 
645               options.SetFormat(format);
646               options.SetVariableFormatDisplayLanguage(
647                   valobj_sp->GetPreferredDisplayLanguage());
648 
649               Stream &output_stream = result.GetOutputStream();
650               options.SetRootValueObjectName(valobj_sp->GetParent() ? name_cstr
651                                                                     : nullptr);
652               valobj_sp->Dump(output_stream, options);
653             } else {
654               const char *error_cstr = error.AsCString(nullptr);
655               if (error_cstr)
656                 result.GetErrorStream().Printf("error: %s\n", error_cstr);
657               else
658                 result.GetErrorStream().Printf("error: unable to find any "
659                                                "variable expression path that "
660                                                "matches '%s'.\n",
661                                                name_cstr);
662             }
663           }
664         }
665       } else // No command arg specified.  Use variable_list, instead.
666       {
667         const size_t num_variables = variable_list->GetSize();
668         if (num_variables > 0) {
669           for (size_t i = 0; i < num_variables; i++) {
670             var_sp = variable_list->GetVariableAtIndex(i);
671             bool dump_variable = true;
672             std::string scope_string;
673             if (dump_variable && m_option_variable.show_scope)
674               scope_string = GetScopeString(var_sp).str();
675 
676             if (dump_variable) {
677               // Use the variable object code to make sure we are
678               // using the same APIs as the public API will be
679               // using...
680               valobj_sp = frame->GetValueObjectForFrameVariable(
681                   var_sp, m_varobj_options.use_dynamic);
682               if (valobj_sp) {
683                 //                                if (format != eFormatDefault)
684                 //                                    valobj_sp->SetFormat
685                 //                                    (format);
686 
687                 // When dumping all variables, don't print any variables
688                 // that are not in scope to avoid extra unneeded output
689                 if (valobj_sp->IsInScope()) {
690                   if (!valobj_sp->GetTargetSP()
691                            ->GetDisplayRuntimeSupportValues() &&
692                       valobj_sp->IsRuntimeSupportValue())
693                     continue;
694 
695                   if (!scope_string.empty())
696                     s.PutCString(scope_string);
697 
698                   if (m_option_variable.show_decl &&
699                       var_sp->GetDeclaration().GetFile()) {
700                     var_sp->GetDeclaration().DumpStopContext(&s, false);
701                     s.PutCString(": ");
702                   }
703 
704                   options.SetFormat(format);
705                   options.SetVariableFormatDisplayLanguage(
706                       valobj_sp->GetPreferredDisplayLanguage());
707                   options.SetRootValueObjectName(name_cstr);
708                   valobj_sp->Dump(result.GetOutputStream(), options);
709                 }
710               }
711             }
712           }
713         }
714       }
715       result.SetStatus(eReturnStatusSuccessFinishResult);
716     }
717 
718     if (m_interpreter.TruncationWarningNecessary()) {
719       result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(),
720                                       m_cmd_name.c_str());
721       m_interpreter.TruncationWarningGiven();
722     }
723 
724     return result.Succeeded();
725   }
726 
727 protected:
728   OptionGroupOptions m_option_group;
729   OptionGroupVariable m_option_variable;
730   OptionGroupFormat m_option_format;
731   OptionGroupValueObjectDisplay m_varobj_options;
732 };
733 
734 #pragma mark CommandObjectMultiwordFrame
735 
736 //-------------------------------------------------------------------------
737 // CommandObjectMultiwordFrame
738 //-------------------------------------------------------------------------
739 
740 CommandObjectMultiwordFrame::CommandObjectMultiwordFrame(
741     CommandInterpreter &interpreter)
742     : CommandObjectMultiword(interpreter, "frame", "Commands for selecting and "
743                                                    "examing the current "
744                                                    "thread's stack frames.",
745                              "frame <subcommand> [<subcommand-options>]") {
746   LoadSubCommand("diagnose",
747                  CommandObjectSP(new CommandObjectFrameDiagnose(interpreter)));
748   LoadSubCommand("info",
749                  CommandObjectSP(new CommandObjectFrameInfo(interpreter)));
750   LoadSubCommand("select",
751                  CommandObjectSP(new CommandObjectFrameSelect(interpreter)));
752   LoadSubCommand("variable",
753                  CommandObjectSP(new CommandObjectFrameVariable(interpreter)));
754 }
755 
756 CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default;
757