xref: /freebsd/contrib/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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 
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 
330b57cec5SDimitry Andric DWARFAbbreviationDeclaration::DWARFAbbreviationDeclaration() {
340b57cec5SDimitry Andric   clear();
350b57cec5SDimitry Andric }
360b57cec5SDimitry Andric 
370b57cec5SDimitry Andric bool
380b57cec5SDimitry Andric DWARFAbbreviationDeclaration::extract(DataExtractor Data,
398bcb0991SDimitry Andric                                       uint64_t* OffsetPtr) {
400b57cec5SDimitry Andric   clear();
418bcb0991SDimitry Andric   const uint64_t Offset = *OffsetPtr;
420b57cec5SDimitry Andric   Code = Data.getULEB128(OffsetPtr);
430b57cec5SDimitry Andric   if (Code == 0) {
440b57cec5SDimitry Andric     return false;
450b57cec5SDimitry Andric   }
460b57cec5SDimitry Andric   CodeByteSize = *OffsetPtr - Offset;
470b57cec5SDimitry Andric   Tag = static_cast<llvm::dwarf::Tag>(Data.getULEB128(OffsetPtr));
480b57cec5SDimitry Andric   if (Tag == DW_TAG_null) {
490b57cec5SDimitry Andric     clear();
500b57cec5SDimitry Andric     return false;
510b57cec5SDimitry Andric   }
520b57cec5SDimitry Andric   uint8_t ChildrenByte = Data.getU8(OffsetPtr);
530b57cec5SDimitry Andric   HasChildren = (ChildrenByte == DW_CHILDREN_yes);
540b57cec5SDimitry Andric   // Assign a value to our optional FixedAttributeSize member variable. If
550b57cec5SDimitry Andric   // this member variable still has a value after the while loop below, then
560b57cec5SDimitry Andric   // all attribute data in this abbreviation declaration has a fixed byte size.
570b57cec5SDimitry Andric   FixedAttributeSize = FixedSizeInfo();
580b57cec5SDimitry Andric 
590b57cec5SDimitry Andric   // Read all of the abbreviation attributes and forms.
600b57cec5SDimitry Andric   while (true) {
610b57cec5SDimitry Andric     auto A = static_cast<Attribute>(Data.getULEB128(OffsetPtr));
620b57cec5SDimitry Andric     auto F = static_cast<Form>(Data.getULEB128(OffsetPtr));
630b57cec5SDimitry Andric     if (A && F) {
640b57cec5SDimitry Andric       bool IsImplicitConst = (F == DW_FORM_implicit_const);
650b57cec5SDimitry Andric       if (IsImplicitConst) {
660b57cec5SDimitry Andric         int64_t V = Data.getSLEB128(OffsetPtr);
670b57cec5SDimitry Andric         AttributeSpecs.push_back(AttributeSpec(A, F, V));
680b57cec5SDimitry Andric         continue;
690b57cec5SDimitry Andric       }
70*bdd1243dSDimitry Andric       std::optional<uint8_t> ByteSize;
710b57cec5SDimitry Andric       // If this abbrevation still has a fixed byte size, then update the
720b57cec5SDimitry Andric       // FixedAttributeSize as needed.
730b57cec5SDimitry Andric       switch (F) {
740b57cec5SDimitry Andric       case DW_FORM_addr:
750b57cec5SDimitry Andric         if (FixedAttributeSize)
760b57cec5SDimitry Andric           ++FixedAttributeSize->NumAddrs;
770b57cec5SDimitry Andric         break;
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric       case DW_FORM_ref_addr:
800b57cec5SDimitry Andric         if (FixedAttributeSize)
810b57cec5SDimitry Andric           ++FixedAttributeSize->NumRefAddrs;
820b57cec5SDimitry Andric         break;
830b57cec5SDimitry Andric 
840b57cec5SDimitry Andric       case DW_FORM_strp:
850b57cec5SDimitry Andric       case DW_FORM_GNU_ref_alt:
860b57cec5SDimitry Andric       case DW_FORM_GNU_strp_alt:
870b57cec5SDimitry Andric       case DW_FORM_line_strp:
880b57cec5SDimitry Andric       case DW_FORM_sec_offset:
890b57cec5SDimitry Andric       case DW_FORM_strp_sup:
900b57cec5SDimitry Andric         if (FixedAttributeSize)
910b57cec5SDimitry Andric           ++FixedAttributeSize->NumDwarfOffsets;
920b57cec5SDimitry Andric         break;
930b57cec5SDimitry Andric 
940b57cec5SDimitry Andric       default:
950b57cec5SDimitry Andric         // The form has a byte size that doesn't depend on Params.
960b57cec5SDimitry Andric         // If it's a fixed size, keep track of it.
970b57cec5SDimitry Andric         if ((ByteSize = dwarf::getFixedFormByteSize(F, dwarf::FormParams()))) {
980b57cec5SDimitry Andric           if (FixedAttributeSize)
990b57cec5SDimitry Andric             FixedAttributeSize->NumBytes += *ByteSize;
1000b57cec5SDimitry Andric           break;
1010b57cec5SDimitry Andric         }
1020b57cec5SDimitry Andric         // Indicate we no longer have a fixed byte size for this
1030b57cec5SDimitry Andric         // abbreviation by clearing the FixedAttributeSize optional value
1040b57cec5SDimitry Andric         // so it doesn't have a value.
1050b57cec5SDimitry Andric         FixedAttributeSize.reset();
1060b57cec5SDimitry Andric         break;
1070b57cec5SDimitry Andric       }
1080b57cec5SDimitry Andric       // Record this attribute and its fixed size if it has one.
1090b57cec5SDimitry Andric       AttributeSpecs.push_back(AttributeSpec(A, F, ByteSize));
1100b57cec5SDimitry Andric     } else if (A == 0 && F == 0) {
1110b57cec5SDimitry Andric       // We successfully reached the end of this abbreviation declaration
1120b57cec5SDimitry Andric       // since both attribute and form are zero.
1130b57cec5SDimitry Andric       break;
1140b57cec5SDimitry Andric     } else {
1150b57cec5SDimitry Andric       // Attribute and form pairs must either both be non-zero, in which case
1160b57cec5SDimitry Andric       // they are added to the abbreviation declaration, or both be zero to
1170b57cec5SDimitry Andric       // terminate the abbrevation declaration. In this case only one was
1180b57cec5SDimitry Andric       // zero which is an error.
1190b57cec5SDimitry Andric       clear();
1200b57cec5SDimitry Andric       return false;
1210b57cec5SDimitry Andric     }
1220b57cec5SDimitry Andric   }
1230b57cec5SDimitry Andric   return true;
1240b57cec5SDimitry Andric }
1250b57cec5SDimitry Andric 
1260b57cec5SDimitry Andric void DWARFAbbreviationDeclaration::dump(raw_ostream &OS) const {
1270b57cec5SDimitry Andric   OS << '[' << getCode() << "] ";
1280b57cec5SDimitry Andric   OS << formatv("{0}", getTag());
1290b57cec5SDimitry Andric   OS << "\tDW_CHILDREN_" << (hasChildren() ? "yes" : "no") << '\n';
1300b57cec5SDimitry Andric   for (const AttributeSpec &Spec : AttributeSpecs) {
1310b57cec5SDimitry Andric     OS << formatv("\t{0}\t{1}", Spec.Attr, Spec.Form);
1320b57cec5SDimitry Andric     if (Spec.isImplicitConst())
1330b57cec5SDimitry Andric       OS << '\t' << Spec.getImplicitConstValue();
1340b57cec5SDimitry Andric     OS << '\n';
1350b57cec5SDimitry Andric   }
1360b57cec5SDimitry Andric   OS << '\n';
1370b57cec5SDimitry Andric }
1380b57cec5SDimitry Andric 
139*bdd1243dSDimitry Andric std::optional<uint32_t>
1400b57cec5SDimitry Andric DWARFAbbreviationDeclaration::findAttributeIndex(dwarf::Attribute Attr) const {
1410b57cec5SDimitry Andric   for (uint32_t i = 0, e = AttributeSpecs.size(); i != e; ++i) {
1420b57cec5SDimitry Andric     if (AttributeSpecs[i].Attr == Attr)
1430b57cec5SDimitry Andric       return i;
1440b57cec5SDimitry Andric   }
145*bdd1243dSDimitry Andric   return std::nullopt;
1460b57cec5SDimitry Andric }
1470b57cec5SDimitry Andric 
148349cc55cSDimitry Andric uint64_t DWARFAbbreviationDeclaration::getAttributeOffsetFromIndex(
149349cc55cSDimitry Andric     uint32_t AttrIndex, uint64_t DIEOffset, const DWARFUnit &U) const {
150349cc55cSDimitry Andric   DWARFDataExtractor DebugInfoData = U.getDebugInfoExtractor();
151349cc55cSDimitry Andric 
152349cc55cSDimitry Andric   // Add the byte size of ULEB that for the abbrev Code so we can start
153349cc55cSDimitry Andric   // skipping the attribute data.
154349cc55cSDimitry Andric   uint64_t Offset = DIEOffset + CodeByteSize;
155349cc55cSDimitry Andric   for (uint32_t CurAttrIdx = 0; CurAttrIdx != AttrIndex; ++CurAttrIdx)
156349cc55cSDimitry Andric     // Match Offset along until we get to the attribute we want.
157349cc55cSDimitry Andric     if (auto FixedSize = AttributeSpecs[CurAttrIdx].getByteSize(U))
158349cc55cSDimitry Andric       Offset += *FixedSize;
159349cc55cSDimitry Andric     else
160349cc55cSDimitry Andric       DWARFFormValue::skipValue(AttributeSpecs[CurAttrIdx].Form, DebugInfoData,
161349cc55cSDimitry Andric                                 &Offset, U.getFormParams());
162349cc55cSDimitry Andric   return Offset;
163349cc55cSDimitry Andric }
164349cc55cSDimitry Andric 
165*bdd1243dSDimitry Andric std::optional<DWARFFormValue>
166349cc55cSDimitry Andric DWARFAbbreviationDeclaration::getAttributeValueFromOffset(
167349cc55cSDimitry Andric     uint32_t AttrIndex, uint64_t Offset, const DWARFUnit &U) const {
168349cc55cSDimitry Andric   assert(AttributeSpecs.size() > AttrIndex &&
169349cc55cSDimitry Andric          "Attribute Index is out of bounds.");
170349cc55cSDimitry Andric 
171349cc55cSDimitry Andric   // We have arrived at the attribute to extract, extract if from Offset.
172349cc55cSDimitry Andric   const AttributeSpec &Spec = AttributeSpecs[AttrIndex];
173349cc55cSDimitry Andric   if (Spec.isImplicitConst())
174349cc55cSDimitry Andric     return DWARFFormValue::createFromSValue(Spec.Form,
175349cc55cSDimitry Andric                                             Spec.getImplicitConstValue());
176349cc55cSDimitry Andric 
177349cc55cSDimitry Andric   DWARFFormValue FormValue(Spec.Form);
178349cc55cSDimitry Andric   DWARFDataExtractor DebugInfoData = U.getDebugInfoExtractor();
179349cc55cSDimitry Andric   if (FormValue.extractValue(DebugInfoData, &Offset, U.getFormParams(), &U))
180349cc55cSDimitry Andric     return FormValue;
181*bdd1243dSDimitry Andric   return std::nullopt;
182349cc55cSDimitry Andric }
183349cc55cSDimitry Andric 
184*bdd1243dSDimitry Andric std::optional<DWARFFormValue>
185349cc55cSDimitry Andric DWARFAbbreviationDeclaration::getAttributeValue(const uint64_t DIEOffset,
186349cc55cSDimitry Andric                                                 const dwarf::Attribute Attr,
1870b57cec5SDimitry Andric                                                 const DWARFUnit &U) const {
1885ffd83dbSDimitry Andric   // Check if this abbreviation has this attribute without needing to skip
1895ffd83dbSDimitry Andric   // any data so we can return quickly if it doesn't.
190*bdd1243dSDimitry Andric   std::optional<uint32_t> MatchAttrIndex = findAttributeIndex(Attr);
1910b57cec5SDimitry Andric   if (!MatchAttrIndex)
192*bdd1243dSDimitry Andric     return std::nullopt;
1930b57cec5SDimitry Andric 
194349cc55cSDimitry Andric   uint64_t Offset = getAttributeOffsetFromIndex(*MatchAttrIndex, DIEOffset, U);
1950b57cec5SDimitry Andric 
196349cc55cSDimitry Andric   return getAttributeValueFromOffset(*MatchAttrIndex, Offset, U);
1970b57cec5SDimitry Andric }
1980b57cec5SDimitry Andric 
1990b57cec5SDimitry Andric size_t DWARFAbbreviationDeclaration::FixedSizeInfo::getByteSize(
2000b57cec5SDimitry Andric     const DWARFUnit &U) const {
2010b57cec5SDimitry Andric   size_t ByteSize = NumBytes;
2020b57cec5SDimitry Andric   if (NumAddrs)
2030b57cec5SDimitry Andric     ByteSize += NumAddrs * U.getAddressByteSize();
2040b57cec5SDimitry Andric   if (NumRefAddrs)
2050b57cec5SDimitry Andric     ByteSize += NumRefAddrs * U.getRefAddrByteSize();
2060b57cec5SDimitry Andric   if (NumDwarfOffsets)
2070b57cec5SDimitry Andric     ByteSize += NumDwarfOffsets * U.getDwarfOffsetByteSize();
2080b57cec5SDimitry Andric   return ByteSize;
2090b57cec5SDimitry Andric }
2100b57cec5SDimitry Andric 
211*bdd1243dSDimitry Andric std::optional<int64_t> DWARFAbbreviationDeclaration::AttributeSpec::getByteSize(
2120b57cec5SDimitry Andric     const DWARFUnit &U) const {
2130b57cec5SDimitry Andric   if (isImplicitConst())
2140b57cec5SDimitry Andric     return 0;
2150b57cec5SDimitry Andric   if (ByteSize.HasByteSize)
2160b57cec5SDimitry Andric     return ByteSize.ByteSize;
217*bdd1243dSDimitry Andric   std::optional<int64_t> S;
2180b57cec5SDimitry Andric   auto FixedByteSize = dwarf::getFixedFormByteSize(Form, U.getFormParams());
2190b57cec5SDimitry Andric   if (FixedByteSize)
2200b57cec5SDimitry Andric     S = *FixedByteSize;
2210b57cec5SDimitry Andric   return S;
2220b57cec5SDimitry Andric }
2230b57cec5SDimitry Andric 
224*bdd1243dSDimitry Andric std::optional<size_t> DWARFAbbreviationDeclaration::getFixedAttributesByteSize(
2250b57cec5SDimitry Andric     const DWARFUnit &U) const {
2260b57cec5SDimitry Andric   if (FixedAttributeSize)
2270b57cec5SDimitry Andric     return FixedAttributeSize->getByteSize(U);
228*bdd1243dSDimitry Andric   return std::nullopt;
2290b57cec5SDimitry Andric }
230