Index: include/lldb/Expression/DWARFExpression.h =================================================================== --- include/lldb/Expression/DWARFExpression.h +++ include/lldb/Expression/DWARFExpression.h @@ -18,6 +18,7 @@ #include class DWARFUnit; +class DWARFDIE; namespace lldb_private { @@ -281,9 +282,9 @@ /// \param[in] reg_set /// The call-frame-info style register kind. /// - /// \param[in] initial_value_ptr - /// A value to put on top of the interpreter stack before evaluating - /// the expression, if the expression is parametrized. Can be NULL. + /// \param[in] stack + /// interpreter stack for evaluation of dwarf expression. It is shared + /// between calls in case of adding/removing entries from stack. /// /// \param[in] result /// A value into which the result of evaluating the expression is @@ -300,9 +301,15 @@ DWARFUnit *dwarf_cu, const lldb::offset_t offset, const lldb::offset_t length, const lldb::RegisterKind reg_set, - const Value *initial_value_ptr, - const Value *object_address_ptr, Value &result, - Status *error_ptr); + const Value *object_address_ptr, + std::vector &stack, Value &result, + Status *error_ptr, bool expression_call = false); + + static bool EvaluateCall(ExecutionContext *exe_ctx, RegisterContext *reg_ctx, + lldb::ModuleSP module_sp, DWARFUnit *dwarf_cu, + DWARFDIE *ref_die, const lldb::RegisterKind reg_set, + const Value *object_address_ptr, + std::vector &stack, Status *error_ptr); bool GetExpressionData(DataExtractor &data) const { data = m_data; Index: source/Expression/DWARFExpression.cpp =================================================================== --- source/Expression/DWARFExpression.cpp +++ source/Expression/DWARFExpression.cpp @@ -1248,6 +1248,9 @@ const Value *object_address_ptr, Value &result, Status *error_ptr) const { ModuleSP module_sp = m_module_wp.lock(); + std::vector stack; + if (initial_value_ptr) + stack.push_back(*initial_value_ptr); if (IsLocationList()) { lldb::offset_t offset = 0; @@ -1293,8 +1296,7 @@ if (length > 0 && lo_pc <= pc && pc < hi_pc) { return DWARFExpression::Evaluate( exe_ctx, reg_ctx, module_sp, m_data, m_dwarf_cu, offset, length, - m_reg_kind, initial_value_ptr, object_address_ptr, result, - error_ptr); + m_reg_kind, object_address_ptr, stack, result, error_ptr); } offset += length; } @@ -1307,7 +1309,7 @@ // Not a location list, just a single expression. return DWARFExpression::Evaluate( exe_ctx, reg_ctx, module_sp, m_data, m_dwarf_cu, 0, m_data.GetByteSize(), - m_reg_kind, initial_value_ptr, object_address_ptr, result, error_ptr); + m_reg_kind, object_address_ptr, stack, result, error_ptr); } bool DWARFExpression::Evaluate( @@ -1315,8 +1317,8 @@ lldb::ModuleSP module_sp, const DataExtractor &opcodes, DWARFUnit *dwarf_cu, const lldb::offset_t opcodes_offset, const lldb::offset_t opcodes_length, const lldb::RegisterKind reg_kind, - const Value *initial_value_ptr, const Value *object_address_ptr, - Value &result, Status *error_ptr) { + const Value *object_address_ptr, std::vector &stack, Value &result, + Status *error_ptr, bool expression_call) { if (opcodes_length == 0) { if (error_ptr) @@ -1324,7 +1326,6 @@ "no location, value may have been optimized out"); return false; } - std::vector stack; Process *process = NULL; StackFrame *frame = NULL; @@ -1336,9 +1337,6 @@ if (reg_ctx == NULL && frame) reg_ctx = frame->GetRegisterContext().get(); - if (initial_value_ptr) - stack.push_back(*initial_value_ptr); - lldb::offset_t offset = opcodes_offset; const lldb::offset_t end_offset = opcodes_offset + opcodes_length; Value tmp; @@ -2478,6 +2476,13 @@ // provides a way of describing how large a part of a variable a particular // DWARF expression refers to. case DW_OP_piece: { + if (expression_call) { + if (error_ptr) + error_ptr->SetErrorStringWithFormat( + "dwarf expression call with DW_OP_piece not supported."); + return false; + } + const uint64_t piece_byte_size = opcodes.GetULEB128(&offset); if (piece_byte_size > 0) { @@ -2690,10 +2695,19 @@ // may be used as parameters by the called expression and values left on // the stack by the called expression may be used as return values by prior // agreement between the calling and called expressions. - case DW_OP_call2: - if (error_ptr) - error_ptr->SetErrorString("Unimplemented opcode DW_OP_call2."); - return false; + case DW_OP_call2: { + dw_offset_t die_ref_offset = + opcodes.GetU16(&offset) + dwarf_cu->GetOffset(); + auto ref_die = dwarf_cu->GetDIE(die_ref_offset); + if (!ref_die.IsValid()) { + if (error_ptr) + error_ptr->SetErrorString("opcode DW_OP_call2 reference not found"); + return false; + } + EvaluateCall(exe_ctx, reg_ctx, module_sp, dwarf_cu, &ref_die, reg_kind, + object_address_ptr, stack, error_ptr); + } break; + // OPCODE: DW_OP_call4 // OPERANDS: 1 // uint32_t compile unit relative offset of a DIE @@ -2713,10 +2727,18 @@ // may be used as parameters by the called expression and values left on // the stack by the called expression may be used as return values by prior // agreement between the calling and called expressions. - case DW_OP_call4: - if (error_ptr) - error_ptr->SetErrorString("Unimplemented opcode DW_OP_call4."); - return false; + case DW_OP_call4: { + dw_offset_t die_ref_offset = + opcodes.GetU32(&offset) + dwarf_cu->GetOffset(); + auto ref_die = dwarf_cu->GetDIE(die_ref_offset); + if (!ref_die.IsValid()) { + if (error_ptr) + error_ptr->SetErrorString("opcode DW_OP_call4 reference not found"); + return false; + } + EvaluateCall(exe_ctx, reg_ctx, module_sp, dwarf_cu, &ref_die, reg_kind, + object_address_ptr, stack, error_ptr); + } break; // OPCODE: DW_OP_stack_value // OPERANDS: None @@ -2896,6 +2918,40 @@ return true; // Return true on success } +bool DWARFExpression::EvaluateCall(ExecutionContext *exe_ctx, + RegisterContext *reg_ctx, + ModuleSP module_sp, + DWARFUnit *dwarf_cu, + DWARFDIE *ref_die, + const RegisterKind reg_kind, + const Value *object_address_ptr, + std::vector &stack, + Status *error_ptr) { + if (!ref_die) + return false; + + DWARFAttributes attributes; + const size_t num_attrib = ref_die->GetAttributes(attributes); + if (num_attrib == 0) + return false; + + const uint32_t attr_index = attributes.FindAttributeIndex(DW_AT_location); + if (attr_index == UINT32_MAX) + return false; + + DWARFFormValue form_value; + attributes.ExtractFormValueAtIndex(attr_index, form_value); + + const DWARFDataExtractor &ref_debug_info_data = ref_die->GetData(); + uint32_t location_offset = + form_value.BlockData() - ref_debug_info_data.GetDataStart(); + uint32_t location_length = form_value.Unsigned(); + Value result(0); + return Evaluate(exe_ctx, reg_ctx, module_sp, ref_debug_info_data, dwarf_cu, + location_offset, location_length, reg_kind, + object_address_ptr, stack, result, error_ptr, true); +} + size_t DWARFExpression::LocationListSize(const DWARFUnit *dwarf_cu, const DataExtractor &debug_loc_data, lldb::offset_t offset) { Index: source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -2774,18 +2774,20 @@ break; case DW_AT_data_member_location: if (form_value.BlockData()) { - Value initialValue(0); Value memberOffset(0); const DWARFDataExtractor &debug_info_data = die.GetData(); uint32_t block_length = form_value.Unsigned(); uint32_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart(); + std::vector stack; + stack.push_back(Value(0)); + if (DWARFExpression::Evaluate( nullptr, // ExecutionContext * nullptr, // RegisterContext * module_sp, debug_info_data, die.GetCU(), block_offset, - block_length, eRegisterKindDWARF, &initialValue, - nullptr, memberOffset, nullptr)) { + block_length, eRegisterKindDWARF, nullptr, stack, + memberOffset, nullptr)) { member_byte_offset = memberOffset.ResolveValue(NULL).UInt(); } } else { @@ -3229,14 +3231,17 @@ Value initialValue(0); Value memberOffset(0); const DWARFDataExtractor &debug_info_data = die.GetData(); + std::vector stack; + stack.push_back(Value(0)); + uint32_t block_length = form_value.Unsigned(); uint32_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart(); if (DWARFExpression::Evaluate(nullptr, nullptr, module_sp, debug_info_data, die.GetCU(), block_offset, block_length, - eRegisterKindDWARF, &initialValue, - nullptr, memberOffset, nullptr)) { + eRegisterKindDWARF, nullptr, + stack, memberOffset, nullptr)) { member_byte_offset = memberOffset.ResolveValue(NULL).UInt(); } } else { Index: source/Target/RegisterContext.cpp =================================================================== --- source/Target/RegisterContext.cpp +++ source/Target/RegisterContext.cpp @@ -87,9 +87,10 @@ Value result; Status error; const lldb::offset_t offset = 0; + std::vector stack; if (dwarf_expr.Evaluate(&exe_ctx, this, opcode_ctx, dwarf_data, nullptr, offset, dwarf_opcode_len, eRegisterKindDWARF, nullptr, - nullptr, result, &error)) { + stack, result, &error)) { expr_result = result.GetScalar().SInt(-1); switch (expr_result) { case 0: Index: unittests/Expression/DWARFExpressionTest.cpp =================================================================== --- unittests/Expression/DWARFExpressionTest.cpp +++ unittests/Expression/DWARFExpressionTest.cpp @@ -22,11 +22,12 @@ Value result; Status status; + std::vector stack; if (!DWARFExpression::Evaluate( /*exe_ctx*/ nullptr, /*reg_ctx*/ nullptr, /*opcode_ctx*/ nullptr, extractor, /*dwarf_cu*/ nullptr, /*offset*/ 0, expr.size(), - lldb::eRegisterKindLLDB, /*initial_value_ptr*/ nullptr, - /*object_address_ptr*/ nullptr, result, &status)) + lldb::eRegisterKindLLDB, /*object_address_ptr*/ nullptr, stack, + result, &status)) return status.ToError(); return result.GetScalar();