185 lines · cpp
1//===- DWARFDebugAddr.cpp -------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/DebugInfo/DWARF/DWARFDebugAddr.h"10#include "llvm/BinaryFormat/Dwarf.h"11#include "llvm/DebugInfo/DWARF/DWARFContext.h"12#include "llvm/Support/Errc.h"13 14using namespace llvm;15 16Error DWARFDebugAddrTable::extractAddresses(const DWARFDataExtractor &Data,17 uint64_t *OffsetPtr,18 uint64_t EndOffset) {19 assert(EndOffset >= *OffsetPtr);20 uint64_t DataSize = EndOffset - *OffsetPtr;21 assert(Data.isValidOffsetForDataOfSize(*OffsetPtr, DataSize));22 if (Error SizeErr = DWARFContext::checkAddressSizeSupported(23 AddrSize, errc::not_supported, "address table at offset 0x%" PRIx64,24 Offset))25 return SizeErr;26 if (DataSize % AddrSize != 0) {27 invalidateLength();28 return createStringError(errc::invalid_argument,29 "address table at offset 0x%" PRIx6430 " contains data of size 0x%" PRIx6431 " which is not a multiple of addr size %" PRIu8,32 Offset, DataSize, AddrSize);33 }34 Addrs.clear();35 size_t Count = DataSize / AddrSize;36 Addrs.reserve(Count);37 while (Count--)38 Addrs.push_back(Data.getRelocatedValue(AddrSize, OffsetPtr));39 return Error::success();40}41 42Error DWARFDebugAddrTable::extractV5(const DWARFDataExtractor &Data,43 uint64_t *OffsetPtr, uint8_t CUAddrSize,44 std::function<void(Error)> WarnCallback) {45 Offset = *OffsetPtr;46 llvm::Error Err = Error::success();47 std::tie(Length, Format) = Data.getInitialLength(OffsetPtr, &Err);48 if (Err) {49 invalidateLength();50 return createStringError(errc::invalid_argument,51 "parsing address table at offset 0x%" PRIx6452 ": %s",53 Offset, toString(std::move(Err)).c_str());54 }55 56 if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, Length)) {57 uint64_t DiagnosticLength = Length;58 invalidateLength();59 return createStringError(60 errc::invalid_argument,61 "section is not large enough to contain an address table "62 "at offset 0x%" PRIx64 " with a unit_length value of 0x%" PRIx64,63 Offset, DiagnosticLength);64 }65 uint64_t EndOffset = *OffsetPtr + Length;66 // Ensure that we can read the remaining header fields.67 if (Length < 4) {68 uint64_t DiagnosticLength = Length;69 invalidateLength();70 return createStringError(71 errc::invalid_argument,72 "address table at offset 0x%" PRIx6473 " has a unit_length value of 0x%" PRIx6474 ", which is too small to contain a complete header",75 Offset, DiagnosticLength);76 }77 78 Version = Data.getU16(OffsetPtr);79 AddrSize = Data.getU8(OffsetPtr);80 SegSize = Data.getU8(OffsetPtr);81 82 // Perform a basic validation of the header fields.83 if (Version != 5)84 return createStringError(errc::not_supported,85 "address table at offset 0x%" PRIx6486 " has unsupported version %" PRIu16,87 Offset, Version);88 // TODO: add support for non-zero segment selector size.89 if (SegSize != 0)90 return createStringError(errc::not_supported,91 "address table at offset 0x%" PRIx6492 " has unsupported segment selector size %" PRIu8,93 Offset, SegSize);94 95 if (Error Err = extractAddresses(Data, OffsetPtr, EndOffset))96 return Err;97 if (CUAddrSize && AddrSize != CUAddrSize) {98 WarnCallback(createStringError(99 errc::invalid_argument,100 "address table at offset 0x%" PRIx64 " has address size %" PRIu8101 " which is different from CU address size %" PRIu8,102 Offset, AddrSize, CUAddrSize));103 }104 return Error::success();105}106 107Error DWARFDebugAddrTable::extractPreStandard(const DWARFDataExtractor &Data,108 uint64_t *OffsetPtr,109 uint16_t CUVersion,110 uint8_t CUAddrSize) {111 assert(CUVersion > 0 && CUVersion < 5);112 113 Offset = *OffsetPtr;114 Length = 0;115 Version = CUVersion;116 AddrSize = CUAddrSize;117 SegSize = 0;118 119 return extractAddresses(Data, OffsetPtr, Data.size());120}121 122Error DWARFDebugAddrTable::extract(const DWARFDataExtractor &Data,123 uint64_t *OffsetPtr,124 uint16_t CUVersion,125 uint8_t CUAddrSize,126 std::function<void(Error)> WarnCallback) {127 if (CUVersion > 0 && CUVersion < 5)128 return extractPreStandard(Data, OffsetPtr, CUVersion, CUAddrSize);129 if (CUVersion == 0)130 WarnCallback(createStringError(errc::invalid_argument,131 "DWARF version is not defined in CU,"132 " assuming version 5"));133 return extractV5(Data, OffsetPtr, CUAddrSize, WarnCallback);134}135 136void DWARFDebugAddrTable::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {137 if (DumpOpts.Verbose)138 OS << format("0x%8.8" PRIx64 ": ", Offset);139 if (Length) {140 int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(Format);141 OS << "Address table header: "142 << format("length = 0x%0*" PRIx64, OffsetDumpWidth, Length)143 << ", format = " << dwarf::FormatString(Format)144 << format(", version = 0x%4.4" PRIx16, Version)145 << format(", addr_size = 0x%2.2" PRIx8, AddrSize)146 << format(", seg_size = 0x%2.2" PRIx8, SegSize) << "\n";147 }148 149 if (Addrs.size() > 0) {150 const char *AddrFmt;151 switch (AddrSize) {152 case 2:153 AddrFmt = "0x%4.4" PRIx64 "\n";154 break;155 case 4:156 AddrFmt = "0x%8.8" PRIx64 "\n";157 break;158 case 8:159 AddrFmt = "0x%16.16" PRIx64 "\n";160 break;161 default:162 llvm_unreachable("unsupported address size");163 }164 OS << "Addrs: [\n";165 for (uint64_t Addr : Addrs)166 OS << format(AddrFmt, Addr);167 OS << "]\n";168 }169}170 171Expected<uint64_t> DWARFDebugAddrTable::getAddrEntry(uint32_t Index) const {172 if (Index < Addrs.size())173 return Addrs[Index];174 return createStringError(errc::invalid_argument,175 "Index %" PRIu32 " is out of range of the "176 "address table at offset 0x%" PRIx64,177 Index, Offset);178}179 180std::optional<uint64_t> DWARFDebugAddrTable::getFullLength() const {181 if (Length == 0)182 return std::nullopt;183 return Length + dwarf::getUnitLengthFieldByteSize(Format);184}185