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