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