1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-24 19:52:54 +01:00

[LLD][LLVM] CG Graph profile using relocations

Currently when .llvm.call-graph-profile is created by llvm it explicitly encodes the symbol indices. This section is basically a black box for post processing tools. For example, if we run strip -s on the object files the symbol table changes, but indices in that section do not. In non-visible behavior indices point to wrong symbols. The visible behavior indices point outside of Symbol table: "invalid symbol index".

This patch changes the format by using R_*_NONE relocations to indicate the from/to symbols. The Frequency (Weight) will still be in the .llvm.call-graph-profile, but symbol information will be in relocation section. In LLD information from both sections is used to reconstruct call graph profile. Relocations themselves will never be applied.

With this approach post processing tools that handle relocations correctly work for this section also. Tools can add/remove symbols and as long as they handle relocation sections with this approach information stays correct.

Doing a quick experiment with clang-13.
The size went up from 107KB to 322KB, aggregate of all the input sections. Size of clang-13 binary is ~118MB. For users of -fprofile-use/-fprofile-sample-use the size of object files will go up slightly, it will not impact final binary size.

Reviewed By: jhenderson, MaskRay

Differential Revision: https://reviews.llvm.org/D104080
This commit is contained in:
Alexander Yermolovich 2021-06-24 08:02:45 -07:00 committed by Wenlei He
parent ad844f8999
commit d12ae1eaf8
17 changed files with 414 additions and 362 deletions

View File

@ -926,17 +926,17 @@ enum : unsigned {
// https://android.googlesource.com/platform/bionic/+/6f12bfece5dcc01325e0abba56a46b1bcf991c69/tools/relocation_packer/src/elf_file.cc#37
SHT_ANDROID_REL = 0x60000001,
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_LLVM_ADDRSIG = 0x6fff4c03, // List of address-significant symbols
// for safe ICF.
SHT_LLVM_ODRTAB = 0x6fff4c00, // LLVM ODR table.
SHT_LLVM_LINKER_OPTIONS = 0x6fff4c01, // LLVM Linker Options.
SHT_LLVM_ADDRSIG = 0x6fff4c03, // List of address-significant symbols
// for safe ICF.
SHT_LLVM_DEPENDENT_LIBRARIES =
0x6fff4c04, // LLVM Dependent Library Specifiers.
SHT_LLVM_SYMPART = 0x6fff4c05, // Symbol partition specification.
SHT_LLVM_PART_EHDR = 0x6fff4c06, // ELF header for loadable partition.
SHT_LLVM_PART_PHDR = 0x6fff4c07, // Phdrs for loadable partition.
SHT_LLVM_BB_ADDR_MAP = 0x6fff4c08, // LLVM Basic Block Address Map.
SHT_LLVM_CALL_GRAPH_PROFILE = 0x6fff4c09, // LLVM Call Graph Profile.
// Android's experimental support for SHT_RELR sections.
// https://android.googlesource.com/platform/bionic/+/b7feec74547f84559a1467aca02708ff61346d2a/libc/include/elf.h#512
SHT_ANDROID_RELR = 0x6fffff00, // Relocation entries; only offsets.

View File

@ -85,7 +85,7 @@ private:
void emitInstToData(const MCInst &Inst, const MCSubtargetInfo &) override;
void fixSymbolsInTLSFixups(const MCExpr *expr);
void finalizeCGProfileEntry(const MCSymbolRefExpr *&S);
void finalizeCGProfileEntry(const MCSymbolRefExpr *&S, uint64_t Offset);
void finalizeCGProfile();
/// Merge the content of the fragment \p EF into the fragment \p DF.

View File

@ -737,8 +737,6 @@ 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;
};

View File

