1//===-- DILEval.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 "lldb/ValueObject/DILEval.h"
10#include "lldb/Symbol/CompileUnit.h"
11#include "lldb/Symbol/VariableList.h"
12#include "lldb/Target/RegisterContext.h"
13#include "lldb/ValueObject/DILAST.h"
14#include "lldb/ValueObject/ValueObject.h"
15#include "lldb/ValueObject/ValueObjectRegister.h"
16#include "lldb/ValueObject/ValueObjectVariable.h"
17#include "llvm/Support/FormatAdapters.h"
18#include <memory>
19
20namespace lldb_private::dil {
21
22static lldb::VariableSP DILFindVariable(ConstString name,
23 VariableList &variable_list) {
24 lldb::VariableSP exact_match;
25 std::vector<lldb::VariableSP> possible_matches;
26
27 for (lldb::VariableSP var_sp : variable_list) {
28 llvm::StringRef str_ref_name = var_sp->GetName().GetStringRef();
29
30 str_ref_name.consume_front(Prefix: "::");
31 // Check for the exact same match
32 if (str_ref_name == name.GetStringRef())
33 return var_sp;
34
35 // Check for possible matches by base name
36 if (var_sp->NameMatches(name))
37 possible_matches.push_back(x: var_sp);
38 }
39
40 // If there's a non-exact match, take it.
41 if (possible_matches.size() > 0)
42 return possible_matches[0];
43
44 return nullptr;
45}
46
47lldb::ValueObjectSP LookupGlobalIdentifier(
48 llvm::StringRef name_ref, std::shared_ptr<StackFrame> stack_frame,
49 lldb::TargetSP target_sp, lldb::DynamicValueType use_dynamic) {
50 // Get a global variables list without the locals from the current frame
51 SymbolContext symbol_context =
52 stack_frame->GetSymbolContext(resolve_scope: lldb::eSymbolContextCompUnit);
53 lldb::VariableListSP variable_list;
54 if (symbol_context.comp_unit)
55 variable_list = symbol_context.comp_unit->GetVariableList(can_create: true);
56
57 name_ref.consume_front(Prefix: "::");
58 lldb::ValueObjectSP value_sp;
59 if (variable_list) {
60 lldb::VariableSP var_sp =
61 DILFindVariable(name: ConstString(name_ref), variable_list&: *variable_list);
62 if (var_sp)
63 value_sp =
64 stack_frame->GetValueObjectForFrameVariable(variable_sp: var_sp, use_dynamic);
65 }
66
67 if (value_sp)
68 return value_sp;
69
70 // Check for match in modules global variables.
71 VariableList modules_var_list;
72 target_sp->GetImages().FindGlobalVariables(
73 name: ConstString(name_ref), max_matches: std::numeric_limits<uint32_t>::max(),
74 variable_list&: modules_var_list);
75
76 if (!modules_var_list.Empty()) {
77 lldb::VariableSP var_sp =
78 DILFindVariable(name: ConstString(name_ref), variable_list&: modules_var_list);
79 if (var_sp)
80 value_sp = ValueObjectVariable::Create(exe_scope: stack_frame.get(), var_sp);
81
82 if (value_sp)
83 return value_sp;
84 }
85 return nullptr;
86}
87
88lldb::ValueObjectSP LookupIdentifier(llvm::StringRef name_ref,
89 std::shared_ptr<StackFrame> stack_frame,
90 lldb::DynamicValueType use_dynamic) {
91 // Support $rax as a special syntax for accessing registers.
92 // Will return an invalid value in case the requested register doesn't exist.
93 if (name_ref.consume_front(Prefix: "$")) {
94 lldb::RegisterContextSP reg_ctx(stack_frame->GetRegisterContext());
95 if (!reg_ctx)
96 return nullptr;
97
98 if (const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name: name_ref))
99 return ValueObjectRegister::Create(exe_scope: stack_frame.get(), reg_ctx_sp&: reg_ctx, reg_info);
100
101 return nullptr;
102 }
103
104 if (!name_ref.contains(Other: "::")) {
105 // Lookup in the current frame.
106 // Try looking for a local variable in current scope.
107 lldb::VariableListSP variable_list(
108 stack_frame->GetInScopeVariableList(get_file_globals: false));
109
110 lldb::ValueObjectSP value_sp;
111 if (variable_list) {
112 lldb::VariableSP var_sp =
113 variable_list->FindVariable(name: ConstString(name_ref));
114 if (var_sp)
115 value_sp =
116 stack_frame->GetValueObjectForFrameVariable(variable_sp: var_sp, use_dynamic);
117 }
118
119 if (value_sp)
120 return value_sp;
121
122 // Try looking for an instance variable (class member).
123 SymbolContext sc = stack_frame->GetSymbolContext(
124 resolve_scope: lldb::eSymbolContextFunction | lldb::eSymbolContextBlock);
125 llvm::StringRef ivar_name = sc.GetInstanceVariableName();
126 value_sp = stack_frame->FindVariable(name: ConstString(ivar_name));
127 if (value_sp)
128 value_sp = value_sp->GetChildMemberWithName(name: name_ref);
129
130 if (value_sp)
131 return value_sp;
132 }
133 return nullptr;
134}
135
136Interpreter::Interpreter(lldb::TargetSP target, llvm::StringRef expr,
137 std::shared_ptr<StackFrame> frame_sp,
138 lldb::DynamicValueType use_dynamic, bool use_synthetic,
139 bool fragile_ivar, bool check_ptr_vs_member)
140 : m_target(std::move(target)), m_expr(expr), m_exe_ctx_scope(frame_sp),
141 m_use_dynamic(use_dynamic), m_use_synthetic(use_synthetic),
142 m_fragile_ivar(fragile_ivar), m_check_ptr_vs_member(check_ptr_vs_member) {
143}
144
145llvm::Expected<lldb::ValueObjectSP> Interpreter::Evaluate(const ASTNode *node) {
146 // Evaluate an AST.
147 auto value_or_error = node->Accept(v: this);
148 // Return the computed value-or-error. The caller is responsible for
149 // checking if an error occured during the evaluation.
150 return value_or_error;
151}
152
153llvm::Expected<lldb::ValueObjectSP>
154Interpreter::Visit(const IdentifierNode *node) {
155 lldb::DynamicValueType use_dynamic = m_use_dynamic;
156
157 lldb::ValueObjectSP identifier =
158 LookupIdentifier(name_ref: node->GetName(), stack_frame: m_exe_ctx_scope, use_dynamic);
159
160 if (!identifier)
161 identifier = LookupGlobalIdentifier(name_ref: node->GetName(), stack_frame: m_exe_ctx_scope,
162 target_sp: m_target, use_dynamic);
163 if (!identifier) {
164 std::string errMsg =
165 llvm::formatv(Fmt: "use of undeclared identifier '{0}'", Vals: node->GetName());
166 return llvm::make_error<DILDiagnosticError>(
167 Args&: m_expr, Args&: errMsg, Args: node->GetLocation(), Args: node->GetName().size());
168 }
169
170 return identifier;
171}
172
173llvm::Expected<lldb::ValueObjectSP>
174Interpreter::Visit(const UnaryOpNode *node) {
175 Status error;
176 auto rhs_or_err = Evaluate(node: node->GetOperand());
177 if (!rhs_or_err)
178 return rhs_or_err;
179
180 lldb::ValueObjectSP rhs = *rhs_or_err;
181
182 switch (node->GetKind()) {
183 case UnaryOpKind::Deref: {
184 lldb::ValueObjectSP dynamic_rhs = rhs->GetDynamicValue(valueType: m_use_dynamic);
185 if (dynamic_rhs)
186 rhs = dynamic_rhs;
187
188 lldb::ValueObjectSP child_sp = rhs->Dereference(error);
189 if (!child_sp && m_use_synthetic) {
190 if (lldb::ValueObjectSP synth_obj_sp = rhs->GetSyntheticValue()) {
191 error.Clear();
192 child_sp = synth_obj_sp->Dereference(error);
193 }
194 }
195 if (error.Fail())
196 return llvm::make_error<DILDiagnosticError>(Args&: m_expr, Args: error.AsCString(),
197 Args: node->GetLocation());
198
199 return child_sp;
200 }
201 case UnaryOpKind::AddrOf: {
202 Status error;
203 lldb::ValueObjectSP value = rhs->AddressOf(error);
204 if (error.Fail())
205 return llvm::make_error<DILDiagnosticError>(Args&: m_expr, Args: error.AsCString(),
206 Args: node->GetLocation());
207
208 return value;
209 }
210 }
211
212 // Unsupported/invalid operation.
213 return llvm::make_error<DILDiagnosticError>(
214 Args&: m_expr, Args: "invalid ast: unexpected binary operator", Args: node->GetLocation());
215}
216
217llvm::Expected<lldb::ValueObjectSP>
218Interpreter::Visit(const MemberOfNode *node) {
219 auto base_or_err = Evaluate(node: node->GetBase());
220 if (!base_or_err)
221 return base_or_err;
222 bool expr_is_ptr = node->GetIsArrow();
223 lldb::ValueObjectSP base = *base_or_err;
224
225 // Perform some basic type & correctness checking.
226 if (node->GetIsArrow()) {
227 if (!m_fragile_ivar) {
228 // Make sure we aren't trying to deref an objective
229 // C ivar if this is not allowed
230 const uint32_t pointer_type_flags =
231 base->GetCompilerType().GetTypeInfo(pointee_or_element_compiler_type: nullptr);
232 if ((pointer_type_flags & lldb::eTypeIsObjC) &&
233 (pointer_type_flags & lldb::eTypeIsPointer)) {
234 // This was an objective C object pointer and it was requested we
235 // skip any fragile ivars so return nothing here
236 return lldb::ValueObjectSP();
237 }
238 }
239
240 // If we have a non-pointer type with a synthetic value then lets check
241 // if we have a synthetic dereference specified.
242 if (!base->IsPointerType() && base->HasSyntheticValue()) {
243 Status deref_error;
244 if (lldb::ValueObjectSP synth_deref_sp =
245 base->GetSyntheticValue()->Dereference(error&: deref_error);
246 synth_deref_sp && deref_error.Success()) {
247 base = std::move(synth_deref_sp);
248 }
249 if (!base || deref_error.Fail()) {
250 std::string errMsg = llvm::formatv(
251 Fmt: "Failed to dereference synthetic value: {0}", Vals&: deref_error);
252 return llvm::make_error<DILDiagnosticError>(
253 Args&: m_expr, Args&: errMsg, Args: node->GetLocation(), Args: node->GetFieldName().size());
254 }
255
256 // Some synthetic plug-ins fail to set the error in Dereference
257 if (!base) {
258 std::string errMsg = "Failed to dereference synthetic value";
259 return llvm::make_error<DILDiagnosticError>(
260 Args&: m_expr, Args&: errMsg, Args: node->GetLocation(), Args: node->GetFieldName().size());
261 }
262 expr_is_ptr = false;
263 }
264 }
265
266 if (m_check_ptr_vs_member) {
267 bool base_is_ptr = base->IsPointerType();
268
269 if (expr_is_ptr != base_is_ptr) {
270 if (base_is_ptr) {
271 std::string errMsg =
272 llvm::formatv(Fmt: "member reference type {0} is a pointer; "
273 "did you mean to use '->'?",
274 Vals: base->GetCompilerType().TypeDescription());
275 return llvm::make_error<DILDiagnosticError>(
276 Args&: m_expr, Args&: errMsg, Args: node->GetLocation(), Args: node->GetFieldName().size());
277 } else {
278 std::string errMsg =
279 llvm::formatv(Fmt: "member reference type {0} is not a pointer; "
280 "did you mean to use '.'?",
281 Vals: base->GetCompilerType().TypeDescription());
282 return llvm::make_error<DILDiagnosticError>(
283 Args&: m_expr, Args&: errMsg, Args: node->GetLocation(), Args: node->GetFieldName().size());
284 }
285 }
286 }
287
288 lldb::ValueObjectSP field_obj =
289 base->GetChildMemberWithName(name: node->GetFieldName());
290 if (!field_obj) {
291 if (m_use_synthetic) {
292 field_obj = base->GetSyntheticValue();
293 if (field_obj)
294 field_obj = field_obj->GetChildMemberWithName(name: node->GetFieldName());
295 }
296
297 if (!m_use_synthetic || !field_obj) {
298 std::string errMsg = llvm::formatv(
299 Fmt: "\"{0}\" is not a member of \"({1}) {2}\"", Vals: node->GetFieldName(),
300 Vals: base->GetTypeName().AsCString(value_if_empty: "<invalid type>"), Vals: base->GetName());
301 return llvm::make_error<DILDiagnosticError>(
302 Args&: m_expr, Args&: errMsg, Args: node->GetLocation(), Args: node->GetFieldName().size());
303 }
304 }
305
306 if (field_obj) {
307 if (m_use_dynamic != lldb::eNoDynamicValues) {
308 lldb::ValueObjectSP dynamic_val_sp =
309 field_obj->GetDynamicValue(valueType: m_use_dynamic);
310 if (dynamic_val_sp)
311 field_obj = dynamic_val_sp;
312 }
313 return field_obj;
314 }
315
316 CompilerType base_type = base->GetCompilerType();
317 if (node->GetIsArrow() && base->IsPointerType())
318 base_type = base_type.GetPointeeType();
319 std::string errMsg = llvm::formatv(
320 Fmt: "\"{0}\" is not a member of \"({1}) {2}\"", Vals: node->GetFieldName(),
321 Vals: base->GetTypeName().AsCString(value_if_empty: "<invalid type>"), Vals: base->GetName());
322 return llvm::make_error<DILDiagnosticError>(
323 Args&: m_expr, Args&: errMsg, Args: node->GetLocation(), Args: node->GetFieldName().size());
324}
325
326llvm::Expected<lldb::ValueObjectSP>
327Interpreter::Visit(const ArraySubscriptNode *node) {
328 auto lhs_or_err = Evaluate(node: node->GetBase());
329 if (!lhs_or_err)
330 return lhs_or_err;
331 lldb::ValueObjectSP base = *lhs_or_err;
332
333 // Check to see if 'base' has a synthetic value; if so, try using that.
334 uint64_t child_idx = node->GetIndex();
335 if (lldb::ValueObjectSP synthetic = base->GetSyntheticValue()) {
336 llvm::Expected<uint32_t> num_children =
337 synthetic->GetNumChildren(max: child_idx + 1);
338 if (!num_children)
339 return llvm::make_error<DILDiagnosticError>(
340 Args&: m_expr, Args: toString(E: num_children.takeError()), Args: node->GetLocation());
341 if (child_idx >= *num_children) {
342 std::string message = llvm::formatv(
343 Fmt: "array index {0} is not valid for \"({1}) {2}\"", Vals&: child_idx,
344 Vals: base->GetTypeName().AsCString(value_if_empty: "<invalid type>"),
345 Vals: base->GetName().AsCString());
346 return llvm::make_error<DILDiagnosticError>(Args&: m_expr, Args&: message,
347 Args: node->GetLocation());
348 }
349 if (lldb::ValueObjectSP child_valobj_sp =
350 synthetic->GetChildAtIndex(idx: child_idx))
351 return child_valobj_sp;
352 }
353
354 auto base_type = base->GetCompilerType().GetNonReferenceType();
355 if (!base_type.IsPointerType() && !base_type.IsArrayType())
356 return llvm::make_error<DILDiagnosticError>(
357 Args&: m_expr, Args: "subscripted value is not an array or pointer",
358 Args: node->GetLocation());
359 if (base_type.IsPointerToVoid())
360 return llvm::make_error<DILDiagnosticError>(
361 Args&: m_expr, Args: "subscript of pointer to incomplete type 'void'",
362 Args: node->GetLocation());
363
364 if (base_type.IsArrayType()) {
365 if (lldb::ValueObjectSP child_valobj_sp = base->GetChildAtIndex(idx: child_idx))
366 return child_valobj_sp;
367 }
368
369 int64_t signed_child_idx = node->GetIndex();
370 return base->GetSyntheticArrayMember(index: signed_child_idx, can_create: true);
371}
372
373llvm::Expected<lldb::ValueObjectSP>
374Interpreter::Visit(const BitFieldExtractionNode *node) {
375 auto lhs_or_err = Evaluate(node: node->GetBase());
376 if (!lhs_or_err)
377 return lhs_or_err;
378 lldb::ValueObjectSP base = *lhs_or_err;
379 int64_t first_index = node->GetFirstIndex();
380 int64_t last_index = node->GetLastIndex();
381
382 // if the format given is [high-low], swap range
383 if (first_index > last_index)
384 std::swap(a&: first_index, b&: last_index);
385
386 Status error;
387 if (base->GetCompilerType().IsReferenceType()) {
388 base = base->Dereference(error);
389 if (error.Fail())
390 return error.ToError();
391 }
392 lldb::ValueObjectSP child_valobj_sp =
393 base->GetSyntheticBitFieldChild(from: first_index, to: last_index, can_create: true);
394 if (!child_valobj_sp) {
395 std::string message = llvm::formatv(
396 Fmt: "bitfield range {0}-{1} is not valid for \"({2}) {3}\"", Vals&: first_index,
397 Vals&: last_index, Vals: base->GetTypeName().AsCString(value_if_empty: "<invalid type>"),
398 Vals: base->GetName().AsCString());
399 return llvm::make_error<DILDiagnosticError>(Args&: m_expr, Args&: message,
400 Args: node->GetLocation());
401 }
402 return child_valobj_sp;
403}
404
405} // namespace lldb_private::dil
406

source code of lldb/source/ValueObject/DILEval.cpp