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

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