@ -516,17 +516,13 @@ struct DependentLibrariesSection : Section {
};
// Represents the call graph profile section entry.
struct CallGraphEntry {
// The symbol of the source of the edge.
StringRef From;
// The symbol index of the destination of the edge.
StringRef To;
struct CallGraphEntryWeight {
// The weight of the edge.
uint64_t Weight;
};
struct CallGraphProfileSection : Section {
Optional<std::vector<CallGraphEntry>> Entries;
Optional<std::vector<CallGraphEntryWeight>> Entries;
CallGraphProfileSection() : Section(ChunkKind::CallGraphProfile) {}
@ -738,7 +734,7 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::BBAddrMapEntry)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::BBAddrMapEntry::BBEntry)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::DynamicEntry)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::LinkerOption)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::CallGraphEntry)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::CallGraphEntryWeight)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::NoteEntry)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::ProgramHeader)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::SectionHeader)
@ -932,8 +928,8 @@ template <> struct MappingTraits<ELFYAML::LinkerOption> {
static void mapping(IO &IO, ELFYAML::LinkerOption &Sym);
};
template <> struct MappingTraits<ELFYAML::CallGraphEntry> {
static void mapping(IO &IO, ELFYAML::CallGraphEntry &E);
template <> struct MappingTraits<ELFYAML::CallGraphEntryWeight> {
static void mapping(IO &IO, ELFYAML::CallGraphEntryWeight &E);
};
template <> struct MappingTraits<ELFYAML::Relocation> {

View File

@ -1127,14 +1127,6 @@ uint64_t ELFWriter::writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) {
OWriter.TargetObjectWriter->addTargetSectionFlags(Ctx, Section);
}
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) {
// Remember the offset into the file for this section.
const uint64_t SecStart = align(Group->getAlignment());
@ -1186,17 +1178,6 @@ 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();
StrTabBuilder.write(W.OS);
@ -1471,7 +1452,11 @@ void ELFObjectWriter::recordRelocation(MCAssembler &Asm,
return;
unsigned Type = TargetObjectWriter->getRelocType(Ctx, Target, Fixup, IsPCRel);
bool RelocateWithSymbol = shouldRelocateWithSymbol(Asm, RefA, SymA, C, Type);
const auto *Parent = cast<MCSectionELF>(Fragment->getParent());
// Emiting relocation with sybmol for CG Profile to help with --cg-profile.
bool RelocateWithSymbol =
shouldRelocateWithSymbol(Asm, RefA, SymA, C, Type) ||
(Parent->getType() == ELF::SHT_LLVM_CALL_GRAPH_PROFILE);
uint64_t Addend = 0;
FixedValue = !RelocateWithSymbol && SymA && !SymA->isUndefined()

View File

@ -477,7 +477,8 @@ void MCELFStreamer::fixSymbolsInTLSFixups(const MCExpr *expr) {
}
}
void MCELFStreamer::finalizeCGProfileEntry(const MCSymbolRefExpr *&SRE) {
void MCELFStreamer::finalizeCGProfileEntry(const MCSymbolRefExpr *&SRE,
uint64_t Offset) {
const MCSymbol *S = &SRE->getSymbol();
if (S->isTemporary()) {
if (!S->isInSection()) {
@ -488,22 +489,35 @@ void MCELFStreamer::finalizeCGProfileEntry(const MCSymbolRefExpr *&SRE) {
}
S = S->getSection().getBeginSymbol();
S->setUsedInReloc();
SRE =
MCSymbolRefExpr::create(S, SRE->getKind(), getContext(), SRE->getLoc());
return;
SRE = MCSymbolRefExpr::create(S, MCSymbolRefExpr::VK_None, getContext(),
SRE->getLoc());
}
// Not a temporary, referece it as a weak undefined.
bool Created;
getAssembler().registerSymbol(*S, &Created);
if (Created)
cast<MCSymbolELF>(S)->setBinding(ELF::STB_WEAK);
const MCConstantExpr *MCOffset = MCConstantExpr::create(Offset, getContext());
MCObjectStreamer::visitUsedExpr(*SRE);
if (Optional<std::pair<bool, std::string>> Err =
MCObjectStreamer::emitRelocDirective(
*MCOffset, "BFD_RELOC_NONE", SRE, SRE->getLoc(),
*getContext().getSubtargetInfo()))
report_fatal_error("Relocation for CG Profile could not be created: " +
Err->second);
}
void MCELFStreamer::finalizeCGProfile() {
for (MCAssembler::CGProfileEntry &E : getAssembler().CGProfile) {
finalizeCGProfileEntry(E.From);
finalizeCGProfileEntry(E.To);
MCAssembler &Asm = getAssembler();
if (Asm.CGProfile.empty())
return;
MCSection *CGProfile = getAssembler().getContext().getELFSection(
".llvm.call-graph-profile", ELF::SHT_LLVM_CALL_GRAPH_PROFILE,
ELF::SHF_EXCLUDE, /*sizeof(Elf_CGProfile_Impl<>)=*/8);
PushSection();
SwitchSection(CGProfile);
uint64_t Offset = 0;
for (MCAssembler::CGProfileEntry &E : Asm.CGProfile) {
finalizeCGProfileEntry(E.From, Offset++);
finalizeCGProfileEntry(E.To, Offset++);
emitIntValue(E.Count, sizeof(uint64_t));
}
PopSection();
}
void MCELFStreamer::emitInstToFragment(const MCInst &Inst,

View File

@ -18,6 +18,7 @@
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/MC/StringTableBuilder.h"
#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Object/ELFTypes.h"
#include "llvm/ObjectYAML/DWARFEmitter.h"
#include "llvm/ObjectYAML/DWARFYAML.h"
#include "llvm/ObjectYAML/ELFYAML.h"
@ -1474,14 +1475,9 @@ void ELFState<ELFT>::writeSectionContent(
if (!Section.Entries)
return;
for (const ELFYAML::CallGraphEntry &E : *Section.Entries) {
unsigned From = toSymbolIndex(E.From, Section.Name, /*IsDynamic=*/false);
unsigned To = toSymbolIndex(E.To, Section.Name, /*IsDynamic=*/false);
CBA.write<uint32_t>(From, ELFT::TargetEndianness);
CBA.write<uint32_t>(To, ELFT::TargetEndianness);
for (const ELFYAML::CallGraphEntryWeight &E : *Section.Entries) {
CBA.write<uint64_t>(E.Weight, ELFT::TargetEndianness);
SHeader.sh_size += 16;
SHeader.sh_size += sizeof(object::Elf_CGProfile_Impl<ELFT>);
}
}

View File

@ -1834,11 +1834,9 @@ void MappingTraits<ELFYAML::LinkerOption>::mapping(IO &IO,
IO.mapRequired("Value", Opt.Value);
}
void MappingTraits<ELFYAML::CallGraphEntry>::mapping(
IO &IO, ELFYAML::CallGraphEntry &E) {
void MappingTraits<ELFYAML::CallGraphEntryWeight>::mapping(
IO &IO, ELFYAML::CallGraphEntryWeight &E) {
assert(IO.getContext() && "The IO context is not initialized");
IO.mapRequired("From", E.From);
IO.mapRequired("To", E.To);
IO.mapRequired("Weight", E.Weight);
}

View File

@ -15,22 +15,46 @@ late3:
.L.local:
# CHECK: Name: .llvm.call-graph-profile
# CHECK-NEXT: Type: SHT_LLVM_CALL_GRAPH_PROFILE (0x6FFF4C02)
# CHECK-NEXT: Type: SHT_LLVM_CALL_GRAPH_PROFILE (0x6FFF4C09)
# 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: Size: 32
# CHECK-NEXT: Link: 7
# CHECK-NEXT: Info: 0
# CHECK-NEXT: AddressAlignment: 1
# CHECK-NEXT: EntrySize: 16
# CHECK-NEXT: EntrySize: 8
# CHECK-NEXT: SectionData (
# CHECK-NEXT: 0000: 02000000 05000000 20000000 00000000
# CHECK-NEXT: 0010: 07000000 02000000 0B000000 00000000
# CHECK-NEXT: 0020: 06000000 03000000 14000000 00000000
# CHECK-NEXT: 0030: 01000000 05000000 2A000000 00000000
# CHECK-NEXT: 0000: 20000000 00000000 0B000000 00000000
# CHECK-NEXT: 0010: 14000000 00000000 2A000000 00000000
# CHECK-NEXT: )
# CHECK: Name: .rela.llvm.call-graph-profile (28)
# CHECK-NEXT: Type: SHT_RELA (0x4)
# CHECK-NEXT: Flags [ (0x0)
# CHECK-NEXT: ]
# CHECK-NEXT: Address: 0x0
# CHECK-NEXT: Offset: 0x140
# CHECK-NEXT: Size: 192
# CHECK-NEXT: Link: 7
# CHECK-NEXT: Info: 5
# CHECK-NEXT: AddressAlignment: 8
# CHECK-NEXT: EntrySize: 24
# CHECK-NEXT: SectionData (
# CHECK-NEXT: 0000: 00000000 00000000 00000000 02000000
# CHECK-NEXT: 0010: 00000000 00000000 01000000 00000000
# CHECK-NEXT: 0020: 00000000 05000000 00000000 00000000
# CHECK-NEXT: 0030: 02000000 00000000 00000000 07000000
# CHECK-NEXT: 0040: 00000000 00000000 03000000 00000000
# CHECK-NEXT: 0050: 00000000 02000000 00000000 00000000
# CHECK-NEXT: 0060: 04000000 00000000 00000000 06000000
# CHECK-NEXT: 0070: 00000000 00000000 05000000 00000000
# CHECK-NEXT: 0080: 00000000 03000000 00000000 00000000
# CHECK-NEXT: 0090: 06000000 00000000 00000000 01000000
# CHECK-NEXT: 00A0: 00000000 00000000 07000000 00000000
# CHECK-NEXT: 00B0: 00000000 05000000 00000000 00000000
# CHECK-NEXT: )
# CHECK: Symbols [
@ -72,7 +96,7 @@ late3:
# CHECK: Name: freq
# CHECK-NEXT: Value:
# CHECK-NEXT: Size:
# CHECK-NEXT: Binding: Weak
# CHECK-NEXT: Binding: Global
# CHECK-NEXT: Type:
# CHECK-NEXT: Other:
# CHECK-NEXT: Section: Undefined

View File

@ -8,15 +8,16 @@
# CHECK: VersionDefinitions [
# CHECK: VersionRequirements [
# CHECK: CGProfile [
# CHECK: CGProfile [
# CHECK: Addrsig [
--- !ELF
FileHeader:
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_REL
Machine: EM_X86_64
Sections:
Sections:
- Name: .symtab2
Type: SHT_SYMTAB
Link: .strtab
@ -49,18 +50,18 @@ Sections:
- Name: .llvm.call-graph-profile
Type: SHT_LLVM_CALL_GRAPH_PROFILE
Content: ''
EntSize: 16
EntSize: 8
- Name: .llvm.call-graph-profile2
Type: SHT_LLVM_CALL_GRAPH_PROFILE
Content: ''
EntSize: 16
EntSize: 8
- Name: .llvm_addrsig
Type: SHT_LLVM_ADDRSIG
Content: ''
- Name: .llvm_addrsig2
Type: SHT_LLVM_ADDRSIG
Content: ''
Symbols:
Symbols:
- Name: f
DynamicSymbols: []
...

View File

@ -26,17 +26,29 @@ FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_DYN
Machine: EM_X86_64
Sections:
- Name: .llvm.call-graph-profile
Type: SHT_LLVM_CALL_GRAPH_PROFILE
Entries:
- From: foo
To: bar
Weight: 89
- From: bar
To: foo
Weight: 98
- Weight: 89
- Weight: 98
EntSize: [[ENTSIZE=<none>]]
- Name: .rela.llvm.call-graph-profile
Type: SHT_RELA
Info: .llvm.call-graph-profile
Relocations:
- Symbol: foo
Type: R_X86_64_NONE
- Offset: 0x1
Symbol: bar
Type: R_X86_64_NONE
- Offset: 0x2
Symbol: bar
Type: R_X86_64_NONE
- Offset: 0x3
Symbol: foo
Type: R_X86_64_NONE
Symbols:
- Name: foo
- Name: bar
@ -46,9 +58,7 @@ Symbols:
# RUN: llvm-readobj %t2.o --cg-profile 2>&1 | FileCheck %s -DFILE=%t2.o --check-prefix=LLVM-ERR
# RUN: llvm-readelf %t2.o --cg-profile | FileCheck %s --check-prefix=GNU
# LLVM-ERR: CGProfile [
# LLVM-ERR-NEXT: warning: '[[FILE]]': unable to dump the SHT_LLVM_CALL_GRAPH_PROFILE section: section [index 1] has invalid sh_entsize: expected 16, but got 15
# LLVM-ERR-NEXT: ]
# LLVM-ERR: warning: '[[FILE]]': unable to load the SHT_LLVM_CALL_GRAPH_PROFILE section: section [index 1] has invalid sh_entsize: expected 8, but got 15
## Check we report a warning when unable to dump a name of a symbol.
# RUN: yaml2obj %s --docnum=2 -o %t3.o
@ -69,7 +79,7 @@ Symbols:
# LLVM-BROKEN-SYM-NEXT: }
# LLVM-BROKEN-SYM-NEXT: CGProfileEntry {
# LLVM-BROKEN-SYM-NEXT: From: (0)
# LLVM-BROKEN-SYM-NEXT: warning: '[[FILE]]': unable to read the name of symbol with index 4: unable to get symbol from section [index 3]: invalid symbol index (4)
# LLVM-BROKEN-SYM-NEXT: warning: '[[FILE]]': unable to read the name of symbol with index 4: unable to get symbol from section [index 4]: invalid symbol index (4)
# LLVM-BROKEN-SYM-NEXT: To: <?> (4)
# LLVM-BROKEN-SYM-NEXT: Weight: 20
# LLVM-BROKEN-SYM-NEXT: }
@ -80,19 +90,35 @@ FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_DYN
Machine: EM_X86_64
Sections:
- Name: .llvm.call-graph-profile
Type: SHT_LLVM_CALL_GRAPH_PROFILE
Entries:
- From: 1
To: 2
Weight: 10
- From: 2
To: 3
Weight: 20
- From: 0x0 ## Null symbol.
To: 0x4 ## This index goes past the end of the symbol table.
Weight: 20
- Weight: 10
- Weight: 20
- Weight: 20
- Name: .rela.llvm.call-graph-profile
Type: SHT_RELA
Info: .llvm.call-graph-profile
Relocations:
- Symbol: 1
Type: R_X86_64_NONE
- Offset: 0x1
Symbol: 2
Type: R_X86_64_NONE
- Offset: 0x2
Symbol: 2
Type: R_X86_64_NONE
- Offset: 0x3
Symbol: 3
Type: R_X86_64_NONE
- Offset: 0x4
Symbol: 0x0 ## Null symbol.
Type: R_X86_64_NONE
- Offset: 0x5
Symbol: 0x4 ## This index goes past the end of the symbol table.
Type: R_X86_64_NONE
- Name: .strtab
Type: SHT_STRTAB
Content: "0041004200" ## '\0', 'A', '\0', 'B', '\0'
@ -100,3 +126,132 @@ Symbols:
- StName: 1 ## 'A'
- StName: 0xFF ## An arbitrary currupted index in the string table.
- StName: 3 ## 'B'
## Check we report a warning when a relocation section is not present.
# RUN: yaml2obj %s --docnum=3 -o %t4.o
# RUN: llvm-readobj %t4.o --cg-profile 2>&1 | FileCheck %s -DFILE=%t4.o --check-prefix=LLVM-NO-RELOC
# RUN: llvm-readobj %t4.o --elf-cg-profile 2>&1 | FileCheck %s -DFILE=%t4.o --check-prefix=LLVM-NO-RELOC
# LLVM-NO-RELOC: warning: '[[FILE]]': relocation section for a call graph section doesn't exist
# LLVM-NO-RELOC-NEXT: CGProfile [
# LLVM-NO-RELOC-NEXT: CGProfileEntry {
# LLVM-NO-RELOC-NEXT: Weight: 89
# LLVM-NO-RELOC-NEXT: }
# LLVM-NO-RELOC-NEXT: CGProfileEntry {
# LLVM-NO-RELOC-NEXT: Weight: 98
# LLVM-NO-RELOC-NEXT: }
# LLVM-NO-RELOC-NEXT: ]
--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_DYN
Sections:
- Name: .llvm.call-graph-profile
Type: SHT_LLVM_CALL_GRAPH_PROFILE
Entries:
- Weight: 89
- Weight: 98
EntSize: [[ENTSIZE=<none>]]
Symbols:
- Name: foo
- Name: bar
## Check we report a warning when the number of relocation section entries does not match the number of call graph entries.
# RUN: yaml2obj %s --docnum=4 -o %t5.o
# RUN: llvm-readobj %t5.o --cg-profile 2>&1 | FileCheck %s -DFILE=%t5.o --check-prefix=LLVM-RELOC-GRAPH-NOT-MATCH
# RUN: llvm-readobj %t5.o --elf-cg-profile 2>&1 | FileCheck %s -DFILE=%t5.o --check-prefix=LLVM-RELOC-GRAPH-NOT-MATCH
# LLVM-RELOC-GRAPH-NOT-MATCH: warning: '[[FILE]]': number of from/to pairs does not match number of frequencies
# LLVM-RELOC-GRAPH-NOT-MATCH-NEXT: CGProfile [
# LLVM-RELOC-GRAPH-NOT-MATCH-NEXT: CGProfileEntry {
# LLVM-RELOC-GRAPH-NOT-MATCH-NEXT: Weight: 89
# LLVM-RELOC-GRAPH-NOT-MATCH-NEXT: }
# LLVM-RELOC-GRAPH-NOT-MATCH-NEXT: CGProfileEntry {
# LLVM-RELOC-GRAPH-NOT-MATCH-NEXT: Weight: 98
# LLVM-RELOC-GRAPH-NOT-MATCH-NEXT: }
# LLVM-RELOC-GRAPH-NOT-MATCH-NEXT: ]
--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_DYN
Machine: EM_X86_64
Sections:
- Name: .llvm.call-graph-profile
Type: SHT_LLVM_CALL_GRAPH_PROFILE
Entries:
- Weight: 89
- Weight: 98
EntSize: [[ENTSIZE=<none>]]
- Name: .rela.llvm.call-graph-profile
Type: SHT_RELA
Info: .llvm.call-graph-profile
Relocations:
- Symbol: foo
Type: R_X86_64_NONE
- Offset: 0x1
Symbol: bar
Type: R_X86_64_NONE
- Offset: 0x2
Symbol: bar
Type: R_X86_64_NONE
- Offset: 0x3
Symbol: foo
Type: R_X86_64_NONE
- Offset: 0x4
Symbol: foo
Type: R_X86_64_NONE
Symbols:
- Name: foo
- Name: bar
## Check we report a warning when a relocation section cant't be loaded.
# RUN: yaml2obj %s --docnum=5 -o %t6.o
# RUN: llvm-readobj %t6.o --cg-profile 2>&1 | FileCheck %s -DFILE=%t6.o --check-prefix=LLVM-RELOC-WRONG-SIZE
# RUN: llvm-readobj %t6.o --elf-cg-profile 2>&1 | FileCheck %s -DFILE=%t6.o --check-prefix=LLVM-RELOC-WRONG-SIZE
# LLVM-RELOC-WRONG-SIZE: warning: '[[FILE]]': unable to load relocations for SHT_LLVM_CALL_GRAPH_PROFILE section: section [index 2] has invalid sh_entsize: expected 24, but got 32
# LLVM-RELOC-WRONG-SIZE-NEXT: CGProfile [
# LLVM-RELOC-WRONG-SIZE-NEXT: CGProfileEntry {
# LLVM-RELOC-WRONG-SIZE-NEXT: Weight: 89
# LLVM-RELOC-WRONG-SIZE-NEXT: }
# LLVM-RELOC-WRONG-SIZE-NEXT: CGProfileEntry {
# LLVM-RELOC-WRONG-SIZE-NEXT: Weight: 98
# LLVM-RELOC-WRONG-SIZE-NEXT: }
# LLVM-RELOC-WRONG-SIZE-NEXT: ]
--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_DYN
Machine: EM_X86_64
Sections:
- Name: .llvm.call-graph-profile
Type: SHT_LLVM_CALL_GRAPH_PROFILE
Entries:
- Weight: 89
- Weight: 98
EntSize: [[ENTSIZE=<none>]]
- Name: .rela.llvm.call-graph-profile
Type: SHT_RELA
Info: .llvm.call-graph-profile
Relocations:
- Symbol: foo
Type: R_X86_64_NONE
- Offset: 0x1
Symbol: bar
Type: R_X86_64_NONE
- Offset: 0x2
Symbol: bar
Type: R_X86_64_NONE
- Offset: 0x3
Symbol: foo
Type: R_X86_64_NONE
EntSize: 32
Symbols:
- Name: foo
- Name: bar

View File

@ -197,8 +197,17 @@ Sections:
- Name: .llvm.call-graph-profile
Type: SHT_LLVM_CALL_GRAPH_PROFILE
Link: .symtab
EntSize: 16
Content: "01000000020000002000000000000000"
EntSize: 8
Content: "2000000000000000"
- Name: .rela.llvm.call-graph-profile
Type: SHT_RELA
Info: .llvm.call-graph-profile
Relocations:
- Symbol: 1
Type: R_X86_64_NONE
- Offset: 0x1
Symbol: 2
Type: R_X86_64_NONE
- Name: .llvm_addrsig
Type: SHT_LLVM_ADDRSIG
Link: .symtab

View File

@ -16,12 +16,8 @@
# BASIC-NEXT: Type: SHT_LLVM_CALL_GRAPH_PROFILE
# BASIC-NEXT: Link: .symtab
# BASIC-NEXT: Entries:
# BASIC-NEXT: - From: foo
# BASIC-NEXT: To: bar
# BASIC-NEXT: Weight: 89
# BASIC-NEXT: - From: bar
# BASIC-NEXT: To: foo
# BASIC-NEXT: Weight: 98
# BASIC-NEXT: - Weight: 89
# BASIC-NEXT: - Weight: 98
# BASIC-NEXT: Symbols:
--- !ELF
@ -33,12 +29,8 @@ Sections:
- Name: .llvm.call-graph-profile
Type: SHT_LLVM_CALL_GRAPH_PROFILE
Entries:
- From: 1
To: 2
Weight: 89
- From: 2
To: 1
Weight: 98
- Weight: 89
- Weight: 98
Symbols:
- Name: foo
- Name: bar
@ -57,59 +49,45 @@ Symbols:
# INVALID-NEXT: - Name: .empty
# INVALID-NEXT: Type: SHT_LLVM_CALL_GRAPH_PROFILE
# INVALID-NEXT: Link: .symtab
# INVALID-NEXT: - Name: .multiple.16.valid
# INVALID-NEXT: - Name: .multiple.8.valid
# INVALID-NEXT: Type: SHT_LLVM_CALL_GRAPH_PROFILE
# INVALID-NEXT: Link: .symtab
# INVALID-NEXT: Entries:
# INVALID-NEXT: - From: foo
# INVALID-NEXT: To: bar
# INVALID-NEXT: Weight: 3
# INVALID-NEXT: - Name: .non.multiple.16
# INVALID-NEXT: - Name: .non.multiple.8
# INVALID-NEXT: Type: SHT_LLVM_CALL_GRAPH_PROFILE
# INVALID-NEXT: Link: .symtab
# INVALID-NEXT: Content: '0000000100000002000000000000000300'
# INVALID-NEXT: - Name: .multiple.16.invalid
# INVALID-NEXT: Content: '000000000000000300'
# INVALID-NEXT: - Name: .multiple.8.invalid
# INVALID-NEXT: Type: SHT_LLVM_CALL_GRAPH_PROFILE
# INVALID-NEXT: Link: .symtab
# INVALID-NEXT: Content: 00112233445566778899AABBCCDDEEFF
# INVALID-NEXT: - Name: .unknown.symbol.1
# INVALID-NEXT: Type: SHT_LLVM_CALL_GRAPH_PROFILE
# INVALID-NEXT: Link: .symtab
# INVALID-NEXT: Content: 000000FF000000020000000000000003
# INVALID-NEXT: - Name: .unknown.symbol.2
# INVALID-NEXT: Type: SHT_LLVM_CALL_GRAPH_PROFILE
# INVALID-NEXT: Link: .symtab
# INVALID-NEXT: Content: 00000001000000FF0000000000000003
# INVALID-NEXT: Content: 008899AABBCCDDEEFF
# INVALID-NEXT: - Name: .link.to.symtable
# INVALID-NEXT: Type: SHT_LLVM_CALL_GRAPH_PROFILE
# INVALID-NEXT: Link: .symtab
# INVALID-NEXT: Entries:
# INVALID-NEXT: - From: foo
# INVALID-NEXT: To: bar
# INVALID-NEXT: Weight: 0
# INVALID-NEXT: - Weight: 0
# INVALID-NEXT: - Name: .link.to.non.symtable.1
# INVALID-NEXT: Type: SHT_LLVM_CALL_GRAPH_PROFILE
# INVALID-NEXT: Content: '00000001000000020000000000000000'
# INVALID-NEXT: Entries:
# INVALID-NEXT: - Weight: 0
# INVALID-NEXT: - Name: .link.to.non.symtable.2
# INVALID-NEXT: Type: SHT_LLVM_CALL_GRAPH_PROFILE
# INVALID-NEXT: Link: .empty
# INVALID-NEXT: Content: '00000001000000020000000000000000'
# INVALID-NEXT: Entries:
# INVALID-NEXT: - Weight: 0
# INVALID-NEXT: - Name: .zero.entry.size
# INVALID-NEXT: Type: SHT_LLVM_CALL_GRAPH_PROFILE
# INVALID-NEXT: Link: .symtab
# INVALID-NEXT: EntSize: 0x0
# INVALID-NEXT: Entries:
# INVALID-NEXT: - From: foo
# INVALID-NEXT: To: bar
# INVALID-NEXT: Weight: 0
# INVALID-NEXT: - Weight: 0
# INVALID-NEXT: - Name: .invalid.entry.size
# INVALID-NEXT: Type: SHT_LLVM_CALL_GRAPH_PROFILE
# INVALID-NEXT: Link: .symtab
# INVALID-NEXT: EntSize: 0x1
# INVALID-NEXT: Entries:
# INVALID-NEXT: - From: foo
# INVALID-NEXT: To: bar
# INVALID-NEXT: Weight: 0
# INVALID-NEXT: - Weight: 0
# INVALID-NEXT: Symbols:
# INVALID-NEXT: - Name: foo
# INVALID-NEXT: - Name: bar
@ -129,67 +107,43 @@ Sections:
## using the "Content" property otherwise.
## TODO: Teach yaml2obj to accept 'Size' key for SHT_LLVM_CALL_GRAPH_PROFILE
## sections and use Entries for cases below.
- Name: .multiple.16.valid
- Name: .multiple.8.valid
Type: SHT_LLVM_CALL_GRAPH_PROFILE
Content: "00000001000000020000000000000003"
- Name: .non.multiple.16
Content: "0000000000000003"
- Name: .non.multiple.8
Type: SHT_LLVM_CALL_GRAPH_PROFILE
Content: "0000000100000002000000000000000300"
- Name: .multiple.16.invalid
Content: "000000000000000300"
- Name: .multiple.8.invalid
Type: SHT_LLVM_CALL_GRAPH_PROFILE
Content: "00112233445566778899AABBCCDDEEFF"
## Case 3: Check we use the "Content" property when unable to match a
## symbol index to a symbol.
- Name: .unknown.symbol.1
Type: SHT_LLVM_CALL_GRAPH_PROFILE
Entries:
- From: 0xff
To: 2
Weight: 3
- Name: .unknown.symbol.2
Type: SHT_LLVM_CALL_GRAPH_PROFILE
Entries:
- From: 1
To: 0xff
Weight: 3
Content: "008899AABBCCDDEEFF"
## Case 4: Check we use the "Content" property when a linked section
## is not a symbol table.
- Name: .link.to.symtable
Type: SHT_LLVM_CALL_GRAPH_PROFILE
Entries:
- From: 1
To: 2
Weight: 0
- Weight: 0
- Name: .link.to.non.symtable.1
Type: SHT_LLVM_CALL_GRAPH_PROFILE
Link: 0
Entries:
- From: 1
To: 2
Weight: 0
- Weight: 0
- Name: .link.to.non.symtable.2
Type: SHT_LLVM_CALL_GRAPH_PROFILE
Link: 1
Entries:
- From: 1
To: 2
Weight: 0
- Weight: 0
## Case 5: Check we can dump a section that has a sh_entsize that is not a multiple of 16.
## Check that in these cases we print the "EntSize" key.
- Name: .zero.entry.size
Type: SHT_LLVM_CALL_GRAPH_PROFILE
EntSize: 0
Entries:
- From: 1
To: 2
Weight: 0
- Weight: 0
- Name: .invalid.entry.size
Type: SHT_LLVM_CALL_GRAPH_PROFILE
EntSize: 1
Entries:
- From: 1
To: 2
Weight: 0
- Weight: 0
Symbols:
- Name: foo
- Name: bar

View File

@ -4,11 +4,11 @@
## for 32/64-bit little/big endian targets is correct.
# RUN: yaml2obj --docnum=1 -D BITS=64 -D ENCODE=LSB %s -o %t.le64
# RUN: llvm-readobj --cg-profile --sections --section-data %t.le64 | FileCheck %s --check-prefixes=BASIC,BASIC-LE
# RUN: yaml2obj --docnum=1 -D BITS=64 -D ENCODE=MSB %s -o %t.be64
# RUN: yaml2obj --docnum=1 -D BITS=64 -D ENCODE=MSB %s -o %t.be64
# RUN: llvm-readobj --cg-profile --sections --section-data %t.be64 | FileCheck %s --check-prefixes=BASIC,BASIC-BE
# RUN: yaml2obj --docnum=1 -D BITS=32 -D ENCODE=LSB %s -o %t.le32
# RUN: yaml2obj --docnum=1 -D BITS=32 -D ENCODE=LSB %s -o %t.le32
# RUN: llvm-readobj --cg-profile --sections --section-data %t.le32 | FileCheck %s --check-prefixes=BASIC,BASIC-LE
# RUN: yaml2obj --docnum=1 -D BITS=32 -D ENCODE=MSB %s -o %t.be32
# RUN: yaml2obj --docnum=1 -D BITS=32 -D ENCODE=MSB %s -o %t.be32
# RUN: llvm-readobj --cg-profile --sections --section-data %t.be32 | FileCheck %s --check-prefixes=BASIC,BASIC-BE
# BASIC: Name: .llvm.call-graph-profile
@ -17,33 +17,27 @@
# BASIC-NEXT: ]
# BASIC-NEXT: Address: 0x0
# BASIC-NEXT: Offset:
# BASIC-NEXT: Size: 32
# BASIC-NEXT: Size: 16
## Check that we link SHT_LLVM_CALL_GRAPH_PROFILE section with .symtab by default.
# BASIC-NEXT: Link: [[SYMTABNDX:.*]]
# BASIC-NEXT: Info: 0
# BASIC-NEXT: AddressAlignment: 0
## Check that the entry size is set to 16 by default.
# BASIC-NEXT: EntrySize: 16
# BASIC-NEXT: EntrySize: 8
# BASIC-NEXT: SectionData (
# BASIC-LE-NEXT: 0000: 01000000 02000000 59000000 00000000
# BASIC-LE-NEXT: 0010: 02000000 01000000 62000000 00000000
# BASIC-BE-NEXT: 0000: 00000001 00000002 00000000 00000059
# BASIC-BE-NEXT: 0010: 00000002 00000001 00000000 00000062
# BASIC-LE-NEXT: 0000: 59000000 00000000 62000000 00000000
# BASIC-BE-NEXT: 0000: 00000000 00000059 00000000 00000062
# BASIC-NEXT: )
# BASIC-NEXT: }
# BASIC-NEXT: Section {
# BASIC-NEXT: Index: [[SYMTABNDX]]
# BASIC-NEXT: Name: .symtab
# BASIC-NEXT: Index: [[SYMTABNDX]]
# BASIC-NEXT: Name: .symtab
# BASIC: CGProfile [
# BASIC-NEXT: CGProfileEntry {
# BASIC-NEXT: From: foo (1)
# BASIC-NEXT: To: bar (2)
# BASIC-NEXT: Weight: 89
# BASIC-NEXT: }
# BASIC-NEXT: CGProfileEntry {
# BASIC-NEXT: From: bar (2)
# BASIC-NEXT: To: foo (1)
# BASIC-NEXT: Weight: 98
# BASIC-NEXT: }
# BASIC-NEXT: ]
@ -57,12 +51,8 @@ Sections:
- Name: .llvm.call-graph-profile
Type: SHT_LLVM_CALL_GRAPH_PROFILE
Entries:
- From: 1
To: 2
Weight: 89
- From: 2
To: 1
Weight: 98
- Weight: 89
- Weight: 98
Symbols:
- Name: foo
- Name: bar
@ -91,47 +81,8 @@ Sections:
Link: 0xFF
EntSize: 0xFF
## Check we can refer to symbols by name.
# RUN: yaml2obj --docnum=3 %s -o %t.sym
# RUN: llvm-readobj --cg-profile %t.sym | FileCheck %s --check-prefix=SYMBOL-NAMES
# SYMBOL-NAMES: CGProfile [
# SYMBOL-NAMES-NEXT: CGProfileEntry {
# SYMBOL-NAMES-NEXT: From: foo (1)
# SYMBOL-NAMES-NEXT: To: bar (2)
# SYMBOL-NAMES-NEXT: Weight: 10
# SYMBOL-NAMES-NEXT: }
# SYMBOL-NAMES-NEXT: CGProfileEntry {
# SYMBOL-NAMES-NEXT: From: foo (1)
# SYMBOL-NAMES-NEXT: To: foo (3)
# SYMBOL-NAMES-NEXT: Weight: 30
# SYMBOL-NAMES-NEXT: }
# SYMBOL-NAMES-NEXT: ]
--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_DYN
Sections:
- Name: .llvm.call-graph-profile
Type: SHT_LLVM_CALL_GRAPH_PROFILE
Entries:
## Case 1: Test we can use symbol names to describe an entry.
- From: foo
To: bar
Weight: 10
## Case 2: Test we can refer to symbols with suffixes.
- From: foo
To: 'foo (1)'
Weight: 30
Symbols:
- Name: foo
- Name: bar
- Name: 'foo (1)'
## Check we can describe SHT_LLVM_CALL_GRAPH_PROFILE sections using the "Content" tag.
# RUN: yaml2obj --docnum=4 %s -o %t.content
# RUN: yaml2obj --docnum=3 %s -o %t.content
# RUN: llvm-readobj --sections --section-data %t.content | FileCheck %s --check-prefix=CONTENT
# CONTENT: Name: .llvm.call-graph-profile
@ -149,69 +100,10 @@ Sections:
Type: SHT_LLVM_CALL_GRAPH_PROFILE
Content: "11223344"
## Check we can't reference unknown symbols by name.
# RUN: not yaml2obj --docnum=5 %s 2>&1 | FileCheck %s --check-prefix=UNKNOWN-NAME
# RUN: not yaml2obj --docnum=6 %s 2>&1 | FileCheck %s --check-prefix=UNKNOWN-NAME
# UNKNOWN-NAME: error: unknown symbol referenced: 'bar' by YAML section '.llvm.call-graph-profile'
--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_DYN
Sections:
- Name: .llvm.call-graph-profile
Type: SHT_LLVM_CALL_GRAPH_PROFILE
## The first symbol is valid, but the second is unknown.
Entries:
- From: foo
To: bar
Weight: 10
Symbols:
- Name: foo
--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_DYN
Sections:
- Name: .llvm.call-graph-profile
Type: SHT_LLVM_CALL_GRAPH_PROFILE
## The first symbol is unknown, but the second is valid.
Entries:
- From: bar
To: foo
Weight: 10
Symbols:
- Name: foo
## Check we can specify arbitrary symbol indexes for an SHT_LLVM_CALL_GRAPH_PROFILE section entry.
# RUN: yaml2obj --docnum=7 %s -o %t.unk
# RUN: llvm-readobj --sections --section-data %t.unk | FileCheck %s --check-prefix=UNKNOWN-INDEX
# UNKNOWN-INDEX: Name: .llvm.call-graph-profile
# UNKNOWN-INDEX: SectionData (
# UNKNOWN-INDEX-NEXT: 0000: 01000000 02000000 03000000 00000000 |
# UNKNOWN-INDEX-NEXT: )
--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_DYN
Sections:
- Name: .llvm.call-graph-profile
Type: SHT_LLVM_CALL_GRAPH_PROFILE
Entries:
- From: 1
To: 2
Weight: 3
## Check we can use the "Content" key with the "Size" key when the size is greater
## than or equal to the content size.
# RUN: not yaml2obj --docnum=8 -DSIZE=1 -DCONTENT="'0011'" %s 2>&1 | \
# RUN: not yaml2obj --docnum=4 -DSIZE=1 -DCONTENT="'0011'" %s 2>&1 | \
# RUN: FileCheck %s --check-prefix=CONTENT-SIZE-ERR
# CONTENT-SIZE-ERR: error: Section size must be greater than or equal to the content size
@ -230,11 +122,11 @@ Sections:
Content: [[CONTENT=<none>]]
Entries: [[ENTRIES=<none>]]
# RUN: yaml2obj --docnum=8 -DSIZE=2 -DCONTENT="'0011'" %s -o %t.cont.size.eq.o
# RUN: yaml2obj --docnum=4 -DSIZE=2 -DCONTENT="'0011'" %s -o %t.cont.size.eq.o
# RUN: llvm-readobj --sections --section-data %t.cont.size.eq.o | \
# RUN: FileCheck %s --check-prefix=CHECK-CONTENT -DDATA="0011"
# RUN: yaml2obj --docnum=8 -DSIZE=3 -DCONTENT="'0011'" %s -o %t.cont.size.gr.o
# RUN: yaml2obj --docnum=4 -DSIZE=3 -DCONTENT="'0011'" %s -o %t.cont.size.gr.o
# RUN: llvm-readobj --sections --section-data %t.cont.size.gr.o | \
# RUN: FileCheck %s --check-prefix=CHECK-CONTENT -DDATA="001100"
@ -255,21 +147,21 @@ Sections:
## Check we can use the "Size" key alone to create the section.
# RUN: yaml2obj --docnum=8 -DSIZE=3 %s -o %t.size.o
# RUN: yaml2obj --docnum=4 -DSIZE=3 %s -o %t.size.o
# RUN: llvm-readobj --sections --section-data %t.size.o | \
# RUN: FileCheck %s --check-prefix=CHECK-CONTENT -DDATA="000000"
## Check we can use the "Content" key alone to create the section.
# RUN: yaml2obj --docnum=8 -DCONTENT="'112233'" %s -o %t.content.o
# RUN: yaml2obj --docnum=4 -DCONTENT="'112233'" %s -o %t.content.o
# RUN: llvm-readobj --sections --section-data %t.content.o | \
# RUN: FileCheck %s --check-prefix=CHECK-CONTENT -DDATA="112233"
## Check we can't use the "Entries" key together with the "Content" or "Size" keys.
# RUN: not yaml2obj --docnum=8 -DSIZE=0 -DENTRIES="[]" %s 2>&1 | \
# RUN: not yaml2obj --docnum=4 -DSIZE=0 -DENTRIES="[]" %s 2>&1 | \
# RUN: FileCheck %s --check-prefix=ENTRIES-ERR
# RUN: not yaml2obj --docnum=8 -DCONTENT="'00'" -DENTRIES="[]" %s 2>&1 | \
# RUN: not yaml2obj --docnum=4 -DCONTENT="'00'" -DENTRIES="[]" %s 2>&1 | \
# RUN: FileCheck %s --check-prefix=ENTRIES-ERR
# ENTRIES-ERR: error: "Entries" cannot be used with "Content" or "Size"

View File

@ -367,7 +367,7 @@ Sections:
# RUN: llvm-readelf %t7 --section-headers | FileCheck %s --check-prefix=LINK-IMPLICIT
# LINK-IMPLICIT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al
# LINK-IMPLICIT: [ 1] .cgp LLVM_CALL_GRAPH_PROFILE 0000000000000000 000040 000000 10 0 0 0
# LINK-IMPLICIT: [ 1] .cgp LLVM_CALL_GRAPH_PROFILE 0000000000000000 000040 000000 08 0 0 0
# LINK-IMPLICIT-NEXT: [ 2] .llvm_addrsig LLVM_ADDRSIG 0000000000000000 000040 000000 00 0 0 0
# LINK-IMPLICIT-NEXT: [ 3] .group GROUP 0000000000000000 000040 000000 04 0 0 0
# LINK-IMPLICIT-NEXT: [ 4] .rela RELA 0000000000000000 000040 000000 18 0 0 0

View File

@ -318,6 +318,12 @@ protected:
void printRelocatableStackSizes(std::function<void()> PrintHeader);
void printNonRelocatableStackSizes(std::function<void()> PrintHeader);
/// Retrieves sections with corresponding relocation sections based on
/// IsMatch.
void getSectionAndRelocations(
std::function<bool(const Elf_Shdr &)> IsMatch,
llvm::MapVector<const Elf_Shdr *, const Elf_Shdr *> &SecToRelocMap);
const object::ELFObjectFile<ELFT> &ObjF;
const ELFFile<ELFT> &Obj;
StringRef FileName;
@ -356,7 +362,6 @@ protected:
const Elf_GnuHash *GnuHashTable = nullptr;
const Elf_Shdr *DotSymtabSec = nullptr;
const Elf_Shdr *DotDynsymSec = nullptr;
const Elf_Shdr *DotCGProfileSec = nullptr;
const Elf_Shdr *DotAddrsigSec = nullptr;
DenseMap<const Elf_Shdr *, ArrayRef<Elf_Word>> ShndxTables;
Optional<uint64_t> SONameOffset;
@ -1838,10 +1843,6 @@ ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> &O,
if (!SymbolVersionNeedSection)
SymbolVersionNeedSection = &Sec;
break;
case ELF::SHT_LLVM_CALL_GRAPH_PROFILE:
if (!DotCGProfileSec)
DotCGProfileSec = &Sec;
break;
case ELF::SHT_LLVM_ADDRSIG:
if (!DotAddrsigSec)
DotAddrsigSec = &Sec;
@ -5898,28 +5899,15 @@ void ELFDumper<ELFT>::printNonRelocatableStackSizes(
}
template <class ELFT>
void ELFDumper<ELFT>::printRelocatableStackSizes(
std::function<void()> PrintHeader) {
// Build a map between stack size sections and their corresponding relocation
// sections.
llvm::MapVector<const Elf_Shdr *, const Elf_Shdr *> StackSizeRelocMap;
void ELFDumper<ELFT>::getSectionAndRelocations(
std::function<bool(const Elf_Shdr &)> IsMatch,
llvm::MapVector<const Elf_Shdr *, const Elf_Shdr *> &SecToRelocMap) {
for (const Elf_Shdr &Sec : cantFail(Obj.sections())) {
StringRef SectionName;
if (Expected<StringRef> NameOrErr = Obj.getSectionName(Sec))
SectionName = *NameOrErr;
else
consumeError(NameOrErr.takeError());
// A stack size section that we haven't encountered yet is mapped to the
// null section until we find its corresponding relocation section.
if (SectionName == ".stack_sizes")
if (StackSizeRelocMap
.insert(std::make_pair(&Sec, (const Elf_Shdr *)nullptr))
if (IsMatch(Sec))
if (SecToRelocMap.insert(std::make_pair(&Sec, (const Elf_Shdr *)nullptr))
.second)
continue;
// Check relocation sections if they are relocating contents of a
// stack sizes section.
if (Sec.sh_type != ELF::SHT_RELA && Sec.sh_type != ELF::SHT_REL)
continue;
@ -5930,14 +5918,28 @@ void ELFDumper<ELFT>::printRelocatableStackSizes(
toString(RelSecOrErr.takeError()));
continue;
}
const Elf_Shdr *ContentsSec = *RelSecOrErr;
if (this->getPrintableSectionName(**RelSecOrErr) != ".stack_sizes")
continue;
// Insert a mapping from the stack sizes section to its relocation section.
StackSizeRelocMap[ContentsSec] = &Sec;
if (IsMatch(*ContentsSec))
SecToRelocMap[ContentsSec] = &Sec;
}
}
template <class ELFT>
void ELFDumper<ELFT>::printRelocatableStackSizes(
std::function<void()> PrintHeader) {
// Build a map between stack size sections and their corresponding relocation
// sections.
llvm::MapVector<const Elf_Shdr *, const Elf_Shdr *> StackSizeRelocMap;
auto IsMatch = [&](const Elf_Shdr &Sec) -> bool {
StringRef SectionName;
if (Expected<StringRef> NameOrErr = Obj.getSectionName(Sec))
SectionName = *NameOrErr;
else
consumeError(NameOrErr.takeError());
return SectionName == ".stack_sizes";
};
getSectionAndRelocations(IsMatch, StackSizeRelocMap);
for (const auto &StackSizeMapEntry : StackSizeRelocMap) {
PrintHeader();
@ -6699,27 +6701,65 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printHashHistograms() {
}
template <class ELFT> void LLVMELFDumper<ELFT>::printCGProfile() {
ListScope L(W, "CGProfile");
if (!this->DotCGProfileSec)
return;
llvm::MapVector<const Elf_Shdr *, const Elf_Shdr *> SecToRelocMap;
Expected<ArrayRef<Elf_CGProfile>> CGProfileOrErr =
this->Obj.template getSectionContentsAsArray<Elf_CGProfile>(
*this->DotCGProfileSec);
if (!CGProfileOrErr) {
this->reportUniqueWarning(
"unable to dump the SHT_LLVM_CALL_GRAPH_PROFILE section: " +
toString(CGProfileOrErr.takeError()));
return;
}
auto IsMatch = [](const Elf_Shdr &Sec) -> bool {
return Sec.sh_type == ELF::SHT_LLVM_CALL_GRAPH_PROFILE;
};
this->getSectionAndRelocations(IsMatch, SecToRelocMap);
for (const Elf_CGProfile &CGPE : *CGProfileOrErr) {
DictScope D(W, "CGProfileEntry");
W.printNumber("From", this->getStaticSymbolName(CGPE.cgp_from),
CGPE.cgp_from);
W.printNumber("To", this->getStaticSymbolName(CGPE.cgp_to),
CGPE.cgp_to);
W.printNumber("Weight", CGPE.cgp_weight);
for (const auto &CGMapEntry : SecToRelocMap) {
const Elf_Shdr *CGSection = CGMapEntry.first;
const Elf_Shdr *CGRelSection = CGMapEntry.second;
Expected<ArrayRef<Elf_CGProfile>> CGProfileOrErr =
this->Obj.template getSectionContentsAsArray<Elf_CGProfile>(*CGSection);
if (!CGProfileOrErr) {
this->reportUniqueWarning(
"unable to load the SHT_LLVM_CALL_GRAPH_PROFILE section: " +
toString(CGProfileOrErr.takeError()));
return;
}
Elf_Rela_Range CGProfileRela;
bool UseReloc = (CGRelSection != nullptr);
if (UseReloc) {
Expected<Elf_Rela_Range> CGProfileRelaOrError =
this->Obj.relas(*CGRelSection);
if (!CGProfileRelaOrError) {
this->reportUniqueWarning("unable to load relocations for "
"SHT_LLVM_CALL_GRAPH_PROFILE section: " +
toString(CGProfileRelaOrError.takeError()));
UseReloc = false;
} else
CGProfileRela = *CGProfileRelaOrError;
if (UseReloc && CGProfileRela.size() != (CGProfileOrErr->size() * 2)) {
this->reportUniqueWarning(
"number of from/to pairs does not match number of frequencies");
UseReloc = false;
}
} else
this->reportUniqueWarning(
"relocation section for a call graph section doesn't exist");
auto GetIndex = [&](uint32_t Index) {
const Elf_Rel_Impl<ELFT, true> &Rel = CGProfileRela[Index];
return Rel.getSymbol(this->Obj.isMips64EL());
};
ListScope L(W, "CGProfile");
for (uint32_t I = 0, Size = CGProfileOrErr->size(); I != Size; ++I) {
const Elf_CGProfile &CGPE = (*CGProfileOrErr)[I];
DictScope D(W, "CGProfileEntry");
if (UseReloc) {
uint32_t From = GetIndex(I * 2);
uint32_t To = GetIndex(I * 2 + 1);
W.printNumber("From", this->getStaticSymbolName(From), From);
W.printNumber("To", this->getStaticSymbolName(To), To);
}
W.printNumber("Weight", CGPE.cgp_weight);
}
}
}

View File

@ -1022,41 +1022,31 @@ ELFDumper<ELFT>::dumpCallGraphProfileSection(const Elf_Shdr *Shdr) {
if (!ContentOrErr)
return ContentOrErr.takeError();
ArrayRef<uint8_t> Content = *ContentOrErr;
const uint32_t SizeOfEntry = ELFYAML::getDefaultShEntSize<ELFT>(
Obj.getHeader().e_machine, S->Type, S->Name);
// Dump the section by using the Content key when it is truncated.
// There is no need to create either "Content" or "Entries" fields when the
// section is empty.
if (Content.empty() || Content.size() % 16 != 0) {
if (Content.empty() || Content.size() % SizeOfEntry != 0) {
if (!Content.empty())
S->Content = yaml::BinaryRef(Content);
return S.release();
}
std::vector<ELFYAML::CallGraphEntry> Entries(Content.size() / 16);
std::vector<ELFYAML::CallGraphEntryWeight> Entries(Content.size() /
SizeOfEntry);
DataExtractor Data(Content, Obj.isLE(), /*AddressSize=*/0);
DataExtractor::Cursor Cur(0);
auto ReadEntry = [&](ELFYAML::CallGraphEntry &E) {
uint32_t FromSymIndex = Data.getU32(Cur);
uint32_t ToSymIndex = Data.getU32(Cur);
auto ReadEntry = [&](ELFYAML::CallGraphEntryWeight &E) {
E.Weight = Data.getU64(Cur);
if (!Cur) {
consumeError(Cur.takeError());
return false;
}
Expected<StringRef> From = getSymbolName(Shdr->sh_link, FromSymIndex);
Expected<StringRef> To = getSymbolName(Shdr->sh_link, ToSymIndex);
if (From && To) {
E.From = *From;
E.To = *To;
return true;
}
consumeError(From.takeError());
consumeError(To.takeError());
return false;
return true;
};
for (ELFYAML::CallGraphEntry &E : Entries) {
for (ELFYAML::CallGraphEntryWeight &E : Entries) {
if (ReadEntry(E))
continue;
S->Content = yaml::BinaryRef(Content);