xref: /freebsd/contrib/llvm-project/lldb/source/ValueObject/DILEval.cpp (revision e64bea71c21eb42e97aa615188ba91f6cce0d36d)
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 
20 namespace lldb_private::dil {
21 
DILFindVariable(ConstString name,VariableList & variable_list)22 static 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("::");
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(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 
LookupGlobalIdentifier(llvm::StringRef name_ref,std::shared_ptr<StackFrame> stack_frame,lldb::TargetSP target_sp,lldb::DynamicValueType use_dynamic)47 lldb::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(lldb::eSymbolContextCompUnit);
53   lldb::VariableListSP variable_list;
54   if (symbol_context.comp_unit)
55     variable_list = symbol_context.comp_unit->GetVariableList(true);
56 
57   name_ref.consume_front("::");
58   lldb::ValueObjectSP value_sp;
59   if (variable_list) {
60     lldb::VariableSP var_sp =
61         DILFindVariable(ConstString(name_ref), *variable_list);
62     if (var_sp)
63       value_sp =
64           stack_frame->GetValueObjectForFrameVariable(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       ConstString(name_ref), std::numeric_limits<uint32_t>::max(),
74       modules_var_list);
75 
76   if (!modules_var_list.Empty()) {
77     lldb::VariableSP var_sp =
78         DILFindVariable(ConstString(name_ref), modules_var_list);
79     if (var_sp)
80       value_sp = ValueObjectVariable::Create(stack_frame.get(), var_sp);
81 
82     if (value_sp)
83       return value_sp;
84   }
85   return nullptr;
86 }
87 
LookupIdentifier(llvm::StringRef name_ref,std::shared_ptr<StackFrame> stack_frame,lldb::DynamicValueType use_dynamic)88 lldb::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("$")) {
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(name_ref))
99       return ValueObjectRegister::Create(stack_frame.get(), reg_ctx, reg_info);
100 
101     return nullptr;
102   }
103 
104   if (!name_ref.contains("::")) {
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(false));
109 
110     lldb::ValueObjectSP value_sp;
111     if (variable_list) {
112       lldb::VariableSP var_sp =
113           variable_list->FindVariable(ConstString(name_ref));
114       if (var_sp)
115         value_sp =
116             stack_frame->GetValueObjectForFrameVariable(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         lldb::eSymbolContextFunction | lldb::eSymbolContextBlock);
125     llvm::StringRef ivar_name = sc.GetInstanceVariableName();
126     value_sp = stack_frame->FindVariable(ConstString(ivar_name));
127     if (value_sp)
128       value_sp = value_sp->GetChildMemberWithName(name_ref);
129 
130     if (value_sp)
131       return value_sp;
132   }
133   return nullptr;
134 }
135 
Interpreter(lldb::TargetSP target,llvm::StringRef expr,std::shared_ptr<StackFrame> frame_sp,lldb::DynamicValueType use_dynamic,bool use_synthetic,bool fragile_ivar,bool check_ptr_vs_member)136 Interpreter::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 
Evaluate(const ASTNode * node)145 llvm::Expected<lldb::ValueObjectSP> Interpreter::Evaluate(const ASTNode *node) {
146   // Evaluate an AST.
147   auto value_or_error = node->Accept(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 
153 llvm::Expected<lldb::ValueObjectSP>
Visit(const IdentifierNode * node)154 Interpreter::Visit(const IdentifierNode *node) {
155   lldb::DynamicValueType use_dynamic = m_use_dynamic;
156 
157   lldb::ValueObjectSP identifier =
158       LookupIdentifier(node->GetName(), m_exe_ctx_scope, use_dynamic);
159 
160   if (!identifier)
161     identifier = LookupGlobalIdentifier(node->GetName(), m_exe_ctx_scope,
162                                         m_target, use_dynamic);
163   if (!identifier) {
164     std::string errMsg =
165         llvm::formatv("use of undeclared identifier '{0}'", node->GetName());
166     return llvm::make_error<DILDiagnosticError>(
167         m_expr, errMsg, node->GetLocation(), node->GetName().size());
168   }
169 
170   return identifier;
171 }
172 
173 llvm::Expected<lldb::ValueObjectSP>
Visit(const UnaryOpNode * node)174 Interpreter::Visit(const UnaryOpNode *node) {
175   Status error;
176   auto rhs_or_err = Evaluate(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(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>(m_expr, error.AsCString(),
197                                                   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>(m_expr, error.AsCString(),
206                                                   node->GetLocation());
207 
208     return value;
209   }
210   }
211 
212   // Unsupported/invalid operation.
213   return llvm::make_error<DILDiagnosticError>(
214       m_expr, "invalid ast: unexpected binary operator", node->GetLocation());
215 }
216 
217 llvm::Expected<lldb::ValueObjectSP>
Visit(const MemberOfNode * node)218 Interpreter::Visit(const MemberOfNode *node) {
219   auto base_or_err = Evaluate(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(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(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             "Failed to dereference synthetic value: {0}", deref_error);
252         return llvm::make_error<DILDiagnosticError>(
253             m_expr, errMsg, node->GetLocation(), 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             m_expr, errMsg, node->GetLocation(), 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("member reference type {0} is a pointer; "
273                           "did you mean to use '->'?",
274                           base->GetCompilerType().TypeDescription());
275         return llvm::make_error<DILDiagnosticError>(
276             m_expr, errMsg, node->GetLocation(), node->GetFieldName().size());
277       } else {
278         std::string errMsg =
279             llvm::formatv("member reference type {0} is not a pointer; "
280                           "did you mean to use '.'?",
281                           base->GetCompilerType().TypeDescription());
282         return llvm::make_error<DILDiagnosticError>(
283             m_expr, errMsg, node->GetLocation(), node->GetFieldName().size());
284       }
285     }
286   }
287 
288   lldb::ValueObjectSP field_obj =
289       base->GetChildMemberWithName(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(node->GetFieldName());
295     }
296 
297     if (!m_use_synthetic || !field_obj) {
298       std::string errMsg = llvm::formatv(
299           "\"{0}\" is not a member of \"({1}) {2}\"", node->GetFieldName(),
300           base->GetTypeName().AsCString("<invalid type>"), base->GetName());
301       return llvm::make_error<DILDiagnosticError>(
302           m_expr, errMsg, node->GetLocation(), 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(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       "\"{0}\" is not a member of \"({1}) {2}\"", node->GetFieldName(),
321       base->GetTypeName().AsCString("<invalid type>"), base->GetName());
322   return llvm::make_error<DILDiagnosticError>(
323       m_expr, errMsg, node->GetLocation(), node->GetFieldName().size());
324 }
325 
326 llvm::Expected<lldb::ValueObjectSP>
Visit(const ArraySubscriptNode * node)327 Interpreter::Visit(const ArraySubscriptNode *node) {
328   auto lhs_or_err = Evaluate(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(child_idx + 1);
338     if (!num_children)
339       return llvm::make_error<DILDiagnosticError>(
340           m_expr, toString(num_children.takeError()), node->GetLocation());
341     if (child_idx >= *num_children) {
342       std::string message = llvm::formatv(
343           "array index {0} is not valid for \"({1}) {2}\"", child_idx,
344           base->GetTypeName().AsCString("<invalid type>"),
345           base->GetName().AsCString());
346       return llvm::make_error<DILDiagnosticError>(m_expr, message,
347                                                   node->GetLocation());
348     }
349     if (lldb::ValueObjectSP child_valobj_sp =
350             synthetic->GetChildAtIndex(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         m_expr, "subscripted value is not an array or pointer",
358         node->GetLocation());
359   if (base_type.IsPointerToVoid())
360     return llvm::make_error<DILDiagnosticError>(
361         m_expr, "subscript of pointer to incomplete type 'void'",
362         node->GetLocation());
363 
364   if (base_type.IsArrayType()) {
365     if (lldb::ValueObjectSP child_valobj_sp = base->GetChildAtIndex(child_idx))
366       return child_valobj_sp;
367   }
368 
369   int64_t signed_child_idx = node->GetIndex();
370   return base->GetSyntheticArrayMember(signed_child_idx, true);
371 }
372 
373 llvm::Expected<lldb::ValueObjectSP>
Visit(const BitFieldExtractionNode * node)374 Interpreter::Visit(const BitFieldExtractionNode *node) {
375   auto lhs_or_err = Evaluate(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(first_index, 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(first_index, last_index, true);
394   if (!child_valobj_sp) {
395     std::string message = llvm::formatv(
396         "bitfield range {0}-{1} is not valid for \"({2}) {3}\"", first_index,
397         last_index, base->GetTypeName().AsCString("<invalid type>"),
398         base->GetName().AsCString());
399     return llvm::make_error<DILDiagnosticError>(m_expr, message,
400                                                 node->GetLocation());
401   }
402   return child_valobj_sp;
403 }
404 
405 } // namespace lldb_private::dil
406