teak-llvm/llvm/lib/DebugInfo/DWARF/DWARFDebugAddr.cpp
Chandler Carruth 2946cd7010 Update the file headers across all of the LLVM projects in the monorepo
to reflect the new license.

We understand that people may be surprised that we're moving the header
entirely to discuss the new license. We checked this carefully with the
Foundation's lawyer and we believe this is the correct approach.

Essentially, all code in the project is now made available by the LLVM
project under our new license, so you will see that the license headers
include that license only. Some of our contributors have contributed
code under our old license, and accordingly, we have retained a copy of
our old license notice in the top-level files in each project and
repository.

llvm-svn: 351636
2019-01-19 08:50:56 +00:00

198 lines
7.6 KiB
C++

//===- 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);
static const char *Fmt32 = "0x%8.8" PRIx64;
static const char *Fmt64 = "0x%16.16" PRIx64;
std::string AddrFmt = "\n";
std::string AddrFmtVerbose = " => ";
if (HeaderData.AddrSize == 4) {
AddrFmt.append(Fmt32);
AddrFmtVerbose.append(Fmt32);
}
else {
AddrFmt.append(Fmt64);
AddrFmtVerbose.append(Fmt64);
}
if (Addrs.size() > 0) {
OS << "Addrs: [";
for (uint64_t Addr : Addrs) {
OS << format(AddrFmt.c_str(), Addr);
if (DumpOpts.Verbose)
OS << format(AddrFmtVerbose.c_str(),
Addr + HeaderOffset + sizeof(HeaderData));
}
OS << "\n]\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();
}