158d3399dSVictor Leschuk //===- DWARFDebugAddr.cpp -------------------------------------------------===//
258d3399dSVictor Leschuk //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
658d3399dSVictor Leschuk //
758d3399dSVictor Leschuk //===----------------------------------------------------------------------===//
858d3399dSVictor Leschuk
958d3399dSVictor Leschuk #include "llvm/DebugInfo/DWARF/DWARFDebugAddr.h"
1058d3399dSVictor Leschuk #include "llvm/BinaryFormat/Dwarf.h"
11d7733f84SJack Anderson #include "llvm/DebugInfo/DWARF/DWARFContext.h"
12290e4823Sserge-sans-paille #include "llvm/Support/Errc.h"
1358d3399dSVictor Leschuk
1458d3399dSVictor Leschuk using namespace llvm;
1558d3399dSVictor Leschuk
extractAddresses(const DWARFDataExtractor & Data,uint64_t * OffsetPtr,uint64_t EndOffset)16dc166123SIgor Kudrin Error DWARFDebugAddrTable::extractAddresses(const DWARFDataExtractor &Data,
17f26a70a5SIgor Kudrin uint64_t *OffsetPtr,
18dc166123SIgor Kudrin uint64_t EndOffset) {
19dc166123SIgor Kudrin assert(EndOffset >= *OffsetPtr);
20dc166123SIgor Kudrin uint64_t DataSize = EndOffset - *OffsetPtr;
21dc166123SIgor Kudrin assert(Data.isValidOffsetForDataOfSize(*OffsetPtr, DataSize));
22d7733f84SJack Anderson if (Error SizeErr = DWARFContext::checkAddressSizeSupported(
23d7733f84SJack Anderson AddrSize, errc::not_supported, "address table at offset 0x%" PRIx64,
24d7733f84SJack Anderson Offset))
25d7733f84SJack Anderson return SizeErr;
26dc166123SIgor Kudrin if (DataSize % AddrSize != 0) {
2758d3399dSVictor Leschuk invalidateLength();
2858d3399dSVictor Leschuk return createStringError(errc::invalid_argument,
29292b67f9SIgor Kudrin "address table at offset 0x%" PRIx64
30dc166123SIgor Kudrin " contains data of size 0x%" PRIx64
31dc166123SIgor Kudrin " which is not a multiple of addr size %" PRIu8,
32dc166123SIgor Kudrin Offset, DataSize, AddrSize);
3358d3399dSVictor Leschuk }
34dc166123SIgor Kudrin Addrs.clear();
35dc166123SIgor Kudrin size_t Count = DataSize / AddrSize;
36dc166123SIgor Kudrin Addrs.reserve(Count);
37dc166123SIgor Kudrin while (Count--)
38dc166123SIgor Kudrin Addrs.push_back(Data.getRelocatedValue(AddrSize, OffsetPtr));
39dc166123SIgor Kudrin return Error::success();
40dc166123SIgor Kudrin }
41dc166123SIgor Kudrin
extractV5(const DWARFDataExtractor & Data,uint64_t * OffsetPtr,uint8_t CUAddrSize,std::function<void (Error)> WarnCallback)42dc166123SIgor Kudrin Error DWARFDebugAddrTable::extractV5(const DWARFDataExtractor &Data,
43dc166123SIgor Kudrin uint64_t *OffsetPtr, uint8_t CUAddrSize,
44dc166123SIgor Kudrin std::function<void(Error)> WarnCallback) {
45dc166123SIgor Kudrin Offset = *OffsetPtr;
4638385630SPavel Labath llvm::Error Err = Error::success();
4738385630SPavel Labath std::tie(Length, Format) = Data.getInitialLength(OffsetPtr, &Err);
4838385630SPavel Labath if (Err) {
4938385630SPavel Labath invalidateLength();
50dc166123SIgor Kudrin return createStringError(errc::invalid_argument,
5138385630SPavel Labath "parsing address table at offset 0x%" PRIx64
5238385630SPavel Labath ": %s",
5338385630SPavel Labath Offset, toString(std::move(Err)).c_str());
54dc166123SIgor Kudrin }
55dc166123SIgor Kudrin
56dc166123SIgor Kudrin if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, Length)) {
5707e50c7bSIgor Kudrin uint64_t DiagnosticLength = Length;
5858d3399dSVictor Leschuk invalidateLength();
59de960423SIgor Kudrin return createStringError(
60de960423SIgor Kudrin errc::invalid_argument,
61292b67f9SIgor Kudrin "section is not large enough to contain an address table "
6207e50c7bSIgor Kudrin "at offset 0x%" PRIx64 " with a unit_length value of 0x%" PRIx64,
63dc166123SIgor Kudrin Offset, DiagnosticLength);
64dc166123SIgor Kudrin }
65dc166123SIgor Kudrin uint64_t EndOffset = *OffsetPtr + Length;
66dc166123SIgor Kudrin // Ensure that we can read the remaining header fields.
67dc166123SIgor Kudrin if (Length < 4) {
6807e50c7bSIgor Kudrin uint64_t DiagnosticLength = Length;
69dc166123SIgor Kudrin invalidateLength();
70dc166123SIgor Kudrin return createStringError(
71dc166123SIgor Kudrin errc::invalid_argument,
72dc166123SIgor Kudrin "address table at offset 0x%" PRIx64
7307e50c7bSIgor Kudrin " has a unit_length value of 0x%" PRIx64
74dc166123SIgor Kudrin ", which is too small to contain a complete header",
75dc166123SIgor Kudrin Offset, DiagnosticLength);
7658d3399dSVictor Leschuk }
7758d3399dSVictor Leschuk
78dc166123SIgor Kudrin Version = Data.getU16(OffsetPtr);
79dc166123SIgor Kudrin AddrSize = Data.getU8(OffsetPtr);
80dc166123SIgor Kudrin SegSize = Data.getU8(OffsetPtr);
8158d3399dSVictor Leschuk
82dc166123SIgor Kudrin // Perform a basic validation of the header fields.
83dc166123SIgor Kudrin if (Version != 5)
84de960423SIgor Kudrin return createStringError(errc::not_supported,
85de960423SIgor Kudrin "address table at offset 0x%" PRIx64
86de960423SIgor Kudrin " has unsupported version %" PRIu16,
87dc166123SIgor Kudrin Offset, Version);
88dc166123SIgor Kudrin // TODO: add support for non-zero segment selector size.
89dc166123SIgor Kudrin if (SegSize != 0)
9058d3399dSVictor Leschuk return createStringError(errc::not_supported,
91292b67f9SIgor Kudrin "address table at offset 0x%" PRIx64
92dc166123SIgor Kudrin " has unsupported segment selector size %" PRIu8,
93dc166123SIgor Kudrin Offset, SegSize);
94dc166123SIgor Kudrin
95dc166123SIgor Kudrin if (Error Err = extractAddresses(Data, OffsetPtr, EndOffset))
96dc166123SIgor Kudrin return Err;
97dc166123SIgor Kudrin if (CUAddrSize && AddrSize != CUAddrSize) {
981ea99a2eSIgor Kudrin WarnCallback(createStringError(
991ea99a2eSIgor Kudrin errc::invalid_argument,
100292b67f9SIgor Kudrin "address table at offset 0x%" PRIx64 " has address size %" PRIu8
10158d3399dSVictor Leschuk " which is different from CU address size %" PRIu8,
102dc166123SIgor Kudrin Offset, AddrSize, CUAddrSize));
10358d3399dSVictor Leschuk }
10458d3399dSVictor Leschuk return Error::success();
10558d3399dSVictor Leschuk }
10658d3399dSVictor Leschuk
extractPreStandard(const DWARFDataExtractor & Data,uint64_t * OffsetPtr,uint16_t CUVersion,uint8_t CUAddrSize)107dc166123SIgor Kudrin Error DWARFDebugAddrTable::extractPreStandard(const DWARFDataExtractor &Data,
108dc166123SIgor Kudrin uint64_t *OffsetPtr,
109dc166123SIgor Kudrin uint16_t CUVersion,
110dc166123SIgor Kudrin uint8_t CUAddrSize) {
111dc166123SIgor Kudrin assert(CUVersion > 0 && CUVersion < 5);
112dc166123SIgor Kudrin
113dc166123SIgor Kudrin Offset = *OffsetPtr;
114dc166123SIgor Kudrin Length = 0;
115dc166123SIgor Kudrin Version = CUVersion;
116dc166123SIgor Kudrin AddrSize = CUAddrSize;
117dc166123SIgor Kudrin SegSize = 0;
118dc166123SIgor Kudrin
119dc166123SIgor Kudrin return extractAddresses(Data, OffsetPtr, Data.size());
120dc166123SIgor Kudrin }
121dc166123SIgor Kudrin
extract(const DWARFDataExtractor & Data,uint64_t * OffsetPtr,uint16_t CUVersion,uint8_t CUAddrSize,std::function<void (Error)> WarnCallback)122dc166123SIgor Kudrin Error DWARFDebugAddrTable::extract(const DWARFDataExtractor &Data,
123dc166123SIgor Kudrin uint64_t *OffsetPtr,
124dc166123SIgor Kudrin uint16_t CUVersion,
125dc166123SIgor Kudrin uint8_t CUAddrSize,
126dc166123SIgor Kudrin std::function<void(Error)> WarnCallback) {
127dc166123SIgor Kudrin if (CUVersion > 0 && CUVersion < 5)
128dc166123SIgor Kudrin return extractPreStandard(Data, OffsetPtr, CUVersion, CUAddrSize);
129dc166123SIgor Kudrin if (CUVersion == 0)
130dc166123SIgor Kudrin WarnCallback(createStringError(errc::invalid_argument,
131dc166123SIgor Kudrin "DWARF version is not defined in CU,"
132dc166123SIgor Kudrin " assuming version 5"));
133dc166123SIgor Kudrin return extractV5(Data, OffsetPtr, CUAddrSize, WarnCallback);
134dc166123SIgor Kudrin }
135dc166123SIgor Kudrin
dump(raw_ostream & OS,DIDumpOptions DumpOpts) const13658d3399dSVictor Leschuk void DWARFDebugAddrTable::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
13758d3399dSVictor Leschuk if (DumpOpts.Verbose)
13807e50c7bSIgor Kudrin OS << format("0x%8.8" PRIx64 ": ", Offset);
13907e50c7bSIgor Kudrin if (Length) {
14048232a48SIgor Kudrin int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(Format);
14148232a48SIgor Kudrin OS << "Address table header: "
14248232a48SIgor Kudrin << format("length = 0x%0*" PRIx64, OffsetDumpWidth, Length)
14348232a48SIgor Kudrin << ", format = " << dwarf::FormatString(Format)
14448232a48SIgor Kudrin << format(", version = 0x%4.4" PRIx16, Version)
14548232a48SIgor Kudrin << format(", addr_size = 0x%2.2" PRIx8, AddrSize)
14648232a48SIgor Kudrin << format(", seg_size = 0x%2.2" PRIx8, SegSize) << "\n";
14707e50c7bSIgor Kudrin }
14858d3399dSVictor Leschuk
14958d3399dSVictor Leschuk if (Addrs.size() > 0) {
150d7733f84SJack Anderson const char *AddrFmt;
151d7733f84SJack Anderson switch (AddrSize) {
152d7733f84SJack Anderson case 2:
153d7733f84SJack Anderson AddrFmt = "0x%4.4" PRIx64 "\n";
154d7733f84SJack Anderson break;
155d7733f84SJack Anderson case 4:
156d7733f84SJack Anderson AddrFmt = "0x%8.8" PRIx64 "\n";
157d7733f84SJack Anderson break;
158d7733f84SJack Anderson case 8:
159d7733f84SJack Anderson AddrFmt = "0x%16.16" PRIx64 "\n";
160d7733f84SJack Anderson break;
161d7733f84SJack Anderson default:
162d7733f84SJack Anderson llvm_unreachable("unsupported address size");
163d7733f84SJack Anderson }
164c310b1aaSIgor Kudrin OS << "Addrs: [\n";
165c310b1aaSIgor Kudrin for (uint64_t Addr : Addrs)
166c310b1aaSIgor Kudrin OS << format(AddrFmt, Addr);
167c310b1aaSIgor Kudrin OS << "]\n";
16858d3399dSVictor Leschuk }
16958d3399dSVictor Leschuk }
17058d3399dSVictor Leschuk
getAddrEntry(uint32_t Index) const17158d3399dSVictor Leschuk Expected<uint64_t> DWARFDebugAddrTable::getAddrEntry(uint32_t Index) const {
17258d3399dSVictor Leschuk if (Index < Addrs.size())
17358d3399dSVictor Leschuk return Addrs[Index];
17458d3399dSVictor Leschuk return createStringError(errc::invalid_argument,
175dc166123SIgor Kudrin "Index %" PRIu32 " is out of range of the "
176292b67f9SIgor Kudrin "address table at offset 0x%" PRIx64,
177dc166123SIgor Kudrin Index, Offset);
17858d3399dSVictor Leschuk }
17958d3399dSVictor Leschuk
getFullLength() const180*89fab98eSFangrui Song std::optional<uint64_t> DWARFDebugAddrTable::getFullLength() const {
181dc166123SIgor Kudrin if (Length == 0)
18211011599SKazu Hirata return std::nullopt;
18307e50c7bSIgor Kudrin return Length + dwarf::getUnitLengthFieldByteSize(Format);
18458d3399dSVictor Leschuk }
185