mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 04:02:41 +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:
parent
ad844f8999
commit
d12ae1eaf8
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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> {
|
||||
|
@ -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()
|
||||
|
@ -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,
|
||||
|
@ -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>);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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: []
|
||||
...
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user