294 lines · cpp
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-exception6//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 14using namespace llvm;15using namespace dwarf_linker;16using namespace dwarf_linker::parallel;17 18static 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 63void 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 182void 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 207void 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}220void 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 248void 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 261void 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