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