https://github.com/Thrrreeee updated https://github.com/llvm/llvm-project/pull/203182
>From e50ddd754233924e97414746c3796c733e3a7df7 Mon Sep 17 00:00:00 2001 From: shijinrui <[email protected]> Date: Tue, 23 Jun 2026 17:42:32 +0800 Subject: [PATCH 1/2] 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,"",@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,"",@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 <[email protected]> Date: Tue, 23 Jun 2026 17:48:35 +0800 Subject: [PATCH 2/2] 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 { _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
