diff options
Diffstat (limited to 'lldb/source/Expression/DWARFExpression.cpp')
-rw-r--r-- | lldb/source/Expression/DWARFExpression.cpp | 423 |
1 files changed, 145 insertions, 278 deletions
diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp index 3789d9147737..69c84640ef93 100644 --- a/lldb/source/Expression/DWARFExpression.cpp +++ b/lldb/source/Expression/DWARFExpression.cpp @@ -47,22 +47,23 @@ ReadAddressFromDebugAddrSection(const DWARFUnit *dwarf_cu, uint32_t index_size = dwarf_cu->GetAddressByteSize(); dw_offset_t addr_base = dwarf_cu->GetAddrBase(); lldb::offset_t offset = addr_base + index * index_size; - return dwarf_cu->GetSymbolFileDWARF() - .GetDWARFContext() - .getOrLoadAddrData() - .GetMaxU64(&offset, index_size); + const DWARFDataExtractor &data = + dwarf_cu->GetSymbolFileDWARF().GetDWARFContext().getOrLoadAddrData(); + if (data.ValidOffsetForDataOfSize(offset, index_size)) + return data.GetMaxU64_unchecked(&offset, index_size); + return LLDB_INVALID_ADDRESS; } // DWARFExpression constructor DWARFExpression::DWARFExpression() : m_module_wp(), m_data(), m_dwarf_cu(nullptr), - m_reg_kind(eRegisterKindDWARF), m_loclist_slide(LLDB_INVALID_ADDRESS) {} + m_reg_kind(eRegisterKindDWARF) {} DWARFExpression::DWARFExpression(lldb::ModuleSP module_sp, const DataExtractor &data, const DWARFUnit *dwarf_cu) : m_module_wp(), m_data(data), m_dwarf_cu(dwarf_cu), - m_reg_kind(eRegisterKindDWARF), m_loclist_slide(LLDB_INVALID_ADDRESS) { + m_reg_kind(eRegisterKindDWARF) { if (module_sp) m_module_wp = module_sp; } @@ -84,18 +85,18 @@ void DWARFExpression::UpdateValue(uint64_t const_value, m_data.SetAddressByteSize(addr_byte_size); } -void DWARFExpression::DumpLocation(Stream *s, lldb::offset_t offset, - lldb::offset_t length, +void DWARFExpression::DumpLocation(Stream *s, const DataExtractor &data, lldb::DescriptionLevel level, ABI *abi) const { - llvm::DWARFExpression(DataExtractor(m_data, offset, length).GetAsLLVM(), - llvm::dwarf::DWARF_VERSION, m_data.GetAddressByteSize()) + llvm::DWARFExpression(data.GetAsLLVM(), llvm::dwarf::DWARF_VERSION, + data.GetAddressByteSize()) .print(s->AsRawOstream(), abi ? &abi->GetMCRegisterInfo() : nullptr, nullptr); } -void DWARFExpression::SetLocationListSlide(addr_t slide) { - m_loclist_slide = slide; +void DWARFExpression::SetLocationListAddresses(addr_t cu_file_addr, + addr_t func_file_addr) { + m_loclist_addresses = LoclistAddresses{cu_file_addr, func_file_addr}; } int DWARFExpression::GetRegisterKind() { return m_reg_kind; } @@ -105,7 +106,26 @@ void DWARFExpression::SetRegisterKind(RegisterKind reg_kind) { } bool DWARFExpression::IsLocationList() const { - return m_loclist_slide != LLDB_INVALID_ADDRESS; + return bool(m_loclist_addresses); +} + +namespace { +/// Implement enough of the DWARFObject interface in order to be able to call +/// DWARFLocationTable::dumpLocationList. We don't have access to a real +/// DWARFObject here because DWARFExpression is used in non-DWARF scenarios too. +class DummyDWARFObject final: public llvm::DWARFObject { +public: + DummyDWARFObject(bool IsLittleEndian) : IsLittleEndian(IsLittleEndian) {} + + bool isLittleEndian() const override { return IsLittleEndian; } + + llvm::Optional<llvm::RelocAddrEntry> find(const llvm::DWARFSection &Sec, + uint64_t Pos) const override { + return llvm::None; + } +private: + bool IsLittleEndian; +}; } void DWARFExpression::GetDescription(Stream *s, lldb::DescriptionLevel level, @@ -114,47 +134,19 @@ void DWARFExpression::GetDescription(Stream *s, lldb::DescriptionLevel level, if (IsLocationList()) { // We have a location list lldb::offset_t offset = 0; - uint32_t count = 0; - addr_t curr_base_addr = location_list_base_addr; - while (m_data.ValidOffset(offset)) { - addr_t begin_addr_offset = LLDB_INVALID_ADDRESS; - addr_t end_addr_offset = LLDB_INVALID_ADDRESS; - if (!AddressRangeForLocationListEntry(m_dwarf_cu, m_data, &offset, - begin_addr_offset, end_addr_offset)) - break; + std::unique_ptr<llvm::DWARFLocationTable> loctable_up = + m_dwarf_cu->GetLocationTable(m_data); - if (begin_addr_offset == 0 && end_addr_offset == 0) - break; + llvm::MCRegisterInfo *MRI = abi ? &abi->GetMCRegisterInfo() : nullptr; - if (begin_addr_offset < end_addr_offset) { - if (count > 0) - s->PutCString(", "); - VMRange addr_range(curr_base_addr + begin_addr_offset, - curr_base_addr + end_addr_offset); - addr_range.Dump(s, 0, 8); - s->PutChar('{'); - lldb::offset_t location_length = m_data.GetU16(&offset); - DumpLocation(s, offset, location_length, level, abi); - s->PutChar('}'); - offset += location_length; - } else { - if ((m_data.GetAddressByteSize() == 4 && - (begin_addr_offset == UINT32_MAX)) || - (m_data.GetAddressByteSize() == 8 && - (begin_addr_offset == UINT64_MAX))) { - curr_base_addr = end_addr_offset + location_list_base_addr; - // We have a new base address - if (count > 0) - s->PutCString(", "); - *s << "base_addr = " << end_addr_offset; - } - } - - count++; - } + loctable_up->dumpLocationList( + &offset, s->AsRawOstream(), + llvm::object::SectionedAddress{m_loclist_addresses->cu_file_addr}, MRI, + DummyDWARFObject(m_data.GetByteOrder() == eByteOrderLittle), nullptr, + llvm::DIDumpOptions(), s->GetIndentLevel() + 2); } else { // We have a normal location that contains DW_OP location opcodes - DumpLocation(s, 0, m_data.GetByteSize(), level, abi); + DumpLocation(s, m_data, level, abi); } } @@ -477,7 +469,7 @@ bool DWARFExpression::Update_DW_OP_addr(lldb::addr_t file_addr) { m_data.GetByteOrder(), addr_byte_size); // Replace the address in the new buffer - if (encoder.PutMaxU64(offset, addr_byte_size, file_addr) == UINT32_MAX) + if (encoder.PutUnsigned(offset, addr_byte_size, file_addr) == UINT32_MAX) return false; // All went well, so now we can reset the data using a shared pointer to @@ -583,8 +575,8 @@ bool DWARFExpression::LinkThreadLocalStorage( if (linked_file_addr == LLDB_INVALID_ADDRESS) return false; // Replace the address in the new buffer - if (encoder.PutMaxU64(const_offset, const_byte_size, - linked_file_addr) == UINT32_MAX) + if (encoder.PutUnsigned(const_offset, const_byte_size, + linked_file_addr) == UINT32_MAX) return false; } break; @@ -614,102 +606,29 @@ bool DWARFExpression::LinkThreadLocalStorage( return true; } -bool DWARFExpression::LocationListContainsAddress( - lldb::addr_t loclist_base_addr, lldb::addr_t addr) const { - if (addr == LLDB_INVALID_ADDRESS) +bool DWARFExpression::LocationListContainsAddress(addr_t func_load_addr, + lldb::addr_t addr) const { + if (func_load_addr == LLDB_INVALID_ADDRESS || addr == LLDB_INVALID_ADDRESS) return false; - if (IsLocationList()) { - lldb::offset_t offset = 0; - - if (loclist_base_addr == LLDB_INVALID_ADDRESS) - return false; - - while (m_data.ValidOffset(offset)) { - // We need to figure out what the value is for the location. - addr_t lo_pc = LLDB_INVALID_ADDRESS; - addr_t hi_pc = LLDB_INVALID_ADDRESS; - if (!AddressRangeForLocationListEntry(m_dwarf_cu, m_data, &offset, lo_pc, - hi_pc)) - break; - - if (lo_pc == 0 && hi_pc == 0) - break; - - if ((m_data.GetAddressByteSize() == 4 && (lo_pc == UINT32_MAX)) || - (m_data.GetAddressByteSize() == 8 && (lo_pc == UINT64_MAX))) { - loclist_base_addr = hi_pc + m_loclist_slide; - continue; - } - lo_pc += loclist_base_addr - m_loclist_slide; - hi_pc += loclist_base_addr - m_loclist_slide; - - if (lo_pc <= addr && addr < hi_pc) - return true; + if (!IsLocationList()) + return false; - offset += m_data.GetU16(&offset); - } - } - return false; + return GetLocationExpression(func_load_addr, addr) != llvm::None; } -bool DWARFExpression::GetLocation(addr_t base_addr, addr_t pc, - lldb::offset_t &offset, - lldb::offset_t &length) { - offset = 0; +bool DWARFExpression::DumpLocationForAddress(Stream *s, + lldb::DescriptionLevel level, + addr_t func_load_addr, + addr_t address, ABI *abi) { if (!IsLocationList()) { - length = m_data.GetByteSize(); + DumpLocation(s, m_data, level, abi); return true; } - - if (base_addr != LLDB_INVALID_ADDRESS && pc != LLDB_INVALID_ADDRESS) { - addr_t curr_base_addr = base_addr; - - while (m_data.ValidOffset(offset)) { - // We need to figure out what the value is for the location. - addr_t lo_pc = LLDB_INVALID_ADDRESS; - addr_t hi_pc = LLDB_INVALID_ADDRESS; - if (!AddressRangeForLocationListEntry(m_dwarf_cu, m_data, &offset, lo_pc, - hi_pc)) - break; - - if (lo_pc == 0 && hi_pc == 0) - break; - - if ((m_data.GetAddressByteSize() == 4 && (lo_pc == UINT32_MAX)) || - (m_data.GetAddressByteSize() == 8 && (lo_pc == UINT64_MAX))) { - curr_base_addr = hi_pc + m_loclist_slide; - continue; - } - - lo_pc += curr_base_addr - m_loclist_slide; - hi_pc += curr_base_addr - m_loclist_slide; - - length = m_data.GetU16(&offset); - - if (length > 0 && lo_pc <= pc && pc < hi_pc) - return true; - - offset += length; - } - } - offset = LLDB_INVALID_OFFSET; - length = 0; - return false; -} - -bool DWARFExpression::DumpLocationForAddress(Stream *s, - lldb::DescriptionLevel level, - addr_t base_addr, addr_t address, - ABI *abi) { - lldb::offset_t offset = 0; - lldb::offset_t length = 0; - - if (GetLocation(base_addr, address, offset, length)) { - if (length > 0) { - DumpLocation(s, offset, length, level, abi); - return true; - } + if (llvm::Optional<DataExtractor> expr = + GetLocationExpression(func_load_addr, address)) { + DumpLocation(s, *expr, level, abi); + return true; } return false; } @@ -830,6 +749,8 @@ static bool Evaluate_DW_OP_entry_value(std::vector<Value> &stack, CallEdge *call_edge = nullptr; ModuleList &modlist = target.GetImages(); + ExecutionContext parent_exe_ctx = *exe_ctx; + parent_exe_ctx.SetFrameSP(parent_frame); if (!parent_frame->IsArtificial()) { // If the parent frame is not artificial, the current activation may be // produced by an ambiguous tail call. In this case, refuse to proceed. @@ -841,7 +762,7 @@ static bool Evaluate_DW_OP_entry_value(std::vector<Value> &stack, return_pc, parent_func->GetName()); return false; } - Function *callee_func = call_edge->GetCallee(modlist); + Function *callee_func = call_edge->GetCallee(modlist, parent_exe_ctx); if (callee_func != current_func) { LLDB_LOG(log, "Evaluate_DW_OP_entry_value: ambiguous call sequence, " "can't find real parent frame"); @@ -851,9 +772,9 @@ static bool Evaluate_DW_OP_entry_value(std::vector<Value> &stack, // The StackFrameList solver machinery has deduced that an unambiguous tail // call sequence that produced the current activation. The first edge in // the parent that points to the current function must be valid. - for (CallEdge &edge : parent_func->GetTailCallingEdges()) { - if (edge.GetCallee(modlist) == current_func) { - call_edge = &edge; + for (auto &edge : parent_func->GetTailCallingEdges()) { + if (edge->GetCallee(modlist, parent_exe_ctx) == current_func) { + call_edge = edge.get(); break; } } @@ -907,8 +828,6 @@ static bool Evaluate_DW_OP_entry_value(std::vector<Value> &stack, // TODO: Add support for DW_OP_push_object_address within a DW_OP_entry_value // subexpresion whenever llvm does. Value result; - ExecutionContext parent_exe_ctx = *exe_ctx; - parent_exe_ctx.SetFrameSP(parent_frame); const DWARFExpression ¶m_expr = matched_param->LocationInCaller; if (!param_expr.Evaluate(&parent_exe_ctx, parent_frame->GetRegisterContext().get(), @@ -936,14 +855,13 @@ bool DWARFExpression::Evaluate(ExecutionContextScope *exe_scope, bool DWARFExpression::Evaluate(ExecutionContext *exe_ctx, RegisterContext *reg_ctx, - lldb::addr_t loclist_base_load_addr, + lldb::addr_t func_load_addr, const Value *initial_value_ptr, const Value *object_address_ptr, Value &result, Status *error_ptr) const { ModuleSP module_sp = m_module_wp.lock(); if (IsLocationList()) { - lldb::offset_t offset = 0; addr_t pc; StackFrame *frame = nullptr; if (reg_ctx) @@ -958,45 +876,18 @@ bool DWARFExpression::Evaluate(ExecutionContext *exe_ctx, pc = reg_ctx_sp->GetPC(); } - if (loclist_base_load_addr != LLDB_INVALID_ADDRESS) { + if (func_load_addr != LLDB_INVALID_ADDRESS) { if (pc == LLDB_INVALID_ADDRESS) { if (error_ptr) error_ptr->SetErrorString("Invalid PC in frame."); return false; } - addr_t curr_loclist_base_load_addr = loclist_base_load_addr; - - while (m_data.ValidOffset(offset)) { - // We need to figure out what the value is for the location. - addr_t lo_pc = LLDB_INVALID_ADDRESS; - addr_t hi_pc = LLDB_INVALID_ADDRESS; - if (!AddressRangeForLocationListEntry(m_dwarf_cu, m_data, &offset, - lo_pc, hi_pc)) - break; - - if (lo_pc == 0 && hi_pc == 0) - break; - - if ((m_data.GetAddressByteSize() == 4 && - (lo_pc == UINT32_MAX)) || - (m_data.GetAddressByteSize() == 8 && - (lo_pc == UINT64_MAX))) { - curr_loclist_base_load_addr = hi_pc + m_loclist_slide; - continue; - } - lo_pc += curr_loclist_base_load_addr - m_loclist_slide; - hi_pc += curr_loclist_base_load_addr - m_loclist_slide; - - uint16_t length = m_data.GetU16(&offset); - - if (length > 0 && lo_pc <= pc && pc < hi_pc) { - return DWARFExpression::Evaluate( - exe_ctx, reg_ctx, module_sp, - DataExtractor(m_data, offset, length), m_dwarf_cu, m_reg_kind, - initial_value_ptr, object_address_ptr, result, error_ptr); - } - offset += length; + if (llvm::Optional<DataExtractor> expr = + GetLocationExpression(func_load_addr, pc)) { + return DWARFExpression::Evaluate( + exe_ctx, reg_ctx, module_sp, *expr, m_dwarf_cu, m_reg_kind, + initial_value_ptr, object_address_ptr, result, error_ptr); } } if (error_ptr) @@ -2655,62 +2546,6 @@ bool DWARFExpression::Evaluate( return true; // Return true on success } -bool DWARFExpression::AddressRangeForLocationListEntry( - const DWARFUnit *dwarf_cu, const DataExtractor &debug_loc_data, - lldb::offset_t *offset_ptr, lldb::addr_t &low_pc, lldb::addr_t &high_pc) { - if (!debug_loc_data.ValidOffset(*offset_ptr)) - return false; - - DWARFExpression::LocationListFormat format = - dwarf_cu->GetSymbolFileDWARF().GetLocationListFormat(); - switch (format) { - case NonLocationList: - return false; - case RegularLocationList: - low_pc = debug_loc_data.GetAddress(offset_ptr); - high_pc = debug_loc_data.GetAddress(offset_ptr); - return true; - case SplitDwarfLocationList: - case LocLists: - switch (debug_loc_data.GetU8(offset_ptr)) { - case DW_LLE_end_of_list: - return false; - case DW_LLE_startx_endx: { - uint64_t index = debug_loc_data.GetULEB128(offset_ptr); - low_pc = ReadAddressFromDebugAddrSection(dwarf_cu, index); - index = debug_loc_data.GetULEB128(offset_ptr); - high_pc = ReadAddressFromDebugAddrSection(dwarf_cu, index); - return true; - } - case DW_LLE_startx_length: { - uint64_t index = debug_loc_data.GetULEB128(offset_ptr); - low_pc = ReadAddressFromDebugAddrSection(dwarf_cu, index); - uint64_t length = (format == LocLists) - ? debug_loc_data.GetULEB128(offset_ptr) - : debug_loc_data.GetU32(offset_ptr); - high_pc = low_pc + length; - return true; - } - case DW_LLE_start_length: { - low_pc = debug_loc_data.GetAddress(offset_ptr); - high_pc = low_pc + debug_loc_data.GetULEB128(offset_ptr); - return true; - } - case DW_LLE_start_end: { - low_pc = debug_loc_data.GetAddress(offset_ptr); - high_pc = debug_loc_data.GetAddress(offset_ptr); - return true; - } - default: - // Not supported entry type - lldbassert(false && "Not supported location list type"); - return false; - } - } - assert(false && "Not supported location list type"); - return false; -} - static bool print_dwarf_exp_op(Stream &s, const DataExtractor &data, lldb::offset_t *offset_ptr, int address_size, int dwarf_ref_size) { @@ -2929,8 +2764,9 @@ void DWARFExpression::PrintDWARFLocationList( s.PutCString("\n "); s.Indent(); if (cu) - s.AddressRange(start_addr + base_addr, end_addr + base_addr, - cu->GetAddressByteSize(), nullptr, ": "); + DumpAddressRange(s.AsRawOstream(), start_addr + base_addr, + end_addr + base_addr, cu->GetAddressByteSize(), nullptr, + ": "); uint32_t loc_length = debug_loc_data.GetU16(&offset); DataExtractor locationData(debug_loc_data, offset, loc_length); @@ -2939,56 +2775,87 @@ void DWARFExpression::PrintDWARFLocationList( } } -bool DWARFExpression::GetOpAndEndOffsets(StackFrame &frame, - lldb::offset_t &op_offset, - lldb::offset_t &end_offset) { - SymbolContext sc = frame.GetSymbolContext(eSymbolContextFunction); - if (!sc.function) { - return false; - } - - addr_t loclist_base_file_addr = - sc.function->GetAddressRange().GetBaseAddress().GetFileAddress(); - if (loclist_base_file_addr == LLDB_INVALID_ADDRESS) { - return false; - } - - addr_t pc_file_addr = frame.GetFrameCodeAddress().GetFileAddress(); - lldb::offset_t opcodes_offset, opcodes_length; - if (!GetLocation(loclist_base_file_addr, pc_file_addr, opcodes_offset, - opcodes_length)) { - return false; - } - - if (opcodes_length == 0) { - return false; - } +static DataExtractor ToDataExtractor(const llvm::DWARFLocationExpression &loc, + ByteOrder byte_order, uint32_t addr_size) { + auto buffer_sp = + std::make_shared<DataBufferHeap>(loc.Expr.data(), loc.Expr.size()); + return DataExtractor(buffer_sp, byte_order, addr_size); +} - op_offset = opcodes_offset; - end_offset = opcodes_offset + opcodes_length; - return true; +llvm::Optional<DataExtractor> +DWARFExpression::GetLocationExpression(addr_t load_function_start, + addr_t addr) const { + Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS); + + std::unique_ptr<llvm::DWARFLocationTable> loctable_up = + m_dwarf_cu->GetLocationTable(m_data); + llvm::Optional<DataExtractor> result; + uint64_t offset = 0; + auto lookup_addr = + [&](uint32_t index) -> llvm::Optional<llvm::object::SectionedAddress> { + addr_t address = ReadAddressFromDebugAddrSection(m_dwarf_cu, index); + if (address == LLDB_INVALID_ADDRESS) + return llvm::None; + return llvm::object::SectionedAddress{address}; + }; + auto process_list = [&](llvm::Expected<llvm::DWARFLocationExpression> loc) { + if (!loc) { + LLDB_LOG_ERROR(log, loc.takeError(), "{0}"); + return true; + } + if (loc->Range) { + // This relocates low_pc and high_pc by adding the difference between the + // function file address, and the actual address it is loaded in memory. + addr_t slide = load_function_start - m_loclist_addresses->func_file_addr; + loc->Range->LowPC += slide; + loc->Range->HighPC += slide; + + if (loc->Range->LowPC <= addr && addr < loc->Range->HighPC) + result = ToDataExtractor(*loc, m_data.GetByteOrder(), + m_data.GetAddressByteSize()); + } + return !result; + }; + llvm::Error E = loctable_up->visitAbsoluteLocationList( + offset, llvm::object::SectionedAddress{m_loclist_addresses->cu_file_addr}, + lookup_addr, process_list); + if (E) + LLDB_LOG_ERROR(log, std::move(E), "{0}"); + return result; } bool DWARFExpression::MatchesOperand(StackFrame &frame, const Instruction::Operand &operand) { using namespace OperandMatchers; - lldb::offset_t op_offset; - lldb::offset_t end_offset; - if (!GetOpAndEndOffsets(frame, op_offset, end_offset)) { - return false; - } - - if (!m_data.ValidOffset(op_offset) || op_offset >= end_offset) { - return false; - } - RegisterContextSP reg_ctx_sp = frame.GetRegisterContext(); if (!reg_ctx_sp) { return false; } - DataExtractor opcodes = m_data; + DataExtractor opcodes; + if (IsLocationList()) { + SymbolContext sc = frame.GetSymbolContext(eSymbolContextFunction); + if (!sc.function) + return false; + + addr_t load_function_start = + sc.function->GetAddressRange().GetBaseAddress().GetFileAddress(); + if (load_function_start == LLDB_INVALID_ADDRESS) + return false; + + addr_t pc = frame.GetFrameCodeAddress().GetLoadAddress( + frame.CalculateTarget().get()); + + if (llvm::Optional<DataExtractor> expr = GetLocationExpression(load_function_start, pc)) + opcodes = std::move(*expr); + else + return false; + } else + opcodes = m_data; + + + lldb::offset_t op_offset = 0; uint8_t opcode = opcodes.GetU8(&op_offset); if (opcode == DW_OP_fbreg) { |