[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 &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)

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