https://github.com/Thrrreeee updated 
https://github.com/llvm/llvm-project/pull/142747

>From 64785ba97f670ace37c3d1e43aef1141a232c00c Mon Sep 17 00:00:00 2001
From: jinruiShi <1379998...@qq.com>
Date: Wed, 4 Jun 2025 16:24:53 +0800
Subject: [PATCH] LLDB support for
 DW_OP_GNU_implicit_pointer/DW_OP_implicit_pointer operation

---
 lldb/include/lldb/Core/Value.h                | 10 +++
 lldb/include/lldb/Symbol/Variable.h           |  8 +-
 .../Commands/CommandObjectDWIMPrint.cpp       |  9 ++-
 lldb/source/Core/Value.cpp                    | 21 +++++-
 lldb/source/Expression/DWARFExpression.cpp    | 20 ++++-
 .../source/Expression/DWARFExpressionList.cpp | 73 ++++++++++++++++++-
 lldb/source/Expression/Materializer.cpp       | 40 ++++++++--
 lldb/source/Symbol/Variable.cpp               |  4 +-
 .../ValueObject/ValueObjectVariable.cpp       | 17 +++--
 llvm/include/llvm/BinaryFormat/Dwarf.def      |  2 +
 llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp  |  2 +
 .../DebugInfo/LogicalView/Core/LVLocation.cpp |  1 +
 12 files changed, 181 insertions(+), 26 deletions(-)

