xref: /freebsd/contrib/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFDebugAddr.cpp (revision 5956d97f4b3204318ceb6aa9c77bd0bc6ea87a41)
1 //===- DWARFDebugAddr.cpp -------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "llvm/DebugInfo/DWARF/DWARFDebugAddr.h"
10 #include "llvm/BinaryFormat/Dwarf.h"
11 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
12 
13 using namespace llvm;
14 
15 Error DWARFDebugAddrTable::extractAddresses(const DWARFDataExtractor &Data,
16                                             uint64_t *OffsetPtr,
17                                             uint64_t EndOffset) {
18   assert(EndOffset >= *OffsetPtr);
19   uint64_t DataSize = EndOffset - *OffsetPtr;
20   assert(Data.isValidOffsetForDataOfSize(*OffsetPtr, DataSize));
21   if (Error SizeErr = DWARFContext::checkAddressSizeSupported(
22           AddrSize, errc::not_supported, "address table at offset 0x%" PRIx64,
23           Offset))
24     return SizeErr;
25   if (DataSize % AddrSize != 0) {
26     invalidateLength();
27     return createStringError(errc::invalid_argument,
28                              "address table at offset 0x%" PRIx64
29                              " contains data of size 0x%" PRIx64
30                              " which is not a multiple of addr size %" PRIu8,
31                              Offset, DataSize, AddrSize);
32   }
33   Addrs.clear();
34   size_t Count = DataSize / AddrSize;
35   Addrs.reserve(Count);
36   while (Count--)
37     Addrs.push_back(Data.getRelocatedValue(AddrSize, OffsetPtr));
38   return Error::success();
39 }
40 
41 Error DWARFDebugAddrTable::extractV5(const DWARFDataExtractor &Data,
42                                      uint64_t *OffsetPtr, uint8_t CUAddrSize,
43                                      std::function<void(Error)> WarnCallback) {
44   Offset = *OffsetPtr;
45   llvm::Error Err = Error::success();
46   std::tie(Length, Format) = Data.getInitialLength(OffsetPtr, &Err);
47   if (Err) {
48     invalidateLength();
49     return createStringError(errc::invalid_argument,
50                              "parsing address table at offset 0x%" PRIx64
51                              ": %s",
52                              Offset, toString(std::move(Err)).c_str());
53   }
54 
55   if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, Length)) {
56     uint64_t DiagnosticLength = Length;
57     invalidateLength();
58     return createStringError(
59         errc::invalid_argument,
60         "section is not large enough to contain an address table "
61         "at offset 0x%" PRIx64 " with a unit_length value of 0x%" PRIx64,
62         Offset, DiagnosticLength);
63   }
64   uint64_t EndOffset = *OffsetPtr + Length;
65   // Ensure that we can read the remaining header fields.
66   if (Length < 4) {
67     uint64_t DiagnosticLength = Length;
68     invalidateLength();
69     return createStringError(
70         errc::invalid_argument,
71         "address table at offset 0x%" PRIx64
72         " has a unit_length value of 0x%" PRIx64
73         ", which is too small to contain a complete header",
74         Offset, DiagnosticLength);
75   }
76 
77   Version = Data.getU16(OffsetPtr);
78   AddrSize = Data.getU8(OffsetPtr);
79   SegSize = Data.getU8(OffsetPtr);
80 
81   // Perform a basic validation of the header fields.
82   if (Version != 5)
83     return createStringError(errc::not_supported,
84                              "address table at offset 0x%" PRIx64
85                              " has unsupported version %" PRIu16,
86                              Offset, Version);
87   // TODO: add support for non-zero segment selector size.
88   if (SegSize != 0)
89     return createStringError(errc::not_supported,
90                              "address table at offset 0x%" PRIx64
91                              " has unsupported segment selector size %" PRIu8,
92                              Offset, SegSize);
93 
94   if (Error Err = extractAddresses(Data, OffsetPtr, EndOffset))
95     return Err;
96   if (CUAddrSize && AddrSize != CUAddrSize) {
97     WarnCallback(createStringError(
98         errc::invalid_argument,
99         "address table at offset 0x%" PRIx64 " has address size %" PRIu8
100         " which is different from CU address size %" PRIu8,
101         Offset, AddrSize, CUAddrSize));
102   }
103   return Error::success();
104 }
105 
106 Error DWARFDebugAddrTable::extractPreStandard(const DWARFDataExtractor &Data,
107                                               uint64_t *OffsetPtr,
108                                               uint16_t CUVersion,
109                                               uint8_t CUAddrSize) {
110   assert(CUVersion > 0 && CUVersion < 5);
111 
112   Offset = *OffsetPtr;
113   Length = 0;
114   Version = CUVersion;
115   AddrSize = CUAddrSize;
116   SegSize = 0;
117 
118   return extractAddresses(Data, OffsetPtr, Data.size());
119 }
120 
121 Error DWARFDebugAddrTable::extract(const DWARFDataExtractor &Data,
122                                    uint64_t *OffsetPtr,
123                                    uint16_t CUVersion,
124                                    uint8_t CUAddrSize,
125                                    std::function<void(Error)> WarnCallback) {
126   if (CUVersion > 0 && CUVersion < 5)
127     return extractPreStandard(Data, OffsetPtr, CUVersion, CUAddrSize);
128   if (CUVersion == 0)
129     WarnCallback(createStringError(errc::invalid_argument,
130                                    "DWARF version is not defined in CU,"
131                                    " assuming version 5"));
132   return extractV5(Data, OffsetPtr, CUAddrSize, WarnCallback);
133 }
134 
135 void DWARFDebugAddrTable::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
136   if (DumpOpts.Verbose)
137     OS << format("0x%8.8" PRIx64 ": ", Offset);
138   if (Length) {
139     int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(Format);
140     OS << "Address table header: "
141        << format("length = 0x%0*" PRIx64, OffsetDumpWidth, Length)
142        << ", format = " << dwarf::FormatString(Format)
143        << format(", version = 0x%4.4" PRIx16, Version)
144        << format(", addr_size = 0x%2.2" PRIx8, AddrSize)
145        << format(", seg_size = 0x%2.2" PRIx8, SegSize) << "\n";
146   }
147 
148   if (Addrs.size() > 0) {
149     const char *AddrFmt;
150     switch (AddrSize) {
151     case 2:
152       AddrFmt = "0x%4.4" PRIx64 "\n";
153       break;
154     case 4:
155       AddrFmt = "0x%8.8" PRIx64 "\n";
156       break;
157     case 8:
158       AddrFmt = "0x%16.16" PRIx64 "\n";
159       break;
160     default:
161       llvm_unreachable("unsupported address size");
162     }
163     OS << "Addrs: [\n";
164     for (uint64_t Addr : Addrs)
165       OS << format(AddrFmt, Addr);
166     OS << "]\n";
167   }
168 }
169 
170 Expected<uint64_t> DWARFDebugAddrTable::getAddrEntry(uint32_t Index) const {
171   if (Index < Addrs.size())
172     return Addrs[Index];
173   return createStringError(errc::invalid_argument,
174                            "Index %" PRIu32 " is out of range of the "
175                            "address table at offset 0x%" PRIx64,
176                            Index, Offset);
177 }
178 
179 Optional<uint64_t> DWARFDebugAddrTable::getFullLength() const {
180   if (Length == 0)
181     return None;
182   return Length + dwarf::getUnitLengthFieldByteSize(Format);
183 }
184 
185