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 void DWARFDebugAddrTable::clear() { 16 HeaderData = {}; 17 Addrs.clear(); 18 invalidateLength(); 19 } 20 21 Error DWARFDebugAddrTable::extract(DWARFDataExtractor Data, 22 uint32_t *OffsetPtr, 23 uint16_t Version, 24 uint8_t AddrSize, 25 std::function<void(Error)> WarnCallback) { 26 clear(); 27 HeaderOffset = *OffsetPtr; 28 // Read and verify the length field. 29 if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, sizeof(uint32_t))) 30 return createStringError(errc::invalid_argument, 31 "section is not large enough to contain a " 32 ".debug_addr table length at offset 0x%" 33 PRIx32, *OffsetPtr); 34 uint16_t UnitVersion; 35 if (Version == 0) { 36 WarnCallback(createStringError(errc::invalid_argument, 37 "DWARF version is not defined in CU," 38 " assuming version 5")); 39 UnitVersion = 5; 40 } else { 41 UnitVersion = Version; 42 } 43 // TODO: Add support for DWARF64. 44 Format = dwarf::DwarfFormat::DWARF32; 45 if (UnitVersion >= 5) { 46 HeaderData.Length = Data.getU32(OffsetPtr); 47 if (HeaderData.Length == 0xffffffffu) { 48 invalidateLength(); 49 return createStringError(errc::not_supported, 50 "DWARF64 is not supported in .debug_addr at offset 0x%" PRIx32, 51 HeaderOffset); 52 } 53 if (HeaderData.Length + sizeof(uint32_t) < sizeof(Header)) { 54 uint32_t TmpLength = getLength(); 55 invalidateLength(); 56 return createStringError(errc::invalid_argument, 57 ".debug_addr table at offset 0x%" PRIx32 58 " has too small length (0x%" PRIx32 59 ") to contain a complete header", 60 HeaderOffset, TmpLength); 61 } 62 uint32_t End = HeaderOffset + getLength(); 63 if (!Data.isValidOffsetForDataOfSize(HeaderOffset, End - HeaderOffset)) { 64 uint32_t TmpLength = getLength(); 65 invalidateLength(); 66 return createStringError(errc::invalid_argument, 67 "section is not large enough to contain a .debug_addr table " 68 "of length 0x%" PRIx32 " at offset 0x%" PRIx32, 69 TmpLength, HeaderOffset); 70 } 71 72 HeaderData.Version = Data.getU16(OffsetPtr); 73 HeaderData.AddrSize = Data.getU8(OffsetPtr); 74 HeaderData.SegSize = Data.getU8(OffsetPtr); 75 DataSize = getDataSize(); 76 } else { 77 HeaderData.Version = UnitVersion; 78 HeaderData.AddrSize = AddrSize; 79 // TODO: Support for non-zero SegSize. 80 HeaderData.SegSize = 0; 81 DataSize = Data.size(); 82 } 83 84 // Perform basic validation of the remaining header fields. 85 86 // We support DWARF version 5 for now as well as pre-DWARF5 87 // implementations of .debug_addr table, which doesn't contain a header 88 // and consists only of a series of addresses. 89 if (HeaderData.Version > 5) { 90 return createStringError(errc::not_supported, "version %" PRIu16 91 " of .debug_addr section at offset 0x%" PRIx32 " is not supported", 92 HeaderData.Version, HeaderOffset); 93 } 94 // FIXME: For now we just treat version mismatch as an error, 95 // however the correct way to associate a .debug_addr table 96 // with a .debug_info table is to look at the DW_AT_addr_base 97 // attribute in the info table. 98 if (HeaderData.Version != UnitVersion) 99 return createStringError(errc::invalid_argument, 100 ".debug_addr table at offset 0x%" PRIx32 101 " has version %" PRIu16 102 " which is different from the version suggested" 103 " by the DWARF unit header: %" PRIu16, 104 HeaderOffset, HeaderData.Version, UnitVersion); 105 if (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8) 106 return createStringError(errc::not_supported, 107 ".debug_addr table at offset 0x%" PRIx32 108 " has unsupported address size %" PRIu8, 109 HeaderOffset, HeaderData.AddrSize); 110 if (HeaderData.AddrSize != AddrSize && AddrSize != 0) 111 return createStringError(errc::invalid_argument, 112 ".debug_addr table at offset 0x%" PRIx32 113 " has address size %" PRIu8 114 " which is different from CU address size %" PRIu8, 115 HeaderOffset, HeaderData.AddrSize, AddrSize); 116 117 // TODO: add support for non-zero segment selector size. 118 if (HeaderData.SegSize != 0) 119 return createStringError(errc::not_supported, 120 ".debug_addr table at offset 0x%" PRIx32 121 " has unsupported segment selector size %" PRIu8, 122 HeaderOffset, HeaderData.SegSize); 123 if (DataSize % HeaderData.AddrSize != 0) { 124 invalidateLength(); 125 return createStringError(errc::invalid_argument, 126 ".debug_addr table at offset 0x%" PRIx32 127 " contains data of size %" PRIu32 128 " which is not a multiple of addr size %" PRIu8, 129 HeaderOffset, DataSize, HeaderData.AddrSize); 130 } 131 Data.setAddressSize(HeaderData.AddrSize); 132 uint32_t AddrCount = DataSize / HeaderData.AddrSize; 133 for (uint32_t I = 0; I < AddrCount; ++I) 134 if (HeaderData.AddrSize == 4) 135 Addrs.push_back(Data.getU32(OffsetPtr)); 136 else 137 Addrs.push_back(Data.getU64(OffsetPtr)); 138 return Error::success(); 139 } 140 141 void DWARFDebugAddrTable::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const { 142 if (DumpOpts.Verbose) 143 OS << format("0x%8.8" PRIx32 ": ", HeaderOffset); 144 OS << format("Addr Section: length = 0x%8.8" PRIx32 145 ", version = 0x%4.4" PRIx16 ", " 146 "addr_size = 0x%2.2" PRIx8 ", seg_size = 0x%2.2" PRIx8 "\n", 147 HeaderData.Length, HeaderData.Version, HeaderData.AddrSize, 148 HeaderData.SegSize); 149 150 static const char *Fmt32 = "0x%8.8" PRIx64; 151 static const char *Fmt64 = "0x%16.16" PRIx64; 152 std::string AddrFmt = "\n"; 153 std::string AddrFmtVerbose = " => "; 154 if (HeaderData.AddrSize == 4) { 155 AddrFmt.append(Fmt32); 156 AddrFmtVerbose.append(Fmt32); 157 } 158 else { 159 AddrFmt.append(Fmt64); 160 AddrFmtVerbose.append(Fmt64); 161 } 162 163 if (Addrs.size() > 0) { 164 OS << "Addrs: ["; 165 for (uint64_t Addr : Addrs) { 166 OS << format(AddrFmt.c_str(), Addr); 167 if (DumpOpts.Verbose) 168 OS << format(AddrFmtVerbose.c_str(), 169 Addr + HeaderOffset + sizeof(HeaderData)); 170 } 171 OS << "\n]\n"; 172 } 173 } 174 175 Expected<uint64_t> DWARFDebugAddrTable::getAddrEntry(uint32_t Index) const { 176 if (Index < Addrs.size()) 177 return Addrs[Index]; 178 return createStringError(errc::invalid_argument, 179 "Index %" PRIu32 " is out of range of the " 180 ".debug_addr table at offset 0x%" PRIx32, 181 Index, HeaderOffset); 182 } 183 184 uint32_t DWARFDebugAddrTable::getLength() const { 185 if (HeaderData.Length == 0) 186 return 0; 187 // TODO: DWARF64 support. 188 return HeaderData.Length + sizeof(uint32_t); 189 } 190 191 uint32_t DWARFDebugAddrTable::getDataSize() const { 192 if (DataSize != 0) 193 return DataSize; 194 if (getLength() == 0) 195 return 0; 196 return getLength() - getHeaderSize(); 197 } 198