1 //===-- DWARFAbbreviationDeclaration.cpp ----------------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
11 #include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
12 #include "llvm/DebugInfo/DWARF/DWARFUnit.h"
13 #include "llvm/Support/Dwarf.h"
14 #include "llvm/Support/Format.h"
15 #include "llvm/Support/raw_ostream.h"
16 using namespace llvm;
17 using namespace dwarf;
18 
19 void DWARFAbbreviationDeclaration::clear() {
20   Code = 0;
21   Tag = DW_TAG_null;
22   CodeByteSize = 0;
23   HasChildren = false;
24   AttributeSpecs.clear();
25   FixedAttributeSize.reset();
26 }
27 
28 DWARFAbbreviationDeclaration::DWARFAbbreviationDeclaration() {
29   clear();
30 }
31 
32 bool
33 DWARFAbbreviationDeclaration::extract(DataExtractor Data,
34                                       uint32_t* OffsetPtr) {
35   clear();
36   const uint32_t Offset = *OffsetPtr;
37   Code = Data.getULEB128(OffsetPtr);
38   if (Code == 0) {
39     return false;
40   }
41   CodeByteSize = *OffsetPtr - Offset;
42   Tag = static_cast<llvm::dwarf::Tag>(Data.getULEB128(OffsetPtr));
43   if (Tag == DW_TAG_null) {
44     clear();
45     return false;
46   }
47   uint8_t ChildrenByte = Data.getU8(OffsetPtr);
48   HasChildren = (ChildrenByte == DW_CHILDREN_yes);
49   // Assign a value to our optional FixedAttributeSize member variable. If
50   // this member variable still has a value after the while loop below, then
51   // all attribute data in this abbreviation declaration has a fixed byte size.
52   FixedAttributeSize = FixedSizeInfo();
53 
54   // Read all of the abbreviation attributes and forms.
55   while (true) {
56     auto A = static_cast<Attribute>(Data.getULEB128(OffsetPtr));
57     auto F = static_cast<Form>(Data.getULEB128(OffsetPtr));
58     if (A && F) {
59       auto FixedFormByteSize = DWARFFormValue::getFixedByteSize(F);
60       AttributeSpecs.push_back(AttributeSpec(A, F, FixedFormByteSize));
61       // If this abbrevation still has a fixed byte size, then update the
62       // FixedAttributeSize as needed.
63       if (FixedAttributeSize) {
64         if (FixedFormByteSize)
65           FixedAttributeSize->NumBytes += *FixedFormByteSize;
66         else {
67           switch (F) {
68           case DW_FORM_addr:
69             ++FixedAttributeSize->NumAddrs;
70             break;
71 
72           case DW_FORM_ref_addr:
73             ++FixedAttributeSize->NumRefAddrs;
74             break;
75 
76           case DW_FORM_strp:
77           case DW_FORM_GNU_ref_alt:
78           case DW_FORM_GNU_strp_alt:
79           case DW_FORM_line_strp:
80           case DW_FORM_sec_offset:
81           case DW_FORM_strp_sup:
82           case DW_FORM_ref_sup:
83             ++FixedAttributeSize->NumDwarfOffsets;
84             break;
85 
86           default:
87             // Indicate we no longer have a fixed byte size for this
88             // abbreviation by clearing the FixedAttributeSize optional value
89             // so it doesn't have a value.
90             FixedAttributeSize.reset();
91             break;
92           }
93         }
94       }
95     } else if (A == 0 && F == 0) {
96       // We successfully reached the end of this abbreviation declaration
97       // since both attribute and form are zero.
98       break;
99     } else {
100       // Attribute and form pairs must either both be non-zero, in which case
101       // they are added to the abbreviation declaration, or both be zero to
102       // terminate the abbrevation declaration. In this case only one was
103       // zero which is an error.
104       clear();
105       return false;
106     }
107   }
108   return true;
109 }
110 
111 void DWARFAbbreviationDeclaration::dump(raw_ostream &OS) const {
112   auto tagString = TagString(getTag());
113   OS << '[' << getCode() << "] ";
114   if (!tagString.empty())
115     OS << tagString;
116   else
117     OS << format("DW_TAG_Unknown_%x", getTag());
118   OS << "\tDW_CHILDREN_" << (hasChildren() ? "yes" : "no") << '\n';
119   for (const AttributeSpec &Spec : AttributeSpecs) {
120     OS << '\t';
121     auto attrString = AttributeString(Spec.Attr);
122     if (!attrString.empty())
123       OS << attrString;
124     else
125       OS << format("DW_AT_Unknown_%x", Spec.Attr);
126     OS << '\t';
127     auto formString = FormEncodingString(Spec.Form);
128     if (!formString.empty())
129       OS << formString;
130     else
131       OS << format("DW_FORM_Unknown_%x", Spec.Form);
132     OS << '\n';
133   }
134   OS << '\n';
135 }
136 
137 Optional<uint32_t>
138 DWARFAbbreviationDeclaration::findAttributeIndex(dwarf::Attribute Attr) const {
139   for (uint32_t i = 0, e = AttributeSpecs.size(); i != e; ++i) {
140     if (AttributeSpecs[i].Attr == Attr)
141       return i;
142   }
143   return None;
144 }
145 
146 bool DWARFAbbreviationDeclaration::getAttributeValue(
147     const uint32_t DIEOffset, const dwarf::Attribute Attr, const DWARFUnit &U,
148     DWARFFormValue &FormValue) const {
149   Optional<uint32_t> MatchAttrIndex = findAttributeIndex(Attr);
150   if (!MatchAttrIndex)
151     return false;
152 
153   auto DebugInfoData = U.getDebugInfoExtractor();
154 
155   // Add the byte size of ULEB that for the abbrev Code so we can start
156   // skipping the attribute data.
157   uint32_t Offset = DIEOffset + CodeByteSize;
158   uint32_t AttrIndex = 0;
159   for (const auto &Spec : AttributeSpecs) {
160     if (*MatchAttrIndex == AttrIndex) {
161       // We have arrived at the attribute to extract, extract if from Offset.
162       FormValue.setForm(Spec.Form);
163       return FormValue.extractValue(DebugInfoData, &Offset, &U);
164     }
165     // March Offset along until we get to the attribute we want.
166     if (Optional<uint8_t> FixedSize = Spec.getByteSize(U))
167       Offset += *FixedSize;
168     else
169       DWARFFormValue::skipValue(Spec.Form, DebugInfoData, &Offset, &U);
170     ++AttrIndex;
171   }
172   return false;
173 }
174 
175 size_t DWARFAbbreviationDeclaration::FixedSizeInfo::getByteSize(
176     const DWARFUnit &U) const {
177   size_t ByteSize = NumBytes;
178   if (NumAddrs)
179     ByteSize += NumAddrs * U.getAddressByteSize();
180   if (NumRefAddrs)
181     ByteSize += NumRefAddrs * U.getRefAddrByteSize();
182   if (NumDwarfOffsets)
183     ByteSize += NumDwarfOffsets * U.getDwarfOffsetByteSize();
184   return ByteSize;
185 }
186 
187 Optional<uint8_t> DWARFAbbreviationDeclaration::AttributeSpec::getByteSize(
188     const DWARFUnit &U) const {
189   return ByteSize ? ByteSize : DWARFFormValue::getFixedByteSize(Form, &U);
190 }
191 
192 Optional<size_t> DWARFAbbreviationDeclaration::getFixedAttributesByteSize(
193     const DWARFUnit &U) const {
194   if (FixedAttributeSize)
195     return FixedAttributeSize->getByteSize(U);
196   return None;
197 }
198