xref: /freebsd/contrib/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFDebugAddr.cpp (revision 349cc55c9796c4596a5b9904cd3281af295f878f)
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