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 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
|
//===- DWARFDebugAddr.cpp -------------------------------------------------===//
//
// 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 "llvm/DebugInfo/DWARF/DWARFDebugAddr.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
using namespace llvm;
void DWARFDebugAddrTable::clear() {
HeaderData = {};
Addrs.clear();
invalidateLength();
}
Error DWARFDebugAddrTable::extract(DWARFDataExtractor Data,
uint32_t *OffsetPtr,
uint16_t Version,
uint8_t AddrSize,
std::function<void(Error)> WarnCallback) {
clear();
HeaderOffset = *OffsetPtr;
// Read and verify the length field.
if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, sizeof(uint32_t)))
return createStringError(errc::invalid_argument,
"section is not large enough to contain a "
".debug_addr table length at offset 0x%"
PRIx32, *OffsetPtr);
uint16_t UnitVersion;
if (Version == 0) {
WarnCallback(createStringError(errc::invalid_argument,
"DWARF version is not defined in CU,"
" assuming version 5"));
UnitVersion = 5;
} else {
UnitVersion = Version;
}
// TODO: Add support for DWARF64.
Format = dwarf::DwarfFormat::DWARF32;
if (UnitVersion >= 5) {
HeaderData.Length = Data.getU32(OffsetPtr);
if (HeaderData.Length == 0xffffffffu) {
invalidateLength();
return createStringError(errc::not_supported,
"DWARF64 is not supported in .debug_addr at offset 0x%" PRIx32,
HeaderOffset);
}
if (HeaderData.Length + sizeof(uint32_t) < sizeof(Header)) {
uint32_t TmpLength = getLength();
invalidateLength();
return createStringError(errc::invalid_argument,
".debug_addr table at offset 0x%" PRIx32
" has too small length (0x%" PRIx32
") to contain a complete header",
HeaderOffset, TmpLength);
}
uint32_t End = HeaderOffset + getLength();
if (!Data.isValidOffsetForDataOfSize(HeaderOffset, End - HeaderOffset)) {
uint32_t TmpLength = getLength();
invalidateLength();
return createStringError(errc::invalid_argument,
"section is not large enough to contain a .debug_addr table "
"of length 0x%" PRIx32 " at offset 0x%" PRIx32,
TmpLength, HeaderOffset);
}
HeaderData.Version = Data.getU16(OffsetPtr);
HeaderData.AddrSize = Data.getU8(OffsetPtr);
HeaderData.SegSize = Data.getU8(OffsetPtr);
DataSize = getDataSize();
} else {
HeaderData.Version = UnitVersion;
HeaderData.AddrSize = AddrSize;
// TODO: Support for non-zero SegSize.
HeaderData.SegSize = 0;
DataSize = Data.size();
}
// Perform basic validation of the remaining header fields.
// We support DWARF version 5 for now as well as pre-DWARF5
// implementations of .debug_addr table, which doesn't contain a header
// and consists only of a series of addresses.
if (HeaderData.Version > 5) {
return createStringError(errc::not_supported, "version %" PRIu16
" of .debug_addr section at offset 0x%" PRIx32 " is not supported",
HeaderData.Version, HeaderOffset);
}
// FIXME: For now we just treat version mismatch as an error,
// however the correct way to associate a .debug_addr table
// with a .debug_info table is to look at the DW_AT_addr_base
// attribute in the info table.
if (HeaderData.Version != UnitVersion)
return createStringError(errc::invalid_argument,
".debug_addr table at offset 0x%" PRIx32
" has version %" PRIu16
" which is different from the version suggested"
" by the DWARF unit header: %" PRIu16,
HeaderOffset, HeaderData.Version, UnitVersion);
if (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8)
return createStringError(errc::not_supported,
".debug_addr table at offset 0x%" PRIx32
" has unsupported address size %" PRIu8,
HeaderOffset, HeaderData.AddrSize);
if (HeaderData.AddrSize != AddrSize && AddrSize != 0)
return createStringError(errc::invalid_argument,
".debug_addr table at offset 0x%" PRIx32
" has address size %" PRIu8
" which is different from CU address size %" PRIu8,
HeaderOffset, HeaderData.AddrSize, AddrSize);
// TODO: add support for non-zero segment selector size.
if (HeaderData.SegSize != 0)
return createStringError(errc::not_supported,
".debug_addr table at offset 0x%" PRIx32
" has unsupported segment selector size %" PRIu8,
HeaderOffset, HeaderData.SegSize);
if (DataSize % HeaderData.AddrSize != 0) {
invalidateLength();
return createStringError(errc::invalid_argument,
".debug_addr table at offset 0x%" PRIx32
" contains data of size %" PRIu32
" which is not a multiple of addr size %" PRIu8,
HeaderOffset, DataSize, HeaderData.AddrSize);
}
Data.setAddressSize(HeaderData.AddrSize);
uint32_t AddrCount = DataSize / HeaderData.AddrSize;
for (uint32_t I = 0; I < AddrCount; ++I)
if (HeaderData.AddrSize == 4)
Addrs.push_back(Data.getU32(OffsetPtr));
else
Addrs.push_back(Data.getU64(OffsetPtr));
return Error::success();
}
void DWARFDebugAddrTable::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
if (DumpOpts.Verbose)
OS << format("0x%8.8" PRIx32 ": ", HeaderOffset);
OS << format("Addr Section: length = 0x%8.8" PRIx32
", version = 0x%4.4" PRIx16 ", "
"addr_size = 0x%2.2" PRIx8 ", seg_size = 0x%2.2" PRIx8 "\n",
HeaderData.Length, HeaderData.Version, HeaderData.AddrSize,
HeaderData.SegSize);
if (Addrs.size() > 0) {
const char *AddrFmt = (HeaderData.AddrSize == 4) ? "0x%8.8" PRIx64 "\n"
: "0x%16.16" PRIx64 "\n";
OS << "Addrs: [\n";
for (uint64_t Addr : Addrs)
OS << format(AddrFmt, Addr);
OS << "]\n";
}
}
Expected<uint64_t> DWARFDebugAddrTable::getAddrEntry(uint32_t Index) const {
if (Index < Addrs.size())
return Addrs[Index];
return createStringError(errc::invalid_argument,
"Index %" PRIu32 " is out of range of the "
".debug_addr table at offset 0x%" PRIx32,
Index, HeaderOffset);
}
uint32_t DWARFDebugAddrTable::getLength() const {
if (HeaderData.Length == 0)
return 0;
// TODO: DWARF64 support.
return HeaderData.Length + sizeof(uint32_t);
}
uint32_t DWARFDebugAddrTable::getDataSize() const {
if (DataSize != 0)
return DataSize;
if (getLength() == 0)
return 0;
return getLength() - getHeaderSize();
}
|