[yaml2obj/obj2yaml] - Add support for the SHT_LLVM_CALL_GRAPH_PROFILE section.

This is a LLVM specific section that is well described here:
https://llvm.org/docs/Extensions.html#sht-llvm-call-graph-profile-section-call-graph-profile

This patch teaches yaml2obj and obj2yaml about how to work with it.

Differential revision: https://reviews.llvm.org/D73788
This commit is contained in:
Georgii Rymar 2020-01-31 12:43:09 +03:00
parent 92570718a8
commit bec54e464e
6 changed files with 722 additions and 0 deletions

View File

@ -153,6 +153,7 @@ struct Chunk {
Fill,
LinkerOptions,
DependentLibraries,
CallGraphProfile
};
ChunkKind Kind;
@ -385,6 +386,27 @@ 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;
// The weight of the edge.
uint64_t Weight;
};
struct CallGraphProfileSection : Section {
Optional<std::vector<CallGraphEntry>> Entries;
Optional<yaml::BinaryRef> Content;
CallGraphProfileSection() : Section(ChunkKind::CallGraphProfile) {}
static bool classof(const Chunk *S) {
return S->Kind == ChunkKind::CallGraphProfile;
}
};
struct SymverSection : Section {
std::vector<uint16_t> Entries;
@ -514,6 +536,7 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::AddrsigSymbol)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::StackSizeEntry)
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::NoteEntry)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::ProgramHeader)
LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr<llvm::ELFYAML::Chunk>)
@ -685,6 +708,10 @@ 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::Relocation> {
static void mapping(IO &IO, ELFYAML::Relocation &Rel);
};

View File

@ -210,6 +210,9 @@ template <class ELFT> class ELFState {
void writeSectionContent(Elf_Shdr &SHeader,
const ELFYAML::DependentLibrariesSection &Section,
ContiguousBlobAccumulator &CBA);
void writeSectionContent(Elf_Shdr &SHeader,
const ELFYAML::CallGraphProfileSection &Section,
ContiguousBlobAccumulator &CBA);
void writeFill(ELFYAML::Fill &Fill, ContiguousBlobAccumulator &CBA);
@ -492,6 +495,8 @@ void ELFState<ELFT>::initSectionHeaders(std::vector<Elf_Shdr> &SHeaders,
writeSectionContent(SHeader, *S, CBA);
} else if (auto S = dyn_cast<ELFYAML::DependentLibrariesSection>(Sec)) {
writeSectionContent(SHeader, *S, CBA);
} else if (auto S = dyn_cast<ELFYAML::CallGraphProfileSection>(Sec)) {
writeSectionContent(SHeader, *S, CBA);
} else {
llvm_unreachable("Unknown section type");
}
@ -982,6 +987,41 @@ void ELFState<ELFT>::writeSectionContent(
}
}
template <class ELFT>
void ELFState<ELFT>::writeSectionContent(
Elf_Shdr &SHeader, const ELFYAML::CallGraphProfileSection &Section,
ContiguousBlobAccumulator &CBA) {
raw_ostream &OS =
CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign);
if (Section.EntSize)
SHeader.sh_entsize = *Section.EntSize;
else
SHeader.sh_entsize = 16;
unsigned Link = 0;
if (Section.Link.empty() && SN2I.lookup(".symtab", Link))
SHeader.sh_link = Link;
if (Section.Content) {
SHeader.sh_size = writeContent(OS, Section.Content, None);
return;
}
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);
support::endian::write<uint32_t>(OS, From, ELFT::TargetEndianness);
support::endian::write<uint32_t>(OS, To, ELFT::TargetEndianness);
support::endian::write<uint64_t>(OS, E.Weight, ELFT::TargetEndianness);
SHeader.sh_size += 16;
}
}
template <class ELFT>
void ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
const ELFYAML::HashSection &Section,

View File

