|  | //===- 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, | 
|  | uint32_t* OffsetPtr) { | 
|  | clear(); | 
|  | const uint32_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 uint32_t DIEOffset, const dwarf::Attribute Attr, | 
|  | const DWARFUnit &U) const { | 
|  | 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. | 
|  | uint32_t Offset = DIEOffset + CodeByteSize; | 
|  | uint32_t AttrIndex = 0; | 
|  | for (const auto &Spec : AttributeSpecs) { | 
|  | if (*MatchAttrIndex == AttrIndex) { | 
|  | // We have arrived at the attribute to extract, extract if from Offset. | 
|  | if (Spec.isImplicitConst()) | 
|  | return DWARFFormValue::createFromSValue(Spec.Form, | 
|  | Spec.getImplicitConstValue()); | 
|  |  | 
|  | DWARFFormValue FormValue(Spec.Form); | 
|  | if (FormValue.extractValue(DebugInfoData, &Offset, U.getFormParams(), &U)) | 
|  | return FormValue; | 
|  | } | 
|  | // March Offset along until we get to the attribute we want. | 
|  | if (auto FixedSize = Spec.getByteSize(U)) | 
|  | Offset += *FixedSize; | 
|  | else | 
|  | DWARFFormValue::skipValue(Spec.Form, DebugInfoData, &Offset, | 
|  | U.getFormParams()); | 
|  | ++AttrIndex; | 
|  | } | 
|  | 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; | 
|  | } |