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