Path: blob/main/contrib/llvm-project/lldb/source/ValueObject/DILEval.cpp
213764 views
//===-- DILEval.cpp -------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "lldb/ValueObject/DILEval.h"9#include "lldb/Symbol/CompileUnit.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>1819namespace lldb_private::dil {2021static lldb::VariableSP DILFindVariable(ConstString name,22VariableList &variable_list) {23lldb::VariableSP exact_match;24std::vector<lldb::VariableSP> possible_matches;2526for (lldb::VariableSP var_sp : variable_list) {27llvm::StringRef str_ref_name = var_sp->GetName().GetStringRef();2829str_ref_name.consume_front("::");30// Check for the exact same match31if (str_ref_name == name.GetStringRef())32return var_sp;3334// Check for possible matches by base name35if (var_sp->NameMatches(name))36possible_matches.push_back(var_sp);37}3839// If there's a non-exact match, take it.40if (possible_matches.size() > 0)41return possible_matches[0];4243return nullptr;44}4546lldb::ValueObjectSP LookupGlobalIdentifier(47llvm::StringRef name_ref, std::shared_ptr<StackFrame> stack_frame,48lldb::TargetSP target_sp, lldb::DynamicValueType use_dynamic) {49// Get a global variables list without the locals from the current frame50SymbolContext symbol_context =51stack_frame->GetSymbolContext(lldb::eSymbolContextCompUnit);52lldb::VariableListSP variable_list;53if (symbol_context.comp_unit)54variable_list = symbol_context.comp_unit->GetVariableList(true);5556name_ref.consume_front("::");57lldb::ValueObjectSP value_sp;58if (variable_list) {59lldb::VariableSP var_sp =60DILFindVariable(ConstString(name_ref), *variable_list);61if (var_sp)62value_sp =63stack_frame->GetValueObjectForFrameVariable(var_sp, use_dynamic);64}6566if (value_sp)67return value_sp;6869// Check for match in modules global variables.70VariableList modules_var_list;71target_sp->GetImages().FindGlobalVariables(72ConstString(name_ref), std::numeric_limits<uint32_t>::max(),73modules_var_list);7475if (!modules_var_list.Empty()) {76lldb::VariableSP var_sp =77DILFindVariable(ConstString(name_ref), modules_var_list);78if (var_sp)79value_sp = ValueObjectVariable::Create(stack_frame.get(), var_sp);8081if (value_sp)82return value_sp;83}84return nullptr;85}8687lldb::ValueObjectSP LookupIdentifier(llvm::StringRef name_ref,88std::shared_ptr<StackFrame> stack_frame,89lldb::DynamicValueType use_dynamic) {90// Support $rax as a special syntax for accessing registers.91// Will return an invalid value in case the requested register doesn't exist.92if (name_ref.consume_front("$")) {93lldb::RegisterContextSP reg_ctx(stack_frame->GetRegisterContext());94if (!reg_ctx)95return nullptr;9697if (const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(name_ref))98return ValueObjectRegister::Create(stack_frame.get(), reg_ctx, reg_info);99100return nullptr;101}102103if (!name_ref.contains("::")) {104// Lookup in the current frame.105// Try looking for a local variable in current scope.106lldb::VariableListSP variable_list(107stack_frame->GetInScopeVariableList(false));108109lldb::ValueObjectSP value_sp;110if (variable_list) {111lldb::VariableSP var_sp =112variable_list->FindVariable(ConstString(name_ref));113if (var_sp)114value_sp =115stack_frame->GetValueObjectForFrameVariable(var_sp, use_dynamic);116}117118if (value_sp)119return value_sp;120121// Try looking for an instance variable (class member).122SymbolContext sc = stack_frame->GetSymbolContext(123lldb::eSymbolContextFunction | lldb::eSymbolContextBlock);124llvm::StringRef ivar_name = sc.GetInstanceVariableName();125value_sp = stack_frame->FindVariable(ConstString(ivar_name));126if (value_sp)127value_sp = value_sp->GetChildMemberWithName(name_ref);128129if (value_sp)130return value_sp;131}132return nullptr;133}134135Interpreter::Interpreter(lldb::TargetSP target, llvm::StringRef expr,136std::shared_ptr<StackFrame> frame_sp,137lldb::DynamicValueType use_dynamic, bool use_synthetic,138bool fragile_ivar, bool check_ptr_vs_member)139: m_target(std::move(target)), m_expr(expr), m_exe_ctx_scope(frame_sp),140m_use_dynamic(use_dynamic), m_use_synthetic(use_synthetic),141m_fragile_ivar(fragile_ivar), m_check_ptr_vs_member(check_ptr_vs_member) {142}143144llvm::Expected<lldb::ValueObjectSP> Interpreter::Evaluate(const ASTNode *node) {145// Evaluate an AST.146auto value_or_error = node->Accept(this);147// Return the computed value-or-error. The caller is responsible for148// checking if an error occured during the evaluation.149return value_or_error;150}151152llvm::Expected<lldb::ValueObjectSP>153Interpreter::Visit(const IdentifierNode *node) {154lldb::DynamicValueType use_dynamic = m_use_dynamic;155156lldb::ValueObjectSP identifier =157LookupIdentifier(node->GetName(), m_exe_ctx_scope, use_dynamic);158159if (!identifier)160identifier = LookupGlobalIdentifier(node->GetName(), m_exe_ctx_scope,161m_target, use_dynamic);162if (!identifier) {163std::string errMsg =164llvm::formatv("use of undeclared identifier '{0}'", node->GetName());165return llvm::make_error<DILDiagnosticError>(166m_expr, errMsg, node->GetLocation(), node->GetName().size());167}168169return identifier;170}171172llvm::Expected<lldb::ValueObjectSP>173Interpreter::Visit(const UnaryOpNode *node) {174Status error;175auto rhs_or_err = Evaluate(node->GetOperand());176if (!rhs_or_err)177return rhs_or_err;178179lldb::ValueObjectSP rhs = *rhs_or_err;180181switch (node->GetKind()) {182case UnaryOpKind::Deref: {183lldb::ValueObjectSP dynamic_rhs = rhs->GetDynamicValue(m_use_dynamic);184if (dynamic_rhs)185rhs = dynamic_rhs;186187lldb::ValueObjectSP child_sp = rhs->Dereference(error);188if (!child_sp && m_use_synthetic) {189if (lldb::ValueObjectSP synth_obj_sp = rhs->GetSyntheticValue()) {190error.Clear();191child_sp = synth_obj_sp->Dereference(error);192}193}194if (error.Fail())195return llvm::make_error<DILDiagnosticError>(m_expr, error.AsCString(),196node->GetLocation());197198return child_sp;199}200case UnaryOpKind::AddrOf: {201Status error;202lldb::ValueObjectSP value = rhs->AddressOf(error);203if (error.Fail())204return llvm::make_error<DILDiagnosticError>(m_expr, error.AsCString(),205node->GetLocation());206207return value;208}209}210211// Unsupported/invalid operation.212return llvm::make_error<DILDiagnosticError>(213m_expr, "invalid ast: unexpected binary operator", node->GetLocation());214}215216llvm::Expected<lldb::ValueObjectSP>217Interpreter::Visit(const MemberOfNode *node) {218auto base_or_err = Evaluate(node->GetBase());219if (!base_or_err)220return base_or_err;221bool expr_is_ptr = node->GetIsArrow();222lldb::ValueObjectSP base = *base_or_err;223224// Perform some basic type & correctness checking.225if (node->GetIsArrow()) {226if (!m_fragile_ivar) {227// Make sure we aren't trying to deref an objective228// C ivar if this is not allowed229const uint32_t pointer_type_flags =230base->GetCompilerType().GetTypeInfo(nullptr);231if ((pointer_type_flags & lldb::eTypeIsObjC) &&232(pointer_type_flags & lldb::eTypeIsPointer)) {233// This was an objective C object pointer and it was requested we234// skip any fragile ivars so return nothing here235return lldb::ValueObjectSP();236}237}238239// If we have a non-pointer type with a synthetic value then lets check240// if we have a synthetic dereference specified.241if (!base->IsPointerType() && base->HasSyntheticValue()) {242Status deref_error;243if (lldb::ValueObjectSP synth_deref_sp =244base->GetSyntheticValue()->Dereference(deref_error);245synth_deref_sp && deref_error.Success()) {246base = std::move(synth_deref_sp);247}248if (!base || deref_error.Fail()) {249std::string errMsg = llvm::formatv(250"Failed to dereference synthetic value: {0}", deref_error);251return llvm::make_error<DILDiagnosticError>(252m_expr, errMsg, node->GetLocation(), node->GetFieldName().size());253}254255// Some synthetic plug-ins fail to set the error in Dereference256if (!base) {257std::string errMsg = "Failed to dereference synthetic value";258return llvm::make_error<DILDiagnosticError>(259m_expr, errMsg, node->GetLocation(), node->GetFieldName().size());260}261expr_is_ptr = false;262}263}264265if (m_check_ptr_vs_member) {266bool base_is_ptr = base->IsPointerType();267268if (expr_is_ptr != base_is_ptr) {269if (base_is_ptr) {270std::string errMsg =271llvm::formatv("member reference type {0} is a pointer; "272"did you mean to use '->'?",273base->GetCompilerType().TypeDescription());274return llvm::make_error<DILDiagnosticError>(275m_expr, errMsg, node->GetLocation(), node->GetFieldName().size());276} else {277std::string errMsg =278llvm::formatv("member reference type {0} is not a pointer; "279"did you mean to use '.'?",280base->GetCompilerType().TypeDescription());281return llvm::make_error<DILDiagnosticError>(282m_expr, errMsg, node->GetLocation(), node->GetFieldName().size());283}284}285}286287lldb::ValueObjectSP field_obj =288base->GetChildMemberWithName(node->GetFieldName());289if (!field_obj) {290if (m_use_synthetic) {291field_obj = base->GetSyntheticValue();292if (field_obj)293field_obj = field_obj->GetChildMemberWithName(node->GetFieldName());294}295296if (!m_use_synthetic || !field_obj) {297std::string errMsg = llvm::formatv(298"\"{0}\" is not a member of \"({1}) {2}\"", node->GetFieldName(),299base->GetTypeName().AsCString("<invalid type>"), base->GetName());300return llvm::make_error<DILDiagnosticError>(301m_expr, errMsg, node->GetLocation(), node->GetFieldName().size());302}303}304305if (field_obj) {306if (m_use_dynamic != lldb::eNoDynamicValues) {307lldb::ValueObjectSP dynamic_val_sp =308field_obj->GetDynamicValue(m_use_dynamic);309if (dynamic_val_sp)310field_obj = dynamic_val_sp;311}312return field_obj;313}314315CompilerType base_type = base->GetCompilerType();316if (node->GetIsArrow() && base->IsPointerType())317base_type = base_type.GetPointeeType();318std::string errMsg = llvm::formatv(319"\"{0}\" is not a member of \"({1}) {2}\"", node->GetFieldName(),320base->GetTypeName().AsCString("<invalid type>"), base->GetName());321return llvm::make_error<DILDiagnosticError>(322m_expr, errMsg, node->GetLocation(), node->GetFieldName().size());323}324325llvm::Expected<lldb::ValueObjectSP>326Interpreter::Visit(const ArraySubscriptNode *node) {327auto lhs_or_err = Evaluate(node->GetBase());328if (!lhs_or_err)329return lhs_or_err;330lldb::ValueObjectSP base = *lhs_or_err;331332// Check to see if 'base' has a synthetic value; if so, try using that.333uint64_t child_idx = node->GetIndex();334if (lldb::ValueObjectSP synthetic = base->GetSyntheticValue()) {335llvm::Expected<uint32_t> num_children =336synthetic->GetNumChildren(child_idx + 1);337if (!num_children)338return llvm::make_error<DILDiagnosticError>(339m_expr, toString(num_children.takeError()), node->GetLocation());340if (child_idx >= *num_children) {341std::string message = llvm::formatv(342"array index {0} is not valid for \"({1}) {2}\"", child_idx,343base->GetTypeName().AsCString("<invalid type>"),344base->GetName().AsCString());345return llvm::make_error<DILDiagnosticError>(m_expr, message,346node->GetLocation());347}348if (lldb::ValueObjectSP child_valobj_sp =349synthetic->GetChildAtIndex(child_idx))350return child_valobj_sp;351}352353auto base_type = base->GetCompilerType().GetNonReferenceType();354if (!base_type.IsPointerType() && !base_type.IsArrayType())355return llvm::make_error<DILDiagnosticError>(356m_expr, "subscripted value is not an array or pointer",357node->GetLocation());358if (base_type.IsPointerToVoid())359return llvm::make_error<DILDiagnosticError>(360m_expr, "subscript of pointer to incomplete type 'void'",361node->GetLocation());362363if (base_type.IsArrayType()) {364if (lldb::ValueObjectSP child_valobj_sp = base->GetChildAtIndex(child_idx))365return child_valobj_sp;366}367368int64_t signed_child_idx = node->GetIndex();369return base->GetSyntheticArrayMember(signed_child_idx, true);370}371372llvm::Expected<lldb::ValueObjectSP>373Interpreter::Visit(const BitFieldExtractionNode *node) {374auto lhs_or_err = Evaluate(node->GetBase());375if (!lhs_or_err)376return lhs_or_err;377lldb::ValueObjectSP base = *lhs_or_err;378int64_t first_index = node->GetFirstIndex();379int64_t last_index = node->GetLastIndex();380381// if the format given is [high-low], swap range382if (first_index > last_index)383std::swap(first_index, last_index);384385Status error;386if (base->GetCompilerType().IsReferenceType()) {387base = base->Dereference(error);388if (error.Fail())389return error.ToError();390}391lldb::ValueObjectSP child_valobj_sp =392base->GetSyntheticBitFieldChild(first_index, last_index, true);393if (!child_valobj_sp) {394std::string message = llvm::formatv(395"bitfield range {0}-{1} is not valid for \"({2}) {3}\"", first_index,396last_index, base->GetTypeName().AsCString("<invalid type>"),397base->GetName().AsCString());398return llvm::make_error<DILDiagnosticError>(m_expr, message,399node->GetLocation());400}401return child_valobj_sp;402}403404} // namespace lldb_private::dil405406407