1e94042caSEugene Zelenko //===- DWARFDebugArangeSet.cpp --------------------------------------------===//
282af9438SZachary Turner //
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
682af9438SZachary Turner //
782af9438SZachary Turner //===----------------------------------------------------------------------===//
882af9438SZachary Turner
982af9438SZachary Turner #include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h"
1063329907SIgor Kudrin #include "llvm/BinaryFormat/Dwarf.h"
11*d7733f84SJack Anderson #include "llvm/DebugInfo/DWARF/DWARFContext.h"
12ea83e0b1SDavid Blaikie #include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
13dcff3961SIgor Kudrin #include "llvm/Support/Errc.h"
1482af9438SZachary Turner #include "llvm/Support/Format.h"
1582af9438SZachary Turner #include "llvm/Support/raw_ostream.h"
1682af9438SZachary Turner #include <cassert>
17e94042caSEugene Zelenko #include <cinttypes>
18e94042caSEugene Zelenko #include <cstdint>
19e94042caSEugene Zelenko #include <cstring>
20e94042caSEugene Zelenko
2182af9438SZachary Turner using namespace llvm;
2282af9438SZachary Turner
dump(raw_ostream & OS,uint32_t AddressSize) const236f24c877SJonas Devlieghere void DWARFDebugArangeSet::Descriptor::dump(raw_ostream &OS,
246f24c877SJonas Devlieghere uint32_t AddressSize) const {
25ea83e0b1SDavid Blaikie OS << '[';
26ea83e0b1SDavid Blaikie DWARFFormValue::dumpAddress(OS, AddressSize, Address);
27ea83e0b1SDavid Blaikie OS << ", ";
28ea83e0b1SDavid Blaikie DWARFFormValue::dumpAddress(OS, AddressSize, getEndAddress());
29ea83e0b1SDavid Blaikie OS << ')';
306f24c877SJonas Devlieghere }
316f24c877SJonas Devlieghere
clear()3282af9438SZachary Turner void DWARFDebugArangeSet::clear() {
33f26a70a5SIgor Kudrin Offset = -1ULL;
3482af9438SZachary Turner std::memset(&HeaderData, 0, sizeof(Header));
3582af9438SZachary Turner ArangeDescriptors.clear();
3682af9438SZachary Turner }
3782af9438SZachary Turner
extract(DWARFDataExtractor data,uint64_t * offset_ptr,function_ref<void (Error)> WarningHandler)38eb2b17eeSPavel Labath Error DWARFDebugArangeSet::extract(DWARFDataExtractor data,
39ca05601cSJames Henderson uint64_t *offset_ptr,
40ca05601cSJames Henderson function_ref<void(Error)> WarningHandler) {
41dcff3961SIgor Kudrin assert(data.isValidOffset(*offset_ptr));
4282af9438SZachary Turner ArangeDescriptors.clear();
4382af9438SZachary Turner Offset = *offset_ptr;
4482af9438SZachary Turner
4563329907SIgor Kudrin // 7.21 Address Range Table (extract)
4682af9438SZachary Turner // Each set of entries in the table of address ranges contained in
4763329907SIgor Kudrin // the .debug_aranges section begins with a header containing:
4863329907SIgor Kudrin // 1. unit_length (initial length)
4963329907SIgor Kudrin // A 4-byte (32-bit DWARF) or 12-byte (64-bit DWARF) length containing
5063329907SIgor Kudrin // the length of the set of entries for this compilation unit,
5163329907SIgor Kudrin // not including the length field itself.
5263329907SIgor Kudrin // 2. version (uhalf)
5363329907SIgor Kudrin // The value in this field is 2.
5463329907SIgor Kudrin // 3. debug_info_offset (section offset)
5563329907SIgor Kudrin // A 4-byte (32-bit DWARF) or 8-byte (64-bit DWARF) offset into the
5663329907SIgor Kudrin // .debug_info section of the compilation unit header.
5763329907SIgor Kudrin // 4. address_size (ubyte)
5863329907SIgor Kudrin // 5. segment_selector_size (ubyte)
5963329907SIgor Kudrin // This header is followed by a series of tuples. Each tuple consists of
6063329907SIgor Kudrin // a segment, an address and a length. The segment selector size is given by
6163329907SIgor Kudrin // the segment_selector_size field of the header; the address and length
6263329907SIgor Kudrin // size are each given by the address_size field of the header. Each set of
6363329907SIgor Kudrin // tuples is terminated by a 0 for the segment, a 0 for the address and 0
6463329907SIgor Kudrin // for the length. If the segment_selector_size field in the header is zero,
6563329907SIgor Kudrin // the segment selectors are omitted from all tuples, including
6663329907SIgor Kudrin // the terminating tuple.
6763329907SIgor Kudrin
68eb2b17eeSPavel Labath Error Err = Error::success();
6969dfa07bSIgor Kudrin std::tie(HeaderData.Length, HeaderData.Format) =
7069dfa07bSIgor Kudrin data.getInitialLength(offset_ptr, &Err);
71eb2b17eeSPavel Labath HeaderData.Version = data.getU16(offset_ptr, &Err);
7269dfa07bSIgor Kudrin HeaderData.CuOffset = data.getUnsigned(
7369dfa07bSIgor Kudrin offset_ptr, dwarf::getDwarfOffsetByteSize(HeaderData.Format), &Err);
74eb2b17eeSPavel Labath HeaderData.AddrSize = data.getU8(offset_ptr, &Err);
75eb2b17eeSPavel Labath HeaderData.SegSize = data.getU8(offset_ptr, &Err);
76eb2b17eeSPavel Labath if (Err) {
77eb2b17eeSPavel Labath return createStringError(errc::invalid_argument,
78eb2b17eeSPavel Labath "parsing address ranges table at offset 0x%" PRIx64
79eb2b17eeSPavel Labath ": %s",
80eb2b17eeSPavel Labath Offset, toString(std::move(Err)).c_str());
81eb2b17eeSPavel Labath }
8282af9438SZachary Turner
8382af9438SZachary Turner // Perform basic validation of the header fields.
8463329907SIgor Kudrin uint64_t full_length =
8569dfa07bSIgor Kudrin dwarf::getUnitLengthFieldByteSize(HeaderData.Format) + HeaderData.Length;
8663329907SIgor Kudrin if (!data.isValidOffsetForDataOfSize(Offset, full_length))
87dcff3961SIgor Kudrin return createStringError(errc::invalid_argument,
88dcff3961SIgor Kudrin "the length of address range table at offset "
89dcff3961SIgor Kudrin "0x%" PRIx64 " exceeds section size",
90dcff3961SIgor Kudrin Offset);
91*d7733f84SJack Anderson if (Error SizeErr = DWARFContext::checkAddressSizeSupported(
92*d7733f84SJack Anderson HeaderData.AddrSize, errc::invalid_argument,
93*d7733f84SJack Anderson "address range table at offset 0x%" PRIx64, Offset))
94*d7733f84SJack Anderson return SizeErr;
95ed9851a0SIgor Kudrin if (HeaderData.SegSize != 0)
96ed9851a0SIgor Kudrin return createStringError(errc::not_supported,
97ed9851a0SIgor Kudrin "non-zero segment selector size in address range "
98ed9851a0SIgor Kudrin "table at offset 0x%" PRIx64 " is not supported",
99ed9851a0SIgor Kudrin Offset);
10082af9438SZachary Turner
101ed9851a0SIgor Kudrin // The first tuple following the header in each set begins at an offset that
102ed9851a0SIgor Kudrin // is a multiple of the size of a single tuple (that is, twice the size of
103ed9851a0SIgor Kudrin // an address because we do not support non-zero segment selector sizes).
104ed9851a0SIgor Kudrin // Therefore, the full length should also be a multiple of the tuple size.
10582af9438SZachary Turner const uint32_t tuple_size = HeaderData.AddrSize * 2;
106ed9851a0SIgor Kudrin if (full_length % tuple_size != 0)
107ed9851a0SIgor Kudrin return createStringError(
108ed9851a0SIgor Kudrin errc::invalid_argument,
109ed9851a0SIgor Kudrin "address range table at offset 0x%" PRIx64
110ed9851a0SIgor Kudrin " has length that is not a multiple of the tuple size",
111ed9851a0SIgor Kudrin Offset);
112ed9851a0SIgor Kudrin
113ed9851a0SIgor Kudrin // The header is padded, if necessary, to the appropriate boundary.
114ed9851a0SIgor Kudrin const uint32_t header_size = *offset_ptr - Offset;
11582af9438SZachary Turner uint32_t first_tuple_offset = 0;
11682af9438SZachary Turner while (first_tuple_offset < header_size)
11782af9438SZachary Turner first_tuple_offset += tuple_size;
11882af9438SZachary Turner
119ed9851a0SIgor Kudrin // There should be space for at least one tuple.
120ed9851a0SIgor Kudrin if (full_length <= first_tuple_offset)
121ed9851a0SIgor Kudrin return createStringError(
122ed9851a0SIgor Kudrin errc::invalid_argument,
123ed9851a0SIgor Kudrin "address range table at offset 0x%" PRIx64
124ed9851a0SIgor Kudrin " has an insufficient length to contain any entries",
125ed9851a0SIgor Kudrin Offset);
126ed9851a0SIgor Kudrin
12782af9438SZachary Turner *offset_ptr = Offset + first_tuple_offset;
12882af9438SZachary Turner
12982af9438SZachary Turner Descriptor arangeDescriptor;
13082af9438SZachary Turner
13182af9438SZachary Turner static_assert(sizeof(arangeDescriptor.Address) ==
13282af9438SZachary Turner sizeof(arangeDescriptor.Length),
13382af9438SZachary Turner "Different datatypes for addresses and sizes!");
13482af9438SZachary Turner assert(sizeof(arangeDescriptor.Address) >= HeaderData.AddrSize);
13582af9438SZachary Turner
136ed9851a0SIgor Kudrin uint64_t end_offset = Offset + full_length;
137ed9851a0SIgor Kudrin while (*offset_ptr < end_offset) {
138ca05601cSJames Henderson uint64_t EntryOffset = *offset_ptr;
13982af9438SZachary Turner arangeDescriptor.Address = data.getUnsigned(offset_ptr, HeaderData.AddrSize);
14082af9438SZachary Turner arangeDescriptor.Length = data.getUnsigned(offset_ptr, HeaderData.AddrSize);
14182af9438SZachary Turner
14282af9438SZachary Turner // Each set of tuples is terminated by a 0 for the address and 0
14382af9438SZachary Turner // for the length.
144ca05601cSJames Henderson if (arangeDescriptor.Length == 0 && arangeDescriptor.Address == 0) {
145ca05601cSJames Henderson if (*offset_ptr == end_offset)
146dcff3961SIgor Kudrin return ErrorSuccess();
147ca05601cSJames Henderson WarningHandler(createStringError(
148ed9851a0SIgor Kudrin errc::invalid_argument,
149ed9851a0SIgor Kudrin "address range table at offset 0x%" PRIx64
150ca05601cSJames Henderson " has a premature terminator entry at offset 0x%" PRIx64,
151ca05601cSJames Henderson Offset, EntryOffset));
152ed9851a0SIgor Kudrin }
153ed9851a0SIgor Kudrin
15482af9438SZachary Turner ArangeDescriptors.push_back(arangeDescriptor);
15582af9438SZachary Turner }
15682af9438SZachary Turner
157dcff3961SIgor Kudrin return createStringError(errc::invalid_argument,
158dcff3961SIgor Kudrin "address range table at offset 0x%" PRIx64
159dcff3961SIgor Kudrin " is not terminated by null entry",
160dcff3961SIgor Kudrin Offset);
16182af9438SZachary Turner }
16282af9438SZachary Turner
dump(raw_ostream & OS) const16382af9438SZachary Turner void DWARFDebugArangeSet::dump(raw_ostream &OS) const {
16469dfa07bSIgor Kudrin int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(HeaderData.Format);
16563329907SIgor Kudrin OS << "Address Range Header: "
16669dfa07bSIgor Kudrin << format("length = 0x%0*" PRIx64 ", ", OffsetDumpWidth, HeaderData.Length)
1672ea94c8aSIgor Kudrin << "format = " << dwarf::FormatString(HeaderData.Format) << ", "
16863329907SIgor Kudrin << format("version = 0x%4.4x, ", HeaderData.Version)
16969dfa07bSIgor Kudrin << format("cu_offset = 0x%0*" PRIx64 ", ", OffsetDumpWidth,
17069dfa07bSIgor Kudrin HeaderData.CuOffset)
17163329907SIgor Kudrin << format("addr_size = 0x%2.2x, ", HeaderData.AddrSize)
17263329907SIgor Kudrin << format("seg_size = 0x%2.2x\n", HeaderData.SegSize);
17382af9438SZachary Turner
17482af9438SZachary Turner for (const auto &Desc : ArangeDescriptors) {
1756f24c877SJonas Devlieghere Desc.dump(OS, HeaderData.AddrSize);
1766f24c877SJonas Devlieghere OS << '\n';
17782af9438SZachary Turner }
17882af9438SZachary Turner }
179