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