| //===- 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 { |
| 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; |
| 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; |
| } |