DWARFDebugAddr.cpp revision 360784
1//===- DWARFDebugAddr.cpp -------------------------------------------------===//
2//
3// 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
6//
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,
22                                   uint64_t *OffsetPtr,
23                                   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,
31                       "section is not large enough to contain a "
32                       ".debug_addr table length at offset 0x%"
33                       PRIx64, *OffsetPtr);
34  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);
47    if (HeaderData.Length == dwarf::DW_LENGTH_DWARF64) {
48      invalidateLength();
49      return createStringError(errc::not_supported,
50          "DWARF64 is not supported in .debug_addr at offset 0x%" PRIx64,
51          HeaderOffset);
52    }
53    if (HeaderData.Length + sizeof(uint32_t) < sizeof(Header)) {
54      uint32_t TmpLength = getLength();
55      invalidateLength();
56      return createStringError(errc::invalid_argument,
57                         ".debug_addr table at offset 0x%" PRIx64
58                         " has too small length (0x%" PRIx32
59                         ") to contain a complete header",
60                         HeaderOffset, TmpLength);
61    }
62    uint64_t End = HeaderOffset + getLength();
63    if (!Data.isValidOffsetForDataOfSize(HeaderOffset, End - HeaderOffset)) {
64      uint32_t TmpLength = getLength();
65      invalidateLength();
66      return createStringError(errc::invalid_argument,
67          "section is not large enough to contain a .debug_addr table "
68          "of length 0x%" PRIx32 " at offset 0x%" PRIx64,
69          TmpLength, HeaderOffset);
70    }
71
72    HeaderData.Version = Data.getU16(OffsetPtr);
73    HeaderData.AddrSize = Data.getU8(OffsetPtr);
74    HeaderData.SegSize = Data.getU8(OffsetPtr);
75    DataSize = getDataSize();
76  } else {
77    HeaderData.Version = UnitVersion;
78    HeaderData.AddrSize = AddrSize;
79    // TODO: Support for non-zero SegSize.
80    HeaderData.SegSize = 0;
81    DataSize = Data.size();
82  }
83
84  // Perform basic validation of the remaining header fields.
85
86  // We support DWARF version 5 for now as well as pre-DWARF5
87  // implementations of .debug_addr table, which doesn't contain a header
88  // and consists only of a series of addresses.
89  if (HeaderData.Version > 5) {
90    return createStringError(errc::not_supported, "version %" PRIu16
91        " of .debug_addr section at offset 0x%" PRIx64 " is not supported",
92        HeaderData.Version, HeaderOffset);
93  }
94  // FIXME: For now we just treat version mismatch as an error,
95  // however the correct way to associate a .debug_addr table
96  // with a .debug_info table is to look at the DW_AT_addr_base
97  // attribute in the info table.
98  if (HeaderData.Version != UnitVersion)
99    return createStringError(errc::invalid_argument,
100                       ".debug_addr table at offset 0x%" PRIx64
101                       " has version %" PRIu16
102                       " which is different from the version suggested"
103                       " by the DWARF unit header: %" PRIu16,
104                       HeaderOffset, HeaderData.Version, UnitVersion);
105  if (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8)
106    return createStringError(errc::not_supported,
107                       ".debug_addr table at offset 0x%" PRIx64
108                       " has unsupported address size %" PRIu8,
109                       HeaderOffset, HeaderData.AddrSize);
110  if (HeaderData.AddrSize != AddrSize && AddrSize != 0)
111    return createStringError(errc::invalid_argument,
112                       ".debug_addr table at offset 0x%" PRIx64
113                       " has address size %" PRIu8
114                       " which is different from CU address size %" PRIu8,
115                       HeaderOffset, HeaderData.AddrSize, AddrSize);
116
117  // TODO: add support for non-zero segment selector size.
118  if (HeaderData.SegSize != 0)
119    return createStringError(errc::not_supported,
120                       ".debug_addr table at offset 0x%" PRIx64
121                       " has unsupported segment selector size %" PRIu8,
122                       HeaderOffset, HeaderData.SegSize);
123  if (DataSize % HeaderData.AddrSize != 0) {
124    invalidateLength();
125    return createStringError(errc::invalid_argument,
126                       ".debug_addr table at offset 0x%" PRIx64
127                       " contains data of size %" PRIu32
128                       " which is not a multiple of addr size %" PRIu8,
129                       HeaderOffset, DataSize, HeaderData.AddrSize);
130  }
131  Data.setAddressSize(HeaderData.AddrSize);
132  uint32_t AddrCount = DataSize / HeaderData.AddrSize;
133  for (uint32_t I = 0; I < AddrCount; ++I)
134    if (HeaderData.AddrSize == 4)
135      Addrs.push_back(Data.getU32(OffsetPtr));
136    else
137      Addrs.push_back(Data.getU64(OffsetPtr));
138  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);
144  OS << format("Addr Section: length = 0x%8.8" PRIx32
145               ", version = 0x%4.4" PRIx16 ", "
146               "addr_size = 0x%2.2" PRIx8 ", seg_size = 0x%2.2" PRIx8 "\n",
147               HeaderData.Length, HeaderData.Version, HeaderData.AddrSize,
148               HeaderData.SegSize);
149
150  if (Addrs.size() > 0) {
151    const char *AddrFmt = (HeaderData.AddrSize == 4) ? "0x%8.8" PRIx64 "\n"
152                                                     : "0x%16.16" PRIx64 "\n";
153    OS << "Addrs: [\n";
154    for (uint64_t Addr : Addrs)
155      OS << format(AddrFmt, Addr);
156    OS << "]\n";
157  }
158}
159
160Expected<uint64_t> DWARFDebugAddrTable::getAddrEntry(uint32_t Index) const {
161  if (Index < Addrs.size())
162    return Addrs[Index];
163  return createStringError(errc::invalid_argument,
164                           "Index %" PRIu32 " is out of range of the "
165                           ".debug_addr table at offset 0x%" PRIx64,
166                           Index, HeaderOffset);
167}
168
169uint32_t DWARFDebugAddrTable::getLength() const {
170  if (HeaderData.Length == 0)
171    return 0;
172  // TODO: DWARF64 support.
173  return HeaderData.Length + sizeof(uint32_t);
174}
175
176uint32_t DWARFDebugAddrTable::getDataSize() const {
177  if (DataSize != 0)
178    return DataSize;
179  if (getLength() == 0)
180    return 0;
181  return getLength() - getHeaderSize();
182}
183