10b57cec5SDimitry Andric //===- DWARFDebugAddr.cpp -------------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFDebugAddr.h" 100b57cec5SDimitry Andric #include "llvm/BinaryFormat/Dwarf.h" 11*349cc55cSDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFContext.h" 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric using namespace llvm; 140b57cec5SDimitry Andric 155ffd83dbSDimitry Andric Error DWARFDebugAddrTable::extractAddresses(const DWARFDataExtractor &Data, 165ffd83dbSDimitry Andric uint64_t *OffsetPtr, 175ffd83dbSDimitry Andric uint64_t EndOffset) { 185ffd83dbSDimitry Andric assert(EndOffset >= *OffsetPtr); 195ffd83dbSDimitry Andric uint64_t DataSize = EndOffset - *OffsetPtr; 205ffd83dbSDimitry Andric assert(Data.isValidOffsetForDataOfSize(*OffsetPtr, DataSize)); 21*349cc55cSDimitry Andric if (Error SizeErr = DWARFContext::checkAddressSizeSupported( 22*349cc55cSDimitry Andric AddrSize, errc::not_supported, "address table at offset 0x%" PRIx64, 23*349cc55cSDimitry Andric Offset)) 24*349cc55cSDimitry Andric return SizeErr; 255ffd83dbSDimitry Andric if (DataSize % AddrSize != 0) { 260b57cec5SDimitry Andric invalidateLength(); 275ffd83dbSDimitry Andric return createStringError(errc::invalid_argument, 285ffd83dbSDimitry Andric "address table at offset 0x%" PRIx64 295ffd83dbSDimitry Andric " contains data of size 0x%" PRIx64 305ffd83dbSDimitry Andric " which is not a multiple of addr size %" PRIu8, 315ffd83dbSDimitry Andric Offset, DataSize, AddrSize); 325ffd83dbSDimitry Andric } 335ffd83dbSDimitry Andric Addrs.clear(); 345ffd83dbSDimitry Andric size_t Count = DataSize / AddrSize; 355ffd83dbSDimitry Andric Addrs.reserve(Count); 365ffd83dbSDimitry Andric while (Count--) 375ffd83dbSDimitry Andric Addrs.push_back(Data.getRelocatedValue(AddrSize, OffsetPtr)); 385ffd83dbSDimitry Andric return Error::success(); 390b57cec5SDimitry Andric } 400b57cec5SDimitry Andric 415ffd83dbSDimitry Andric Error DWARFDebugAddrTable::extractV5(const DWARFDataExtractor &Data, 425ffd83dbSDimitry Andric uint64_t *OffsetPtr, uint8_t CUAddrSize, 430b57cec5SDimitry Andric std::function<void(Error)> WarnCallback) { 445ffd83dbSDimitry Andric Offset = *OffsetPtr; 455ffd83dbSDimitry Andric llvm::Error Err = Error::success(); 465ffd83dbSDimitry Andric std::tie(Length, Format) = Data.getInitialLength(OffsetPtr, &Err); 475ffd83dbSDimitry Andric if (Err) { 485ffd83dbSDimitry Andric invalidateLength(); 490b57cec5SDimitry Andric return createStringError(errc::invalid_argument, 505ffd83dbSDimitry Andric "parsing address table at offset 0x%" PRIx64 515ffd83dbSDimitry Andric ": %s", 525ffd83dbSDimitry Andric Offset, toString(std::move(Err)).c_str()); 535ffd83dbSDimitry Andric } 545ffd83dbSDimitry Andric 555ffd83dbSDimitry Andric if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, Length)) { 565ffd83dbSDimitry Andric uint64_t DiagnosticLength = Length; 575ffd83dbSDimitry Andric invalidateLength(); 585ffd83dbSDimitry Andric return createStringError( 595ffd83dbSDimitry Andric errc::invalid_argument, 605ffd83dbSDimitry Andric "section is not large enough to contain an address table " 615ffd83dbSDimitry Andric "at offset 0x%" PRIx64 " with a unit_length value of 0x%" PRIx64, 625ffd83dbSDimitry Andric Offset, DiagnosticLength); 635ffd83dbSDimitry Andric } 645ffd83dbSDimitry Andric uint64_t EndOffset = *OffsetPtr + Length; 655ffd83dbSDimitry Andric // Ensure that we can read the remaining header fields. 665ffd83dbSDimitry Andric if (Length < 4) { 675ffd83dbSDimitry Andric uint64_t DiagnosticLength = Length; 685ffd83dbSDimitry Andric invalidateLength(); 695ffd83dbSDimitry Andric return createStringError( 705ffd83dbSDimitry Andric errc::invalid_argument, 715ffd83dbSDimitry Andric "address table at offset 0x%" PRIx64 725ffd83dbSDimitry Andric " has a unit_length value of 0x%" PRIx64 735ffd83dbSDimitry Andric ", which is too small to contain a complete header", 745ffd83dbSDimitry Andric Offset, DiagnosticLength); 755ffd83dbSDimitry Andric } 765ffd83dbSDimitry Andric 775ffd83dbSDimitry Andric Version = Data.getU16(OffsetPtr); 785ffd83dbSDimitry Andric AddrSize = Data.getU8(OffsetPtr); 795ffd83dbSDimitry Andric SegSize = Data.getU8(OffsetPtr); 805ffd83dbSDimitry Andric 815ffd83dbSDimitry Andric // Perform a basic validation of the header fields. 825ffd83dbSDimitry Andric if (Version != 5) 835ffd83dbSDimitry Andric return createStringError(errc::not_supported, 845ffd83dbSDimitry Andric "address table at offset 0x%" PRIx64 855ffd83dbSDimitry Andric " has unsupported version %" PRIu16, 865ffd83dbSDimitry Andric Offset, Version); 875ffd83dbSDimitry Andric // TODO: add support for non-zero segment selector size. 885ffd83dbSDimitry Andric if (SegSize != 0) 895ffd83dbSDimitry Andric return createStringError(errc::not_supported, 905ffd83dbSDimitry Andric "address table at offset 0x%" PRIx64 915ffd83dbSDimitry Andric " has unsupported segment selector size %" PRIu8, 925ffd83dbSDimitry Andric Offset, SegSize); 935ffd83dbSDimitry Andric 945ffd83dbSDimitry Andric if (Error Err = extractAddresses(Data, OffsetPtr, EndOffset)) 955ffd83dbSDimitry Andric return Err; 965ffd83dbSDimitry Andric if (CUAddrSize && AddrSize != CUAddrSize) { 975ffd83dbSDimitry Andric WarnCallback(createStringError( 985ffd83dbSDimitry Andric errc::invalid_argument, 995ffd83dbSDimitry Andric "address table at offset 0x%" PRIx64 " has address size %" PRIu8 1005ffd83dbSDimitry Andric " which is different from CU address size %" PRIu8, 1015ffd83dbSDimitry Andric Offset, AddrSize, CUAddrSize)); 1025ffd83dbSDimitry Andric } 1035ffd83dbSDimitry Andric return Error::success(); 1045ffd83dbSDimitry Andric } 1055ffd83dbSDimitry Andric 1065ffd83dbSDimitry Andric Error DWARFDebugAddrTable::extractPreStandard(const DWARFDataExtractor &Data, 1075ffd83dbSDimitry Andric uint64_t *OffsetPtr, 1085ffd83dbSDimitry Andric uint16_t CUVersion, 1095ffd83dbSDimitry Andric uint8_t CUAddrSize) { 1105ffd83dbSDimitry Andric assert(CUVersion > 0 && CUVersion < 5); 1115ffd83dbSDimitry Andric 1125ffd83dbSDimitry Andric Offset = *OffsetPtr; 1135ffd83dbSDimitry Andric Length = 0; 1145ffd83dbSDimitry Andric Version = CUVersion; 1155ffd83dbSDimitry Andric AddrSize = CUAddrSize; 1165ffd83dbSDimitry Andric SegSize = 0; 1175ffd83dbSDimitry Andric 1185ffd83dbSDimitry Andric return extractAddresses(Data, OffsetPtr, Data.size()); 1195ffd83dbSDimitry Andric } 1205ffd83dbSDimitry Andric 1215ffd83dbSDimitry Andric Error DWARFDebugAddrTable::extract(const DWARFDataExtractor &Data, 1225ffd83dbSDimitry Andric uint64_t *OffsetPtr, 1235ffd83dbSDimitry Andric uint16_t CUVersion, 1245ffd83dbSDimitry Andric uint8_t CUAddrSize, 1255ffd83dbSDimitry Andric std::function<void(Error)> WarnCallback) { 1265ffd83dbSDimitry Andric if (CUVersion > 0 && CUVersion < 5) 1275ffd83dbSDimitry Andric return extractPreStandard(Data, OffsetPtr, CUVersion, CUAddrSize); 1285ffd83dbSDimitry Andric if (CUVersion == 0) 1290b57cec5SDimitry Andric WarnCallback(createStringError(errc::invalid_argument, 1300b57cec5SDimitry Andric "DWARF version is not defined in CU," 1310b57cec5SDimitry Andric " assuming version 5")); 1325ffd83dbSDimitry Andric return extractV5(Data, OffsetPtr, CUAddrSize, WarnCallback); 1330b57cec5SDimitry Andric } 1340b57cec5SDimitry Andric 1350b57cec5SDimitry Andric void DWARFDebugAddrTable::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const { 1360b57cec5SDimitry Andric if (DumpOpts.Verbose) 1375ffd83dbSDimitry Andric OS << format("0x%8.8" PRIx64 ": ", Offset); 1385ffd83dbSDimitry Andric if (Length) { 1395ffd83dbSDimitry Andric int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(Format); 1405ffd83dbSDimitry Andric OS << "Address table header: " 1415ffd83dbSDimitry Andric << format("length = 0x%0*" PRIx64, OffsetDumpWidth, Length) 1425ffd83dbSDimitry Andric << ", format = " << dwarf::FormatString(Format) 1435ffd83dbSDimitry Andric << format(", version = 0x%4.4" PRIx16, Version) 1445ffd83dbSDimitry Andric << format(", addr_size = 0x%2.2" PRIx8, AddrSize) 1455ffd83dbSDimitry Andric << format(", seg_size = 0x%2.2" PRIx8, SegSize) << "\n"; 1465ffd83dbSDimitry Andric } 1470b57cec5SDimitry Andric 1480b57cec5SDimitry Andric if (Addrs.size() > 0) { 149*349cc55cSDimitry Andric const char *AddrFmt; 150*349cc55cSDimitry Andric switch (AddrSize) { 151*349cc55cSDimitry Andric case 2: 152*349cc55cSDimitry Andric AddrFmt = "0x%4.4" PRIx64 "\n"; 153*349cc55cSDimitry Andric break; 154*349cc55cSDimitry Andric case 4: 155*349cc55cSDimitry Andric AddrFmt = "0x%8.8" PRIx64 "\n"; 156*349cc55cSDimitry Andric break; 157*349cc55cSDimitry Andric case 8: 158*349cc55cSDimitry Andric AddrFmt = "0x%16.16" PRIx64 "\n"; 159*349cc55cSDimitry Andric break; 160*349cc55cSDimitry Andric default: 161*349cc55cSDimitry Andric llvm_unreachable("unsupported address size"); 162*349cc55cSDimitry Andric } 1630b57cec5SDimitry Andric OS << "Addrs: [\n"; 1640b57cec5SDimitry Andric for (uint64_t Addr : Addrs) 1650b57cec5SDimitry Andric OS << format(AddrFmt, Addr); 1660b57cec5SDimitry Andric OS << "]\n"; 1670b57cec5SDimitry Andric } 1680b57cec5SDimitry Andric } 1690b57cec5SDimitry Andric 1700b57cec5SDimitry Andric Expected<uint64_t> DWARFDebugAddrTable::getAddrEntry(uint32_t Index) const { 1710b57cec5SDimitry Andric if (Index < Addrs.size()) 1720b57cec5SDimitry Andric return Addrs[Index]; 1730b57cec5SDimitry Andric return createStringError(errc::invalid_argument, 1740b57cec5SDimitry Andric "Index %" PRIu32 " is out of range of the " 1755ffd83dbSDimitry Andric "address table at offset 0x%" PRIx64, 1765ffd83dbSDimitry Andric Index, Offset); 1770b57cec5SDimitry Andric } 1780b57cec5SDimitry Andric 1795ffd83dbSDimitry Andric Optional<uint64_t> DWARFDebugAddrTable::getFullLength() const { 1805ffd83dbSDimitry Andric if (Length == 0) 1815ffd83dbSDimitry Andric return None; 1825ffd83dbSDimitry Andric return Length + dwarf::getUnitLengthFieldByteSize(Format); 1830b57cec5SDimitry Andric } 1840b57cec5SDimitry Andric 185