brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.2 KiB · 5fa2b1e Raw
173 lines · cpp
1//===-- VariablesRequestHandler.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 9#include "DAP.h"10#include "EventHelper.h"11#include "Handler/RequestHandler.h"12#include "JSONUtils.h"13#include "ProtocolUtils.h"14 15using namespace llvm;16using namespace lldb_dap::protocol;17 18namespace lldb_dap {19 20/// Retrieves all child variables for the given variable reference.21///22/// A filter can be used to limit the fetched children to either named or23/// indexed children.24Expected<VariablesResponseBody>25VariablesRequestHandler::Run(const VariablesArguments &arguments) const {26  const uint64_t var_ref = arguments.variablesReference;27  const uint64_t count = arguments.count;28  const uint64_t start = arguments.start;29  bool hex = false;30  if (arguments.format)31    hex = arguments.format->hex;32 33  std::vector<Variable> variables;34 35  if (lldb::SBValueList *top_scope = dap.variables.GetTopLevelScope(var_ref)) {36    // variablesReference is one of our scopes, not an actual variable it is37    // asking for the list of args, locals or globals.38    int64_t start_idx = 0;39    int64_t num_children = 0;40 41    if (var_ref == VARREF_REGS) {42      // Change the default format of any pointer sized registers in the first43      // register set to be the lldb::eFormatAddressInfo so we show the pointer44      // and resolve what the pointer resolves to. Only change the format if the45      // format was set to the default format or if it was hex as some registers46      // have formats set for them.47      const uint32_t addr_size = dap.target.GetProcess().GetAddressByteSize();48      lldb::SBValue reg_set = dap.variables.registers.GetValueAtIndex(0);49      const uint32_t num_regs = reg_set.GetNumChildren();50      for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx) {51        lldb::SBValue reg = reg_set.GetChildAtIndex(reg_idx);52        const lldb::Format format = reg.GetFormat();53        if (format == lldb::eFormatDefault || format == lldb::eFormatHex) {54          if (reg.GetByteSize() == addr_size)55            reg.SetFormat(lldb::eFormatAddressInfo);56        }57      }58    }59 60    num_children = top_scope->GetSize();61    if (num_children == 0 && var_ref == VARREF_LOCALS) {62      // Check for an error in the SBValueList that might explain why we don't63      // have locals. If we have an error display it as the sole value in the64      // the locals.65 66      // "error" owns the error string so we must keep it alive as long as we67      // want to use the returns "const char *"68      lldb::SBError error = top_scope->GetError();69      const char *var_err = error.GetCString();70      if (var_err) {71        // Create a fake variable named "error" to explain why variables were72        // not available. This new error will help let users know when there was73        // a problem that kept variables from being available for display and74        // allow users to fix this issue instead of seeing no variables. The75        // errors are only set when there is a problem that the user could76        // fix, so no error will show up when you have no debug info, only when77        // we do have debug info and something that is fixable can be done.78        Variable var;79        var.name = "<error>";80        var.type = "const char *";81        var.value = var_err;82        variables.emplace_back(var);83      }84    }85    const int64_t end_idx = start_idx + ((count == 0) ? num_children : count);86 87    // We first find out which variable names are duplicated88    std::map<std::string, int> variable_name_counts;89    for (auto i = start_idx; i < end_idx; ++i) {90      lldb::SBValue variable = top_scope->GetValueAtIndex(i);91      if (!variable.IsValid())92        break;93      variable_name_counts[GetNonNullVariableName(variable)]++;94    }95 96    // Show return value if there is any ( in the local top frame )97    if (var_ref == VARREF_LOCALS) {98      auto process = dap.target.GetProcess();99      auto selected_thread = process.GetSelectedThread();100      lldb::SBValue stop_return_value = selected_thread.GetStopReturnValue();101 102      if (stop_return_value.IsValid() &&103          (selected_thread.GetSelectedFrame().GetFrameID() == 0)) {104        auto renamed_return_value = stop_return_value.Clone("(Return Value)");105        int64_t return_var_ref = 0;106 107        if (stop_return_value.MightHaveChildren() ||108            stop_return_value.IsSynthetic()) {109          return_var_ref = dap.variables.InsertVariable(stop_return_value,110                                                        /*is_permanent=*/false);111        }112        variables.emplace_back(CreateVariable(113            renamed_return_value, return_var_ref, hex,114            dap.configuration.enableAutoVariableSummaries,115            dap.configuration.enableSyntheticChildDebugging, false));116      }117    }118 119    // Now we construct the result with unique display variable names120    for (auto i = start_idx; i < end_idx; ++i) {121      lldb::SBValue variable = top_scope->GetValueAtIndex(i);122 123      if (!variable.IsValid())124        break;125 126      const int64_t frame_var_ref =127          dap.variables.InsertVariable(variable, /*is_permanent=*/false);128      variables.emplace_back(CreateVariable(129          variable, frame_var_ref, hex,130          dap.configuration.enableAutoVariableSummaries,131          dap.configuration.enableSyntheticChildDebugging,132          variable_name_counts[GetNonNullVariableName(variable)] > 1));133    }134  } else {135    // We are expanding a variable that has children, so we will return its136    // children.137    lldb::SBValue variable = dap.variables.GetVariable(var_ref);138    if (variable.IsValid()) {139      const bool is_permanent =140          dap.variables.IsPermanentVariableReference(var_ref);141      auto addChild = [&](lldb::SBValue child,142                          std::optional<std::string> custom_name = {}) {143        if (!child.IsValid())144          return;145        const int64_t child_var_ref =146            dap.variables.InsertVariable(child, is_permanent);147        variables.emplace_back(148            CreateVariable(child, child_var_ref, hex,149                           dap.configuration.enableAutoVariableSummaries,150                           dap.configuration.enableSyntheticChildDebugging,151                           /*is_name_duplicated=*/false, custom_name));152      };153      const int64_t num_children = variable.GetNumChildren();154      const int64_t end_idx = start + ((count == 0) ? num_children : count);155      int64_t i = start;156      for (; i < end_idx && i < num_children; ++i)157        addChild(variable.GetChildAtIndex(i));158 159      // If we haven't filled the count quota from the request, we insert a new160      // "[raw]" child that can be used to inspect the raw version of a161      // synthetic member. That eliminates the need for the user to go to the162      // debug console and type `frame var <variable> to get these values.163      if (dap.configuration.enableSyntheticChildDebugging &&164          variable.IsSynthetic() && i == num_children)165        addChild(variable.GetNonSyntheticValue(), "[raw]");166    }167  }168 169  return VariablesResponseBody{variables};170}171 172} // namespace lldb_dap173