DWARFAbbreviationDeclaration.cpp revision 360784
1//===- DWARFAbbreviationDeclaration.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/DWARFAbbreviationDeclaration.h"
10
11#include "llvm/ADT/None.h"
12#include "llvm/ADT/Optional.h"
13#include "llvm/BinaryFormat/Dwarf.h"
14#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
15#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
16#include "llvm/Support/DataExtractor.h"
17#include "llvm/Support/Format.h"
18#include "llvm/Support/FormatVariadic.h"
19#include "llvm/Support/raw_ostream.h"
20#include <cstddef>
21#include <cstdint>
22
23using namespace llvm;
24using namespace dwarf;
25
26void DWARFAbbreviationDeclaration::clear() {
27  Code = 0;
28  Tag = DW_TAG_null;
29  CodeByteSize = 0;
30  HasChildren = false;
31  AttributeSpecs.clear();
32  FixedAttributeSize.reset();
33}
34
35DWARFAbbreviationDeclaration::DWARFAbbreviationDeclaration() {
36  clear();
37}
38
39bool
40DWARFAbbreviationDeclaration::extract(DataExtractor Data,
41                                      uint64_t* OffsetPtr) {
42  clear();
43  const uint64_t Offset = *OffsetPtr;
44  Code = Data.getULEB128(OffsetPtr);
45  if (Code == 0) {
46    return false;
47  }
48  CodeByteSize = *OffsetPtr - Offset;
49  Tag = static_cast<llvm::dwarf::Tag>(Data.getULEB128(OffsetPtr));
50  if (Tag == DW_TAG_null) {
51    clear();
52    return false;
53  }
54  uint8_t ChildrenByte = Data.getU8(OffsetPtr);
55  HasChildren = (ChildrenByte == DW_CHILDREN_yes);
56  // Assign a value to our optional FixedAttributeSize member variable. If
57  // this member variable still has a value after the while loop below, then
58  // all attribute data in this abbreviation declaration has a fixed byte size.
59  FixedAttributeSize = FixedSizeInfo();
60
61  // Read all of the abbreviation attributes and forms.
62  while (true) {
63    auto A = static_cast<Attribute>(Data.getULEB128(OffsetPtr));
64    auto F = static_cast<Form>(Data.getULEB128(OffsetPtr));
65    if (A && F) {
66      bool IsImplicitConst = (F == DW_FORM_implicit_const);
67      if (IsImplicitConst) {
68        int64_t V = Data.getSLEB128(OffsetPtr);
69        AttributeSpecs.push_back(AttributeSpec(A, F, V));
70        continue;
71      }
72      Optional<uint8_t> ByteSize;
73      // If this abbrevation still has a fixed byte size, then update the
74      // FixedAttributeSize as needed.
75      switch (F) {
76      case DW_FORM_addr:
77        if (FixedAttributeSize)
78          ++FixedAttributeSize->NumAddrs;
79        break;
80
81      case DW_FORM_ref_addr:
82        if (FixedAttributeSize)
83          ++FixedAttributeSize->NumRefAddrs;
84        break;
85
86      case DW_FORM_strp:
87      case DW_FORM_GNU_ref_alt:
88      case DW_FORM_GNU_strp_alt:
89      case DW_FORM_line_strp:
90      case DW_FORM_sec_offset:
91      case DW_FORM_strp_sup:
92        if (FixedAttributeSize)
93          ++FixedAttributeSize->NumDwarfOffsets;
94        break;
95
96      default:
97        // The form has a byte size that doesn't depend on Params.
98        // If it's a fixed size, keep track of it.
99        if ((ByteSize = dwarf::getFixedFormByteSize(F, dwarf::FormParams()))) {
100          if (FixedAttributeSize)
101            FixedAttributeSize->NumBytes += *ByteSize;
102          break;
103        }
104        // Indicate we no longer have a fixed byte size for this
105        // abbreviation by clearing the FixedAttributeSize optional value
106        // so it doesn't have a value.
107        FixedAttributeSize.reset();
108        break;
109      }
110      // Record this attribute and its fixed size if it has one.
111      AttributeSpecs.push_back(AttributeSpec(A, F, ByteSize));
112    } else if (A == 0 && F == 0) {
113      // We successfully reached the end of this abbreviation declaration
114      // since both attribute and form are zero.
115      break;
116    } else {
117      // Attribute and form pairs must either both be non-zero, in which case
118      // they are added to the abbreviation declaration, or both be zero to
119      // terminate the abbrevation declaration. In this case only one was
120      // zero which is an error.
121      clear();
122      return false;
123    }
124  }
125  return true;
126}
127
128void DWARFAbbreviationDeclaration::dump(raw_ostream &OS) const {
129  OS << '[' << getCode() << "] ";
130  OS << formatv("{0}", getTag());
131  OS << "\tDW_CHILDREN_" << (hasChildren() ? "yes" : "no") << '\n';
132  for (const AttributeSpec &Spec : AttributeSpecs) {
133    OS << formatv("\t{0}\t{1}", Spec.Attr, Spec.Form);
134    if (Spec.isImplicitConst())
135      OS << '\t' << Spec.getImplicitConstValue();
136    OS << '\n';
137  }
138  OS << '\n';
139}
140
141Optional<uint32_t>
142DWARFAbbreviationDeclaration::findAttributeIndex(dwarf::Attribute Attr) const {
143  for (uint32_t i = 0, e = AttributeSpecs.size(); i != e; ++i) {
144    if (AttributeSpecs[i].Attr == Attr)
145      return i;
146  }
147  return None;
148}
149
150Optional<DWARFFormValue> DWARFAbbreviationDeclaration::getAttributeValue(
151    const uint64_t DIEOffset, const dwarf::Attribute Attr,
152    const DWARFUnit &U) const {
153  Optional<uint32_t> MatchAttrIndex = findAttributeIndex(Attr);
154  if (!MatchAttrIndex)
155    return None;
156
157  auto DebugInfoData = U.getDebugInfoExtractor();
158
159  // Add the byte size of ULEB that for the abbrev Code so we can start
160  // skipping the attribute data.
161  uint64_t Offset = DIEOffset + CodeByteSize;
162  uint32_t AttrIndex = 0;
163  for (const auto &Spec : AttributeSpecs) {
164    if (*MatchAttrIndex == AttrIndex) {
165      // We have arrived at the attribute to extract, extract if from Offset.
166      if (Spec.isImplicitConst())
167        return DWARFFormValue::createFromSValue(Spec.Form,
168                                                Spec.getImplicitConstValue());
169
170      DWARFFormValue FormValue(Spec.Form);
171      if (FormValue.extractValue(DebugInfoData, &Offset, U.getFormParams(), &U))
172        return FormValue;
173    }
174    // March Offset along until we get to the attribute we want.
175    if (auto FixedSize = Spec.getByteSize(U))
176      Offset += *FixedSize;
177    else
178      DWARFFormValue::skipValue(Spec.Form, DebugInfoData, &Offset,
179                                U.getFormParams());
180    ++AttrIndex;
181  }
182  return None;
183}
184
185size_t DWARFAbbreviationDeclaration::FixedSizeInfo::getByteSize(
186    const DWARFUnit &U) const {
187  size_t ByteSize = NumBytes;
188  if (NumAddrs)
189    ByteSize += NumAddrs * U.getAddressByteSize();
190  if (NumRefAddrs)
191    ByteSize += NumRefAddrs * U.getRefAddrByteSize();
192  if (NumDwarfOffsets)
193    ByteSize += NumDwarfOffsets * U.getDwarfOffsetByteSize();
194  return ByteSize;
195}
196
197Optional<int64_t> DWARFAbbreviationDeclaration::AttributeSpec::getByteSize(
198    const DWARFUnit &U) const {
199  if (isImplicitConst())
200    return 0;
201  if (ByteSize.HasByteSize)
202    return ByteSize.ByteSize;
203  Optional<int64_t> S;
204  auto FixedByteSize = dwarf::getFixedFormByteSize(Form, U.getFormParams());
205  if (FixedByteSize)
206    S = *FixedByteSize;
207  return S;
208}
209
210Optional<size_t> DWARFAbbreviationDeclaration::getFixedAttributesByteSize(
211    const DWARFUnit &U) const {
212  if (FixedAttributeSize)
213    return FixedAttributeSize->getByteSize(U);
214  return None;
215}
216