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/DWARFDataExtractor.h"
15 #include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
16 #include "llvm/DebugInfo/DWARF/DWARFUnit.h"
17 #include "llvm/Support/DataExtractor.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 
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 
35 DWARFAbbreviationDeclaration::DWARFAbbreviationDeclaration() {
36   clear();
37 }
38 
39 bool
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 
128 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>
142 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 
150 uint64_t DWARFAbbreviationDeclaration::getAttributeOffsetFromIndex(
151     uint32_t AttrIndex, uint64_t DIEOffset, const DWARFUnit &U) const {
152   DWARFDataExtractor DebugInfoData = U.getDebugInfoExtractor();
153 
154   // Add the byte size of ULEB that for the abbrev Code so we can start
155   // skipping the attribute data.
156   uint64_t Offset = DIEOffset + CodeByteSize;
157   for (uint32_t CurAttrIdx = 0; CurAttrIdx != AttrIndex; ++CurAttrIdx)
158     // Match Offset along until we get to the attribute we want.
159     if (auto FixedSize = AttributeSpecs[CurAttrIdx].getByteSize(U))
160       Offset += *FixedSize;
161     else
162       DWARFFormValue::skipValue(AttributeSpecs[CurAttrIdx].Form, DebugInfoData,
163                                 &Offset, U.getFormParams());
164   return Offset;
165 }
166 
167 Optional<DWARFFormValue>
168 DWARFAbbreviationDeclaration::getAttributeValueFromOffset(
169     uint32_t AttrIndex, uint64_t Offset, const DWARFUnit &U) const {
170   assert(AttributeSpecs.size() > AttrIndex &&
171          "Attribute Index is out of bounds.");
172 
173   // We have arrived at the attribute to extract, extract if from Offset.
174   const AttributeSpec &Spec = AttributeSpecs[AttrIndex];
175   if (Spec.isImplicitConst())
176     return DWARFFormValue::createFromSValue(Spec.Form,
177                                             Spec.getImplicitConstValue());
178 
179   DWARFFormValue FormValue(Spec.Form);
180   DWARFDataExtractor DebugInfoData = U.getDebugInfoExtractor();
181   if (FormValue.extractValue(DebugInfoData, &Offset, U.getFormParams(), &U))
182     return FormValue;
183   return None;
184 }
185 
186 Optional<DWARFFormValue>
187 DWARFAbbreviationDeclaration::getAttributeValue(const uint64_t DIEOffset,
188                                                 const dwarf::Attribute Attr,
189                                                 const DWARFUnit &U) const {
190   // Check if this abbreviation has this attribute without needing to skip
191   // any data so we can return quickly if it doesn't.
192   Optional<uint32_t> MatchAttrIndex = findAttributeIndex(Attr);
193   if (!MatchAttrIndex)
194     return None;
195 
196   uint64_t Offset = getAttributeOffsetFromIndex(*MatchAttrIndex, DIEOffset, U);
197 
198   return getAttributeValueFromOffset(*MatchAttrIndex, Offset, U);
199 }
200 
201 size_t DWARFAbbreviationDeclaration::FixedSizeInfo::getByteSize(
202     const DWARFUnit &U) const {
203   size_t ByteSize = NumBytes;
204   if (NumAddrs)
205     ByteSize += NumAddrs * U.getAddressByteSize();
206   if (NumRefAddrs)
207     ByteSize += NumRefAddrs * U.getRefAddrByteSize();
208   if (NumDwarfOffsets)
209     ByteSize += NumDwarfOffsets * U.getDwarfOffsetByteSize();
210   return ByteSize;
211 }
212 
213 Optional<int64_t> DWARFAbbreviationDeclaration::AttributeSpec::getByteSize(
214     const DWARFUnit &U) const {
215   if (isImplicitConst())
216     return 0;
217   if (ByteSize.HasByteSize)
218     return ByteSize.ByteSize;
219   Optional<int64_t> S;
220   auto FixedByteSize = dwarf::getFixedFormByteSize(Form, U.getFormParams());
221   if (FixedByteSize)
222     S = *FixedByteSize;
223   return S;
224 }
225 
226 Optional<size_t> DWARFAbbreviationDeclaration::getFixedAttributesByteSize(
227     const DWARFUnit &U) const {
228   if (FixedAttributeSize)
229     return FixedAttributeSize->getByteSize(U);
230   return None;
231 }
232