[llvm] bec54e4 - [yaml2obj/obj2yaml] - Add support for the SHT_LLVM_CALL_GRAPH_PROFILE section.
Georgii Rymar via llvm-commits
llvm-commits at lists.llvm.org
Tue Feb 4 04:13:46 PST 2020
Author: Georgii Rymar
Date: 2020-02-04T15:13:20+03:00
New Revision: bec54e464e6a5defee29f49f0ba871aa2c55c382
URL: https://github.com/llvm/llvm-project/commit/bec54e464e6a5defee29f49f0ba871aa2c55c382
DIFF: https://github.com/llvm/llvm-project/commit/bec54e464e6a5defee29f49f0ba871aa2c55c382.diff
LOG: [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
Added:
llvm/test/tools/obj2yaml/call-graph-profile-section.yaml
llvm/test/tools/yaml2obj/ELF/call-graph-profile-section.yaml
Modified:
llvm/include/llvm/ObjectYAML/ELFYAML.h
llvm/lib/ObjectYAML/ELFEmitter.cpp
llvm/lib/ObjectYAML/ELFYAML.cpp
llvm/tools/obj2yaml/elf2yaml.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/ObjectYAML/ELFYAML.h b/llvm/include/llvm/ObjectYAML/ELFYAML.h
index f87135e6a1b5..19b6de8763c7 100644
--- a/llvm/include/llvm/ObjectYAML/ELFYAML.h
+++ b/llvm/include/llvm/ObjectYAML/ELFYAML.h
@@ -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);
};
diff --git a/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp
index 7a51cbc87659..76c2ff6fa978 100644
--- a/llvm/lib/ObjectYAML/ELFEmitter.cpp
+++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp
@@ -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,
diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp
index 2de6aaa78b0c..4b21490a2754 100644
--- a/llvm/lib/ObjectYAML/ELFYAML.cpp
+++ b/llvm/lib/ObjectYAML/ELFYAML.cpp
@@ -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 §ionOrType) {
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)
diff --git a/llvm/test/tools/obj2yaml/call-graph-profile-section.yaml b/llvm/test/tools/obj2yaml/call-graph-profile-section.yaml
new file mode 100644
index 000000000000..0608bb4f0b9f
--- /dev/null
+++ b/llvm/test/tools/obj2yaml/call-graph-profile-section.yaml
@@ -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
diff --git a/llvm/test/tools/yaml2obj/ELF/call-graph-profile-section.yaml b/llvm/test/tools/yaml2obj/ELF/call-graph-profile-section.yaml
new file mode 100644
index 000000000000..4555bdc656d7
--- /dev/null
+++ b/llvm/test/tools/yaml2obj/ELF/call-graph-profile-section.yaml
@@ -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
diff --git a/llvm/tools/obj2yaml/elf2yaml.cpp b/llvm/tools/obj2yaml/elf2yaml.cpp
index 199a482fc399..43e340bdb8be 100644
--- a/llvm/tools/obj2yaml/elf2yaml.cpp
+++ b/llvm/tools/obj2yaml/elf2yaml.cpp
@@ -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) {
More information about the llvm-commits
mailing list