xref: /freebsd/contrib/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFDebugAddr.cpp (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
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"
110b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFUnit.h"
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric using namespace llvm;
140b57cec5SDimitry Andric 
15*5ffd83dbSDimitry Andric Error DWARFDebugAddrTable::extractAddresses(const DWARFDataExtractor &Data,
16*5ffd83dbSDimitry Andric                                             uint64_t *OffsetPtr,
17*5ffd83dbSDimitry Andric                                             uint64_t EndOffset) {
18*5ffd83dbSDimitry Andric   assert(EndOffset >= *OffsetPtr);
19*5ffd83dbSDimitry Andric   uint64_t DataSize = EndOffset - *OffsetPtr;
20*5ffd83dbSDimitry Andric   assert(Data.isValidOffsetForDataOfSize(*OffsetPtr, DataSize));
21*5ffd83dbSDimitry Andric   if (AddrSize != 4 && AddrSize != 8)
22*5ffd83dbSDimitry Andric     return createStringError(errc::not_supported,
23*5ffd83dbSDimitry Andric                              "address table at offset 0x%" PRIx64
24*5ffd83dbSDimitry Andric                              " has unsupported address size %" PRIu8
25*5ffd83dbSDimitry Andric                              " (4 and 8 are supported)",
26*5ffd83dbSDimitry Andric                              Offset, AddrSize);
27*5ffd83dbSDimitry Andric   if (DataSize % AddrSize != 0) {
280b57cec5SDimitry Andric     invalidateLength();
29*5ffd83dbSDimitry Andric     return createStringError(errc::invalid_argument,
30*5ffd83dbSDimitry Andric                              "address table at offset 0x%" PRIx64
31*5ffd83dbSDimitry Andric                              " contains data of size 0x%" PRIx64
32*5ffd83dbSDimitry Andric                              " which is not a multiple of addr size %" PRIu8,
33*5ffd83dbSDimitry Andric                              Offset, DataSize, AddrSize);
34*5ffd83dbSDimitry Andric   }
35*5ffd83dbSDimitry Andric   Addrs.clear();
36*5ffd83dbSDimitry Andric   size_t Count = DataSize / AddrSize;
37*5ffd83dbSDimitry Andric   Addrs.reserve(Count);
38*5ffd83dbSDimitry Andric   while (Count--)
39*5ffd83dbSDimitry Andric     Addrs.push_back(Data.getRelocatedValue(AddrSize, OffsetPtr));
40*5ffd83dbSDimitry Andric   return Error::success();
410b57cec5SDimitry Andric }
420b57cec5SDimitry Andric 
43*5ffd83dbSDimitry Andric Error DWARFDebugAddrTable::extractV5(const DWARFDataExtractor &Data,
44*5ffd83dbSDimitry Andric                                      uint64_t *OffsetPtr, uint8_t CUAddrSize,
450b57cec5SDimitry Andric                                      std::function<void(Error)> WarnCallback) {
46*5ffd83dbSDimitry Andric   Offset = *OffsetPtr;
47*5ffd83dbSDimitry Andric   llvm::Error Err = Error::success();
48*5ffd83dbSDimitry Andric   std::tie(Length, Format) = Data.getInitialLength(OffsetPtr, &Err);
49*5ffd83dbSDimitry Andric   if (Err) {
50*5ffd83dbSDimitry Andric     invalidateLength();
510b57cec5SDimitry Andric     return createStringError(errc::invalid_argument,
52*5ffd83dbSDimitry Andric                              "parsing address table at offset 0x%" PRIx64
53*5ffd83dbSDimitry Andric                              ": %s",
54*5ffd83dbSDimitry Andric                              Offset, toString(std::move(Err)).c_str());
55*5ffd83dbSDimitry Andric   }
56*5ffd83dbSDimitry Andric 
57*5ffd83dbSDimitry Andric   if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, Length)) {
58*5ffd83dbSDimitry Andric     uint64_t DiagnosticLength = Length;
59*5ffd83dbSDimitry Andric     invalidateLength();
60*5ffd83dbSDimitry Andric     return createStringError(
61*5ffd83dbSDimitry Andric         errc::invalid_argument,
62*5ffd83dbSDimitry Andric         "section is not large enough to contain an address table "
63*5ffd83dbSDimitry Andric         "at offset 0x%" PRIx64 " with a unit_length value of 0x%" PRIx64,
64*5ffd83dbSDimitry Andric         Offset, DiagnosticLength);
65*5ffd83dbSDimitry Andric   }
66*5ffd83dbSDimitry Andric   uint64_t EndOffset = *OffsetPtr + Length;
67*5ffd83dbSDimitry Andric   // Ensure that we can read the remaining header fields.
68*5ffd83dbSDimitry Andric   if (Length < 4) {
69*5ffd83dbSDimitry Andric     uint64_t DiagnosticLength = Length;
70*5ffd83dbSDimitry Andric     invalidateLength();
71*5ffd83dbSDimitry Andric     return createStringError(
72*5ffd83dbSDimitry Andric         errc::invalid_argument,
73*5ffd83dbSDimitry Andric         "address table at offset 0x%" PRIx64
74*5ffd83dbSDimitry Andric         " has a unit_length value of 0x%" PRIx64
75*5ffd83dbSDimitry Andric         ", which is too small to contain a complete header",
76*5ffd83dbSDimitry Andric         Offset, DiagnosticLength);
77*5ffd83dbSDimitry Andric   }
78*5ffd83dbSDimitry Andric 
79*5ffd83dbSDimitry Andric   Version = Data.getU16(OffsetPtr);
80*5ffd83dbSDimitry Andric   AddrSize = Data.getU8(OffsetPtr);
81*5ffd83dbSDimitry Andric   SegSize = Data.getU8(OffsetPtr);
82*5ffd83dbSDimitry Andric 
83*5ffd83dbSDimitry Andric   // Perform a basic validation of the header fields.
84*5ffd83dbSDimitry Andric   if (Version != 5)
85*5ffd83dbSDimitry Andric     return createStringError(errc::not_supported,
86*5ffd83dbSDimitry Andric                              "address table at offset 0x%" PRIx64
87*5ffd83dbSDimitry Andric                              " has unsupported version %" PRIu16,
88*5ffd83dbSDimitry Andric                              Offset, Version);
89*5ffd83dbSDimitry Andric   // TODO: add support for non-zero segment selector size.
90*5ffd83dbSDimitry Andric   if (SegSize != 0)
91*5ffd83dbSDimitry Andric     return createStringError(errc::not_supported,
92*5ffd83dbSDimitry Andric                              "address table at offset 0x%" PRIx64
93*5ffd83dbSDimitry Andric                              " has unsupported segment selector size %" PRIu8,
94*5ffd83dbSDimitry Andric                              Offset, SegSize);
95*5ffd83dbSDimitry Andric 
96*5ffd83dbSDimitry Andric   if (Error Err = extractAddresses(Data, OffsetPtr, EndOffset))
97*5ffd83dbSDimitry Andric     return Err;
98*5ffd83dbSDimitry Andric   if (CUAddrSize && AddrSize != CUAddrSize) {
99*5ffd83dbSDimitry Andric     WarnCallback(createStringError(
100*5ffd83dbSDimitry Andric         errc::invalid_argument,
101*5ffd83dbSDimitry Andric         "address table at offset 0x%" PRIx64 " has address size %" PRIu8
102*5ffd83dbSDimitry Andric         " which is different from CU address size %" PRIu8,
103*5ffd83dbSDimitry Andric         Offset, AddrSize, CUAddrSize));
104*5ffd83dbSDimitry Andric   }
105*5ffd83dbSDimitry Andric   return Error::success();
106*5ffd83dbSDimitry Andric }
107*5ffd83dbSDimitry Andric 
108*5ffd83dbSDimitry Andric Error DWARFDebugAddrTable::extractPreStandard(const DWARFDataExtractor &Data,
109*5ffd83dbSDimitry Andric                                               uint64_t *OffsetPtr,
110*5ffd83dbSDimitry Andric                                               uint16_t CUVersion,
111*5ffd83dbSDimitry Andric                                               uint8_t CUAddrSize) {
112*5ffd83dbSDimitry Andric   assert(CUVersion > 0 && CUVersion < 5);
113*5ffd83dbSDimitry Andric 
114*5ffd83dbSDimitry Andric   Offset = *OffsetPtr;
115*5ffd83dbSDimitry Andric   Length = 0;
116*5ffd83dbSDimitry Andric   Version = CUVersion;
117*5ffd83dbSDimitry Andric   AddrSize = CUAddrSize;
118*5ffd83dbSDimitry Andric   SegSize = 0;
119*5ffd83dbSDimitry Andric 
120*5ffd83dbSDimitry Andric   return extractAddresses(Data, OffsetPtr, Data.size());
121*5ffd83dbSDimitry Andric }
122*5ffd83dbSDimitry Andric 
123*5ffd83dbSDimitry Andric Error DWARFDebugAddrTable::extract(const DWARFDataExtractor &Data,
124*5ffd83dbSDimitry Andric                                    uint64_t *OffsetPtr,
125*5ffd83dbSDimitry Andric                                    uint16_t CUVersion,
126*5ffd83dbSDimitry Andric                                    uint8_t CUAddrSize,
127*5ffd83dbSDimitry Andric                                    std::function<void(Error)> WarnCallback) {
128*5ffd83dbSDimitry Andric   if (CUVersion > 0 && CUVersion < 5)
129*5ffd83dbSDimitry Andric     return extractPreStandard(Data, OffsetPtr, CUVersion, CUAddrSize);
130*5ffd83dbSDimitry Andric   if (CUVersion == 0)
1310b57cec5SDimitry Andric     WarnCallback(createStringError(errc::invalid_argument,
1320b57cec5SDimitry Andric                                    "DWARF version is not defined in CU,"
1330b57cec5SDimitry Andric                                    " assuming version 5"));
134*5ffd83dbSDimitry Andric   return extractV5(Data, OffsetPtr, CUAddrSize, WarnCallback);
1350b57cec5SDimitry Andric }
1360b57cec5SDimitry Andric 
1370b57cec5SDimitry Andric void DWARFDebugAddrTable::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
1380b57cec5SDimitry Andric   if (DumpOpts.Verbose)
139*5ffd83dbSDimitry Andric     OS << format("0x%8.8" PRIx64 ": ", Offset);
140*5ffd83dbSDimitry Andric   if (Length) {
141*5ffd83dbSDimitry Andric     int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(Format);
142*5ffd83dbSDimitry Andric     OS << "Address table header: "
143*5ffd83dbSDimitry Andric        << format("length = 0x%0*" PRIx64, OffsetDumpWidth, Length)
144*5ffd83dbSDimitry Andric        << ", format = " << dwarf::FormatString(Format)
145*5ffd83dbSDimitry Andric        << format(", version = 0x%4.4" PRIx16, Version)
146*5ffd83dbSDimitry Andric        << format(", addr_size = 0x%2.2" PRIx8, AddrSize)
147*5ffd83dbSDimitry Andric        << format(", seg_size = 0x%2.2" PRIx8, SegSize) << "\n";
148*5ffd83dbSDimitry Andric   }
1490b57cec5SDimitry Andric 
1500b57cec5SDimitry Andric   if (Addrs.size() > 0) {
151*5ffd83dbSDimitry Andric     const char *AddrFmt =
152*5ffd83dbSDimitry Andric         (AddrSize == 4) ? "0x%8.8" PRIx64 "\n" : "0x%16.16" PRIx64 "\n";
1530b57cec5SDimitry Andric     OS << "Addrs: [\n";
1540b57cec5SDimitry Andric     for (uint64_t Addr : Addrs)
1550b57cec5SDimitry Andric       OS << format(AddrFmt, Addr);
1560b57cec5SDimitry Andric     OS << "]\n";
1570b57cec5SDimitry Andric   }
1580b57cec5SDimitry Andric }
1590b57cec5SDimitry Andric 
1600b57cec5SDimitry Andric Expected<uint64_t> DWARFDebugAddrTable::getAddrEntry(uint32_t Index) const {
1610b57cec5SDimitry Andric   if (Index < Addrs.size())
1620b57cec5SDimitry Andric     return Addrs[Index];
1630b57cec5SDimitry Andric   return createStringError(errc::invalid_argument,
1640b57cec5SDimitry Andric                            "Index %" PRIu32 " is out of range of the "
165*5ffd83dbSDimitry Andric                            "address table at offset 0x%" PRIx64,
166*5ffd83dbSDimitry Andric                            Index, Offset);
1670b57cec5SDimitry Andric }
1680b57cec5SDimitry Andric 
169*5ffd83dbSDimitry Andric Optional<uint64_t> DWARFDebugAddrTable::getFullLength() const {
170*5ffd83dbSDimitry Andric   if (Length == 0)
171*5ffd83dbSDimitry Andric     return None;
172*5ffd83dbSDimitry Andric   return Length + dwarf::getUnitLengthFieldByteSize(Format);
1730b57cec5SDimitry Andric }
1740b57cec5SDimitry Andric 
175