llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lldb

Author: Thrrreeee (Thrrreeee)

<details>
<summary>Changes</summary>

This Pull Request introduces support in LLDB for the DWARF operations 
`DW_OP_GNU_implicit_pointer` and `DW_OP_implicit_pointer`.
These operators are commonly found in debug information and are used to enhance 
the debugging experience by improving how variable expressions are represented. 
By introducing handling for these operations, LLDB will be able to interpret 
and display variable values more accurately when debugging binaries that 
contain such DWARF expressions. This update improves LLDB's compatibility and 
correctness when working with debug information generated by GCC, Clang, and 
other DWARF-compliant toolchains, and helps ensure a more robust debugging 
experience.

---
Full diff: https://github.com/llvm/llvm-project/pull/142747.diff


11 Files Affected:

- (modified) lldb/include/lldb/Core/Value.h (+10) 
- (modified) lldb/include/lldb/Symbol/Variable.h (+5-1) 
- (modified) lldb/source/Commands/CommandObjectDWIMPrint.cpp (+8-1) 
- (modified) lldb/source/Core/Value.cpp (+20-1) 
- (modified) lldb/source/Expression/DWARFExpression.cpp (+16-4) 
- (modified) lldb/source/Expression/DWARFExpressionList.cpp (+70-3) 
- (modified) lldb/source/Expression/Materializer.cpp (+33-7) 
- (modified) lldb/source/ValueObject/ValueObjectVariable.cpp (+11-6) 
- (modified) llvm/include/llvm/BinaryFormat/Dwarf.def (+2) 
- (modified) llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp (+2) 
- (modified) llvm/lib/DebugInfo/LogicalView/Core/LVLocation.cpp (+1) 


``````````diff
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..81e0ce30448fa 100644
--- a/lldb/include/lldb/Symbol/Variable.h
+++ b/lldb/include/lldb/Symbol/Variable.h
@@ -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 GetIsImplicitPointer() 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..e3dd4f08d4e10 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()->GetIsImplicitPointer()) {
+        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..458e40bc0c70c 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()->GetIsImplicitPointer()) {
           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()->GetIsImplicitPointer()) {
+          // 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()->GetIsImplicitPointer()) {
           actually_write = false;
         }
       }
 
       Status set_error;
-
       if (actually_write) {
         valobj_sp->SetData(data, set_error);
 
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]);

``````````

</details>


https://github.com/llvm/llvm-project/pull/142747
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to