xref: /freebsd-src/contrib/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFDebugAddr.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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"
1281ad6265SDimitry Andric #include "llvm/Support/Errc.h"
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric using namespace llvm;
150b57cec5SDimitry Andric 
extractAddresses(const DWARFDataExtractor & Data,uint64_t * OffsetPtr,uint64_t EndOffset)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 
extractV5(const DWARFDataExtractor & Data,uint64_t * OffsetPtr,uint8_t CUAddrSize,std::function<void (Error)> WarnCallback)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 
extractPreStandard(const DWARFDataExtractor & Data,uint64_t * OffsetPtr,uint16_t CUVersion,uint8_t CUAddrSize)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 
extract(const DWARFDataExtractor & Data,uint64_t * OffsetPtr,uint16_t CUVersion,uint8_t CUAddrSize,std::function<void (Error)> WarnCallback)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 
dump(raw_ostream & OS,DIDumpOptions DumpOpts) const1360b57cec5SDimitry 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 
getAddrEntry(uint32_t Index) const1710b57cec5SDimitry 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 
getFullLength() const180*bdd1243dSDimitry Andric std::optional<uint64_t> DWARFDebugAddrTable::getFullLength() const {
1815ffd83dbSDimitry Andric   if (Length == 0)
182*bdd1243dSDimitry Andric     return std::nullopt;
1835ffd83dbSDimitry Andric   return Length + dwarf::getUnitLengthFieldByteSize(Format);
1840b57cec5SDimitry Andric }
185