Line data Source code
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 :
16 30 : void DWARFDebugAddrTable::clear() {
17 30 : HeaderData = {};
18 : Addrs.clear();
19 : invalidateLength();
20 30 : }
21 :
22 30 : Error DWARFDebugAddrTable::extract(DWARFDataExtractor Data,
23 : uint32_t *OffsetPtr,
24 : uint16_t Version,
25 : uint8_t AddrSize,
26 : std::function<void(Error)> WarnCallback) {
27 30 : clear();
28 30 : 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 1 : PRIx32, *OffsetPtr);
35 : uint16_t UnitVersion;
36 29 : if (Version == 0) {
37 6 : WarnCallback(createStringError(errc::invalid_argument,
38 : "DWARF version is not defined in CU,"
39 : " assuming version 5"));
40 6 : UnitVersion = 5;
41 : } else {
42 23 : UnitVersion = Version;
43 : }
44 : // TODO: Add support for DWARF64.
45 29 : Format = dwarf::DwarfFormat::DWARF32;
46 29 : if (UnitVersion >= 5) {
47 19 : HeaderData.Length = Data.getU32(OffsetPtr);
48 19 : 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 2 : HeaderOffset);
53 : }
54 18 : if (HeaderData.Length + sizeof(uint32_t) < sizeof(Header)) {
55 1 : 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 2 : HeaderOffset, TmpLength);
62 : }
63 17 : uint32_t End = HeaderOffset + getLength();
64 17 : if (!Data.isValidOffsetForDataOfSize(HeaderOffset, End - HeaderOffset)) {
65 1 : 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 2 : TmpLength, HeaderOffset);
71 : }
72 :
73 16 : HeaderData.Version = Data.getU16(OffsetPtr);
74 16 : HeaderData.AddrSize = Data.getU8(OffsetPtr);
75 16 : HeaderData.SegSize = Data.getU8(OffsetPtr);
76 16 : DataSize = getDataSize();
77 : } else {
78 10 : HeaderData.Version = UnitVersion;
79 10 : HeaderData.AddrSize = AddrSize;
80 : // TODO: Support for non-zero SegSize.
81 10 : HeaderData.SegSize = 0;
82 20 : 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 26 : 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 2 : 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 25 : 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 2 : HeaderOffset, HeaderData.Version, UnitVersion);
106 24 : 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 2 : HeaderOffset, HeaderData.AddrSize);
111 23 : 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 2 : HeaderOffset, HeaderData.AddrSize, AddrSize);
117 :
118 : // TODO: add support for non-zero segment selector size.
119 22 : 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 2 : HeaderOffset, HeaderData.SegSize);
124 21 : 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 2 : HeaderOffset, DataSize, HeaderData.AddrSize);
131 : }
132 : Data.setAddressSize(HeaderData.AddrSize);
133 20 : uint32_t AddrCount = DataSize / HeaderData.AddrSize;
134 80 : for (uint32_t I = 0; I < AddrCount; ++I)
135 60 : if (HeaderData.AddrSize == 4)
136 14 : Addrs.push_back(Data.getU32(OffsetPtr));
137 : else
138 46 : Addrs.push_back(Data.getU64(OffsetPtr));
139 : return Error::success();
140 : }
141 :
142 20 : void DWARFDebugAddrTable::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
143 20 : if (DumpOpts.Verbose)
144 24 : OS << format("0x%8.8" PRIx32 ": ", HeaderOffset);
145 20 : 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 20 : HeaderData.SegSize);
150 :
151 : static const char *Fmt32 = "0x%8.8" PRIx32;
152 : static const char *Fmt64 = "0x%16.16" PRIx64;
153 20 : std::string AddrFmt = "\n";
154 20 : std::string AddrFmtVerbose = " => ";
155 20 : if (HeaderData.AddrSize == 4) {
156 8 : AddrFmt.append(Fmt32);
157 8 : AddrFmtVerbose.append(Fmt32);
158 : }
159 : else {
160 12 : AddrFmt.append(Fmt64);
161 12 : AddrFmtVerbose.append(Fmt64);
162 : }
163 :
164 20 : if (Addrs.size() > 0) {
165 19 : OS << "Addrs: [";
166 79 : for (uint64_t Addr : Addrs) {
167 60 : OS << format(AddrFmt.c_str(), Addr);
168 60 : if (DumpOpts.Verbose)
169 44 : OS << format(AddrFmtVerbose.c_str(),
170 88 : Addr + HeaderOffset + sizeof(HeaderData));
171 : }
172 19 : OS << "\n]\n";
173 : }
174 20 : }
175 :
176 0 : Expected<uint64_t> DWARFDebugAddrTable::getAddrEntry(uint32_t Index) const {
177 0 : if (Index < Addrs.size())
178 : return Addrs[Index];
179 0 : return createStringError(errc::invalid_argument,
180 : "Index %" PRIu32 " is out of range of the "
181 : ".debug_addr table at offset 0x%" PRIx32,
182 0 : Index, HeaderOffset);
183 : }
184 :
185 66 : uint32_t DWARFDebugAddrTable::getLength() const {
186 66 : if (HeaderData.Length == 0)
187 : return 0;
188 : // TODO: DWARF64 support.
189 61 : return HeaderData.Length + sizeof(uint32_t);
190 : }
191 :
192 16 : uint32_t DWARFDebugAddrTable::getDataSize() const {
193 16 : if (DataSize != 0)
194 : return DataSize;
195 16 : if (getLength() == 0)
196 : return 0;
197 16 : return getLength() - getHeaderSize();
198 : }
|