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