brintos

brintos / llvm-project-archived public Read only

0
0
Text · 45.5 KiB · 9133359 Raw
1260 lines · cpp
1//===-- CommandObjectFrame.cpp --------------------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8#include "CommandObjectFrame.h"9#include "lldb/Core/Debugger.h"10#include "lldb/DataFormatters/DataVisualization.h"11#include "lldb/DataFormatters/ValueObjectPrinter.h"12#include "lldb/Host/Config.h"13#include "lldb/Host/OptionParser.h"14#include "lldb/Interpreter/CommandInterpreter.h"15#include "lldb/Interpreter/CommandOptionArgumentTable.h"16#include "lldb/Interpreter/CommandReturnObject.h"17#include "lldb/Interpreter/OptionArgParser.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#include "lldb/ValueObject/ValueObject.h"33 34#include <memory>35#include <optional>36#include <string>37 38using namespace lldb;39using namespace lldb_private;40 41#pragma mark CommandObjectFrameDiagnose42 43// CommandObjectFrameInfo44 45// CommandObjectFrameDiagnose46 47#define LLDB_OPTIONS_frame_diag48#include "CommandOptions.inc"49 50class CommandObjectFrameDiagnose : public CommandObjectParsed {51public:52  class CommandOptions : public Options {53  public:54    CommandOptions() { OptionParsingStarting(nullptr); }55 56    ~CommandOptions() override = default;57 58    Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,59                          ExecutionContext *execution_context) override {60      Status error;61      const int short_option = m_getopt_table[option_idx].val;62      switch (short_option) {63      case 'r':64        reg = ConstString(option_arg);65        break;66 67      case 'a': {68        address.emplace();69        if (option_arg.getAsInteger(0, *address)) {70          address.reset();71          error = Status::FromErrorStringWithFormat(72              "invalid address argument '%s'", option_arg.str().c_str());73        }74      } break;75 76      case 'o': {77        offset.emplace();78        if (option_arg.getAsInteger(0, *offset)) {79          offset.reset();80          error = Status::FromErrorStringWithFormat(81              "invalid offset argument '%s'", option_arg.str().c_str());82        }83      } break;84 85      default:86        llvm_unreachable("Unimplemented option");87      }88 89      return error;90    }91 92    void OptionParsingStarting(ExecutionContext *execution_context) override {93      address.reset();94      reg.reset();95      offset.reset();96    }97 98    llvm::ArrayRef<OptionDefinition> GetDefinitions() override {99      return llvm::ArrayRef(g_frame_diag_options);100    }101 102    // Options.103    std::optional<lldb::addr_t> address;104    std::optional<ConstString> reg;105    std::optional<int64_t> offset;106  };107 108  CommandObjectFrameDiagnose(CommandInterpreter &interpreter)109      : CommandObjectParsed(interpreter, "frame diagnose",110                            "Try to determine what path the current stop "111                            "location used to get to a register or address",112                            nullptr,113                            eCommandRequiresThread | eCommandTryTargetAPILock |114                                eCommandProcessMustBeLaunched |115                                eCommandProcessMustBePaused) {116    AddSimpleArgumentList(eArgTypeFrameIndex, eArgRepeatOptional);117  }118 119  ~CommandObjectFrameDiagnose() override = default;120 121  Options *GetOptions() override { return &m_options; }122 123protected:124  void DoExecute(Args &command, CommandReturnObject &result) override {125    Thread *thread = m_exe_ctx.GetThreadPtr();126    StackFrameSP frame_sp = thread->GetSelectedFrame(SelectMostRelevantFrame);127 128    ValueObjectSP valobj_sp;129 130    if (m_options.address) {131      if (m_options.reg || m_options.offset) {132        result.AppendError(133            "`frame diagnose --address` is incompatible with other arguments.");134        return;135      }136      valobj_sp = frame_sp->GuessValueForAddress(*m_options.address);137    } else if (m_options.reg) {138      valobj_sp = frame_sp->GuessValueForRegisterAndOffset(139          *m_options.reg, m_options.offset.value_or(0));140    } else {141      StopInfoSP stop_info_sp = thread->GetStopInfo();142      if (!stop_info_sp) {143        result.AppendError("no arguments provided, and no stop info");144        return;145      }146 147      valobj_sp = StopInfo::GetCrashingDereference(stop_info_sp);148    }149 150    if (!valobj_sp) {151      result.AppendError("no diagnosis available");152      return;153    }154 155    result.GetValueObjectList().Append(valobj_sp);156    DumpValueObjectOptions::DeclPrintingHelper helper =157        [&valobj_sp](ConstString type, ConstString var,158                     const DumpValueObjectOptions &opts,159                     Stream &stream) -> bool {160      const ValueObject::GetExpressionPathFormat format = ValueObject::161          GetExpressionPathFormat::eGetExpressionPathFormatHonorPointers;162      valobj_sp->GetExpressionPath(stream, format);163      stream.PutCString(" =");164      return true;165    };166 167    DumpValueObjectOptions options;168    options.SetDeclPrintingHelper(helper);169    // We've already handled the case where the value object sp is null, so170    // this is just to make sure future changes don't skip that:171    assert(valobj_sp.get() && "Must have a valid ValueObject to print");172    ValueObjectPrinter printer(*valobj_sp, &result.GetOutputStream(), options);173    if (llvm::Error error = printer.PrintValueObject())174      result.AppendError(toString(std::move(error)));175  }176 177  CommandOptions m_options;178};179 180#pragma mark CommandObjectFrameInfo181 182// CommandObjectFrameInfo183 184class CommandObjectFrameInfo : public CommandObjectParsed {185public:186  CommandObjectFrameInfo(CommandInterpreter &interpreter)187      : CommandObjectParsed(interpreter, "frame info",188                            "List information about the current "189                            "stack frame in the current thread.",190                            "frame info",191                            eCommandRequiresFrame | eCommandTryTargetAPILock |192                                eCommandProcessMustBeLaunched |193                                eCommandProcessMustBePaused) {}194 195  ~CommandObjectFrameInfo() override = default;196 197protected:198  void DoExecute(Args &command, CommandReturnObject &result) override {199    m_exe_ctx.GetFrameRef().DumpUsingSettingsFormat(&result.GetOutputStream());200    result.SetStatus(eReturnStatusSuccessFinishResult);201  }202};203 204#pragma mark CommandObjectFrameSelect205 206// CommandObjectFrameSelect207 208#define LLDB_OPTIONS_frame_select209#include "CommandOptions.inc"210 211class CommandObjectFrameSelect : public CommandObjectParsed {212public:213  class CommandOptions : public Options {214  public:215    CommandOptions() { OptionParsingStarting(nullptr); }216 217    ~CommandOptions() override = default;218 219    Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,220                          ExecutionContext *execution_context) override {221      Status error;222      const int short_option = m_getopt_table[option_idx].val;223      switch (short_option) {224      case 'r': {225        int32_t offset = 0;226        if (option_arg.getAsInteger(0, offset) || offset == INT32_MIN) {227          error = Status::FromErrorStringWithFormat(228              "invalid frame offset argument '%s'", option_arg.str().c_str());229        } else230          relative_frame_offset = offset;231        break;232      }233 234      default:235        llvm_unreachable("Unimplemented option");236      }237 238      return error;239    }240 241    void OptionParsingStarting(ExecutionContext *execution_context) override {242      relative_frame_offset.reset();243    }244 245    llvm::ArrayRef<OptionDefinition> GetDefinitions() override {246      return llvm::ArrayRef(g_frame_select_options);247    }248 249    std::optional<int32_t> relative_frame_offset;250  };251 252  CommandObjectFrameSelect(CommandInterpreter &interpreter)253      : CommandObjectParsed(interpreter, "frame select",254                            "Select the current stack frame by "255                            "index from within the current thread "256                            "(see 'thread backtrace'.)",257                            nullptr,258                            eCommandRequiresThread | eCommandTryTargetAPILock |259                                eCommandProcessMustBeLaunched |260                                eCommandProcessMustBePaused) {261    AddSimpleArgumentList(eArgTypeFrameIndex, eArgRepeatOptional);262  }263 264  ~CommandObjectFrameSelect() override = default;265 266  Options *GetOptions() override { return &m_options; }267 268private:269  void SkipHiddenFrames(Thread &thread, uint32_t frame_idx) {270    uint32_t candidate_idx = frame_idx;271    const unsigned max_depth = 12;272    for (unsigned num_try = 0; num_try < max_depth; ++num_try) {273      if (candidate_idx == 0 && *m_options.relative_frame_offset == -1) {274        candidate_idx = UINT32_MAX;275        break;276      }277      candidate_idx += *m_options.relative_frame_offset;278      if (auto candidate_sp = thread.GetStackFrameAtIndex(candidate_idx)) {279        if (candidate_sp->IsHidden())280          continue;281        // Now candidate_idx is the first non-hidden frame.282        break;283      }284      candidate_idx = UINT32_MAX;285      break;286    };287    if (candidate_idx != UINT32_MAX)288      m_options.relative_frame_offset = candidate_idx - frame_idx;289  }290 291protected:292  void DoExecute(Args &command, CommandReturnObject &result) override {293    // No need to check "thread" for validity as eCommandRequiresThread ensures294    // it is valid295    Thread *thread = m_exe_ctx.GetThreadPtr();296 297    uint32_t frame_idx = UINT32_MAX;298    if (m_options.relative_frame_offset) {299      // The one and only argument is a signed relative frame index300      frame_idx = thread->GetSelectedFrameIndex(SelectMostRelevantFrame);301      if (frame_idx == UINT32_MAX)302        frame_idx = 0;303 304      // If moving up/down by one, skip over hidden frames, unless we started305      // in a hidden frame.306      if ((*m_options.relative_frame_offset == 1 ||307           *m_options.relative_frame_offset == -1)) {308        if (auto current_frame_sp = thread->GetStackFrameAtIndex(frame_idx);309            !current_frame_sp->IsHidden())310          SkipHiddenFrames(*thread, frame_idx);311      }312 313      if (*m_options.relative_frame_offset < 0) {314        if (static_cast<int32_t>(frame_idx) >=315            -*m_options.relative_frame_offset)316          frame_idx += *m_options.relative_frame_offset;317        else {318          if (frame_idx == 0) {319            // If you are already at the bottom of the stack, then just warn320            // and don't reset the frame.321            result.AppendError("already at the bottom of the stack");322            return;323          } else324            frame_idx = 0;325        }326      } else if (*m_options.relative_frame_offset > 0) {327        // I don't want "up 20" where "20" takes you past the top of the stack328        // to produce an error, but rather to just go to the top.  OTOH, start329        // by seeing if the requested frame exists, in which case we can avoid330        // counting the stack here...331        const uint32_t frame_requested =332            frame_idx + *m_options.relative_frame_offset;333        StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_requested);334        if (frame_sp)335          frame_idx = frame_requested;336        else {337          // The request went past the stack, so handle that case:338          const uint32_t num_frames = thread->GetStackFrameCount();339          if (static_cast<int32_t>(num_frames - frame_idx) >340              *m_options.relative_frame_offset)341          frame_idx += *m_options.relative_frame_offset;342          else {343            if (frame_idx == num_frames - 1) {344              // If we are already at the top of the stack, just warn and don't345              // reset the frame.346              result.AppendError("already at the top of the stack");347              return;348            } else349              frame_idx = num_frames - 1;350          }351        }352      }353    } else {354      if (command.GetArgumentCount() > 1) {355        result.AppendErrorWithFormat(356            "too many arguments; expected frame-index, saw '%s'.\n",357            command[0].c_str());358        m_options.GenerateOptionUsage(359            result.GetErrorStream(), *this,360            GetCommandInterpreter().GetDebugger().GetTerminalWidth(),361            GetCommandInterpreter().GetDebugger().GetUseColor());362        return;363      }364 365      if (command.GetArgumentCount() == 1) {366        if (command[0].ref().getAsInteger(0, frame_idx)) {367          result.AppendErrorWithFormat("invalid frame index argument '%s'.",368                                       command[0].c_str());369          return;370        }371      } else if (command.GetArgumentCount() == 0) {372        frame_idx = thread->GetSelectedFrameIndex(SelectMostRelevantFrame);373        if (frame_idx == UINT32_MAX) {374          frame_idx = 0;375        }376      }377    }378 379    bool success = thread->SetSelectedFrameByIndexNoisily(380        frame_idx, result.GetOutputStream());381    if (success) {382      m_exe_ctx.SetFrameSP(thread->GetSelectedFrame(SelectMostRelevantFrame));383      result.SetStatus(eReturnStatusSuccessFinishResult);384    } else {385      result.AppendErrorWithFormat("Frame index (%u) out of range.\n",386                                   frame_idx);387    }388  }389 390  CommandOptions m_options;391};392 393#pragma mark CommandObjectFrameVariable394// List images with associated information395class CommandObjectFrameVariable : public CommandObjectParsed {396public:397  CommandObjectFrameVariable(CommandInterpreter &interpreter)398      : CommandObjectParsed(399            interpreter, "frame variable",400            "Show variables for the current stack frame. Defaults to all "401            "arguments and local variables in scope. Names of argument, "402            "local, file static and file global variables can be specified.",403            nullptr,404            eCommandRequiresFrame | eCommandTryTargetAPILock |405                eCommandProcessMustBeLaunched | eCommandProcessMustBePaused |406                eCommandRequiresProcess),407        m_option_variable(408            true), // Include the frame specific options by passing "true"409        m_option_format(eFormatDefault) {410    SetHelpLong(R"(411Children of aggregate variables can be specified such as 'var->child.x'.  In412'frame variable', the operators -> and [] do not invoke operator overloads if413they exist, but directly access the specified element.  If you want to trigger414operator overloads use the expression command to print the variable instead.415 416It is worth noting that except for overloaded operators, when printing local417variables 'expr local_var' and 'frame var local_var' produce the same results.418However, 'frame variable' is more efficient, since it uses debug information and419memory reads directly, rather than parsing and evaluating an expression, which420may even involve JITing and running code in the target program.)");421 422    AddSimpleArgumentList(eArgTypeVarName, eArgRepeatStar);423 424    m_option_group.Append(&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);425    m_option_group.Append(&m_option_format,426                          OptionGroupFormat::OPTION_GROUP_FORMAT |427                              OptionGroupFormat::OPTION_GROUP_GDB_FMT,428                          LLDB_OPT_SET_1);429    m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);430    m_option_group.Finalize();431  }432 433  ~CommandObjectFrameVariable() override = default;434 435  Options *GetOptions() override { return &m_option_group; }436 437protected:438  llvm::StringRef GetScopeString(VariableSP var_sp) {439    if (!var_sp)440      return llvm::StringRef();441 442    switch (var_sp->GetScope()) {443    case eValueTypeVariableGlobal:444      return "GLOBAL: ";445    case eValueTypeVariableStatic:446      return "STATIC: ";447    case eValueTypeVariableArgument:448      return "ARG: ";449    case eValueTypeVariableLocal:450      return "LOCAL: ";451    case eValueTypeVariableThreadLocal:452      return "THREAD: ";453    default:454      break;455    }456 457    return llvm::StringRef();458  }459 460  /// Returns true if `scope` matches any of the options in `m_option_variable`.461  bool ScopeRequested(lldb::ValueType scope) {462    switch (scope) {463    case eValueTypeVariableGlobal:464    case eValueTypeVariableStatic:465      return m_option_variable.show_globals;466    case eValueTypeVariableArgument:467      return m_option_variable.show_args;468    case eValueTypeVariableLocal:469      return m_option_variable.show_locals;470    case eValueTypeInvalid:471    case eValueTypeRegister:472    case eValueTypeRegisterSet:473    case eValueTypeConstResult:474    case eValueTypeVariableThreadLocal:475    case eValueTypeVTable:476    case eValueTypeVTableEntry:477      return false;478    }479    llvm_unreachable("Unexpected scope value");480  }481 482  /// Finds all the variables in `all_variables` whose name matches `regex`,483  /// inserting them into `matches`. Variables already contained in `matches`484  /// are not inserted again.485  /// Nullopt is returned in case of no matches.486  /// A sub-range of `matches` with all newly inserted variables is returned.487  /// This may be empty if all matches were already contained in `matches`.488  std::optional<llvm::ArrayRef<VariableSP>>489  findUniqueRegexMatches(RegularExpression &regex,490                         VariableList &matches,491                         const VariableList &all_variables) {492    bool any_matches = false;493    const size_t previous_num_vars = matches.GetSize();494 495    for (const VariableSP &var : all_variables) {496      if (!var->NameMatches(regex) || !ScopeRequested(var->GetScope()))497        continue;498      any_matches = true;499      matches.AddVariableIfUnique(var);500    }501 502    if (any_matches)503      return matches.toArrayRef().drop_front(previous_num_vars);504    return std::nullopt;505  }506 507  void DoExecute(Args &command, CommandReturnObject &result) override {508    // No need to check "frame" for validity as eCommandRequiresFrame ensures509    // it is valid510    StackFrame *frame = m_exe_ctx.GetFramePtr();511 512    Stream &s = result.GetOutputStream();513 514    // Using a regex should behave like looking for an exact name match: it515    // also finds globals.516    m_option_variable.show_globals |= m_option_variable.use_regex;517 518    // Be careful about the stack frame, if any summary formatter runs code, it519    // might clear the StackFrameList for the thread.  So hold onto a shared520    // pointer to the frame so it stays alive.521 522    Status error;523    VariableList *variable_list =524        frame->GetVariableList(m_option_variable.show_globals, &error);525 526    if (error.Fail() && (!variable_list || variable_list->GetSize() == 0)) {527      result.AppendError(error.AsCString());528    }529 530    ValueObjectSP valobj_sp;531 532    TypeSummaryImplSP summary_format_sp;533    if (!m_option_variable.summary.IsCurrentValueEmpty())534      DataVisualization::NamedSummaryFormats::GetSummaryFormat(535          ConstString(m_option_variable.summary.GetCurrentValue()),536          summary_format_sp);537    else if (!m_option_variable.summary_string.IsCurrentValueEmpty())538      summary_format_sp = std::make_shared<StringSummaryFormat>(539          TypeSummaryImpl::Flags(),540          m_option_variable.summary_string.GetCurrentValue());541 542    DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(543        eLanguageRuntimeDescriptionDisplayVerbosityFull, eFormatDefault,544        summary_format_sp));545 546    const SymbolContext &sym_ctx =547        frame->GetSymbolContext(eSymbolContextFunction);548    if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction())549      m_option_variable.show_globals = true;550 551    if (variable_list) {552      const Format format = m_option_format.GetFormat();553      options.SetFormat(format);554 555      if (!command.empty()) {556        VariableList regex_var_list;557 558        // If we have any args to the variable command, we will make variable559        // objects from them...560        for (auto &entry : command) {561          if (m_option_variable.use_regex) {562            llvm::StringRef name_str = entry.ref();563            RegularExpression regex(name_str);564            if (regex.IsValid()) {565              std::optional<llvm::ArrayRef<VariableSP>> results =566                  findUniqueRegexMatches(regex, regex_var_list, *variable_list);567              if (!results) {568                result.AppendErrorWithFormat(569                    "no variables matched the regular expression '%s'.",570                    entry.c_str());571                continue;572              }573              for (const VariableSP &var_sp : *results) {574                valobj_sp = frame->GetValueObjectForFrameVariable(575                    var_sp, m_varobj_options.use_dynamic);576                if (valobj_sp) {577                  result.GetValueObjectList().Append(valobj_sp);578 579                  std::string scope_string;580                  if (m_option_variable.show_scope)581                    scope_string = GetScopeString(var_sp).str();582 583                  if (!scope_string.empty())584                    s.PutCString(scope_string);585 586                  if (m_option_variable.show_decl &&587                      var_sp->GetDeclaration().GetFile()) {588                    bool show_fullpaths = false;589                    bool show_module = true;590                    if (var_sp->DumpDeclaration(&s, show_fullpaths,591                                                show_module))592                      s.PutCString(": ");593                  }594                  auto &strm = result.GetOutputStream();595                  if (llvm::Error error = valobj_sp->Dump(strm, options))596                    result.AppendError(toString(std::move(error)));597                }598              }599            } else {600              if (llvm::Error err = regex.GetError())601                result.AppendError(llvm::toString(std::move(err)));602              else603                result.AppendErrorWithFormat(604                    "unknown regex error when compiling '%s'", entry.c_str());605            }606          } else // No regex, either exact variable names or variable607                 // 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              result.GetValueObjectList().Append(valobj_sp);620 621              std::string scope_string;622              if (m_option_variable.show_scope)623                scope_string = GetScopeString(var_sp).str();624 625              if (!scope_string.empty())626                s.PutCString(scope_string);627              if (m_option_variable.show_decl && var_sp &&628                  var_sp->GetDeclaration().GetFile()) {629                var_sp->GetDeclaration().DumpStopContext(&s, false);630                s.PutCString(": ");631              }632 633              options.SetFormat(format);634              options.SetVariableFormatDisplayLanguage(635                  valobj_sp->GetPreferredDisplayLanguage());636 637              Stream &output_stream = result.GetOutputStream();638              options.SetRootValueObjectName(639                  valobj_sp->GetParent() ? entry.c_str() : nullptr);640              if (llvm::Error error = valobj_sp->Dump(output_stream, options))641                result.AppendError(toString(std::move(error)));642            } else {643              if (auto error_cstr = error.AsCString(nullptr))644                result.AppendError(error_cstr);645              else646                result.AppendErrorWithFormat(647                    "unable to find any variable expression path that matches "648                    "'%s'.",649                    entry.c_str());650            }651          }652        }653      } else // No command arg specified.  Use variable_list, instead.654      {655        const size_t num_variables = variable_list->GetSize();656        if (num_variables > 0) {657          for (size_t i = 0; i < num_variables; i++) {658            VariableSP var_sp = variable_list->GetVariableAtIndex(i);659            if (!ScopeRequested(var_sp->GetScope()))660                continue;661            std::string scope_string;662            if (m_option_variable.show_scope)663              scope_string = GetScopeString(var_sp).str();664 665            // Use the variable object code to make sure we are using the same666            // APIs as the public API will be using...667            valobj_sp = frame->GetValueObjectForFrameVariable(668                var_sp, m_varobj_options.use_dynamic);669            if (valobj_sp) {670              result.GetValueObjectList().Append(valobj_sp);671 672              // When dumping all variables, don't print any variables that are673              // not in scope to avoid extra unneeded output674              if (valobj_sp->IsInScope()) {675                if (!valobj_sp->GetTargetSP()676                         ->GetDisplayRuntimeSupportValues() &&677                    valobj_sp->IsRuntimeSupportValue())678                  continue;679 680                if (!scope_string.empty())681                  s.PutCString(scope_string);682 683                if (m_option_variable.show_decl &&684                    var_sp->GetDeclaration().GetFile()) {685                  var_sp->GetDeclaration().DumpStopContext(&s, false);686                  s.PutCString(": ");687                }688 689                options.SetFormat(format);690                options.SetVariableFormatDisplayLanguage(691                    valobj_sp->GetPreferredDisplayLanguage());692                options.SetRootValueObjectName(693                    var_sp ? var_sp->GetName().AsCString() : nullptr);694                if (llvm::Error error =695                        valobj_sp->Dump(result.GetOutputStream(), options))696                  result.AppendError(toString(std::move(error)));697              }698            }699          }700        }701      }702      if (result.GetStatus() != eReturnStatusFailed)703        result.SetStatus(eReturnStatusSuccessFinishResult);704    }705 706    if (m_option_variable.show_recognized_args) {707      auto recognized_frame = frame->GetRecognizedFrame();708      if (recognized_frame) {709        ValueObjectListSP recognized_arg_list =710            recognized_frame->GetRecognizedArguments();711        if (recognized_arg_list) {712          for (auto &rec_value_sp : recognized_arg_list->GetObjects()) {713            result.GetValueObjectList().Append(rec_value_sp);714            options.SetFormat(m_option_format.GetFormat());715            options.SetVariableFormatDisplayLanguage(716                rec_value_sp->GetPreferredDisplayLanguage());717            options.SetRootValueObjectName(rec_value_sp->GetName().AsCString());718            if (llvm::Error error =719                    rec_value_sp->Dump(result.GetOutputStream(), options))720              result.AppendError(toString(std::move(error)));721          }722        }723      }724    }725 726    m_interpreter.PrintWarningsIfNecessary(result.GetOutputStream(),727                                           m_cmd_name);728 729    // Increment statistics.730    TargetStats &target_stats = GetTarget().GetStatistics();731    if (result.Succeeded())732      target_stats.GetFrameVariableStats().NotifySuccess();733    else734      target_stats.GetFrameVariableStats().NotifyFailure();735  }736 737  OptionGroupOptions m_option_group;738  OptionGroupVariable m_option_variable;739  OptionGroupFormat m_option_format;740  OptionGroupValueObjectDisplay m_varobj_options;741};742 743#pragma mark CommandObjectFrameRecognizer744 745#define LLDB_OPTIONS_frame_recognizer_add746#include "CommandOptions.inc"747 748class CommandObjectFrameRecognizerAdd : public CommandObjectParsed {749private:750  class CommandOptions : public Options {751  public:752    CommandOptions() = default;753    ~CommandOptions() override = default;754 755    Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,756                          ExecutionContext *execution_context) override {757      Status error;758      const int short_option = m_getopt_table[option_idx].val;759 760      switch (short_option) {761      case 'f': {762        bool value, success;763        value = OptionArgParser::ToBoolean(option_arg, true, &success);764        if (success) {765          m_first_instruction_only = value;766        } else {767          error = Status::FromErrorStringWithFormat(768              "invalid boolean value '%s' passed for -f option",769              option_arg.str().c_str());770        }771      } break;772      case 'l':773        m_class_name = std::string(option_arg);774        break;775      case 's':776        m_module = std::string(option_arg);777        break;778      case 'n':779        m_symbols.push_back(std::string(option_arg));780        break;781      case 'x':782        m_regex = true;783        break;784      default:785        llvm_unreachable("Unimplemented option");786      }787 788      return error;789    }790 791    void OptionParsingStarting(ExecutionContext *execution_context) override {792      m_module = "";793      m_symbols.clear();794      m_class_name = "";795      m_regex = false;796      m_first_instruction_only = true;797    }798 799    llvm::ArrayRef<OptionDefinition> GetDefinitions() override {800      return llvm::ArrayRef(g_frame_recognizer_add_options);801    }802 803    // Instance variables to hold the values for command options.804    std::string m_class_name;805    std::string m_module;806    std::vector<std::string> m_symbols;807    bool m_regex;808    bool m_first_instruction_only;809  };810 811  CommandOptions m_options;812 813  Options *GetOptions() override { return &m_options; }814 815protected:816  void DoExecute(Args &command, CommandReturnObject &result) override;817 818public:819  CommandObjectFrameRecognizerAdd(CommandInterpreter &interpreter)820      : CommandObjectParsed(interpreter, "frame recognizer add",821                            "Add a new frame recognizer.", nullptr) {822    SetHelpLong(R"(823Frame recognizers allow for retrieving information about special frames based on824ABI, arguments or other special properties of that frame, even without source825code or debug info. Currently, one use case is to extract function arguments826that would otherwise be unaccesible, or augment existing arguments.827 828Adding a custom frame recognizer is possible by implementing a Python class829and using the 'frame recognizer add' command. The Python class should have a830'get_recognized_arguments' method and it will receive an argument of type831lldb.SBFrame representing the current frame that we are trying to recognize.832The method should return a (possibly empty) list of lldb.SBValue objects that833represent the recognized arguments.834 835An example of a recognizer that retrieves the file descriptor values from libc836functions 'read', 'write' and 'close' follows:837 838  class LibcFdRecognizer(object):839    def get_recognized_arguments(self, frame):840      if frame.name in ["read", "write", "close"]:841        fd = frame.EvaluateExpression("$arg1").unsigned842        target = frame.thread.process.target843        value = target.CreateValueFromExpression("fd", "(int)%d" % fd)844        return [value]845      return []846 847The file containing this implementation can be imported via 'command script848import' and then we can register this recognizer with 'frame recognizer add'.849It's important to restrict the recognizer to the libc library (which is850libsystem_kernel.dylib on macOS) to avoid matching functions with the same name851in other modules:852 853(lldb) command script import .../fd_recognizer.py854(lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib855 856When the program is stopped at the beginning of the 'read' function in libc, we857can view the recognizer arguments in 'frame variable':858 859(lldb) b read860(lldb) r861Process 1234 stopped862* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3863    frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read864(lldb) frame variable865(int) fd = 3866 867    )");868  }869  ~CommandObjectFrameRecognizerAdd() override = default;870};871 872void CommandObjectFrameRecognizerAdd::DoExecute(Args &command,873                                                CommandReturnObject &result) {874#if LLDB_ENABLE_PYTHON875  if (m_options.m_class_name.empty()) {876    result.AppendErrorWithFormat(877        "%s needs a Python class name (-l argument).\n", m_cmd_name.c_str());878    return;879  }880 881  if (m_options.m_module.empty()) {882    result.AppendErrorWithFormat("%s needs a module name (-s argument).\n",883                                 m_cmd_name.c_str());884    return;885  }886 887  if (m_options.m_symbols.empty()) {888    result.AppendErrorWithFormat(889        "%s needs at least one symbol name (-n argument).\n",890        m_cmd_name.c_str());891    return;892  }893 894  if (m_options.m_regex && m_options.m_symbols.size() > 1) {895    result.AppendErrorWithFormat(896        "%s needs only one symbol regular expression (-n argument).\n",897        m_cmd_name.c_str());898    return;899  }900 901  ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();902 903  if (interpreter &&904      !interpreter->CheckObjectExists(m_options.m_class_name.c_str())) {905    result.AppendWarning("The provided class does not exist - please define it "906                         "before attempting to use this frame recognizer");907  }908 909  StackFrameRecognizerSP recognizer_sp =910      StackFrameRecognizerSP(new ScriptedStackFrameRecognizer(911          interpreter, m_options.m_class_name.c_str()));912  if (m_options.m_regex) {913    auto module = std::make_shared<RegularExpression>(m_options.m_module);914    auto func =915        std::make_shared<RegularExpression>(m_options.m_symbols.front());916    GetTarget().GetFrameRecognizerManager().AddRecognizer(917        recognizer_sp, module, func, Mangled::NamePreference::ePreferDemangled,918        m_options.m_first_instruction_only);919  } else {920    auto module = ConstString(m_options.m_module);921    std::vector<ConstString> symbols(m_options.m_symbols.begin(),922                                     m_options.m_symbols.end());923    GetTarget().GetFrameRecognizerManager().AddRecognizer(924        recognizer_sp, module, symbols,925        Mangled::NamePreference::ePreferDemangled,926        m_options.m_first_instruction_only);927  }928#endif929 930  result.SetStatus(eReturnStatusSuccessFinishNoResult);931}932 933class CommandObjectFrameRecognizerClear : public CommandObjectParsed {934public:935  CommandObjectFrameRecognizerClear(CommandInterpreter &interpreter)936      : CommandObjectParsed(interpreter, "frame recognizer clear",937                            "Delete all frame recognizers.", nullptr) {}938 939  ~CommandObjectFrameRecognizerClear() override = default;940 941protected:942  void DoExecute(Args &command, CommandReturnObject &result) override {943    GetTarget().GetFrameRecognizerManager().RemoveAllRecognizers();944    result.SetStatus(eReturnStatusSuccessFinishResult);945  }946};947 948static void949PrintRecognizerDetails(Stream &strm, const std::string &name, bool enabled,950                       const std::string &module,951                       llvm::ArrayRef<lldb_private::ConstString> symbols,952                       Mangled::NamePreference symbol_mangling, bool regexp) {953  if (!enabled)954    strm << "[disabled] ";955 956  strm << name << ", ";957 958  if (!module.empty())959    strm << "module " << module << ", ";960 961  switch (symbol_mangling) {962  case Mangled::NamePreference ::ePreferMangled:963    strm << "mangled symbol ";964    break;965  case Mangled::NamePreference ::ePreferDemangled:966    strm << "demangled symbol ";967    break;968  case Mangled::NamePreference ::ePreferDemangledWithoutArguments:969    strm << "demangled (no args) symbol ";970    break;971  }972 973  if (regexp)974    strm << "regex ";975 976  llvm::interleaveComma(symbols, strm);977}978 979// Base class for commands which accept a single frame recognizer as an argument980class CommandObjectWithFrameRecognizerArg : public CommandObjectParsed {981public:982  CommandObjectWithFrameRecognizerArg(CommandInterpreter &interpreter,983                                      const char *name,984                                      const char *help = nullptr,985                                      const char *syntax = nullptr,986                                      uint32_t flags = 0)987      : CommandObjectParsed(interpreter, name, help, syntax, flags) {988    AddSimpleArgumentList(eArgTypeRecognizerID);989  }990 991  void992  HandleArgumentCompletion(CompletionRequest &request,993                           OptionElementVector &opt_element_vector) override {994    if (request.GetCursorIndex() != 0)995      return;996 997    GetTarget().GetFrameRecognizerManager().ForEach(998        [&request](uint32_t rid, bool enabled, std::string rname,999                   std::string module,1000                   llvm::ArrayRef<lldb_private::ConstString> symbols,1001                   Mangled::NamePreference symbol_mangling, bool regexp) {1002          StreamString strm;1003          if (rname.empty())1004            rname = "(internal)";1005 1006          PrintRecognizerDetails(strm, rname, enabled, module, symbols,1007                                 symbol_mangling, regexp);1008 1009          request.TryCompleteCurrentArg(std::to_string(rid), strm.GetString());1010        });1011  }1012 1013  virtual void DoExecuteWithId(CommandReturnObject &result,1014                               uint32_t recognizer_id) = 0;1015 1016  void DoExecute(Args &command, CommandReturnObject &result) override {1017    uint32_t recognizer_id;1018    if (!llvm::to_integer(command.GetArgumentAtIndex(0), recognizer_id)) {1019      result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n",1020                                   command.GetArgumentAtIndex(0));1021      return;1022    }1023 1024    DoExecuteWithId(result, recognizer_id);1025  }1026};1027 1028class CommandObjectFrameRecognizerEnable1029    : public CommandObjectWithFrameRecognizerArg {1030public:1031  CommandObjectFrameRecognizerEnable(CommandInterpreter &interpreter)1032      : CommandObjectWithFrameRecognizerArg(1033            interpreter, "frame recognizer enable",1034            "Enable a frame recognizer by id.", nullptr) {1035    AddSimpleArgumentList(eArgTypeRecognizerID);1036  }1037 1038  ~CommandObjectFrameRecognizerEnable() override = default;1039 1040protected:1041  void DoExecuteWithId(CommandReturnObject &result,1042                       uint32_t recognizer_id) override {1043    auto &recognizer_mgr = GetTarget().GetFrameRecognizerManager();1044    if (!recognizer_mgr.SetEnabledForID(recognizer_id, true)) {1045      result.AppendErrorWithFormat("'%u' is not a valid recognizer id.\n",1046                                   recognizer_id);1047      return;1048    }1049    result.SetStatus(eReturnStatusSuccessFinishResult);1050  }1051};1052 1053class CommandObjectFrameRecognizerDisable1054    : public CommandObjectWithFrameRecognizerArg {1055public:1056  CommandObjectFrameRecognizerDisable(CommandInterpreter &interpreter)1057      : CommandObjectWithFrameRecognizerArg(1058            interpreter, "frame recognizer disable",1059            "Disable a frame recognizer by id.", nullptr) {1060    AddSimpleArgumentList(eArgTypeRecognizerID);1061  }1062 1063  ~CommandObjectFrameRecognizerDisable() override = default;1064 1065protected:1066  void DoExecuteWithId(CommandReturnObject &result,1067                       uint32_t recognizer_id) override {1068    auto &recognizer_mgr = GetTarget().GetFrameRecognizerManager();1069    if (!recognizer_mgr.SetEnabledForID(recognizer_id, false)) {1070      result.AppendErrorWithFormat("'%u' is not a valid recognizer id.\n",1071                                   recognizer_id);1072      return;1073    }1074    result.SetStatus(eReturnStatusSuccessFinishResult);1075  }1076};1077 1078class CommandObjectFrameRecognizerDelete1079    : public CommandObjectWithFrameRecognizerArg {1080public:1081  CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter)1082      : CommandObjectWithFrameRecognizerArg(1083            interpreter, "frame recognizer delete",1084            "Delete an existing frame recognizer by id.", nullptr) {1085    AddSimpleArgumentList(eArgTypeRecognizerID);1086  }1087 1088  ~CommandObjectFrameRecognizerDelete() override = default;1089 1090protected:1091  void DoExecuteWithId(CommandReturnObject &result,1092                       uint32_t recognizer_id) override {1093    auto &recognizer_mgr = GetTarget().GetFrameRecognizerManager();1094    if (!recognizer_mgr.RemoveRecognizerWithID(recognizer_id)) {1095      result.AppendErrorWithFormat("'%u' is not a valid recognizer id.\n",1096                                   recognizer_id);1097      return;1098    }1099    result.SetStatus(eReturnStatusSuccessFinishResult);1100  }1101};1102 1103class CommandObjectFrameRecognizerList : public CommandObjectParsed {1104public:1105  CommandObjectFrameRecognizerList(CommandInterpreter &interpreter)1106      : CommandObjectParsed(interpreter, "frame recognizer list",1107                            "Show a list of active frame recognizers.",1108                            nullptr) {}1109 1110  ~CommandObjectFrameRecognizerList() override = default;1111 1112protected:1113  void DoExecute(Args &command, CommandReturnObject &result) override {1114    bool any_printed = false;1115    GetTarget().GetFrameRecognizerManager().ForEach(1116        [&result,1117         &any_printed](uint32_t recognizer_id, bool enabled, std::string name,1118                       std::string module, llvm::ArrayRef<ConstString> symbols,1119                       Mangled::NamePreference symbol_mangling, bool regexp) {1120          Stream &stream = result.GetOutputStream();1121 1122          if (name.empty())1123            name = "(internal)";1124 1125          stream << std::to_string(recognizer_id) << ": ";1126          PrintRecognizerDetails(stream, name, enabled, module, symbols,1127                                 symbol_mangling, regexp);1128 1129          stream.EOL();1130          stream.Flush();1131 1132          any_printed = true;1133        });1134 1135    if (any_printed)1136      result.SetStatus(eReturnStatusSuccessFinishResult);1137    else {1138      result.GetOutputStream().PutCString("no matching results found.\n");1139      result.SetStatus(eReturnStatusSuccessFinishNoResult);1140    }1141  }1142};1143 1144class CommandObjectFrameRecognizerInfo : public CommandObjectParsed {1145public:1146  CommandObjectFrameRecognizerInfo(CommandInterpreter &interpreter)1147      : CommandObjectParsed(1148            interpreter, "frame recognizer info",1149            "Show which frame recognizer is applied a stack frame (if any).",1150            nullptr) {1151    AddSimpleArgumentList(eArgTypeFrameIndex);1152  }1153 1154  ~CommandObjectFrameRecognizerInfo() override = default;1155 1156protected:1157  void DoExecute(Args &command, CommandReturnObject &result) override {1158    const char *frame_index_str = command.GetArgumentAtIndex(0);1159    uint32_t frame_index;1160    if (!llvm::to_integer(frame_index_str, frame_index)) {1161      result.AppendErrorWithFormat("'%s' is not a valid frame index.",1162                                   frame_index_str);1163      return;1164    }1165 1166    Process *process = m_exe_ctx.GetProcessPtr();1167    if (process == nullptr) {1168      result.AppendError("no process");1169      return;1170    }1171    Thread *thread = m_exe_ctx.GetThreadPtr();1172    if (thread == nullptr) {1173      result.AppendError("no thread");1174      return;1175    }1176    if (command.GetArgumentCount() != 1) {1177      result.AppendErrorWithFormat(1178          "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str());1179      return;1180    }1181 1182    StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index);1183    if (!frame_sp) {1184      result.AppendErrorWithFormat("no frame with index %u", frame_index);1185      return;1186    }1187 1188    auto recognizer =1189        GetTarget().GetFrameRecognizerManager().GetRecognizerForFrame(frame_sp);1190 1191    Stream &output_stream = result.GetOutputStream();1192    output_stream.Printf("frame %d ", frame_index);1193    if (recognizer) {1194      output_stream << "is recognized by ";1195      output_stream << recognizer->GetName();1196    } else {1197      output_stream << "not recognized by any recognizer";1198    }1199    output_stream.EOL();1200    result.SetStatus(eReturnStatusSuccessFinishResult);1201  }1202};1203 1204class CommandObjectFrameRecognizer : public CommandObjectMultiword {1205public:1206  CommandObjectFrameRecognizer(CommandInterpreter &interpreter)1207      : CommandObjectMultiword(1208            interpreter, "frame recognizer",1209            "Commands for editing and viewing frame recognizers.",1210            "frame recognizer [<sub-command-options>] ") {1211    LoadSubCommand("info", CommandObjectSP(new CommandObjectFrameRecognizerInfo(1212                               interpreter)));1213    LoadSubCommand("list", CommandObjectSP(new CommandObjectFrameRecognizerList(1214                               interpreter)));1215    LoadSubCommand("add", CommandObjectSP(new CommandObjectFrameRecognizerAdd(1216                              interpreter)));1217    LoadSubCommand(1218        "enable",1219        CommandObjectSP(new CommandObjectFrameRecognizerEnable(interpreter)));1220    LoadSubCommand(1221        "disable",1222        CommandObjectSP(new CommandObjectFrameRecognizerDisable(interpreter)));1223    LoadSubCommand(1224        "delete",1225        CommandObjectSP(new CommandObjectFrameRecognizerDelete(interpreter)));1226    LoadSubCommand(1227        "clear",1228        CommandObjectSP(new CommandObjectFrameRecognizerClear(interpreter)));1229  }1230 1231  ~CommandObjectFrameRecognizer() override = default;1232};1233 1234#pragma mark CommandObjectMultiwordFrame1235 1236// CommandObjectMultiwordFrame1237 1238CommandObjectMultiwordFrame::CommandObjectMultiwordFrame(1239    CommandInterpreter &interpreter)1240    : CommandObjectMultiword(interpreter, "frame",1241                             "Commands for selecting and "1242                             "examining the current "1243                             "thread's stack frames.",1244                             "frame <subcommand> [<subcommand-options>]") {1245  LoadSubCommand("diagnose",1246                 CommandObjectSP(new CommandObjectFrameDiagnose(interpreter)));1247  LoadSubCommand("info",1248                 CommandObjectSP(new CommandObjectFrameInfo(interpreter)));1249  LoadSubCommand("select",1250                 CommandObjectSP(new CommandObjectFrameSelect(interpreter)));1251  LoadSubCommand("variable",1252                 CommandObjectSP(new CommandObjectFrameVariable(interpreter)));1253#if LLDB_ENABLE_PYTHON1254  LoadSubCommand("recognizer", CommandObjectSP(new CommandObjectFrameRecognizer(1255                                   interpreter)));1256#endif1257}1258 1259CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default;1260