Index: llvm/trunk/include/llvm/CodeGen/AccelTable.h =================================================================== --- llvm/trunk/include/llvm/CodeGen/AccelTable.h +++ llvm/trunk/include/llvm/CodeGen/AccelTable.h @@ -406,6 +406,68 @@ #endif }; +/// Accelerator table data implementation for simple accelerator tables with +/// a DIE offset but no actual DIE pointer. +class AppleAccelTableStaticOffsetData : public AppleAccelTableData { +public: + AppleAccelTableStaticOffsetData(uint32_t Offset) : Offset(Offset) {} + + void emit(AsmPrinter *Asm) const override; + + static constexpr AppleAccelTableHeader::Atom Atoms[] = { + AppleAccelTableHeader::Atom(dwarf::DW_ATOM_die_offset, + dwarf::DW_FORM_data4)}; + +#ifndef NDEBUG + void print(raw_ostream &OS) const override { + OS << " Static Offset: " << Offset << "\n"; + } + +#endif +protected: + uint64_t order() const override { return Offset; } + + uint32_t Offset; +}; + +/// Accelerator table data implementation for type accelerator tables with +/// a DIE offset but no actual DIE pointer. +class AppleAccelTableStaticTypeData : public AppleAccelTableStaticOffsetData { +public: + AppleAccelTableStaticTypeData(uint32_t Offset, uint16_t Tag, + bool ObjCClassIsImplementation, + uint32_t QualifiedNameHash) + : AppleAccelTableStaticOffsetData(Offset), + QualifiedNameHash(QualifiedNameHash), Tag(Tag), + ObjCClassIsImplementation(ObjCClassIsImplementation) {} + + void emit(AsmPrinter *Asm) const override; + + static constexpr AppleAccelTableHeader::Atom Atoms[] = { + AppleAccelTableHeader::Atom(dwarf::DW_ATOM_die_offset, + dwarf::DW_FORM_data4), + AppleAccelTableHeader::Atom(dwarf::DW_ATOM_die_tag, dwarf::DW_FORM_data2), + AppleAccelTableHeader::Atom(5, dwarf::DW_FORM_data1), + AppleAccelTableHeader::Atom(6, dwarf::DW_FORM_data4)}; + +#ifndef NDEBUG + void print(raw_ostream &OS) const override { + OS << " Static Offset: " << Offset << "\n"; + OS << " QualifiedNameHash: " << format("%x\n", QualifiedNameHash) << "\n"; + OS << " Tag: " << dwarf::TagString(Tag) << "\n"; + OS << " ObjCClassIsImplementation: " + << (ObjCClassIsImplementation ? "true" : "false"); + OS << "\n"; + } +#endif +protected: + uint64_t order() const override { return Offset; } + + uint32_t QualifiedNameHash; + uint16_t Tag; + bool ObjCClassIsImplementation; +}; + } // end namespace llvm #endif // LLVM_LIB_CODEGEN_ASMPRINTER_DWARFACCELTABLE_H Index: llvm/trunk/lib/CodeGen/AsmPrinter/AccelTable.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/AccelTable.cpp +++ llvm/trunk/lib/CodeGen/AsmPrinter/AccelTable.cpp @@ -72,6 +72,8 @@ constexpr AppleAccelTableHeader::Atom AppleAccelTableTypeData::Atoms[]; constexpr AppleAccelTableHeader::Atom AppleAccelTableOffsetData::Atoms[]; +constexpr AppleAccelTableHeader::Atom AppleAccelTableStaticOffsetData::Atoms[]; +constexpr AppleAccelTableHeader::Atom AppleAccelTableStaticTypeData::Atoms[]; void AppleAccelTableBase::emitHeader(AsmPrinter *Asm) { Header.emit(Asm); } @@ -219,3 +221,15 @@ Asm->EmitInt16(Die->getTag()); Asm->EmitInt8(0); } + +void AppleAccelTableStaticOffsetData::emit(AsmPrinter *Asm) const { + Asm->EmitInt32(Offset); +} + +void AppleAccelTableStaticTypeData::emit(AsmPrinter *Asm) const { + Asm->EmitInt32(Offset); + Asm->EmitInt16(Tag); + Asm->EmitInt8(ObjCClassIsImplementation ? dwarf::DW_FLAG_type_implementation + : 0); + Asm->EmitInt32(QualifiedNameHash); +} Index: llvm/trunk/test/tools/dsymutil/X86/basic-lto-linking-x86.test =================================================================== --- llvm/trunk/test/tools/dsymutil/X86/basic-lto-linking-x86.test +++ llvm/trunk/test/tools/dsymutil/X86/basic-lto-linking-x86.test @@ -78,7 +78,7 @@ CHECK: DW_AT_type (0x0000000000000063 CHECK: DW_AT_location (0x00000000 CHECK: [0x0000000000000000, 0x000000000000000e): DW_OP_reg5 RDI, DW_OP_piece 0x4) -CHECK: DW_TAG_inlined_subroutine +CHECK:[[INC1:0x[0-9a-f]*]]{{.*}}DW_TAG_inlined_subroutine CHECK: DW_AT_abstract_origin (cu + 0x00a7 "inc") CHECK: DW_AT_low_pc (0x0000000100000f63) CHECK: DW_AT_high_pc (0x0000000100000f72) @@ -120,7 +120,7 @@ CHECK: DW_TAG_lexical_block CHECK: DW_AT_low_pc (0x0000000100000f94) CHECK: DW_AT_high_pc (0x0000000100000fa7) -CHECK: DW_TAG_inlined_subroutine +CHECK:[[INC2:0x[0-9a-f]*]]{{.*}}DW_TAG_inlined_subroutine CHECK: DW_AT_abstract_origin (cu + 0x009a "inc") CHECK: DW_AT_ranges (0x00000000 CHECK: [0x0000000100000f94, 0x0000000100000f9a) @@ -197,3 +197,194 @@ CHECK-NEXT: Offset Name CHECK-NEXT: 0x00000063 "int" CHECK-NEXT: 0x00000079 "char" + +CHECK: .apple_names contents: +CHECK-NEXT: Header { +CHECK-NEXT: Magic: 0x48415348 +CHECK-NEXT: Version: 0x1 +CHECK-NEXT: Hash function: 0x0 +CHECK-NEXT: Bucket count: 7 +CHECK-NEXT: Hashes count: 7 +CHECK-NEXT: HeaderData length: 12 +CHECK-NEXT: } +CHECK-NEXT: DIE offset base: 0 +CHECK-NEXT: Number of atoms: 1 +CHECK-NEXT: Atoms [ +CHECK-NEXT: Atom 0 { +CHECK-NEXT: Type: DW_ATOM_die_offset +CHECK-NEXT: Form: DW_FORM_data4 +CHECK-NEXT: } +CHECK-NEXT: ] +CHECK-NEXT: Bucket 0 [ +CHECK-NEXT: Hash 0xb8860c2 [ +CHECK-NEXT: Name@0x74 { +CHECK-NEXT: String: 0x0000007e "baz" +CHECK-NEXT: Data 0 [ +CHECK-NEXT: Atom[0]: 0x000000c0 +CHECK-NEXT: ] +CHECK-NEXT: } +CHECK-NEXT: ] +CHECK-NEXT: Hash 0xb88801f [ +CHECK-NEXT: Name@0x84 { +CHECK-NEXT: String: 0x0000008a "inc" +CHECK-NEXT: Data 0 [ +CHECK-NEXT: Atom[0]: 0x00000110 +CHECK-NEXT: ] +CHECK-NEXT: Data 1 [ +CHECK-NEXT: Atom[0]: 0x000001c7 +CHECK-NEXT: ] +CHECK-NEXT: } +CHECK-NEXT: ] +CHECK-NEXT: ] +CHECK-NEXT: Bucket 1 [ +CHECK-NEXT: EMPTY +CHECK-NEXT: ] +CHECK-NEXT: Bucket 2 [ +CHECK-NEXT: Hash 0xfed12c6a [ +CHECK-NEXT: Name@0x98 { +CHECK-NEXT: String: 0x00000072 "private_int" +CHECK-NEXT: Data 0 [ +CHECK-NEXT: Atom[0]: 0x000000a7 +CHECK-NEXT: ] +CHECK-NEXT: } +CHECK-NEXT: ] +CHECK-NEXT: ] +CHECK-NEXT: Bucket 3 [ +CHECK-NEXT: Hash 0xb88b5c8 [ +CHECK-NEXT: Name@0xa8 { +CHECK-NEXT: String: 0x00000097 "val" +CHECK-NEXT: Data 0 [ +CHECK-NEXT: Atom[0]: 0x00000160 +CHECK-NEXT: ] +CHECK-NEXT: } +CHECK-NEXT: ] +CHECK-NEXT: Hash 0x7c9a7f6a [ +CHECK-NEXT: Name@0xb8 { +CHECK-NEXT: String: 0x00000051 "main" +CHECK-NEXT: Data 0 [ +CHECK-NEXT: Atom[0]: 0x00000026 +CHECK-NEXT: ] +CHECK-NEXT: } +CHECK-NEXT: ] +CHECK-NEXT: ] +CHECK-NEXT: Bucket 4 [ +CHECK-NEXT: EMPTY +CHECK-NEXT: ] +CHECK-NEXT: Bucket 5 [ +CHECK-NEXT: Hash 0xb887389 [ +CHECK-NEXT: Name@0xc8 { +CHECK-NEXT: String: 0x00000082 "foo" +CHECK-NEXT: Data 0 [ +CHECK-NEXT: Atom[0]: 0x000000d9 +CHECK-NEXT: ] +CHECK-NEXT: } +CHECK-NEXT: ] +CHECK-NEXT: ] +CHECK-NEXT: Bucket 6 [ +CHECK-NEXT: Hash 0xb8860ba [ +CHECK-NEXT: Name@0xd8 { +CHECK-NEXT: String: 0x0000009b "bar" +CHECK-NEXT: Data 0 [ +CHECK-NEXT: Atom[0]: 0x0000017f +CHECK-NEXT: ] +CHECK-NEXT: } +CHECK-NEXT: ] +CHECK-NEXT: ] + +CHECK: apple_types contents: +CHECK-NEXT: Header { +CHECK-NEXT: Magic: 0x48415348 +CHECK-NEXT: Version: 0x1 +CHECK-NEXT: Hash function: 0x0 +CHECK-NEXT: Bucket count: 2 +CHECK-NEXT: Hashes count: 2 +CHECK-NEXT: HeaderData length: 24 +CHECK-NEXT: } +CHECK-NEXT: DIE offset base: 0 +CHECK-NEXT: Number of atoms: 4 +CHECK-NEXT: Atoms [ +CHECK-NEXT: Atom 0 { +CHECK-NEXT: Type: DW_ATOM_die_offset +CHECK-NEXT: Form: DW_FORM_data4 +CHECK-NEXT: } +CHECK-NEXT: Atom 1 { +CHECK-NEXT: Type: DW_ATOM_die_tag +CHECK-NEXT: Form: DW_FORM_data2 +CHECK-NEXT: } +CHECK-NEXT: Atom 2 { +CHECK-NEXT: Type: DW_ATOM_type_flags +CHECK-NEXT: Form: DW_FORM_data1 +CHECK-NEXT: } +CHECK-NEXT: Atom 3 { +CHECK-NEXT: Type: DW_ATOM_qual_name_hash +CHECK-NEXT: Form: DW_FORM_data4 +CHECK-NEXT: } +CHECK-NEXT: ] +CHECK-NEXT: Bucket 0 [ +CHECK-NEXT: Hash 0xb888030 [ +CHECK-NEXT: Name@0x44 { +CHECK-NEXT: String: 0x00000060 "int" +CHECK-NEXT: Data 0 [ +CHECK-NEXT: Atom[0]: 0x00000063 +CHECK-NEXT: Atom[1]: 0x0024 +CHECK-NEXT: Atom[2]: 0x00 +CHECK-NEXT: Atom[3]: 0x0c3a28a4 +CHECK-NEXT: ] +CHECK-NEXT: } +CHECK-NEXT: ] +CHECK-NEXT: ] +CHECK-NEXT: Bucket 1 [ +CHECK-NEXT: Hash 0x7c952063 [ +CHECK-NEXT: Name@0x5b { +CHECK-NEXT: String: 0x00000064 "char" +CHECK-NEXT: Data 0 [ +CHECK-NEXT: Atom[0]: 0x00000079 +CHECK-NEXT: Atom[1]: 0x0024 +CHECK-NEXT: Atom[2]: 0x00 +CHECK-NEXT: Atom[3]: 0x937bd757 +CHECK-NEXT: ] +CHECK-NEXT: } +CHECK-NEXT: ] +CHECK-NEXT: ] + +CHECK: .apple_namespaces contents: +CHECK-NEXT: Header { +CHECK-NEXT: Magic: 0x48415348 +CHECK-NEXT: Version: 0x1 +CHECK-NEXT: Hash function: 0x0 +CHECK-NEXT: Bucket count: 1 +CHECK-NEXT: Hashes count: 0 +CHECK-NEXT: HeaderData length: 12 +CHECK-NEXT: } +CHECK-NEXT: DIE offset base: 0 +CHECK-NEXT: Number of atoms: 1 +CHECK-NEXT: Atoms [ +CHECK-NEXT: Atom 0 { +CHECK-NEXT: Type: DW_ATOM_die_offset +CHECK-NEXT: Form: DW_FORM_data4 +CHECK-NEXT: } +CHECK-NEXT: ] +CHECK-NEXT: Bucket 0 [ +CHECK-NEXT: EMPTY +CHECK-NEXT: ] + +CHECK: .apple_objc contents: +CHECK-NEXT: Header { +CHECK-NEXT: Magic: 0x48415348 +CHECK-NEXT: Version: 0x1 +CHECK-NEXT: Hash function: 0x0 +CHECK-NEXT: Bucket count: 1 +CHECK-NEXT: Hashes count: 0 +CHECK-NEXT: HeaderData length: 12 +CHECK-NEXT: } +CHECK-NEXT: DIE offset base: 0 +CHECK-NEXT: Number of atoms: 1 +CHECK-NEXT: Atoms [ +CHECK-NEXT: Atom 0 { +CHECK-NEXT: Type: DW_ATOM_die_offset +CHECK-NEXT: Form: DW_FORM_data4 +CHECK-NEXT: } +CHECK-NEXT: ] +CHECK-NEXT: Bucket 0 [ +CHECK-NEXT: EMPTY +CHECK-NEXT: ] Index: llvm/trunk/test/tools/dsymutil/X86/objc.test =================================================================== --- llvm/trunk/test/tools/dsymutil/X86/objc.test +++ llvm/trunk/test/tools/dsymutil/X86/objc.test @@ -0,0 +1,52 @@ +RUN: llvm-dsymutil -f -oso-prepend-path=%p/.. %p/../Inputs/objc.macho.x86_64 -o - \ +RUN: | llvm-dwarfdump -apple-types -apple-objc - | FileCheck %s + +CHECK: .apple_types contents: +CHECK: String: 0x00000066 "A" +CHECK-NEXT: Data 0 [ +CHECK-NEXT: Atom[0]: 0x0000012d +CHECK-NEXT: Atom[1]: 0x0013 +CHECK-NEXT: Atom[2]: 0x02 +CHECK-NEXT: Atom[3]: 0x0b87b15a +CHECK-NEXT: ] + +CHECK: .apple_objc contents: +CHECK-NEXT: Header { +CHECK-NEXT: Magic: 0x48415348 +CHECK-NEXT: Version: 0x1 +CHECK-NEXT: Hash function: 0x0 +CHECK-NEXT: Bucket count: 2 +CHECK-NEXT: Hashes count: 2 +CHECK-NEXT: HeaderData length: 12 +CHECK-NEXT: } +CHECK-NEXT: DIE offset base: 0 +CHECK-NEXT: Number of atoms: 1 +CHECK-NEXT: Atoms [ +CHECK-NEXT: Atom 0 { +CHECK-NEXT: Type: DW_ATOM_die_offset +CHECK-NEXT: Form: DW_FORM_data4 +CHECK-NEXT: } +CHECK-NEXT: ] +CHECK-NEXT: Bucket 0 [ +CHECK-NEXT: Hash 0x2b5e6 [ +CHECK-NEXT: Name@0x38 { +CHECK-NEXT: String: 0x00000066 "A" +CHECK-NEXT: Data 0 [ +CHECK-NEXT: Atom[0]: 0x00000027 +CHECK-NEXT: ] +CHECK-NEXT: Data 1 [ +CHECK-NEXT: Atom[0]: 0x0000007a +CHECK-NEXT: ] +CHECK-NEXT: } +CHECK-NEXT: ] +CHECK-NEXT: ] +CHECK-NEXT: Bucket 1 [ +CHECK-NEXT: Hash 0x3fa0f4b5 [ +CHECK-NEXT: Name@0x4c { +CHECK-NEXT: String: 0x0000009d "A(Category)" +CHECK-NEXT: Data 0 [ +CHECK-NEXT: Atom[0]: 0x0000007a +CHECK-NEXT: ] +CHECK-NEXT: } +CHECK-NEXT: ] +CHECK-NEXT: ] Index: llvm/trunk/tools/dsymutil/DwarfLinker.cpp =================================================================== --- llvm/trunk/tools/dsymutil/DwarfLinker.cpp +++ llvm/trunk/tools/dsymutil/DwarfLinker.cpp @@ -30,6 +30,7 @@ #include "llvm/ADT/Twine.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/BinaryFormat/MachO.h" +#include "llvm/CodeGen/AccelTable.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/DIE.h" #include "llvm/Config/config.h" @@ -62,6 +63,7 @@ #include "llvm/Support/Allocator.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/DJB.h" #include "llvm/Support/DataExtractor.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" @@ -357,29 +359,56 @@ /// debug_loc section. void noteLocationAttribute(PatchLocation Attr, int64_t PcOffset); - /// Add a name accelerator entry for \p Die with \p Name which is stored in - /// the string table at \p Offset. - void addNameAccelerator(const DIE *Die, const char *Name, uint32_t Offset, + /// Add a name accelerator entry for \a Die with \a Name. + void addNamespaceAccelerator(const DIE *Die, DwarfStringPoolEntryRef Name); + + /// Add a name accelerator entry for \a Die with \a Name. + void addNameAccelerator(const DIE *Die, DwarfStringPoolEntryRef Name, + bool SkipPubnamesSection = false); + + /// Add various accelerator entries for \p Die with \p Name which is stored + /// in the string table at \p Offset. \p Name must be an Objective-C + /// selector. + void addObjCAccelerator(const DIE *Die, DwarfStringPoolEntryRef Name, bool SkipPubnamesSection = false); /// Add a type accelerator entry for \p Die with \p Name which is stored in /// the string table at \p Offset. - void addTypeAccelerator(const DIE *Die, const char *Name, uint32_t Offset); + void addTypeAccelerator(const DIE *Die, DwarfStringPoolEntryRef Name, + bool ObjcClassImplementation, + uint32_t QualifiedNameHash); struct AccelInfo { - StringRef Name; ///< Name of the entry. - const DIE *Die; ///< DIE this entry describes. - uint32_t NameOffset; ///< Offset of Name in the string pool. - bool SkipPubSection; ///< Emit this entry only in the apple_* sections. + /// Name of the entry. + DwarfStringPoolEntryRef Name; + + /// DIE this entry describes. + const DIE *Die; + + /// Hash of the fully qualified name. + uint32_t QualifiedNameHash; + + /// Emit this entry only in the apple_* sections. + bool SkipPubSection; - AccelInfo(StringRef Name, const DIE *Die, uint32_t NameOffset, + /// Is this an ObjC class implem? + bool ObjcClassImplementation; + + AccelInfo(DwarfStringPoolEntryRef Name, const DIE *Die, bool SkipPubSection = false) - : Name(Name), Die(Die), NameOffset(NameOffset), - SkipPubSection(SkipPubSection) {} + : Name(Name), Die(Die), SkipPubSection(SkipPubSection) {} + + AccelInfo(DwarfStringPoolEntryRef Name, const DIE *Die, + uint32_t QualifiedNameHash, bool ObjCClassIsImplementation) + : Name(Name), Die(Die), QualifiedNameHash(QualifiedNameHash), + SkipPubSection(false), + ObjcClassImplementation(ObjCClassIsImplementation) {} }; const std::vector &getPubnames() const { return Pubnames; } const std::vector &getPubtypes() const { return Pubtypes; } + const std::vector &getNamespaces() const { return Namespaces; } + const std::vector &getObjC() const { return ObjC; } /// Get the full path for file \a FileNum in the line table StringRef getResolvedPath(unsigned FileNum) { @@ -442,6 +471,8 @@ /// @{ std::vector Pubnames; std::vector Pubtypes; + std::vector Namespaces; + std::vector ObjC; /// @} /// Cached resolved paths from the line table. @@ -518,18 +549,28 @@ LocationAttributes.emplace_back(Attr, PcOffset); } -/// Add a name accelerator entry for \p Die with \p Name -/// which is stored in the string table at \p Offset. -void CompileUnit::addNameAccelerator(const DIE *Die, const char *Name, - uint32_t Offset, bool SkipPubSection) { - Pubnames.emplace_back(Name, Die, Offset, SkipPubSection); +void CompileUnit::addNamespaceAccelerator(const DIE *Die, + DwarfStringPoolEntryRef Name) { + Namespaces.emplace_back(Name, Die); +} + +void CompileUnit::addObjCAccelerator(const DIE *Die, + DwarfStringPoolEntryRef Name, + bool SkipPubSection) { + ObjC.emplace_back(Name, Die, SkipPubSection); } -/// Add a type accelerator entry for \p Die with \p Name -/// which is stored in the string table at \p Offset. -void CompileUnit::addTypeAccelerator(const DIE *Die, const char *Name, - uint32_t Offset) { - Pubtypes.emplace_back(Name, Die, Offset, false); +void CompileUnit::addNameAccelerator(const DIE *Die, + DwarfStringPoolEntryRef Name, + bool SkipPubSection) { + Pubnames.emplace_back(Name, Die, SkipPubSection); +} + +void CompileUnit::addTypeAccelerator(const DIE *Die, + DwarfStringPoolEntryRef Name, + bool ObjcClassImplementation, + uint32_t QualifiedNameHash) { + Pubtypes.emplace_back(Name, Die, QualifiedNameHash, ObjcClassImplementation); } namespace { @@ -642,6 +683,19 @@ void emitFDE(uint32_t CIEOffset, uint32_t AddreSize, uint32_t Address, StringRef Bytes); + /// Emit Apple namespaces accelerator table. + void + emitAppleNamespaces(AppleAccelTable &Table); + + /// Emit Apple names accelerator table. + void emitAppleNames(AppleAccelTable &Table); + + /// Emit Apple Objective-C accelerator table. + void emitAppleObjc(AppleAccelTable &Table); + + /// Emit Apple type accelerator table. + void emitAppleTypes(AppleAccelTable &Table); + uint32_t getFrameSectionSize() const { return FrameSectionSize; } }; @@ -779,11 +833,49 @@ for (auto Entry : Entries) { if (Entry.getIndex() == -1U) break; - Asm->OutStreamer->EmitBytes( - StringRef(Entry.getString().data(), Entry.getString().size() + 1)); + // Emit the string itself. + Asm->OutStreamer->EmitBytes(Entry.getString()); + // Emit a null terminator. + Asm->EmitInt8(0); } } +void DwarfStreamer::emitAppleNamespaces( + AppleAccelTable &Table) { + Asm->OutStreamer->SwitchSection(MOFI->getDwarfAccelNamespaceSection()); + Table.finalizeTable(Asm.get(), "namespac"); + auto *SectionBegin = Asm->createTempSymbol("namespac_begin"); + Asm->OutStreamer->EmitLabel(SectionBegin); + Table.emit(Asm.get(), SectionBegin); +} + +void DwarfStreamer::emitAppleNames( + AppleAccelTable &Table) { + Asm->OutStreamer->SwitchSection(MOFI->getDwarfAccelNamesSection()); + Table.finalizeTable(Asm.get(), "names"); + auto *SectionBegin = Asm->createTempSymbol("names_begin"); + Asm->OutStreamer->EmitLabel(SectionBegin); + Table.emit(Asm.get(), SectionBegin); +} + +void DwarfStreamer::emitAppleObjc( + AppleAccelTable &Table) { + Asm->OutStreamer->SwitchSection(MOFI->getDwarfAccelObjCSection()); + Table.finalizeTable(Asm.get(), "objc"); + auto *SectionBegin = Asm->createTempSymbol("objc_begin"); + Asm->OutStreamer->EmitLabel(SectionBegin); + Table.emit(Asm.get(), SectionBegin); +} + +void DwarfStreamer::emitAppleTypes( + AppleAccelTable &Table) { + Asm->OutStreamer->SwitchSection(MOFI->getDwarfAccelTypesSection()); + Table.finalizeTable(Asm.get(), "types"); + auto *SectionBegin = Asm->createTempSymbol("types_begin"); + Asm->OutStreamer->EmitLabel(SectionBegin); + Table.emit(Asm.get(), SectionBegin); +} + /// Emit the swift_ast section stored in \p Buffers. void DwarfStreamer::emitSwiftAST(StringRef Buffer) { MCSection *SwiftASTSection = MOFI->getDwarfSwiftASTSection(); @@ -1137,8 +1229,11 @@ HeaderEmitted = true; } Asm->EmitInt32(Name.Die->getOffset()); - Asm->OutStreamer->EmitBytes( - StringRef(Name.Name.data(), Name.Name.size() + 1)); + + // Emit the string itself. + Asm->OutStreamer->EmitBytes(Name.Name.getString()); + // Emit a null terminator. + Asm->EmitInt8(0); } if (!HeaderEmitted) @@ -1396,8 +1491,7 @@ /// clone*Attributes helpers about the attributes of a particular DIE. struct AttributesInfo { /// Names. - const char *Name = nullptr; - const char *MangledName = nullptr; + DwarfStringPoolEntryRef Name, MangledName, NameWithoutTemplate; /// Offsets in the string pool. uint32_t NameOffset = 0; @@ -1415,6 +1509,9 @@ /// Does the DIE have a low_pc attribute? bool HasLowPc = false; + /// Does the DIE have a ranges attribute? + bool HasRanges = false; + /// Is this DIE only a declaration? bool IsDeclaration = false; @@ -1470,10 +1567,18 @@ /// described by \p Die and store them in \Info if they are not /// already there. /// \returns is a name was found. - bool getDIENames(const DWARFDie &Die, AttributesInfo &Info); + bool getDIENames(const DWARFDie &Die, AttributesInfo &Info, + bool StripTemplate = false); /// Create a copy of abbreviation Abbrev. void copyAbbrev(const DWARFAbbreviationDeclaration &Abbrev, bool hasODR); + + uint32_t hashFullyQualifiedName(DWARFDie DIE, CompileUnit &U, + int RecurseDepth = 0); + + /// Helper for cloneDIE. + void addObjCAccelerator(CompileUnit &Unit, const DIE *Die, + DwarfStringPoolEntryRef Name, bool SkipPubSection); }; /// Assign an abbreviation number to \p Abbrev @@ -1569,6 +1674,12 @@ /// debug_frame section. uint32_t LastCIEOffset = 0; + /// Apple accelerator tables. + AppleAccelTable AppleNames; + AppleAccelTable AppleNamespaces; + AppleAccelTable AppleObjc; + AppleAccelTable AppleTypes; + /// Mapping the PCM filename to the DwoId. StringMap ClangModules; @@ -1829,16 +1940,30 @@ } bool DwarfLinker::DIECloner::getDIENames(const DWARFDie &Die, - AttributesInfo &Info) { + AttributesInfo &Info, + bool StripTemplate) { + // This function will be called on DIEs having low_pcs and + // ranges. As getting the name might be more expansive, filter out + // blocks directly. + if (Die.getTag() == dwarf::DW_TAG_lexical_block) + return false; + // FIXME: a bit wasteful as the first getName might return the // short name. - if (!Info.MangledName && - (Info.MangledName = Die.getName(DINameKind::LinkageName))) - Info.MangledNameOffset = - Linker.StringPool.getStringOffset(Info.MangledName); - - if (!Info.Name && (Info.Name = Die.getName(DINameKind::ShortName))) - Info.NameOffset = Linker.StringPool.getStringOffset(Info.Name); + if (!Info.MangledName) + if (const char *MangledName = Die.getName(DINameKind::LinkageName)) + Info.MangledName = Linker.StringPool.getEntry(MangledName); + + if (!Info.Name) + if (const char *Name = Die.getName(DINameKind::ShortName)) + Info.Name = Linker.StringPool.getEntry(Name); + + if (StripTemplate && Info.Name && Info.MangledName != Info.Name) { + // FIXME: dsymutil compatibility. This is wrong for operator< + auto Split = Info.Name.getString().split('<'); + if (!Split.second.empty()) + Info.NameWithoutTemplate = Linker.StringPool.getEntry(Split.first); + } return Info.Name || Info.MangledName; } @@ -2623,6 +2748,7 @@ DIE &Die, AttributeSpec AttrSpec, const DWARFFormValue &Val, const CompileUnit &Unit, AttributesInfo &Info) { uint64_t Addr = *Val.getAsAddress(); + if (AttrSpec.Attr == dwarf::DW_AT_low_pc) { if (Die.getTag() == dwarf::DW_TAG_inlined_subroutine || Die.getTag() == dwarf::DW_TAG_lexical_block) @@ -2684,8 +2810,10 @@ PatchLocation Patch = Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr), dwarf::Form(AttrSpec.Form), DIEInteger(Value)); - if (AttrSpec.Attr == dwarf::DW_AT_ranges) + if (AttrSpec.Attr == dwarf::DW_AT_ranges) { Unit.noteRangeAttribute(Die, Patch); + Info.HasRanges = true; + } // A more generic way to check for location attributes would be // nice, but it's very unlikely that any other attribute needs a @@ -2825,6 +2953,55 @@ return false; } +static bool isObjCSelector(StringRef Name) { + return Name.size() > 2 && (Name[0] == '-' || Name[0] == '+') && + (Name[1] == '['); +} + +void DwarfLinker::DIECloner::addObjCAccelerator(CompileUnit &Unit, + const DIE *Die, + DwarfStringPoolEntryRef Name, + bool SkipPubSection) { + assert(isObjCSelector(Name.getString()) && "not an objc selector"); + // Objective C method or class function. + // "- [Class(Category) selector :withArg ...]" + StringRef ClassNameStart(Name.getString().drop_front(2)); + size_t FirstSpace = ClassNameStart.find(' '); + if (FirstSpace == StringRef::npos) + return; + + StringRef SelectorStart(ClassNameStart.data() + FirstSpace + 1); + if (!SelectorStart.size()) + return; + + StringRef Selector(SelectorStart.data(), SelectorStart.size() - 1); + Unit.addNameAccelerator(Die, Linker.StringPool.getEntry(Selector), + SkipPubSection); + + // Add an entry for the class name that points to this + // method/class function. + StringRef ClassName(ClassNameStart.data(), FirstSpace); + Unit.addObjCAccelerator(Die, Linker.StringPool.getEntry(ClassName), + SkipPubSection); + + if (ClassName[ClassName.size() - 1] == ')') { + size_t OpenParens = ClassName.find('('); + if (OpenParens != StringRef::npos) { + StringRef ClassNameNoCategory(ClassName.data(), OpenParens); + Unit.addObjCAccelerator( + Die, Linker.StringPool.getEntry(ClassNameNoCategory), SkipPubSection); + + std::string MethodNameNoCategory(Name.getString().data(), OpenParens + 2); + // FIXME: The missing space here may be a bug, but + // dsymutil-classic also does it this way. + MethodNameNoCategory.append(SelectorStart); + Unit.addNameAccelerator(Die, + Linker.StringPool.getEntry(MethodNameNoCategory), + SkipPubSection); + } + } +} + static bool shouldSkipAttribute(DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, uint16_t Tag, bool InDebugMap, bool SkipPC, @@ -2965,25 +3142,46 @@ // FIXME: This is slightly wrong. An inline_subroutine without a // low_pc, but with AT_ranges might be interesting to get into the // accelerator tables too. For now stick with dsymutil's behavior. - if ((Info.InDebugMap || AttrInfo.HasLowPc) && + if ((Info.InDebugMap || AttrInfo.HasLowPc || AttrInfo.HasRanges) && Tag != dwarf::DW_TAG_compile_unit && - getDIENames(InputDIE, AttrInfo)) { + getDIENames(InputDIE, AttrInfo, + Tag != dwarf::DW_TAG_inlined_subroutine)) { if (AttrInfo.MangledName && AttrInfo.MangledName != AttrInfo.Name) Unit.addNameAccelerator(Die, AttrInfo.MangledName, - AttrInfo.MangledNameOffset, Tag == dwarf::DW_TAG_inlined_subroutine); - if (AttrInfo.Name) - Unit.addNameAccelerator(Die, AttrInfo.Name, AttrInfo.NameOffset, + if (AttrInfo.Name) { + if (AttrInfo.NameWithoutTemplate) + Unit.addNameAccelerator(Die, AttrInfo.NameWithoutTemplate, + /* SkipPubSection */ true); + Unit.addNameAccelerator(Die, AttrInfo.Name, Tag == dwarf::DW_TAG_inlined_subroutine); + } + if (AttrInfo.Name && isObjCSelector(AttrInfo.Name.getString())) + addObjCAccelerator(Unit, Die, AttrInfo.Name, /* SkipPubSection =*/true); + + } else if (Tag == dwarf::DW_TAG_namespace) { + if (!AttrInfo.Name) + AttrInfo.Name = Linker.StringPool.getEntry("(anonymous namespace)"); + Unit.addNamespaceAccelerator(Die, AttrInfo.Name); } else if (isTypeTag(Tag) && !AttrInfo.IsDeclaration && - getDIENames(InputDIE, AttrInfo)) { - if (AttrInfo.Name) - Unit.addTypeAccelerator(Die, AttrInfo.Name, AttrInfo.NameOffset); + getDIENames(InputDIE, AttrInfo) && AttrInfo.Name && + AttrInfo.Name.getString()[0]) { + uint32_t Hash = hashFullyQualifiedName(InputDIE, Unit); + uint64_t RuntimeLang = + dwarf::toUnsigned(InputDIE.find(dwarf::DW_AT_APPLE_runtime_class)) + .getValueOr(0); + bool ObjCClassIsImplementation = + (RuntimeLang == dwarf::DW_LANG_ObjC || + RuntimeLang == dwarf::DW_LANG_ObjC_plus_plus) && + dwarf::toUnsigned(InputDIE.find(dwarf::DW_AT_APPLE_objc_complete_type)) + .getValueOr(0); + Unit.addTypeAccelerator(Die, AttrInfo.Name, ObjCClassIsImplementation, + Hash); } // Determine whether there are any children that we want to keep. bool HasChildren = false; - for (auto Child: InputDIE.children()) { + for (auto Child : InputDIE.children()) { unsigned Idx = U.getDIEIndex(Child); if (Unit.getInfo(Idx).Keep) { HasChildren = true; @@ -3263,8 +3461,32 @@ } void DwarfLinker::emitAcceleratorEntriesForUnit(CompileUnit &Unit) { - Streamer->emitPubNamesForUnit(Unit); - Streamer->emitPubTypesForUnit(Unit); + // Add namespaces. + for (const auto &Namespace : Unit.getNamespaces()) + AppleNamespaces.addName(Namespace.Name, + Namespace.Die->getOffset() + Unit.getStartOffset()); + + /// Add names. + if (!Options.Minimize) + Streamer->emitPubNamesForUnit(Unit); + for (const auto &Pubname : Unit.getPubnames()) + AppleNames.addName(Pubname.Name, + Pubname.Die->getOffset() + Unit.getStartOffset()); + + /// Add types. + if (!Options.Minimize) + Streamer->emitPubTypesForUnit(Unit); + for (const auto &Pubtype : Unit.getPubtypes()) + AppleTypes.addName( + Pubtype.Name, Pubtype.Die->getOffset() + Unit.getStartOffset(), + Pubtype.Die->getTag(), + Pubtype.ObjcClassImplementation ? dwarf::DW_FLAG_type_implementation + : 0, + Pubtype.QualifiedNameHash); + + /// Add ObjC names. + for (const auto &ObjC : Unit.getObjC()) + AppleObjc.addName(ObjC.Name, ObjC.Die->getOffset() + Unit.getStartOffset()); } /// Read the frame info stored in the object, and emit the @@ -3367,6 +3589,50 @@ Linker.AssignAbbrev(Copy); } +uint32_t DwarfLinker::DIECloner::hashFullyQualifiedName(DWARFDie DIE, + CompileUnit &U, + int RecurseDepth) { + const char *Name = nullptr; + DWARFUnit *OrigUnit = &U.getOrigUnit(); + CompileUnit *CU = &U; + Optional Ref; + + while (1) { + if (const char *CurrentName = DIE.getName(DINameKind::ShortName)) + Name = CurrentName; + + if (!(Ref = DIE.find(dwarf::DW_AT_specification)) && + !(Ref = DIE.find(dwarf::DW_AT_abstract_origin))) + break; + + if (!Ref->isFormClass(DWARFFormValue::FC_Reference)) + break; + + CompileUnit *RefCU; + if (auto RefDIE = resolveDIEReference(Linker, CompileUnits, *Ref, + U.getOrigUnit(), DIE, RefCU)) { + CU = RefCU; + OrigUnit = &RefCU->getOrigUnit(); + DIE = RefDIE; + } + } + + unsigned Idx = OrigUnit->getDIEIndex(DIE); + if (!Name && DIE.getTag() == dwarf::DW_TAG_namespace) + Name = "(anonymous namespace)"; + + if (CU->getInfo(Idx).ParentIdx == 0 || + // FIXME: dsymutil-classic compatibility. Ignore modules. + CU->getOrigUnit().getDIEAtIndex(CU->getInfo(Idx).ParentIdx).getTag() == + dwarf::DW_TAG_module) + return djbHash(Name ? Name : "", djbHash(RecurseDepth ? "" : "::")); + + DWARFDie Die = OrigUnit->getDIEAtIndex(CU->getInfo(Idx).ParentIdx); + return djbHash((Name ? Name : ""), + djbHash((Name ? "::" : ""), + hashFullyQualifiedName(Die, *CU, ++RecurseDepth))); +} + static uint64_t getDwoId(const DWARFDie &CUDie, const DWARFUnit &Unit) { auto DwoId = dwarf::toUnsigned(CUDie.find({dwarf::DW_AT_dwo_id, @@ -3565,9 +3831,9 @@ // an empty line table for the unit, even if the unit doesn't // actually exist in the DIE tree. Linker.patchLineTableForUnit(*CurrentUnit, DwarfContext); + Linker.emitAcceleratorEntriesForUnit(*CurrentUnit); Linker.patchRangesForUnit(*CurrentUnit, DwarfContext); Linker.Streamer->emitLocationsForUnit(*CurrentUnit, DwarfContext); - Linker.emitAcceleratorEntriesForUnit(*CurrentUnit); } if (Linker.Options.NoOutput) @@ -3695,6 +3961,10 @@ if (!Options.NoOutput) { Streamer->emitAbbrevs(Abbreviations, MaxDwarfVersion); Streamer->emitStrings(StringPool); + Streamer->emitAppleNames(AppleNames); + Streamer->emitAppleNamespaces(AppleNamespaces); + Streamer->emitAppleTypes(AppleTypes); + Streamer->emitAppleObjc(AppleObjc); } return Options.NoOutput ? true : Streamer->finish(Map); Index: llvm/trunk/tools/dsymutil/dsymutil.h =================================================================== --- llvm/trunk/tools/dsymutil/dsymutil.h +++ llvm/trunk/tools/dsymutil/dsymutil.h @@ -39,6 +39,9 @@ /// Do not unique types according to ODR bool NoODR; + /// Minimize + bool Minimize = false; + /// Do not check swiftmodule timestamp bool NoTimestamp = false;