1 //===- DWARFDebugAddr.cpp -------------------------------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "llvm/DebugInfo/DWARF/DWARFDebugAddr.h"
11 #include "llvm/BinaryFormat/Dwarf.h"
12 #include "llvm/DebugInfo/DWARF/DWARFUnit.h"
13
14 using namespace llvm;
15
clear()16 void DWARFDebugAddrTable::clear() {
17 HeaderData = {};
18 Addrs.clear();
19 invalidateLength();
20 }
21
extract(DWARFDataExtractor Data,uint32_t * OffsetPtr,uint16_t Version,uint8_t AddrSize,std::function<void (Error)> WarnCallback)22 Error DWARFDebugAddrTable::extract(DWARFDataExtractor Data,
23 uint32_t *OffsetPtr,
24 uint16_t Version,
25 uint8_t AddrSize,
26 std::function<void(Error)> WarnCallback) {
27 clear();
28 HeaderOffset = *OffsetPtr;
29 // Read and verify the length field.
30 if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, sizeof(uint32_t)))
31 return createStringError(errc::invalid_argument,
32 "section is not large enough to contain a "
33 ".debug_addr table length at offset 0x%"
34 PRIx32, *OffsetPtr);
35 uint16_t UnitVersion;
36 if (Version == 0) {
37 WarnCallback(createStringError(errc::invalid_argument,
38 "DWARF version is not defined in CU,"
39 " assuming version 5"));
40 UnitVersion = 5;
41 } else {
42 UnitVersion = Version;
43 }
44 // TODO: Add support for DWARF64.
45 Format = dwarf::DwarfFormat::DWARF32;
46 if (UnitVersion >= 5) {
47 HeaderData.Length = Data.getU32(OffsetPtr);
48 if (HeaderData.Length == 0xffffffffu) {
49 invalidateLength();
50 return createStringError(errc::not_supported,
51 "DWARF64 is not supported in .debug_addr at offset 0x%" PRIx32,
52 HeaderOffset);
53 }
54 if (HeaderData.Length + sizeof(uint32_t) < sizeof(Header)) {
55 uint32_t TmpLength = getLength();
56 invalidateLength();
57 return createStringError(errc::invalid_argument,
58 ".debug_addr table at offset 0x%" PRIx32
59 " has too small length (0x%" PRIx32
60 ") to contain a complete header",
61 HeaderOffset, TmpLength);
62 }
63 uint32_t End = HeaderOffset + getLength();
64 if (!Data.isValidOffsetForDataOfSize(HeaderOffset, End - HeaderOffset)) {
65 uint32_t TmpLength = getLength();
66 invalidateLength();
67 return createStringError(errc::invalid_argument,
68 "section is not large enough to contain a .debug_addr table "
69 "of length 0x%" PRIx32 " at offset 0x%" PRIx32,
70 TmpLength, HeaderOffset);
71 }
72
73 HeaderData.Version = Data.getU16(OffsetPtr);
74 HeaderData.AddrSize = Data.getU8(OffsetPtr);
75 HeaderData.SegSize = Data.getU8(OffsetPtr);
76 DataSize = getDataSize();
77 } else {
78 HeaderData.Version = UnitVersion;
79 HeaderData.AddrSize = AddrSize;
80 // TODO: Support for non-zero SegSize.
81 HeaderData.SegSize = 0;
82 DataSize = Data.size();
83 }
84
85 // Perform basic validation of the remaining header fields.
86
87 // We support DWARF version 5 for now as well as pre-DWARF5
88 // implementations of .debug_addr table, which doesn't contain a header
89 // and consists only of a series of addresses.
90 if (HeaderData.Version > 5) {
91 return createStringError(errc::not_supported, "version %" PRIu16
92 " of .debug_addr section at offset 0x%" PRIx32 " is not supported",
93 HeaderData.Version, HeaderOffset);
94 }
95 // FIXME: For now we just treat version mismatch as an error,
96 // however the correct way to associate a .debug_addr table
97 // with a .debug_info table is to look at the DW_AT_addr_base
98 // attribute in the info table.
99 if (HeaderData.Version != UnitVersion)
100 return createStringError(errc::invalid_argument,
101 ".debug_addr table at offset 0x%" PRIx32
102 " has version %" PRIu16
103 " which is different from the version suggested"
104 " by the DWARF unit header: %" PRIu16,
105 HeaderOffset, HeaderData.Version, UnitVersion);
106 if (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8)
107 return createStringError(errc::not_supported,
108 ".debug_addr table at offset 0x%" PRIx32
109 " has unsupported address size %" PRIu8,
110 HeaderOffset, HeaderData.AddrSize);
111 if (HeaderData.AddrSize != AddrSize && AddrSize != 0)
112 return createStringError(errc::invalid_argument,
113 ".debug_addr table at offset 0x%" PRIx32
114 " has address size %" PRIu8
115 " which is different from CU address size %" PRIu8,
116 HeaderOffset, HeaderData.AddrSize, AddrSize);
117
118 // TODO: add support for non-zero segment selector size.
119 if (HeaderData.SegSize != 0)
120 return createStringError(errc::not_supported,
121 ".debug_addr table at offset 0x%" PRIx32
122 " has unsupported segment selector size %" PRIu8,
123 HeaderOffset, HeaderData.SegSize);
124 if (DataSize % HeaderData.AddrSize != 0) {
125 invalidateLength();
126 return createStringError(errc::invalid_argument,
127 ".debug_addr table at offset 0x%" PRIx32
128 " contains data of size %" PRIu32
129 " which is not a multiple of addr size %" PRIu8,
130 HeaderOffset, DataSize, HeaderData.AddrSize);
131 }
132 Data.setAddressSize(HeaderData.AddrSize);
133 uint32_t AddrCount = DataSize / HeaderData.AddrSize;
134 for (uint32_t I = 0; I < AddrCount; ++I)
135 if (HeaderData.AddrSize == 4)
136 Addrs.push_back(Data.getU32(OffsetPtr));
137 else
138 Addrs.push_back(Data.getU64(OffsetPtr));
139 return Error::success();
140 }
141
dump(raw_ostream & OS,DIDumpOptions DumpOpts) const142 void DWARFDebugAddrTable::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
143 if (DumpOpts.Verbose)
144 OS << format("0x%8.8" PRIx32 ": ", HeaderOffset);
145 OS << format("Addr Section: length = 0x%8.8" PRIx32
146 ", version = 0x%4.4" PRIx16 ", "
147 "addr_size = 0x%2.2" PRIx8 ", seg_size = 0x%2.2" PRIx8 "\n",
148 HeaderData.Length, HeaderData.Version, HeaderData.AddrSize,
149 HeaderData.SegSize);
150
151 static const char *Fmt32 = "0x%8.8" PRIx32;
152 static const char *Fmt64 = "0x%16.16" PRIx64;
153 std::string AddrFmt = "\n";
154 std::string AddrFmtVerbose = " => ";
155 if (HeaderData.AddrSize == 4) {
156 AddrFmt.append(Fmt32);
157 AddrFmtVerbose.append(Fmt32);
158 }
159 else {
160 AddrFmt.append(Fmt64);
161 AddrFmtVerbose.append(Fmt64);
162 }
163
164 if (Addrs.size() > 0) {
165 OS << "Addrs: [";
166 for (uint64_t Addr : Addrs) {
167 OS << format(AddrFmt.c_str(), Addr);
168 if (DumpOpts.Verbose)
169 OS << format(AddrFmtVerbose.c_str(),
170 Addr + HeaderOffset + sizeof(HeaderData));
171 }
172 OS << "\n]\n";
173 }
174 }
175
getAddrEntry(uint32_t Index) const176 Expected<uint64_t> DWARFDebugAddrTable::getAddrEntry(uint32_t Index) const {
177 if (Index < Addrs.size())
178 return Addrs[Index];
179 return createStringError(errc::invalid_argument,
180 "Index %" PRIu32 " is out of range of the "
181 ".debug_addr table at offset 0x%" PRIx32,
182 Index, HeaderOffset);
183 }
184
getLength() const185 uint32_t DWARFDebugAddrTable::getLength() const {
186 if (HeaderData.Length == 0)
187 return 0;
188 // TODO: DWARF64 support.
189 return HeaderData.Length + sizeof(uint32_t);
190 }
191
getDataSize() const192 uint32_t DWARFDebugAddrTable::getDataSize() const {
193 if (DataSize != 0)
194 return DataSize;
195 if (getLength() == 0)
196 return 0;
197 return getLength() - getHeaderSize();
198 }
199