//===-- DWARFDebugRanges.cpp ------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "DWARFDebugRanges.h" #include "DWARFUnit.h" #include "SymbolFileDWARF.h" #include "lldb/Utility/Stream.h" #include using namespace lldb_private; using namespace std; 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(SymbolFileDWARF *dwarf2Data) { DWARFRangeList range_list; lldb::offset_t offset = 0; dw_offset_t debug_ranges_offset = offset; while (Extract(dwarf2Data, &offset, range_list)) { range_list.Sort(); m_range_map[debug_ranges_offset] = range_list; debug_ranges_offset = offset; } } bool DWARFDebugRanges::Extract(SymbolFileDWARF *dwarf2Data, lldb::offset_t *offset_ptr, DWARFRangeList &range_list) { range_list.Clear(); lldb::offset_t range_offset = *offset_ptr; const DWARFDataExtractor &debug_ranges_data = dwarf2Data->get_debug_ranges_data(); 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), NULL); } } } 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 &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()->get_debug_addr_data().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(SymbolFileDWARF *dwarf2Data) { const DWARFDataExtractor &data = dwarf2Data->get_debug_rnglists_data(); lldb::offset_t offset = 0; uint64_t length = data.GetU32(&offset); bool isDwarf64 = (length == 0xffffffff); if (isDwarf64) length = data.GetU64(&offset); 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, isDwarf64 ? 8 : 4)); lldb::offset_t listOffset = offset; std::vector 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]; }