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 // Check that we can read the unit length field. 48 if (!Data.isValidOffsetForDataOfSize(Offset, 4)) 49 return createStringError(errc::invalid_argument, 50 "section is not large enough to contain an " 51 "address table length at offset 0x%" PRIx64, 52 Offset); 53 Format = dwarf::DwarfFormat::DWARF32; 54 Length = Data.getU32(OffsetPtr); 55 if (Length == dwarf::DW_LENGTH_DWARF64) { 56 // Check that we can read the extended unit length field. 57 if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, 8)) { 58 invalidateLength(); 59 return createStringError( 60 errc::invalid_argument, 61 "section is not large enough to contain an extended length field " 62 "of the address table at offset 0x%" PRIx64, 63 Offset); 64 } 65 Format = dwarf::DwarfFormat::DWARF64; 66 Length = Data.getU64(OffsetPtr); 67 } else if (Length >= dwarf::DW_LENGTH_lo_reserved) { 68 uint64_t DiagnosticLength = Length; 69 invalidateLength(); 70 return createStringError( 71 errc::not_supported, 72 "address table at offset 0x%" PRIx64 73 " has unsupported reserved unit length of value 0x%" PRIx64, 74 Offset, DiagnosticLength); 75 } 76 77 if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, Length)) { 78 uint64_t DiagnosticLength = Length; 79 invalidateLength(); 80 return createStringError( 81 errc::invalid_argument, 82 "section is not large enough to contain an address table " 83 "at offset 0x%" PRIx64 " with a unit_length value of 0x%" PRIx64, 84 Offset, DiagnosticLength); 85 } 86 uint64_t EndOffset = *OffsetPtr + Length; 87 // Ensure that we can read the remaining header fields. 88 if (Length < 4) { 89 uint64_t DiagnosticLength = Length; 90 invalidateLength(); 91 return createStringError( 92 errc::invalid_argument, 93 "address table at offset 0x%" PRIx64 94 " has a unit_length value of 0x%" PRIx64 95 ", which is too small to contain a complete header", 96 Offset, DiagnosticLength); 97 } 98 99 Version = Data.getU16(OffsetPtr); 100 AddrSize = Data.getU8(OffsetPtr); 101 SegSize = Data.getU8(OffsetPtr); 102 103 // Perform a basic validation of the header fields. 104 if (Version != 5) 105 return createStringError(errc::not_supported, 106 "address table at offset 0x%" PRIx64 107 " has unsupported version %" PRIu16, 108 Offset, Version); 109 // TODO: add support for non-zero segment selector size. 110 if (SegSize != 0) 111 return createStringError(errc::not_supported, 112 "address table at offset 0x%" PRIx64 113 " has unsupported segment selector size %" PRIu8, 114 Offset, SegSize); 115 116 if (Error Err = extractAddresses(Data, OffsetPtr, EndOffset)) 117 return Err; 118 if (CUAddrSize && AddrSize != CUAddrSize) { 119 WarnCallback(createStringError( 120 errc::invalid_argument, 121 "address table at offset 0x%" PRIx64 " has address size %" PRIu8 122 " which is different from CU address size %" PRIu8, 123 Offset, AddrSize, CUAddrSize)); 124 } 125 return Error::success(); 126 } 127 128 Error DWARFDebugAddrTable::extractPreStandard(const DWARFDataExtractor &Data, 129 uint64_t *OffsetPtr, 130 uint16_t CUVersion, 131 uint8_t CUAddrSize) { 132 assert(CUVersion > 0 && CUVersion < 5); 133 134 Offset = *OffsetPtr; 135 Length = 0; 136 Version = CUVersion; 137 AddrSize = CUAddrSize; 138 SegSize = 0; 139 140 return extractAddresses(Data, OffsetPtr, Data.size()); 141 } 142 143 Error DWARFDebugAddrTable::extract(const DWARFDataExtractor &Data, 144 uint64_t *OffsetPtr, 145 uint16_t CUVersion, 146 uint8_t CUAddrSize, 147 std::function<void(Error)> WarnCallback) { 148 if (CUVersion > 0 && CUVersion < 5) 149 return extractPreStandard(Data, OffsetPtr, CUVersion, CUAddrSize); 150 if (CUVersion == 0) 151 WarnCallback(createStringError(errc::invalid_argument, 152 "DWARF version is not defined in CU," 153 " assuming version 5")); 154 return extractV5(Data, OffsetPtr, CUAddrSize, WarnCallback); 155 } 156 157 void DWARFDebugAddrTable::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const { 158 if (DumpOpts.Verbose) 159 OS << format("0x%8.8" PRIx64 ": ", Offset); 160 if (Length) { 161 int LengthFieldWidth = (Format == dwarf::DwarfFormat::DWARF64) ? 16 : 8; 162 OS << format("Address table header: length = 0x%0*" PRIx64 163 ", version = 0x%4.4" PRIx16 ", addr_size = 0x%2.2" PRIx8 164 ", seg_size = 0x%2.2" PRIx8 "\n", 165 LengthFieldWidth, Length, Version, AddrSize, SegSize); 166 } 167 168 if (Addrs.size() > 0) { 169 const char *AddrFmt = 170 (AddrSize == 4) ? "0x%8.8" PRIx64 "\n" : "0x%16.16" PRIx64 "\n"; 171 OS << "Addrs: [\n"; 172 for (uint64_t Addr : Addrs) 173 OS << format(AddrFmt, Addr); 174 OS << "]\n"; 175 } 176 } 177 178 Expected<uint64_t> DWARFDebugAddrTable::getAddrEntry(uint32_t Index) const { 179 if (Index < Addrs.size()) 180 return Addrs[Index]; 181 return createStringError(errc::invalid_argument, 182 "Index %" PRIu32 " is out of range of the " 183 "address table at offset 0x%" PRIx64, 184 Index, Offset); 185 } 186 187 Optional<uint64_t> DWARFDebugAddrTable::getFullLength() const { 188 if (Length == 0) 189 return None; 190 return Length + dwarf::getUnitLengthFieldByteSize(Format); 191 } 192 193