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