[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