[Lldb-commits] [lldb] [LLDB] Add AST node classes, functions, etc. for Data Inspection Lang… (PR #95738)
via lldb-commits
lldb-commits at lists.llvm.org
Fri Aug 9 09:46:01 PDT 2024
================
@@ -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
More information about the lldb-commits
mailing list