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