blob: eb7070f55ca64e7e84ce50f05748a164c98d1cc1 [file] [log] [blame]
Victor Leschuk58d33992018-07-31 22:19:19 +00001//===- DWARFDebugAddr.cpp -------------------------------------------------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Victor Leschuk58d33992018-07-31 22:19:19 +00006//
7//===----------------------------------------------------------------------===//
8
9#include "llvm/DebugInfo/DWARF/DWARFDebugAddr.h"
10#include "llvm/BinaryFormat/Dwarf.h"
11#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
12
13using namespace llvm;
14
15void DWARFDebugAddrTable::clear() {
16 HeaderData = {};
17 Addrs.clear();
18 invalidateLength();
19}
20
21Error DWARFDebugAddrTable::extract(DWARFDataExtractor Data,
Igor Kudrinf26a70a2019-08-06 10:49:40 +000022 uint64_t *OffsetPtr,
Victor Leschuk58d33992018-07-31 22:19:19 +000023 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,
Igor Kudrin292b67f2020-02-11 15:55:12 +070031 "section is not large enough to contain an "
32 "address table length at offset 0x%"
Igor Kudrinf26a70a2019-08-06 10:49:40 +000033 PRIx64, *OffsetPtr);
Victor Leschuk58d33992018-07-31 22:19:19 +000034 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);
Igor Kudrin3daefb02019-07-24 11:34:29 +000047 if (HeaderData.Length == dwarf::DW_LENGTH_DWARF64) {
Victor Leschuk58d33992018-07-31 22:19:19 +000048 invalidateLength();
49 return createStringError(errc::not_supported,
Igor Kudrinf26a70a2019-08-06 10:49:40 +000050 "DWARF64 is not supported in .debug_addr at offset 0x%" PRIx64,
Victor Leschuk58d33992018-07-31 22:19:19 +000051 HeaderOffset);
52 }
53 if (HeaderData.Length + sizeof(uint32_t) < sizeof(Header)) {
Igor Kudrinde960422020-02-06 16:30:30 +070054 uint32_t TmpLength = HeaderData.Length;
Victor Leschuk58d33992018-07-31 22:19:19 +000055 invalidateLength();
56 return createStringError(errc::invalid_argument,
Igor Kudrin292b67f2020-02-11 15:55:12 +070057 "address table at offset 0x%" PRIx64
Igor Kudrinde960422020-02-06 16:30:30 +070058 " has a unit_length value of 0x%" PRIx32
59 ", which is too small to contain a complete header",
Victor Leschuk58d33992018-07-31 22:19:19 +000060 HeaderOffset, TmpLength);
61 }
Igor Kudrinf26a70a2019-08-06 10:49:40 +000062 uint64_t End = HeaderOffset + getLength();
Victor Leschuk58d33992018-07-31 22:19:19 +000063 if (!Data.isValidOffsetForDataOfSize(HeaderOffset, End - HeaderOffset)) {
Igor Kudrinde960422020-02-06 16:30:30 +070064 uint32_t TmpLength = HeaderData.Length;
Victor Leschuk58d33992018-07-31 22:19:19 +000065 invalidateLength();
Igor Kudrinde960422020-02-06 16:30:30 +070066 return createStringError(
67 errc::invalid_argument,
Igor Kudrin292b67f2020-02-11 15:55:12 +070068 "section is not large enough to contain an address table "
Igor Kudrinde960422020-02-06 16:30:30 +070069 "at offset 0x%" PRIx64 " with a unit_length value of 0x%" PRIx32,
70 HeaderOffset, TmpLength);
Victor Leschuk58d33992018-07-31 22:19:19 +000071 }
72
73 HeaderData.Version = Data.getU16(OffsetPtr);
74 HeaderData.AddrSize = Data.getU8(OffsetPtr);
75 HeaderData.SegSize = Data.getU8(OffsetPtr);
76 DataSize = getDataSize();
77 } else {
78 HeaderData.Version = UnitVersion;
79 HeaderData.AddrSize = AddrSize;
80 // TODO: Support for non-zero SegSize.
81 HeaderData.SegSize = 0;
82 DataSize = Data.size();
83 }
84
85 // Perform basic validation of the remaining header fields.
86
87 // We support DWARF version 5 for now as well as pre-DWARF5
88 // implementations of .debug_addr table, which doesn't contain a header
89 // and consists only of a series of addresses.
90 if (HeaderData.Version > 5) {
Igor Kudrinde960422020-02-06 16:30:30 +070091 return createStringError(errc::not_supported,
92 "address table at offset 0x%" PRIx64
93 " has unsupported version %" PRIu16,
94 HeaderOffset, HeaderData.Version);
Victor Leschuk58d33992018-07-31 22:19:19 +000095 }
96 // FIXME: For now we just treat version mismatch as an error,
97 // however the correct way to associate a .debug_addr table
98 // with a .debug_info table is to look at the DW_AT_addr_base
99 // attribute in the info table.
100 if (HeaderData.Version != UnitVersion)
101 return createStringError(errc::invalid_argument,
Igor Kudrin292b67f2020-02-11 15:55:12 +0700102 "address table at offset 0x%" PRIx64
Victor Leschuk58d33992018-07-31 22:19:19 +0000103 " has version %" PRIu16
104 " which is different from the version suggested"
105 " by the DWARF unit header: %" PRIu16,
106 HeaderOffset, HeaderData.Version, UnitVersion);
107 if (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8)
108 return createStringError(errc::not_supported,
Igor Kudrin292b67f2020-02-11 15:55:12 +0700109 "address table at offset 0x%" PRIx64
Igor Kudrinde960422020-02-06 16:30:30 +0700110 " has unsupported address size %" PRIu8
111 " (4 and 8 are supported)",
Victor Leschuk58d33992018-07-31 22:19:19 +0000112 HeaderOffset, HeaderData.AddrSize);
113 if (HeaderData.AddrSize != AddrSize && AddrSize != 0)
Igor Kudrin1ea99a22020-02-06 17:08:20 +0700114 WarnCallback(createStringError(
115 errc::invalid_argument,
Igor Kudrin292b67f2020-02-11 15:55:12 +0700116 "address table at offset 0x%" PRIx64 " has address size %" PRIu8
Igor Kudrin1ea99a22020-02-06 17:08:20 +0700117 " which is different from CU address size %" PRIu8,
118 HeaderOffset, HeaderData.AddrSize, AddrSize));
Victor Leschuk58d33992018-07-31 22:19:19 +0000119
120 // TODO: add support for non-zero segment selector size.
121 if (HeaderData.SegSize != 0)
122 return createStringError(errc::not_supported,
Igor Kudrin292b67f2020-02-11 15:55:12 +0700123 "address table at offset 0x%" PRIx64
Victor Leschuk58d33992018-07-31 22:19:19 +0000124 " has unsupported segment selector size %" PRIu8,
125 HeaderOffset, HeaderData.SegSize);
126 if (DataSize % HeaderData.AddrSize != 0) {
127 invalidateLength();
128 return createStringError(errc::invalid_argument,
Igor Kudrin292b67f2020-02-11 15:55:12 +0700129 "address table at offset 0x%" PRIx64
Victor Leschuk58d33992018-07-31 22:19:19 +0000130 " contains data of size %" PRIu32
131 " which is not a multiple of addr size %" PRIu8,
132 HeaderOffset, DataSize, HeaderData.AddrSize);
133 }
134 Data.setAddressSize(HeaderData.AddrSize);
135 uint32_t AddrCount = DataSize / HeaderData.AddrSize;
136 for (uint32_t I = 0; I < AddrCount; ++I)
Igor Kudrin5d58eb92020-02-11 19:43:20 +0700137 Addrs.push_back(Data.getRelocatedAddress(OffsetPtr));
Victor Leschuk58d33992018-07-31 22:19:19 +0000138 return Error::success();
139}
140
141void DWARFDebugAddrTable::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
142 if (DumpOpts.Verbose)
143 OS << format("0x%8.8" PRIx32 ": ", HeaderOffset);
Igor Kudrin675c4be2020-02-06 20:34:10 +0700144 if (HeaderData.Length)
145 OS << format("Address table header: length = 0x%8.8" PRIx32
146 ", version = 0x%4.4" PRIx16 ", "
147 "addr_size = 0x%2.2" PRIx8 ", seg_size = 0x%2.2" PRIx8 "\n",
148 HeaderData.Length, HeaderData.Version, HeaderData.AddrSize,
149 HeaderData.SegSize);
Victor Leschuk58d33992018-07-31 22:19:19 +0000150
Victor Leschuk58d33992018-07-31 22:19:19 +0000151 if (Addrs.size() > 0) {
Igor Kudrinc310b1a2019-07-02 09:57:28 +0000152 const char *AddrFmt = (HeaderData.AddrSize == 4) ? "0x%8.8" PRIx64 "\n"
153 : "0x%16.16" PRIx64 "\n";
154 OS << "Addrs: [\n";
155 for (uint64_t Addr : Addrs)
156 OS << format(AddrFmt, Addr);
157 OS << "]\n";
Victor Leschuk58d33992018-07-31 22:19:19 +0000158 }
159}
160
161Expected<uint64_t> DWARFDebugAddrTable::getAddrEntry(uint32_t Index) const {
162 if (Index < Addrs.size())
163 return Addrs[Index];
164 return createStringError(errc::invalid_argument,
Igor Kudrin292b67f2020-02-11 15:55:12 +0700165 "Index %" PRIu32 " is out of range in the "
166 "address table at offset 0x%" PRIx64,
Victor Leschuk58d33992018-07-31 22:19:19 +0000167 Index, HeaderOffset);
168}
169
170uint32_t DWARFDebugAddrTable::getLength() const {
171 if (HeaderData.Length == 0)
172 return 0;
173 // TODO: DWARF64 support.
174 return HeaderData.Length + sizeof(uint32_t);
175}
176
177uint32_t DWARFDebugAddrTable::getDataSize() const {
178 if (DataSize != 0)
179 return DataSize;
180 if (getLength() == 0)
181 return 0;
182 return getLength() - getHeaderSize();
183}