diff --git a/lldb/include/lldb/Core/Value.h b/lldb/include/lldb/Core/Value.h
index 3714621b469ec..b5411e2377c93 100644
--- a/lldb/include/lldb/Core/Value.h
+++ b/lldb/include/lldb/Core/Value.h
@@ -82,6 +82,10 @@ class Value {
 
   ValueType GetValueType() const;
 
+  void setImplictPointerDIEoffset(uint64_t offset);
+  void setImplictPointerOffset(int64_t offset);
+  uint64_t getImplictPointerDIEoffset() const;
+  int64_t getImplictPointerOffset() const;
   AddressType GetValueAddressType() const;
 
   ContextType GetContextType() const { return m_context_type; }
@@ -182,6 +186,12 @@ class Value {
   ValueType m_value_type = ValueType::Scalar;
   ContextType m_context_type = ContextType::Invalid;
   DataBufferHeap m_data_buffer;
+  struct {
+    /* 4- or 8-byte offset of DIE  */
+    uint64_t die_offset = 0;
+    /* The byte offset into the resulting data.  */
+    int64_t result_offset;
+  } implicit_pointer;
 };
 
 class ValueList {
diff --git a/lldb/include/lldb/Symbol/Variable.h 
b/lldb/include/lldb/Symbol/Variable.h
index c437624d1ea6d..d38945f32f89e 100644
--- a/lldb/include/lldb/Symbol/Variable.h
+++ b/lldb/include/lldb/Symbol/Variable.h
@@ -34,7 +34,7 @@ class Variable : public UserID, public 
std::enable_shared_from_this<Variable> {
            SymbolContextScope *owner_scope, const RangeList &scope_range,
            Declaration *decl, const DWARFExpressionList &location,
            bool external, bool artificial, bool location_is_constant_data,
-           bool static_member = false);
+           bool static_member = false, bool is_implicit_pointer = false);
 
   virtual ~Variable();
 
@@ -97,6 +97,9 @@ class Variable : public UserID, public 
std::enable_shared_from_this<Variable> {
 
   void SetLocationIsConstantValueData(bool b) { m_loc_is_const_data = b; }
 
+  bool IsImplicitPointer() const { return m_is_implicit_pointer; }
+
+  void SetIsImplicitPointer(bool b) { m_is_implicit_pointer = b; }
   typedef size_t (*GetVariableCallback)(void *baton, const char *name,
                                         VariableList &var_list);
 
@@ -140,7 +143,8 @@ class Variable : public UserID, public 
std::enable_shared_from_this<Variable> {
   unsigned m_loc_is_const_data : 1;
   /// Non-zero if variable is static member of a class or struct.
   unsigned m_static_member : 1;
-
+  /// Non-zero if the variable is a implicit pointer type.
+  unsigned m_is_implicit_pointer : 1;
 private:
   Variable(const Variable &rhs) = delete;
   Variable &operator=(const Variable &rhs) = delete;
diff --git a/lldb/source/Commands/CommandObjectDWIMPrint.cpp 
b/lldb/source/Commands/CommandObjectDWIMPrint.cpp
index 17c60297a521e..1cf82dfb780a4 100644
--- a/lldb/source/Commands/CommandObjectDWIMPrint.cpp
+++ b/lldb/source/Commands/CommandObjectDWIMPrint.cpp
@@ -19,6 +19,7 @@
 #include "lldb/Target/StackFrame.h"
 #include "lldb/Utility/ConstString.h"
 #include "lldb/ValueObject/ValueObject.h"
+#include "lldb/Symbol/Variable.h"
 #include "lldb/lldb-defines.h"
 #include "lldb/lldb-enumerations.h"
 #include "lldb/lldb-forward.h"
@@ -174,7 +175,13 @@ void CommandObjectDWIMPrint::DoExecute(StringRef command,
         if (auto persisted_valobj = valobj_sp->Persist())
           valobj_sp = persisted_valobj;
       }
-
+      // FIXME: LLDB haven't implemented "optimization out" output.
+      if (valobj_sp->GetVariable()->IsImplicitPointer()) {
+        result.AppendMessageWithFormatv("expression `{0}` is an implicit "
+                                        "pointer, value has been optimized 
out",
+                                        expr);
+        return;
+      }
       if (verbosity == eDWIMPrintVerbosityFull) {
         StringRef flags;
         if (args.HasArgs())
diff --git a/lldb/source/Core/Value.cpp b/lldb/source/Core/Value.cpp
index c91b3f852f986..4e7956c7894b5 100644
--- a/lldb/source/Core/Value.cpp
+++ b/lldb/source/Core/Value.cpp
@@ -55,7 +55,8 @@ Value::Value(const void *bytes, int len)
 Value::Value(const Value &v)
     : m_value(v.m_value), m_compiler_type(v.m_compiler_type),
       m_context(v.m_context), m_value_type(v.m_value_type),
-      m_context_type(v.m_context_type), m_data_buffer() {
+      m_context_type(v.m_context_type), m_data_buffer(),
+      implicit_pointer(v.implicit_pointer) {
   const uintptr_t rhs_value =
       (uintptr_t)v.m_value.ULongLong(LLDB_INVALID_ADDRESS);
   if ((rhs_value != 0) &&
@@ -65,6 +66,8 @@ Value::Value(const Value &v)
 
     m_value = (uintptr_t)m_data_buffer.GetBytes();
   }
+  implicit_pointer.result_offset = v.implicit_pointer.result_offset;
+  implicit_pointer.die_offset = v.implicit_pointer.die_offset;
 }
 
 Value &Value::operator=(const Value &rhs) {
@@ -74,6 +77,7 @@ Value &Value::operator=(const Value &rhs) {
     m_context = rhs.m_context;
     m_value_type = rhs.m_value_type;
     m_context_type = rhs.m_context_type;
+    implicit_pointer = rhs.implicit_pointer;
     const uintptr_t rhs_value =
         (uintptr_t)rhs.m_value.ULongLong(LLDB_INVALID_ADDRESS);
     if ((rhs_value != 0) &&
@@ -641,6 +645,8 @@ void Value::Clear() {
   m_context = nullptr;
   m_context_type = ContextType::Invalid;
   m_data_buffer.Clear();
+  implicit_pointer.result_offset = 0;
+  implicit_pointer.die_offset = 0;
 }
 
 const char *Value::GetValueTypeAsCString(ValueType value_type) {
@@ -659,6 +665,19 @@ const char *Value::GetValueTypeAsCString(ValueType 
value_type) {
   llvm_unreachable("enum cases exhausted.");
 }
 
+void Value::setImplictPointerDIEoffset(uint64_t offset) {
+  implicit_pointer.die_offset = offset;
+}
+void Value::setImplictPointerOffset(int64_t offset) {
+  implicit_pointer.result_offset = offset;
+}
+uint64_t Value::getImplictPointerDIEoffset() const {
+  return implicit_pointer.die_offset;
+}
+int64_t Value::getImplictPointerOffset() const {
+  return implicit_pointer.result_offset;
+}
+
 const char *Value::GetContextTypeAsCString(ContextType context_type) {
   switch (context_type) {
   case ContextType::Invalid:
diff --git a/lldb/source/Expression/DWARFExpression.cpp 
b/lldb/source/Expression/DWARFExpression.cpp
index f48f3ab9307dd..aa84c415b8fad 100644
--- a/lldb/source/Expression/DWARFExpression.cpp
+++ b/lldb/source/Expression/DWARFExpression.cpp
@@ -357,7 +357,7 @@ static lldb::offset_t GetOpcodeDataSize(const DataExtractor 
&data,
     offset += block_len;
     return offset - data_offset;
   }
-
+  case DW_OP_GNU_implicit_pointer: 
   case DW_OP_implicit_pointer: // 0xa0 4-byte (or 8-byte for DWARF 64) constant
                                // + LEB128
   {
@@ -2066,11 +2066,23 @@ llvm::Expected<Value> DWARFExpression::Evaluate(
       stack.push_back(result);
       break;
     }
-
+    // OPCODE: DW_OP_implicit_pointer 
+    // OPERANDS: 
+    // (1) 2 4- or 8-byte offset of DIE
+    // (2) SLEB128 constant offset
+    // DESCRIPTION: First offset is a reference to a debugging information 
entry that describes the dereferenced object’s value
+    // and a signed number that is treated as a byte offset from the start of 
that value
+    case DW_OP_GNU_implicit_pointer:
     case DW_OP_implicit_pointer: {
       dwarf4_location_description_kind = Implicit;
-      return llvm::createStringError("Could not evaluate %s.",
-                                     DW_OP_value_to_name(op));
+      uint64_t die_offset = opcodes.GetU32(&offset);
+      int64_t result_offset = opcodes.GetSLEB128(&offset);
+      
+      Value implicit_ptr_value;
+      implicit_ptr_value.setImplictPointerDIEoffset(die_offset);
+      implicit_ptr_value.setImplictPointerOffset(result_offset);
+      stack.push_back(implicit_ptr_value);
+      break;
     }
 
     // OPCODE: DW_OP_push_object_address
diff --git a/lldb/source/Expression/DWARFExpressionList.cpp 
b/lldb/source/Expression/DWARFExpressionList.cpp
index be6c0a151159d..1715aee155ad2 100644
--- a/lldb/source/Expression/DWARFExpressionList.cpp
+++ b/lldb/source/Expression/DWARFExpressionList.cpp
@@ -9,13 +9,16 @@
 #include "lldb/Expression/DWARFExpressionList.h"
 #include "Plugins/SymbolFile/DWARF/DWARFUnit.h"
 #include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/VariableList.h"
 #include "lldb/Target/RegisterContext.h"
 #include "lldb/Target/StackFrame.h"
+#include "lldb/ValueObject/ValueObject.h"
 #include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
 #include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
 
 using namespace lldb;
 using namespace lldb_private;
+using namespace lldb_private::plugin::dwarf;
 
 bool DWARFExpressionList::IsAlwaysValidSingleExpr() const {
   return GetAlwaysValidExpr() != nullptr;
@@ -197,6 +200,58 @@ void DWARFExpressionList::GetDescription(Stream *s,
   }
 }
 
+//===----------------------------------------------------------------------===//
+// ResolveImplicitPointerValue resolves an implicit pointer value from a DIE
+// offset and an offset within that DIE. It retrieves the variable name from
+// the DIE, finds the corresponding variable in the current frame's variable
+// list, and constructs a Value object representing the implicit pointer.
+static llvm::Expected<Value> ResolveImplicitPointerValue(ExecutionContext 
*exe_ctx,
+                                                  const DWARFUnit *dwarf_cu,
+                                                  uint64_t die_offset,
+                                                  uint64_t offset) {
+  if (!exe_ctx || !dwarf_cu)
+    return llvm::createStringError("invalid execution context or DWARF CU");
+
+  DWARFDIE die = const_cast<DWARFUnit *>(dwarf_cu)->GetDIE(die_offset);
+  if (!die) {
+    return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                   "Could not locate DIE at offset 0x%" PRIx64
+                                   " for implicit pointer.",
+                                   die_offset);
+  }
+
+  DWARFAttributes attrs = die.GetAttributes();
+  const char *name = die.GetAttributeValueAsString(dwarf::DW_AT_name, nullptr);
+  StackFrame *frame = exe_ctx->GetFramePtr();
+  if (!frame)
+    return llvm::createStringError("no frame for implicit pointer");
+
+  const bool get_file_globals = true;
+  VariableListSP var_list_sp(frame->GetInScopeVariableList(get_file_globals));
+  VariableList *variable_list = var_list_sp.get();
+  if (!variable_list)
+    return llvm::createStringError("no variable list for implicit pointer");
+
+  VariableSP var_sp = variable_list->FindVariable(ConstString(name), false);
+  ValueObjectSP valobj_sp;
+  if (var_sp && !valobj_sp) {
+    valobj_sp =
+        frame->GetValueObjectForFrameVariable(var_sp, lldb::eNoDynamicValues);
+  }
+  if (!valobj_sp) {
+    return llvm::createStringError("invalid variable path '{0}'", name);
+  }
+  valobj_sp->UpdateValueIfNeeded(false);
+  lldb::addr_t base_addr = valobj_sp->GetValue().GetScalar().ULongLong(0);
+  if (base_addr == LLDB_INVALID_ADDRESS) {
+    return llvm::createStringError("invalid base address");
+  }
+
+  valobj_sp->GetValue().setImplictPointerDIEoffset(die_offset);
+  valobj_sp->GetValue().setImplictPointerOffset(offset);
+  return valobj_sp->GetValue();
+}
+
 llvm::Expected<Value> DWARFExpressionList::Evaluate(
     ExecutionContext *exe_ctx, RegisterContext *reg_ctx,
     lldb::addr_t func_load_addr, const Value *initial_value_ptr,
@@ -233,7 +288,19 @@ llvm::Expected<Value> DWARFExpressionList::Evaluate(
   }
   expr.GetExpressionData(data);
   reg_kind = expr.GetRegisterKind();
-  return DWARFExpression::Evaluate(exe_ctx, reg_ctx, module_sp, data,
-                                   m_dwarf_cu, reg_kind, initial_value_ptr,
-                                   object_address_ptr);
+  llvm::Expected<Value> maybe_value = DWARFExpression::Evaluate(
+      exe_ctx, reg_ctx, module_sp, data, m_dwarf_cu, reg_kind,
+      initial_value_ptr, object_address_ptr);
+  if (maybe_value) {
+    Value &value = *maybe_value;
+    if (value.getImplictPointerDIEoffset() != 0) {
+      auto resolved = ResolveImplicitPointerValue(
+          exe_ctx, m_dwarf_cu, value.getImplictPointerDIEoffset(),
+          value.getImplictPointerOffset());
+      if (!resolved)
+        return resolved.takeError();
+      maybe_value = *resolved;
+    }
+  }
+  return maybe_value;
 }
diff --git a/lldb/source/Expression/Materializer.cpp 
b/lldb/source/Expression/Materializer.cpp
index 8d48b5e50041c..710a26a1adcee 100644
--- a/lldb/source/Expression/Materializer.cpp
+++ b/lldb/source/Expression/Materializer.cpp
@@ -540,8 +540,9 @@ class EntityVariableBase : public Materializer::Entity {
           return;
         }
 
-        if (data.GetByteSize() <
-            llvm::expectedToOptional(GetByteSize(scope)).value_or(0)) {
+        if ((data.GetByteSize() <
+             llvm::expectedToOptional(GetByteSize(scope)).value_or(0)) &&
+            !valobj_sp->GetVariable()->IsImplicitPointer()) {
           if (data.GetByteSize() == 0 && !LocationExpressionIsValid()) {
             err = Status::FromErrorStringWithFormat(
                 "the variable '%s' has no location, "
@@ -599,10 +600,17 @@ class EntityVariableBase : public Materializer::Entity {
           return;
         }
 
+        lldb::addr_t tmp_allocation = m_temporary_allocation;
+        if (valobj_sp->GetVariable()->IsImplicitPointer()) {
+          // If the variable is an implicit pointer, we need to write the
+          // address of the temporary region into the memory location
+          // that the implicit pointer points to.
+          uint64_t ptr_offset = 
valobj_sp->GetValue().getImplictPointerOffset();
+          MallocTmp(map, tmp_allocation, byte_align, ptr_offset, err);
+        }
         Status pointer_write_error;
 
-        map.WritePointerToMemory(load_addr, m_temporary_allocation,
-                                 pointer_write_error);
+        map.WritePointerToMemory(load_addr, tmp_allocation, 
pointer_write_error);
 
         if (!pointer_write_error.Success()) {
           err = Status::FromErrorStringWithFormat(
@@ -613,6 +621,24 @@ class EntityVariableBase : public Materializer::Entity {
     }
   }
 
+void MallocTmp(IRMemoryMap &map, lldb::addr_t &allocation,
+               size_t byte_align, uint64_t offset, Status &err) {
+  Status alloc_error;
+  const bool zero_memory = false;
+  allocation = map.Malloc(sizeof(lldb::addr_t), byte_align,
+                              lldb::ePermissionsReadable | 
lldb::ePermissionsWritable,
+                              IRMemoryMap::eAllocationPolicyMirror,
+                              zero_memory, alloc_error);
+  if (!alloc_error.Success()) {
+    err = Status::FromErrorStringWithFormat(
+        "Couldn't allocate a temporary region for %s: %s",
+        GetName().AsCString(), alloc_error.AsCString());
+    return;
+  }
+  Status pointer_write_error;
+  map.WritePointerToMemory(allocation, m_temporary_allocation + offset,
+                           pointer_write_error);
+}
   void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
                      lldb::addr_t process_address, lldb::addr_t frame_top,
                      lldb::addr_t frame_bottom, Status &err) override {
@@ -659,15 +685,15 @@ class EntityVariableBase : public Materializer::Entity {
       bool actually_write = true;
 
       if (m_original_data) {
-        if ((data.GetByteSize() == m_original_data->GetByteSize()) &&
+        if (((data.GetByteSize() == m_original_data->GetByteSize()) &&
             !memcmp(m_original_data->GetBytes(), data.GetDataStart(),
-                    data.GetByteSize())) {
+                    data.GetByteSize())) || 
+                    valobj_sp->GetVariable()->IsImplicitPointer()) {
           actually_write = false;
         }
       }
 
       Status set_error;
-
       if (actually_write) {
         valobj_sp->SetData(data, set_error);
 
diff --git a/lldb/source/Symbol/Variable.cpp b/lldb/source/Symbol/Variable.cpp
index 8244725aba545..745dece41ac2f 100644
--- a/lldb/source/Symbol/Variable.cpp
+++ b/lldb/source/Symbol/Variable.cpp
@@ -43,13 +43,13 @@ Variable::Variable(lldb::user_id_t uid, const char *name, 
const char *mangled,
                    const RangeList &scope_range, Declaration *decl_ptr,
                    const DWARFExpressionList &location_list, bool external,
                    bool artificial, bool location_is_constant_data,
-                   bool static_member)
+                   bool static_member, bool is_implicit_pointer)
     : UserID(uid), m_name(name), m_mangled(ConstString(mangled)),
       m_symfile_type_sp(symfile_type_sp), m_scope(scope),
       m_owner_scope(context), m_scope_range(scope_range),
       m_declaration(decl_ptr), m_location_list(location_list), 
m_external(external),
       m_artificial(artificial), m_loc_is_const_data(location_is_constant_data),
-      m_static_member(static_member) {}
+      m_static_member(static_member), 
m_is_implicit_pointer(is_implicit_pointer) {}
 
 Variable::~Variable() = default;
 
diff --git a/lldb/source/ValueObject/ValueObjectVariable.cpp 
b/lldb/source/ValueObject/ValueObjectVariable.cpp
index 12a84f9f2ed74..1d87dfae5138f 100644
--- a/lldb/source/ValueObject/ValueObjectVariable.cpp
+++ b/lldb/source/ValueObject/ValueObjectVariable.cpp
@@ -165,12 +165,17 @@ bool ValueObjectVariable::UpdateValue() {
     if (maybe_value) {
       m_value = *maybe_value;
       m_resolved_value = m_value;
-      m_value.SetContext(Value::ContextType::Variable, variable);
-
-      CompilerType compiler_type = GetCompilerType();
-      if (compiler_type.IsValid())
-        m_value.SetCompilerType(compiler_type);
-
+      CompilerType compiler_type;
+      if (m_value.getImplictPointerDIEoffset() != 0) {
+        compiler_type = m_value.GetCompilerType();
+        variable->SetIsImplicitPointer(true);
+        m_override_type = compiler_type;
+      } else {
+        m_value.SetContext(Value::ContextType::Variable, variable);
+        compiler_type = GetCompilerType();
+        if (compiler_type.IsValid())
+          m_value.SetCompilerType(compiler_type);
+      }
       Value::ValueType value_type = m_value.GetValueType();
 
       // The size of the buffer within m_value can be less than the size
diff --git a/llvm/include/llvm/BinaryFormat/Dwarf.def 
b/llvm/include/llvm/BinaryFormat/Dwarf.def
index e52324a8ebc12..b1b406cbebf97 100644
--- a/llvm/include/llvm/BinaryFormat/Dwarf.def
+++ b/llvm/include/llvm/BinaryFormat/Dwarf.def
@@ -887,6 +887,8 @@ HANDLE_DW_OP(0xed, WASM_location, -1, -1, 0, WASM)
 HANDLE_DW_OP(0xee, WASM_location_int, -1, -1, 0, WASM)
 // Historic and not implemented in LLVM.
 HANDLE_DW_OP(0xf0, APPLE_uninit, -1, -1, 0, APPLE)
+// The GNU implicit pointer extension.
+HANDLE_DW_OP(0xf2, GNU_implicit_pointer, 2, 0, 5, GNU)
 // The GNU entry value extension.
 HANDLE_DW_OP(0xf3, GNU_entry_value, 2, 0, 0, GNU)
 HANDLE_DW_OP(0xf8, PGI_omp_thread_num, -1, -1, 0, PGI)
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp 
b/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
index 2ae5ff3efc8c5..17e816a1e4552 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
@@ -104,6 +104,8 @@ static std::vector<Desc> getOpDescriptions() {
   Descriptions[DW_OP_GNU_addr_index] = Desc(Op::Dwarf4, Op::SizeLEB);
   Descriptions[DW_OP_GNU_const_index] = Desc(Op::Dwarf4, Op::SizeLEB);
   Descriptions[DW_OP_GNU_entry_value] = Desc(Op::Dwarf4, Op::SizeLEB);
+  Descriptions[DW_OP_GNU_implicit_pointer] =
+    Desc(Op::Dwarf4, Op::SizeRefAddr, Op::SignedSizeLEB);
   // This Description acts as a marker that getSubOpDesc must be called
   // to fetch the final Description for the operation. Each such final
   // Description must share the same first SizeSubOpLEB operand.
diff --git a/llvm/lib/DebugInfo/LogicalView/Core/LVLocation.cpp 
b/llvm/lib/DebugInfo/LogicalView/Core/LVLocation.cpp
index 3c078d8ee74b8..7c1a025e9a4b9 100644
--- a/llvm/lib/DebugInfo/LogicalView/Core/LVLocation.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVLocation.cpp
@@ -284,6 +284,7 @@ std::string LVOperation::getOperandsDWARFInfo() {
   case dwarf::DW_OP_implicit_value:
     Stream << "TODO: DW_OP_implicit_value";
     break;
+  case dwarf::DW_OP_GNU_implicit_pointer:
   case dwarf::DW_OP_implicit_pointer:
     Stream << "implicit_pointer DIE offset " << hexString(Operands[0]) << " "
            << int(Operands[1]);

_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to