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
23 using namespace llvm;
24 using namespace dwarf;
25
clear()26 void DWARFAbbreviationDeclaration::clear() {
27 Code = 0;
28 Tag = DW_TAG_null;
29 CodeByteSize = 0;
30 HasChildren = false;
31 AttributeSpecs.clear();
32 FixedAttributeSize.reset();
33 }
34
DWARFAbbreviationDeclaration()35 DWARFAbbreviationDeclaration::DWARFAbbreviationDeclaration() {
36 clear();
37 }
38
39 bool
extract(DataExtractor Data,uint64_t * OffsetPtr)40 DWARFAbbreviationDeclaration::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
dump(raw_ostream & OS) const128 void 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
141 Optional<uint32_t>
findAttributeIndex(dwarf::Attribute Attr) const142 DWARFAbbreviationDeclaration::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
getAttributeValue(const uint64_t DIEOffset,const dwarf::Attribute Attr,const DWARFUnit & U) const150 Optional<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
getByteSize(const DWARFUnit & U) const185 size_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
getByteSize(const DWARFUnit & U) const197 Optional<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
getFixedAttributesByteSize(const DWARFUnit & U) const210 Optional<size_t> DWARFAbbreviationDeclaration::getFixedAttributesByteSize(
211 const DWARFUnit &U) const {
212 if (FixedAttributeSize)
213 return FixedAttributeSize->getByteSize(U);
214 return None;
215 }
216