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-exception
6//
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 or
23/// 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(variablesReference: var_ref)) {
36 // variablesReference is one of our scopes, not an actual variable it is
37 // 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 first
43 // register set to be the lldb::eFormatAddressInfo so we show the pointer
44 // and resolve what the pointer resolves to. Only change the format if the
45 // format was set to the default format or if it was hex as some registers
46 // have formats set for them.
47 const uint32_t addr_size = dap.target.GetProcess().GetAddressByteSize();
48 lldb::SBValue reg_set = dap.variables.registers.GetValueAtIndex(idx: 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(idx: 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't
63 // have locals. If we have an error display it as the sole value in the
64 // the locals.
65
66 // "error" owns the error string so we must keep it alive as long as we
67 // 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 were
72 // not available. This new error will help let users know when there was
73 // a problem that kept variables from being available for display and
74 // allow users to fix this issue instead of seeing no variables. The
75 // errors are only set when there is a problem that the user could
76 // fix, so no error will show up when you have no debug info, only when
77 // 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(args&: 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 duplicated
88 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(idx: i);
91 if (!variable.IsValid())
92 break;
93 variable_name_counts[GetNonNullVariableName(value&: 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(new_name: "(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(variable: stop_return_value,
110 /*is_permanent=*/false);
111 }
112 variables.emplace_back(args: CreateVariable(
113 v: renamed_return_value, var_ref: return_var_ref, format_hex: hex,
114 auto_variable_summaries: dap.configuration.enableAutoVariableSummaries,
115 synthetic_child_debugging: dap.configuration.enableSyntheticChildDebugging, is_name_duplicated: false));
116 }
117 }
118
119 // Now we construct the result with unique display variable names
120 for (auto i = start_idx; i < end_idx; ++i) {
121 lldb::SBValue variable = top_scope->GetValueAtIndex(idx: 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(args: CreateVariable(
129 v: variable, var_ref: frame_var_ref, format_hex: hex,
130 auto_variable_summaries: dap.configuration.enableAutoVariableSummaries,
131 synthetic_child_debugging: dap.configuration.enableSyntheticChildDebugging,
132 is_name_duplicated: variable_name_counts[GetNonNullVariableName(value&: variable)] > 1));
133 }
134 } else {
135 // We are expanding a variable that has children, so we will return its
136 // 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(variable: child, is_permanent);
147 variables.emplace_back(
148 args: CreateVariable(v: child, var_ref: child_var_ref, format_hex: hex,
149 auto_variable_summaries: dap.configuration.enableAutoVariableSummaries,
150 synthetic_child_debugging: 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(idx: i));
158
159 // If we haven't filled the count quota from the request, we insert a new
160 // "[raw]" child that can be used to inspect the raw version of a
161 // synthetic member. That eliminates the need for the user to go to the
162 // 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: variables};
170}
171
172} // namespace lldb_dap
173

source code of lldb/tools/lldb-dap/Handler/VariablesRequestHandler.cpp