1337137Sdim//===- DWARFDebugAddr.cpp -------------------------------------------------===// 2337137Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6337137Sdim// 7337137Sdim//===----------------------------------------------------------------------===// 8337137Sdim 9337137Sdim#include "llvm/DebugInfo/DWARF/DWARFDebugAddr.h" 10337137Sdim#include "llvm/BinaryFormat/Dwarf.h" 11337137Sdim#include "llvm/DebugInfo/DWARF/DWARFUnit.h" 12337137Sdim 13337137Sdimusing namespace llvm; 14337137Sdim 15337137Sdimvoid DWARFDebugAddrTable::clear() { 16337137Sdim HeaderData = {}; 17337137Sdim Addrs.clear(); 18337137Sdim invalidateLength(); 19337137Sdim} 20337137Sdim 21337137SdimError DWARFDebugAddrTable::extract(DWARFDataExtractor Data, 22360784Sdim uint64_t *OffsetPtr, 23337137Sdim uint16_t Version, 24337137Sdim uint8_t AddrSize, 25337137Sdim std::function<void(Error)> WarnCallback) { 26337137Sdim clear(); 27337137Sdim HeaderOffset = *OffsetPtr; 28337137Sdim // Read and verify the length field. 29337137Sdim if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, sizeof(uint32_t))) 30337137Sdim return createStringError(errc::invalid_argument, 31337137Sdim "section is not large enough to contain a " 32337137Sdim ".debug_addr table length at offset 0x%" 33360784Sdim PRIx64, *OffsetPtr); 34337137Sdim uint16_t UnitVersion; 35337137Sdim if (Version == 0) { 36337137Sdim WarnCallback(createStringError(errc::invalid_argument, 37337137Sdim "DWARF version is not defined in CU," 38337137Sdim " assuming version 5")); 39337137Sdim UnitVersion = 5; 40337137Sdim } else { 41337137Sdim UnitVersion = Version; 42337137Sdim } 43337137Sdim // TODO: Add support for DWARF64. 44337137Sdim Format = dwarf::DwarfFormat::DWARF32; 45337137Sdim if (UnitVersion >= 5) { 46337137Sdim HeaderData.Length = Data.getU32(OffsetPtr); 47360784Sdim if (HeaderData.Length == dwarf::DW_LENGTH_DWARF64) { 48337137Sdim invalidateLength(); 49337137Sdim return createStringError(errc::not_supported, 50360784Sdim "DWARF64 is not supported in .debug_addr at offset 0x%" PRIx64, 51337137Sdim HeaderOffset); 52337137Sdim } 53337137Sdim if (HeaderData.Length + sizeof(uint32_t) < sizeof(Header)) { 54337137Sdim uint32_t TmpLength = getLength(); 55337137Sdim invalidateLength(); 56337137Sdim return createStringError(errc::invalid_argument, 57360784Sdim ".debug_addr table at offset 0x%" PRIx64 58337137Sdim " has too small length (0x%" PRIx32 59337137Sdim ") to contain a complete header", 60337137Sdim HeaderOffset, TmpLength); 61337137Sdim } 62360784Sdim uint64_t End = HeaderOffset + getLength(); 63337137Sdim if (!Data.isValidOffsetForDataOfSize(HeaderOffset, End - HeaderOffset)) { 64337137Sdim uint32_t TmpLength = getLength(); 65337137Sdim invalidateLength(); 66337137Sdim return createStringError(errc::invalid_argument, 67337137Sdim "section is not large enough to contain a .debug_addr table " 68360784Sdim "of length 0x%" PRIx32 " at offset 0x%" PRIx64, 69337137Sdim TmpLength, HeaderOffset); 70337137Sdim } 71337137Sdim 72337137Sdim HeaderData.Version = Data.getU16(OffsetPtr); 73337137Sdim HeaderData.AddrSize = Data.getU8(OffsetPtr); 74337137Sdim HeaderData.SegSize = Data.getU8(OffsetPtr); 75337137Sdim DataSize = getDataSize(); 76337137Sdim } else { 77337137Sdim HeaderData.Version = UnitVersion; 78337137Sdim HeaderData.AddrSize = AddrSize; 79337137Sdim // TODO: Support for non-zero SegSize. 80337137Sdim HeaderData.SegSize = 0; 81337137Sdim DataSize = Data.size(); 82337137Sdim } 83337137Sdim 84337137Sdim // Perform basic validation of the remaining header fields. 85337137Sdim 86337137Sdim // We support DWARF version 5 for now as well as pre-DWARF5 87337137Sdim // implementations of .debug_addr table, which doesn't contain a header 88337137Sdim // and consists only of a series of addresses. 89337137Sdim if (HeaderData.Version > 5) { 90337137Sdim return createStringError(errc::not_supported, "version %" PRIu16 91360784Sdim " of .debug_addr section at offset 0x%" PRIx64 " is not supported", 92337137Sdim HeaderData.Version, HeaderOffset); 93337137Sdim } 94337137Sdim // FIXME: For now we just treat version mismatch as an error, 95337137Sdim // however the correct way to associate a .debug_addr table 96337137Sdim // with a .debug_info table is to look at the DW_AT_addr_base 97337137Sdim // attribute in the info table. 98337137Sdim if (HeaderData.Version != UnitVersion) 99337137Sdim return createStringError(errc::invalid_argument, 100360784Sdim ".debug_addr table at offset 0x%" PRIx64 101337137Sdim " has version %" PRIu16 102337137Sdim " which is different from the version suggested" 103337137Sdim " by the DWARF unit header: %" PRIu16, 104337137Sdim HeaderOffset, HeaderData.Version, UnitVersion); 105337137Sdim if (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8) 106337137Sdim return createStringError(errc::not_supported, 107360784Sdim ".debug_addr table at offset 0x%" PRIx64 108337137Sdim " has unsupported address size %" PRIu8, 109337137Sdim HeaderOffset, HeaderData.AddrSize); 110337137Sdim if (HeaderData.AddrSize != AddrSize && AddrSize != 0) 111337137Sdim return createStringError(errc::invalid_argument, 112360784Sdim ".debug_addr table at offset 0x%" PRIx64 113337137Sdim " has address size %" PRIu8 114337137Sdim " which is different from CU address size %" PRIu8, 115337137Sdim HeaderOffset, HeaderData.AddrSize, AddrSize); 116337137Sdim 117337137Sdim // TODO: add support for non-zero segment selector size. 118337137Sdim if (HeaderData.SegSize != 0) 119337137Sdim return createStringError(errc::not_supported, 120360784Sdim ".debug_addr table at offset 0x%" PRIx64 121337137Sdim " has unsupported segment selector size %" PRIu8, 122337137Sdim HeaderOffset, HeaderData.SegSize); 123337137Sdim if (DataSize % HeaderData.AddrSize != 0) { 124337137Sdim invalidateLength(); 125337137Sdim return createStringError(errc::invalid_argument, 126360784Sdim ".debug_addr table at offset 0x%" PRIx64 127337137Sdim " contains data of size %" PRIu32 128337137Sdim " which is not a multiple of addr size %" PRIu8, 129337137Sdim HeaderOffset, DataSize, HeaderData.AddrSize); 130337137Sdim } 131337137Sdim Data.setAddressSize(HeaderData.AddrSize); 132337137Sdim uint32_t AddrCount = DataSize / HeaderData.AddrSize; 133337137Sdim for (uint32_t I = 0; I < AddrCount; ++I) 134337137Sdim if (HeaderData.AddrSize == 4) 135337137Sdim Addrs.push_back(Data.getU32(OffsetPtr)); 136337137Sdim else 137337137Sdim Addrs.push_back(Data.getU64(OffsetPtr)); 138337137Sdim return Error::success(); 139337137Sdim} 140337137Sdim 141337137Sdimvoid DWARFDebugAddrTable::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const { 142337137Sdim if (DumpOpts.Verbose) 143337137Sdim OS << format("0x%8.8" PRIx32 ": ", HeaderOffset); 144337137Sdim OS << format("Addr Section: length = 0x%8.8" PRIx32 145337137Sdim ", version = 0x%4.4" PRIx16 ", " 146337137Sdim "addr_size = 0x%2.2" PRIx8 ", seg_size = 0x%2.2" PRIx8 "\n", 147337137Sdim HeaderData.Length, HeaderData.Version, HeaderData.AddrSize, 148337137Sdim HeaderData.SegSize); 149337137Sdim 150337137Sdim if (Addrs.size() > 0) { 151353358Sdim const char *AddrFmt = (HeaderData.AddrSize == 4) ? "0x%8.8" PRIx64 "\n" 152353358Sdim : "0x%16.16" PRIx64 "\n"; 153353358Sdim OS << "Addrs: [\n"; 154353358Sdim for (uint64_t Addr : Addrs) 155353358Sdim OS << format(AddrFmt, Addr); 156353358Sdim OS << "]\n"; 157337137Sdim } 158337137Sdim} 159337137Sdim 160337137SdimExpected<uint64_t> DWARFDebugAddrTable::getAddrEntry(uint32_t Index) const { 161337137Sdim if (Index < Addrs.size()) 162337137Sdim return Addrs[Index]; 163337137Sdim return createStringError(errc::invalid_argument, 164337137Sdim "Index %" PRIu32 " is out of range of the " 165360784Sdim ".debug_addr table at offset 0x%" PRIx64, 166337137Sdim Index, HeaderOffset); 167337137Sdim} 168337137Sdim 169337137Sdimuint32_t DWARFDebugAddrTable::getLength() const { 170337137Sdim if (HeaderData.Length == 0) 171337137Sdim return 0; 172337137Sdim // TODO: DWARF64 support. 173337137Sdim return HeaderData.Length + sizeof(uint32_t); 174337137Sdim} 175337137Sdim 176337137Sdimuint32_t DWARFDebugAddrTable::getDataSize() const { 177337137Sdim if (DataSize != 0) 178337137Sdim return DataSize; 179337137Sdim if (getLength() == 0) 180337137Sdim return 0; 181337137Sdim return getLength() - getHeaderSize(); 182337137Sdim} 183