1 //=== AcceleratorRecordsSaver.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 "AcceleratorRecordsSaver.h" 10 #include "llvm/DWARFLinker/Utils.h" 11 #include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" 12 #include "llvm/Support/DJB.h" 13 14 using namespace llvm; 15 using namespace dwarf_linker; 16 using namespace dwarf_linker::parallel; 17 18 static uint32_t hashFullyQualifiedName(CompileUnit &InputCU, DWARFDie &InputDIE, 19 int ChildRecurseDepth = 0) { 20 const char *Name = nullptr; 21 CompileUnit *CU = &InputCU; 22 std::optional<DWARFFormValue> RefVal; 23 24 if (Error Err = finiteLoop([&]() -> Expected<bool> { 25 if (const char *CurrentName = InputDIE.getName(DINameKind::ShortName)) 26 Name = CurrentName; 27 28 if (!(RefVal = InputDIE.find(dwarf::DW_AT_specification)) && 29 !(RefVal = InputDIE.find(dwarf::DW_AT_abstract_origin))) 30 return false; 31 32 if (!RefVal->isFormClass(DWARFFormValue::FC_Reference)) 33 return false; 34 35 std::optional<UnitEntryPairTy> RefDie = CU->resolveDIEReference( 36 *RefVal, ResolveInterCUReferencesMode::Resolve); 37 if (!RefDie) 38 return false; 39 40 if (!RefDie->DieEntry) 41 return false; 42 43 CU = RefDie->CU; 44 InputDIE = RefDie->CU->getDIE(RefDie->DieEntry); 45 return true; 46 })) { 47 consumeError(std::move(Err)); 48 } 49 50 if (!Name && InputDIE.getTag() == dwarf::DW_TAG_namespace) 51 Name = "(anonymous namespace)"; 52 53 DWARFDie ParentDie = InputDIE.getParent(); 54 if (!ParentDie.isValid() || ParentDie.getTag() == dwarf::DW_TAG_compile_unit) 55 return djbHash(Name ? Name : "", djbHash(ChildRecurseDepth ? "" : "::")); 56 57 return djbHash( 58 (Name ? Name : ""), 59 djbHash((Name ? "::" : ""), 60 hashFullyQualifiedName(*CU, ParentDie, ++ChildRecurseDepth))); 61 } 62 63 void AcceleratorRecordsSaver::save(const DWARFDebugInfoEntry *InputDieEntry, 64 DIE *OutDIE, AttributesInfo &AttrInfo, 65 TypeEntry *TypeEntry) { 66 if (GlobalData.getOptions().AccelTables.empty()) 67 return; 68 69 DWARFDie InputDIE = InUnit.getDIE(InputDieEntry); 70 71 // Look for short name recursively if short name is not known yet. 72 if (AttrInfo.Name == nullptr) 73 if (const char *ShortName = InputDIE.getShortName()) 74 AttrInfo.Name = GlobalData.getStringPool().insert(ShortName).first; 75 76 switch (InputDieEntry->getTag()) { 77 case dwarf::DW_TAG_array_type: 78 case dwarf::DW_TAG_class_type: 79 case dwarf::DW_TAG_enumeration_type: 80 case dwarf::DW_TAG_pointer_type: 81 case dwarf::DW_TAG_reference_type: 82 case dwarf::DW_TAG_string_type: 83 case dwarf::DW_TAG_structure_type: 84 case dwarf::DW_TAG_subroutine_type: 85 case dwarf::DW_TAG_typedef: 86 case dwarf::DW_TAG_union_type: 87 case dwarf::DW_TAG_ptr_to_member_type: 88 case dwarf::DW_TAG_set_type: 89 case dwarf::DW_TAG_subrange_type: 90 case dwarf::DW_TAG_base_type: 91 case dwarf::DW_TAG_const_type: 92 case dwarf::DW_TAG_constant: 93 case dwarf::DW_TAG_file_type: 94 case dwarf::DW_TAG_namelist: 95 case dwarf::DW_TAG_packed_type: 96 case dwarf::DW_TAG_volatile_type: 97 case dwarf::DW_TAG_restrict_type: 98 case dwarf::DW_TAG_atomic_type: 99 case dwarf::DW_TAG_interface_type: 100 case dwarf::DW_TAG_unspecified_type: 101 case dwarf::DW_TAG_shared_type: 102 case dwarf::DW_TAG_immutable_type: 103 case dwarf::DW_TAG_rvalue_reference_type: { 104 if (!AttrInfo.IsDeclaration && AttrInfo.Name != nullptr && 105 !AttrInfo.Name->getKey().empty()) { 106 uint32_t Hash = hashFullyQualifiedName(InUnit, InputDIE); 107 108 uint64_t RuntimeLang = 109 dwarf::toUnsigned(InputDIE.find(dwarf::DW_AT_APPLE_runtime_class)) 110 .value_or(0); 111 112 bool ObjCClassIsImplementation = 113 (RuntimeLang == dwarf::DW_LANG_ObjC || 114 RuntimeLang == dwarf::DW_LANG_ObjC_plus_plus) && 115 dwarf::toUnsigned( 116 InputDIE.find(dwarf::DW_AT_APPLE_objc_complete_type)) 117 .value_or(0); 118 119 saveTypeRecord(AttrInfo.Name, OutDIE, InputDieEntry->getTag(), Hash, 120 ObjCClassIsImplementation, TypeEntry); 121 } 122 } break; 123 case dwarf::DW_TAG_namespace: { 124 if (AttrInfo.Name == nullptr) 125 AttrInfo.Name = 126 GlobalData.getStringPool().insert("(anonymous namespace)").first; 127 128 saveNamespaceRecord(AttrInfo.Name, OutDIE, InputDieEntry->getTag(), 129 TypeEntry); 130 } break; 131 case dwarf::DW_TAG_imported_declaration: { 132 if (AttrInfo.Name != nullptr) 133 saveNamespaceRecord(AttrInfo.Name, OutDIE, InputDieEntry->getTag(), 134 TypeEntry); 135 } break; 136 case dwarf::DW_TAG_compile_unit: 137 case dwarf::DW_TAG_lexical_block: { 138 // Nothing to do. 139 } break; 140 default: 141 if (TypeEntry) 142 // Do not store this kind of accelerator entries for type entries. 143 return; 144 145 if (AttrInfo.HasLiveAddress || AttrInfo.HasRanges) { 146 if (AttrInfo.Name) 147 saveNameRecord(AttrInfo.Name, OutDIE, InputDieEntry->getTag(), 148 InputDieEntry->getTag() == 149 dwarf::DW_TAG_inlined_subroutine); 150 151 // Look for mangled name recursively if mangled name is not known yet. 152 if (!AttrInfo.MangledName) 153 if (const char *LinkageName = InputDIE.getLinkageName()) 154 AttrInfo.MangledName = 155 GlobalData.getStringPool().insert(LinkageName).first; 156 157 if (AttrInfo.MangledName && AttrInfo.MangledName != AttrInfo.Name) 158 saveNameRecord(AttrInfo.MangledName, OutDIE, InputDieEntry->getTag(), 159 InputDieEntry->getTag() == 160 dwarf::DW_TAG_inlined_subroutine); 161 162 // Strip template parameters from the short name. 163 if (AttrInfo.Name && AttrInfo.MangledName != AttrInfo.Name && 164 (InputDieEntry->getTag() != dwarf::DW_TAG_inlined_subroutine)) { 165 if (std::optional<StringRef> Name = 166 StripTemplateParameters(AttrInfo.Name->getKey())) { 167 StringEntry *NameWithoutTemplateParams = 168 GlobalData.getStringPool().insert(*Name).first; 169 170 saveNameRecord(NameWithoutTemplateParams, OutDIE, 171 InputDieEntry->getTag(), true); 172 } 173 } 174 175 if (AttrInfo.Name) 176 saveObjC(InputDieEntry, OutDIE, AttrInfo); 177 } 178 break; 179 } 180 } 181 182 void AcceleratorRecordsSaver::saveObjC(const DWARFDebugInfoEntry *InputDieEntry, 183 DIE *OutDIE, AttributesInfo &AttrInfo) { 184 std::optional<ObjCSelectorNames> Names = 185 getObjCNamesIfSelector(AttrInfo.Name->getKey()); 186 if (!Names) 187 return; 188 189 StringEntry *Selector = 190 GlobalData.getStringPool().insert(Names->Selector).first; 191 saveNameRecord(Selector, OutDIE, InputDieEntry->getTag(), true); 192 StringEntry *ClassName = 193 GlobalData.getStringPool().insert(Names->ClassName).first; 194 saveObjCNameRecord(ClassName, OutDIE, InputDieEntry->getTag()); 195 if (Names->ClassNameNoCategory) { 196 StringEntry *ClassNameNoCategory = 197 GlobalData.getStringPool().insert(*Names->ClassNameNoCategory).first; 198 saveObjCNameRecord(ClassNameNoCategory, OutDIE, InputDieEntry->getTag()); 199 } 200 if (Names->MethodNameNoCategory) { 201 StringEntry *MethodNameNoCategory = 202 GlobalData.getStringPool().insert(*Names->MethodNameNoCategory).first; 203 saveNameRecord(MethodNameNoCategory, OutDIE, InputDieEntry->getTag(), true); 204 } 205 } 206 207 void AcceleratorRecordsSaver::saveNameRecord(StringEntry *Name, DIE *OutDIE, 208 dwarf::Tag Tag, 209 bool AvoidForPubSections) { 210 DwarfUnit::AccelInfo Info; 211 212 Info.Type = DwarfUnit::AccelType::Name; 213 Info.String = Name; 214 Info.OutOffset = OutDIE->getOffset(); 215 Info.Tag = Tag; 216 Info.AvoidForPubSections = AvoidForPubSections; 217 218 OutUnit.getAsCompileUnit()->saveAcceleratorInfo(Info); 219 } 220 void AcceleratorRecordsSaver::saveNamespaceRecord(StringEntry *Name, 221 DIE *OutDIE, dwarf::Tag Tag, 222 TypeEntry *TypeEntry) { 223 if (OutUnit.isCompileUnit()) { 224 assert(TypeEntry == nullptr); 225 DwarfUnit::AccelInfo Info; 226 227 Info.Type = DwarfUnit::AccelType::Namespace; 228 Info.String = Name; 229 Info.OutOffset = OutDIE->getOffset(); 230 Info.Tag = Tag; 231 232 OutUnit.getAsCompileUnit()->saveAcceleratorInfo(Info); 233 return; 234 } 235 236 assert(TypeEntry != nullptr); 237 TypeUnit::TypeUnitAccelInfo Info; 238 Info.Type = DwarfUnit::AccelType::Namespace; 239 Info.String = Name; 240 Info.OutOffset = 0xbaddef; 241 Info.Tag = Tag; 242 Info.OutDIE = OutDIE; 243 Info.TypeEntryBodyPtr = TypeEntry->getValue().load(); 244 245 OutUnit.getAsTypeUnit()->saveAcceleratorInfo(Info); 246 } 247 248 void AcceleratorRecordsSaver::saveObjCNameRecord(StringEntry *Name, DIE *OutDIE, 249 dwarf::Tag Tag) { 250 DwarfUnit::AccelInfo Info; 251 252 Info.Type = DwarfUnit::AccelType::ObjC; 253 Info.String = Name; 254 Info.OutOffset = OutDIE->getOffset(); 255 Info.Tag = Tag; 256 Info.AvoidForPubSections = true; 257 258 OutUnit.getAsCompileUnit()->saveAcceleratorInfo(Info); 259 } 260 261 void AcceleratorRecordsSaver::saveTypeRecord(StringEntry *Name, DIE *OutDIE, 262 dwarf::Tag Tag, 263 uint32_t QualifiedNameHash, 264 bool ObjcClassImplementation, 265 TypeEntry *TypeEntry) { 266 if (OutUnit.isCompileUnit()) { 267 assert(TypeEntry == nullptr); 268 DwarfUnit::AccelInfo Info; 269 270 Info.Type = DwarfUnit::AccelType::Type; 271 Info.String = Name; 272 Info.OutOffset = OutDIE->getOffset(); 273 Info.Tag = Tag; 274 Info.QualifiedNameHash = QualifiedNameHash; 275 Info.ObjcClassImplementation = ObjcClassImplementation; 276 277 OutUnit.getAsCompileUnit()->saveAcceleratorInfo(Info); 278 return; 279 } 280 281 assert(TypeEntry != nullptr); 282 TypeUnit::TypeUnitAccelInfo Info; 283 284 Info.Type = DwarfUnit::AccelType::Type; 285 Info.String = Name; 286 Info.OutOffset = 0xbaddef; 287 Info.Tag = Tag; 288 Info.QualifiedNameHash = QualifiedNameHash; 289 Info.ObjcClassImplementation = ObjcClassImplementation; 290 Info.OutDIE = OutDIE; 291 Info.TypeEntryBodyPtr = TypeEntry->getValue().load(); 292 OutUnit.getAsTypeUnit()->saveAcceleratorInfo(Info); 293 } 294