xref: /llvm-project/llvm/lib/DebugInfo/DWARF/DWARFDebugAddr.cpp (revision 89fab98e884f05076bbd420d95b5de3596f5452c)
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