252 lines · cpp
1//===- DWARFAbbreviationDeclaration.cpp -----------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"10 11#include "llvm/BinaryFormat/Dwarf.h"12#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"13#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"14#include "llvm/DebugInfo/DWARF/DWARFUnit.h"15#include "llvm/Support/DataExtractor.h"16#include "llvm/Support/FormatVariadic.h"17#include "llvm/Support/raw_ostream.h"18#include <cstddef>19#include <cstdint>20 21using namespace llvm;22using namespace dwarf;23 24void DWARFAbbreviationDeclaration::clear() {25 Code = 0;26 Tag = DW_TAG_null;27 CodeByteSize = 0;28 HasChildren = false;29 AttributeSpecs.clear();30 FixedAttributeSize.reset();31}32 33DWARFAbbreviationDeclaration::DWARFAbbreviationDeclaration() {34 clear();35}36 37llvm::Expected<DWARFAbbreviationDeclaration::ExtractState>38DWARFAbbreviationDeclaration::extract(DataExtractor Data, uint64_t *OffsetPtr) {39 clear();40 const uint64_t Offset = *OffsetPtr;41 Error Err = Error::success();42 Code = Data.getULEB128(OffsetPtr, &Err);43 if (Err)44 return std::move(Err);45 46 if (Code == 0)47 return ExtractState::Complete;48 49 CodeByteSize = *OffsetPtr - Offset;50 Tag = static_cast<llvm::dwarf::Tag>(Data.getULEB128(OffsetPtr, &Err));51 if (Err)52 return std::move(Err);53 54 if (Tag == DW_TAG_null) {55 clear();56 return make_error<llvm::object::GenericBinaryError>(57 "abbreviation declaration requires a non-null tag");58 }59 uint8_t ChildrenByte = Data.getU8(OffsetPtr, &Err);60 if (Err)61 return std::move(Err);62 63 HasChildren = (ChildrenByte == DW_CHILDREN_yes);64 // Assign a value to our optional FixedAttributeSize member variable. If65 // this member variable still has a value after the while loop below, then66 // all attribute data in this abbreviation declaration has a fixed byte size.67 FixedAttributeSize = FixedSizeInfo();68 69 // Read all of the abbreviation attributes and forms.70 while (Data.isValidOffset(*OffsetPtr)) {71 auto A = static_cast<Attribute>(Data.getULEB128(OffsetPtr, &Err));72 if (Err)73 return std::move(Err);74 75 auto F = static_cast<Form>(Data.getULEB128(OffsetPtr, &Err));76 if (Err)77 return std::move(Err);78 79 // We successfully reached the end of this abbreviation declaration80 // since both attribute and form are zero. There may be more abbreviation81 // declarations afterwards.82 if (!A && !F)83 return ExtractState::MoreItems;84 85 if (!A || !F) {86 // Attribute and form pairs must either both be non-zero, in which case87 // they are added to the abbreviation declaration, or both be zero to88 // terminate the abbrevation declaration. In this case only one was89 // zero which is an error.90 clear();91 return make_error<llvm::object::GenericBinaryError>(92 "malformed abbreviation declaration attribute. Either the attribute "93 "or the form is zero while the other is not");94 }95 96 bool IsImplicitConst = (F == DW_FORM_implicit_const);97 if (IsImplicitConst) {98 int64_t V = Data.getSLEB128(OffsetPtr);99 AttributeSpecs.push_back(AttributeSpec(A, F, V));100 continue;101 }102 std::optional<uint8_t> ByteSize;103 // If this abbrevation still has a fixed byte size, then update the104 // FixedAttributeSize as needed.105 switch (F) {106 case DW_FORM_addr:107 if (FixedAttributeSize)108 ++FixedAttributeSize->NumAddrs;109 break;110 111 case DW_FORM_ref_addr:112 if (FixedAttributeSize)113 ++FixedAttributeSize->NumRefAddrs;114 break;115 116 case DW_FORM_strp:117 case DW_FORM_GNU_ref_alt:118 case DW_FORM_GNU_strp_alt:119 case DW_FORM_line_strp:120 case DW_FORM_sec_offset:121 case DW_FORM_strp_sup:122 if (FixedAttributeSize)123 ++FixedAttributeSize->NumDwarfOffsets;124 break;125 126 default:127 // The form has a byte size that doesn't depend on Params.128 // If it's a fixed size, keep track of it.129 if ((ByteSize = dwarf::getFixedFormByteSize(F, dwarf::FormParams()))) {130 if (FixedAttributeSize)131 FixedAttributeSize->NumBytes += *ByteSize;132 break;133 }134 // Indicate we no longer have a fixed byte size for this135 // abbreviation by clearing the FixedAttributeSize optional value136 // so it doesn't have a value.137 FixedAttributeSize.reset();138 break;139 }140 // Record this attribute and its fixed size if it has one.141 AttributeSpecs.push_back(AttributeSpec(A, F, ByteSize));142 }143 return make_error<llvm::object::GenericBinaryError>(144 "abbreviation declaration attribute list was not terminated with a null "145 "entry");146}147 148void DWARFAbbreviationDeclaration::dump(raw_ostream &OS) const {149 OS << '[' << getCode() << "] ";150 OS << formatv("{0}", getTag());151 OS << "\tDW_CHILDREN_" << (hasChildren() ? "yes" : "no") << '\n';152 for (const AttributeSpec &Spec : AttributeSpecs) {153 OS << formatv("\t{0}\t{1}", Spec.Attr, Spec.Form);154 if (Spec.isImplicitConst())155 OS << '\t' << Spec.getImplicitConstValue();156 OS << '\n';157 }158 OS << '\n';159}160 161std::optional<uint32_t>162DWARFAbbreviationDeclaration::findAttributeIndex(dwarf::Attribute Attr) const {163 for (uint32_t i = 0, e = AttributeSpecs.size(); i != e; ++i) {164 if (AttributeSpecs[i].Attr == Attr)165 return i;166 }167 return std::nullopt;168}169 170uint64_t DWARFAbbreviationDeclaration::getAttributeOffsetFromIndex(171 uint32_t AttrIndex, uint64_t DIEOffset, const DWARFUnit &U) const {172 DWARFDataExtractor DebugInfoData = U.getDebugInfoExtractor();173 174 // Add the byte size of ULEB that for the abbrev Code so we can start175 // skipping the attribute data.176 uint64_t Offset = DIEOffset + CodeByteSize;177 for (uint32_t CurAttrIdx = 0; CurAttrIdx != AttrIndex; ++CurAttrIdx)178 // Match Offset along until we get to the attribute we want.179 if (auto FixedSize = AttributeSpecs[CurAttrIdx].getByteSize(U))180 Offset += *FixedSize;181 else182 DWARFFormValue::skipValue(AttributeSpecs[CurAttrIdx].Form, DebugInfoData,183 &Offset, U.getFormParams());184 return Offset;185}186 187std::optional<DWARFFormValue>188DWARFAbbreviationDeclaration::getAttributeValueFromOffset(189 uint32_t AttrIndex, uint64_t Offset, const DWARFUnit &U) const {190 assert(AttributeSpecs.size() > AttrIndex &&191 "Attribute Index is out of bounds.");192 193 // We have arrived at the attribute to extract, extract if from Offset.194 const AttributeSpec &Spec = AttributeSpecs[AttrIndex];195 if (Spec.isImplicitConst())196 return DWARFFormValue::createFromSValue(Spec.Form,197 Spec.getImplicitConstValue());198 199 DWARFFormValue FormValue(Spec.Form);200 DWARFDataExtractor DebugInfoData = U.getDebugInfoExtractor();201 if (FormValue.extractValue(DebugInfoData, &Offset, U.getFormParams(), &U))202 return FormValue;203 return std::nullopt;204}205 206std::optional<DWARFFormValue>207DWARFAbbreviationDeclaration::getAttributeValue(const uint64_t DIEOffset,208 const dwarf::Attribute Attr,209 const DWARFUnit &U) const {210 // Check if this abbreviation has this attribute without needing to skip211 // any data so we can return quickly if it doesn't.212 std::optional<uint32_t> MatchAttrIndex = findAttributeIndex(Attr);213 if (!MatchAttrIndex)214 return std::nullopt;215 216 uint64_t Offset = getAttributeOffsetFromIndex(*MatchAttrIndex, DIEOffset, U);217 218 return getAttributeValueFromOffset(*MatchAttrIndex, Offset, U);219}220 221size_t DWARFAbbreviationDeclaration::FixedSizeInfo::getByteSize(222 const DWARFUnit &U) const {223 size_t ByteSize = NumBytes;224 if (NumAddrs)225 ByteSize += NumAddrs * U.getAddressByteSize();226 if (NumRefAddrs)227 ByteSize += NumRefAddrs * U.getRefAddrByteSize();228 if (NumDwarfOffsets)229 ByteSize += NumDwarfOffsets * U.getDwarfOffsetByteSize();230 return ByteSize;231}232 233std::optional<int64_t> DWARFAbbreviationDeclaration::AttributeSpec::getByteSize(234 const DWARFUnit &U) const {235 if (isImplicitConst())236 return 0;237 if (ByteSize.HasByteSize)238 return ByteSize.ByteSize;239 std::optional<int64_t> S;240 auto FixedByteSize = dwarf::getFixedFormByteSize(Form, U.getFormParams());241 if (FixedByteSize)242 S = *FixedByteSize;243 return S;244}245 246std::optional<size_t> DWARFAbbreviationDeclaration::getFixedAttributesByteSize(247 const DWARFUnit &U) const {248 if (FixedAttributeSize)249 return FixedAttributeSize->getByteSize(U);250 return std::nullopt;251}252