blob: d2344e7e4f5df7f0880471786ed3d9dfbecc7bea [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
Igor Kudrindc166122020-02-06 14:14:12 +070015Error 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 }
Victor Leschuk58d33992018-07-31 22:19:19 +000035 Addrs.clear();
Igor Kudrindc166122020-02-06 14:14:12 +070036 size_t Count = DataSize / AddrSize;
37 Addrs.reserve(Count);
38 while (Count--)
39 Addrs.push_back(Data.getRelocatedValue(AddrSize, OffsetPtr));
40 return Error::success();
Victor Leschuk58d33992018-07-31 22:19:19 +000041}
42
Igor Kudrindc166122020-02-06 14:14:12 +070043Error 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))
Victor Leschuk58d33992018-07-31 22:19:19 +000049 return createStringError(errc::invalid_argument,
Igor Kudrindc166122020-02-06 14:14:12 +070050 "section is not large enough to contain an "
51 "address table length at offset 0x%" PRIx64,
52 Offset);
Victor Leschuk58d33992018-07-31 22:19:19 +000053 // TODO: Add support for DWARF64.
54 Format = dwarf::DwarfFormat::DWARF32;
Igor Kudrindc166122020-02-06 14:14:12 +070055 Length = Data.getU32(OffsetPtr);
56 if (Length == dwarf::DW_LENGTH_DWARF64) {
57 invalidateLength();
58 return createStringError(
59 errc::not_supported,
60 "DWARF64 is not supported in .debug_addr at offset 0x%" PRIx64, Offset);
Victor Leschuk58d33992018-07-31 22:19:19 +000061 }
62
Igor Kudrindc166122020-02-06 14:14:12 +070063 if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, Length)) {
64 uint32_t DiagnosticLength = Length;
65 invalidateLength();
66 return createStringError(
67 errc::invalid_argument,
68 "section is not large enough to contain an address table "
69 "at offset 0x%" PRIx64 " with a unit_length value of 0x%" PRIx32,
70 Offset, DiagnosticLength);
71 }
72 uint64_t EndOffset = *OffsetPtr + Length;
73 // Ensure that we can read the remaining header fields.
74 if (Length < 4) {
75 uint32_t DiagnosticLength = Length;
76 invalidateLength();
77 return createStringError(
78 errc::invalid_argument,
79 "address table at offset 0x%" PRIx64
80 " has a unit_length value of 0x%" PRIx32
81 ", which is too small to contain a complete header",
82 Offset, DiagnosticLength);
83 }
Victor Leschuk58d33992018-07-31 22:19:19 +000084
Igor Kudrindc166122020-02-06 14:14:12 +070085 Version = Data.getU16(OffsetPtr);
86 AddrSize = Data.getU8(OffsetPtr);
87 SegSize = Data.getU8(OffsetPtr);
88
89 // Perform a basic validation of the header fields.
90 if (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,
Igor Kudrindc166122020-02-06 14:14:12 +070094 Offset, Version);
95 // TODO: add support for non-zero segment selector size.
96 if (SegSize != 0)
Victor Leschuk58d33992018-07-31 22:19:19 +000097 return createStringError(errc::not_supported,
Igor Kudrindc166122020-02-06 14:14:12 +070098 "address table at offset 0x%" PRIx64
99 " has unsupported segment selector size %" PRIu8,
100 Offset, SegSize);
101
102 if (Error Err = extractAddresses(Data, OffsetPtr, EndOffset))
103 return Err;
104 if (CUAddrSize && AddrSize != CUAddrSize) {
Igor Kudrin1ea99a22020-02-06 17:08:20 +0700105 WarnCallback(createStringError(
106 errc::invalid_argument,
Igor Kudrin292b67f2020-02-11 15:55:12 +0700107 "address table at offset 0x%" PRIx64 " has address size %" PRIu8
Igor Kudrin1ea99a22020-02-06 17:08:20 +0700108 " which is different from CU address size %" PRIu8,
Igor Kudrindc166122020-02-06 14:14:12 +0700109 Offset, AddrSize, CUAddrSize));
Victor Leschuk58d33992018-07-31 22:19:19 +0000110 }
Victor Leschuk58d33992018-07-31 22:19:19 +0000111 return Error::success();
112}
113
Igor Kudrindc166122020-02-06 14:14:12 +0700114Error DWARFDebugAddrTable::extractPreStandard(const DWARFDataExtractor &Data,
115 uint64_t *OffsetPtr,
116 uint16_t CUVersion,
117 uint8_t CUAddrSize) {
118 assert(CUVersion > 0 && CUVersion < 5);
119
120 Offset = *OffsetPtr;
121 Length = 0;
122 Version = CUVersion;
123 AddrSize = CUAddrSize;
124 SegSize = 0;
125
126 return extractAddresses(Data, OffsetPtr, Data.size());
127}
128
129Error DWARFDebugAddrTable::extract(const DWARFDataExtractor &Data,
130 uint64_t *OffsetPtr,
131 uint16_t CUVersion,
132 uint8_t CUAddrSize,
133 std::function<void(Error)> WarnCallback) {
134 if (CUVersion > 0 && CUVersion < 5)
135 return extractPreStandard(Data, OffsetPtr, CUVersion, CUAddrSize);
136 if (CUVersion == 0)
137 WarnCallback(createStringError(errc::invalid_argument,
138 "DWARF version is not defined in CU,"
139 " assuming version 5"));
140 return extractV5(Data, OffsetPtr, CUAddrSize, WarnCallback);
141}
142
Victor Leschuk58d33992018-07-31 22:19:19 +0000143void DWARFDebugAddrTable::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
144 if (DumpOpts.Verbose)
Igor Kudrindc166122020-02-06 14:14:12 +0700145 OS << format("0x%8.8" PRIx32 ": ", Offset);
146 if (Length)
Igor Kudrin675c4be2020-02-06 20:34:10 +0700147 OS << format("Address table header: length = 0x%8.8" PRIx32
Igor Kudrindc166122020-02-06 14:14:12 +0700148 ", version = 0x%4.4" PRIx16 ", addr_size = 0x%2.2" PRIx8
149 ", seg_size = 0x%2.2" PRIx8 "\n",
150 Length, Version, AddrSize, SegSize);
Victor Leschuk58d33992018-07-31 22:19:19 +0000151
Victor Leschuk58d33992018-07-31 22:19:19 +0000152 if (Addrs.size() > 0) {
Igor Kudrindc166122020-02-06 14:14:12 +0700153 const char *AddrFmt =
154 (AddrSize == 4) ? "0x%8.8" PRIx64 "\n" : "0x%16.16" PRIx64 "\n";
Igor Kudrinc310b1a2019-07-02 09:57:28 +0000155 OS << "Addrs: [\n";
156 for (uint64_t Addr : Addrs)
157 OS << format(AddrFmt, Addr);
158 OS << "]\n";
Victor Leschuk58d33992018-07-31 22:19:19 +0000159 }
160}
161
162Expected<uint64_t> DWARFDebugAddrTable::getAddrEntry(uint32_t Index) const {
163 if (Index < Addrs.size())
164 return Addrs[Index];
165 return createStringError(errc::invalid_argument,
Igor Kudrindc166122020-02-06 14:14:12 +0700166 "Index %" PRIu32 " is out of range of the "
Igor Kudrin292b67f2020-02-11 15:55:12 +0700167 "address table at offset 0x%" PRIx64,
Igor Kudrindc166122020-02-06 14:14:12 +0700168 Index, Offset);
Victor Leschuk58d33992018-07-31 22:19:19 +0000169}
170
Igor Kudrindc166122020-02-06 14:14:12 +0700171Optional<uint64_t> DWARFDebugAddrTable::getFullLength() const {
172 if (Length == 0)
173 return None;
Victor Leschuk58d33992018-07-31 22:19:19 +0000174 // TODO: DWARF64 support.
Igor Kudrindc166122020-02-06 14:14:12 +0700175 return Length + sizeof(uint32_t);
Victor Leschuk58d33992018-07-31 22:19:19 +0000176}
177