Index: include/lldb/Expression/DWARFExpression.h =================================================================== --- include/lldb/Expression/DWARFExpression.h +++ include/lldb/Expression/DWARFExpression.h @@ -386,15 +386,27 @@ lldb::DescriptionLevel level, ABI *abi) const; bool GetLocation(lldb::addr_t base_addr, lldb::addr_t pc, - lldb::offset_t &offset, lldb::offset_t &len); + lldb::offset_t &offset, lldb::offset_t &len) const; static bool AddressRangeForLocationListEntry( const DWARFCompileUnit *dwarf_cu, const DataExtractor &debug_loc_data, - lldb::offset_t *offset_ptr, lldb::addr_t &low_pc, lldb::addr_t &high_pc); + lldb::offset_t *offset_ptr, lldb::addr_t &base_addr, lldb::addr_t &low_pc, + lldb::addr_t &high_pc); bool GetOpAndEndOffsets(StackFrame &frame, lldb::offset_t &op_offset, lldb::offset_t &end_offset); + // Iterate over all location list entries in this DWARF location expression. + // The specified callback will be called once for each entry with passing in + // the high_pc, low_pc and offset for that entry. The callback should return + // true to continue iterating while false to stop iterating after the current + // location list item. The function returns the number of bytes processed + // from the location list during the iteration. + static lldb::offset_t IterateLocationListEntries( + const DWARFCompileUnit *dwarf_cu, const DataExtractor &debug_loc_data, + lldb::addr_t base_addr, + std::function callback); + //------------------------------------------------------------------ /// Classes that inherit from DWARFExpression can see and modify these //------------------------------------------------------------------ Index: source/Expression/DWARFExpression.cpp =================================================================== --- source/Expression/DWARFExpression.cpp +++ source/Expression/DWARFExpression.cpp @@ -52,6 +52,18 @@ &offset, index_size); } +static dw_addr_t GetBaseAddressMarker(uint32_t addr_size) { + switch (addr_size) { + case 2: + return 0xffff; + case 4: + return 0xffffffff; + case 8: + return 0xffffffffffffffff; + } + llvm_unreachable("GetBaseAddressMarker unsupported address size."); +} + //---------------------------------------------------------------------- // DWARFExpression constructor //---------------------------------------------------------------------- @@ -604,46 +616,23 @@ addr_t location_list_base_addr, ABI *abi) const { 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; - - if (begin_addr_offset == 0 && end_addr_offset == 0) - break; - - 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; - } - } - + auto callback = [&](lldb::addr_t low_pc, lldb::addr_t high_pc, + lldb::offset_t offset) { + if (count > 0) + s->PutCString(", "); + + VMRange addr_range(low_pc, high_pc); + 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('}'); count++; - } + return true; + }; + IterateLocationListEntries(m_dwarf_cu, m_data, location_list_base_addr, + callback); } else { // We have a normal location that contains DW_OP location opcodes DumpLocation(s, 0, m_data.GetByteSize(), level, abi); @@ -1154,75 +1143,55 @@ bool DWARFExpression::LocationListContainsAddress( lldb::addr_t loclist_base_addr, lldb::addr_t addr) const { - if (addr == LLDB_INVALID_ADDRESS) + if (addr == LLDB_INVALID_ADDRESS || loclist_base_addr == LLDB_INVALID_ADDRESS) return false; - if (IsLocationList()) { - lldb::offset_t offset = 0; + if (!IsLocationList()) + return false; - if (loclist_base_addr == LLDB_INVALID_ADDRESS) + bool does_contain = false; + auto callback = [&](lldb::addr_t low_pc, lldb::addr_t high_pc, + lldb::offset_t offset) { + if (addr >= low_pc && addr < high_pc) { + does_contain = true; 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; - - 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; - - offset += m_data.GetU16(&offset); } - } - return false; + return true; + }; + IterateLocationListEntries(m_dwarf_cu, m_data, + loclist_base_addr - m_loclist_slide, callback); + return does_contain; } bool DWARFExpression::GetLocation(addr_t base_addr, addr_t pc, lldb::offset_t &offset, - lldb::offset_t &length) { + lldb::offset_t &length) const { offset = 0; if (!IsLocationList()) { length = m_data.GetByteSize(); 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; - - lo_pc += curr_base_addr - m_loclist_slide; - hi_pc += curr_base_addr - m_loclist_slide; + if (base_addr == LLDB_INVALID_ADDRESS || pc == LLDB_INVALID_ADDRESS) { + offset = LLDB_INVALID_OFFSET; + length = 0; + return false; + } + bool does_contain = false; + auto callback = [&](lldb::addr_t low_pc, lldb::addr_t high_pc, + lldb::offset_t data_offset) { + if (pc >= low_pc && pc < high_pc) { + offset = data_offset; length = m_data.GetU16(&offset); - - if (length > 0 && lo_pc <= pc && pc < hi_pc) - return true; - - offset += length; + does_contain = true; + return false; } - } - offset = LLDB_INVALID_OFFSET; - length = 0; - return false; + return true; + }; + IterateLocationListEntries(m_dwarf_cu, m_data, base_addr - m_loclist_slide, + callback); + return does_contain; } bool DWARFExpression::DumpLocationForAddress(Stream *s, @@ -1260,7 +1229,6 @@ ModuleSP module_sp = m_module_wp.lock(); if (IsLocationList()) { - lldb::offset_t offset = 0; addr_t pc; StackFrame *frame = NULL; if (reg_ctx) @@ -1282,33 +1250,15 @@ 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; - - 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, m_data, m_dwarf_cu, offset, length, - m_reg_kind, initial_value_ptr, object_address_ptr, result, - error_ptr); - } - offset += length; + lldb::offset_t offset = 0, length = 0; + if (GetLocation(loclist_base_load_addr, pc, offset, length)) { + 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); } } + if (error_ptr) error_ptr->SetErrorString("variable not available"); return false; @@ -2987,64 +2937,90 @@ size_t DWARFExpression::LocationListSize(const DWARFCompileUnit *dwarf_cu, const DataExtractor &debug_loc_data, lldb::offset_t offset) { - const lldb::offset_t debug_loc_offset = offset; - while (debug_loc_data.ValidOffset(offset)) { - lldb::addr_t start_addr = LLDB_INVALID_ADDRESS; - lldb::addr_t end_addr = LLDB_INVALID_ADDRESS; - if (!AddressRangeForLocationListEntry(dwarf_cu, debug_loc_data, &offset, - start_addr, end_addr)) - break; - - if (start_addr == 0 && end_addr == 0) - break; - - uint16_t loc_length = debug_loc_data.GetU16(&offset); - offset += loc_length; - } - - if (offset > debug_loc_offset) - return offset - debug_loc_offset; - return 0; + auto callback = [&](lldb::addr_t low_pc, lldb::addr_t high_pc, + lldb::offset_t offset) { return true; }; + return IterateLocationListEntries(dwarf_cu, debug_loc_data, 0, callback); } -bool DWARFExpression::AddressRangeForLocationListEntry( +lldb::offset_t DWARFExpression::IterateLocationListEntries( const DWARFCompileUnit *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; - + lldb::addr_t base_addr, + std::function callback) { switch (dwarf_cu->GetSymbolFileDWARF()->GetLocationListFormat()) { 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: - 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; + return 0; + case RegularLocationList: { + lldb::offset_t offset = 0; + lldb::addr_t base_addr_marker = + GetBaseAddressMarker(dwarf_cu->GetDefaultAddressSize()); + while (debug_loc_data.ValidOffset(offset)) { + lldb::addr_t low_pc = debug_loc_data.GetAddress(&offset); + lldb::addr_t high_pc = debug_loc_data.GetAddress(&offset); + if (low_pc == base_addr_marker) { + base_addr = high_pc; + continue; + } + if (low_pc == 0 && high_pc == 0) + return offset; + + if (!callback(low_pc + base_addr, high_pc + base_addr, offset)) { + return offset + debug_loc_data.GetU16(&offset); + } + offset += debug_loc_data.GetU16(&offset); } - case DW_LLE_startx_length: { - uint64_t index = debug_loc_data.GetULEB128(offset_ptr); - low_pc = ReadAddressFromDebugAddrSection(dwarf_cu, index); - uint32_t length = debug_loc_data.GetU32(offset_ptr); - high_pc = low_pc + length; - return true; + return offset; + } + case SplitDwarfLocationList: { + lldb::offset_t offset = 0; + while (debug_loc_data.ValidOffset(offset)) { + switch (debug_loc_data.GetU8(&offset)) { + case DW_LLE_end_of_list: + return offset; + case DW_LLE_base_addressx: { + uint64_t index = debug_loc_data.GetULEB128(&offset); + base_addr = ReadAddressFromDebugAddrSection(dwarf_cu, index); + break; + } + case DW_LLE_startx_endx: { + uint64_t index = debug_loc_data.GetULEB128(&offset); + lldb::addr_t low_pc = ReadAddressFromDebugAddrSection(dwarf_cu, index); + index = debug_loc_data.GetULEB128(&offset); + lldb::addr_t high_pc = ReadAddressFromDebugAddrSection(dwarf_cu, index); + if (!callback(low_pc, high_pc, offset)) { + return offset + debug_loc_data.GetU16(&offset); + } + offset += debug_loc_data.GetU16(&offset); + break; + } + case DW_LLE_startx_length: { + uint64_t index = debug_loc_data.GetULEB128(&offset); + lldb::addr_t low_pc = ReadAddressFromDebugAddrSection(dwarf_cu, index); + uint32_t length = debug_loc_data.GetU32(&offset); + lldb::addr_t high_pc = low_pc + length; + if (!callback(low_pc, high_pc, offset)) { + return offset + debug_loc_data.GetU16(&offset); + } + offset += debug_loc_data.GetU16(&offset); + break; + } + case DW_LLE_offset_pair: { + lldb::addr_t low_pc = debug_loc_data.GetULEB128(&offset); + lldb::addr_t high_pc = debug_loc_data.GetULEB128(&offset); + if (!callback(low_pc + base_addr, high_pc + base_addr, offset)) { + return offset + debug_loc_data.GetU16(&offset); + } + offset += debug_loc_data.GetU16(&offset); + break; + } + default: + // Not supported entry type + return offset; + } } - default: - // Not supported entry type - return false; } + return 0; } assert(false && "Not supported location list type"); - return false; } static bool print_dwarf_exp_op(Stream &s, const DataExtractor &data,