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