1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-02-01 05:01:59 +01:00

[dsymutil] Generate Apple accelerator tables

This patch adds support for generating accelerator tables in dsymutil.
This feature was already present in our internal repository but not yet
upstreamed because it requires changes to the Apple accelerator table
implementation.

Differential revision: https://reviews.llvm.org/D42501

llvm-svn: 323655
This commit is contained in:
Jonas Devlieghere 2018-01-29 14:52:50 +00:00
parent e67245cd45
commit 2967253e75
8 changed files with 642 additions and 50 deletions

View File

@ -406,6 +406,68 @@ public:
#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

View File

@ -72,6 +72,8 @@ void AppleAccelTableHeader::setBucketAndHashCount(uint32_t HashCount) {
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 @@ void AppleAccelTableTypeData::emit(AsmPrinter *Asm) const {
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);
}

Binary file not shown.

Binary file not shown.

View File

@ -78,7 +78,7 @@ CHECK: DW_AT_name ("arg")
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: [0x0000000000000019, 0x000000000000001d): DW_OP_reg5 RDI, DW_OP_
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: length = 0x0000001f version = 0x0002 unit_offset = 0x00000000 unit_s
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: ]

View File

@ -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: ]

View File

@ -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 @@ public:
/// 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;
AccelInfo(StringRef Name, const DIE *Die, uint32_t NameOffset,
/// 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;
/// 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<AccelInfo> &getPubnames() const { return Pubnames; }
const std::vector<AccelInfo> &getPubtypes() const { return Pubtypes; }
const std::vector<AccelInfo> &getNamespaces() const { return Namespaces; }
const std::vector<AccelInfo> &getObjC() const { return ObjC; }
/// Get the full path for file \a FileNum in the line table
StringRef getResolvedPath(unsigned FileNum) {
@ -442,6 +471,8 @@ private:
/// @{
std::vector<AccelInfo> Pubnames;
std::vector<AccelInfo> Pubtypes;
std::vector<AccelInfo> Namespaces;
std::vector<AccelInfo> ObjC;
/// @}
/// Cached resolved paths from the line table.
@ -518,18 +549,28 @@ void CompileUnit::noteLocationAttribute(PatchLocation Attr, int64_t PcOffset) {
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);
}
/// 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::addObjCAccelerator(const DIE *Die,
DwarfStringPoolEntryRef Name,
bool SkipPubSection) {
ObjC.emplace_back(Name, Die, SkipPubSection);
}
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 @@ public:
void emitFDE(uint32_t CIEOffset, uint32_t AddreSize, uint32_t Address,
StringRef Bytes);
/// Emit Apple namespaces accelerator table.
void
emitAppleNamespaces(AppleAccelTable<AppleAccelTableStaticOffsetData> &Table);
/// Emit Apple names accelerator table.
void emitAppleNames(AppleAccelTable<AppleAccelTableStaticOffsetData> &Table);
/// Emit Apple Objective-C accelerator table.
void emitAppleObjc(AppleAccelTable<AppleAccelTableStaticOffsetData> &Table);
/// Emit Apple type accelerator table.
void emitAppleTypes(AppleAccelTable<AppleAccelTableStaticTypeData> &Table);
uint32_t getFrameSectionSize() const { return FrameSectionSize; }
};
@ -779,11 +833,49 @@ void DwarfStreamer::emitStrings(const NonRelocatableStringpool &Pool) {
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<AppleAccelTableStaticOffsetData> &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<AppleAccelTableStaticOffsetData> &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<AppleAccelTableStaticOffsetData> &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<AppleAccelTableStaticTypeData> &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 @@ void DwarfStreamer::emitPubSectionForUnit(
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 @@ private:
/// 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 @@ private:
/// 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 @@ private:
/// 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 @@ private:
/// debug_frame section.
uint32_t LastCIEOffset = 0;
/// Apple accelerator tables.
AppleAccelTable<AppleAccelTableStaticOffsetData> AppleNames;
AppleAccelTable<AppleAccelTableStaticOffsetData> AppleNamespaces;
AppleAccelTable<AppleAccelTableStaticOffsetData> AppleObjc;
AppleAccelTable<AppleAccelTableStaticTypeData> AppleTypes;
/// Mapping the PCM filename to the DwoId.
StringMap<uint64_t> ClangModules;
@ -1829,16 +1940,30 @@ PointerIntPair<DeclContext *, 1> DeclContextTree::getChildDeclContext(
}
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.MangledName)
if (const char *MangledName = Die.getName(DINameKind::LinkageName))
Info.MangledName = Linker.StringPool.getEntry(MangledName);
if (!Info.Name && (Info.Name = Die.getName(DINameKind::ShortName)))
Info.NameOffset = Linker.StringPool.getStringOffset(Info.Name);
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 @@ unsigned DwarfLinker::DIECloner::cloneAddressAttribute(
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 @@ unsigned DwarfLinker::DIECloner::cloneScalarAttribute(
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 @@ static bool isTypeTag(uint16_t Tag) {
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 @@ DIE *DwarfLinker::DIECloner::cloneDIE(
// 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::patchLineTableForUnit(CompileUnit &Unit,
}
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 @@ void DwarfLinker::DIECloner::copyAbbrev(
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<DWARFFormValue> 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 @@ void DwarfLinker::DIECloner::cloneAllCompileUnits(DWARFContext &DwarfContext) {
// 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 @@ bool DwarfLinker::link(const DebugMap &Map) {
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);

View File

@ -39,6 +39,9 @@ struct LinkOptions {
/// Do not unique types according to ODR
bool NoODR;
/// Minimize
bool Minimize = false;
/// Do not check swiftmodule timestamp
bool NoTimestamp = false;