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 bool
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 
126 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>
140 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 
148 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>
166 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>
185 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 
199 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 
211 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 
224 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