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/Value.h"
21 #include "lldb/Core/ValueObject.h"
22 #include "lldb/Core/ValueObjectVariable.h"
23 #include "lldb/DataFormatters/DataVisualization.h"
24 #include "lldb/DataFormatters/ValueObjectPrinter.h"
25 #include "lldb/Host/Host.h"
26 #include "lldb/Host/OptionParser.h"
27 #include "lldb/Interpreter/CommandInterpreter.h"
28 #include "lldb/Interpreter/CommandReturnObject.h"
29 #include "lldb/Interpreter/OptionGroupFormat.h"
30 #include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
31 #include "lldb/Interpreter/OptionGroupVariable.h"
32 #include "lldb/Interpreter/Options.h"
33 #include "lldb/Symbol/ClangASTContext.h"
34 #include "lldb/Symbol/CompilerType.h"
35 #include "lldb/Symbol/Function.h"
36 #include "lldb/Symbol/ObjectFile.h"
37 #include "lldb/Symbol/SymbolContext.h"
38 #include "lldb/Symbol/Type.h"
39 #include "lldb/Symbol/Variable.h"
40 #include "lldb/Symbol/VariableList.h"
41 #include "lldb/Target/Process.h"
42 #include "lldb/Target/StackFrame.h"
43 #include "lldb/Target/StopInfo.h"
44 #include "lldb/Target/Target.h"
45 #include "lldb/Target/Thread.h"
46 #include "lldb/Utility/Args.h"
47 #include "lldb/Utility/LLDBAssert.h"
48 #include "lldb/Utility/StreamString.h"
49 #include "lldb/Utility/Timer.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 constexpr OptionDefinition g_frame_diag_options[] = {
65     // clang-format off
66   { LLDB_OPT_SET_1, false, "register", 'r', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeRegisterName,    "A register to diagnose." },
67   { LLDB_OPT_SET_1, false, "address",  'a', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeAddress,         "An address to diagnose." },
68   { LLDB_OPT_SET_1, false, "offset",   'o', OptionParser::eRequiredArgument, 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     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
81                           ExecutionContext *execution_context) override {
82       Status 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 
196     DumpValueObjectOptions::DeclPrintingHelper helper = [&valobj_sp](
197         ConstString type, ConstString var, const DumpValueObjectOptions &opts,
198         Stream &stream) -> bool {
199       const ValueObject::GetExpressionPathFormat format = ValueObject::
200           GetExpressionPathFormat::eGetExpressionPathFormatHonorPointers;
201       const bool qualify_cxx_base_classes = false;
202       valobj_sp->GetExpressionPath(stream, qualify_cxx_base_classes, format);
203       stream.PutCString(" =");
204       return true;
205     };
206 
207     DumpValueObjectOptions options;
208     options.SetDeclPrintingHelper(helper);
209     ValueObjectPrinter printer(valobj_sp.get(), &result.GetOutputStream(),
210                                options);
211     printer.PrintValueObject();
212 
213     return true;
214   }
215 
216 protected:
217   CommandOptions m_options;
218 };
219 
220 #pragma mark CommandObjectFrameInfo
221 
222 //-------------------------------------------------------------------------
223 // CommandObjectFrameInfo
224 //-------------------------------------------------------------------------
225 
226 class CommandObjectFrameInfo : public CommandObjectParsed {
227 public:
228   CommandObjectFrameInfo(CommandInterpreter &interpreter)
229       : CommandObjectParsed(
230             interpreter, "frame info", "List information about the current "
231                                        "stack frame in the current thread.",
232             "frame info",
233             eCommandRequiresFrame | eCommandTryTargetAPILock |
234                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {}
235 
236   ~CommandObjectFrameInfo() override = default;
237 
238 protected:
239   bool DoExecute(Args &command, CommandReturnObject &result) override {
240     m_exe_ctx.GetFrameRef().DumpUsingSettingsFormat(&result.GetOutputStream());
241     result.SetStatus(eReturnStatusSuccessFinishResult);
242     return result.Succeeded();
243   }
244 };
245 
246 #pragma mark CommandObjectFrameSelect
247 
248 //-------------------------------------------------------------------------
249 // CommandObjectFrameSelect
250 //-------------------------------------------------------------------------
251 
252 static OptionDefinition g_frame_select_options[] = {
253     // clang-format off
254   { LLDB_OPT_SET_1, false, "relative", 'r', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeOffset, "A relative frame index offset from the current frame index." },
255     // clang-format on
256 };
257 
258 class CommandObjectFrameSelect : public CommandObjectParsed {
259 public:
260   class CommandOptions : public Options {
261   public:
262     CommandOptions() : Options() { OptionParsingStarting(nullptr); }
263 
264     ~CommandOptions() override = default;
265 
266     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
267                           ExecutionContext *execution_context) override {
268       Status error;
269       const int short_option = m_getopt_table[option_idx].val;
270       switch (short_option) {
271       case 'r':
272         if (option_arg.getAsInteger(0, relative_frame_offset)) {
273           relative_frame_offset = INT32_MIN;
274           error.SetErrorStringWithFormat("invalid frame offset argument '%s'",
275                                          option_arg.str().c_str());
276         }
277         break;
278 
279       default:
280         error.SetErrorStringWithFormat("invalid short option character '%c'",
281                                        short_option);
282         break;
283       }
284 
285       return error;
286     }
287 
288     void OptionParsingStarting(ExecutionContext *execution_context) override {
289       relative_frame_offset = INT32_MIN;
290     }
291 
292     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
293       return llvm::makeArrayRef(g_frame_select_options);
294     }
295 
296     int32_t relative_frame_offset;
297   };
298 
299   CommandObjectFrameSelect(CommandInterpreter &interpreter)
300       : CommandObjectParsed(
301             interpreter, "frame select", "Select the current stack frame by "
302                                          "index from within the current thread "
303                                          "(see 'thread backtrace'.)",
304             nullptr,
305             eCommandRequiresThread | eCommandTryTargetAPILock |
306                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused),
307         m_options() {
308     CommandArgumentEntry arg;
309     CommandArgumentData index_arg;
310 
311     // Define the first (and only) variant of this arg.
312     index_arg.arg_type = eArgTypeFrameIndex;
313     index_arg.arg_repetition = eArgRepeatOptional;
314 
315     // There is only one variant this argument could be; put it into the
316     // argument entry.
317     arg.push_back(index_arg);
318 
319     // Push the data for the first argument into the m_arguments vector.
320     m_arguments.push_back(arg);
321   }
322 
323   ~CommandObjectFrameSelect() override = default;
324 
325   Options *GetOptions() override { return &m_options; }
326 
327 protected:
328   bool DoExecute(Args &command, CommandReturnObject &result) override {
329     // No need to check "thread" for validity as eCommandRequiresThread ensures
330     // it is valid
331     Thread *thread = m_exe_ctx.GetThreadPtr();
332 
333     uint32_t frame_idx = UINT32_MAX;
334     if (m_options.relative_frame_offset != INT32_MIN) {
335       // The one and only argument is a signed relative frame index
336       frame_idx = thread->GetSelectedFrameIndex();
337       if (frame_idx == UINT32_MAX)
338         frame_idx = 0;
339 
340       if (m_options.relative_frame_offset < 0) {
341         if (static_cast<int32_t>(frame_idx) >= -m_options.relative_frame_offset)
342           frame_idx += m_options.relative_frame_offset;
343         else {
344           if (frame_idx == 0) {
345             // If you are already at the bottom of the stack, then just warn
346             // and don't reset the frame.
347             result.AppendError("Already at the bottom of the stack.");
348             result.SetStatus(eReturnStatusFailed);
349             return false;
350           } else
351             frame_idx = 0;
352         }
353       } else if (m_options.relative_frame_offset > 0) {
354         // I don't want "up 20" where "20" takes you past the top of the stack
355         // to produce
356         // an error, but rather to just go to the top.  So I have to count the
357         // stack here...
358         const uint32_t num_frames = thread->GetStackFrameCount();
359         if (static_cast<int32_t>(num_frames - frame_idx) >
360             m_options.relative_frame_offset)
361           frame_idx += m_options.relative_frame_offset;
362         else {
363           if (frame_idx == num_frames - 1) {
364             // If we are already at the top of the stack, just warn and don't
365             // reset the frame.
366             result.AppendError("Already at the top of the stack.");
367             result.SetStatus(eReturnStatusFailed);
368             return false;
369           } else
370             frame_idx = num_frames - 1;
371         }
372       }
373     } else {
374       if (command.GetArgumentCount() > 1) {
375         result.AppendErrorWithFormat(
376             "too many arguments; expected frame-index, saw '%s'.\n",
377             command[0].c_str());
378         m_options.GenerateOptionUsage(
379             result.GetErrorStream(), this,
380             GetCommandInterpreter().GetDebugger().GetTerminalWidth());
381         return false;
382       }
383 
384       if (command.GetArgumentCount() == 1) {
385         if (command[0].ref.getAsInteger(0, frame_idx)) {
386           result.AppendErrorWithFormat("invalid frame index argument '%s'.",
387                                        command[0].c_str());
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       }
397     }
398 
399     bool success = thread->SetSelectedFrameByIndexNoisily(
400         frame_idx, result.GetOutputStream());
401     if (success) {
402       m_exe_ctx.SetFrameSP(thread->GetSelectedFrame());
403       result.SetStatus(eReturnStatusSuccessFinishResult);
404     } else {
405       result.AppendErrorWithFormat("Frame index (%u) out of range.\n",
406                                    frame_idx);
407       result.SetStatus(eReturnStatusFailed);
408     }
409 
410     return result.Succeeded();
411   }
412 
413 protected:
414   CommandOptions m_options;
415 };
416 
417 #pragma mark CommandObjectFrameVariable
418 //----------------------------------------------------------------------
419 // List images with associated information
420 //----------------------------------------------------------------------
421 class CommandObjectFrameVariable : public CommandObjectParsed {
422 public:
423   CommandObjectFrameVariable(CommandInterpreter &interpreter)
424       : CommandObjectParsed(
425             interpreter, "frame variable",
426             "Show variables for the current stack frame. Defaults to all "
427             "arguments and local variables in scope. Names of argument, "
428             "local, file static and file global variables can be specified. "
429             "Children of aggregate variables can be specified such as "
430             "'var->child.x'.  The -> and [] operators in 'frame variable' do "
431             "not invoke operator overloads if they exist, but directly access "
432             "the specified element.  If you want to trigger operator overloads "
433             "use the expression command to print the variable instead."
434             "\nIt is worth noting that except for overloaded "
435             "operators, when printing local variables 'expr local_var' and "
436             "'frame var local_var' produce the same "
437             "results.  However, 'frame variable' is more efficient, since it "
438             "uses debug information and memory reads directly, rather than "
439             "parsing and evaluating an expression, which may even involve "
440             "JITing and running code in the target program.",
441             nullptr, eCommandRequiresFrame | eCommandTryTargetAPILock |
442                          eCommandProcessMustBeLaunched |
443                          eCommandProcessMustBePaused | eCommandRequiresProcess),
444         m_option_group(),
445         m_option_variable(
446             true), // Include the frame specific options by passing "true"
447         m_option_format(eFormatDefault),
448         m_varobj_options() {
449     CommandArgumentEntry arg;
450     CommandArgumentData var_name_arg;
451 
452     // Define the first (and only) variant of this arg.
453     var_name_arg.arg_type = eArgTypeVarName;
454     var_name_arg.arg_repetition = eArgRepeatStar;
455 
456     // There is only one variant this argument could be; put it into the
457     // argument entry.
458     arg.push_back(var_name_arg);
459 
460     // Push the data for the first argument into the m_arguments vector.
461     m_arguments.push_back(arg);
462 
463     m_option_group.Append(&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
464     m_option_group.Append(&m_option_format,
465                           OptionGroupFormat::OPTION_GROUP_FORMAT |
466                               OptionGroupFormat::OPTION_GROUP_GDB_FMT,
467                           LLDB_OPT_SET_1);
468     m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
469     m_option_group.Finalize();
470   }
471 
472   ~CommandObjectFrameVariable() override = default;
473 
474   Options *GetOptions() override { return &m_option_group; }
475 
476   int HandleArgumentCompletion(
477       CompletionRequest &request,
478       OptionElementVector &opt_element_vector) override {
479     // Arguments are the standard source file completer.
480     CommandCompletions::InvokeCommonCompletionCallbacks(
481         GetCommandInterpreter(), CommandCompletions::eVariablePathCompletion,
482         request, nullptr);
483     return request.GetNumberOfMatches();
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
511     // it 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 for the thread.  So hold onto a shared
518     // pointer to the frame so it stays alive.
519 
520     VariableList *variable_list =
521         frame->GetVariableList(m_option_variable.show_globals);
522 
523     VariableSP var_sp;
524     ValueObjectSP valobj_sp;
525 
526     TypeSummaryImplSP summary_format_sp;
527     if (!m_option_variable.summary.IsCurrentValueEmpty())
528       DataVisualization::NamedSummaryFormats::GetSummaryFormat(
529           ConstString(m_option_variable.summary.GetCurrentValue()),
530           summary_format_sp);
531     else if (!m_option_variable.summary_string.IsCurrentValueEmpty())
532       summary_format_sp.reset(new StringSummaryFormat(
533           TypeSummaryImpl::Flags(),
534           m_option_variable.summary_string.GetCurrentValue()));
535 
536     DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(
537         eLanguageRuntimeDescriptionDisplayVerbosityFull, eFormatDefault,
538         summary_format_sp));
539 
540     const SymbolContext &sym_ctx =
541         frame->GetSymbolContext(eSymbolContextFunction);
542     if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction())
543       m_option_variable.show_globals = true;
544 
545     if (variable_list) {
546       const Format format = m_option_format.GetFormat();
547       options.SetFormat(format);
548 
549       if (!command.empty()) {
550         VariableList regex_var_list;
551 
552         // If we have any args to the variable command, we will make variable
553         // objects from them...
554         for (auto &entry : command) {
555           if (m_option_variable.use_regex) {
556             const size_t regex_start_index = regex_var_list.GetSize();
557             llvm::StringRef name_str = entry.ref;
558             RegularExpression regex(name_str);
559             if (regex.Compile(name_str)) {
560               size_t num_matches = 0;
561               const size_t num_new_regex_vars =
562                   variable_list->AppendVariablesIfUnique(regex, regex_var_list,
563                                                          num_matches);
564               if (num_new_regex_vars > 0) {
565                 for (size_t regex_idx = regex_start_index,
566                             end_index = regex_var_list.GetSize();
567                      regex_idx < end_index; ++regex_idx) {
568                   var_sp = regex_var_list.GetVariableAtIndex(regex_idx);
569                   if (var_sp) {
570                     valobj_sp = frame->GetValueObjectForFrameVariable(
571                         var_sp, m_varobj_options.use_dynamic);
572                     if (valobj_sp) {
573                       std::string scope_string;
574                       if (m_option_variable.show_scope)
575                         scope_string = GetScopeString(var_sp).str();
576 
577                       if (!scope_string.empty())
578                         s.PutCString(scope_string);
579 
580                       if (m_option_variable.show_decl &&
581                           var_sp->GetDeclaration().GetFile()) {
582                         bool show_fullpaths = false;
583                         bool show_module = true;
584                         if (var_sp->DumpDeclaration(&s, show_fullpaths,
585                                                     show_module))
586                           s.PutCString(": ");
587                       }
588                       valobj_sp->Dump(result.GetOutputStream(), options);
589                     }
590                   }
591                 }
592               } else if (num_matches == 0) {
593                 result.GetErrorStream().Printf("error: no variables matched "
594                                                "the regular expression '%s'.\n",
595                                                entry.c_str());
596               }
597             } else {
598               char regex_error[1024];
599               if (regex.GetErrorAsCString(regex_error, sizeof(regex_error)))
600                 result.GetErrorStream().Printf("error: %s\n", regex_error);
601               else
602                 result.GetErrorStream().Printf(
603                     "error: unknown regex error when compiling '%s'\n",
604                     entry.c_str());
605             }
606           } else // No regex, either exact variable names or variable
607                  // expressions.
608           {
609             Status error;
610             uint32_t expr_path_options =
611                 StackFrame::eExpressionPathOptionCheckPtrVsMember |
612                 StackFrame::eExpressionPathOptionsAllowDirectIVarAccess |
613                 StackFrame::eExpressionPathOptionsInspectAnonymousUnions;
614             lldb::VariableSP var_sp;
615             valobj_sp = frame->GetValueForVariableExpressionPath(
616                 entry.ref, m_varobj_options.use_dynamic, expr_path_options,
617                 var_sp, error);
618             if (valobj_sp) {
619               std::string scope_string;
620               if (m_option_variable.show_scope)
621                 scope_string = GetScopeString(var_sp).str();
622 
623               if (!scope_string.empty())
624                 s.PutCString(scope_string);
625               if (m_option_variable.show_decl && var_sp &&
626                   var_sp->GetDeclaration().GetFile()) {
627                 var_sp->GetDeclaration().DumpStopContext(&s, false);
628                 s.PutCString(": ");
629               }
630 
631               options.SetFormat(format);
632               options.SetVariableFormatDisplayLanguage(
633                   valobj_sp->GetPreferredDisplayLanguage());
634 
635               Stream &output_stream = result.GetOutputStream();
636               options.SetRootValueObjectName(
637                   valobj_sp->GetParent() ? entry.c_str() : nullptr);
638               valobj_sp->Dump(output_stream, options);
639             } else {
640               const char *error_cstr = error.AsCString(nullptr);
641               if (error_cstr)
642                 result.GetErrorStream().Printf("error: %s\n", error_cstr);
643               else
644                 result.GetErrorStream().Printf("error: unable to find any "
645                                                "variable expression path that "
646                                                "matches '%s'.\n",
647                                                entry.c_str());
648             }
649           }
650         }
651       } else // No command arg specified.  Use variable_list, instead.
652       {
653         const size_t num_variables = variable_list->GetSize();
654         if (num_variables > 0) {
655           for (size_t i = 0; i < num_variables; i++) {
656             var_sp = variable_list->GetVariableAtIndex(i);
657             switch (var_sp->GetScope()) {
658             case eValueTypeVariableGlobal:
659               if (!m_option_variable.show_globals)
660                 continue;
661               break;
662             case eValueTypeVariableStatic:
663               if (!m_option_variable.show_globals)
664                 continue;
665               break;
666             case eValueTypeVariableArgument:
667               if (!m_option_variable.show_args)
668                 continue;
669               break;
670             case eValueTypeVariableLocal:
671               if (!m_option_variable.show_locals)
672                 continue;
673               break;
674             default:
675               continue;
676               break;
677             }
678             std::string scope_string;
679             if (m_option_variable.show_scope)
680               scope_string = GetScopeString(var_sp).str();
681 
682             // Use the variable object code to make sure we are using the same
683             // APIs as the public API will be using...
684             valobj_sp = frame->GetValueObjectForFrameVariable(
685                 var_sp, m_varobj_options.use_dynamic);
686             if (valobj_sp) {
687               // When dumping all variables, don't print any variables that are
688               // 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(
708                     var_sp ? var_sp->GetName().AsCString() : nullptr);
709                 valobj_sp->Dump(result.GetOutputStream(), options);
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     // Increment statistics.
725     bool res = result.Succeeded();
726     Target *target = GetSelectedOrDummyTarget();
727     if (res)
728       target->IncrementStats(StatisticKind::FrameVarSuccess);
729     else
730       target->IncrementStats(StatisticKind::FrameVarFailure);
731     return res;
732   }
733 
734 protected:
735   OptionGroupOptions m_option_group;
736   OptionGroupVariable m_option_variable;
737   OptionGroupFormat m_option_format;
738   OptionGroupValueObjectDisplay m_varobj_options;
739 };
740 
741 #pragma mark CommandObjectMultiwordFrame
742 
743 //-------------------------------------------------------------------------
744 // CommandObjectMultiwordFrame
745 //-------------------------------------------------------------------------
746 
747 CommandObjectMultiwordFrame::CommandObjectMultiwordFrame(
748     CommandInterpreter &interpreter)
749     : CommandObjectMultiword(interpreter, "frame", "Commands for selecting and "
750                                                    "examing the current "
751                                                    "thread's stack frames.",
752                              "frame <subcommand> [<subcommand-options>]") {
753   LoadSubCommand("diagnose",
754                  CommandObjectSP(new CommandObjectFrameDiagnose(interpreter)));
755   LoadSubCommand("info",
756                  CommandObjectSP(new CommandObjectFrameInfo(interpreter)));
757   LoadSubCommand("select",
758                  CommandObjectSP(new CommandObjectFrameSelect(interpreter)));
759   LoadSubCommand("variable",
760                  CommandObjectSP(new CommandObjectFrameVariable(interpreter)));
761 }
762 
763 CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default;
764