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/DWARFContext.h" 12 #include "llvm/Support/Errc.h" 13 14 using namespace llvm; 15 16 Error 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%" PRIx64 30 " contains data of size 0x%" PRIx64 31 " 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 42 Error 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%" PRIx64 52 ": %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%" PRIx64 73 " has a unit_length value of 0x%" PRIx64 74 ", 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%" PRIx64 86 " 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%" PRIx64 92 " 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 %" PRIu8 101 " which is different from CU address size %" PRIu8, 102 Offset, AddrSize, CUAddrSize)); 103 } 104 return Error::success(); 105 } 106 107 Error 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 122 Error 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 136 void 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 171 Expected<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 180 std::optional<uint64_t> DWARFDebugAddrTable::getFullLength() const { 181 if (Length == 0) 182 return std::nullopt; 183 return Length + dwarf::getUnitLengthFieldByteSize(Format); 184 } 185