@ -1149,6 +1149,12 @@ static void sectionMapping(IO &IO,
IO.mapOptional("Content", Section.Content);
}
static void sectionMapping(IO &IO, ELFYAML::CallGraphProfileSection &Section) {
commonSectionMapping(IO, Section);
IO.mapOptional("Entries", Section.Entries);
IO.mapOptional("Content", Section.Content);
}
void MappingTraits<ELFYAML::SectionOrType>::mapping(
IO &IO, ELFYAML::SectionOrType &sectionOrType) {
IO.mapRequired("SectionOrType", sectionOrType.sectionNameOrType);
@ -1282,6 +1288,11 @@ void MappingTraits<std::unique_ptr<ELFYAML::Chunk>>::mapping(
sectionMapping(IO,
*cast<ELFYAML::DependentLibrariesSection>(Section.get()));
break;
case ELF::SHT_LLVM_CALL_GRAPH_PROFILE:
if (!IO.outputting())
Section.reset(new ELFYAML::CallGraphProfileSection());
sectionMapping(IO, *cast<ELFYAML::CallGraphProfileSection>(Section.get()));
break;
default:
if (!IO.outputting()) {
StringRef Name;
@ -1463,6 +1474,12 @@ StringRef MappingTraits<std::unique_ptr<ELFYAML::Chunk>>::validate(
return {};
}
if (const auto *CGP = dyn_cast<ELFYAML::CallGraphProfileSection>(C.get())) {
if (CGP->Entries && CGP->Content)
return "\"Entries\" and \"Content\" can't be used together";
return {};
}
return {};
}
@ -1600,6 +1617,14 @@ void MappingTraits<ELFYAML::LinkerOption>::mapping(IO &IO,
IO.mapRequired("Value", Opt.Value);
}
void MappingTraits<ELFYAML::CallGraphEntry>::mapping(
IO &IO, ELFYAML::CallGraphEntry &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);
}
LLVM_YAML_STRONG_TYPEDEF(uint8_t, MIPS_AFL_REG)
LLVM_YAML_STRONG_TYPEDEF(uint8_t, MIPS_ABI_FP)
LLVM_YAML_STRONG_TYPEDEF(uint32_t, MIPS_AFL_EXT)

View File

@ -0,0 +1,269 @@
## Test how we dump SHT_LLVM_CALL_GRAPH_PROFILE sections for 32 and 64-bit targets.
## Test we use the "Entries" property when it is possible to dump values correctly.
# RUN: yaml2obj --docnum=1 %s -o %t.le64
# RUN: obj2yaml %t.le64 | FileCheck %s --check-prefix=BASIC
# RUN: yaml2obj --docnum=2 %s -o %t.be64
# RUN: obj2yaml %t.be64 | FileCheck %s --check-prefix=BASIC
# RUN: yaml2obj --docnum=3 %s -o %t.le32
# RUN: obj2yaml %t.le32 | FileCheck %s --check-prefix=BASIC
# RUN: yaml2obj --docnum=4 %s -o %t.be32
# RUN: obj2yaml %t.be32 | FileCheck %s --check-prefix=BASIC
# BASIC: Sections:
# BASIC-NEXT: - Name: .llvm.call-graph-profile
# BASIC-NEXT: Type: SHT_LLVM_CALL_GRAPH_PROFILE
# BASIC-NEXT: Link: .symtab
# BASIC-NEXT: EntSize: 0x0000000000000010
# 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: Symbols:
## TODO: we should really improve yaml2obj somehow to be able to collapse
## the following four YAML descriptions into a single one.
--- !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:
- From: 1
To: 2
Weight: 89
- From: 2
To: 1
Weight: 98
Symbols:
- Name: foo
- Name: bar
--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2MSB
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: 89
- From: 2
To: 1
Weight: 98
Symbols:
- Name: foo
- Name: bar
--- !ELF
FileHeader:
Class: ELFCLASS32
Data: ELFDATA2LSB
Type: ET_DYN
Machine: EM_386
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
Symbols:
- Name: foo
- Name: bar
--- !ELF
FileHeader:
Class: ELFCLASS32
Data: ELFDATA2MSB
Type: ET_DYN
Machine: EM_386
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
Symbols:
- Name: foo
- Name: bar
## Check how we handle broken cases.
# RUN: yaml2obj --docnum=5 %s -o %t.invalid
# RUN: obj2yaml %t.invalid | FileCheck %s --check-prefix=INVALID
# INVALID: --- !ELF
# INVALID-NEXT: FileHeader:
# INVALID-NEXT: Class: ELFCLASS32
# INVALID-NEXT: Data: ELFDATA2MSB
# INVALID-NEXT: Type: ET_DYN
# INVALID-NEXT: Machine: EM_386
# INVALID-NEXT: Sections:
# INVALID-NEXT: - Name: .empty
# INVALID-NEXT: Type: SHT_LLVM_CALL_GRAPH_PROFILE
# INVALID-NEXT: Link: .symtab
# INVALID-NEXT: EntSize: 0x0000000000000010
# INVALID-NEXT: - Name: .multiple.16.valid
# INVALID-NEXT: Type: SHT_LLVM_CALL_GRAPH_PROFILE
# INVALID-NEXT: Link: .symtab
# INVALID-NEXT: EntSize: 0x0000000000000010
# INVALID-NEXT: Entries:
# INVALID-NEXT: - From: foo
# INVALID-NEXT: To: bar
# INVALID-NEXT: Weight: 3
# INVALID-NEXT: - Name: .non.multiple.16
# INVALID-NEXT: Type: SHT_LLVM_CALL_GRAPH_PROFILE
# INVALID-NEXT: Link: .symtab
# INVALID-NEXT: EntSize: 0x0000000000000010
# INVALID-NEXT: Content: '0000000100000002000000000000000300'
# INVALID-NEXT: - Name: .multiple.16.invalid
# INVALID-NEXT: Type: SHT_LLVM_CALL_GRAPH_PROFILE
# INVALID-NEXT: Link: .symtab
# INVALID-NEXT: EntSize: 0x0000000000000010
# INVALID-NEXT: Content: 00112233445566778899AABBCCDDEEFF
# INVALID-NEXT: - Name: .unknown.symbol.1
# INVALID-NEXT: Type: SHT_LLVM_CALL_GRAPH_PROFILE
# INVALID-NEXT: Link: .symtab
# INVALID-NEXT: EntSize: 0x0000000000000010
# INVALID-NEXT: Content: 000000FF000000020000000000000003
# INVALID-NEXT: - Name: .unknown.symbol.2
# INVALID-NEXT: Type: SHT_LLVM_CALL_GRAPH_PROFILE
# INVALID-NEXT: Link: .symtab
# INVALID-NEXT: EntSize: 0x0000000000000010
# INVALID-NEXT: Content: 00000001000000FF0000000000000003
# INVALID-NEXT: - Name: .link.to.symtable
# INVALID-NEXT: Type: SHT_LLVM_CALL_GRAPH_PROFILE
# INVALID-NEXT: Link: .symtab
# INVALID-NEXT: EntSize: 0x0000000000000010
# INVALID-NEXT: Entries:
# INVALID-NEXT: - From: foo
# INVALID-NEXT: To: bar
# INVALID-NEXT: Weight: 0
# INVALID-NEXT: - Name: .link.to.non.symtable.1
# INVALID-NEXT: Type: SHT_LLVM_CALL_GRAPH_PROFILE
# INVALID-NEXT: EntSize: 0x0000000000000010
# INVALID-NEXT: Content: '00000001000000020000000000000000'
# INVALID-NEXT: - Name: .link.to.non.symtable.2
# INVALID-NEXT: Type: SHT_LLVM_CALL_GRAPH_PROFILE
# INVALID-NEXT: Link: .empty
# INVALID-NEXT: EntSize: 0x0000000000000010
# INVALID-NEXT: Content: '00000001000000020000000000000000'
# INVALID-NEXT: - Name: .zero.entry.size
# 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: - Name: .invalid.entry.size
# INVALID-NEXT: Type: SHT_LLVM_CALL_GRAPH_PROFILE
# INVALID-NEXT: Link: .symtab
# INVALID-NEXT: EntSize: 0x0000000000000001
# INVALID-NEXT: Entries:
# INVALID-NEXT: - From: foo
# INVALID-NEXT: To: bar
# INVALID-NEXT: Weight: 0
# INVALID-NEXT: Symbols:
# INVALID-NEXT: - Name: foo
# INVALID-NEXT: - Name: bar
--- !ELF
FileHeader:
Class: ELFCLASS32
Data: ELFDATA2MSB
Type: ET_DYN
Machine: EM_386
Sections:
## Case 1: Content is empty.
- Name: .empty
Type: SHT_LLVM_CALL_GRAPH_PROFILE
## Case 2: Check that we use the "Entries" property to dump the data when it
## has a size that is a multiple of 16 and is valid (it is possible to match
## symbol indexes to symbols), but fallback to dumping the whole section
## 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
Type: SHT_LLVM_CALL_GRAPH_PROFILE
Content: "00000001000000020000000000000003"
- Name: .non.multiple.16
Type: SHT_LLVM_CALL_GRAPH_PROFILE
Content: "0000000100000002000000000000000300"
- Name: .multiple.16.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
## 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
- Name: .link.to.non.symtable.1
Type: SHT_LLVM_CALL_GRAPH_PROFILE
Link: 0
Entries:
- From: 1
To: 2
Weight: 0
- Name: .link.to.non.symtable.2
Type: SHT_LLVM_CALL_GRAPH_PROFILE
Link: 1
Entries:
- From: 1
To: 2
Weight: 0
## Case 5: Check we can dump a section that has a sh_entsize that is not a multiple of 16.
- Name: .zero.entry.size
Type: SHT_LLVM_CALL_GRAPH_PROFILE
EntSize: 0
Entries:
- From: 1
To: 2
Weight: 0
- Name: .invalid.entry.size
Type: SHT_LLVM_CALL_GRAPH_PROFILE
EntSize: 1
Entries:
- From: 1
To: 2
Weight: 0
Symbols:
- Name: foo
- Name: bar

View File

@ -0,0 +1,295 @@
## Test how we create SHT_LLVM_CALL_GRAPH_PROFILE sections.
## Test that the content of SHT_LLVM_CALL_GRAPH_PROFILE sections
## for 32/64-bit little/big endian targets is correct.
# RUN: yaml2obj --docnum=1 %s -o %t.le64
# RUN: llvm-readobj --elf-cg-profile --sections --section-data %t.le64 | FileCheck %s --check-prefixes=BASIC,BASIC-LE
# RUN: yaml2obj --docnum=2 %s -o %t.be64
# RUN: llvm-readobj --elf-cg-profile --sections --section-data %t.be64 | FileCheck %s --check-prefixes=BASIC,BASIC-BE
# RUN: yaml2obj --docnum=3 %s -o %t.le32
# RUN: llvm-readobj --elf-cg-profile --sections --section-data %t.le32 | FileCheck %s --check-prefixes=BASIC,BASIC-LE
# RUN: yaml2obj --docnum=4 %s -o %t.be32
# RUN: llvm-readobj --elf-cg-profile --sections --section-data %t.be32 | FileCheck %s --check-prefixes=BASIC,BASIC-BE
# BASIC: Name: .llvm.call-graph-profile
# BASIC-NEXT: Type: SHT_LLVM_CALL_GRAPH_PROFILE
# BASIC-NEXT: Flags [
# BASIC-NEXT: ]
# BASIC-NEXT: Address: 0x0
# BASIC-NEXT: Offset:
# BASIC-NEXT: Size: 32
## 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: 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-NEXT: )
# BASIC-NEXT: }
# BASIC-NEXT: Section {
# 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: ]
## TODO: we should really improve yaml2obj somehow to be able to collapse
## the following four YAML descriptions into a single one.
--- !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:
- From: 1
To: 2
Weight: 89
- From: 2
To: 1
Weight: 98
Symbols:
- Name: foo
- Name: bar
--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2MSB
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: 89
- From: 2
To: 1
Weight: 98
Symbols:
- Name: foo
- Name: bar
--- !ELF
FileHeader:
Class: ELFCLASS32
Data: ELFDATA2LSB
Type: ET_DYN
Machine: EM_386
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
Symbols:
- Name: foo
- Name: bar
--- !ELF
FileHeader:
Class: ELFCLASS32
Data: ELFDATA2MSB
Type: ET_DYN
Machine: EM_386
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
Symbols:
- Name: foo
- Name: bar
## Check we can set arbitrary sh_link and sh_entsize values.
## Check we can specify neither "Content" nor "Entries" tags.
# RUN: yaml2obj --docnum=5 %s -o %t.link
# RUN: llvm-readelf --sections %t.link | FileCheck %s --check-prefix=LINK
# LINK: [Nr] Name Type Address Off Size ES Flg Lk
# LINK: [ 1] .llvm.foo LLVM_CALL_GRAPH_PROFILE 0000000000000000 000040 000000 00 0
# LINK: [ 2] .llvm.bar LLVM_CALL_GRAPH_PROFILE 0000000000000000 000040 000000 ff 255
--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_DYN
Machine: EM_X86_64
Sections:
- Name: .llvm.foo
Type: SHT_LLVM_CALL_GRAPH_PROFILE
Link: 0x0
EntSize: 0
- Name: .llvm.bar
Type: SHT_LLVM_CALL_GRAPH_PROFILE
Link: 0xFF
EntSize: 0xFF
## Check we can't specify both "Content" and "Entries" tags.
# RUN: not yaml2obj --docnum=6 %s 2>&1 | FileCheck %s --check-prefix=BOTH
# BOTH: error: "Entries" and "Content" can't be used together
--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_DYN
Machine: EM_X86_64
Sections:
- Name: .llvm.foo
Type: SHT_LLVM_CALL_GRAPH_PROFILE
Content: ""
Entries: []
## Check we can refer to symbols by name.
# RUN: yaml2obj --docnum=7 %s -o %t.sym
# RUN: llvm-readobj --elf-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
Machine: EM_X86_64
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=8 %s -o %t.content
# RUN: llvm-readobj --sections --section-data %t.content | FileCheck %s --check-prefix=CONTENT
# CONTENT: Name: .llvm.call-graph-profile
# CONTENT: SectionData (
# CONTENT-NEXT: 0000: 11223344 |
# CONTENT-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
Content: "11223344"
## Check we can't reference unknown symbols by name.
# RUN: not yaml2obj --docnum=9 %s 2>&1 | FileCheck %s --check-prefix=UNKNOWN-NAME
# RUN: not yaml2obj --docnum=10 %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
Machine: EM_X86_64
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
Machine: EM_X86_64
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=11 %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
Machine: EM_X86_64
Sections:
- Name: .llvm.call-graph-profile
Type: SHT_LLVM_CALL_GRAPH_PROFILE
Entries:
- From: 1
To: 2
Weight: 3

View File

@ -65,6 +65,8 @@ class ELFDumper {
dumpLinkerOptionsSection(const Elf_Shdr *Shdr);
Expected<ELFYAML::DependentLibrariesSection *>
dumpDependentLibrariesSection(const Elf_Shdr *Shdr);
Expected<ELFYAML::CallGraphProfileSection *>
dumpCallGraphProfileSection(const Elf_Shdr *Shdr);
Expected<ELFYAML::DynamicSection *> dumpDynamicSection(const Elf_Shdr *Shdr);
Expected<ELFYAML::RelocationSection *> dumpRelocSection(const Elf_Shdr *Shdr);
Expected<ELFYAML::RelrSection *> dumpRelrSection(const Elf_Shdr *Shdr);
@ -346,6 +348,14 @@ template <class ELFT> Expected<ELFYAML::Object *> ELFDumper<ELFT>::dump() {
Y->Chunks.emplace_back(*SecOrErr);
break;
}
case ELF::SHT_LLVM_CALL_GRAPH_PROFILE: {
Expected<ELFYAML::CallGraphProfileSection *> SecOrErr =
dumpCallGraphProfileSection(&Sec);
if (!SecOrErr)
return SecOrErr.takeError();
Y->Chunks.emplace_back(*SecOrErr);
break;
}
case ELF::SHT_NULL: {
// We only dump the SHT_NULL section at index 0 when it
// has at least one non-null field, because yaml2obj
@ -677,6 +687,62 @@ ELFDumper<ELFT>::dumpDependentLibrariesSection(const Elf_Shdr *Shdr) {
return DL.release();
}
template <class ELFT>
Expected<ELFYAML::CallGraphProfileSection *>
ELFDumper<ELFT>::dumpCallGraphProfileSection(const Elf_Shdr *Shdr) {
auto S = std::make_unique<ELFYAML::CallGraphProfileSection>();
if (Error E = dumpCommonSection(Shdr, *S))
return std::move(E);
Expected<ArrayRef<uint8_t>> ContentOrErr = Obj.getSectionContents(Shdr);
if (!ContentOrErr)
return ContentOrErr.takeError();
ArrayRef<uint8_t> Content = *ContentOrErr;
// 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())
S->Content = yaml::BinaryRef(Content);
return S.release();
}
std::vector<ELFYAML::CallGraphEntry> Entries(Content.size() / 16);
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);
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;
};
for (ELFYAML::CallGraphEntry &E : Entries) {
if (ReadEntry(E))
continue;
S->Content = yaml::BinaryRef(Content);
return S.release();
}
S->Entries = std::move(Entries);
return S.release();
}
template <class ELFT>
Expected<ELFYAML::DynamicSection *>
ELFDumper<ELFT>::dumpDynamicSection(const Elf_Shdr *Shdr) {