mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 20:51:52 +01:00
[MC] Add assembler support for .cg_profile.
Object FIle Representation At codegen time this is emitted into the ELF file a pair of symbol indices and a weight. In assembly it looks like: .cg_profile a, b, 32 .cg_profile freq, a, 11 .cg_profile freq, b, 20 When writing an ELF file these are put into a SHT_LLVM_CALL_GRAPH_PROFILE (0x6fff4c02) section as (uint32_t, uint32_t, uint64_t) tuples as (from symbol index, to symbol index, weight). Differential Revision: https://reviews.llvm.org/D44965 llvm-svn: 333823
This commit is contained in:
parent
ed2c720917
commit
cf322e810a
@ -285,6 +285,50 @@ The following directives are specified:
|
||||
The paramter identifies an additional library search path to be considered
|
||||
when looking up libraries after the inclusion of this option.
|
||||
|
||||
``SHT_LLVM_CALL_GRAPH_PROFILE`` Section (Call Graph Profile)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This section is used to pass a call graph profile to the linker which can be
|
||||
used to optimize the placement of sections. It contains a sequence of
|
||||
(from symbol, to symbol, weight) tuples.
|
||||
|
||||
It shall have a type of ``SHT_LLVM_CALL_GRAPH_PROFILE`` (0x6fff4c02), shall
|
||||
have the ``SHF_EXCLUDE`` flag set, the ``sh_link`` member shall hold the section
|
||||
header index of the associated symbol table, and shall have a ``sh_entsize`` of
|
||||
16. It should be named ``.llvm.call-graph-profile``.
|
||||
|
||||
The contents of the section shall be a sequence of ``Elf_CGProfile`` entries.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
typedef struct {
|
||||
Elf_Word cgp_from;
|
||||
Elf_Word cgp_to;
|
||||
Elf_Xword cgp_weight;
|
||||
} Elf_CGProfile;
|
||||
|
||||
cgp_from
|
||||
The symbol index of the source of the edge.
|
||||
|
||||
cgp_to
|
||||
The symbol index of the destination of the edge.
|
||||
|
||||
cgp_weight
|
||||
The weight of the edge.
|
||||
|
||||
This is represented in assembly as:
|
||||
|
||||
.. code-block:: gas
|
||||
|
||||
.cg_profile from, to, 42
|
||||
|
||||
``.cg_profile`` directives are processed at the end of the file. It is an error
|
||||
if either ``from`` or ``to`` are undefined temporary symbols. If either symbol
|
||||
is a temporary symbol, then the section symbol is used instead. If either
|
||||
symbol is undefined, then that symbol is defined as if ``.weak symbol`` has been
|
||||
written at the end of the file. This forces the symbol to show up in the symbol
|
||||
table.
|
||||
|
||||
Target Specific Behaviour
|
||||
=========================
|
||||
|
||||
|
@ -803,6 +803,7 @@ enum : unsigned {
|
||||
SHT_ANDROID_RELA = 0x60000002,
|
||||
SHT_LLVM_ODRTAB = 0x6fff4c00, // LLVM ODR table.
|
||||
SHT_LLVM_LINKER_OPTIONS = 0x6fff4c01, // LLVM Linker Options.
|
||||
SHT_LLVM_CALL_GRAPH_PROFILE = 0x6fff4c02, // LLVM Call Graph Profile.
|
||||
SHT_GNU_ATTRIBUTES = 0x6ffffff5, // Object attributes.
|
||||
SHT_GNU_HASH = 0x6ffffff6, // GNU-style hash table.
|
||||
SHT_GNU_verdef = 0x6ffffffd, // GNU version definitions.
|
||||
|
@ -418,6 +418,13 @@ public:
|
||||
const MCLOHContainer &getLOHContainer() const {
|
||||
return const_cast<MCAssembler *>(this)->getLOHContainer();
|
||||
}
|
||||
|
||||
struct CGProfileEntry {
|
||||
const MCSymbolRefExpr *From;
|
||||
const MCSymbolRefExpr *To;
|
||||
uint64_t Count;
|
||||
};
|
||||
std::vector<CGProfileEntry> CGProfile;
|
||||
/// @}
|
||||
/// \name Backend Data Access
|
||||
/// @{
|
||||
|
@ -69,6 +69,9 @@ public:
|
||||
|
||||
void EmitValueToAlignment(unsigned, int64_t, unsigned, unsigned) override;
|
||||
|
||||
void emitCGProfileEntry(const MCSymbolRefExpr *From,
|
||||
const MCSymbolRefExpr *To, uint64_t Count) override;
|
||||
|
||||
void FinishImpl() override;
|
||||
|
||||
void EmitBundleAlignMode(unsigned AlignPow2) override;
|
||||
@ -81,6 +84,8 @@ private:
|
||||
void EmitInstToData(const MCInst &Inst, const MCSubtargetInfo &) override;
|
||||
|
||||
void fixSymbolsInTLSFixups(const MCExpr *expr);
|
||||
void finalizeCGProfileEntry(const MCSymbolRefExpr *&S);
|
||||
void finalizeCGProfile();
|
||||
|
||||
/// Merge the content of the fragment \p EF into the fragment \p DF.
|
||||
void mergeFragment(MCDataFragment *, MCDataFragment *);
|
||||
|
@ -901,6 +901,9 @@ public:
|
||||
SMLoc Loc = SMLoc());
|
||||
virtual void EmitWinEHHandlerData(SMLoc Loc = SMLoc());
|
||||
|
||||
virtual void emitCGProfileEntry(const MCSymbolRefExpr *From,
|
||||
const MCSymbolRefExpr *To, uint64_t Count);
|
||||
|
||||
/// Get the .pdata section used for the given section. Typically the given
|
||||
/// section is either the main .text section or some other COMDAT .text
|
||||
/// section, but it may be any section containing code.
|
||||
|
@ -43,6 +43,7 @@ template <class ELFT> struct Elf_Chdr_Impl;
|
||||
template <class ELFT> struct Elf_Nhdr_Impl;
|
||||
template <class ELFT> class Elf_Note_Impl;
|
||||
template <class ELFT> class Elf_Note_Iterator_Impl;
|
||||
template <class ELFT> struct Elf_CGProfile_Impl;
|
||||
|
||||
template <endianness E, bool Is64> struct ELFType {
|
||||
private:
|
||||
@ -72,6 +73,7 @@ public:
|
||||
using Nhdr = Elf_Nhdr_Impl<ELFType<E, Is64>>;
|
||||
using Note = Elf_Note_Impl<ELFType<E, Is64>>;
|
||||
using NoteIterator = Elf_Note_Iterator_Impl<ELFType<E, Is64>>;
|
||||
using CGProfile = Elf_CGProfile_Impl<ELFType<E, Is64>>;
|
||||
using DynRange = ArrayRef<Dyn>;
|
||||
using ShdrRange = ArrayRef<Shdr>;
|
||||
using SymRange = ArrayRef<Sym>;
|
||||
@ -678,6 +680,13 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template <class ELFT> struct Elf_CGProfile_Impl {
|
||||
LLVM_ELF_IMPORT_TYPES_ELFT(ELFT)
|
||||
Elf_Word cgp_from;
|
||||
Elf_Word cgp_to;
|
||||
Elf_Xword cgp_weight;
|
||||
};
|
||||
|
||||
// MIPS .reginfo section
|
||||
template <class ELFT>
|
||||
struct Elf_Mips_RegInfo;
|
||||
|
@ -976,6 +976,7 @@ void ELFWriter::writeSection(const SectionIndexMapTy &SectionIndexMap,
|
||||
break;
|
||||
|
||||
case ELF::SHT_SYMTAB_SHNDX:
|
||||
case ELF::SHT_LLVM_CALL_GRAPH_PROFILE:
|
||||
sh_link = SymbolTableIndex;
|
||||
break;
|
||||
|
||||
@ -1091,6 +1092,14 @@ uint64_t ELFWriter::writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) {
|
||||
}
|
||||
}
|
||||
|
||||
MCSectionELF *CGProfileSection = nullptr;
|
||||
if (!Asm.CGProfile.empty()) {
|
||||
CGProfileSection = Ctx.getELFSection(".llvm.call-graph-profile",
|
||||
ELF::SHT_LLVM_CALL_GRAPH_PROFILE,
|
||||
ELF::SHF_EXCLUDE, 16, "");
|
||||
SectionIndexMap[CGProfileSection] = addToSectionTable(CGProfileSection);
|
||||
}
|
||||
|
||||
for (MCSectionELF *Group : Groups) {
|
||||
align(Group->getAlignment());
|
||||
|
||||
@ -1132,6 +1141,17 @@ uint64_t ELFWriter::writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) {
|
||||
}
|
||||
}
|
||||
|
||||
if (CGProfileSection) {
|
||||
uint64_t SecStart = W.OS.tell();
|
||||
for (const MCAssembler::CGProfileEntry &CGPE : Asm.CGProfile) {
|
||||
W.write<uint32_t>(CGPE.From->getSymbol().getIndex());
|
||||
W.write<uint32_t>(CGPE.To->getSymbol().getIndex());
|
||||
W.write<uint64_t>(CGPE.Count);
|
||||
}
|
||||
uint64_t SecEnd = W.OS.tell();
|
||||
SectionOffsets[CGProfileSection] = std::make_pair(SecStart, SecEnd);
|
||||
}
|
||||
|
||||
{
|
||||
uint64_t SecStart = W.OS.tell();
|
||||
const MCSectionELF *Sec = createStringTable(Ctx);
|
||||
|
@ -304,6 +304,9 @@ public:
|
||||
SMLoc Loc) override;
|
||||
void EmitWinEHHandlerData(SMLoc Loc) override;
|
||||
|
||||
void emitCGProfileEntry(const MCSymbolRefExpr *From,
|
||||
const MCSymbolRefExpr *To, uint64_t Count) override;
|
||||
|
||||
void EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI,
|
||||
bool PrintSchedInfo) override;
|
||||
|
||||
@ -1650,6 +1653,17 @@ void MCAsmStreamer::EmitWinCFIEndProlog(SMLoc Loc) {
|
||||
EmitEOL();
|
||||
}
|
||||
|
||||
void MCAsmStreamer::emitCGProfileEntry(const MCSymbolRefExpr *From,
|
||||
const MCSymbolRefExpr *To,
|
||||
uint64_t Count) {
|
||||
OS << "\t.cg_profile ";
|
||||
From->getSymbol().print(OS, MAI);
|
||||
OS << ", ";
|
||||
To->getSymbol().print(OS, MAI);
|
||||
OS << ", " << Count;
|
||||
EmitEOL();
|
||||
}
|
||||
|
||||
void MCAsmStreamer::AddEncodingComment(const MCInst &Inst,
|
||||
const MCSubtargetInfo &STI,
|
||||
bool PrintSchedInfo) {
|
||||
|
@ -355,6 +355,12 @@ void MCELFStreamer::EmitValueToAlignment(unsigned ByteAlignment,
|
||||
ValueSize, MaxBytesToEmit);
|
||||
}
|
||||
|
||||
void MCELFStreamer::emitCGProfileEntry(const MCSymbolRefExpr *From,
|
||||
const MCSymbolRefExpr *To,
|
||||
uint64_t Count) {
|
||||
getAssembler().CGProfile.push_back({From, To, Count});
|
||||
}
|
||||
|
||||
void MCELFStreamer::EmitIdent(StringRef IdentString) {
|
||||
MCSection *Comment = getAssembler().getContext().getELFSection(
|
||||
".comment", ELF::SHT_PROGBITS, ELF::SHF_MERGE | ELF::SHF_STRINGS, 1, "");
|
||||
@ -447,6 +453,37 @@ void MCELFStreamer::fixSymbolsInTLSFixups(const MCExpr *expr) {
|
||||
}
|
||||
}
|
||||
|
||||
void MCELFStreamer::finalizeCGProfileEntry(const MCSymbolRefExpr *&SRE) {
|
||||
const MCSymbol *S = &SRE->getSymbol();
|
||||
if (S->isTemporary()) {
|
||||
if (!S->isInSection()) {
|
||||
getContext().reportError(
|
||||
SRE->getLoc(), Twine("Reference to undefined temporary symbol ") +
|
||||
"`" + S->getName() + "`");
|
||||
return;
|
||||
}
|
||||
S = S->getSection().getBeginSymbol();
|
||||
S->setUsedInReloc();
|
||||
SRE =
|
||||
MCSymbolRefExpr::create(S, SRE->getKind(), getContext(), SRE->getLoc());
|
||||
return;
|
||||
}
|
||||
// Not a temporary, referece it as a weak undefined.
|
||||
bool Created;
|
||||
getAssembler().registerSymbol(*S, &Created);
|
||||
if (Created) {
|
||||
cast<MCSymbolELF>(S)->setBinding(ELF::STB_WEAK);
|
||||
cast<MCSymbolELF>(S)->setExternal(true);
|
||||
}
|
||||
}
|
||||
|
||||
void MCELFStreamer::finalizeCGProfile() {
|
||||
for (MCAssembler::CGProfileEntry &E : getAssembler().CGProfile) {
|
||||
finalizeCGProfileEntry(E.From);
|
||||
finalizeCGProfileEntry(E.To);
|
||||
}
|
||||
}
|
||||
|
||||
void MCELFStreamer::EmitInstToFragment(const MCInst &Inst,
|
||||
const MCSubtargetInfo &STI) {
|
||||
this->MCObjectStreamer::EmitInstToFragment(Inst, STI);
|
||||
@ -612,6 +649,7 @@ void MCELFStreamer::FinishImpl() {
|
||||
MCSection *CurSection = getCurrentSectionOnly();
|
||||
setSectionAlignmentForBundling(getAssembler(), CurSection);
|
||||
|
||||
finalizeCGProfile();
|
||||
EmitFrames(nullptr);
|
||||
|
||||
this->MCObjectStreamer::FinishImpl();
|
||||
|
@ -85,6 +85,7 @@ public:
|
||||
addDirectiveHandler<
|
||||
&ELFAsmParser::ParseDirectiveSymbolAttribute>(".hidden");
|
||||
addDirectiveHandler<&ELFAsmParser::ParseDirectiveSubsection>(".subsection");
|
||||
addDirectiveHandler<&ELFAsmParser::ParseDirectiveCGProfile>(".cg_profile");
|
||||
}
|
||||
|
||||
// FIXME: Part of this logic is duplicated in the MCELFStreamer. What is
|
||||
@ -149,6 +150,7 @@ public:
|
||||
bool ParseDirectiveWeakref(StringRef, SMLoc);
|
||||
bool ParseDirectiveSymbolAttribute(StringRef, SMLoc);
|
||||
bool ParseDirectiveSubsection(StringRef, SMLoc);
|
||||
bool ParseDirectiveCGProfile(StringRef, SMLoc);
|
||||
|
||||
private:
|
||||
bool ParseSectionName(StringRef &SectionName);
|
||||
@ -610,6 +612,8 @@ EndStmt:
|
||||
Type = ELF::SHT_LLVM_ODRTAB;
|
||||
else if (TypeName == "llvm_linker_options")
|
||||
Type = ELF::SHT_LLVM_LINKER_OPTIONS;
|
||||
else if (TypeName == "llvm_call_graph_profile")
|
||||
Type = ELF::SHT_LLVM_CALL_GRAPH_PROFILE;
|
||||
else if (TypeName.getAsInteger(0, Type))
|
||||
return TokError("unknown section type");
|
||||
}
|
||||
@ -840,6 +844,47 @@ bool ELFAsmParser::ParseDirectiveSubsection(StringRef, SMLoc) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// ParseDirectiveCGProfile
|
||||
/// ::= .cg_profile identifier, identifier, <number>
|
||||
bool ELFAsmParser::ParseDirectiveCGProfile(StringRef, SMLoc) {
|
||||
StringRef From;
|
||||
SMLoc FromLoc = getLexer().getLoc();
|
||||
if (getParser().parseIdentifier(From))
|
||||
return TokError("expected identifier in directive");
|
||||
|
||||
if (getLexer().isNot(AsmToken::Comma))
|
||||
return TokError("expected a comma");
|
||||
Lex();
|
||||
|
||||
StringRef To;
|
||||
SMLoc ToLoc = getLexer().getLoc();
|
||||
if (getParser().parseIdentifier(To))
|
||||
return TokError("expected identifier in directive");
|
||||
|
||||
if (getLexer().isNot(AsmToken::Comma))
|
||||
return TokError("expected a comma");
|
||||
Lex();
|
||||
|
||||
int64_t Count;
|
||||
if (getParser().parseIntToken(
|
||||
Count, "expected integer count in '.cg_profile' directive"))
|
||||
return true;
|
||||
|
||||
if (getLexer().isNot(AsmToken::EndOfStatement))
|
||||
return TokError("unexpected token in directive");
|
||||
|
||||
MCSymbol *FromSym = getContext().getOrCreateSymbol(From);
|
||||
MCSymbol *ToSym = getContext().getOrCreateSymbol(To);
|
||||
|
||||
getStreamer().emitCGProfileEntry(
|
||||
MCSymbolRefExpr::create(FromSym, MCSymbolRefExpr::VK_None, getContext(),
|
||||
FromLoc),
|
||||
MCSymbolRefExpr::create(ToSym, MCSymbolRefExpr::VK_None, getContext(),
|
||||
ToLoc),
|
||||
Count);
|
||||
return false;
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
|
||||
MCAsmParserExtension *createELFAsmParser() {
|
||||
|
@ -150,6 +150,8 @@ void MCSectionELF::PrintSwitchToSection(const MCAsmInfo &MAI, const Triple &T,
|
||||
OS << "llvm_odrtab";
|
||||
else if (Type == ELF::SHT_LLVM_LINKER_OPTIONS)
|
||||
OS << "llvm_linker_options";
|
||||
else if (Type == ELF::SHT_LLVM_CALL_GRAPH_PROFILE)
|
||||
OS << "llvm_call_graph_profile";
|
||||
else
|
||||
report_fatal_error("unsupported type 0x" + Twine::utohexstr(Type) +
|
||||
" for section " + getSectionName());
|
||||
|
@ -661,6 +661,10 @@ void MCStreamer::EmitWinEHHandlerData(SMLoc Loc) {
|
||||
getContext().reportError(Loc, "Chained unwind areas can't have handlers!");
|
||||
}
|
||||
|
||||
void MCStreamer::emitCGProfileEntry(const MCSymbolRefExpr *From,
|
||||
const MCSymbolRefExpr *To, uint64_t Count) {
|
||||
}
|
||||
|
||||
static MCSection *getWinCFISection(MCContext &Context, unsigned *NextWinCFIID,
|
||||
MCSection *MainCFISec,
|
||||
const MCSection *TextSec) {
|
||||
|
@ -206,6 +206,7 @@ StringRef llvm::object::getELFSectionTypeName(uint32_t Machine, unsigned Type) {
|
||||
STRINGIFY_ENUM_CASE(ELF, SHT_ANDROID_RELA);
|
||||
STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_ODRTAB);
|
||||
STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_LINKER_OPTIONS);
|
||||
STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_CALL_GRAPH_PROFILE);
|
||||
STRINGIFY_ENUM_CASE(ELF, SHT_GNU_ATTRIBUTES);
|
||||
STRINGIFY_ENUM_CASE(ELF, SHT_GNU_HASH);
|
||||
STRINGIFY_ENUM_CASE(ELF, SHT_GNU_verdef);
|
||||
|
@ -441,6 +441,7 @@ void ScalarEnumerationTraits<ELFYAML::ELF_SHT>::enumeration(
|
||||
ECase(SHT_ANDROID_RELA);
|
||||
ECase(SHT_LLVM_ODRTAB);
|
||||
ECase(SHT_LLVM_LINKER_OPTIONS);
|
||||
ECase(SHT_LLVM_CALL_GRAPH_PROFILE);
|
||||
ECase(SHT_GNU_ATTRIBUTES);
|
||||
ECase(SHT_GNU_HASH);
|
||||
ECase(SHT_GNU_verdef);
|
||||
|
9
test/MC/AsmParser/directive_cgprofile.s
Normal file
9
test/MC/AsmParser/directive_cgprofile.s
Normal file
@ -0,0 +1,9 @@
|
||||
# RUN: llvm-mc -triple i386-unknown-unknown %s | FileCheck %s
|
||||
|
||||
.cg_profile a, b, 32
|
||||
.cg_profile freq, a, 11
|
||||
.cg_profile freq, b, 20
|
||||
|
||||
# CHECK: .cg_profile a, b, 32
|
||||
# CHECK: .cg_profile freq, a, 11
|
||||
# CHECK: .cg_profile freq, b, 20
|
7
test/MC/ELF/cgprofile-error.s
Normal file
7
test/MC/ELF/cgprofile-error.s
Normal file
@ -0,0 +1,7 @@
|
||||
# RUN: not llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o /dev/null 2>&1 | FileCheck %s
|
||||
|
||||
.cg_profile a, .L.temp, 32
|
||||
|
||||
# CHECK: cgprofile-error.s:3:18: error: Reference to undefined temporary symbol `.L.temp`
|
||||
# CHECK-NEXT: .cg_profile a, .L.temp, 32
|
||||
# CHECK-NEXT: ^
|
100
test/MC/ELF/cgprofile.s
Normal file
100
test/MC/ELF/cgprofile.s
Normal file
@ -0,0 +1,100 @@
|
||||
# RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o - | llvm-readobj -s -t -sd -elf-cg-profile | FileCheck %s
|
||||
|
||||
.section .test,"aw",@progbits
|
||||
a: .word b
|
||||
|
||||
.cg_profile a, b, 32
|
||||
.cg_profile freq, a, 11
|
||||
.cg_profile late, late2, 20
|
||||
.cg_profile .L.local, b, 42
|
||||
|
||||
.globl late
|
||||
late:
|
||||
late2: .word 0
|
||||
late3:
|
||||
.L.local:
|
||||
|
||||
# CHECK: Name: .llvm.call-graph-profile
|
||||
# CHECK-NEXT: Type: SHT_LLVM_CALL_GRAPH_PROFILE (0x6FFF4C02)
|
||||
# CHECK-NEXT: Flags [ (0x80000000)
|
||||
# CHECK-NEXT: SHF_EXCLUDE (0x80000000)
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: Address:
|
||||
# CHECK-NEXT: Offset:
|
||||
# CHECK-NEXT: Size: 64
|
||||
# CHECK-NEXT: Link: 6
|
||||
# CHECK-NEXT: Info: 0
|
||||
# CHECK-NEXT: AddressAlignment: 1
|
||||
# CHECK-NEXT: EntrySize: 16
|
||||
# CHECK-NEXT: SectionData (
|
||||
# CHECK-NEXT: 0000: 01000000 05000000 20000000 00000000
|
||||
# CHECK-NEXT: 0010: 06000000 01000000 0B000000 00000000
|
||||
# CHECK-NEXT: 0020: 07000000 02000000 14000000 00000000
|
||||
# CHECK-NEXT: 0030: 04000000 05000000 2A000000 00000000
|
||||
# CHECK-NEXT: )
|
||||
|
||||
# CHECK: Symbols [
|
||||
# CHECK: Name: a
|
||||
# CHECK-NEXT: Value:
|
||||
# CHECK-NEXT: Size:
|
||||
# CHECK-NEXT: Binding: Local
|
||||
# CHECK-NEXT: Type:
|
||||
# CHECK-NEXT: Other:
|
||||
# CHECK-NEXT: Section: .test
|
||||
# CHECK: Name: late2
|
||||
# CHECK-NEXT: Value:
|
||||
# CHECK-NEXT: Size:
|
||||
# CHECK-NEXT: Binding: Local
|
||||
# CHECK-NEXT: Type:
|
||||
# CHECK-NEXT: Other:
|
||||
# CHECK-NEXT: Section: .test
|
||||
# CHECK: Name: late3
|
||||
# CHECK-NEXT: Value:
|
||||
# CHECK-NEXT: Size:
|
||||
# CHECK-NEXT: Binding: Local
|
||||
# CHECK-NEXT: Type:
|
||||
# CHECK-NEXT: Other:
|
||||
# CHECK-NEXT: Section: .test
|
||||
# CHECK: Name: b
|
||||
# CHECK-NEXT: Value:
|
||||
# CHECK-NEXT: Size:
|
||||
# CHECK-NEXT: Binding: Global
|
||||
# CHECK-NEXT: Type:
|
||||
# CHECK-NEXT: Other:
|
||||
# CHECK-NEXT: Section: Undefined
|
||||
# CHECK: Name: freq
|
||||
# CHECK-NEXT: Value:
|
||||
# CHECK-NEXT: Size:
|
||||
# CHECK-NEXT: Binding: Weak
|
||||
# CHECK-NEXT: Type:
|
||||
# CHECK-NEXT: Other:
|
||||
# CHECK-NEXT: Section: Undefined
|
||||
# CHECK: Name: late
|
||||
# CHECK-NEXT: Value:
|
||||
# CHECK-NEXT: Size:
|
||||
# CHECK-NEXT: Binding: Global
|
||||
# CHECK-NEXT: Type:
|
||||
# CHECK-NEXT: Other:
|
||||
# CHECK-NEXT: Section: .test
|
||||
# CHECK: CGProfile [
|
||||
# CHECK-NEXT: CGProfileEntry {
|
||||
# CHECK-NEXT: From: a
|
||||
# CHECK-NEXT: To: b
|
||||
# CHECK-NEXT: Weight: 32
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: CGProfileEntry {
|
||||
# CHECK-NEXT: From: freq
|
||||
# CHECK-NEXT: To: a
|
||||
# CHECK-NEXT: Weight: 11
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: CGProfileEntry {
|
||||
# CHECK-NEXT: From: late
|
||||
# CHECK-NEXT: To: late2
|
||||
# CHECK-NEXT: Weight: 20
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: CGProfileEntry {
|
||||
# CHECK-NEXT: From:
|
||||
# CHECK-NEXT: To: b
|
||||
# CHECK-NEXT: Weight: 42
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: ]
|
@ -100,6 +100,7 @@ using namespace ELF;
|
||||
using Elf_Vernaux = typename ELFT::Vernaux; \
|
||||
using Elf_Verdef = typename ELFT::Verdef; \
|
||||
using Elf_Verdaux = typename ELFT::Verdaux; \
|
||||
using Elf_CGProfile = typename ELFT::CGProfile; \
|
||||
using uintX_t = typename ELFT::uint;
|
||||
|
||||
namespace {
|
||||
@ -164,6 +165,8 @@ public:
|
||||
|
||||
void printHashHistogram() override;
|
||||
|
||||
void printCGProfile() override;
|
||||
|
||||
void printNotes() override;
|
||||
|
||||
void printELFLinkerOptions() override;
|
||||
@ -210,6 +213,7 @@ private:
|
||||
const Elf_Hash *HashTable = nullptr;
|
||||
const Elf_GnuHash *GnuHashTable = nullptr;
|
||||
const Elf_Shdr *DotSymtabSec = nullptr;
|
||||
const Elf_Shdr *DotCGProfileSec = nullptr;
|
||||
StringRef DynSymtabName;
|
||||
ArrayRef<Elf_Word> ShndxTable;
|
||||
|
||||
@ -257,9 +261,11 @@ public:
|
||||
void getSectionNameIndex(const Elf_Sym *Symbol, const Elf_Sym *FirstSym,
|
||||
StringRef &SectionName,
|
||||
unsigned &SectionIndex) const;
|
||||
StringRef getStaticSymbolName(uint32_t Index) const;
|
||||
|
||||
void printSymbolsHelper(bool IsDynamic) const;
|
||||
const Elf_Shdr *getDotSymtabSec() const { return DotSymtabSec; }
|
||||
const Elf_Shdr *getDotCGProfileSec() const { return DotCGProfileSec; }
|
||||
ArrayRef<Elf_Word> getShndxTable() const { return ShndxTable; }
|
||||
StringRef getDynamicStringTable() const { return DynamicStringTable; }
|
||||
const DynRegionInfo &getDynRelRegion() const { return DynRelRegion; }
|
||||
@ -319,6 +325,7 @@ public:
|
||||
bool IsDynamic) = 0;
|
||||
virtual void printProgramHeaders(const ELFFile<ELFT> *Obj) = 0;
|
||||
virtual void printHashHistogram(const ELFFile<ELFT> *Obj) = 0;
|
||||
virtual void printCGProfile(const ELFFile<ELFT> *Obj) = 0;
|
||||
virtual void printNotes(const ELFFile<ELFT> *Obj) = 0;
|
||||
virtual void printELFLinkerOptions(const ELFFile<ELFT> *Obj) = 0;
|
||||
virtual void printMipsGOT(const MipsGOTParser<ELFT> &Parser) = 0;
|
||||
@ -349,6 +356,7 @@ public:
|
||||
size_t Offset) override;
|
||||
void printProgramHeaders(const ELFO *Obj) override;
|
||||
void printHashHistogram(const ELFFile<ELFT> *Obj) override;
|
||||
void printCGProfile(const ELFFile<ELFT> *Obj) override;
|
||||
void printNotes(const ELFFile<ELFT> *Obj) override;
|
||||
void printELFLinkerOptions(const ELFFile<ELFT> *Obj) override;
|
||||
void printMipsGOT(const MipsGOTParser<ELFT> &Parser) override;
|
||||
@ -410,6 +418,7 @@ public:
|
||||
void printDynamicRelocations(const ELFO *Obj) override;
|
||||
void printProgramHeaders(const ELFO *Obj) override;
|
||||
void printHashHistogram(const ELFFile<ELFT> *Obj) override;
|
||||
void printCGProfile(const ELFFile<ELFT> *Obj) override;
|
||||
void printNotes(const ELFFile<ELFT> *Obj) override;
|
||||
void printELFLinkerOptions(const ELFFile<ELFT> *Obj) override;
|
||||
void printMipsGOT(const MipsGOTParser<ELFT> &Parser) override;
|
||||
@ -736,6 +745,16 @@ StringRef ELFDumper<ELFT>::getSymbolVersion(StringRef StrTab,
|
||||
return StringRef(StrTab.data() + name_offset);
|
||||
}
|
||||
|
||||
template <typename ELFT>
|
||||
StringRef ELFDumper<ELFT>::getStaticSymbolName(uint32_t Index) const {
|
||||
StringRef StrTable = unwrapOrError(Obj->getStringTableForSymtab(*DotSymtabSec));
|
||||
Elf_Sym_Range Syms = unwrapOrError(Obj->symbols(DotSymtabSec));
|
||||
if (Index >= Syms.size())
|
||||
reportError("Invalid symbol index");
|
||||
const Elf_Sym *Sym = &Syms[Index];
|
||||
return unwrapOrError(Sym->getName(StrTable));
|
||||
}
|
||||
|
||||
template <typename ELFT>
|
||||
std::string ELFDumper<ELFT>::getFullSymbolName(const Elf_Sym *Symbol,
|
||||
StringRef StrTable,
|
||||
@ -1390,6 +1409,10 @@ ELFDumper<ELFT>::ELFDumper(const ELFFile<ELFT> *Obj, ScopedPrinter &Writer)
|
||||
reportError("Multiple SHT_GNU_verneed");
|
||||
dot_gnu_version_r_sec = &Sec;
|
||||
break;
|
||||
case ELF::SHT_LLVM_CALL_GRAPH_PROFILE:
|
||||
if (DotCGProfileSec != nullptr)
|
||||
reportError("Multiple .note.llvm.cgprofile");
|
||||
DotCGProfileSec = &Sec;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1534,6 +1557,10 @@ template <class ELFT> void ELFDumper<ELFT>::printHashHistogram() {
|
||||
ELFDumperStyle->printHashHistogram(Obj);
|
||||
}
|
||||
|
||||
template <class ELFT> void ELFDumper<ELFT>::printCGProfile() {
|
||||
ELFDumperStyle->printCGProfile(Obj);
|
||||
}
|
||||
|
||||
template <class ELFT> void ELFDumper<ELFT>::printNotes() {
|
||||
ELFDumperStyle->printNotes(Obj);
|
||||
}
|
||||
@ -2721,6 +2748,8 @@ std::string getSectionTypeString(unsigned Arch, unsigned Type) {
|
||||
return "LLVM_ODRTAB";
|
||||
case SHT_LLVM_LINKER_OPTIONS:
|
||||
return "LLVM_LINKER_OPTIONS";
|
||||
case SHT_LLVM_CALL_GRAPH_PROFILE:
|
||||
return "LLVM_CALL_GRAPH_PROFILE";
|
||||
// FIXME: Parse processor specific GNU attributes
|
||||
case SHT_GNU_ATTRIBUTES:
|
||||
return "ATTRIBUTES";
|
||||
@ -3374,6 +3403,11 @@ void GNUStyle<ELFT>::printHashHistogram(const ELFFile<ELFT> *Obj) {
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void GNUStyle<ELFT>::printCGProfile(const ELFFile<ELFT> *Obj) {
|
||||
OS << "GNUStyle::printCGProfile not implemented\n";
|
||||
}
|
||||
|
||||
static std::string getGNUNoteTypeName(const uint32_t NT) {
|
||||
static const struct {
|
||||
uint32_t ID;
|
||||
@ -4137,6 +4171,24 @@ void LLVMStyle<ELFT>::printHashHistogram(const ELFFile<ELFT> *Obj) {
|
||||
W.startLine() << "Hash Histogram not implemented!\n";
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void LLVMStyle<ELFT>::printCGProfile(const ELFFile<ELFT> *Obj) {
|
||||
ListScope L(W, "CGProfile");
|
||||
if (!this->dumper()->getDotCGProfileSec())
|
||||
return;
|
||||
auto CGProfile =
|
||||
unwrapOrError(Obj->template getSectionContentsAsArray<Elf_CGProfile>(
|
||||
this->dumper()->getDotCGProfileSec()));
|
||||
for (const Elf_CGProfile &CGPE : CGProfile) {
|
||||
DictScope D(W, "CGProfileEntry");
|
||||
W.printNumber("From", this->dumper()->getStaticSymbolName(CGPE.cgp_from),
|
||||
CGPE.cgp_from);
|
||||
W.printNumber("To", this->dumper()->getStaticSymbolName(CGPE.cgp_to),
|
||||
CGPE.cgp_to);
|
||||
W.printNumber("Weight", CGPE.cgp_weight);
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void LLVMStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) {
|
||||
W.startLine() << "printNotes not implemented!\n";
|
||||
|
@ -47,6 +47,7 @@ public:
|
||||
virtual void printVersionInfo() {}
|
||||
virtual void printGroupSections() {}
|
||||
virtual void printHashHistogram() {}
|
||||
virtual void printCGProfile() {}
|
||||
virtual void printNotes() {}
|
||||
virtual void printELFLinkerOptions() {}
|
||||
|
||||
|
@ -284,6 +284,8 @@ namespace opts {
|
||||
cl::alias HashHistogramShort("I", cl::desc("Alias for -elf-hash-histogram"),
|
||||
cl::aliasopt(HashHistogram));
|
||||
|
||||
cl::opt<bool> CGProfile("elf-cg-profile", cl::desc("Display callgraph profile section"));
|
||||
|
||||
cl::opt<OutputStyleTy>
|
||||
Output("elf-output-style", cl::desc("Specify ELF dump style"),
|
||||
cl::values(clEnumVal(LLVM, "LLVM default style"),
|
||||
@ -441,6 +443,8 @@ static void dumpObject(const ObjectFile *Obj, ScopedPrinter &Writer) {
|
||||
Dumper->printGroupSections();
|
||||
if (opts::HashHistogram)
|
||||
Dumper->printHashHistogram();
|
||||
if (opts::CGProfile)
|
||||
Dumper->printCGProfile();
|
||||
if (opts::Notes)
|
||||
Dumper->printNotes();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user