================ @@ -0,0 +1,560 @@ +//===-- DILAST.cpp --------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/Core/DILAST.h" +#include "lldb/API/SBType.h" +#include "lldb/Core/ValueObjectRegister.h" +#include "lldb/Core/ValueObjectVariable.h" +#include "lldb/Symbol/TypeList.h" +#include "lldb/Symbol/VariableList.h" +#include "lldb/Target/LanguageRuntime.h" +#include "lldb/Target/RegisterContext.h" +#include "llvm/ADT/StringRef.h" + +#include <vector> + +namespace lldb_private { + +namespace DIL { + +lldb::ValueObjectSP +GetDynamicOrSyntheticValue(lldb::ValueObjectSP in_valobj_sp, + lldb::DynamicValueType use_dynamic, + bool use_synthetic) { + Status error; + + if (!in_valobj_sp) { + error.SetErrorString("invalid value object"); + return in_valobj_sp; + } + + lldb::ValueObjectSP value_sp = in_valobj_sp; + + Target *target = value_sp->GetTargetSP().get(); + // If this ValueObject holds an error, then it is valuable for that. + if (value_sp->GetError().Fail()) + return value_sp; + + if (!target) + return lldb::ValueObjectSP(); + + if (use_dynamic != lldb::eNoDynamicValues) { + lldb::ValueObjectSP dynamic_sp = value_sp->GetDynamicValue(use_dynamic); + if (dynamic_sp) + value_sp = dynamic_sp; + } + + if (use_synthetic) { + lldb::ValueObjectSP synthetic_sp = value_sp->GetSyntheticValue(); + if (synthetic_sp) + value_sp = synthetic_sp; + } + + if (!value_sp) + error.SetErrorString("invalid value object"); + + return value_sp; +} + +CompilerType DILASTNode::GetDereferencedResultType() const { + auto type = result_type(); + return type.IsReferenceType() ? type.GetNonReferenceType() : type; +} + +std::optional<MemberInfo> +GetFieldWithNameIndexPath(lldb::ValueObjectSP lhs_val_sp, CompilerType type, + const std::string &name, std::vector<uint32_t> *idx, + CompilerType empty_type, bool use_synthetic, + bool is_dynamic) { + bool is_synthetic = false; + // Go through the fields first. + uint32_t num_fields = type.GetNumFields(); + lldb::ValueObjectSP empty_valobj_sp; + for (uint32_t i = 0; i < num_fields; ++i) { + uint64_t bit_offset = 0; + uint32_t bitfield_bit_size = 0; + bool is_bitfield = false; + std::string name_sstr; + CompilerType field_type(type.GetFieldAtIndex( + i, name_sstr, &bit_offset, &bitfield_bit_size, &is_bitfield)); + auto field_name = + name_sstr.length() == 0 ? std::optional<std::string>() : name_sstr; + if (field_type.IsValid()) { + std::optional<uint32_t> size_in_bits; + if (is_bitfield) + size_in_bits = bitfield_bit_size; + struct MemberInfo field = {field_name, field_type, size_in_bits, + is_synthetic, is_dynamic, empty_valobj_sp}; + + // Name can be null if this is a padding field. + if (field.name == name) { + if (lhs_val_sp) { + lldb::ValueObjectSP child_valobj_sp = + lhs_val_sp->GetChildMemberWithName(name); + if (child_valobj_sp) + field.val_obj_sp = child_valobj_sp; + } + + if (idx) { + assert(idx->empty()); + // Direct base classes are located before fields, so field members + // needs to be offset by the number of base classes. + idx->push_back(i + type.GetNumberOfNonEmptyBaseClasses()); + } + return field; + } else if (field.type.IsAnonymousType()) { + // Every member of an anonymous struct is considered to be a member of + // the enclosing struct or union. This applies recursively if the + // enclosing struct or union is also anonymous. + + assert(!field.name && "Field should be unnamed."); + + std::optional<MemberInfo> field_in_anon_type = + GetFieldWithNameIndexPath(lhs_val_sp, field.type, name, idx, + empty_type, use_synthetic, is_dynamic); + if (field_in_anon_type) { + if (idx) { + idx->push_back(i + type.GetNumberOfNonEmptyBaseClasses()); + } + return field_in_anon_type.value(); + } + } + } + } + + // LLDB can't access inherited fields of anonymous struct members. + if (type.IsAnonymousType()) { + return {}; + } + + // Go through the base classes and look for the field there. + uint32_t num_non_empty_bases = 0; + uint32_t num_direct_bases = type.GetNumDirectBaseClasses(); + for (uint32_t i = 0; i < num_direct_bases; ++i) { + uint32_t bit_offset; + auto base = type.GetDirectBaseClassAtIndex(i, &bit_offset); + auto field = GetFieldWithNameIndexPath( + lhs_val_sp, base, name, idx, empty_type, use_synthetic, is_dynamic); + if (field) { + if (idx) { + idx->push_back(num_non_empty_bases); + } + return field.value(); + } + if (base.GetNumFields() > 0) { + num_non_empty_bases += 1; + } + } + + // Check for synthetic member + if (lhs_val_sp && use_synthetic) { + lldb::ValueObjectSP child_valobj_sp = lhs_val_sp->GetSyntheticValue(); + if (child_valobj_sp) { + is_synthetic = true; + uint32_t child_idx = child_valobj_sp->GetIndexOfChildWithName(name); + child_valobj_sp = child_valobj_sp->GetChildMemberWithName(name); + if (child_valobj_sp) { + CompilerType field_type = child_valobj_sp->GetCompilerType(); + if (field_type.IsValid()) { + struct MemberInfo field = {name, field_type, {}, + is_synthetic, is_dynamic, child_valobj_sp}; + if (idx) { + assert(idx->empty()); + idx->push_back(child_idx); + } + return field; + } + } + } + } + + if (lhs_val_sp) { + lldb::ValueObjectSP dynamic_val_sp = + lhs_val_sp->GetDynamicValue(lldb::eDynamicDontRunTarget); + if (dynamic_val_sp) { + CompilerType lhs_type = dynamic_val_sp->GetCompilerType(); + if (lhs_type.IsPointerType()) + lhs_type = lhs_type.GetPointeeType(); + is_dynamic = true; + return GetFieldWithNameIndexPath(dynamic_val_sp, lhs_type, name, idx, + empty_type, use_synthetic, is_dynamic); + } + } + + return {}; +} + +std::tuple<std::optional<MemberInfo>, std::vector<uint32_t>> +GetMemberInfo(lldb::ValueObjectSP lhs_val_sp, CompilerType type, + const std::string &name, bool use_synthetic) { + std::vector<uint32_t> idx; + CompilerType empty_type; + bool is_dynamic = false; + std::optional<MemberInfo> member = GetFieldWithNameIndexPath( + lhs_val_sp, type, name, &idx, empty_type, use_synthetic, is_dynamic); + std::reverse(idx.begin(), idx.end()); + return {member, std::move(idx)}; +} + +static lldb::ValueObjectSP +LookupStaticIdentifier(lldb::TargetSP target_sp, + const llvm::StringRef &name_ref, + ConstString unqualified_name) { + // List global variable with the same "basename". There can be many matches + // from other scopes (namespaces, classes), so we do additional filtering + // later. + std::vector<lldb::ValueObjectSP> values; + VariableList variable_list; + ConstString name(name_ref); + target_sp->GetImages().FindGlobalVariables( + name, (size_t)std::numeric_limits<uint32_t>::max, variable_list); + if (!variable_list.Empty()) { + ExecutionContextScope *exe_scope = target_sp->GetProcessSP().get(); + if (exe_scope == nullptr) + exe_scope = target_sp.get(); + for (const lldb::VariableSP &var_sp : variable_list) { + lldb::ValueObjectSP valobj_sp( + ValueObjectVariable::Create(exe_scope, var_sp)); + if (valobj_sp) + values.push_back(valobj_sp); + } + } + + // Find the corrent variable by matching the name. + for (uint32_t i = 0; i < values.size(); ++i) { + lldb::ValueObjectSP val = values[i]; + if (val->GetVariable() && + (val->GetVariable()->NameMatches(unqualified_name) || + val->GetVariable()->NameMatches(ConstString(name_ref)))) + return val; + } + lldb::ValueObjectSP empty_obj_sp; + return empty_obj_sp; +} + +struct EnumMember { + CompilerType type; + ConstString name; + llvm::APSInt value; +}; + +static std::vector<EnumMember> GetEnumMembers(CompilerType type) { + std::vector<EnumMember> enum_member_list; + if (type.IsValid()) { + type.ForEachEnumerator( + [&enum_member_list](const CompilerType &integer_type, ConstString name, + const llvm::APSInt &value) -> bool { + EnumMember enum_member = {integer_type, name, value}; + enum_member_list.push_back(enum_member); + return true; // Keep iterating + }); + } + return enum_member_list; +} + +CompilerType +ResolveTypeByName(const std::string &name, + std::shared_ptr<ExecutionContextScope> ctx_scope) { + // Internally types don't have global scope qualifier in their names and + // LLDB doesn't support queries with it too. + llvm::StringRef name_ref(name); + bool global_scope = false; + + if (name_ref.starts_with("::")) { + name_ref = name_ref.drop_front(2); + global_scope = true; + } ---------------- cmtice wrote:
Sometimes it works and sometimes it doesn't. It appears that I can prefix plain global vars with '::', but I can't (e.g.) prefix namespaces with '::'. So current frame var works with '::globalVar', and also on 'ns::globalVar', but fails on '::ns::globalVar'. I am unclear if there is any work or change you are requesting here, other than commenting on the comment? https://github.com/llvm/llvm-project/pull/95738 _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits