1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
|
//===-- DWARFDebugArangeSet.cpp -------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "DWARFDebugArangeSet.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cassert>
using namespace llvm;
void DWARFDebugArangeSet::clear() {
Offset = -1U;
std::memset(&Header, 0, sizeof(Header));
ArangeDescriptors.clear();
}
void DWARFDebugArangeSet::compact() {
if (ArangeDescriptors.empty())
return;
// Iterate through all arange descriptors and combine any ranges that
// overlap or have matching boundaries. The ArangeDescriptors are assumed
// to be in ascending order.
uint32_t i = 0;
while (i + 1 < ArangeDescriptors.size()) {
if (ArangeDescriptors[i].getEndAddress() >= ArangeDescriptors[i+1].Address){
// The current range ends at or exceeds the start of the next address
// range. Compute the max end address between the two and use that to
// make the new length.
const uint64_t max_end_addr =
std::max(ArangeDescriptors[i].getEndAddress(),
ArangeDescriptors[i+1].getEndAddress());
ArangeDescriptors[i].Length = max_end_addr - ArangeDescriptors[i].Address;
// Now remove the next entry as it was just combined with the previous one
ArangeDescriptors.erase(ArangeDescriptors.begin()+i+1);
} else {
// Discontiguous address range, just proceed to the next one.
++i;
}
}
}
bool
DWARFDebugArangeSet::extract(DataExtractor data, uint32_t *offset_ptr) {
if (data.isValidOffset(*offset_ptr)) {
ArangeDescriptors.clear();
Offset = *offset_ptr;
// 7.20 Address Range Table
//
// Each set of entries in the table of address ranges contained in
// the .debug_aranges section begins with a header consisting of: a
// 4-byte length containing the length of the set of entries for this
// compilation unit, not including the length field itself; a 2-byte
// version identifier containing the value 2 for DWARF Version 2; a
// 4-byte offset into the.debug_infosection; a 1-byte unsigned integer
// containing the size in bytes of an address (or the offset portion of
// an address for segmented addressing) on the target system; and a
// 1-byte unsigned integer containing the size in bytes of a segment
// descriptor on the target system. This header is followed by a series
// of tuples. Each tuple consists of an address and a length, each in
// the size appropriate for an address on the target architecture.
Header.Length = data.getU32(offset_ptr);
Header.Version = data.getU16(offset_ptr);
Header.CuOffset = data.getU32(offset_ptr);
Header.AddrSize = data.getU8(offset_ptr);
Header.SegSize = data.getU8(offset_ptr);
// Perform basic validation of the header fields.
if (!data.isValidOffsetForDataOfSize(Offset, Header.Length) ||
(Header.AddrSize != 4 && Header.AddrSize != 8)) {
clear();
return false;
}
// The first tuple following the header in each set begins at an offset
// that is a multiple of the size of a single tuple (that is, twice the
// size of an address). The header is padded, if necessary, to the
// appropriate boundary.
const uint32_t header_size = *offset_ptr - Offset;
const uint32_t tuple_size = Header.AddrSize * 2;
uint32_t first_tuple_offset = 0;
while (first_tuple_offset < header_size)
first_tuple_offset += tuple_size;
*offset_ptr = Offset + first_tuple_offset;
Descriptor arangeDescriptor;
assert(sizeof(arangeDescriptor.Address) == sizeof(arangeDescriptor.Length));
assert(sizeof(arangeDescriptor.Address) >= Header.AddrSize);
while (data.isValidOffset(*offset_ptr)) {
arangeDescriptor.Address = data.getUnsigned(offset_ptr, Header.AddrSize);
arangeDescriptor.Length = data.getUnsigned(offset_ptr, Header.AddrSize);
// Each set of tuples is terminated by a 0 for the address and 0
// for the length.
if (arangeDescriptor.Address || arangeDescriptor.Length)
ArangeDescriptors.push_back(arangeDescriptor);
else
break; // We are done if we get a zero address and length
}
return !ArangeDescriptors.empty();
}
return false;
}
void DWARFDebugArangeSet::dump(raw_ostream &OS) const {
OS << format("Address Range Header: length = 0x%8.8x, version = 0x%4.4x, ",
Header.Length, Header.Version)
<< format("cu_offset = 0x%8.8x, addr_size = 0x%2.2x, seg_size = 0x%2.2x\n",
Header.CuOffset, Header.AddrSize, Header.SegSize);
const uint32_t hex_width = Header.AddrSize * 2;
for (DescriptorConstIter pos = ArangeDescriptors.begin(),
end = ArangeDescriptors.end(); pos != end; ++pos)
OS << format("[0x%*.*llx -", hex_width, hex_width, pos->Address)
<< format(" 0x%*.*llx)\n", hex_width, hex_width, pos->getEndAddress());
}
namespace {
class DescriptorContainsAddress {
const uint64_t Address;
public:
DescriptorContainsAddress(uint64_t address) : Address(address) {}
bool operator()(const DWARFDebugArangeSet::Descriptor &desc) const {
return Address >= desc.Address && Address < (desc.Address + desc.Length);
}
};
}
uint32_t DWARFDebugArangeSet::findAddress(uint64_t address) const {
DescriptorConstIter end = ArangeDescriptors.end();
DescriptorConstIter pos =
std::find_if(ArangeDescriptors.begin(), end, // Range
DescriptorContainsAddress(address)); // Predicate
if (pos != end)
return Header.CuOffset;
return -1U;
}
|