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/DWARFUnit.h"
15 void DWARFDebugAddrTable::clear() {
21 Error
DWARFDebugAddrTable::extract(DWARFDataExtractor Data
,
25 std::function
<void(Error
)> WarnCallback
) {
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%"
36 WarnCallback(createStringError(errc::invalid_argument
,
37 "DWARF version is not defined in CU,"
38 " assuming version 5"));
41 UnitVersion
= Version
;
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
== dwarf::DW_LENGTH_DWARF64
) {
49 return createStringError(errc::not_supported
,
50 "DWARF64 is not supported in .debug_addr at offset 0x%" PRIx64
,
53 if (HeaderData
.Length
+ sizeof(uint32_t) < sizeof(Header
)) {
54 uint32_t TmpLength
= getLength();
56 return createStringError(errc::invalid_argument
,
57 ".debug_addr table at offset 0x%" PRIx64
58 " has too small length (0x%" PRIx32
59 ") to contain a complete header",
60 HeaderOffset
, TmpLength
);
62 uint64_t End
= HeaderOffset
+ getLength();
63 if (!Data
.isValidOffsetForDataOfSize(HeaderOffset
, End
- HeaderOffset
)) {
64 uint32_t TmpLength
= getLength();
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%" PRIx64
,
69 TmpLength
, HeaderOffset
);
72 HeaderData
.Version
= Data
.getU16(OffsetPtr
);
73 HeaderData
.AddrSize
= Data
.getU8(OffsetPtr
);
74 HeaderData
.SegSize
= Data
.getU8(OffsetPtr
);
75 DataSize
= getDataSize();
77 HeaderData
.Version
= UnitVersion
;
78 HeaderData
.AddrSize
= AddrSize
;
79 // TODO: Support for non-zero SegSize.
80 HeaderData
.SegSize
= 0;
81 DataSize
= Data
.size();
84 // Perform basic validation of the remaining header fields.
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%" PRIx64
" is not supported",
92 HeaderData
.Version
, HeaderOffset
);
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%" PRIx64
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%" PRIx64
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%" PRIx64
113 " has address size %" PRIu8
114 " which is different from CU address size %" PRIu8
,
115 HeaderOffset
, HeaderData
.AddrSize
, AddrSize
);
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%" PRIx64
121 " has unsupported segment selector size %" PRIu8
,
122 HeaderOffset
, HeaderData
.SegSize
);
123 if (DataSize
% HeaderData
.AddrSize
!= 0) {
125 return createStringError(errc::invalid_argument
,
126 ".debug_addr table at offset 0x%" PRIx64
127 " contains data of size %" PRIu32
128 " which is not a multiple of addr size %" PRIu8
,
129 HeaderOffset
, DataSize
, HeaderData
.AddrSize
);
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
));
137 Addrs
.push_back(Data
.getU64(OffsetPtr
));
138 return Error::success();
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
,
150 if (Addrs
.size() > 0) {
151 const char *AddrFmt
= (HeaderData
.AddrSize
== 4) ? "0x%8.8" PRIx64
"\n"
152 : "0x%16.16" PRIx64
"\n";
154 for (uint64_t Addr
: Addrs
)
155 OS
<< format(AddrFmt
, Addr
);
160 Expected
<uint64_t> DWARFDebugAddrTable::getAddrEntry(uint32_t Index
) const {
161 if (Index
< Addrs
.size())
163 return createStringError(errc::invalid_argument
,
164 "Index %" PRIu32
" is out of range of the "
165 ".debug_addr table at offset 0x%" PRIx64
,
166 Index
, HeaderOffset
);
169 uint32_t DWARFDebugAddrTable::getLength() const {
170 if (HeaderData
.Length
== 0)
172 // TODO: DWARF64 support.
173 return HeaderData
.Length
+ sizeof(uint32_t);
176 uint32_t DWARFDebugAddrTable::getDataSize() const {
179 if (getLength() == 0)
181 return getLength() - getHeaderSize();