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