//===-- 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 "SymbolFileDWARF.h" #include "lldb/Core/Stream.h" #include using namespace lldb_private; using namespace std; DWARFDebugRanges::DWARFDebugRanges() : m_range_map() { } DWARFDebugRanges::~DWARFDebugRanges() { } void DWARFDebugRanges::Extract(SymbolFileDWARF* dwarf2Data) { RangeList range_list; dw_offset_t offset = 0; dw_offset_t debug_ranges_offset = offset; while (range_list.Extract(dwarf2Data, &offset)) { m_range_map[debug_ranges_offset] = range_list; debug_ranges_offset = offset; } } bool DWARFDebugRanges::RangeList::AddRange(dw_addr_t lo_addr, dw_addr_t hi_addr) { if (lo_addr <= hi_addr) { Range range(lo_addr, hi_addr); ranges.push_back(range); return true; } return false; } const DWARFDebugRanges::Range* DWARFDebugRanges::RangeList::Lookup(dw_addr_t offset) const { Range::const_iterator pos = ranges.begin(); Range::const_iterator end_pos = ranges.end(); for (pos = ranges.begin(); pos != end_pos; ++pos) { if (pos->begin_offset <= offset && offset < pos->end_offset) { return &(*pos); } } return NULL; } size_t DWARFDebugRanges::RangeList::Size() const { return ranges.size(); } void DWARFDebugRanges::RangeList::AddOffset(dw_addr_t offset) { if (!ranges.empty()) { Range::iterator pos = ranges.begin(); Range::iterator end_pos = ranges.end(); for (pos = ranges.begin(); pos != end_pos; ++pos) { // assert for unsigned overflows assert (~pos->begin_offset >= offset); assert (~pos->end_offset >= offset); pos->begin_offset += offset; pos->end_offset += offset; } } } void DWARFDebugRanges::RangeList::SubtractOffset(dw_addr_t offset) { if (!ranges.empty()) { Range::iterator pos = ranges.begin(); Range::iterator end_pos = ranges.end(); for (pos = ranges.begin(); pos != end_pos; ++pos) { assert (pos->begin_offset >= offset); assert (pos->end_offset >= offset); pos->begin_offset -= offset; pos->end_offset -= offset; } } } const DWARFDebugRanges::Range* DWARFDebugRanges::RangeList::RangeAtIndex(size_t i) const { if (i < ranges.size()) return &ranges[i]; return NULL; } bool DWARFDebugRanges::RangeList::Extract(SymbolFileDWARF* dwarf2Data, uint32_t* offset_ptr) { Clear(); uint32_t range_offset = *offset_ptr; const DataExtractor& debug_ranges_data = dwarf2Data->get_debug_ranges_data(); uint32_t addr_size = debug_ranges_data.GetAddressByteSize(); 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; } // Extend 4 byte addresses that consits of 32 bits of 1's to be 64 bits // of ones switch (addr_size) { case 2: if (begin == 0xFFFFull) begin = DW_INVALID_ADDRESS; break; case 4: if (begin == 0xFFFFFFFFull) begin = DW_INVALID_ADDRESS; break; case 8: break; default: assert(!"DWARFDebugRanges::RangeList::Extract() unsupported address size."); break; } // Filter out empty ranges if (begin != end) ranges.push_back(Range(begin, end)); } // Make sure we consumed at least something return range_offset != *offset_ptr; } dw_addr_t DWARFDebugRanges::RangeList::LowestAddress(const dw_addr_t cu_base_addr) const { dw_addr_t addr = DW_INVALID_ADDRESS; dw_addr_t curr_base_addr = cu_base_addr; if (!ranges.empty()) { Range::const_iterator pos = ranges.begin(); Range::const_iterator end_pos = ranges.end(); for (pos = ranges.begin(); pos != end_pos; ++pos) { if (pos->begin_offset == DW_INVALID_ADDRESS) curr_base_addr = pos->end_offset; else if (curr_base_addr != DW_INVALID_ADDRESS) { dw_addr_t curr_addr = curr_base_addr + pos->begin_offset; if (addr > curr_addr) addr = curr_addr; } } } return addr; } dw_addr_t DWARFDebugRanges::RangeList::HighestAddress(const dw_addr_t cu_base_addr) const { dw_addr_t addr = 0; dw_addr_t curr_base_addr = cu_base_addr; if (!ranges.empty()) { Range::const_iterator pos = ranges.begin(); Range::const_iterator end_pos = ranges.end(); for (pos = ranges.begin(); pos != end_pos; ++pos) { if (pos->begin_offset == DW_INVALID_ADDRESS) curr_base_addr = pos->end_offset; else if (curr_base_addr != DW_INVALID_ADDRESS) { dw_addr_t curr_addr = curr_base_addr + pos->end_offset; if (addr < curr_addr) addr = curr_addr; } } } if (addr != 0) return addr; return DW_INVALID_ADDRESS; } void DWARFDebugRanges::Dump(Stream *s, const DataExtractor& debug_ranges_data, uint32_t* offset_ptr, dw_addr_t cu_base_addr) { uint32_t addr_size = s->GetAddressByteSize(); bool verbose = s->GetVerbose(); 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 consits of 32 bits of 1's to be 64 bits // of ones if (begin == 0xFFFFFFFFull && addr_size == 4) begin = DW_INVALID_ADDRESS; s->Indent(); if (verbose) { s->AddressRange(begin, end, sizeof (dw_addr_t), " offsets = "); } if (begin == 0 && end == 0) { s->PutCString(" End"); break; } else if (begin == DW_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), verbose ? " ==> addrs = " : NULL); } } } bool DWARFDebugRanges::FindRanges(dw_offset_t debug_ranges_offset, RangeList& range_list) const { range_map_const_iterator pos = m_range_map.find(debug_ranges_offset); if (pos != m_range_map.end()) { range_list = pos->second; return true; } return false; }