1
0
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:
Michael J. Spencer 2018-06-02 16:33:01 +00:00
parent ed2c720917
commit cf322e810a
20 changed files with 367 additions and 0 deletions

View File

@ -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
=========================

View File

@ -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.

View File

@ -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
/// @{

View File

@ -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 *);

View File

@ -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.

View File

@ -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;

View File

@ -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);

View File

@ -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) {

View File

@ -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();

View File

@ -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() {

View File

@ -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());

View File

@ -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) {

View File

@ -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);

View File

@ -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);

View 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

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

View File

@ -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";

View File

@ -47,6 +47,7 @@ public:
virtual void printVersionInfo() {}
virtual void printGroupSections() {}
virtual void printHashHistogram() {}
virtual void printCGProfile() {}
virtual void printNotes() {}
virtual void printELFLinkerOptions() {}

View File

@ -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();
}