xref: /freebsd/contrib/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp (revision 349cc55c9796c4596a5b9904cd3281af295f878f)
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/ADT/None.h"
120b57cec5SDimitry Andric #include "llvm/ADT/Optional.h"
130b57cec5SDimitry Andric #include "llvm/BinaryFormat/Dwarf.h"
140b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
150b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFUnit.h"
160b57cec5SDimitry Andric #include "llvm/Support/DataExtractor.h"
170b57cec5SDimitry Andric #include "llvm/Support/Format.h"
180b57cec5SDimitry Andric #include "llvm/Support/FormatVariadic.h"
190b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
200b57cec5SDimitry Andric #include <cstddef>
210b57cec5SDimitry Andric #include <cstdint>
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric using namespace llvm;
240b57cec5SDimitry Andric using namespace dwarf;
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric void DWARFAbbreviationDeclaration::clear() {
270b57cec5SDimitry Andric   Code = 0;
280b57cec5SDimitry Andric   Tag = DW_TAG_null;
290b57cec5SDimitry Andric   CodeByteSize = 0;
300b57cec5SDimitry Andric   HasChildren = false;
310b57cec5SDimitry Andric   AttributeSpecs.clear();
320b57cec5SDimitry Andric   FixedAttributeSize.reset();
330b57cec5SDimitry Andric }
340b57cec5SDimitry Andric 
350b57cec5SDimitry Andric DWARFAbbreviationDeclaration::DWARFAbbreviationDeclaration() {
360b57cec5SDimitry Andric   clear();
370b57cec5SDimitry Andric }
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric bool
400b57cec5SDimitry Andric DWARFAbbreviationDeclaration::extract(DataExtractor Data,
418bcb0991SDimitry Andric                                       uint64_t* OffsetPtr) {
420b57cec5SDimitry Andric   clear();
438bcb0991SDimitry Andric   const uint64_t Offset = *OffsetPtr;
440b57cec5SDimitry Andric   Code = Data.getULEB128(OffsetPtr);
450b57cec5SDimitry Andric   if (Code == 0) {
460b57cec5SDimitry Andric     return false;
470b57cec5SDimitry Andric   }
480b57cec5SDimitry Andric   CodeByteSize = *OffsetPtr - Offset;
490b57cec5SDimitry Andric   Tag = static_cast<llvm::dwarf::Tag>(Data.getULEB128(OffsetPtr));
500b57cec5SDimitry Andric   if (Tag == DW_TAG_null) {
510b57cec5SDimitry Andric     clear();
520b57cec5SDimitry Andric     return false;
530b57cec5SDimitry Andric   }
540b57cec5SDimitry Andric   uint8_t ChildrenByte = Data.getU8(OffsetPtr);
550b57cec5SDimitry Andric   HasChildren = (ChildrenByte == DW_CHILDREN_yes);
560b57cec5SDimitry Andric   // Assign a value to our optional FixedAttributeSize member variable. If
570b57cec5SDimitry Andric   // this member variable still has a value after the while loop below, then
580b57cec5SDimitry Andric   // all attribute data in this abbreviation declaration has a fixed byte size.
590b57cec5SDimitry Andric   FixedAttributeSize = FixedSizeInfo();
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric   // Read all of the abbreviation attributes and forms.
620b57cec5SDimitry Andric   while (true) {
630b57cec5SDimitry Andric     auto A = static_cast<Attribute>(Data.getULEB128(OffsetPtr));
640b57cec5SDimitry Andric     auto F = static_cast<Form>(Data.getULEB128(OffsetPtr));
650b57cec5SDimitry Andric     if (A && F) {
660b57cec5SDimitry Andric       bool IsImplicitConst = (F == DW_FORM_implicit_const);
670b57cec5SDimitry Andric       if (IsImplicitConst) {
680b57cec5SDimitry Andric         int64_t V = Data.getSLEB128(OffsetPtr);
690b57cec5SDimitry Andric         AttributeSpecs.push_back(AttributeSpec(A, F, V));
700b57cec5SDimitry Andric         continue;
710b57cec5SDimitry Andric       }
720b57cec5SDimitry Andric       Optional<uint8_t> ByteSize;
730b57cec5SDimitry Andric       // If this abbrevation still has a fixed byte size, then update the
740b57cec5SDimitry Andric       // FixedAttributeSize as needed.
750b57cec5SDimitry Andric       switch (F) {
760b57cec5SDimitry Andric       case DW_FORM_addr:
770b57cec5SDimitry Andric         if (FixedAttributeSize)
780b57cec5SDimitry Andric           ++FixedAttributeSize->NumAddrs;
790b57cec5SDimitry Andric         break;
800b57cec5SDimitry Andric 
810b57cec5SDimitry Andric       case DW_FORM_ref_addr:
820b57cec5SDimitry Andric         if (FixedAttributeSize)
830b57cec5SDimitry Andric           ++FixedAttributeSize->NumRefAddrs;
840b57cec5SDimitry Andric         break;
850b57cec5SDimitry Andric 
860b57cec5SDimitry Andric       case DW_FORM_strp:
870b57cec5SDimitry Andric       case DW_FORM_GNU_ref_alt:
880b57cec5SDimitry Andric       case DW_FORM_GNU_strp_alt:
890b57cec5SDimitry Andric       case DW_FORM_line_strp:
900b57cec5SDimitry Andric       case DW_FORM_sec_offset:
910b57cec5SDimitry Andric       case DW_FORM_strp_sup:
920b57cec5SDimitry Andric         if (FixedAttributeSize)
930b57cec5SDimitry Andric           ++FixedAttributeSize->NumDwarfOffsets;
940b57cec5SDimitry Andric         break;
950b57cec5SDimitry Andric 
960b57cec5SDimitry Andric       default:
970b57cec5SDimitry Andric         // The form has a byte size that doesn't depend on Params.
980b57cec5SDimitry Andric         // If it's a fixed size, keep track of it.
990b57cec5SDimitry Andric         if ((ByteSize = dwarf::getFixedFormByteSize(F, dwarf::FormParams()))) {
1000b57cec5SDimitry Andric           if (FixedAttributeSize)
1010b57cec5SDimitry Andric             FixedAttributeSize->NumBytes += *ByteSize;
1020b57cec5SDimitry Andric           break;
1030b57cec5SDimitry Andric         }
1040b57cec5SDimitry Andric         // Indicate we no longer have a fixed byte size for this
1050b57cec5SDimitry Andric         // abbreviation by clearing the FixedAttributeSize optional value
1060b57cec5SDimitry Andric         // so it doesn't have a value.
1070b57cec5SDimitry Andric         FixedAttributeSize.reset();
1080b57cec5SDimitry Andric         break;
1090b57cec5SDimitry Andric       }
1100b57cec5SDimitry Andric       // Record this attribute and its fixed size if it has one.
1110b57cec5SDimitry Andric       AttributeSpecs.push_back(AttributeSpec(A, F, ByteSize));
1120b57cec5SDimitry Andric     } else if (A == 0 && F == 0) {
1130b57cec5SDimitry Andric       // We successfully reached the end of this abbreviation declaration
1140b57cec5SDimitry Andric       // since both attribute and form are zero.
1150b57cec5SDimitry Andric       break;
1160b57cec5SDimitry Andric     } else {
1170b57cec5SDimitry Andric       // Attribute and form pairs must either both be non-zero, in which case
1180b57cec5SDimitry Andric       // they are added to the abbreviation declaration, or both be zero to
1190b57cec5SDimitry Andric       // terminate the abbrevation declaration. In this case only one was
1200b57cec5SDimitry Andric       // zero which is an error.
1210b57cec5SDimitry Andric       clear();
1220b57cec5SDimitry Andric       return false;
1230b57cec5SDimitry Andric     }
1240b57cec5SDimitry Andric   }
1250b57cec5SDimitry Andric   return true;
1260b57cec5SDimitry Andric }
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric void DWARFAbbreviationDeclaration::dump(raw_ostream &OS) const {
1290b57cec5SDimitry Andric   OS << '[' << getCode() << "] ";
1300b57cec5SDimitry Andric   OS << formatv("{0}", getTag());
1310b57cec5SDimitry Andric   OS << "\tDW_CHILDREN_" << (hasChildren() ? "yes" : "no") << '\n';
1320b57cec5SDimitry Andric   for (const AttributeSpec &Spec : AttributeSpecs) {
1330b57cec5SDimitry Andric     OS << formatv("\t{0}\t{1}", Spec.Attr, Spec.Form);
1340b57cec5SDimitry Andric     if (Spec.isImplicitConst())
1350b57cec5SDimitry Andric       OS << '\t' << Spec.getImplicitConstValue();
1360b57cec5SDimitry Andric     OS << '\n';
1370b57cec5SDimitry Andric   }
1380b57cec5SDimitry Andric   OS << '\n';
1390b57cec5SDimitry Andric }
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric Optional<uint32_t>
1420b57cec5SDimitry Andric DWARFAbbreviationDeclaration::findAttributeIndex(dwarf::Attribute Attr) const {
1430b57cec5SDimitry Andric   for (uint32_t i = 0, e = AttributeSpecs.size(); i != e; ++i) {
1440b57cec5SDimitry Andric     if (AttributeSpecs[i].Attr == Attr)
1450b57cec5SDimitry Andric       return i;
1460b57cec5SDimitry Andric   }
1470b57cec5SDimitry Andric   return None;
1480b57cec5SDimitry Andric }
1490b57cec5SDimitry Andric 
150*349cc55cSDimitry Andric uint64_t DWARFAbbreviationDeclaration::getAttributeOffsetFromIndex(
151*349cc55cSDimitry Andric     uint32_t AttrIndex, uint64_t DIEOffset, const DWARFUnit &U) const {
152*349cc55cSDimitry Andric   DWARFDataExtractor DebugInfoData = U.getDebugInfoExtractor();
153*349cc55cSDimitry Andric 
154*349cc55cSDimitry Andric   // Add the byte size of ULEB that for the abbrev Code so we can start
155*349cc55cSDimitry Andric   // skipping the attribute data.
156*349cc55cSDimitry Andric   uint64_t Offset = DIEOffset + CodeByteSize;
157*349cc55cSDimitry Andric   for (uint32_t CurAttrIdx = 0; CurAttrIdx != AttrIndex; ++CurAttrIdx)
158*349cc55cSDimitry Andric     // Match Offset along until we get to the attribute we want.
159*349cc55cSDimitry Andric     if (auto FixedSize = AttributeSpecs[CurAttrIdx].getByteSize(U))
160*349cc55cSDimitry Andric       Offset += *FixedSize;
161*349cc55cSDimitry Andric     else
162*349cc55cSDimitry Andric       DWARFFormValue::skipValue(AttributeSpecs[CurAttrIdx].Form, DebugInfoData,
163*349cc55cSDimitry Andric                                 &Offset, U.getFormParams());
164*349cc55cSDimitry Andric   return Offset;
165*349cc55cSDimitry Andric }
166*349cc55cSDimitry Andric 
167*349cc55cSDimitry Andric Optional<DWARFFormValue>
168*349cc55cSDimitry Andric DWARFAbbreviationDeclaration::getAttributeValueFromOffset(
169*349cc55cSDimitry Andric     uint32_t AttrIndex, uint64_t Offset, const DWARFUnit &U) const {
170*349cc55cSDimitry Andric   assert(AttributeSpecs.size() > AttrIndex &&
171*349cc55cSDimitry Andric          "Attribute Index is out of bounds.");
172*349cc55cSDimitry Andric 
173*349cc55cSDimitry Andric   // We have arrived at the attribute to extract, extract if from Offset.
174*349cc55cSDimitry Andric   const AttributeSpec &Spec = AttributeSpecs[AttrIndex];
175*349cc55cSDimitry Andric   if (Spec.isImplicitConst())
176*349cc55cSDimitry Andric     return DWARFFormValue::createFromSValue(Spec.Form,
177*349cc55cSDimitry Andric                                             Spec.getImplicitConstValue());
178*349cc55cSDimitry Andric 
179*349cc55cSDimitry Andric   DWARFFormValue FormValue(Spec.Form);
180*349cc55cSDimitry Andric   DWARFDataExtractor DebugInfoData = U.getDebugInfoExtractor();
181*349cc55cSDimitry Andric   if (FormValue.extractValue(DebugInfoData, &Offset, U.getFormParams(), &U))
182*349cc55cSDimitry Andric     return FormValue;
183*349cc55cSDimitry Andric   return None;
184*349cc55cSDimitry Andric }
185*349cc55cSDimitry Andric 
186*349cc55cSDimitry Andric Optional<DWARFFormValue>
187*349cc55cSDimitry Andric DWARFAbbreviationDeclaration::getAttributeValue(const uint64_t DIEOffset,
188*349cc55cSDimitry Andric                                                 const dwarf::Attribute Attr,
1890b57cec5SDimitry Andric                                                 const DWARFUnit &U) const {
1905ffd83dbSDimitry Andric   // Check if this abbreviation has this attribute without needing to skip
1915ffd83dbSDimitry Andric   // any data so we can return quickly if it doesn't.
1920b57cec5SDimitry Andric   Optional<uint32_t> MatchAttrIndex = findAttributeIndex(Attr);
1930b57cec5SDimitry Andric   if (!MatchAttrIndex)
1940b57cec5SDimitry Andric     return None;
1950b57cec5SDimitry Andric 
196*349cc55cSDimitry Andric   uint64_t Offset = getAttributeOffsetFromIndex(*MatchAttrIndex, DIEOffset, U);
1970b57cec5SDimitry Andric 
198*349cc55cSDimitry Andric   return getAttributeValueFromOffset(*MatchAttrIndex, Offset, U);
1990b57cec5SDimitry Andric }
2000b57cec5SDimitry Andric 
2010b57cec5SDimitry Andric size_t DWARFAbbreviationDeclaration::FixedSizeInfo::getByteSize(
2020b57cec5SDimitry Andric     const DWARFUnit &U) const {
2030b57cec5SDimitry Andric   size_t ByteSize = NumBytes;
2040b57cec5SDimitry Andric   if (NumAddrs)
2050b57cec5SDimitry Andric     ByteSize += NumAddrs * U.getAddressByteSize();
2060b57cec5SDimitry Andric   if (NumRefAddrs)
2070b57cec5SDimitry Andric     ByteSize += NumRefAddrs * U.getRefAddrByteSize();
2080b57cec5SDimitry Andric   if (NumDwarfOffsets)
2090b57cec5SDimitry Andric     ByteSize += NumDwarfOffsets * U.getDwarfOffsetByteSize();
2100b57cec5SDimitry Andric   return ByteSize;
2110b57cec5SDimitry Andric }
2120b57cec5SDimitry Andric 
2130b57cec5SDimitry Andric Optional<int64_t> DWARFAbbreviationDeclaration::AttributeSpec::getByteSize(
2140b57cec5SDimitry Andric     const DWARFUnit &U) const {
2150b57cec5SDimitry Andric   if (isImplicitConst())
2160b57cec5SDimitry Andric     return 0;
2170b57cec5SDimitry Andric   if (ByteSize.HasByteSize)
2180b57cec5SDimitry Andric     return ByteSize.ByteSize;
2190b57cec5SDimitry Andric   Optional<int64_t> S;
2200b57cec5SDimitry Andric   auto FixedByteSize = dwarf::getFixedFormByteSize(Form, U.getFormParams());
2210b57cec5SDimitry Andric   if (FixedByteSize)
2220b57cec5SDimitry Andric     S = *FixedByteSize;
2230b57cec5SDimitry Andric   return S;
2240b57cec5SDimitry Andric }
2250b57cec5SDimitry Andric 
2260b57cec5SDimitry Andric Optional<size_t> DWARFAbbreviationDeclaration::getFixedAttributesByteSize(
2270b57cec5SDimitry Andric     const DWARFUnit &U) const {
2280b57cec5SDimitry Andric   if (FixedAttributeSize)
2290b57cec5SDimitry Andric     return FixedAttributeSize->getByteSize(U);
2300b57cec5SDimitry Andric   return None;
2310b57cec5SDimitry Andric }
232