Path: blob/main/contrib/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp
35266 views
//===- DWARFAbbreviationDeclaration.cpp -----------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"910#include "llvm/BinaryFormat/Dwarf.h"11#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"12#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"13#include "llvm/DebugInfo/DWARF/DWARFUnit.h"14#include "llvm/Support/DataExtractor.h"15#include "llvm/Support/FormatVariadic.h"16#include "llvm/Support/raw_ostream.h"17#include <cstddef>18#include <cstdint>1920using namespace llvm;21using namespace dwarf;2223void DWARFAbbreviationDeclaration::clear() {24Code = 0;25Tag = DW_TAG_null;26CodeByteSize = 0;27HasChildren = false;28AttributeSpecs.clear();29FixedAttributeSize.reset();30}3132DWARFAbbreviationDeclaration::DWARFAbbreviationDeclaration() {33clear();34}3536llvm::Expected<DWARFAbbreviationDeclaration::ExtractState>37DWARFAbbreviationDeclaration::extract(DataExtractor Data, uint64_t *OffsetPtr) {38clear();39const uint64_t Offset = *OffsetPtr;40Error Err = Error::success();41Code = Data.getULEB128(OffsetPtr, &Err);42if (Err)43return std::move(Err);4445if (Code == 0)46return ExtractState::Complete;4748CodeByteSize = *OffsetPtr - Offset;49Tag = static_cast<llvm::dwarf::Tag>(Data.getULEB128(OffsetPtr, &Err));50if (Err)51return std::move(Err);5253if (Tag == DW_TAG_null) {54clear();55return make_error<llvm::object::GenericBinaryError>(56"abbreviation declaration requires a non-null tag");57}58uint8_t ChildrenByte = Data.getU8(OffsetPtr, &Err);59if (Err)60return std::move(Err);6162HasChildren = (ChildrenByte == DW_CHILDREN_yes);63// Assign a value to our optional FixedAttributeSize member variable. If64// this member variable still has a value after the while loop below, then65// all attribute data in this abbreviation declaration has a fixed byte size.66FixedAttributeSize = FixedSizeInfo();6768// Read all of the abbreviation attributes and forms.69while (Data.isValidOffset(*OffsetPtr)) {70auto A = static_cast<Attribute>(Data.getULEB128(OffsetPtr, &Err));71if (Err)72return std::move(Err);7374auto F = static_cast<Form>(Data.getULEB128(OffsetPtr, &Err));75if (Err)76return std::move(Err);7778// We successfully reached the end of this abbreviation declaration79// since both attribute and form are zero. There may be more abbreviation80// declarations afterwards.81if (!A && !F)82return ExtractState::MoreItems;8384if (!A || !F) {85// Attribute and form pairs must either both be non-zero, in which case86// they are added to the abbreviation declaration, or both be zero to87// terminate the abbrevation declaration. In this case only one was88// zero which is an error.89clear();90return make_error<llvm::object::GenericBinaryError>(91"malformed abbreviation declaration attribute. Either the attribute "92"or the form is zero while the other is not");93}9495bool IsImplicitConst = (F == DW_FORM_implicit_const);96if (IsImplicitConst) {97int64_t V = Data.getSLEB128(OffsetPtr);98AttributeSpecs.push_back(AttributeSpec(A, F, V));99continue;100}101std::optional<uint8_t> ByteSize;102// If this abbrevation still has a fixed byte size, then update the103// FixedAttributeSize as needed.104switch (F) {105case DW_FORM_addr:106if (FixedAttributeSize)107++FixedAttributeSize->NumAddrs;108break;109110case DW_FORM_ref_addr:111if (FixedAttributeSize)112++FixedAttributeSize->NumRefAddrs;113break;114115case DW_FORM_strp:116case DW_FORM_GNU_ref_alt:117case DW_FORM_GNU_strp_alt:118case DW_FORM_line_strp:119case DW_FORM_sec_offset:120case DW_FORM_strp_sup:121if (FixedAttributeSize)122++FixedAttributeSize->NumDwarfOffsets;123break;124125default:126// The form has a byte size that doesn't depend on Params.127// If it's a fixed size, keep track of it.128if ((ByteSize = dwarf::getFixedFormByteSize(F, dwarf::FormParams()))) {129if (FixedAttributeSize)130FixedAttributeSize->NumBytes += *ByteSize;131break;132}133// Indicate we no longer have a fixed byte size for this134// abbreviation by clearing the FixedAttributeSize optional value135// so it doesn't have a value.136FixedAttributeSize.reset();137break;138}139// Record this attribute and its fixed size if it has one.140AttributeSpecs.push_back(AttributeSpec(A, F, ByteSize));141}142return make_error<llvm::object::GenericBinaryError>(143"abbreviation declaration attribute list was not terminated with a null "144"entry");145}146147void DWARFAbbreviationDeclaration::dump(raw_ostream &OS) const {148OS << '[' << getCode() << "] ";149OS << formatv("{0}", getTag());150OS << "\tDW_CHILDREN_" << (hasChildren() ? "yes" : "no") << '\n';151for (const AttributeSpec &Spec : AttributeSpecs) {152OS << formatv("\t{0}\t{1}", Spec.Attr, Spec.Form);153if (Spec.isImplicitConst())154OS << '\t' << Spec.getImplicitConstValue();155OS << '\n';156}157OS << '\n';158}159160std::optional<uint32_t>161DWARFAbbreviationDeclaration::findAttributeIndex(dwarf::Attribute Attr) const {162for (uint32_t i = 0, e = AttributeSpecs.size(); i != e; ++i) {163if (AttributeSpecs[i].Attr == Attr)164return i;165}166return std::nullopt;167}168169uint64_t DWARFAbbreviationDeclaration::getAttributeOffsetFromIndex(170uint32_t AttrIndex, uint64_t DIEOffset, const DWARFUnit &U) const {171DWARFDataExtractor DebugInfoData = U.getDebugInfoExtractor();172173// Add the byte size of ULEB that for the abbrev Code so we can start174// skipping the attribute data.175uint64_t Offset = DIEOffset + CodeByteSize;176for (uint32_t CurAttrIdx = 0; CurAttrIdx != AttrIndex; ++CurAttrIdx)177// Match Offset along until we get to the attribute we want.178if (auto FixedSize = AttributeSpecs[CurAttrIdx].getByteSize(U))179Offset += *FixedSize;180else181DWARFFormValue::skipValue(AttributeSpecs[CurAttrIdx].Form, DebugInfoData,182&Offset, U.getFormParams());183return Offset;184}185186std::optional<DWARFFormValue>187DWARFAbbreviationDeclaration::getAttributeValueFromOffset(188uint32_t AttrIndex, uint64_t Offset, const DWARFUnit &U) const {189assert(AttributeSpecs.size() > AttrIndex &&190"Attribute Index is out of bounds.");191192// We have arrived at the attribute to extract, extract if from Offset.193const AttributeSpec &Spec = AttributeSpecs[AttrIndex];194if (Spec.isImplicitConst())195return DWARFFormValue::createFromSValue(Spec.Form,196Spec.getImplicitConstValue());197198DWARFFormValue FormValue(Spec.Form);199DWARFDataExtractor DebugInfoData = U.getDebugInfoExtractor();200if (FormValue.extractValue(DebugInfoData, &Offset, U.getFormParams(), &U))201return FormValue;202return std::nullopt;203}204205std::optional<DWARFFormValue>206DWARFAbbreviationDeclaration::getAttributeValue(const uint64_t DIEOffset,207const dwarf::Attribute Attr,208const DWARFUnit &U) const {209// Check if this abbreviation has this attribute without needing to skip210// any data so we can return quickly if it doesn't.211std::optional<uint32_t> MatchAttrIndex = findAttributeIndex(Attr);212if (!MatchAttrIndex)213return std::nullopt;214215uint64_t Offset = getAttributeOffsetFromIndex(*MatchAttrIndex, DIEOffset, U);216217return getAttributeValueFromOffset(*MatchAttrIndex, Offset, U);218}219220size_t DWARFAbbreviationDeclaration::FixedSizeInfo::getByteSize(221const DWARFUnit &U) const {222size_t ByteSize = NumBytes;223if (NumAddrs)224ByteSize += NumAddrs * U.getAddressByteSize();225if (NumRefAddrs)226ByteSize += NumRefAddrs * U.getRefAddrByteSize();227if (NumDwarfOffsets)228ByteSize += NumDwarfOffsets * U.getDwarfOffsetByteSize();229return ByteSize;230}231232std::optional<int64_t> DWARFAbbreviationDeclaration::AttributeSpec::getByteSize(233const DWARFUnit &U) const {234if (isImplicitConst())235return 0;236if (ByteSize.HasByteSize)237return ByteSize.ByteSize;238std::optional<int64_t> S;239auto FixedByteSize = dwarf::getFixedFormByteSize(Form, U.getFormParams());240if (FixedByteSize)241S = *FixedByteSize;242return S;243}244245std::optional<size_t> DWARFAbbreviationDeclaration::getFixedAttributesByteSize(246const DWARFUnit &U) const {247if (FixedAttributeSize)248return FixedAttributeSize->getByteSize(U);249return std::nullopt;250}251252253