10b57cec5SDimitry Andric //===- DWARFDebugAddr.cpp -------------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFDebugAddr.h" 100b57cec5SDimitry Andric #include "llvm/BinaryFormat/Dwarf.h" 110b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFUnit.h" 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric using namespace llvm; 140b57cec5SDimitry Andric 15*5ffd83dbSDimitry Andric Error DWARFDebugAddrTable::extractAddresses(const DWARFDataExtractor &Data, 16*5ffd83dbSDimitry Andric uint64_t *OffsetPtr, 17*5ffd83dbSDimitry Andric uint64_t EndOffset) { 18*5ffd83dbSDimitry Andric assert(EndOffset >= *OffsetPtr); 19*5ffd83dbSDimitry Andric uint64_t DataSize = EndOffset - *OffsetPtr; 20*5ffd83dbSDimitry Andric assert(Data.isValidOffsetForDataOfSize(*OffsetPtr, DataSize)); 21*5ffd83dbSDimitry Andric if (AddrSize != 4 && AddrSize != 8) 22*5ffd83dbSDimitry Andric return createStringError(errc::not_supported, 23*5ffd83dbSDimitry Andric "address table at offset 0x%" PRIx64 24*5ffd83dbSDimitry Andric " has unsupported address size %" PRIu8 25*5ffd83dbSDimitry Andric " (4 and 8 are supported)", 26*5ffd83dbSDimitry Andric Offset, AddrSize); 27*5ffd83dbSDimitry Andric if (DataSize % AddrSize != 0) { 280b57cec5SDimitry Andric invalidateLength(); 29*5ffd83dbSDimitry Andric return createStringError(errc::invalid_argument, 30*5ffd83dbSDimitry Andric "address table at offset 0x%" PRIx64 31*5ffd83dbSDimitry Andric " contains data of size 0x%" PRIx64 32*5ffd83dbSDimitry Andric " which is not a multiple of addr size %" PRIu8, 33*5ffd83dbSDimitry Andric Offset, DataSize, AddrSize); 34*5ffd83dbSDimitry Andric } 35*5ffd83dbSDimitry Andric Addrs.clear(); 36*5ffd83dbSDimitry Andric size_t Count = DataSize / AddrSize; 37*5ffd83dbSDimitry Andric Addrs.reserve(Count); 38*5ffd83dbSDimitry Andric while (Count--) 39*5ffd83dbSDimitry Andric Addrs.push_back(Data.getRelocatedValue(AddrSize, OffsetPtr)); 40*5ffd83dbSDimitry Andric return Error::success(); 410b57cec5SDimitry Andric } 420b57cec5SDimitry Andric 43*5ffd83dbSDimitry Andric Error DWARFDebugAddrTable::extractV5(const DWARFDataExtractor &Data, 44*5ffd83dbSDimitry Andric uint64_t *OffsetPtr, uint8_t CUAddrSize, 450b57cec5SDimitry Andric std::function<void(Error)> WarnCallback) { 46*5ffd83dbSDimitry Andric Offset = *OffsetPtr; 47*5ffd83dbSDimitry Andric llvm::Error Err = Error::success(); 48*5ffd83dbSDimitry Andric std::tie(Length, Format) = Data.getInitialLength(OffsetPtr, &Err); 49*5ffd83dbSDimitry Andric if (Err) { 50*5ffd83dbSDimitry Andric invalidateLength(); 510b57cec5SDimitry Andric return createStringError(errc::invalid_argument, 52*5ffd83dbSDimitry Andric "parsing address table at offset 0x%" PRIx64 53*5ffd83dbSDimitry Andric ": %s", 54*5ffd83dbSDimitry Andric Offset, toString(std::move(Err)).c_str()); 55*5ffd83dbSDimitry Andric } 56*5ffd83dbSDimitry Andric 57*5ffd83dbSDimitry Andric if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, Length)) { 58*5ffd83dbSDimitry Andric uint64_t DiagnosticLength = Length; 59*5ffd83dbSDimitry Andric invalidateLength(); 60*5ffd83dbSDimitry Andric return createStringError( 61*5ffd83dbSDimitry Andric errc::invalid_argument, 62*5ffd83dbSDimitry Andric "section is not large enough to contain an address table " 63*5ffd83dbSDimitry Andric "at offset 0x%" PRIx64 " with a unit_length value of 0x%" PRIx64, 64*5ffd83dbSDimitry Andric Offset, DiagnosticLength); 65*5ffd83dbSDimitry Andric } 66*5ffd83dbSDimitry Andric uint64_t EndOffset = *OffsetPtr + Length; 67*5ffd83dbSDimitry Andric // Ensure that we can read the remaining header fields. 68*5ffd83dbSDimitry Andric if (Length < 4) { 69*5ffd83dbSDimitry Andric uint64_t DiagnosticLength = Length; 70*5ffd83dbSDimitry Andric invalidateLength(); 71*5ffd83dbSDimitry Andric return createStringError( 72*5ffd83dbSDimitry Andric errc::invalid_argument, 73*5ffd83dbSDimitry Andric "address table at offset 0x%" PRIx64 74*5ffd83dbSDimitry Andric " has a unit_length value of 0x%" PRIx64 75*5ffd83dbSDimitry Andric ", which is too small to contain a complete header", 76*5ffd83dbSDimitry Andric Offset, DiagnosticLength); 77*5ffd83dbSDimitry Andric } 78*5ffd83dbSDimitry Andric 79*5ffd83dbSDimitry Andric Version = Data.getU16(OffsetPtr); 80*5ffd83dbSDimitry Andric AddrSize = Data.getU8(OffsetPtr); 81*5ffd83dbSDimitry Andric SegSize = Data.getU8(OffsetPtr); 82*5ffd83dbSDimitry Andric 83*5ffd83dbSDimitry Andric // Perform a basic validation of the header fields. 84*5ffd83dbSDimitry Andric if (Version != 5) 85*5ffd83dbSDimitry Andric return createStringError(errc::not_supported, 86*5ffd83dbSDimitry Andric "address table at offset 0x%" PRIx64 87*5ffd83dbSDimitry Andric " has unsupported version %" PRIu16, 88*5ffd83dbSDimitry Andric Offset, Version); 89*5ffd83dbSDimitry Andric // TODO: add support for non-zero segment selector size. 90*5ffd83dbSDimitry Andric if (SegSize != 0) 91*5ffd83dbSDimitry Andric return createStringError(errc::not_supported, 92*5ffd83dbSDimitry Andric "address table at offset 0x%" PRIx64 93*5ffd83dbSDimitry Andric " has unsupported segment selector size %" PRIu8, 94*5ffd83dbSDimitry Andric Offset, SegSize); 95*5ffd83dbSDimitry Andric 96*5ffd83dbSDimitry Andric if (Error Err = extractAddresses(Data, OffsetPtr, EndOffset)) 97*5ffd83dbSDimitry Andric return Err; 98*5ffd83dbSDimitry Andric if (CUAddrSize && AddrSize != CUAddrSize) { 99*5ffd83dbSDimitry Andric WarnCallback(createStringError( 100*5ffd83dbSDimitry Andric errc::invalid_argument, 101*5ffd83dbSDimitry Andric "address table at offset 0x%" PRIx64 " has address size %" PRIu8 102*5ffd83dbSDimitry Andric " which is different from CU address size %" PRIu8, 103*5ffd83dbSDimitry Andric Offset, AddrSize, CUAddrSize)); 104*5ffd83dbSDimitry Andric } 105*5ffd83dbSDimitry Andric return Error::success(); 106*5ffd83dbSDimitry Andric } 107*5ffd83dbSDimitry Andric 108*5ffd83dbSDimitry Andric Error DWARFDebugAddrTable::extractPreStandard(const DWARFDataExtractor &Data, 109*5ffd83dbSDimitry Andric uint64_t *OffsetPtr, 110*5ffd83dbSDimitry Andric uint16_t CUVersion, 111*5ffd83dbSDimitry Andric uint8_t CUAddrSize) { 112*5ffd83dbSDimitry Andric assert(CUVersion > 0 && CUVersion < 5); 113*5ffd83dbSDimitry Andric 114*5ffd83dbSDimitry Andric Offset = *OffsetPtr; 115*5ffd83dbSDimitry Andric Length = 0; 116*5ffd83dbSDimitry Andric Version = CUVersion; 117*5ffd83dbSDimitry Andric AddrSize = CUAddrSize; 118*5ffd83dbSDimitry Andric SegSize = 0; 119*5ffd83dbSDimitry Andric 120*5ffd83dbSDimitry Andric return extractAddresses(Data, OffsetPtr, Data.size()); 121*5ffd83dbSDimitry Andric } 122*5ffd83dbSDimitry Andric 123*5ffd83dbSDimitry Andric Error DWARFDebugAddrTable::extract(const DWARFDataExtractor &Data, 124*5ffd83dbSDimitry Andric uint64_t *OffsetPtr, 125*5ffd83dbSDimitry Andric uint16_t CUVersion, 126*5ffd83dbSDimitry Andric uint8_t CUAddrSize, 127*5ffd83dbSDimitry Andric std::function<void(Error)> WarnCallback) { 128*5ffd83dbSDimitry Andric if (CUVersion > 0 && CUVersion < 5) 129*5ffd83dbSDimitry Andric return extractPreStandard(Data, OffsetPtr, CUVersion, CUAddrSize); 130*5ffd83dbSDimitry Andric if (CUVersion == 0) 1310b57cec5SDimitry Andric WarnCallback(createStringError(errc::invalid_argument, 1320b57cec5SDimitry Andric "DWARF version is not defined in CU," 1330b57cec5SDimitry Andric " assuming version 5")); 134*5ffd83dbSDimitry Andric return extractV5(Data, OffsetPtr, CUAddrSize, WarnCallback); 1350b57cec5SDimitry Andric } 1360b57cec5SDimitry Andric 1370b57cec5SDimitry Andric void DWARFDebugAddrTable::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const { 1380b57cec5SDimitry Andric if (DumpOpts.Verbose) 139*5ffd83dbSDimitry Andric OS << format("0x%8.8" PRIx64 ": ", Offset); 140*5ffd83dbSDimitry Andric if (Length) { 141*5ffd83dbSDimitry Andric int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(Format); 142*5ffd83dbSDimitry Andric OS << "Address table header: " 143*5ffd83dbSDimitry Andric << format("length = 0x%0*" PRIx64, OffsetDumpWidth, Length) 144*5ffd83dbSDimitry Andric << ", format = " << dwarf::FormatString(Format) 145*5ffd83dbSDimitry Andric << format(", version = 0x%4.4" PRIx16, Version) 146*5ffd83dbSDimitry Andric << format(", addr_size = 0x%2.2" PRIx8, AddrSize) 147*5ffd83dbSDimitry Andric << format(", seg_size = 0x%2.2" PRIx8, SegSize) << "\n"; 148*5ffd83dbSDimitry Andric } 1490b57cec5SDimitry Andric 1500b57cec5SDimitry Andric if (Addrs.size() > 0) { 151*5ffd83dbSDimitry Andric const char *AddrFmt = 152*5ffd83dbSDimitry Andric (AddrSize == 4) ? "0x%8.8" PRIx64 "\n" : "0x%16.16" PRIx64 "\n"; 1530b57cec5SDimitry Andric OS << "Addrs: [\n"; 1540b57cec5SDimitry Andric for (uint64_t Addr : Addrs) 1550b57cec5SDimitry Andric OS << format(AddrFmt, Addr); 1560b57cec5SDimitry Andric OS << "]\n"; 1570b57cec5SDimitry Andric } 1580b57cec5SDimitry Andric } 1590b57cec5SDimitry Andric 1600b57cec5SDimitry Andric Expected<uint64_t> DWARFDebugAddrTable::getAddrEntry(uint32_t Index) const { 1610b57cec5SDimitry Andric if (Index < Addrs.size()) 1620b57cec5SDimitry Andric return Addrs[Index]; 1630b57cec5SDimitry Andric return createStringError(errc::invalid_argument, 1640b57cec5SDimitry Andric "Index %" PRIu32 " is out of range of the " 165*5ffd83dbSDimitry Andric "address table at offset 0x%" PRIx64, 166*5ffd83dbSDimitry Andric Index, Offset); 1670b57cec5SDimitry Andric } 1680b57cec5SDimitry Andric 169*5ffd83dbSDimitry Andric Optional<uint64_t> DWARFDebugAddrTable::getFullLength() const { 170*5ffd83dbSDimitry Andric if (Length == 0) 171*5ffd83dbSDimitry Andric return None; 172*5ffd83dbSDimitry Andric return Length + dwarf::getUnitLengthFieldByteSize(Format); 1730b57cec5SDimitry Andric } 1740b57cec5SDimitry Andric 175