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" 11349cc55cSDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFContext.h" 12*81ad6265SDimitry Andric #include "llvm/Support/Errc.h" 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric using namespace llvm; 150b57cec5SDimitry Andric 165ffd83dbSDimitry Andric Error DWARFDebugAddrTable::extractAddresses(const DWARFDataExtractor &Data, 175ffd83dbSDimitry Andric uint64_t *OffsetPtr, 185ffd83dbSDimitry Andric uint64_t EndOffset) { 195ffd83dbSDimitry Andric assert(EndOffset >= *OffsetPtr); 205ffd83dbSDimitry Andric uint64_t DataSize = EndOffset - *OffsetPtr; 215ffd83dbSDimitry Andric assert(Data.isValidOffsetForDataOfSize(*OffsetPtr, DataSize)); 22349cc55cSDimitry Andric if (Error SizeErr = DWARFContext::checkAddressSizeSupported( 23349cc55cSDimitry Andric AddrSize, errc::not_supported, "address table at offset 0x%" PRIx64, 24349cc55cSDimitry Andric Offset)) 25349cc55cSDimitry Andric return SizeErr; 265ffd83dbSDimitry Andric if (DataSize % AddrSize != 0) { 270b57cec5SDimitry Andric invalidateLength(); 285ffd83dbSDimitry Andric return createStringError(errc::invalid_argument, 295ffd83dbSDimitry Andric "address table at offset 0x%" PRIx64 305ffd83dbSDimitry Andric " contains data of size 0x%" PRIx64 315ffd83dbSDimitry Andric " which is not a multiple of addr size %" PRIu8, 325ffd83dbSDimitry Andric Offset, DataSize, AddrSize); 335ffd83dbSDimitry Andric } 345ffd83dbSDimitry Andric Addrs.clear(); 355ffd83dbSDimitry Andric size_t Count = DataSize / AddrSize; 365ffd83dbSDimitry Andric Addrs.reserve(Count); 375ffd83dbSDimitry Andric while (Count--) 385ffd83dbSDimitry Andric Addrs.push_back(Data.getRelocatedValue(AddrSize, OffsetPtr)); 395ffd83dbSDimitry Andric return Error::success(); 400b57cec5SDimitry Andric } 410b57cec5SDimitry Andric 425ffd83dbSDimitry Andric Error DWARFDebugAddrTable::extractV5(const DWARFDataExtractor &Data, 435ffd83dbSDimitry Andric uint64_t *OffsetPtr, uint8_t CUAddrSize, 440b57cec5SDimitry Andric std::function<void(Error)> WarnCallback) { 455ffd83dbSDimitry Andric Offset = *OffsetPtr; 465ffd83dbSDimitry Andric llvm::Error Err = Error::success(); 475ffd83dbSDimitry Andric std::tie(Length, Format) = Data.getInitialLength(OffsetPtr, &Err); 485ffd83dbSDimitry Andric if (Err) { 495ffd83dbSDimitry Andric invalidateLength(); 500b57cec5SDimitry Andric return createStringError(errc::invalid_argument, 515ffd83dbSDimitry Andric "parsing address table at offset 0x%" PRIx64 525ffd83dbSDimitry Andric ": %s", 535ffd83dbSDimitry Andric Offset, toString(std::move(Err)).c_str()); 545ffd83dbSDimitry Andric } 555ffd83dbSDimitry Andric 565ffd83dbSDimitry Andric if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, Length)) { 575ffd83dbSDimitry Andric uint64_t DiagnosticLength = Length; 585ffd83dbSDimitry Andric invalidateLength(); 595ffd83dbSDimitry Andric return createStringError( 605ffd83dbSDimitry Andric errc::invalid_argument, 615ffd83dbSDimitry Andric "section is not large enough to contain an address table " 625ffd83dbSDimitry Andric "at offset 0x%" PRIx64 " with a unit_length value of 0x%" PRIx64, 635ffd83dbSDimitry Andric Offset, DiagnosticLength); 645ffd83dbSDimitry Andric } 655ffd83dbSDimitry Andric uint64_t EndOffset = *OffsetPtr + Length; 665ffd83dbSDimitry Andric // Ensure that we can read the remaining header fields. 675ffd83dbSDimitry Andric if (Length < 4) { 685ffd83dbSDimitry Andric uint64_t DiagnosticLength = Length; 695ffd83dbSDimitry Andric invalidateLength(); 705ffd83dbSDimitry Andric return createStringError( 715ffd83dbSDimitry Andric errc::invalid_argument, 725ffd83dbSDimitry Andric "address table at offset 0x%" PRIx64 735ffd83dbSDimitry Andric " has a unit_length value of 0x%" PRIx64 745ffd83dbSDimitry Andric ", which is too small to contain a complete header", 755ffd83dbSDimitry Andric Offset, DiagnosticLength); 765ffd83dbSDimitry Andric } 775ffd83dbSDimitry Andric 785ffd83dbSDimitry Andric Version = Data.getU16(OffsetPtr); 795ffd83dbSDimitry Andric AddrSize = Data.getU8(OffsetPtr); 805ffd83dbSDimitry Andric SegSize = Data.getU8(OffsetPtr); 815ffd83dbSDimitry Andric 825ffd83dbSDimitry Andric // Perform a basic validation of the header fields. 835ffd83dbSDimitry Andric if (Version != 5) 845ffd83dbSDimitry Andric return createStringError(errc::not_supported, 855ffd83dbSDimitry Andric "address table at offset 0x%" PRIx64 865ffd83dbSDimitry Andric " has unsupported version %" PRIu16, 875ffd83dbSDimitry Andric Offset, Version); 885ffd83dbSDimitry Andric // TODO: add support for non-zero segment selector size. 895ffd83dbSDimitry Andric if (SegSize != 0) 905ffd83dbSDimitry Andric return createStringError(errc::not_supported, 915ffd83dbSDimitry Andric "address table at offset 0x%" PRIx64 925ffd83dbSDimitry Andric " has unsupported segment selector size %" PRIu8, 935ffd83dbSDimitry Andric Offset, SegSize); 945ffd83dbSDimitry Andric 955ffd83dbSDimitry Andric if (Error Err = extractAddresses(Data, OffsetPtr, EndOffset)) 965ffd83dbSDimitry Andric return Err; 975ffd83dbSDimitry Andric if (CUAddrSize && AddrSize != CUAddrSize) { 985ffd83dbSDimitry Andric WarnCallback(createStringError( 995ffd83dbSDimitry Andric errc::invalid_argument, 1005ffd83dbSDimitry Andric "address table at offset 0x%" PRIx64 " has address size %" PRIu8 1015ffd83dbSDimitry Andric " which is different from CU address size %" PRIu8, 1025ffd83dbSDimitry Andric Offset, AddrSize, CUAddrSize)); 1035ffd83dbSDimitry Andric } 1045ffd83dbSDimitry Andric return Error::success(); 1055ffd83dbSDimitry Andric } 1065ffd83dbSDimitry Andric 1075ffd83dbSDimitry Andric Error DWARFDebugAddrTable::extractPreStandard(const DWARFDataExtractor &Data, 1085ffd83dbSDimitry Andric uint64_t *OffsetPtr, 1095ffd83dbSDimitry Andric uint16_t CUVersion, 1105ffd83dbSDimitry Andric uint8_t CUAddrSize) { 1115ffd83dbSDimitry Andric assert(CUVersion > 0 && CUVersion < 5); 1125ffd83dbSDimitry Andric 1135ffd83dbSDimitry Andric Offset = *OffsetPtr; 1145ffd83dbSDimitry Andric Length = 0; 1155ffd83dbSDimitry Andric Version = CUVersion; 1165ffd83dbSDimitry Andric AddrSize = CUAddrSize; 1175ffd83dbSDimitry Andric SegSize = 0; 1185ffd83dbSDimitry Andric 1195ffd83dbSDimitry Andric return extractAddresses(Data, OffsetPtr, Data.size()); 1205ffd83dbSDimitry Andric } 1215ffd83dbSDimitry Andric 1225ffd83dbSDimitry Andric Error DWARFDebugAddrTable::extract(const DWARFDataExtractor &Data, 1235ffd83dbSDimitry Andric uint64_t *OffsetPtr, 1245ffd83dbSDimitry Andric uint16_t CUVersion, 1255ffd83dbSDimitry Andric uint8_t CUAddrSize, 1265ffd83dbSDimitry Andric std::function<void(Error)> WarnCallback) { 1275ffd83dbSDimitry Andric if (CUVersion > 0 && CUVersion < 5) 1285ffd83dbSDimitry Andric return extractPreStandard(Data, OffsetPtr, CUVersion, CUAddrSize); 1295ffd83dbSDimitry Andric if (CUVersion == 0) 1300b57cec5SDimitry Andric WarnCallback(createStringError(errc::invalid_argument, 1310b57cec5SDimitry Andric "DWARF version is not defined in CU," 1320b57cec5SDimitry Andric " assuming version 5")); 1335ffd83dbSDimitry Andric return extractV5(Data, OffsetPtr, CUAddrSize, WarnCallback); 1340b57cec5SDimitry Andric } 1350b57cec5SDimitry Andric 1360b57cec5SDimitry Andric void DWARFDebugAddrTable::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const { 1370b57cec5SDimitry Andric if (DumpOpts.Verbose) 1385ffd83dbSDimitry Andric OS << format("0x%8.8" PRIx64 ": ", Offset); 1395ffd83dbSDimitry Andric if (Length) { 1405ffd83dbSDimitry Andric int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(Format); 1415ffd83dbSDimitry Andric OS << "Address table header: " 1425ffd83dbSDimitry Andric << format("length = 0x%0*" PRIx64, OffsetDumpWidth, Length) 1435ffd83dbSDimitry Andric << ", format = " << dwarf::FormatString(Format) 1445ffd83dbSDimitry Andric << format(", version = 0x%4.4" PRIx16, Version) 1455ffd83dbSDimitry Andric << format(", addr_size = 0x%2.2" PRIx8, AddrSize) 1465ffd83dbSDimitry Andric << format(", seg_size = 0x%2.2" PRIx8, SegSize) << "\n"; 1475ffd83dbSDimitry Andric } 1480b57cec5SDimitry Andric 1490b57cec5SDimitry Andric if (Addrs.size() > 0) { 150349cc55cSDimitry Andric const char *AddrFmt; 151349cc55cSDimitry Andric switch (AddrSize) { 152349cc55cSDimitry Andric case 2: 153349cc55cSDimitry Andric AddrFmt = "0x%4.4" PRIx64 "\n"; 154349cc55cSDimitry Andric break; 155349cc55cSDimitry Andric case 4: 156349cc55cSDimitry Andric AddrFmt = "0x%8.8" PRIx64 "\n"; 157349cc55cSDimitry Andric break; 158349cc55cSDimitry Andric case 8: 159349cc55cSDimitry Andric AddrFmt = "0x%16.16" PRIx64 "\n"; 160349cc55cSDimitry Andric break; 161349cc55cSDimitry Andric default: 162349cc55cSDimitry Andric llvm_unreachable("unsupported address size"); 163349cc55cSDimitry Andric } 1640b57cec5SDimitry Andric OS << "Addrs: [\n"; 1650b57cec5SDimitry Andric for (uint64_t Addr : Addrs) 1660b57cec5SDimitry Andric OS << format(AddrFmt, Addr); 1670b57cec5SDimitry Andric OS << "]\n"; 1680b57cec5SDimitry Andric } 1690b57cec5SDimitry Andric } 1700b57cec5SDimitry Andric 1710b57cec5SDimitry Andric Expected<uint64_t> DWARFDebugAddrTable::getAddrEntry(uint32_t Index) const { 1720b57cec5SDimitry Andric if (Index < Addrs.size()) 1730b57cec5SDimitry Andric return Addrs[Index]; 1740b57cec5SDimitry Andric return createStringError(errc::invalid_argument, 1750b57cec5SDimitry Andric "Index %" PRIu32 " is out of range of the " 1765ffd83dbSDimitry Andric "address table at offset 0x%" PRIx64, 1775ffd83dbSDimitry Andric Index, Offset); 1780b57cec5SDimitry Andric } 1790b57cec5SDimitry Andric 1805ffd83dbSDimitry Andric Optional<uint64_t> DWARFDebugAddrTable::getFullLength() const { 1815ffd83dbSDimitry Andric if (Length == 0) 1825ffd83dbSDimitry Andric return None; 1835ffd83dbSDimitry Andric return Length + dwarf::getUnitLengthFieldByteSize(Format); 1840b57cec5SDimitry Andric } 1850b57cec5SDimitry Andric 186