xref: /freebsd-src/contrib/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
10b57cec5SDimitry Andric //===- DWARFAbbreviationDeclaration.cpp -----------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
100b57cec5SDimitry Andric 
110b57cec5SDimitry Andric #include "llvm/BinaryFormat/Dwarf.h"
1281ad6265SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
130b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
140b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFUnit.h"
150b57cec5SDimitry Andric #include "llvm/Support/DataExtractor.h"
160b57cec5SDimitry Andric #include "llvm/Support/FormatVariadic.h"
170b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
180b57cec5SDimitry Andric #include <cstddef>
190b57cec5SDimitry Andric #include <cstdint>
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric using namespace llvm;
220b57cec5SDimitry Andric using namespace dwarf;
230b57cec5SDimitry Andric 
clear()240b57cec5SDimitry Andric void DWARFAbbreviationDeclaration::clear() {
250b57cec5SDimitry Andric   Code = 0;
260b57cec5SDimitry Andric   Tag = DW_TAG_null;
270b57cec5SDimitry Andric   CodeByteSize = 0;
280b57cec5SDimitry Andric   HasChildren = false;
290b57cec5SDimitry Andric   AttributeSpecs.clear();
300b57cec5SDimitry Andric   FixedAttributeSize.reset();
310b57cec5SDimitry Andric }
320b57cec5SDimitry Andric 
DWARFAbbreviationDeclaration()330b57cec5SDimitry Andric DWARFAbbreviationDeclaration::DWARFAbbreviationDeclaration() {
340b57cec5SDimitry Andric   clear();
350b57cec5SDimitry Andric }
360b57cec5SDimitry Andric 
37*06c3fb27SDimitry Andric llvm::Expected<DWARFAbbreviationDeclaration::ExtractState>
extract(DataExtractor Data,uint64_t * OffsetPtr)38*06c3fb27SDimitry Andric DWARFAbbreviationDeclaration::extract(DataExtractor Data, uint64_t *OffsetPtr) {
390b57cec5SDimitry Andric   clear();
408bcb0991SDimitry Andric   const uint64_t Offset = *OffsetPtr;
41*06c3fb27SDimitry Andric   Error Err = Error::success();
42*06c3fb27SDimitry Andric   Code = Data.getULEB128(OffsetPtr, &Err);
43*06c3fb27SDimitry Andric   if (Err)
44*06c3fb27SDimitry Andric     return std::move(Err);
45*06c3fb27SDimitry Andric 
46*06c3fb27SDimitry Andric   if (Code == 0)
47*06c3fb27SDimitry Andric     return ExtractState::Complete;
48*06c3fb27SDimitry Andric 
490b57cec5SDimitry Andric   CodeByteSize = *OffsetPtr - Offset;
50*06c3fb27SDimitry Andric   Tag = static_cast<llvm::dwarf::Tag>(Data.getULEB128(OffsetPtr, &Err));
51*06c3fb27SDimitry Andric   if (Err)
52*06c3fb27SDimitry Andric     return std::move(Err);
53*06c3fb27SDimitry Andric 
540b57cec5SDimitry Andric   if (Tag == DW_TAG_null) {
550b57cec5SDimitry Andric     clear();
56*06c3fb27SDimitry Andric     return make_error<llvm::object::GenericBinaryError>(
57*06c3fb27SDimitry Andric         "abbreviation declaration requires a non-null tag");
580b57cec5SDimitry Andric   }
59*06c3fb27SDimitry Andric   uint8_t ChildrenByte = Data.getU8(OffsetPtr, &Err);
60*06c3fb27SDimitry Andric   if (Err)
61*06c3fb27SDimitry Andric     return std::move(Err);
62*06c3fb27SDimitry Andric 
630b57cec5SDimitry Andric   HasChildren = (ChildrenByte == DW_CHILDREN_yes);
640b57cec5SDimitry Andric   // Assign a value to our optional FixedAttributeSize member variable. If
650b57cec5SDimitry Andric   // this member variable still has a value after the while loop below, then
660b57cec5SDimitry Andric   // all attribute data in this abbreviation declaration has a fixed byte size.
670b57cec5SDimitry Andric   FixedAttributeSize = FixedSizeInfo();
680b57cec5SDimitry Andric 
690b57cec5SDimitry Andric   // Read all of the abbreviation attributes and forms.
70*06c3fb27SDimitry Andric   while (Data.isValidOffset(*OffsetPtr)) {
71*06c3fb27SDimitry Andric     auto A = static_cast<Attribute>(Data.getULEB128(OffsetPtr, &Err));
72*06c3fb27SDimitry Andric     if (Err)
73*06c3fb27SDimitry Andric       return std::move(Err);
74*06c3fb27SDimitry Andric 
75*06c3fb27SDimitry Andric     auto F = static_cast<Form>(Data.getULEB128(OffsetPtr, &Err));
76*06c3fb27SDimitry Andric     if (Err)
77*06c3fb27SDimitry Andric       return std::move(Err);
78*06c3fb27SDimitry Andric 
79*06c3fb27SDimitry Andric     // We successfully reached the end of this abbreviation declaration
80*06c3fb27SDimitry Andric     // since both attribute and form are zero. There may be more abbreviation
81*06c3fb27SDimitry Andric     // declarations afterwards.
82*06c3fb27SDimitry Andric     if (!A && !F)
83*06c3fb27SDimitry Andric       return ExtractState::MoreItems;
84*06c3fb27SDimitry Andric 
85*06c3fb27SDimitry Andric     if (!A || !F) {
86*06c3fb27SDimitry Andric       // Attribute and form pairs must either both be non-zero, in which case
87*06c3fb27SDimitry Andric       // they are added to the abbreviation declaration, or both be zero to
88*06c3fb27SDimitry Andric       // terminate the abbrevation declaration. In this case only one was
89*06c3fb27SDimitry Andric       // zero which is an error.
90*06c3fb27SDimitry Andric       clear();
91*06c3fb27SDimitry Andric       return make_error<llvm::object::GenericBinaryError>(
92*06c3fb27SDimitry Andric           "malformed abbreviation declaration attribute. Either the attribute "
93*06c3fb27SDimitry Andric           "or the form is zero while the other is not");
94*06c3fb27SDimitry Andric     }
95*06c3fb27SDimitry Andric 
960b57cec5SDimitry Andric     bool IsImplicitConst = (F == DW_FORM_implicit_const);
970b57cec5SDimitry Andric     if (IsImplicitConst) {
980b57cec5SDimitry Andric       int64_t V = Data.getSLEB128(OffsetPtr);
990b57cec5SDimitry Andric       AttributeSpecs.push_back(AttributeSpec(A, F, V));
1000b57cec5SDimitry Andric       continue;
1010b57cec5SDimitry Andric     }
102bdd1243dSDimitry Andric     std::optional<uint8_t> ByteSize;
1030b57cec5SDimitry Andric     // If this abbrevation still has a fixed byte size, then update the
1040b57cec5SDimitry Andric     // FixedAttributeSize as needed.
1050b57cec5SDimitry Andric     switch (F) {
1060b57cec5SDimitry Andric     case DW_FORM_addr:
1070b57cec5SDimitry Andric       if (FixedAttributeSize)
1080b57cec5SDimitry Andric         ++FixedAttributeSize->NumAddrs;
1090b57cec5SDimitry Andric       break;
1100b57cec5SDimitry Andric 
1110b57cec5SDimitry Andric     case DW_FORM_ref_addr:
1120b57cec5SDimitry Andric       if (FixedAttributeSize)
1130b57cec5SDimitry Andric         ++FixedAttributeSize->NumRefAddrs;
1140b57cec5SDimitry Andric       break;
1150b57cec5SDimitry Andric 
1160b57cec5SDimitry Andric     case DW_FORM_strp:
1170b57cec5SDimitry Andric     case DW_FORM_GNU_ref_alt:
1180b57cec5SDimitry Andric     case DW_FORM_GNU_strp_alt:
1190b57cec5SDimitry Andric     case DW_FORM_line_strp:
1200b57cec5SDimitry Andric     case DW_FORM_sec_offset:
1210b57cec5SDimitry Andric     case DW_FORM_strp_sup:
1220b57cec5SDimitry Andric       if (FixedAttributeSize)
1230b57cec5SDimitry Andric         ++FixedAttributeSize->NumDwarfOffsets;
1240b57cec5SDimitry Andric       break;
1250b57cec5SDimitry Andric 
1260b57cec5SDimitry Andric     default:
1270b57cec5SDimitry Andric       // The form has a byte size that doesn't depend on Params.
1280b57cec5SDimitry Andric       // If it's a fixed size, keep track of it.
1290b57cec5SDimitry Andric       if ((ByteSize = dwarf::getFixedFormByteSize(F, dwarf::FormParams()))) {
1300b57cec5SDimitry Andric         if (FixedAttributeSize)
1310b57cec5SDimitry Andric           FixedAttributeSize->NumBytes += *ByteSize;
1320b57cec5SDimitry Andric         break;
1330b57cec5SDimitry Andric       }
1340b57cec5SDimitry Andric       // Indicate we no longer have a fixed byte size for this
1350b57cec5SDimitry Andric       // abbreviation by clearing the FixedAttributeSize optional value
1360b57cec5SDimitry Andric       // so it doesn't have a value.
1370b57cec5SDimitry Andric       FixedAttributeSize.reset();
1380b57cec5SDimitry Andric       break;
1390b57cec5SDimitry Andric     }
1400b57cec5SDimitry Andric     // Record this attribute and its fixed size if it has one.
1410b57cec5SDimitry Andric     AttributeSpecs.push_back(AttributeSpec(A, F, ByteSize));
1420b57cec5SDimitry Andric   }
143*06c3fb27SDimitry Andric   return make_error<llvm::object::GenericBinaryError>(
144*06c3fb27SDimitry Andric       "abbreviation declaration attribute list was not terminated with a null "
145*06c3fb27SDimitry Andric       "entry");
1460b57cec5SDimitry Andric }
1470b57cec5SDimitry Andric 
dump(raw_ostream & OS) const1480b57cec5SDimitry Andric void DWARFAbbreviationDeclaration::dump(raw_ostream &OS) const {
1490b57cec5SDimitry Andric   OS << '[' << getCode() << "] ";
1500b57cec5SDimitry Andric   OS << formatv("{0}", getTag());
1510b57cec5SDimitry Andric   OS << "\tDW_CHILDREN_" << (hasChildren() ? "yes" : "no") << '\n';
1520b57cec5SDimitry Andric   for (const AttributeSpec &Spec : AttributeSpecs) {
1530b57cec5SDimitry Andric     OS << formatv("\t{0}\t{1}", Spec.Attr, Spec.Form);
1540b57cec5SDimitry Andric     if (Spec.isImplicitConst())
1550b57cec5SDimitry Andric       OS << '\t' << Spec.getImplicitConstValue();
1560b57cec5SDimitry Andric     OS << '\n';
1570b57cec5SDimitry Andric   }
1580b57cec5SDimitry Andric   OS << '\n';
1590b57cec5SDimitry Andric }
1600b57cec5SDimitry Andric 
161bdd1243dSDimitry Andric std::optional<uint32_t>
findAttributeIndex(dwarf::Attribute Attr) const1620b57cec5SDimitry Andric DWARFAbbreviationDeclaration::findAttributeIndex(dwarf::Attribute Attr) const {
1630b57cec5SDimitry Andric   for (uint32_t i = 0, e = AttributeSpecs.size(); i != e; ++i) {
1640b57cec5SDimitry Andric     if (AttributeSpecs[i].Attr == Attr)
1650b57cec5SDimitry Andric       return i;
1660b57cec5SDimitry Andric   }
167bdd1243dSDimitry Andric   return std::nullopt;
1680b57cec5SDimitry Andric }
1690b57cec5SDimitry Andric 
getAttributeOffsetFromIndex(uint32_t AttrIndex,uint64_t DIEOffset,const DWARFUnit & U) const170349cc55cSDimitry Andric uint64_t DWARFAbbreviationDeclaration::getAttributeOffsetFromIndex(
171349cc55cSDimitry Andric     uint32_t AttrIndex, uint64_t DIEOffset, const DWARFUnit &U) const {
172349cc55cSDimitry Andric   DWARFDataExtractor DebugInfoData = U.getDebugInfoExtractor();
173349cc55cSDimitry Andric 
174349cc55cSDimitry Andric   // Add the byte size of ULEB that for the abbrev Code so we can start
175349cc55cSDimitry Andric   // skipping the attribute data.
176349cc55cSDimitry Andric   uint64_t Offset = DIEOffset + CodeByteSize;
177349cc55cSDimitry Andric   for (uint32_t CurAttrIdx = 0; CurAttrIdx != AttrIndex; ++CurAttrIdx)
178349cc55cSDimitry Andric     // Match Offset along until we get to the attribute we want.
179349cc55cSDimitry Andric     if (auto FixedSize = AttributeSpecs[CurAttrIdx].getByteSize(U))
180349cc55cSDimitry Andric       Offset += *FixedSize;
181349cc55cSDimitry Andric     else
182349cc55cSDimitry Andric       DWARFFormValue::skipValue(AttributeSpecs[CurAttrIdx].Form, DebugInfoData,
183349cc55cSDimitry Andric                                 &Offset, U.getFormParams());
184349cc55cSDimitry Andric   return Offset;
185349cc55cSDimitry Andric }
186349cc55cSDimitry Andric 
187bdd1243dSDimitry Andric std::optional<DWARFFormValue>
getAttributeValueFromOffset(uint32_t AttrIndex,uint64_t Offset,const DWARFUnit & U) const188349cc55cSDimitry Andric DWARFAbbreviationDeclaration::getAttributeValueFromOffset(
189349cc55cSDimitry Andric     uint32_t AttrIndex, uint64_t Offset, const DWARFUnit &U) const {
190349cc55cSDimitry Andric   assert(AttributeSpecs.size() > AttrIndex &&
191349cc55cSDimitry Andric          "Attribute Index is out of bounds.");
192349cc55cSDimitry Andric 
193349cc55cSDimitry Andric   // We have arrived at the attribute to extract, extract if from Offset.
194349cc55cSDimitry Andric   const AttributeSpec &Spec = AttributeSpecs[AttrIndex];
195349cc55cSDimitry Andric   if (Spec.isImplicitConst())
196349cc55cSDimitry Andric     return DWARFFormValue::createFromSValue(Spec.Form,
197349cc55cSDimitry Andric                                             Spec.getImplicitConstValue());
198349cc55cSDimitry Andric 
199349cc55cSDimitry Andric   DWARFFormValue FormValue(Spec.Form);
200349cc55cSDimitry Andric   DWARFDataExtractor DebugInfoData = U.getDebugInfoExtractor();
201349cc55cSDimitry Andric   if (FormValue.extractValue(DebugInfoData, &Offset, U.getFormParams(), &U))
202349cc55cSDimitry Andric     return FormValue;
203bdd1243dSDimitry Andric   return std::nullopt;
204349cc55cSDimitry Andric }
205349cc55cSDimitry Andric 
206bdd1243dSDimitry Andric std::optional<DWARFFormValue>
getAttributeValue(const uint64_t DIEOffset,const dwarf::Attribute Attr,const DWARFUnit & U) const207349cc55cSDimitry Andric DWARFAbbreviationDeclaration::getAttributeValue(const uint64_t DIEOffset,
208349cc55cSDimitry Andric                                                 const dwarf::Attribute Attr,
2090b57cec5SDimitry Andric                                                 const DWARFUnit &U) const {
2105ffd83dbSDimitry Andric   // Check if this abbreviation has this attribute without needing to skip
2115ffd83dbSDimitry Andric   // any data so we can return quickly if it doesn't.
212bdd1243dSDimitry Andric   std::optional<uint32_t> MatchAttrIndex = findAttributeIndex(Attr);
2130b57cec5SDimitry Andric   if (!MatchAttrIndex)
214bdd1243dSDimitry Andric     return std::nullopt;
2150b57cec5SDimitry Andric 
216349cc55cSDimitry Andric   uint64_t Offset = getAttributeOffsetFromIndex(*MatchAttrIndex, DIEOffset, U);
2170b57cec5SDimitry Andric 
218349cc55cSDimitry Andric   return getAttributeValueFromOffset(*MatchAttrIndex, Offset, U);
2190b57cec5SDimitry Andric }
2200b57cec5SDimitry Andric 
getByteSize(const DWARFUnit & U) const2210b57cec5SDimitry Andric size_t DWARFAbbreviationDeclaration::FixedSizeInfo::getByteSize(
2220b57cec5SDimitry Andric     const DWARFUnit &U) const {
2230b57cec5SDimitry Andric   size_t ByteSize = NumBytes;
2240b57cec5SDimitry Andric   if (NumAddrs)
2250b57cec5SDimitry Andric     ByteSize += NumAddrs * U.getAddressByteSize();
2260b57cec5SDimitry Andric   if (NumRefAddrs)
2270b57cec5SDimitry Andric     ByteSize += NumRefAddrs * U.getRefAddrByteSize();
2280b57cec5SDimitry Andric   if (NumDwarfOffsets)
2290b57cec5SDimitry Andric     ByteSize += NumDwarfOffsets * U.getDwarfOffsetByteSize();
2300b57cec5SDimitry Andric   return ByteSize;
2310b57cec5SDimitry Andric }
2320b57cec5SDimitry Andric 
getByteSize(const DWARFUnit & U) const233bdd1243dSDimitry Andric std::optional<int64_t> DWARFAbbreviationDeclaration::AttributeSpec::getByteSize(
2340b57cec5SDimitry Andric     const DWARFUnit &U) const {
2350b57cec5SDimitry Andric   if (isImplicitConst())
2360b57cec5SDimitry Andric     return 0;
2370b57cec5SDimitry Andric   if (ByteSize.HasByteSize)
2380b57cec5SDimitry Andric     return ByteSize.ByteSize;
239bdd1243dSDimitry Andric   std::optional<int64_t> S;
2400b57cec5SDimitry Andric   auto FixedByteSize = dwarf::getFixedFormByteSize(Form, U.getFormParams());
2410b57cec5SDimitry Andric   if (FixedByteSize)
2420b57cec5SDimitry Andric     S = *FixedByteSize;
2430b57cec5SDimitry Andric   return S;
2440b57cec5SDimitry Andric }
2450b57cec5SDimitry Andric 
getFixedAttributesByteSize(const DWARFUnit & U) const246bdd1243dSDimitry Andric std::optional<size_t> DWARFAbbreviationDeclaration::getFixedAttributesByteSize(
2470b57cec5SDimitry Andric     const DWARFUnit &U) const {
2480b57cec5SDimitry Andric   if (FixedAttributeSize)
2490b57cec5SDimitry Andric     return FixedAttributeSize->getByteSize(U);
250bdd1243dSDimitry Andric   return std::nullopt;
2510b57cec5SDimitry Andric }
252