//===- 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 #include 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(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(Data.getULEB128(OffsetPtr)); auto F = static_cast
(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 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 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 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 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 DWARFAbbreviationDeclaration::AttributeSpec::getByteSize( const DWARFUnit &U) const { if (isImplicitConst()) return 0; if (ByteSize.HasByteSize) return ByteSize.ByteSize; Optional S; auto FixedByteSize = dwarf::getFixedFormByteSize(Form, U.getFormParams()); if (FixedByteSize) S = *FixedByteSize; return S; } Optional DWARFAbbreviationDeclaration::getFixedAttributesByteSize( const DWARFUnit &U) const { if (FixedAttributeSize) return FixedAttributeSize->getByteSize(U); return None; }