1 //===- DWARFDebugAddr.cpp -------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "llvm/DebugInfo/DWARF/DWARFDebugAddr.h"
10 #include "llvm/BinaryFormat/Dwarf.h"
11 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
12 #include "llvm/Support/Errc.h"
16 Error
DWARFDebugAddrTable::extractAddresses(const DWARFDataExtractor
&Data
,
19 assert(EndOffset
>= *OffsetPtr
);
20 uint64_t DataSize
= EndOffset
- *OffsetPtr
;
21 assert(Data
.isValidOffsetForDataOfSize(*OffsetPtr
, DataSize
));
22 if (Error SizeErr
= DWARFContext::checkAddressSizeSupported(
23 AddrSize
, errc::not_supported
, "address table at offset 0x%" PRIx64
,
26 if (DataSize
% AddrSize
!= 0) {
28 return createStringError(errc::invalid_argument
,
29 "address table at offset 0x%" PRIx64
30 " contains data of size 0x%" PRIx64
31 " which is not a multiple of addr size %" PRIu8
,
32 Offset
, DataSize
, AddrSize
);
35 size_t Count
= DataSize
/ AddrSize
;
38 Addrs
.push_back(Data
.getRelocatedValue(AddrSize
, OffsetPtr
));
39 return Error::success();
42 Error
DWARFDebugAddrTable::extractV5(const DWARFDataExtractor
&Data
,
43 uint64_t *OffsetPtr
, uint8_t CUAddrSize
,
44 std::function
<void(Error
)> WarnCallback
) {
46 llvm::Error Err
= Error::success();
47 std::tie(Length
, Format
) = Data
.getInitialLength(OffsetPtr
, &Err
);
50 return createStringError(errc::invalid_argument
,
51 "parsing address table at offset 0x%" PRIx64
53 Offset
, toString(std::move(Err
)).c_str());
56 if (!Data
.isValidOffsetForDataOfSize(*OffsetPtr
, Length
)) {
57 uint64_t DiagnosticLength
= Length
;
59 return createStringError(
60 errc::invalid_argument
,
61 "section is not large enough to contain an address table "
62 "at offset 0x%" PRIx64
" with a unit_length value of 0x%" PRIx64
,
63 Offset
, DiagnosticLength
);
65 uint64_t EndOffset
= *OffsetPtr
+ Length
;
66 // Ensure that we can read the remaining header fields.
68 uint64_t DiagnosticLength
= Length
;
70 return createStringError(
71 errc::invalid_argument
,
72 "address table at offset 0x%" PRIx64
73 " has a unit_length value of 0x%" PRIx64
74 ", which is too small to contain a complete header",
75 Offset
, DiagnosticLength
);
78 Version
= Data
.getU16(OffsetPtr
);
79 AddrSize
= Data
.getU8(OffsetPtr
);
80 SegSize
= Data
.getU8(OffsetPtr
);
82 // Perform a basic validation of the header fields.
84 return createStringError(errc::not_supported
,
85 "address table at offset 0x%" PRIx64
86 " has unsupported version %" PRIu16
,
88 // TODO: add support for non-zero segment selector size.
90 return createStringError(errc::not_supported
,
91 "address table at offset 0x%" PRIx64
92 " has unsupported segment selector size %" PRIu8
,
95 if (Error Err
= extractAddresses(Data
, OffsetPtr
, EndOffset
))
97 if (CUAddrSize
&& AddrSize
!= CUAddrSize
) {
98 WarnCallback(createStringError(
99 errc::invalid_argument
,
100 "address table at offset 0x%" PRIx64
" has address size %" PRIu8
101 " which is different from CU address size %" PRIu8
,
102 Offset
, AddrSize
, CUAddrSize
));
104 return Error::success();
107 Error
DWARFDebugAddrTable::extractPreStandard(const DWARFDataExtractor
&Data
,
110 uint8_t CUAddrSize
) {
111 assert(CUVersion
> 0 && CUVersion
< 5);
116 AddrSize
= CUAddrSize
;
119 return extractAddresses(Data
, OffsetPtr
, Data
.size());
122 Error
DWARFDebugAddrTable::extract(const DWARFDataExtractor
&Data
,
126 std::function
<void(Error
)> WarnCallback
) {
127 if (CUVersion
> 0 && CUVersion
< 5)
128 return extractPreStandard(Data
, OffsetPtr
, CUVersion
, CUAddrSize
);
130 WarnCallback(createStringError(errc::invalid_argument
,
131 "DWARF version is not defined in CU,"
132 " assuming version 5"));
133 return extractV5(Data
, OffsetPtr
, CUAddrSize
, WarnCallback
);
136 void DWARFDebugAddrTable::dump(raw_ostream
&OS
, DIDumpOptions DumpOpts
) const {
137 if (DumpOpts
.Verbose
)
138 OS
<< format("0x%8.8" PRIx64
": ", Offset
);
140 int OffsetDumpWidth
= 2 * dwarf::getDwarfOffsetByteSize(Format
);
141 OS
<< "Address table header: "
142 << format("length = 0x%0*" PRIx64
, OffsetDumpWidth
, Length
)
143 << ", format = " << dwarf::FormatString(Format
)
144 << format(", version = 0x%4.4" PRIx16
, Version
)
145 << format(", addr_size = 0x%2.2" PRIx8
, AddrSize
)
146 << format(", seg_size = 0x%2.2" PRIx8
, SegSize
) << "\n";
149 if (Addrs
.size() > 0) {
153 AddrFmt
= "0x%4.4" PRIx64
"\n";
156 AddrFmt
= "0x%8.8" PRIx64
"\n";
159 AddrFmt
= "0x%16.16" PRIx64
"\n";
162 llvm_unreachable("unsupported address size");
165 for (uint64_t Addr
: Addrs
)
166 OS
<< format(AddrFmt
, Addr
);
171 Expected
<uint64_t> DWARFDebugAddrTable::getAddrEntry(uint32_t Index
) const {
172 if (Index
< Addrs
.size())
174 return createStringError(errc::invalid_argument
,
175 "Index %" PRIu32
" is out of range of the "
176 "address table at offset 0x%" PRIx64
,
180 std::optional
<uint64_t> DWARFDebugAddrTable::getFullLength() const {
183 return Length
+ dwarf::getUnitLengthFieldByteSize(Format
);