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