diff options
Diffstat (limited to 'contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp')
| -rw-r--r-- | contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp | 290 |
1 files changed, 290 insertions, 0 deletions
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp new file mode 100644 index 000000000000..207c71211c9a --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp @@ -0,0 +1,290 @@ +//===-- DWARFDebugRanges.cpp ------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "DWARFDebugRanges.h" +#include "DWARFUnit.h" +#include "lldb/Utility/Stream.h" + +using namespace lldb_private; + +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."); +} + +DWARFDebugRanges::DWARFDebugRanges() : m_range_map() {} + +void DWARFDebugRanges::Extract(DWARFContext &context) { + DWARFRangeList range_list; + lldb::offset_t offset = 0; + dw_offset_t debug_ranges_offset = offset; + while (Extract(context, &offset, range_list)) { + range_list.Sort(); + m_range_map[debug_ranges_offset] = range_list; + debug_ranges_offset = offset; + } +} + +bool DWARFDebugRanges::Extract(DWARFContext &context, + lldb::offset_t *offset_ptr, + DWARFRangeList &range_list) { + range_list.Clear(); + + lldb::offset_t range_offset = *offset_ptr; + const DWARFDataExtractor &debug_ranges_data = context.getOrLoadRangesData(); + uint32_t addr_size = debug_ranges_data.GetAddressByteSize(); + dw_addr_t base_addr = 0; + dw_addr_t base_addr_marker = GetBaseAddressMarker(addr_size); + + while ( + debug_ranges_data.ValidOffsetForDataOfSize(*offset_ptr, 2 * addr_size)) { + dw_addr_t begin = debug_ranges_data.GetMaxU64(offset_ptr, addr_size); + dw_addr_t end = debug_ranges_data.GetMaxU64(offset_ptr, addr_size); + + if (!begin && !end) { + // End of range list + break; + } + + if (begin == base_addr_marker) { + base_addr = end; + continue; + } + + // Filter out empty ranges + if (begin < end) + range_list.Append(DWARFRangeList::Entry(begin + base_addr, end - begin)); + } + + // Make sure we consumed at least something + return range_offset != *offset_ptr; +} + +void DWARFDebugRanges::Dump(Stream &s, + const DWARFDataExtractor &debug_ranges_data, + lldb::offset_t *offset_ptr, + dw_addr_t cu_base_addr) { + uint32_t addr_size = s.GetAddressByteSize(); + + dw_addr_t base_addr = cu_base_addr; + while ( + debug_ranges_data.ValidOffsetForDataOfSize(*offset_ptr, 2 * addr_size)) { + dw_addr_t begin = debug_ranges_data.GetMaxU64(offset_ptr, addr_size); + dw_addr_t end = debug_ranges_data.GetMaxU64(offset_ptr, addr_size); + // Extend 4 byte addresses that consists of 32 bits of 1's to be 64 bits of + // ones + if (begin == 0xFFFFFFFFull && addr_size == 4) + begin = LLDB_INVALID_ADDRESS; + + s.Indent(); + if (begin == 0 && end == 0) { + s.PutCString(" End"); + break; + } else if (begin == LLDB_INVALID_ADDRESS) { + // A base address selection entry + base_addr = end; + s.Address(base_addr, sizeof(dw_addr_t), " Base address = "); + } else { + // Convert from offset to an address + dw_addr_t begin_addr = begin + base_addr; + dw_addr_t end_addr = end + base_addr; + + s.AddressRange(begin_addr, end_addr, sizeof(dw_addr_t), nullptr); + } + } +} + +bool DWARFDebugRanges::FindRanges(const DWARFUnit *cu, + dw_offset_t debug_ranges_offset, + DWARFRangeList &range_list) const { + dw_addr_t debug_ranges_address = cu->GetRangesBase() + debug_ranges_offset; + range_map_const_iterator pos = m_range_map.find(debug_ranges_address); + if (pos != m_range_map.end()) { + range_list = pos->second; + + // All DW_AT_ranges are relative to the base address of the compile + // unit. We add the compile unit base address to make sure all the + // addresses are properly fixed up. + range_list.Slide(cu->GetBaseAddress()); + return true; + } + return false; +} + +uint64_t DWARFDebugRanges::GetOffset(size_t Index) const { + lldbassert(false && "DW_FORM_rnglistx is not present before DWARF5"); + return 0; +} + +bool DWARFDebugRngLists::ExtractRangeList( + const DWARFDataExtractor &data, uint8_t addrSize, + lldb::offset_t *offset_ptr, std::vector<RngListEntry> &rangeList) { + rangeList.clear(); + + bool error = false; + while (!error) { + switch (data.GetU8(offset_ptr)) { + case DW_RLE_end_of_list: + return true; + + case DW_RLE_start_length: { + dw_addr_t begin = data.GetMaxU64(offset_ptr, addrSize); + dw_addr_t len = data.GetULEB128(offset_ptr); + rangeList.push_back({DW_RLE_start_length, begin, len}); + break; + } + + case DW_RLE_start_end: { + dw_addr_t begin = data.GetMaxU64(offset_ptr, addrSize); + dw_addr_t end = data.GetMaxU64(offset_ptr, addrSize); + rangeList.push_back({DW_RLE_start_end, begin, end}); + break; + } + + case DW_RLE_base_address: { + dw_addr_t base = data.GetMaxU64(offset_ptr, addrSize); + rangeList.push_back({DW_RLE_base_address, base, 0}); + break; + } + + case DW_RLE_offset_pair: { + dw_addr_t begin = data.GetULEB128(offset_ptr); + dw_addr_t end = data.GetULEB128(offset_ptr); + rangeList.push_back({DW_RLE_offset_pair, begin, end}); + break; + } + + case DW_RLE_base_addressx: { + dw_addr_t base = data.GetULEB128(offset_ptr); + rangeList.push_back({DW_RLE_base_addressx, base, 0}); + break; + } + + case DW_RLE_startx_endx: { + dw_addr_t start = data.GetULEB128(offset_ptr); + dw_addr_t end = data.GetULEB128(offset_ptr); + rangeList.push_back({DW_RLE_startx_endx, start, end}); + break; + } + + case DW_RLE_startx_length: { + dw_addr_t start = data.GetULEB128(offset_ptr); + dw_addr_t length = data.GetULEB128(offset_ptr); + rangeList.push_back({DW_RLE_startx_length, start, length}); + break; + } + + default: + lldbassert(0 && "unknown range list entry encoding"); + error = true; + } + } + + return false; +} + +static uint64_t ReadAddressFromDebugAddrSection(const DWARFUnit *cu, + uint32_t index) { + uint32_t index_size = cu->GetAddressByteSize(); + dw_offset_t addr_base = cu->GetAddrBase(); + lldb::offset_t offset = addr_base + index * index_size; + return cu->GetSymbolFileDWARF() + .GetDWARFContext() + .getOrLoadAddrData() + .GetMaxU64(&offset, index_size); +} + +bool DWARFDebugRngLists::FindRanges(const DWARFUnit *cu, + dw_offset_t debug_ranges_offset, + DWARFRangeList &range_list) const { + range_list.Clear(); + dw_addr_t debug_ranges_address = cu->GetRangesBase() + debug_ranges_offset; + auto pos = m_range_map.find(debug_ranges_address); + if (pos != m_range_map.end()) { + dw_addr_t BaseAddr = cu->GetBaseAddress(); + for (const RngListEntry &E : pos->second) { + switch (E.encoding) { + case DW_RLE_start_length: + range_list.Append(DWARFRangeList::Entry(E.value0, E.value1)); + break; + case DW_RLE_base_address: + BaseAddr = E.value0; + break; + case DW_RLE_start_end: + range_list.Append(DWARFRangeList::Entry(E.value0, E.value1 - E.value0)); + break; + case DW_RLE_offset_pair: + range_list.Append( + DWARFRangeList::Entry(BaseAddr + E.value0, E.value1 - E.value0)); + break; + case DW_RLE_base_addressx: { + BaseAddr = ReadAddressFromDebugAddrSection(cu, E.value0); + break; + } + case DW_RLE_startx_endx: { + dw_addr_t start = ReadAddressFromDebugAddrSection(cu, E.value0); + dw_addr_t end = ReadAddressFromDebugAddrSection(cu, E.value1); + range_list.Append(DWARFRangeList::Entry(start, end - start)); + break; + } + case DW_RLE_startx_length: { + dw_addr_t start = ReadAddressFromDebugAddrSection(cu, E.value0); + range_list.Append(DWARFRangeList::Entry(start, E.value1)); + break; + } + default: + llvm_unreachable("unexpected encoding"); + } + } + return true; + } + return false; +} + +void DWARFDebugRngLists::Extract(DWARFContext &context) { + const DWARFDataExtractor &data = context.getOrLoadRngListsData(); + lldb::offset_t offset = 0; + + uint64_t length = data.GetU32(&offset); + // FIXME: Handle DWARF64. + lldb::offset_t end = offset + length; + + // Check version. + if (data.GetU16(&offset) < 5) + return; + + uint8_t addrSize = data.GetU8(&offset); + + // We do not support non-zero segment selector size. + if (data.GetU8(&offset) != 0) { + lldbassert(0 && "not implemented"); + return; + } + + uint32_t offsetsAmount = data.GetU32(&offset); + for (uint32_t i = 0; i < offsetsAmount; ++i) + Offsets.push_back(data.GetMaxU64(&offset, 4)); + + lldb::offset_t listOffset = offset; + std::vector<RngListEntry> rangeList; + while (offset < end && ExtractRangeList(data, addrSize, &offset, rangeList)) { + m_range_map[listOffset] = rangeList; + listOffset = offset; + } +} + +uint64_t DWARFDebugRngLists::GetOffset(size_t Index) const { + return Offsets[Index]; +} |
