| //===- DWARFAbbreviationDeclaration.cpp -----------------------------------===// | 
 | // | 
 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
 | // See https://llvm.org/LICENSE.txt for license information. | 
 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" | 
 |  | 
 | #include "llvm/ADT/None.h" | 
 | #include "llvm/ADT/Optional.h" | 
 | #include "llvm/BinaryFormat/Dwarf.h" | 
 | #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" | 
 | #include "llvm/DebugInfo/DWARF/DWARFUnit.h" | 
 | #include "llvm/Support/DataExtractor.h" | 
 | #include "llvm/Support/Format.h" | 
 | #include "llvm/Support/FormatVariadic.h" | 
 | #include "llvm/Support/raw_ostream.h" | 
 | #include <cstddef> | 
 | #include <cstdint> | 
 |  | 
 | using namespace llvm; | 
 | using namespace dwarf; | 
 |  | 
 | void DWARFAbbreviationDeclaration::clear() { | 
 |   Code = 0; | 
 |   Tag = DW_TAG_null; | 
 |   CodeByteSize = 0; | 
 |   HasChildren = false; | 
 |   AttributeSpecs.clear(); | 
 |   FixedAttributeSize.reset(); | 
 | } | 
 |  | 
 | DWARFAbbreviationDeclaration::DWARFAbbreviationDeclaration() { | 
 |   clear(); | 
 | } | 
 |  | 
 | bool | 
 | DWARFAbbreviationDeclaration::extract(DataExtractor Data, | 
 |                                       uint64_t* OffsetPtr) { | 
 |   clear(); | 
 |   const uint64_t Offset = *OffsetPtr; | 
 |   Code = Data.getULEB128(OffsetPtr); | 
 |   if (Code == 0) { | 
 |     return false; | 
 |   } | 
 |   CodeByteSize = *OffsetPtr - Offset; | 
 |   Tag = static_cast<llvm::dwarf::Tag>(Data.getULEB128(OffsetPtr)); | 
 |   if (Tag == DW_TAG_null) { | 
 |     clear(); | 
 |     return false; | 
 |   } | 
 |   uint8_t ChildrenByte = Data.getU8(OffsetPtr); | 
 |   HasChildren = (ChildrenByte == DW_CHILDREN_yes); | 
 |   // Assign a value to our optional FixedAttributeSize member variable. If | 
 |   // this member variable still has a value after the while loop below, then | 
 |   // all attribute data in this abbreviation declaration has a fixed byte size. | 
 |   FixedAttributeSize = FixedSizeInfo(); | 
 |  | 
 |   // Read all of the abbreviation attributes and forms. | 
 |   while (true) { | 
 |     auto A = static_cast<Attribute>(Data.getULEB128(OffsetPtr)); | 
 |     auto F = static_cast<Form>(Data.getULEB128(OffsetPtr)); | 
 |     if (A && F) { | 
 |       bool IsImplicitConst = (F == DW_FORM_implicit_const); | 
 |       if (IsImplicitConst) { | 
 |         int64_t V = Data.getSLEB128(OffsetPtr); | 
 |         AttributeSpecs.push_back(AttributeSpec(A, F, V)); | 
 |         continue; | 
 |       } | 
 |       Optional<uint8_t> ByteSize; | 
 |       // If this abbrevation still has a fixed byte size, then update the | 
 |       // FixedAttributeSize as needed. | 
 |       switch (F) { | 
 |       case DW_FORM_addr: | 
 |         if (FixedAttributeSize) | 
 |           ++FixedAttributeSize->NumAddrs; | 
 |         break; | 
 |  | 
 |       case DW_FORM_ref_addr: | 
 |         if (FixedAttributeSize) | 
 |           ++FixedAttributeSize->NumRefAddrs; | 
 |         break; | 
 |  | 
 |       case DW_FORM_strp: | 
 |       case DW_FORM_GNU_ref_alt: | 
 |       case DW_FORM_GNU_strp_alt: | 
 |       case DW_FORM_line_strp: | 
 |       case DW_FORM_sec_offset: | 
 |       case DW_FORM_strp_sup: | 
 |         if (FixedAttributeSize) | 
 |           ++FixedAttributeSize->NumDwarfOffsets; | 
 |         break; | 
 |  | 
 |       default: | 
 |         // The form has a byte size that doesn't depend on Params. | 
 |         // If it's a fixed size, keep track of it. | 
 |         if ((ByteSize = dwarf::getFixedFormByteSize(F, dwarf::FormParams()))) { | 
 |           if (FixedAttributeSize) | 
 |             FixedAttributeSize->NumBytes += *ByteSize; | 
 |           break; | 
 |         } | 
 |         // Indicate we no longer have a fixed byte size for this | 
 |         // abbreviation by clearing the FixedAttributeSize optional value | 
 |         // so it doesn't have a value. | 
 |         FixedAttributeSize.reset(); | 
 |         break; | 
 |       } | 
 |       // Record this attribute and its fixed size if it has one. | 
 |       AttributeSpecs.push_back(AttributeSpec(A, F, ByteSize)); | 
 |     } else if (A == 0 && F == 0) { | 
 |       // We successfully reached the end of this abbreviation declaration | 
 |       // since both attribute and form are zero. | 
 |       break; | 
 |     } else { | 
 |       // Attribute and form pairs must either both be non-zero, in which case | 
 |       // they are added to the abbreviation declaration, or both be zero to | 
 |       // terminate the abbrevation declaration. In this case only one was | 
 |       // zero which is an error. | 
 |       clear(); | 
 |       return false; | 
 |     } | 
 |   } | 
 |   return true; | 
 | } | 
 |  | 
 | void DWARFAbbreviationDeclaration::dump(raw_ostream &OS) const { | 
 |   OS << '[' << getCode() << "] "; | 
 |   OS << formatv("{0}", getTag()); | 
 |   OS << "\tDW_CHILDREN_" << (hasChildren() ? "yes" : "no") << '\n'; | 
 |   for (const AttributeSpec &Spec : AttributeSpecs) { | 
 |     OS << formatv("\t{0}\t{1}", Spec.Attr, Spec.Form); | 
 |     if (Spec.isImplicitConst()) | 
 |       OS << '\t' << Spec.getImplicitConstValue(); | 
 |     OS << '\n'; | 
 |   } | 
 |   OS << '\n'; | 
 | } | 
 |  | 
 | Optional<uint32_t> | 
 | DWARFAbbreviationDeclaration::findAttributeIndex(dwarf::Attribute Attr) const { | 
 |   for (uint32_t i = 0, e = AttributeSpecs.size(); i != e; ++i) { | 
 |     if (AttributeSpecs[i].Attr == Attr) | 
 |       return i; | 
 |   } | 
 |   return None; | 
 | } | 
 |  | 
 | Optional<DWARFFormValue> DWARFAbbreviationDeclaration::getAttributeValue( | 
 |     const uint64_t DIEOffset, const dwarf::Attribute Attr, | 
 |     const DWARFUnit &U) const { | 
 |   // Check if this abbreviation has this attribute without needing to skip | 
 |   // any data so we can return quickly if it doesn't. | 
 |   Optional<uint32_t> MatchAttrIndex = findAttributeIndex(Attr); | 
 |   if (!MatchAttrIndex) | 
 |     return None; | 
 |  | 
 |   auto DebugInfoData = U.getDebugInfoExtractor(); | 
 |  | 
 |   // Add the byte size of ULEB that for the abbrev Code so we can start | 
 |   // skipping the attribute data. | 
 |   uint64_t Offset = DIEOffset + CodeByteSize; | 
 |   for (uint32_t CurAttrIdx = 0; CurAttrIdx != *MatchAttrIndex; ++CurAttrIdx) | 
 |     // Match Offset along until we get to the attribute we want. | 
 |     if (auto FixedSize = AttributeSpecs[CurAttrIdx].getByteSize(U)) | 
 |       Offset += *FixedSize; | 
 |     else | 
 |       DWARFFormValue::skipValue(AttributeSpecs[CurAttrIdx].Form, DebugInfoData, | 
 |                                 &Offset, U.getFormParams()); | 
 |  | 
 |   // We have arrived at the attribute to extract, extract if from Offset. | 
 |   const AttributeSpec &Spec = AttributeSpecs[*MatchAttrIndex]; | 
 |   if (Spec.isImplicitConst()) | 
 |     return DWARFFormValue::createFromSValue(Spec.Form, | 
 |                                             Spec.getImplicitConstValue()); | 
 |  | 
 |   DWARFFormValue FormValue(Spec.Form); | 
 |   if (FormValue.extractValue(DebugInfoData, &Offset, U.getFormParams(), &U)) | 
 |     return FormValue; | 
 |  | 
 |   return None; | 
 | } | 
 |  | 
 | size_t DWARFAbbreviationDeclaration::FixedSizeInfo::getByteSize( | 
 |     const DWARFUnit &U) const { | 
 |   size_t ByteSize = NumBytes; | 
 |   if (NumAddrs) | 
 |     ByteSize += NumAddrs * U.getAddressByteSize(); | 
 |   if (NumRefAddrs) | 
 |     ByteSize += NumRefAddrs * U.getRefAddrByteSize(); | 
 |   if (NumDwarfOffsets) | 
 |     ByteSize += NumDwarfOffsets * U.getDwarfOffsetByteSize(); | 
 |   return ByteSize; | 
 | } | 
 |  | 
 | Optional<int64_t> DWARFAbbreviationDeclaration::AttributeSpec::getByteSize( | 
 |     const DWARFUnit &U) const { | 
 |   if (isImplicitConst()) | 
 |     return 0; | 
 |   if (ByteSize.HasByteSize) | 
 |     return ByteSize.ByteSize; | 
 |   Optional<int64_t> S; | 
 |   auto FixedByteSize = dwarf::getFixedFormByteSize(Form, U.getFormParams()); | 
 |   if (FixedByteSize) | 
 |     S = *FixedByteSize; | 
 |   return S; | 
 | } | 
 |  | 
 | Optional<size_t> DWARFAbbreviationDeclaration::getFixedAttributesByteSize( | 
 |     const DWARFUnit &U) const { | 
 |   if (FixedAttributeSize) | 
 |     return FixedAttributeSize->getByteSize(U); | 
 |   return None; | 
 | } |