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