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-exception 6 // 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 21 using namespace llvm; 22 using namespace dwarf; 23 24 void DWARFAbbreviationDeclaration::clear() { 25 Code = 0; 26 Tag = DW_TAG_null; 27 CodeByteSize = 0; 28 HasChildren = false; 29 AttributeSpecs.clear(); 30 FixedAttributeSize.reset(); 31 } 32 33 DWARFAbbreviationDeclaration::DWARFAbbreviationDeclaration() { 34 clear(); 35 } 36 37 bool 38 DWARFAbbreviationDeclaration::extract(DataExtractor Data, 39 uint64_t* OffsetPtr) { 40 clear(); 41 const uint64_t Offset = *OffsetPtr; 42 Code = Data.getULEB128(OffsetPtr); 43 if (Code == 0) { 44 return false; 45 } 46 CodeByteSize = *OffsetPtr - Offset; 47 Tag = static_cast<llvm::dwarf::Tag>(Data.getULEB128(OffsetPtr)); 48 if (Tag == DW_TAG_null) { 49 clear(); 50 return false; 51 } 52 uint8_t ChildrenByte = Data.getU8(OffsetPtr); 53 HasChildren = (ChildrenByte == DW_CHILDREN_yes); 54 // Assign a value to our optional FixedAttributeSize member variable. If 55 // this member variable still has a value after the while loop below, then 56 // all attribute data in this abbreviation declaration has a fixed byte size. 57 FixedAttributeSize = FixedSizeInfo(); 58 59 // Read all of the abbreviation attributes and forms. 60 while (true) { 61 auto A = static_cast<Attribute>(Data.getULEB128(OffsetPtr)); 62 auto F = static_cast<Form>(Data.getULEB128(OffsetPtr)); 63 if (A && F) { 64 bool IsImplicitConst = (F == DW_FORM_implicit_const); 65 if (IsImplicitConst) { 66 int64_t V = Data.getSLEB128(OffsetPtr); 67 AttributeSpecs.push_back(AttributeSpec(A, F, V)); 68 continue; 69 } 70 std::optional<uint8_t> ByteSize; 71 // If this abbrevation still has a fixed byte size, then update the 72 // FixedAttributeSize as needed. 73 switch (F) { 74 case DW_FORM_addr: 75 if (FixedAttributeSize) 76 ++FixedAttributeSize->NumAddrs; 77 break; 78 79 case DW_FORM_ref_addr: 80 if (FixedAttributeSize) 81 ++FixedAttributeSize->NumRefAddrs; 82 break; 83 84 case DW_FORM_strp: 85 case DW_FORM_GNU_ref_alt: 86 case DW_FORM_GNU_strp_alt: 87 case DW_FORM_line_strp: 88 case DW_FORM_sec_offset: 89 case DW_FORM_strp_sup: 90 if (FixedAttributeSize) 91 ++FixedAttributeSize->NumDwarfOffsets; 92 break; 93 94 default: 95 // The form has a byte size that doesn't depend on Params. 96 // If it's a fixed size, keep track of it. 97 if ((ByteSize = dwarf::getFixedFormByteSize(F, dwarf::FormParams()))) { 98 if (FixedAttributeSize) 99 FixedAttributeSize->NumBytes += *ByteSize; 100 break; 101 } 102 // Indicate we no longer have a fixed byte size for this 103 // abbreviation by clearing the FixedAttributeSize optional value 104 // so it doesn't have a value. 105 FixedAttributeSize.reset(); 106 break; 107 } 108 // Record this attribute and its fixed size if it has one. 109 AttributeSpecs.push_back(AttributeSpec(A, F, ByteSize)); 110 } else if (A == 0 && F == 0) { 111 // We successfully reached the end of this abbreviation declaration 112 // since both attribute and form are zero. 113 break; 114 } else { 115 // Attribute and form pairs must either both be non-zero, in which case 116 // they are added to the abbreviation declaration, or both be zero to 117 // terminate the abbrevation declaration. In this case only one was 118 // zero which is an error. 119 clear(); 120 return false; 121 } 122 } 123 return true; 124 } 125 126 void DWARFAbbreviationDeclaration::dump(raw_ostream &OS) const { 127 OS << '[' << getCode() << "] "; 128 OS << formatv("{0}", getTag()); 129 OS << "\tDW_CHILDREN_" << (hasChildren() ? "yes" : "no") << '\n'; 130 for (const AttributeSpec &Spec : AttributeSpecs) { 131 OS << formatv("\t{0}\t{1}", Spec.Attr, Spec.Form); 132 if (Spec.isImplicitConst()) 133 OS << '\t' << Spec.getImplicitConstValue(); 134 OS << '\n'; 135 } 136 OS << '\n'; 137 } 138 139 std::optional<uint32_t> 140 DWARFAbbreviationDeclaration::findAttributeIndex(dwarf::Attribute Attr) const { 141 for (uint32_t i = 0, e = AttributeSpecs.size(); i != e; ++i) { 142 if (AttributeSpecs[i].Attr == Attr) 143 return i; 144 } 145 return std::nullopt; 146 } 147 148 uint64_t DWARFAbbreviationDeclaration::getAttributeOffsetFromIndex( 149 uint32_t AttrIndex, uint64_t DIEOffset, const DWARFUnit &U) const { 150 DWARFDataExtractor DebugInfoData = U.getDebugInfoExtractor(); 151 152 // Add the byte size of ULEB that for the abbrev Code so we can start 153 // skipping the attribute data. 154 uint64_t Offset = DIEOffset + CodeByteSize; 155 for (uint32_t CurAttrIdx = 0; CurAttrIdx != AttrIndex; ++CurAttrIdx) 156 // Match Offset along until we get to the attribute we want. 157 if (auto FixedSize = AttributeSpecs[CurAttrIdx].getByteSize(U)) 158 Offset += *FixedSize; 159 else 160 DWARFFormValue::skipValue(AttributeSpecs[CurAttrIdx].Form, DebugInfoData, 161 &Offset, U.getFormParams()); 162 return Offset; 163 } 164 165 std::optional<DWARFFormValue> 166 DWARFAbbreviationDeclaration::getAttributeValueFromOffset( 167 uint32_t AttrIndex, uint64_t Offset, const DWARFUnit &U) const { 168 assert(AttributeSpecs.size() > AttrIndex && 169 "Attribute Index is out of bounds."); 170 171 // We have arrived at the attribute to extract, extract if from Offset. 172 const AttributeSpec &Spec = AttributeSpecs[AttrIndex]; 173 if (Spec.isImplicitConst()) 174 return DWARFFormValue::createFromSValue(Spec.Form, 175 Spec.getImplicitConstValue()); 176 177 DWARFFormValue FormValue(Spec.Form); 178 DWARFDataExtractor DebugInfoData = U.getDebugInfoExtractor(); 179 if (FormValue.extractValue(DebugInfoData, &Offset, U.getFormParams(), &U)) 180 return FormValue; 181 return std::nullopt; 182 } 183 184 std::optional<DWARFFormValue> 185 DWARFAbbreviationDeclaration::getAttributeValue(const uint64_t DIEOffset, 186 const dwarf::Attribute Attr, 187 const DWARFUnit &U) const { 188 // Check if this abbreviation has this attribute without needing to skip 189 // any data so we can return quickly if it doesn't. 190 std::optional<uint32_t> MatchAttrIndex = findAttributeIndex(Attr); 191 if (!MatchAttrIndex) 192 return std::nullopt; 193 194 uint64_t Offset = getAttributeOffsetFromIndex(*MatchAttrIndex, DIEOffset, U); 195 196 return getAttributeValueFromOffset(*MatchAttrIndex, Offset, U); 197 } 198 199 size_t DWARFAbbreviationDeclaration::FixedSizeInfo::getByteSize( 200 const DWARFUnit &U) const { 201 size_t ByteSize = NumBytes; 202 if (NumAddrs) 203 ByteSize += NumAddrs * U.getAddressByteSize(); 204 if (NumRefAddrs) 205 ByteSize += NumRefAddrs * U.getRefAddrByteSize(); 206 if (NumDwarfOffsets) 207 ByteSize += NumDwarfOffsets * U.getDwarfOffsetByteSize(); 208 return ByteSize; 209 } 210 211 std::optional<int64_t> DWARFAbbreviationDeclaration::AttributeSpec::getByteSize( 212 const DWARFUnit &U) const { 213 if (isImplicitConst()) 214 return 0; 215 if (ByteSize.HasByteSize) 216 return ByteSize.ByteSize; 217 std::optional<int64_t> S; 218 auto FixedByteSize = dwarf::getFixedFormByteSize(Form, U.getFormParams()); 219 if (FixedByteSize) 220 S = *FixedByteSize; 221 return S; 222 } 223 224 std::optional<size_t> DWARFAbbreviationDeclaration::getFixedAttributesByteSize( 225 const DWARFUnit &U) const { 226 if (FixedAttributeSize) 227 return FixedAttributeSize->getByteSize(U); 228 return std::nullopt; 229 } 230