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 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 
43 Error DWARFDebugAddrTable::extractV5(const DWARFDataExtractor &Data,
44                                      uint64_t *OffsetPtr, uint8_t CUAddrSize,
45                                      std::function<void(Error)> WarnCallback) {
46   Offset = *OffsetPtr;
47   // Check that we can read the unit length field.
48   if (!Data.isValidOffsetForDataOfSize(Offset, 4))
49     return createStringError(errc::invalid_argument,
50                              "section is not large enough to contain an "
51                              "address table length at offset 0x%" PRIx64,
52                              Offset);
53   Format = dwarf::DwarfFormat::DWARF32;
54   Length = Data.getU32(OffsetPtr);
55   if (Length == dwarf::DW_LENGTH_DWARF64) {
56     // Check that we can read the extended unit length field.
57     if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, 8)) {
58       invalidateLength();
59       return createStringError(
60           errc::invalid_argument,
61           "section is not large enough to contain an extended length field "
62           "of the address table at offset 0x%" PRIx64,
63           Offset);
64     }
65     Format = dwarf::DwarfFormat::DWARF64;
66     Length = Data.getU64(OffsetPtr);
67   } else if (Length >= dwarf::DW_LENGTH_lo_reserved) {
68     uint64_t DiagnosticLength = Length;
69     invalidateLength();
70     return createStringError(
71         errc::not_supported,
72         "address table at offset 0x%" PRIx64
73         " has unsupported reserved unit length of value 0x%" PRIx64,
74         Offset, DiagnosticLength);
75   }
76 
77   if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, Length)) {
78     uint64_t DiagnosticLength = Length;
79     invalidateLength();
80     return createStringError(
81         errc::invalid_argument,
82         "section is not large enough to contain an address table "
83         "at offset 0x%" PRIx64 " with a unit_length value of 0x%" PRIx64,
84         Offset, DiagnosticLength);
85   }
86   uint64_t EndOffset = *OffsetPtr + Length;
87   // Ensure that we can read the remaining header fields.
88   if (Length < 4) {
89     uint64_t DiagnosticLength = Length;
90     invalidateLength();
91     return createStringError(
92         errc::invalid_argument,
93         "address table at offset 0x%" PRIx64
94         " has a unit_length value of 0x%" PRIx64
95         ", which is too small to contain a complete header",
96         Offset, DiagnosticLength);
97   }
98 
99   Version = Data.getU16(OffsetPtr);
100   AddrSize = Data.getU8(OffsetPtr);
101   SegSize = Data.getU8(OffsetPtr);
102 
103   // Perform a basic validation of the header fields.
104   if (Version != 5)
105     return createStringError(errc::not_supported,
106                              "address table at offset 0x%" PRIx64
107                              " has unsupported version %" PRIu16,
108                              Offset, Version);
109   // TODO: add support for non-zero segment selector size.
110   if (SegSize != 0)
111     return createStringError(errc::not_supported,
112                              "address table at offset 0x%" PRIx64
113                              " has unsupported segment selector size %" PRIu8,
114                              Offset, SegSize);
115 
116   if (Error Err = extractAddresses(Data, OffsetPtr, EndOffset))
117     return Err;
118   if (CUAddrSize && AddrSize != CUAddrSize) {
119     WarnCallback(createStringError(
120         errc::invalid_argument,
121         "address table at offset 0x%" PRIx64 " has address size %" PRIu8
122         " which is different from CU address size %" PRIu8,
123         Offset, AddrSize, CUAddrSize));
124   }
125   return Error::success();
126 }
127 
128 Error DWARFDebugAddrTable::extractPreStandard(const DWARFDataExtractor &Data,
129                                               uint64_t *OffsetPtr,
130                                               uint16_t CUVersion,
131                                               uint8_t CUAddrSize) {
132   assert(CUVersion > 0 && CUVersion < 5);
133 
134   Offset = *OffsetPtr;
135   Length = 0;
136   Version = CUVersion;
137   AddrSize = CUAddrSize;
138   SegSize = 0;
139 
140   return extractAddresses(Data, OffsetPtr, Data.size());
141 }
142 
143 Error DWARFDebugAddrTable::extract(const DWARFDataExtractor &Data,
144                                    uint64_t *OffsetPtr,
145                                    uint16_t CUVersion,
146                                    uint8_t CUAddrSize,
147                                    std::function<void(Error)> WarnCallback) {
148   if (CUVersion > 0 && CUVersion < 5)
149     return extractPreStandard(Data, OffsetPtr, CUVersion, CUAddrSize);
150   if (CUVersion == 0)
151     WarnCallback(createStringError(errc::invalid_argument,
152                                    "DWARF version is not defined in CU,"
153                                    " assuming version 5"));
154   return extractV5(Data, OffsetPtr, CUAddrSize, WarnCallback);
155 }
156 
157 void DWARFDebugAddrTable::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
158   if (DumpOpts.Verbose)
159     OS << format("0x%8.8" PRIx64 ": ", Offset);
160   if (Length) {
161     int LengthFieldWidth = (Format == dwarf::DwarfFormat::DWARF64) ? 16 : 8;
162     OS << format("Address table header: length = 0x%0*" PRIx64
163                  ", version = 0x%4.4" PRIx16 ", addr_size = 0x%2.2" PRIx8
164                  ", seg_size = 0x%2.2" PRIx8 "\n",
165                  LengthFieldWidth, Length, Version, AddrSize, SegSize);
166   }
167 
168   if (Addrs.size() > 0) {
169     const char *AddrFmt =
170         (AddrSize == 4) ? "0x%8.8" PRIx64 "\n" : "0x%16.16" PRIx64 "\n";
171     OS << "Addrs: [\n";
172     for (uint64_t Addr : Addrs)
173       OS << format(AddrFmt, Addr);
174     OS << "]\n";
175   }
176 }
177 
178 Expected<uint64_t> DWARFDebugAddrTable::getAddrEntry(uint32_t Index) const {
179   if (Index < Addrs.size())
180     return Addrs[Index];
181   return createStringError(errc::invalid_argument,
182                            "Index %" PRIu32 " is out of range of the "
183                            "address table at offset 0x%" PRIx64,
184                            Index, Offset);
185 }
186 
187 Optional<uint64_t> DWARFDebugAddrTable::getFullLength() const {
188   if (Length == 0)
189     return None;
190   return Length + dwarf::getUnitLengthFieldByteSize(Format);
191 }
192 
193