CommandObjectFrame.cpp revision 360784
1//===-- CommandObjectFrame.cpp ----------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8#include "CommandObjectFrame.h"
9#include "lldb/Core/Debugger.h"
10#include "lldb/Core/ValueObject.h"
11#include "lldb/DataFormatters/DataVisualization.h"
12#include "lldb/DataFormatters/ValueObjectPrinter.h"
13#include "lldb/Host/Config.h"
14#include "lldb/Host/OptionParser.h"
15#include "lldb/Host/StringConvert.h"
16#include "lldb/Interpreter/CommandInterpreter.h"
17#include "lldb/Interpreter/CommandReturnObject.h"
18#include "lldb/Interpreter/OptionGroupFormat.h"
19#include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
20#include "lldb/Interpreter/OptionGroupVariable.h"
21#include "lldb/Interpreter/Options.h"
22#include "lldb/Symbol/Function.h"
23#include "lldb/Symbol/SymbolContext.h"
24#include "lldb/Symbol/Variable.h"
25#include "lldb/Symbol/VariableList.h"
26#include "lldb/Target/StackFrame.h"
27#include "lldb/Target/StackFrameRecognizer.h"
28#include "lldb/Target/StopInfo.h"
29#include "lldb/Target/Target.h"
30#include "lldb/Target/Thread.h"
31#include "lldb/Utility/Args.h"
32
33#include <memory>
34#include <string>
35
36using namespace lldb;
37using namespace lldb_private;
38
39#pragma mark CommandObjectFrameDiagnose
40
41// CommandObjectFrameInfo
42
43// CommandObjectFrameDiagnose
44
45#define LLDB_OPTIONS_frame_diag
46#include "CommandOptions.inc"
47
48class CommandObjectFrameDiagnose : public CommandObjectParsed {
49public:
50  class CommandOptions : public Options {
51  public:
52    CommandOptions() : Options() { OptionParsingStarting(nullptr); }
53
54    ~CommandOptions() override = default;
55
56    Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
57                          ExecutionContext *execution_context) override {
58      Status error;
59      const int short_option = m_getopt_table[option_idx].val;
60      switch (short_option) {
61      case 'r':
62        reg = ConstString(option_arg);
63        break;
64
65      case 'a': {
66        address.emplace();
67        if (option_arg.getAsInteger(0, *address)) {
68          address.reset();
69          error.SetErrorStringWithFormat("invalid address argument '%s'",
70                                         option_arg.str().c_str());
71        }
72      } break;
73
74      case 'o': {
75        offset.emplace();
76        if (option_arg.getAsInteger(0, *offset)) {
77          offset.reset();
78          error.SetErrorStringWithFormat("invalid offset argument '%s'",
79                                         option_arg.str().c_str());
80        }
81      } break;
82
83      default:
84        llvm_unreachable("Unimplemented option");
85      }
86
87      return error;
88    }
89
90    void OptionParsingStarting(ExecutionContext *execution_context) override {
91      address.reset();
92      reg.reset();
93      offset.reset();
94    }
95
96    llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
97      return llvm::makeArrayRef(g_frame_diag_options);
98    }
99
100    // Options.
101    llvm::Optional<lldb::addr_t> address;
102    llvm::Optional<ConstString> reg;
103    llvm::Optional<int64_t> offset;
104  };
105
106  CommandObjectFrameDiagnose(CommandInterpreter &interpreter)
107      : CommandObjectParsed(interpreter, "frame diagnose",
108                            "Try to determine what path path the current stop "
109                            "location used to get to a register or address",
110                            nullptr,
111                            eCommandRequiresThread | eCommandTryTargetAPILock |
112                                eCommandProcessMustBeLaunched |
113                                eCommandProcessMustBePaused),
114        m_options() {
115    CommandArgumentEntry arg;
116    CommandArgumentData index_arg;
117
118    // Define the first (and only) variant of this arg.
119    index_arg.arg_type = eArgTypeFrameIndex;
120    index_arg.arg_repetition = eArgRepeatOptional;
121
122    // There is only one variant this argument could be; put it into the
123    // argument entry.
124    arg.push_back(index_arg);
125
126    // Push the data for the first argument into the m_arguments vector.
127    m_arguments.push_back(arg);
128  }
129
130  ~CommandObjectFrameDiagnose() override = default;
131
132  Options *GetOptions() override { return &m_options; }
133
134protected:
135  bool DoExecute(Args &command, CommandReturnObject &result) override {
136    Thread *thread = m_exe_ctx.GetThreadPtr();
137    StackFrameSP frame_sp = thread->GetSelectedFrame();
138
139    ValueObjectSP valobj_sp;
140
141    if (m_options.address.hasValue()) {
142      if (m_options.reg.hasValue() || m_options.offset.hasValue()) {
143        result.AppendError(
144            "`frame diagnose --address` is incompatible with other arguments.");
145        result.SetStatus(eReturnStatusFailed);
146        return false;
147      }
148      valobj_sp = frame_sp->GuessValueForAddress(m_options.address.getValue());
149    } else if (m_options.reg.hasValue()) {
150      valobj_sp = frame_sp->GuessValueForRegisterAndOffset(
151          m_options.reg.getValue(), m_options.offset.getValueOr(0));
152    } else {
153      StopInfoSP stop_info_sp = thread->GetStopInfo();
154      if (!stop_info_sp) {
155        result.AppendError("No arguments provided, and no stop info.");
156        result.SetStatus(eReturnStatusFailed);
157        return false;
158      }
159
160      valobj_sp = StopInfo::GetCrashingDereference(stop_info_sp);
161    }
162
163    if (!valobj_sp) {
164      result.AppendError("No diagnosis available.");
165      result.SetStatus(eReturnStatusFailed);
166      return false;
167    }
168
169    DumpValueObjectOptions::DeclPrintingHelper helper =
170        [&valobj_sp](ConstString type, ConstString var,
171                     const DumpValueObjectOptions &opts,
172                     Stream &stream) -> bool {
173      const ValueObject::GetExpressionPathFormat format = ValueObject::
174          GetExpressionPathFormat::eGetExpressionPathFormatHonorPointers;
175      const bool qualify_cxx_base_classes = false;
176      valobj_sp->GetExpressionPath(stream, qualify_cxx_base_classes, format);
177      stream.PutCString(" =");
178      return true;
179    };
180
181    DumpValueObjectOptions options;
182    options.SetDeclPrintingHelper(helper);
183    ValueObjectPrinter printer(valobj_sp.get(), &result.GetOutputStream(),
184                               options);
185    printer.PrintValueObject();
186
187    return true;
188  }
189
190protected:
191  CommandOptions m_options;
192};
193
194#pragma mark CommandObjectFrameInfo
195
196// CommandObjectFrameInfo
197
198class CommandObjectFrameInfo : public CommandObjectParsed {
199public:
200  CommandObjectFrameInfo(CommandInterpreter &interpreter)
201      : CommandObjectParsed(interpreter, "frame info",
202                            "List information about the current "
203                            "stack frame in the current thread.",
204                            "frame info",
205                            eCommandRequiresFrame | eCommandTryTargetAPILock |
206                                eCommandProcessMustBeLaunched |
207                                eCommandProcessMustBePaused) {}
208
209  ~CommandObjectFrameInfo() override = default;
210
211protected:
212  bool DoExecute(Args &command, CommandReturnObject &result) override {
213    m_exe_ctx.GetFrameRef().DumpUsingSettingsFormat(&result.GetOutputStream());
214    result.SetStatus(eReturnStatusSuccessFinishResult);
215    return result.Succeeded();
216  }
217};
218
219#pragma mark CommandObjectFrameSelect
220
221// CommandObjectFrameSelect
222
223#define LLDB_OPTIONS_frame_select
224#include "CommandOptions.inc"
225
226class CommandObjectFrameSelect : public CommandObjectParsed {
227public:
228  class CommandOptions : public Options {
229  public:
230    CommandOptions() : Options() { OptionParsingStarting(nullptr); }
231
232    ~CommandOptions() override = default;
233
234    Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
235                          ExecutionContext *execution_context) override {
236      Status error;
237      const int short_option = m_getopt_table[option_idx].val;
238      switch (short_option) {
239      case 'r': {
240        int32_t offset = 0;
241        if (option_arg.getAsInteger(0, offset) || offset == INT32_MIN) {
242          error.SetErrorStringWithFormat("invalid frame offset argument '%s'",
243                                         option_arg.str().c_str());
244        } else
245          relative_frame_offset = offset;
246        break;
247      }
248
249      default:
250        llvm_unreachable("Unimplemented option");
251      }
252
253      return error;
254    }
255
256    void OptionParsingStarting(ExecutionContext *execution_context) override {
257      relative_frame_offset.reset();
258    }
259
260    llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
261      return llvm::makeArrayRef(g_frame_select_options);
262    }
263
264    llvm::Optional<int32_t> relative_frame_offset;
265  };
266
267  CommandObjectFrameSelect(CommandInterpreter &interpreter)
268      : CommandObjectParsed(interpreter, "frame select",
269                            "Select the current stack frame by "
270                            "index from within the current thread "
271                            "(see 'thread backtrace'.)",
272                            nullptr,
273                            eCommandRequiresThread | eCommandTryTargetAPILock |
274                                eCommandProcessMustBeLaunched |
275                                eCommandProcessMustBePaused),
276        m_options() {
277    CommandArgumentEntry arg;
278    CommandArgumentData index_arg;
279
280    // Define the first (and only) variant of this arg.
281    index_arg.arg_type = eArgTypeFrameIndex;
282    index_arg.arg_repetition = eArgRepeatOptional;
283
284    // There is only one variant this argument could be; put it into the
285    // argument entry.
286    arg.push_back(index_arg);
287
288    // Push the data for the first argument into the m_arguments vector.
289    m_arguments.push_back(arg);
290  }
291
292  ~CommandObjectFrameSelect() override = default;
293
294  Options *GetOptions() override { return &m_options; }
295
296protected:
297  bool DoExecute(Args &command, CommandReturnObject &result) override {
298    // No need to check "thread" for validity as eCommandRequiresThread ensures
299    // it is valid
300    Thread *thread = m_exe_ctx.GetThreadPtr();
301
302    uint32_t frame_idx = UINT32_MAX;
303    if (m_options.relative_frame_offset.hasValue()) {
304      // The one and only argument is a signed relative frame index
305      frame_idx = thread->GetSelectedFrameIndex();
306      if (frame_idx == UINT32_MAX)
307        frame_idx = 0;
308
309      if (*m_options.relative_frame_offset < 0) {
310        if (static_cast<int32_t>(frame_idx) >=
311            -*m_options.relative_frame_offset)
312          frame_idx += *m_options.relative_frame_offset;
313        else {
314          if (frame_idx == 0) {
315            // If you are already at the bottom of the stack, then just warn
316            // and don't reset the frame.
317            result.AppendError("Already at the bottom of the stack.");
318            result.SetStatus(eReturnStatusFailed);
319            return false;
320          } else
321            frame_idx = 0;
322        }
323      } else if (*m_options.relative_frame_offset > 0) {
324        // I don't want "up 20" where "20" takes you past the top of the stack
325        // to produce
326        // an error, but rather to just go to the top.  So I have to count the
327        // stack here...
328        const uint32_t num_frames = thread->GetStackFrameCount();
329        if (static_cast<int32_t>(num_frames - frame_idx) >
330            *m_options.relative_frame_offset)
331          frame_idx += *m_options.relative_frame_offset;
332        else {
333          if (frame_idx == num_frames - 1) {
334            // If we are already at the top of the stack, just warn and don't
335            // reset the frame.
336            result.AppendError("Already at the top of the stack.");
337            result.SetStatus(eReturnStatusFailed);
338            return false;
339          } else
340            frame_idx = num_frames - 1;
341        }
342      }
343    } else {
344      if (command.GetArgumentCount() > 1) {
345        result.AppendErrorWithFormat(
346            "too many arguments; expected frame-index, saw '%s'.\n",
347            command[0].c_str());
348        m_options.GenerateOptionUsage(
349            result.GetErrorStream(), this,
350            GetCommandInterpreter().GetDebugger().GetTerminalWidth());
351        return false;
352      }
353
354      if (command.GetArgumentCount() == 1) {
355        if (command[0].ref().getAsInteger(0, frame_idx)) {
356          result.AppendErrorWithFormat("invalid frame index argument '%s'.",
357                                       command[0].c_str());
358          result.SetStatus(eReturnStatusFailed);
359          return false;
360        }
361      } else if (command.GetArgumentCount() == 0) {
362        frame_idx = thread->GetSelectedFrameIndex();
363        if (frame_idx == UINT32_MAX) {
364          frame_idx = 0;
365        }
366      }
367    }
368
369    bool success = thread->SetSelectedFrameByIndexNoisily(
370        frame_idx, result.GetOutputStream());
371    if (success) {
372      m_exe_ctx.SetFrameSP(thread->GetSelectedFrame());
373      result.SetStatus(eReturnStatusSuccessFinishResult);
374    } else {
375      result.AppendErrorWithFormat("Frame index (%u) out of range.\n",
376                                   frame_idx);
377      result.SetStatus(eReturnStatusFailed);
378    }
379
380    return result.Succeeded();
381  }
382
383protected:
384  CommandOptions m_options;
385};
386
387#pragma mark CommandObjectFrameVariable
388// List images with associated information
389class CommandObjectFrameVariable : public CommandObjectParsed {
390public:
391  CommandObjectFrameVariable(CommandInterpreter &interpreter)
392      : CommandObjectParsed(
393            interpreter, "frame variable",
394            "Show variables for the current stack frame. Defaults to all "
395            "arguments and local variables in scope. Names of argument, "
396            "local, file static and file global variables can be specified. "
397            "Children of aggregate variables can be specified such as "
398            "'var->child.x'.  The -> and [] operators in 'frame variable' do "
399            "not invoke operator overloads if they exist, but directly access "
400            "the specified element.  If you want to trigger operator overloads "
401            "use the expression command to print the variable instead."
402            "\nIt is worth noting that except for overloaded "
403            "operators, when printing local variables 'expr local_var' and "
404            "'frame var local_var' produce the same "
405            "results.  However, 'frame variable' is more efficient, since it "
406            "uses debug information and memory reads directly, rather than "
407            "parsing and evaluating an expression, which may even involve "
408            "JITing and running code in the target program.",
409            nullptr,
410            eCommandRequiresFrame | eCommandTryTargetAPILock |
411                eCommandProcessMustBeLaunched | eCommandProcessMustBePaused |
412                eCommandRequiresProcess),
413        m_option_group(),
414        m_option_variable(
415            true), // Include the frame specific options by passing "true"
416        m_option_format(eFormatDefault), m_varobj_options() {
417    CommandArgumentEntry arg;
418    CommandArgumentData var_name_arg;
419
420    // Define the first (and only) variant of this arg.
421    var_name_arg.arg_type = eArgTypeVarName;
422    var_name_arg.arg_repetition = eArgRepeatStar;
423
424    // There is only one variant this argument could be; put it into the
425    // argument entry.
426    arg.push_back(var_name_arg);
427
428    // Push the data for the first argument into the m_arguments vector.
429    m_arguments.push_back(arg);
430
431    m_option_group.Append(&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
432    m_option_group.Append(&m_option_format,
433                          OptionGroupFormat::OPTION_GROUP_FORMAT |
434                              OptionGroupFormat::OPTION_GROUP_GDB_FMT,
435                          LLDB_OPT_SET_1);
436    m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
437    m_option_group.Finalize();
438  }
439
440  ~CommandObjectFrameVariable() override = default;
441
442  Options *GetOptions() override { return &m_option_group; }
443
444  void
445  HandleArgumentCompletion(CompletionRequest &request,
446                           OptionElementVector &opt_element_vector) override {
447    // Arguments are the standard source file completer.
448    CommandCompletions::InvokeCommonCompletionCallbacks(
449        GetCommandInterpreter(), CommandCompletions::eVariablePathCompletion,
450        request, nullptr);
451  }
452
453protected:
454  llvm::StringRef GetScopeString(VariableSP var_sp) {
455    if (!var_sp)
456      return llvm::StringRef::withNullAsEmpty(nullptr);
457
458    switch (var_sp->GetScope()) {
459    case eValueTypeVariableGlobal:
460      return "GLOBAL: ";
461    case eValueTypeVariableStatic:
462      return "STATIC: ";
463    case eValueTypeVariableArgument:
464      return "ARG: ";
465    case eValueTypeVariableLocal:
466      return "LOCAL: ";
467    case eValueTypeVariableThreadLocal:
468      return "THREAD: ";
469    default:
470      break;
471    }
472
473    return llvm::StringRef::withNullAsEmpty(nullptr);
474  }
475
476  bool DoExecute(Args &command, CommandReturnObject &result) override {
477    // No need to check "frame" for validity as eCommandRequiresFrame ensures
478    // it is valid
479    StackFrame *frame = m_exe_ctx.GetFramePtr();
480
481    Stream &s = result.GetOutputStream();
482
483    // Be careful about the stack frame, if any summary formatter runs code, it
484    // might clear the StackFrameList for the thread.  So hold onto a shared
485    // pointer to the frame so it stays alive.
486
487    VariableList *variable_list =
488        frame->GetVariableList(m_option_variable.show_globals);
489
490    VariableSP var_sp;
491    ValueObjectSP valobj_sp;
492
493    TypeSummaryImplSP summary_format_sp;
494    if (!m_option_variable.summary.IsCurrentValueEmpty())
495      DataVisualization::NamedSummaryFormats::GetSummaryFormat(
496          ConstString(m_option_variable.summary.GetCurrentValue()),
497          summary_format_sp);
498    else if (!m_option_variable.summary_string.IsCurrentValueEmpty())
499      summary_format_sp = std::make_shared<StringSummaryFormat>(
500          TypeSummaryImpl::Flags(),
501          m_option_variable.summary_string.GetCurrentValue());
502
503    DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(
504        eLanguageRuntimeDescriptionDisplayVerbosityFull, eFormatDefault,
505        summary_format_sp));
506
507    const SymbolContext &sym_ctx =
508        frame->GetSymbolContext(eSymbolContextFunction);
509    if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction())
510      m_option_variable.show_globals = true;
511
512    if (variable_list) {
513      const Format format = m_option_format.GetFormat();
514      options.SetFormat(format);
515
516      if (!command.empty()) {
517        VariableList regex_var_list;
518
519        // If we have any args to the variable command, we will make variable
520        // objects from them...
521        for (auto &entry : command) {
522          if (m_option_variable.use_regex) {
523            const size_t regex_start_index = regex_var_list.GetSize();
524            llvm::StringRef name_str = entry.ref();
525            RegularExpression regex(name_str);
526            if (regex.IsValid()) {
527              size_t num_matches = 0;
528              const size_t num_new_regex_vars =
529                  variable_list->AppendVariablesIfUnique(regex, regex_var_list,
530                                                         num_matches);
531              if (num_new_regex_vars > 0) {
532                for (size_t regex_idx = regex_start_index,
533                            end_index = regex_var_list.GetSize();
534                     regex_idx < end_index; ++regex_idx) {
535                  var_sp = regex_var_list.GetVariableAtIndex(regex_idx);
536                  if (var_sp) {
537                    valobj_sp = frame->GetValueObjectForFrameVariable(
538                        var_sp, m_varobj_options.use_dynamic);
539                    if (valobj_sp) {
540                      std::string scope_string;
541                      if (m_option_variable.show_scope)
542                        scope_string = GetScopeString(var_sp).str();
543
544                      if (!scope_string.empty())
545                        s.PutCString(scope_string);
546
547                      if (m_option_variable.show_decl &&
548                          var_sp->GetDeclaration().GetFile()) {
549                        bool show_fullpaths = false;
550                        bool show_module = true;
551                        if (var_sp->DumpDeclaration(&s, show_fullpaths,
552                                                    show_module))
553                          s.PutCString(": ");
554                      }
555                      valobj_sp->Dump(result.GetOutputStream(), options);
556                    }
557                  }
558                }
559              } else if (num_matches == 0) {
560                result.GetErrorStream().Printf("error: no variables matched "
561                                               "the regular expression '%s'.\n",
562                                               entry.c_str());
563              }
564            } else {
565              if (llvm::Error err = regex.GetError())
566                result.GetErrorStream().Printf(
567                    "error: %s\n", llvm::toString(std::move(err)).c_str());
568              else
569                result.GetErrorStream().Printf(
570                    "error: unknown regex error when compiling '%s'\n",
571                    entry.c_str());
572            }
573          } else // No regex, either exact variable names or variable
574                 // expressions.
575          {
576            Status error;
577            uint32_t expr_path_options =
578                StackFrame::eExpressionPathOptionCheckPtrVsMember |
579                StackFrame::eExpressionPathOptionsAllowDirectIVarAccess |
580                StackFrame::eExpressionPathOptionsInspectAnonymousUnions;
581            lldb::VariableSP var_sp;
582            valobj_sp = frame->GetValueForVariableExpressionPath(
583                entry.ref(), m_varobj_options.use_dynamic, expr_path_options,
584                var_sp, error);
585            if (valobj_sp) {
586              std::string scope_string;
587              if (m_option_variable.show_scope)
588                scope_string = GetScopeString(var_sp).str();
589
590              if (!scope_string.empty())
591                s.PutCString(scope_string);
592              if (m_option_variable.show_decl && var_sp &&
593                  var_sp->GetDeclaration().GetFile()) {
594                var_sp->GetDeclaration().DumpStopContext(&s, false);
595                s.PutCString(": ");
596              }
597
598              options.SetFormat(format);
599              options.SetVariableFormatDisplayLanguage(
600                  valobj_sp->GetPreferredDisplayLanguage());
601
602              Stream &output_stream = result.GetOutputStream();
603              options.SetRootValueObjectName(
604                  valobj_sp->GetParent() ? entry.c_str() : nullptr);
605              valobj_sp->Dump(output_stream, options);
606            } else {
607              const char *error_cstr = error.AsCString(nullptr);
608              if (error_cstr)
609                result.GetErrorStream().Printf("error: %s\n", error_cstr);
610              else
611                result.GetErrorStream().Printf("error: unable to find any "
612                                               "variable expression path that "
613                                               "matches '%s'.\n",
614                                               entry.c_str());
615            }
616          }
617        }
618      } else // No command arg specified.  Use variable_list, instead.
619      {
620        const size_t num_variables = variable_list->GetSize();
621        if (num_variables > 0) {
622          for (size_t i = 0; i < num_variables; i++) {
623            var_sp = variable_list->GetVariableAtIndex(i);
624            switch (var_sp->GetScope()) {
625            case eValueTypeVariableGlobal:
626              if (!m_option_variable.show_globals)
627                continue;
628              break;
629            case eValueTypeVariableStatic:
630              if (!m_option_variable.show_globals)
631                continue;
632              break;
633            case eValueTypeVariableArgument:
634              if (!m_option_variable.show_args)
635                continue;
636              break;
637            case eValueTypeVariableLocal:
638              if (!m_option_variable.show_locals)
639                continue;
640              break;
641            default:
642              continue;
643              break;
644            }
645            std::string scope_string;
646            if (m_option_variable.show_scope)
647              scope_string = GetScopeString(var_sp).str();
648
649            // Use the variable object code to make sure we are using the same
650            // APIs as the public API will be using...
651            valobj_sp = frame->GetValueObjectForFrameVariable(
652                var_sp, m_varobj_options.use_dynamic);
653            if (valobj_sp) {
654              // When dumping all variables, don't print any variables that are
655              // not in scope to avoid extra unneeded output
656              if (valobj_sp->IsInScope()) {
657                if (!valobj_sp->GetTargetSP()
658                         ->GetDisplayRuntimeSupportValues() &&
659                    valobj_sp->IsRuntimeSupportValue())
660                  continue;
661
662                if (!scope_string.empty())
663                  s.PutCString(scope_string);
664
665                if (m_option_variable.show_decl &&
666                    var_sp->GetDeclaration().GetFile()) {
667                  var_sp->GetDeclaration().DumpStopContext(&s, false);
668                  s.PutCString(": ");
669                }
670
671                options.SetFormat(format);
672                options.SetVariableFormatDisplayLanguage(
673                    valobj_sp->GetPreferredDisplayLanguage());
674                options.SetRootValueObjectName(
675                    var_sp ? var_sp->GetName().AsCString() : nullptr);
676                valobj_sp->Dump(result.GetOutputStream(), options);
677              }
678            }
679          }
680        }
681      }
682      result.SetStatus(eReturnStatusSuccessFinishResult);
683    }
684
685    if (m_option_variable.show_recognized_args) {
686      auto recognized_frame = frame->GetRecognizedFrame();
687      if (recognized_frame) {
688        ValueObjectListSP recognized_arg_list =
689            recognized_frame->GetRecognizedArguments();
690        if (recognized_arg_list) {
691          for (auto &rec_value_sp : recognized_arg_list->GetObjects()) {
692            options.SetFormat(m_option_format.GetFormat());
693            options.SetVariableFormatDisplayLanguage(
694                rec_value_sp->GetPreferredDisplayLanguage());
695            options.SetRootValueObjectName(rec_value_sp->GetName().AsCString());
696            rec_value_sp->Dump(result.GetOutputStream(), options);
697          }
698        }
699      }
700    }
701
702    if (m_interpreter.TruncationWarningNecessary()) {
703      result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(),
704                                      m_cmd_name.c_str());
705      m_interpreter.TruncationWarningGiven();
706    }
707
708    // Increment statistics.
709    bool res = result.Succeeded();
710    Target &target = GetSelectedOrDummyTarget();
711    if (res)
712      target.IncrementStats(StatisticKind::FrameVarSuccess);
713    else
714      target.IncrementStats(StatisticKind::FrameVarFailure);
715    return res;
716  }
717
718protected:
719  OptionGroupOptions m_option_group;
720  OptionGroupVariable m_option_variable;
721  OptionGroupFormat m_option_format;
722  OptionGroupValueObjectDisplay m_varobj_options;
723};
724
725#pragma mark CommandObjectFrameRecognizer
726
727#define LLDB_OPTIONS_frame_recognizer_add
728#include "CommandOptions.inc"
729
730class CommandObjectFrameRecognizerAdd : public CommandObjectParsed {
731private:
732  class CommandOptions : public Options {
733  public:
734    CommandOptions() : Options() {}
735    ~CommandOptions() override = default;
736
737    Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
738                          ExecutionContext *execution_context) override {
739      Status error;
740      const int short_option = m_getopt_table[option_idx].val;
741
742      switch (short_option) {
743      case 'l':
744        m_class_name = std::string(option_arg);
745        break;
746      case 's':
747        m_module = std::string(option_arg);
748        break;
749      case 'n':
750        m_function = std::string(option_arg);
751        break;
752      case 'x':
753        m_regex = true;
754        break;
755      default:
756        llvm_unreachable("Unimplemented option");
757      }
758
759      return error;
760    }
761
762    void OptionParsingStarting(ExecutionContext *execution_context) override {
763      m_module = "";
764      m_function = "";
765      m_class_name = "";
766      m_regex = false;
767    }
768
769    llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
770      return llvm::makeArrayRef(g_frame_recognizer_add_options);
771    }
772
773    // Instance variables to hold the values for command options.
774    std::string m_class_name;
775    std::string m_module;
776    std::string m_function;
777    bool m_regex;
778  };
779
780  CommandOptions m_options;
781
782  Options *GetOptions() override { return &m_options; }
783
784protected:
785  bool DoExecute(Args &command, CommandReturnObject &result) override;
786
787public:
788  CommandObjectFrameRecognizerAdd(CommandInterpreter &interpreter)
789      : CommandObjectParsed(interpreter, "frame recognizer add",
790                            "Add a new frame recognizer.", nullptr),
791        m_options() {
792    SetHelpLong(R"(
793Frame recognizers allow for retrieving information about special frames based on
794ABI, arguments or other special properties of that frame, even without source
795code or debug info. Currently, one use case is to extract function arguments
796that would otherwise be unaccesible, or augment existing arguments.
797
798Adding a custom frame recognizer is possible by implementing a Python class
799and using the 'frame recognizer add' command. The Python class should have a
800'get_recognized_arguments' method and it will receive an argument of type
801lldb.SBFrame representing the current frame that we are trying to recognize.
802The method should return a (possibly empty) list of lldb.SBValue objects that
803represent the recognized arguments.
804
805An example of a recognizer that retrieves the file descriptor values from libc
806functions 'read', 'write' and 'close' follows:
807
808  class LibcFdRecognizer(object):
809    def get_recognized_arguments(self, frame):
810      if frame.name in ["read", "write", "close"]:
811        fd = frame.EvaluateExpression("$arg1").unsigned
812        value = lldb.target.CreateValueFromExpression("fd", "(int)%d" % fd)
813        return [value]
814      return []
815
816The file containing this implementation can be imported via 'command script
817import' and then we can register this recognizer with 'frame recognizer add'.
818It's important to restrict the recognizer to the libc library (which is
819libsystem_kernel.dylib on macOS) to avoid matching functions with the same name
820in other modules:
821
822(lldb) command script import .../fd_recognizer.py
823(lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib
824
825When the program is stopped at the beginning of the 'read' function in libc, we
826can view the recognizer arguments in 'frame variable':
827
828(lldb) b read
829(lldb) r
830Process 1234 stopped
831* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3
832    frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read
833(lldb) frame variable
834(int) fd = 3
835
836    )");
837  }
838  ~CommandObjectFrameRecognizerAdd() override = default;
839};
840
841bool CommandObjectFrameRecognizerAdd::DoExecute(Args &command,
842                                                CommandReturnObject &result) {
843#if LLDB_ENABLE_PYTHON
844  if (m_options.m_class_name.empty()) {
845    result.AppendErrorWithFormat(
846        "%s needs a Python class name (-l argument).\n", m_cmd_name.c_str());
847    result.SetStatus(eReturnStatusFailed);
848    return false;
849  }
850
851  if (m_options.m_module.empty()) {
852    result.AppendErrorWithFormat("%s needs a module name (-s argument).\n",
853                                 m_cmd_name.c_str());
854    result.SetStatus(eReturnStatusFailed);
855    return false;
856  }
857
858  if (m_options.m_function.empty()) {
859    result.AppendErrorWithFormat("%s needs a function name (-n argument).\n",
860                                 m_cmd_name.c_str());
861    result.SetStatus(eReturnStatusFailed);
862    return false;
863  }
864
865  ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
866
867  if (interpreter &&
868      !interpreter->CheckObjectExists(m_options.m_class_name.c_str())) {
869    result.AppendWarning("The provided class does not exist - please define it "
870                         "before attempting to use this frame recognizer");
871  }
872
873  StackFrameRecognizerSP recognizer_sp =
874      StackFrameRecognizerSP(new ScriptedStackFrameRecognizer(
875          interpreter, m_options.m_class_name.c_str()));
876  if (m_options.m_regex) {
877    auto module =
878        RegularExpressionSP(new RegularExpression(m_options.m_module));
879    auto func =
880        RegularExpressionSP(new RegularExpression(m_options.m_function));
881    StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func);
882  } else {
883    auto module = ConstString(m_options.m_module);
884    auto func = ConstString(m_options.m_function);
885    StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func);
886  }
887#endif
888
889  result.SetStatus(eReturnStatusSuccessFinishNoResult);
890  return result.Succeeded();
891}
892
893class CommandObjectFrameRecognizerClear : public CommandObjectParsed {
894public:
895  CommandObjectFrameRecognizerClear(CommandInterpreter &interpreter)
896      : CommandObjectParsed(interpreter, "frame recognizer clear",
897                            "Delete all frame recognizers.", nullptr) {}
898
899  ~CommandObjectFrameRecognizerClear() override = default;
900
901protected:
902  bool DoExecute(Args &command, CommandReturnObject &result) override {
903    StackFrameRecognizerManager::RemoveAllRecognizers();
904    result.SetStatus(eReturnStatusSuccessFinishResult);
905    return result.Succeeded();
906  }
907};
908
909class CommandObjectFrameRecognizerDelete : public CommandObjectParsed {
910public:
911  CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter)
912      : CommandObjectParsed(interpreter, "frame recognizer delete",
913                            "Delete an existing frame recognizer.", nullptr) {}
914
915  ~CommandObjectFrameRecognizerDelete() override = default;
916
917protected:
918  bool DoExecute(Args &command, CommandReturnObject &result) override {
919    if (command.GetArgumentCount() == 0) {
920      if (!m_interpreter.Confirm(
921              "About to delete all frame recognizers, do you want to do that?",
922              true)) {
923        result.AppendMessage("Operation cancelled...");
924        result.SetStatus(eReturnStatusFailed);
925        return false;
926      }
927
928      StackFrameRecognizerManager::RemoveAllRecognizers();
929      result.SetStatus(eReturnStatusSuccessFinishResult);
930      return result.Succeeded();
931    }
932
933    if (command.GetArgumentCount() != 1) {
934      result.AppendErrorWithFormat("'%s' takes zero or one arguments.\n",
935                                   m_cmd_name.c_str());
936      result.SetStatus(eReturnStatusFailed);
937      return false;
938    }
939
940    uint32_t recognizer_id =
941        StringConvert::ToUInt32(command.GetArgumentAtIndex(0), 0, 0);
942
943    StackFrameRecognizerManager::RemoveRecognizerWithID(recognizer_id);
944    result.SetStatus(eReturnStatusSuccessFinishResult);
945    return result.Succeeded();
946  }
947};
948
949class CommandObjectFrameRecognizerList : public CommandObjectParsed {
950public:
951  CommandObjectFrameRecognizerList(CommandInterpreter &interpreter)
952      : CommandObjectParsed(interpreter, "frame recognizer list",
953                            "Show a list of active frame recognizers.",
954                            nullptr) {}
955
956  ~CommandObjectFrameRecognizerList() override = default;
957
958protected:
959  bool DoExecute(Args &command, CommandReturnObject &result) override {
960    bool any_printed = false;
961    StackFrameRecognizerManager::ForEach(
962        [&result, &any_printed](uint32_t recognizer_id, std::string name,
963                                std::string function, std::string symbol,
964                                bool regexp) {
965          if (name == "")
966            name = "(internal)";
967          result.GetOutputStream().Printf(
968              "%d: %s, module %s, function %s%s\n", recognizer_id, name.c_str(),
969              function.c_str(), symbol.c_str(), regexp ? " (regexp)" : "");
970          any_printed = true;
971        });
972
973    if (any_printed)
974      result.SetStatus(eReturnStatusSuccessFinishResult);
975    else {
976      result.GetOutputStream().PutCString("no matching results found.\n");
977      result.SetStatus(eReturnStatusSuccessFinishNoResult);
978    }
979    return result.Succeeded();
980  }
981};
982
983class CommandObjectFrameRecognizerInfo : public CommandObjectParsed {
984public:
985  CommandObjectFrameRecognizerInfo(CommandInterpreter &interpreter)
986      : CommandObjectParsed(
987            interpreter, "frame recognizer info",
988            "Show which frame recognizer is applied a stack frame (if any).",
989            nullptr) {
990    CommandArgumentEntry arg;
991    CommandArgumentData index_arg;
992
993    // Define the first (and only) variant of this arg.
994    index_arg.arg_type = eArgTypeFrameIndex;
995    index_arg.arg_repetition = eArgRepeatPlain;
996
997    // There is only one variant this argument could be; put it into the
998    // argument entry.
999    arg.push_back(index_arg);
1000
1001    // Push the data for the first argument into the m_arguments vector.
1002    m_arguments.push_back(arg);
1003  }
1004
1005  ~CommandObjectFrameRecognizerInfo() override = default;
1006
1007protected:
1008  bool DoExecute(Args &command, CommandReturnObject &result) override {
1009    Process *process = m_exe_ctx.GetProcessPtr();
1010    if (process == nullptr) {
1011      result.AppendError("no process");
1012      result.SetStatus(eReturnStatusFailed);
1013      return false;
1014    }
1015    Thread *thread = m_exe_ctx.GetThreadPtr();
1016    if (thread == nullptr) {
1017      result.AppendError("no thread");
1018      result.SetStatus(eReturnStatusFailed);
1019      return false;
1020    }
1021    if (command.GetArgumentCount() != 1) {
1022      result.AppendErrorWithFormat(
1023          "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str());
1024      result.SetStatus(eReturnStatusFailed);
1025      return false;
1026    }
1027
1028    uint32_t frame_index =
1029        StringConvert::ToUInt32(command.GetArgumentAtIndex(0), 0, 0);
1030    StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index);
1031    if (!frame_sp) {
1032      result.AppendErrorWithFormat("no frame with index %u", frame_index);
1033      result.SetStatus(eReturnStatusFailed);
1034      return false;
1035    }
1036
1037    auto recognizer =
1038        StackFrameRecognizerManager::GetRecognizerForFrame(frame_sp);
1039
1040    Stream &output_stream = result.GetOutputStream();
1041    output_stream.Printf("frame %d ", frame_index);
1042    if (recognizer) {
1043      output_stream << "is recognized by ";
1044      output_stream << recognizer->GetName();
1045    } else {
1046      output_stream << "not recognized by any recognizer";
1047    }
1048    output_stream.EOL();
1049    result.SetStatus(eReturnStatusSuccessFinishResult);
1050    return result.Succeeded();
1051  }
1052};
1053
1054class CommandObjectFrameRecognizer : public CommandObjectMultiword {
1055public:
1056  CommandObjectFrameRecognizer(CommandInterpreter &interpreter)
1057      : CommandObjectMultiword(
1058            interpreter, "frame recognizer",
1059            "Commands for editing and viewing frame recognizers.",
1060            "frame recognizer [<sub-command-options>] ") {
1061    LoadSubCommand("add", CommandObjectSP(new CommandObjectFrameRecognizerAdd(
1062                              interpreter)));
1063    LoadSubCommand(
1064        "clear",
1065        CommandObjectSP(new CommandObjectFrameRecognizerClear(interpreter)));
1066    LoadSubCommand(
1067        "delete",
1068        CommandObjectSP(new CommandObjectFrameRecognizerDelete(interpreter)));
1069    LoadSubCommand("list", CommandObjectSP(new CommandObjectFrameRecognizerList(
1070                               interpreter)));
1071    LoadSubCommand("info", CommandObjectSP(new CommandObjectFrameRecognizerInfo(
1072                               interpreter)));
1073  }
1074
1075  ~CommandObjectFrameRecognizer() override = default;
1076};
1077
1078#pragma mark CommandObjectMultiwordFrame
1079
1080// CommandObjectMultiwordFrame
1081
1082CommandObjectMultiwordFrame::CommandObjectMultiwordFrame(
1083    CommandInterpreter &interpreter)
1084    : CommandObjectMultiword(interpreter, "frame",
1085                             "Commands for selecting and "
1086                             "examing the current "
1087                             "thread's stack frames.",
1088                             "frame <subcommand> [<subcommand-options>]") {
1089  LoadSubCommand("diagnose",
1090                 CommandObjectSP(new CommandObjectFrameDiagnose(interpreter)));
1091  LoadSubCommand("info",
1092                 CommandObjectSP(new CommandObjectFrameInfo(interpreter)));
1093  LoadSubCommand("select",
1094                 CommandObjectSP(new CommandObjectFrameSelect(interpreter)));
1095  LoadSubCommand("variable",
1096                 CommandObjectSP(new CommandObjectFrameVariable(interpreter)));
1097#if LLDB_ENABLE_PYTHON
1098  LoadSubCommand("recognizer", CommandObjectSP(new CommandObjectFrameRecognizer(
1099                                   interpreter)));
1100#endif
1101}
1102
1103CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default;
1104