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