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 llvm::Expected<DWARFAbbreviationDeclaration::ExtractState> 38 DWARFAbbreviationDeclaration::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. If 65 // this member variable still has a value after the while loop below, then 66 // 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 declaration 80 // since both attribute and form are zero. There may be more abbreviation 81 // 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 case 87 // they are added to the abbreviation declaration, or both be zero to 88 // terminate the abbrevation declaration. In this case only one was 89 // 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 the 104 // 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 this 135 // abbreviation by clearing the FixedAttributeSize optional value 136 // 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 148 void 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 161 std::optional<uint32_t> 162 DWARFAbbreviationDeclaration::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 170 uint64_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 start 175 // 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 else 182 DWARFFormValue::skipValue(AttributeSpecs[CurAttrIdx].Form, DebugInfoData, 183 &Offset, U.getFormParams()); 184 return Offset; 185 } 186 187 std::optional<DWARFFormValue> 188 DWARFAbbreviationDeclaration::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 206 std::optional<DWARFFormValue> 207 DWARFAbbreviationDeclaration::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 skip 211 // 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 221 size_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 233 std::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 246 std::optional<size_t> DWARFAbbreviationDeclaration::getFixedAttributesByteSize( 247 const DWARFUnit &U) const { 248 if (FixedAttributeSize) 249 return FixedAttributeSize->getByteSize(U); 250 return std::nullopt; 251 } 252