[Lldb-commits] [lldb] [LLDB] Support for DW_OP_Implicit_pointer (PR #203182)
via lldb-commits
lldb-commits at lists.llvm.org
Tue Jun 23 03:56:54 PDT 2026
https://github.com/Thrrreeee updated https://github.com/llvm/llvm-project/pull/203182
>From e50ddd754233924e97414746c3796c733e3a7df7 Mon Sep 17 00:00:00 2001
From: shijinrui <shijinrui at bytedance.com>
Date: Tue, 23 Jun 2026 17:42:32 +0800
Subject: [PATCH 1/3] Support for DW_OP_Implicit_pointer
---
lldb/include/lldb/Core/Value.h | 18 ++
.../include/lldb/Expression/DWARFExpression.h | 1 +
lldb/source/Core/Value.cpp | 7 +-
lldb/source/Expression/DWARFExpression.cpp | 47 +++-
.../Plugins/SymbolFile/DWARF/DWARFUnit.h | 3 +
.../SymbolFile/DWARF/SymbolFileDWARF.cpp | 62 ++++-
.../SymbolFile/DWARF/SymbolFileDWARF.h | 6 +
lldb/source/ValueObject/ValueObject.cpp | 56 ++++
.../DWARF/x86/DW_OP_implicit_pointer.s | 243 ++++++++++++++++++
.../Expression/DWARFExpressionTest.cpp | 48 +++-
10 files changed, 467 insertions(+), 24 deletions(-)
create mode 100644 lldb/test/Shell/SymbolFile/DWARF/x86/DW_OP_implicit_pointer.s
diff --git a/lldb/include/lldb/Core/Value.h b/lldb/include/lldb/Core/Value.h
index 3714621b469ec..2f4f7a3d23cb2 100644
--- a/lldb/include/lldb/Core/Value.h
+++ b/lldb/include/lldb/Core/Value.h
@@ -19,6 +19,7 @@
#include "llvm/ADT/APInt.h"
+#include <optional>
#include <vector>
#include <cstdint>
@@ -37,6 +38,11 @@ namespace lldb_private {
class Value {
public:
+ struct ImplicitPointerInfo {
+ uint64_t die_offset = 0;
+ int64_t byte_offset = 0;
+ };
+
/// Type that describes Value::m_value.
enum class ValueType {
Invalid = -1,
@@ -93,6 +99,17 @@ class Value {
m_context_type = ContextType::Invalid;
}
+ bool IsImplicitPointer() const { return m_implicit_pointer_info.has_value(); }
+
+ ImplicitPointerInfo GetImplicitPointerInfo() const {
+ return *m_implicit_pointer_info;
+ }
+
+ void SetImplicitPointer(ImplicitPointerInfo implicit_pointer) {
+ m_implicit_pointer_info = implicit_pointer;
+ m_value_type = ValueType::Invalid;
+ }
+
void SetContext(ContextType context_type, void *p) {
m_context_type = context_type;
m_context = p;
@@ -182,6 +199,7 @@ class Value {
ValueType m_value_type = ValueType::Scalar;
ContextType m_context_type = ContextType::Invalid;
DataBufferHeap m_data_buffer;
+ std::optional<ImplicitPointerInfo> m_implicit_pointer_info;
};
class ValueList {
diff --git a/lldb/include/lldb/Expression/DWARFExpression.h b/lldb/include/lldb/Expression/DWARFExpression.h
index b1895690985a7..38e4fb5c34c57 100644
--- a/lldb/include/lldb/Expression/DWARFExpression.h
+++ b/lldb/include/lldb/Expression/DWARFExpression.h
@@ -44,6 +44,7 @@ class DWARFExpression {
virtual uint16_t GetVersion() const = 0;
virtual dw_addr_t GetBaseAddress() const = 0;
+ virtual llvm::dwarf::DwarfFormat GetDwarfFormat() const = 0;
virtual uint8_t GetAddressByteSize() const = 0;
virtual llvm::Expected<std::pair<uint64_t, bool>>
GetDIEBitSizeAndSign(uint64_t relative_die_offset) const = 0;
diff --git a/lldb/source/Core/Value.cpp b/lldb/source/Core/Value.cpp
index f9e65d397f05f..e9b57efcfe066 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(),
+ m_implicit_pointer_info(v.m_implicit_pointer_info) {
const uintptr_t rhs_value =
(uintptr_t)v.m_value.ULongLong(LLDB_INVALID_ADDRESS);
if ((rhs_value != 0) &&
@@ -74,6 +75,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;
+ m_implicit_pointer_info = rhs.m_implicit_pointer_info;
const uintptr_t rhs_value =
(uintptr_t)rhs.m_value.ULongLong(LLDB_INVALID_ADDRESS);
if ((rhs_value != 0) &&
@@ -89,12 +91,14 @@ Value &Value::operator=(const Value &rhs) {
void Value::SetBytes(const void *bytes, int len) {
m_value_type = ValueType::HostAddress;
+ m_implicit_pointer_info.reset();
m_data_buffer.CopyData(bytes, len);
m_value = (uintptr_t)m_data_buffer.GetBytes();
}
void Value::AppendBytes(const void *bytes, int len) {
m_value_type = ValueType::HostAddress;
+ m_implicit_pointer_info.reset();
m_data_buffer.AppendData(bytes, len);
m_value = (uintptr_t)m_data_buffer.GetBytes();
}
@@ -639,6 +643,7 @@ void Value::Clear() {
m_value_type = ValueType::Scalar;
m_context = nullptr;
m_context_type = ContextType::Invalid;
+ m_implicit_pointer_info.reset();
m_data_buffer.Clear();
}
diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp
index dd436e0c8afd9..519716b5041ab 100644
--- a/lldb/source/Expression/DWARFExpression.cpp
+++ b/lldb/source/Expression/DWARFExpression.cpp
@@ -219,7 +219,6 @@ GetOpcodeDataSize(const DataExtractor &data, const lldb::offset_t data_offset,
case DW_OP_APPLE_uninit:
case DW_OP_PGI_omp_thread_num:
case DW_OP_hi_user:
- case DW_OP_GNU_implicit_pointer:
break;
case DW_OP_addr:
@@ -419,12 +418,14 @@ GetOpcodeDataSize(const DataExtractor &data, const lldb::offset_t data_offset,
return offset - data_offset;
}
- case DW_OP_implicit_pointer: // 0xa0 4-byte (or 8-byte for DWARF 64) constant
- // + LEB128
+ case DW_OP_implicit_pointer: // 0xa0 4-byte (or 8-byte for DWARF64) DIE offset
+ case DW_OP_GNU_implicit_pointer: // 0xf2 4-byte (or 8-byte for DWARF64) DIE
+ // offset followed by SLEB128 byte offset.
{
+ DwarfFormat format = dwarf_cu ? dwarf_cu->GetDwarfFormat() : DWARF32;
+ offset += getDwarfOffsetByteSize(format);
data.Skip_LEB128(&offset);
- return (dwarf_cu ? dwarf_cu->GetAddressByteSize() : 4) + offset -
- data_offset;
+ return offset - data_offset;
}
case DW_OP_GNU_entry_value:
@@ -943,6 +944,9 @@ static llvm::Error Evaluate_DW_OP_deref(EvalContext &eval_ctx,
// Deref a register or implicit location and truncate the value to `size`
// bytes. See the corresponding comment in DW_OP_deref for more details on
// why we deref these locations this way.
+ if (eval_ctx.stack.back().IsImplicitPointer())
+ return llvm::createStringError("cannot dereference an implicit pointer");
+
if (eval_ctx.loc_desc_kind == Register ||
eval_ctx.loc_desc_kind == Implicit) {
// Reset context to default values.
@@ -1077,6 +1081,10 @@ static llvm::Error Evaluate_DW_OP_piece(EvalContext &eval_ctx,
if (piece_byte_size == 0)
return llvm::Error::success();
+ if (eval_ctx.pieces.IsImplicitPointer())
+ return llvm::createStringError(
+ "DW_OP_piece cannot combine DW_OP_implicit_pointer with other pieces");
+
Value curr_piece;
if (eval_ctx.stack.empty()) {
@@ -1100,6 +1108,16 @@ static llvm::Error Evaluate_DW_OP_piece(EvalContext &eval_ctx,
UpdateValueTypeFromLocationDescription(eval_ctx, piece_locdesc,
&curr_piece_source_value);
+ if (curr_piece_source_value.IsImplicitPointer()) {
+ if (eval_ctx.pieces.GetBuffer().GetByteSize() != 0)
+ return llvm::createStringError(
+ "DW_OP_piece cannot combine DW_OP_implicit_pointer with other "
+ "pieces");
+ eval_ctx.pieces = curr_piece_source_value;
+ eval_ctx.op_piece_offset += piece_byte_size;
+ return llvm::Error::success();
+ }
+
const Value::ValueType curr_piece_source_value_type =
curr_piece_source_value.GetValueType();
Scalar &scalar = curr_piece_source_value.GetScalar();
@@ -1299,7 +1317,9 @@ llvm::Expected<Value> DWARFExpression::Evaluate(
const Value *object_address_ptr) {
uint32_t address_size = opcodes.GetAddressByteSize();
llvm::DataExtractor expr_data = opcodes.GetAsLLVM();
- llvm::DWARFExpression expr(expr_data, address_size);
+ std::optional<DwarfFormat> dwarf_format =
+ dwarf_cu ? dwarf_cu->GetDwarfFormat() : DWARF32;
+ llvm::DWARFExpression expr(expr_data, address_size, dwarf_format);
if (expr_data.size() == 0)
return llvm::createStringError(
@@ -1853,10 +1873,16 @@ llvm::Expected<Value> DWARFExpression::Evaluate(
break;
}
- case DW_OP_implicit_pointer: {
+ case DW_OP_implicit_pointer:
+ case DW_OP_GNU_implicit_pointer: {
eval_ctx.loc_desc_kind = Implicit;
- return llvm::createStringError("could not evaluate %s",
- DW_OP_value_to_name(opcode));
+ uint64_t die_offset = op->getRawOperand(0);
+ int64_t byte_offset = static_cast<int64_t>(op->getRawOperand(1));
+
+ Value result;
+ result.SetImplicitPointer({die_offset, byte_offset});
+ stack.push_back(result);
+ break;
}
case DW_OP_push_object_address:
@@ -1981,7 +2007,8 @@ llvm::Expected<Value> DWARFExpression::Evaluate(
if (stack.empty()) {
// Nothing on the stack, check if we created a piece value from DW_OP_piece
// or DW_OP_bit_piece opcodes
- if (eval_ctx.pieces.GetBuffer().GetByteSize())
+ if (eval_ctx.pieces.GetBuffer().GetByteSize() ||
+ eval_ctx.pieces.IsImplicitPointer())
return eval_ctx.pieces;
return llvm::createStringError("stack empty after evaluation");
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h
index 6fde9af57fa8b..c02060a622ada 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h
@@ -122,6 +122,9 @@ class DWARFUnit : public DWARFExpression::Delegate, public UserID {
const llvm::dwarf::FormParams &GetFormParams() const {
return m_header.getFormParams();
}
+ llvm::dwarf::DwarfFormat GetDwarfFormat() const override {
+ return m_header.getFormat();
+ }
const llvm::DWARFAbbreviationDeclarationSet *GetAbbreviations() const;
dw_offset_t GetAbbrevOffset() const;
uint8_t GetAddressByteSize() const override {
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index c81fd1c83be85..f72fc002fc4cf 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -60,7 +60,10 @@
#include "lldb/Symbol/TypeMap.h"
#include "lldb/Symbol/TypeSystem.h"
#include "lldb/Symbol/VariableList.h"
+#include "lldb/ValueObject/ValueObjectConstResult.h"
+#include "lldb/ValueObject/ValueObjectVariable.h"
+#include "lldb/Target/ExecutionContextScope.h"
#include "lldb/Target/Language.h"
#include "lldb/Target/Target.h"
@@ -89,6 +92,7 @@
#include "llvm/Support/FormatVariadic.h"
#include <algorithm>
+#include <cstdint>
#include <map>
#include <memory>
#include <optional>
@@ -96,7 +100,7 @@
#include <cctype>
#include <cstring>
-//#define ENABLE_DEBUG_PRINTF // COMMENT OUT THIS LINE PRIOR TO CHECKIN
+// #define ENABLE_DEBUG_PRINTF // COMMENT OUT THIS LINE PRIOR TO CHECKIN
#ifdef ENABLE_DEBUG_PRINTF
#include <cstdio>
@@ -3443,6 +3447,62 @@ size_t SymbolFileDWARF::ParseVariablesForContext(const SymbolContext &sc) {
return 0;
}
+lldb::ValueObjectSP SymbolFileDWARF::ResolveImplicitPointer(
+ uint64_t die_offset, int64_t byte_offset, CompilerType pointee_type,
+ ExecutionContextScope *exe_scope, Variable *context_var) {
+ if (!pointee_type || !exe_scope)
+ return nullptr;
+
+ SymbolContext sc;
+ if (context_var)
+ context_var->CalculateSymbolContext(&sc);
+ if (!sc.comp_unit)
+ if (StackFrameSP frame_sp = exe_scope->CalculateStackFrame())
+ sc = frame_sp->GetSymbolContext(eSymbolContextCompUnit |
+ eSymbolContextFunction |
+ eSymbolContextBlock);
+
+ DWARFDIE target_die = DebugInfo().GetDIE(DIERef::Section::DebugInfo,
+ die_offset);
+ if (!target_die)
+ return nullptr;
+
+ if (!sc.comp_unit) {
+ if (DWARFUnit *dwarf_cu = target_die.GetCU())
+ if (auto *compile_unit = llvm::dyn_cast<DWARFCompileUnit>(dwarf_cu))
+ sc.comp_unit = GetCompUnitForDWARFCompUnit(*compile_unit);
+ }
+
+ VariableSP target_var_sp = ParseVariableDIECached(sc, target_die);
+ if (!target_var_sp)
+ return nullptr;
+
+ ValueObjectSP target_valobj_sp =
+ ValueObjectVariable::Create(exe_scope, target_var_sp);
+ if (!target_valobj_sp || !target_valobj_sp->UpdateValueIfNeeded(false))
+ return nullptr;
+
+ DataExtractor target_data;
+ Status target_error;
+ target_valobj_sp->GetData(target_data, target_error);
+ if (target_error.Fail() || target_data.GetByteSize() == 0)
+ return nullptr;
+
+ if (byte_offset < 0 ||
+ static_cast<uint64_t>(byte_offset) > target_data.GetByteSize())
+ return nullptr;
+
+ lldb::offset_t data_offset = byte_offset;
+ lldb::offset_t data_size = target_data.GetByteSize() - data_offset;
+ if (auto type_size =
+ llvm::expectedToOptional(pointee_type.GetByteSize(exe_scope)))
+ data_size = std::min<lldb::offset_t>(data_size, *type_size);
+
+ DataExtractor pointee_data(target_data, data_offset, data_size);
+ return ValueObjectConstResult::Create(exe_scope, pointee_type, ConstString(),
+ pointee_data, LLDB_INVALID_ADDRESS);
+}
+
VariableSP SymbolFileDWARF::ParseVariableDIECached(const SymbolContext &sc,
const DWARFDIE &die) {
if (!die)
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
index 21a190d1b38f0..32f646ecc79c7 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -136,6 +136,12 @@ class SymbolFileDWARF : public SymbolFileCommon {
size_t ParseVariablesForContext(const SymbolContext &sc) override;
+ lldb::ValueObjectSP
+ ResolveImplicitPointer(uint64_t die_offset, int64_t byte_offset,
+ CompilerType pointee_type,
+ ExecutionContextScope *exe_scope,
+ Variable *context_var);
+
std::optional<ArrayInfo>
GetDynamicArrayInfoForUID(lldb::user_id_t type_uid,
const ExecutionContext *exe_ctx) override;
diff --git a/lldb/source/ValueObject/ValueObject.cpp b/lldb/source/ValueObject/ValueObject.cpp
index 32332c2962e87..afd65ac6b0805 100644
--- a/lldb/source/ValueObject/ValueObject.cpp
+++ b/lldb/source/ValueObject/ValueObject.cpp
@@ -23,6 +23,7 @@
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/CompilerType.h"
#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/SymbolFile.h"
#include "lldb/Symbol/Type.h"
#include "lldb/Symbol/Variable.h"
#include "lldb/Target/ABI.h"
@@ -51,7 +52,9 @@
#include "lldb/ValueObject/ValueObjectVTable.h"
#include "lldb/lldb-enumerations.h"
+#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Casting.h"
#include <algorithm>
#include <atomic>
@@ -2393,6 +2396,18 @@ ValueObjectSP ValueObject::GetValueForExpressionPath_Impl(
*final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
return ValueObjectSP();
}
+ root->UpdateValueIfNeeded(false);
+ if (root->GetValue().IsImplicitPointer()) {
+ Status error;
+ root = DereferenceValueOrAlternate(
+ *root, options.m_synthetic_children_traversal, error);
+ if (error.Fail() || !root) {
+ *reason_to_stop =
+ ValueObject::eExpressionPathScanEndReasonDereferencingFailed;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ }
}
[[fallthrough]];
case '.': // or fallthrough from ->
@@ -2817,6 +2832,47 @@ ValueObjectSP ValueObject::Dereference(Status &error) {
if (m_deref_valobj)
return m_deref_valobj->GetSP();
+ UpdateValueIfNeeded(false);
+ if (m_value.IsImplicitPointer()) {
+ CompilerType pointee_type = GetCompilerType().GetPointeeType();
+ if (!pointee_type) {
+ error = Status::FromErrorString("implicit pointer has no pointee type");
+ return ValueObjectSP();
+ }
+
+ ModuleSP module_sp = GetModule();
+ SymbolFile *symbol_file = module_sp ? module_sp->GetSymbolFile() : nullptr;
+ if (!symbol_file) {
+ error = Status::FromErrorString(
+ "cannot resolve DW_OP_implicit_pointer without symbol file");
+ return ValueObjectSP();
+ }
+
+ ExecutionContext exe_ctx(GetExecutionContextRef());
+ Value::ImplicitPointerInfo implicit_pointer =
+ m_value.GetImplicitPointerInfo();
+ auto *dwarf_symbol_file = llvm::dyn_cast<plugin::dwarf::SymbolFileDWARF>(
+ symbol_file->GetBackingSymbolFile());
+ if (!dwarf_symbol_file) {
+ error = Status::FromErrorString(
+ "cannot resolve DW_OP_implicit_pointer without DWARF symbol file");
+ return ValueObjectSP();
+ }
+
+ ValueObjectSP result_sp = dwarf_symbol_file->ResolveImplicitPointer(
+ implicit_pointer.die_offset, implicit_pointer.byte_offset,
+ pointee_type, exe_ctx.GetBestExecutionContextScope(), GetVariable().get());
+ if (!result_sp) {
+ error = Status::FromErrorStringWithFormat(
+ "cannot resolve DW_OP_implicit_pointer target DIE 0x%" PRIx64,
+ implicit_pointer.die_offset);
+ return ValueObjectSP();
+ }
+
+ error.Clear();
+ return result_sp;
+ }
+
std::string deref_name_str;
uint32_t deref_byte_size = 0;
int32_t deref_byte_offset = 0;
diff --git a/lldb/test/Shell/SymbolFile/DWARF/x86/DW_OP_implicit_pointer.s b/lldb/test/Shell/SymbolFile/DWARF/x86/DW_OP_implicit_pointer.s
new file mode 100644
index 0000000000000..1e4dc45733775
--- /dev/null
+++ b/lldb/test/Shell/SymbolFile/DWARF/x86/DW_OP_implicit_pointer.s
@@ -0,0 +1,243 @@
+# Test DW_OP_implicit_pointer for both scalar types (int, char) and struct types.
+#
+# RUN: llvm-mc -filetype=obj -o %t -triple x86_64-pc-linux %s
+# RUN: %lldb %t \
+# RUN: -o "target variable int_val" \
+# RUN: -o "target variable *int_ptr" \
+# RUN: -o "target variable char_val" \
+# RUN: -o "target variable *char_ptr" \
+# RUN: -o "target variable point" \
+# RUN: -o "target variable *struct_ptr" \
+# RUN: -o "target variable struct_ptr->y" \
+# RUN: -b | FileCheck %s
+
+# CHECK: (lldb) target variable int_val
+# CHECK: (int) int_val = 42
+
+# CHECK: (lldb) target variable *int_ptr
+# CHECK: (int) {{.*}} = 42
+
+# CHECK: (lldb) target variable char_val
+# CHECK: (char) char_val = 'A'
+
+# CHECK: (lldb) target variable *char_ptr
+# CHECK: (char) {{.*}} = 'A'
+
+# CHECK: (lldb) target variable point
+# CHECK: (Point) point = {
+# CHECK-NEXT: x = 10
+# CHECK-NEXT: y = 20
+# CHECK-NEXT: }
+
+# CHECK: (lldb) target variable *struct_ptr
+# CHECK: (Point) {{.*}} = {
+# CHECK-NEXT: x = 10
+# CHECK-NEXT: y = 20
+# CHECK-NEXT: }
+
+# CHECK: (lldb) target variable struct_ptr->y
+# CHECK: (int) {{.*}} = 20
+
+ .section .debug_abbrev,"", at progbits
+ .byte 1 # Abbrev [1] DW_TAG_compile_unit
+ .byte 17 # DW_TAG_compile_unit
+ .byte 1 # DW_CHILDREN_yes
+ .byte 0
+ .byte 0
+
+ .byte 2 # Abbrev [2] DW_TAG_variable
+ .byte 52 # DW_TAG_variable
+ .byte 0 # DW_CHILDREN_no
+ .byte 3 # DW_AT_name
+ .byte 8 # DW_FORM_string
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 2 # DW_AT_location
+ .byte 24 # DW_FORM_exprloc
+ .byte 0
+ .byte 0
+
+ .byte 3 # Abbrev [3] DW_TAG_base_type
+ .byte 36 # DW_TAG_base_type
+ .byte 0 # DW_CHILDREN_no
+ .byte 3 # DW_AT_name
+ .byte 8 # DW_FORM_string
+ .byte 62 # DW_AT_encoding
+ .byte 11 # DW_FORM_data1
+ .byte 11 # DW_AT_byte_size
+ .byte 11 # DW_FORM_data1
+ .byte 0
+ .byte 0
+
+ .byte 4 # Abbrev [4] DW_TAG_pointer_type
+ .byte 15 # DW_TAG_pointer_type
+ .byte 0 # DW_CHILDREN_no
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 0
+ .byte 0
+
+ .byte 5 # Abbrev [5] DW_TAG_structure_type
+ .byte 19 # DW_TAG_structure_type
+ .byte 1 # DW_CHILDREN_yes
+ .byte 3 # DW_AT_name
+ .byte 8 # DW_FORM_string
+ .byte 11 # DW_AT_byte_size
+ .byte 11 # DW_FORM_data1
+ .byte 0
+ .byte 0
+
+ .byte 6 # Abbrev [6] DW_TAG_member
+ .byte 13 # DW_TAG_member
+ .byte 0 # DW_CHILDREN_no
+ .byte 3 # DW_AT_name
+ .byte 8 # DW_FORM_string
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 56 # DW_AT_data_member_location
+ .byte 11 # DW_FORM_data1
+ .byte 0
+ .byte 0
+
+ .byte 0 # End of abbrev table
+
+# ===================================================================
+ .section .debug_info,"", at progbits
+.Ldummy_cu_begin:
+ .long .Ldummy_cu_end - .Ldummy_cu_start
+.Ldummy_cu_start:
+ .short 5 # DWARF version 5
+ .byte 1 # DW_UT_compile
+ .byte 8 # Address size
+ .long .debug_abbrev
+
+ .byte 1 # DW_TAG_compile_unit
+ .byte 0 # End of compile unit children
+.Ldummy_cu_end:
+
+.Lcu_begin0:
+ .long .Lcu_end0 - .Lcu_start0
+.Lcu_start0:
+ .short 5 # DWARF version 5
+ .byte 1 # DW_UT_compile
+ .byte 8 # Address size
+ .long .debug_abbrev
+
+ .byte 1 # DW_TAG_compile_unit
+
+# ---- Base types ----
+.Lint_type:
+ .byte 3 # DW_TAG_base_type
+ .asciz "int"
+ .byte 5 # DW_ATE_signed
+ .byte 4 # 4 bytes
+
+.Lchar_type:
+ .byte 3 # DW_TAG_base_type
+ .asciz "char"
+ .byte 6 # DW_ATE_signed_char
+ .byte 1 # 1 byte
+
+# ---- Pointer types ----
+.Lint_ptr_type:
+ .byte 4 # DW_TAG_pointer_type
+ .long .Lint_type - .Lcu_begin0
+
+.Lchar_ptr_type:
+ .byte 4 # DW_TAG_pointer_type
+ .long .Lchar_type - .Lcu_begin0
+
+.Lstruct_ptr_type:
+ .byte 4 # DW_TAG_pointer_type
+ .long .Lstruct_type - .Lcu_begin0
+
+# ---- struct Point { int x; int y; } ----
+.Lstruct_type:
+ .byte 5 # DW_TAG_structure_type
+ .asciz "Point"
+ .byte 8 # byte_size = 8
+
+ .byte 6 # DW_TAG_member
+ .asciz "x"
+ .long .Lint_type - .Lcu_begin0
+ .byte 0 # offset 0
+
+ .byte 6 # DW_TAG_member
+ .asciz "y"
+ .long .Lint_type - .Lcu_begin0
+ .byte 4 # offset 4
+
+ .byte 0 # end of struct children
+
+# int_val = 42
+.Lint_val:
+ .byte 2 # DW_TAG_variable
+ .asciz "int_val"
+ .long .Lint_type - .Lcu_begin0
+ .byte .Lint_val_loc_end - .Lint_val_loc_start
+.Lint_val_loc_start:
+ .byte 0x9e # DW_OP_implicit_value
+ .uleb128 4 # length = 4
+ .long 42
+.Lint_val_loc_end:
+
+# char_val = 'A' (0x41)
+.Lchar_val:
+ .byte 2 # DW_TAG_variable
+ .asciz "char_val"
+ .long .Lchar_type - .Lcu_begin0
+ .byte .Lchar_val_loc_end - .Lchar_val_loc_start
+.Lchar_val_loc_start:
+ .byte 0x9e # DW_OP_implicit_value
+ .uleb128 1 # length = 1
+ .byte 0x41 # 'A'
+.Lchar_val_loc_end:
+
+# point = {x=10, y=20}
+.Lpoint_val:
+ .byte 2 # DW_TAG_variable
+ .asciz "point"
+ .long .Lstruct_type - .Lcu_begin0
+ .byte .Lpoint_loc_end - .Lpoint_loc_start
+.Lpoint_loc_start:
+ .byte 0x9e # DW_OP_implicit_value
+ .uleb128 8 # length = 8 (two ints)
+ .long 10 # x = 10
+ .long 20 # y = 20
+.Lpoint_loc_end:
+
+# int *int_ptr -> points to int_val, offset 0
+ .byte 2 # DW_TAG_variable
+ .asciz "int_ptr"
+ .long .Lint_ptr_type - .Lcu_begin0
+ .byte .Lint_ptr_loc_end - .Lint_ptr_loc_start
+.Lint_ptr_loc_start:
+ .byte 0xa0 # DW_OP_implicit_pointer
+ .long .Lint_val # reference to int_val DIE
+ .sleb128 0 # byte offset = 0
+.Lint_ptr_loc_end:
+
+# char *char_ptr -> points to char_val, offset 0
+ .byte 2 # DW_TAG_variable
+ .asciz "char_ptr"
+ .long .Lchar_ptr_type - .Lcu_begin0
+ .byte .Lchar_ptr_loc_end - .Lchar_ptr_loc_start
+.Lchar_ptr_loc_start:
+ .byte 0xa0 # DW_OP_implicit_pointer
+ .long .Lchar_val # reference to char_val DIE
+ .sleb128 0 # byte offset = 0
+.Lchar_ptr_loc_end:
+
+# Point *struct_ptr -> points to point, offset 0
+ .byte 2 # DW_TAG_variable
+ .asciz "struct_ptr"
+ .long .Lstruct_ptr_type - .Lcu_begin0
+ .byte .Lstruct_ptr_loc_end - .Lstruct_ptr_loc_start
+.Lstruct_ptr_loc_start:
+ .byte 0xa0 # DW_OP_implicit_pointer
+ .long .Lpoint_val # reference to point DIE
+ .sleb128 0 # byte offset = 0
+.Lstruct_ptr_loc_end:
+
+ .byte 0 # End of compile unit children
+.Lcu_end0:
diff --git a/lldb/unittests/Expression/DWARFExpressionTest.cpp b/lldb/unittests/Expression/DWARFExpressionTest.cpp
index 6d4a624505390..433433bb0d186 100644
--- a/lldb/unittests/Expression/DWARFExpressionTest.cpp
+++ b/lldb/unittests/Expression/DWARFExpressionTest.cpp
@@ -48,11 +48,21 @@ class MockDwarfDelegate : public DWARFExpression::Delegate {
static constexpr uint16_t DEFAULT_DWARF_VERSION = 5;
static MockDwarfDelegate Dwarf5() { return MockDwarfDelegate(5); }
static MockDwarfDelegate Dwarf2() { return MockDwarfDelegate(2); }
+ static MockDwarfDelegate Dwarf64() {
+ return MockDwarfDelegate(5, llvm::dwarf::DWARF64);
+ }
MockDwarfDelegate() : MockDwarfDelegate(DEFAULT_DWARF_VERSION) {}
- explicit MockDwarfDelegate(uint16_t version) : m_dwarf_version(version) {}
+ explicit MockDwarfDelegate(uint16_t version,
+ llvm::dwarf::DwarfFormat dwarf_format =
+ llvm::dwarf::DWARF32)
+ : m_dwarf_version(version),
+ m_dwarf_format(dwarf_format) {}
uint16_t GetVersion() const override { return m_dwarf_version; }
+ llvm::dwarf::DwarfFormat GetDwarfFormat() const override {
+ return m_dwarf_format;
+ }
dw_addr_t GetBaseAddress() const override { return 0; }
@@ -83,6 +93,7 @@ class MockDwarfDelegate : public DWARFExpression::Delegate {
private:
uint16_t m_dwarf_version;
+ llvm::dwarf::DwarfFormat m_dwarf_format;
};
/// Mock memory implementation for testing.
@@ -1020,17 +1031,30 @@ TEST(DWARFExpression, DW_OP_call_ref_unhandled) {
"unhandled opcode DW_OP_call_ref in DWARFExpression"));
}
-TEST(DWARFExpression, DW_OP_implicit_pointer_unimplemented) {
- EXPECT_THAT_EXPECTED(
- Evaluate({DW_OP_implicit_pointer, 0x00, 0x00, 0x00, 0x00, 0x00}),
- llvm::Failed());
-}
-
-TEST(DWARFExpression, DW_OP_GNU_implicit_pointer_unhandled) {
- EXPECT_THAT_EXPECTED(
- Evaluate({DW_OP_GNU_implicit_pointer, 0x00, 0x00, 0x00, 0x00, 0x00}),
- llvm::FailedWithMessage(
- "unhandled opcode DW_OP_GNU_implicit_pointer in DWARFExpression"));
+TEST(DWARFExpression, DW_OP_implicit_pointer) {
+ MockDwarfDelegate dwarf32 = MockDwarfDelegate::Dwarf5();
+ llvm::Expected<Value> result = Evaluate(
+ {DW_OP_implicit_pointer, 0x34, 0x12, 0x00, 0x00, 0x00}, {}, &dwarf32);
+ ASSERT_THAT_EXPECTED(result, llvm::Succeeded());
+ ASSERT_TRUE(result->IsImplicitPointer());
+ Value::ImplicitPointerInfo implicit_pointer =
+ result->GetImplicitPointerInfo();
+ EXPECT_EQ(implicit_pointer.die_offset, 0x1234u);
+ EXPECT_EQ(implicit_pointer.byte_offset, 0);
+}
+
+TEST(DWARFExpression, DW_OP_implicit_pointer_DWARF64) {
+ MockDwarfDelegate dwarf64 = MockDwarfDelegate::Dwarf64();
+ llvm::Expected<Value> result =
+ Evaluate({DW_OP_implicit_pointer, 0x78, 0x56, 0x34, 0x12, 0x00, 0x00,
+ 0x00, 0x00, 0x02},
+ {}, &dwarf64);
+ ASSERT_THAT_EXPECTED(result, llvm::Succeeded());
+ ASSERT_TRUE(result->IsImplicitPointer());
+ Value::ImplicitPointerInfo implicit_pointer =
+ result->GetImplicitPointerInfo();
+ EXPECT_EQ(implicit_pointer.die_offset, 0x12345678u);
+ EXPECT_EQ(implicit_pointer.byte_offset, 2);
}
TEST(DWARFExpression, DW_OP_const_type_unhandled) {
>From 787bfa924d07906e298da2334abac717e5d8b029 Mon Sep 17 00:00:00 2001
From: shijinrui <shijinrui at bytedance.com>
Date: Tue, 23 Jun 2026 17:48:35 +0800
Subject: [PATCH 2/3] fix format
---
lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h | 10 +++++-----
lldb/source/ValueObject/ValueObject.cpp | 6 +++---
lldb/unittests/Expression/DWARFExpressionTest.cpp | 9 ++++-----
3 files changed, 12 insertions(+), 13 deletions(-)
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
index 32f646ecc79c7..067dd2a660ead 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -136,11 +136,11 @@ class SymbolFileDWARF : public SymbolFileCommon {
size_t ParseVariablesForContext(const SymbolContext &sc) override;
- lldb::ValueObjectSP
- ResolveImplicitPointer(uint64_t die_offset, int64_t byte_offset,
- CompilerType pointee_type,
- ExecutionContextScope *exe_scope,
- Variable *context_var);
+ lldb::ValueObjectSP ResolveImplicitPointer(uint64_t die_offset,
+ int64_t byte_offset,
+ CompilerType pointee_type,
+ ExecutionContextScope *exe_scope,
+ Variable *context_var);
std::optional<ArrayInfo>
GetDynamicArrayInfoForUID(lldb::user_id_t type_uid,
diff --git a/lldb/source/ValueObject/ValueObject.cpp b/lldb/source/ValueObject/ValueObject.cpp
index afd65ac6b0805..357cc88058c70 100644
--- a/lldb/source/ValueObject/ValueObject.cpp
+++ b/lldb/source/ValueObject/ValueObject.cpp
@@ -53,8 +53,8 @@
#include "lldb/lldb-enumerations.h"
#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/Casting.h"
+#include "llvm/Support/Compiler.h"
#include <algorithm>
#include <atomic>
@@ -2860,8 +2860,8 @@ ValueObjectSP ValueObject::Dereference(Status &error) {
}
ValueObjectSP result_sp = dwarf_symbol_file->ResolveImplicitPointer(
- implicit_pointer.die_offset, implicit_pointer.byte_offset,
- pointee_type, exe_ctx.GetBestExecutionContextScope(), GetVariable().get());
+ implicit_pointer.die_offset, implicit_pointer.byte_offset, pointee_type,
+ exe_ctx.GetBestExecutionContextScope(), GetVariable().get());
if (!result_sp) {
error = Status::FromErrorStringWithFormat(
"cannot resolve DW_OP_implicit_pointer target DIE 0x%" PRIx64,
diff --git a/lldb/unittests/Expression/DWARFExpressionTest.cpp b/lldb/unittests/Expression/DWARFExpressionTest.cpp
index 433433bb0d186..75a87ced8438c 100644
--- a/lldb/unittests/Expression/DWARFExpressionTest.cpp
+++ b/lldb/unittests/Expression/DWARFExpressionTest.cpp
@@ -53,11 +53,10 @@ class MockDwarfDelegate : public DWARFExpression::Delegate {
}
MockDwarfDelegate() : MockDwarfDelegate(DEFAULT_DWARF_VERSION) {}
- explicit MockDwarfDelegate(uint16_t version,
- llvm::dwarf::DwarfFormat dwarf_format =
- llvm::dwarf::DWARF32)
- : m_dwarf_version(version),
- m_dwarf_format(dwarf_format) {}
+ explicit MockDwarfDelegate(
+ uint16_t version,
+ llvm::dwarf::DwarfFormat dwarf_format = llvm::dwarf::DWARF32)
+ : m_dwarf_version(version), m_dwarf_format(dwarf_format) {}
uint16_t GetVersion() const override { return m_dwarf_version; }
llvm::dwarf::DwarfFormat GetDwarfFormat() const override {
>From c2da33b3ef1d63eaa50ca6db261369e78c678a55 Mon Sep 17 00:00:00 2001
From: shijinrui <shijinrui at bytedance.com>
Date: Tue, 23 Jun 2026 18:56:35 +0800
Subject: [PATCH 3/3] fix
---
lldb/include/lldb/Symbol/SymbolFile.h | 5 +++++
.../SymbolFile/DWARF/SymbolFileDWARF.cpp | 4 ++--
.../Plugins/SymbolFile/DWARF/SymbolFileDWARF.h | 2 +-
lldb/source/ValueObject/ValueObject.cpp | 18 +++++-------------
4 files changed, 13 insertions(+), 16 deletions(-)
diff --git a/lldb/include/lldb/Symbol/SymbolFile.h b/lldb/include/lldb/Symbol/SymbolFile.h
index ae6504c016d7b..dd11c4a36ab33 100644
--- a/lldb/include/lldb/Symbol/SymbolFile.h
+++ b/lldb/include/lldb/Symbol/SymbolFile.h
@@ -207,6 +207,11 @@ class SymbolFile : public PluginInterface {
std::vector<SourceModule> &imported_modules) = 0;
virtual size_t ParseBlocksRecursive(Function &func) = 0;
virtual size_t ParseVariablesForContext(const SymbolContext &sc) = 0;
+ virtual lldb::ValueObjectSP ResolveImplicitPointer(
+ uint64_t die_offset, int64_t byte_offset, CompilerType pointee_type,
+ ExecutionContextScope *exe_scope, Variable *context_var) {
+ return {};
+ }
virtual Type *ResolveTypeUID(lldb::user_id_t type_uid) = 0;
/// The characteristics of an array type.
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index f72fc002fc4cf..afc1272256746 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -3462,8 +3462,8 @@ lldb::ValueObjectSP SymbolFileDWARF::ResolveImplicitPointer(
eSymbolContextFunction |
eSymbolContextBlock);
- DWARFDIE target_die = DebugInfo().GetDIE(DIERef::Section::DebugInfo,
- die_offset);
+ DWARFDIE target_die =
+ DebugInfo().GetDIE(DIERef::Section::DebugInfo, die_offset);
if (!target_die)
return nullptr;
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
index 067dd2a660ead..7f19142c42575 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -140,7 +140,7 @@ class SymbolFileDWARF : public SymbolFileCommon {
int64_t byte_offset,
CompilerType pointee_type,
ExecutionContextScope *exe_scope,
- Variable *context_var);
+ Variable *context_var) override;
std::optional<ArrayInfo>
GetDynamicArrayInfoForUID(lldb::user_id_t type_uid,
diff --git a/lldb/source/ValueObject/ValueObject.cpp b/lldb/source/ValueObject/ValueObject.cpp
index 357cc88058c70..eff9d9bada125 100644
--- a/lldb/source/ValueObject/ValueObject.cpp
+++ b/lldb/source/ValueObject/ValueObject.cpp
@@ -52,8 +52,6 @@
#include "lldb/ValueObject/ValueObjectVTable.h"
#include "lldb/lldb-enumerations.h"
-#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
-#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include <algorithm>
@@ -2851,17 +2849,11 @@ ValueObjectSP ValueObject::Dereference(Status &error) {
ExecutionContext exe_ctx(GetExecutionContextRef());
Value::ImplicitPointerInfo implicit_pointer =
m_value.GetImplicitPointerInfo();
- auto *dwarf_symbol_file = llvm::dyn_cast<plugin::dwarf::SymbolFileDWARF>(
- symbol_file->GetBackingSymbolFile());
- if (!dwarf_symbol_file) {
- error = Status::FromErrorString(
- "cannot resolve DW_OP_implicit_pointer without DWARF symbol file");
- return ValueObjectSP();
- }
-
- ValueObjectSP result_sp = dwarf_symbol_file->ResolveImplicitPointer(
- implicit_pointer.die_offset, implicit_pointer.byte_offset, pointee_type,
- exe_ctx.GetBestExecutionContextScope(), GetVariable().get());
+ ValueObjectSP result_sp =
+ symbol_file->GetBackingSymbolFile()->ResolveImplicitPointer(
+ implicit_pointer.die_offset, implicit_pointer.byte_offset,
+ pointee_type, exe_ctx.GetBestExecutionContextScope(),
+ GetVariable().get());
if (!result_sp) {
error = Status::FromErrorStringWithFormat(
"cannot resolve DW_OP_implicit_pointer target DIE 0x%" PRIx64,
More information about the lldb-commits
mailing list