10b57cec5SDimitry Andric //===- DWARFAbbreviationDeclaration.cpp -----------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" 100b57cec5SDimitry Andric 110b57cec5SDimitry Andric #include "llvm/BinaryFormat/Dwarf.h" 1281ad6265SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" 130b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" 140b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFUnit.h" 150b57cec5SDimitry Andric #include "llvm/Support/DataExtractor.h" 160b57cec5SDimitry Andric #include "llvm/Support/FormatVariadic.h" 170b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 180b57cec5SDimitry Andric #include <cstddef> 190b57cec5SDimitry Andric #include <cstdint> 200b57cec5SDimitry Andric 210b57cec5SDimitry Andric using namespace llvm; 220b57cec5SDimitry Andric using namespace dwarf; 230b57cec5SDimitry Andric 240b57cec5SDimitry Andric void DWARFAbbreviationDeclaration::clear() { 250b57cec5SDimitry Andric Code = 0; 260b57cec5SDimitry Andric Tag = DW_TAG_null; 270b57cec5SDimitry Andric CodeByteSize = 0; 280b57cec5SDimitry Andric HasChildren = false; 290b57cec5SDimitry Andric AttributeSpecs.clear(); 300b57cec5SDimitry Andric FixedAttributeSize.reset(); 310b57cec5SDimitry Andric } 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric DWARFAbbreviationDeclaration::DWARFAbbreviationDeclaration() { 340b57cec5SDimitry Andric clear(); 350b57cec5SDimitry Andric } 360b57cec5SDimitry Andric 370b57cec5SDimitry Andric bool 380b57cec5SDimitry Andric DWARFAbbreviationDeclaration::extract(DataExtractor Data, 398bcb0991SDimitry Andric uint64_t* OffsetPtr) { 400b57cec5SDimitry Andric clear(); 418bcb0991SDimitry Andric const uint64_t Offset = *OffsetPtr; 420b57cec5SDimitry Andric Code = Data.getULEB128(OffsetPtr); 430b57cec5SDimitry Andric if (Code == 0) { 440b57cec5SDimitry Andric return false; 450b57cec5SDimitry Andric } 460b57cec5SDimitry Andric CodeByteSize = *OffsetPtr - Offset; 470b57cec5SDimitry Andric Tag = static_cast<llvm::dwarf::Tag>(Data.getULEB128(OffsetPtr)); 480b57cec5SDimitry Andric if (Tag == DW_TAG_null) { 490b57cec5SDimitry Andric clear(); 500b57cec5SDimitry Andric return false; 510b57cec5SDimitry Andric } 520b57cec5SDimitry Andric uint8_t ChildrenByte = Data.getU8(OffsetPtr); 530b57cec5SDimitry Andric HasChildren = (ChildrenByte == DW_CHILDREN_yes); 540b57cec5SDimitry Andric // Assign a value to our optional FixedAttributeSize member variable. If 550b57cec5SDimitry Andric // this member variable still has a value after the while loop below, then 560b57cec5SDimitry Andric // all attribute data in this abbreviation declaration has a fixed byte size. 570b57cec5SDimitry Andric FixedAttributeSize = FixedSizeInfo(); 580b57cec5SDimitry Andric 590b57cec5SDimitry Andric // Read all of the abbreviation attributes and forms. 600b57cec5SDimitry Andric while (true) { 610b57cec5SDimitry Andric auto A = static_cast<Attribute>(Data.getULEB128(OffsetPtr)); 620b57cec5SDimitry Andric auto F = static_cast<Form>(Data.getULEB128(OffsetPtr)); 630b57cec5SDimitry Andric if (A && F) { 640b57cec5SDimitry Andric bool IsImplicitConst = (F == DW_FORM_implicit_const); 650b57cec5SDimitry Andric if (IsImplicitConst) { 660b57cec5SDimitry Andric int64_t V = Data.getSLEB128(OffsetPtr); 670b57cec5SDimitry Andric AttributeSpecs.push_back(AttributeSpec(A, F, V)); 680b57cec5SDimitry Andric continue; 690b57cec5SDimitry Andric } 70*bdd1243dSDimitry Andric std::optional<uint8_t> ByteSize; 710b57cec5SDimitry Andric // If this abbrevation still has a fixed byte size, then update the 720b57cec5SDimitry Andric // FixedAttributeSize as needed. 730b57cec5SDimitry Andric switch (F) { 740b57cec5SDimitry Andric case DW_FORM_addr: 750b57cec5SDimitry Andric if (FixedAttributeSize) 760b57cec5SDimitry Andric ++FixedAttributeSize->NumAddrs; 770b57cec5SDimitry Andric break; 780b57cec5SDimitry Andric 790b57cec5SDimitry Andric case DW_FORM_ref_addr: 800b57cec5SDimitry Andric if (FixedAttributeSize) 810b57cec5SDimitry Andric ++FixedAttributeSize->NumRefAddrs; 820b57cec5SDimitry Andric break; 830b57cec5SDimitry Andric 840b57cec5SDimitry Andric case DW_FORM_strp: 850b57cec5SDimitry Andric case DW_FORM_GNU_ref_alt: 860b57cec5SDimitry Andric case DW_FORM_GNU_strp_alt: 870b57cec5SDimitry Andric case DW_FORM_line_strp: 880b57cec5SDimitry Andric case DW_FORM_sec_offset: 890b57cec5SDimitry Andric case DW_FORM_strp_sup: 900b57cec5SDimitry Andric if (FixedAttributeSize) 910b57cec5SDimitry Andric ++FixedAttributeSize->NumDwarfOffsets; 920b57cec5SDimitry Andric break; 930b57cec5SDimitry Andric 940b57cec5SDimitry Andric default: 950b57cec5SDimitry Andric // The form has a byte size that doesn't depend on Params. 960b57cec5SDimitry Andric // If it's a fixed size, keep track of it. 970b57cec5SDimitry Andric if ((ByteSize = dwarf::getFixedFormByteSize(F, dwarf::FormParams()))) { 980b57cec5SDimitry Andric if (FixedAttributeSize) 990b57cec5SDimitry Andric FixedAttributeSize->NumBytes += *ByteSize; 1000b57cec5SDimitry Andric break; 1010b57cec5SDimitry Andric } 1020b57cec5SDimitry Andric // Indicate we no longer have a fixed byte size for this 1030b57cec5SDimitry Andric // abbreviation by clearing the FixedAttributeSize optional value 1040b57cec5SDimitry Andric // so it doesn't have a value. 1050b57cec5SDimitry Andric FixedAttributeSize.reset(); 1060b57cec5SDimitry Andric break; 1070b57cec5SDimitry Andric } 1080b57cec5SDimitry Andric // Record this attribute and its fixed size if it has one. 1090b57cec5SDimitry Andric AttributeSpecs.push_back(AttributeSpec(A, F, ByteSize)); 1100b57cec5SDimitry Andric } else if (A == 0 && F == 0) { 1110b57cec5SDimitry Andric // We successfully reached the end of this abbreviation declaration 1120b57cec5SDimitry Andric // since both attribute and form are zero. 1130b57cec5SDimitry Andric break; 1140b57cec5SDimitry Andric } else { 1150b57cec5SDimitry Andric // Attribute and form pairs must either both be non-zero, in which case 1160b57cec5SDimitry Andric // they are added to the abbreviation declaration, or both be zero to 1170b57cec5SDimitry Andric // terminate the abbrevation declaration. In this case only one was 1180b57cec5SDimitry Andric // zero which is an error. 1190b57cec5SDimitry Andric clear(); 1200b57cec5SDimitry Andric return false; 1210b57cec5SDimitry Andric } 1220b57cec5SDimitry Andric } 1230b57cec5SDimitry Andric return true; 1240b57cec5SDimitry Andric } 1250b57cec5SDimitry Andric 1260b57cec5SDimitry Andric void DWARFAbbreviationDeclaration::dump(raw_ostream &OS) const { 1270b57cec5SDimitry Andric OS << '[' << getCode() << "] "; 1280b57cec5SDimitry Andric OS << formatv("{0}", getTag()); 1290b57cec5SDimitry Andric OS << "\tDW_CHILDREN_" << (hasChildren() ? "yes" : "no") << '\n'; 1300b57cec5SDimitry Andric for (const AttributeSpec &Spec : AttributeSpecs) { 1310b57cec5SDimitry Andric OS << formatv("\t{0}\t{1}", Spec.Attr, Spec.Form); 1320b57cec5SDimitry Andric if (Spec.isImplicitConst()) 1330b57cec5SDimitry Andric OS << '\t' << Spec.getImplicitConstValue(); 1340b57cec5SDimitry Andric OS << '\n'; 1350b57cec5SDimitry Andric } 1360b57cec5SDimitry Andric OS << '\n'; 1370b57cec5SDimitry Andric } 1380b57cec5SDimitry Andric 139*bdd1243dSDimitry Andric std::optional<uint32_t> 1400b57cec5SDimitry Andric DWARFAbbreviationDeclaration::findAttributeIndex(dwarf::Attribute Attr) const { 1410b57cec5SDimitry Andric for (uint32_t i = 0, e = AttributeSpecs.size(); i != e; ++i) { 1420b57cec5SDimitry Andric if (AttributeSpecs[i].Attr == Attr) 1430b57cec5SDimitry Andric return i; 1440b57cec5SDimitry Andric } 145*bdd1243dSDimitry Andric return std::nullopt; 1460b57cec5SDimitry Andric } 1470b57cec5SDimitry Andric 148349cc55cSDimitry Andric uint64_t DWARFAbbreviationDeclaration::getAttributeOffsetFromIndex( 149349cc55cSDimitry Andric uint32_t AttrIndex, uint64_t DIEOffset, const DWARFUnit &U) const { 150349cc55cSDimitry Andric DWARFDataExtractor DebugInfoData = U.getDebugInfoExtractor(); 151349cc55cSDimitry Andric 152349cc55cSDimitry Andric // Add the byte size of ULEB that for the abbrev Code so we can start 153349cc55cSDimitry Andric // skipping the attribute data. 154349cc55cSDimitry Andric uint64_t Offset = DIEOffset + CodeByteSize; 155349cc55cSDimitry Andric for (uint32_t CurAttrIdx = 0; CurAttrIdx != AttrIndex; ++CurAttrIdx) 156349cc55cSDimitry Andric // Match Offset along until we get to the attribute we want. 157349cc55cSDimitry Andric if (auto FixedSize = AttributeSpecs[CurAttrIdx].getByteSize(U)) 158349cc55cSDimitry Andric Offset += *FixedSize; 159349cc55cSDimitry Andric else 160349cc55cSDimitry Andric DWARFFormValue::skipValue(AttributeSpecs[CurAttrIdx].Form, DebugInfoData, 161349cc55cSDimitry Andric &Offset, U.getFormParams()); 162349cc55cSDimitry Andric return Offset; 163349cc55cSDimitry Andric } 164349cc55cSDimitry Andric 165*bdd1243dSDimitry Andric std::optional<DWARFFormValue> 166349cc55cSDimitry Andric DWARFAbbreviationDeclaration::getAttributeValueFromOffset( 167349cc55cSDimitry Andric uint32_t AttrIndex, uint64_t Offset, const DWARFUnit &U) const { 168349cc55cSDimitry Andric assert(AttributeSpecs.size() > AttrIndex && 169349cc55cSDimitry Andric "Attribute Index is out of bounds."); 170349cc55cSDimitry Andric 171349cc55cSDimitry Andric // We have arrived at the attribute to extract, extract if from Offset. 172349cc55cSDimitry Andric const AttributeSpec &Spec = AttributeSpecs[AttrIndex]; 173349cc55cSDimitry Andric if (Spec.isImplicitConst()) 174349cc55cSDimitry Andric return DWARFFormValue::createFromSValue(Spec.Form, 175349cc55cSDimitry Andric Spec.getImplicitConstValue()); 176349cc55cSDimitry Andric 177349cc55cSDimitry Andric DWARFFormValue FormValue(Spec.Form); 178349cc55cSDimitry Andric DWARFDataExtractor DebugInfoData = U.getDebugInfoExtractor(); 179349cc55cSDimitry Andric if (FormValue.extractValue(DebugInfoData, &Offset, U.getFormParams(), &U)) 180349cc55cSDimitry Andric return FormValue; 181*bdd1243dSDimitry Andric return std::nullopt; 182349cc55cSDimitry Andric } 183349cc55cSDimitry Andric 184*bdd1243dSDimitry Andric std::optional<DWARFFormValue> 185349cc55cSDimitry Andric DWARFAbbreviationDeclaration::getAttributeValue(const uint64_t DIEOffset, 186349cc55cSDimitry Andric const dwarf::Attribute Attr, 1870b57cec5SDimitry Andric const DWARFUnit &U) const { 1885ffd83dbSDimitry Andric // Check if this abbreviation has this attribute without needing to skip 1895ffd83dbSDimitry Andric // any data so we can return quickly if it doesn't. 190*bdd1243dSDimitry Andric std::optional<uint32_t> MatchAttrIndex = findAttributeIndex(Attr); 1910b57cec5SDimitry Andric if (!MatchAttrIndex) 192*bdd1243dSDimitry Andric return std::nullopt; 1930b57cec5SDimitry Andric 194349cc55cSDimitry Andric uint64_t Offset = getAttributeOffsetFromIndex(*MatchAttrIndex, DIEOffset, U); 1950b57cec5SDimitry Andric 196349cc55cSDimitry Andric return getAttributeValueFromOffset(*MatchAttrIndex, Offset, U); 1970b57cec5SDimitry Andric } 1980b57cec5SDimitry Andric 1990b57cec5SDimitry Andric size_t DWARFAbbreviationDeclaration::FixedSizeInfo::getByteSize( 2000b57cec5SDimitry Andric const DWARFUnit &U) const { 2010b57cec5SDimitry Andric size_t ByteSize = NumBytes; 2020b57cec5SDimitry Andric if (NumAddrs) 2030b57cec5SDimitry Andric ByteSize += NumAddrs * U.getAddressByteSize(); 2040b57cec5SDimitry Andric if (NumRefAddrs) 2050b57cec5SDimitry Andric ByteSize += NumRefAddrs * U.getRefAddrByteSize(); 2060b57cec5SDimitry Andric if (NumDwarfOffsets) 2070b57cec5SDimitry Andric ByteSize += NumDwarfOffsets * U.getDwarfOffsetByteSize(); 2080b57cec5SDimitry Andric return ByteSize; 2090b57cec5SDimitry Andric } 2100b57cec5SDimitry Andric 211*bdd1243dSDimitry Andric std::optional<int64_t> DWARFAbbreviationDeclaration::AttributeSpec::getByteSize( 2120b57cec5SDimitry Andric const DWARFUnit &U) const { 2130b57cec5SDimitry Andric if (isImplicitConst()) 2140b57cec5SDimitry Andric return 0; 2150b57cec5SDimitry Andric if (ByteSize.HasByteSize) 2160b57cec5SDimitry Andric return ByteSize.ByteSize; 217*bdd1243dSDimitry Andric std::optional<int64_t> S; 2180b57cec5SDimitry Andric auto FixedByteSize = dwarf::getFixedFormByteSize(Form, U.getFormParams()); 2190b57cec5SDimitry Andric if (FixedByteSize) 2200b57cec5SDimitry Andric S = *FixedByteSize; 2210b57cec5SDimitry Andric return S; 2220b57cec5SDimitry Andric } 2230b57cec5SDimitry Andric 224*bdd1243dSDimitry Andric std::optional<size_t> DWARFAbbreviationDeclaration::getFixedAttributesByteSize( 2250b57cec5SDimitry Andric const DWARFUnit &U) const { 2260b57cec5SDimitry Andric if (FixedAttributeSize) 2270b57cec5SDimitry Andric return FixedAttributeSize->getByteSize(U); 228*bdd1243dSDimitry Andric return std::nullopt; 2290b57cec5SDimitry Andric } 230