From d12ae1eaf82fcf53fa95bf157a0a3e912898c576 Mon Sep 17 00:00:00 2001 From: Alexander Yermolovich Date: Thu, 24 Jun 2021 08:02:45 -0700 Subject: [PATCH] [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 --- include/llvm/BinaryFormat/ELF.h | 10 +- include/llvm/MC/MCELFStreamer.h | 2 +- include/llvm/Object/ELFTypes.h | 2 - include/llvm/ObjectYAML/ELFYAML.h | 14 +- lib/MC/ELFObjectWriter.cpp | 25 +-- lib/MC/MCELFStreamer.cpp | 38 ++-- lib/ObjectYAML/ELFEmitter.cpp | 10 +- lib/ObjectYAML/ELFYAML.cpp | 6 +- test/MC/ELF/cgprofile.s | 42 +++- test/Object/multiple-sections.yaml | 11 +- .../llvm-readobj/ELF/call-graph-profile.test | 193 ++++++++++++++++-- test/tools/llvm-readobj/ELF/demangle.test | 13 +- .../ELF/call-graph-profile-section.yaml | 100 +++------ .../ELF/call-graph-profile-section.yaml | 146 ++----------- .../yaml2obj/ELF/section-headers-exclude.yaml | 2 +- tools/llvm-readobj/ELFDumper.cpp | 136 +++++++----- tools/obj2yaml/elf2yaml.cpp | 26 +-- 17 files changed, 414 insertions(+), 362 deletions(-) diff --git a/include/llvm/BinaryFormat/ELF.h b/include/llvm/BinaryFormat/ELF.h index 255fa141419..99ad345bbcc 100644 --- a/include/llvm/BinaryFormat/ELF.h +++ b/include/llvm/BinaryFormat/ELF.h @@ -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. diff --git a/include/llvm/MC/MCELFStreamer.h b/include/llvm/MC/MCELFStreamer.h index 280eb7ec92c..45179378e71 100644 --- a/include/llvm/MC/MCELFStreamer.h +++ b/include/llvm/MC/MCELFStreamer.h @@ -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. diff --git a/include/llvm/Object/ELFTypes.h b/include/llvm/Object/ELFTypes.h index 6cd93efa41a..54ebd751d8d 100644 --- a/include/llvm/Object/ELFTypes.h +++ b/include/llvm/Object/ELFTypes.h @@ -737,8 +737,6 @@ public: template struct Elf_CGProfile_Impl { LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) - Elf_Word cgp_from; - Elf_Word cgp_to; Elf_Xword cgp_weight; }; diff --git a/include/llvm/ObjectYAML/ELFYAML.h b/include/llvm/ObjectYAML/ELFYAML.h index 521bdee8b49..92a9f78ce7b 100644 --- a/include/llvm/ObjectYAML/ELFYAML.h +++ b/include/llvm/ObjectYAML/ELFYAML.h @@ -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> Entries; + Optional> 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 { static void mapping(IO &IO, ELFYAML::LinkerOption &Sym); }; -template <> struct MappingTraits { - static void mapping(IO &IO, ELFYAML::CallGraphEntry &E); +template <> struct MappingTraits { + static void mapping(IO &IO, ELFYAML::CallGraphEntryWeight &E); }; template <> struct MappingTraits { diff --git a/lib/MC/ELFObjectWriter.cpp b/lib/MC/ELFObjectWriter.cpp index 534c263d735..fec77d27eb9 100644 --- a/lib/MC/ELFObjectWriter.cpp +++ b/lib/MC/ELFObjectWriter.cpp @@ -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(CGPE.From->getSymbol().getIndex()); - W.write(CGPE.To->getSymbol().getIndex()); - W.write(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(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() diff --git a/lib/MC/MCELFStreamer.cpp b/lib/MC/MCELFStreamer.cpp index 5a6c042333d..76e69a65996 100644 --- a/lib/MC/MCELFStreamer.cpp +++ b/lib/MC/MCELFStreamer.cpp @@ -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(S)->setBinding(ELF::STB_WEAK); + const MCConstantExpr *MCOffset = MCConstantExpr::create(Offset, getContext()); + MCObjectStreamer::visitUsedExpr(*SRE); + if (Optional> 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, diff --git a/lib/ObjectYAML/ELFEmitter.cpp b/lib/ObjectYAML/ELFEmitter.cpp index 7890884711a..f8f2f0c1202 100644 --- a/lib/ObjectYAML/ELFEmitter.cpp +++ b/lib/ObjectYAML/ELFEmitter.cpp @@ -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::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(From, ELFT::TargetEndianness); - CBA.write(To, ELFT::TargetEndianness); + for (const ELFYAML::CallGraphEntryWeight &E : *Section.Entries) { CBA.write(E.Weight, ELFT::TargetEndianness); - SHeader.sh_size += 16; + SHeader.sh_size += sizeof(object::Elf_CGProfile_Impl); } } diff --git a/lib/ObjectYAML/ELFYAML.cpp b/lib/ObjectYAML/ELFYAML.cpp index 31bae6bf1f3..af6247e9339 100644 --- a/lib/ObjectYAML/ELFYAML.cpp +++ b/lib/ObjectYAML/ELFYAML.cpp @@ -1834,11 +1834,9 @@ void MappingTraits::mapping(IO &IO, IO.mapRequired("Value", Opt.Value); } -void MappingTraits::mapping( - IO &IO, ELFYAML::CallGraphEntry &E) { +void MappingTraits::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); } diff --git a/test/MC/ELF/cgprofile.s b/test/MC/ELF/cgprofile.s index 7938c2db8eb..11c7464976d 100644 --- a/test/MC/ELF/cgprofile.s +++ b/test/MC/ELF/cgprofile.s @@ -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 diff --git a/test/Object/multiple-sections.yaml b/test/Object/multiple-sections.yaml index 07af9252e26..a0f8df7cfeb 100644 --- a/test/Object/multiple-sections.yaml +++ b/test/Object/multiple-sections.yaml @@ -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: [] ... diff --git a/test/tools/llvm-readobj/ELF/call-graph-profile.test b/test/tools/llvm-readobj/ELF/call-graph-profile.test index 92539a4601d..d0115b4c6c1 100644 --- a/test/tools/llvm-readobj/ELF/call-graph-profile.test +++ b/test/tools/llvm-readobj/ELF/call-graph-profile.test @@ -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=]] + - 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=]] +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=]] + - 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=]] + - 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 diff --git a/test/tools/llvm-readobj/ELF/demangle.test b/test/tools/llvm-readobj/ELF/demangle.test index 4369a9e9481..25be40a72b9 100644 --- a/test/tools/llvm-readobj/ELF/demangle.test +++ b/test/tools/llvm-readobj/ELF/demangle.test @@ -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 diff --git a/test/tools/obj2yaml/ELF/call-graph-profile-section.yaml b/test/tools/obj2yaml/ELF/call-graph-profile-section.yaml index 88ea98af4bd..a1ac4d9f58f 100644 --- a/test/tools/obj2yaml/ELF/call-graph-profile-section.yaml +++ b/test/tools/obj2yaml/ELF/call-graph-profile-section.yaml @@ -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 diff --git a/test/tools/yaml2obj/ELF/call-graph-profile-section.yaml b/test/tools/yaml2obj/ELF/call-graph-profile-section.yaml index c52add3a021..121b1e950c3 100644 --- a/test/tools/yaml2obj/ELF/call-graph-profile-section.yaml +++ b/test/tools/yaml2obj/ELF/call-graph-profile-section.yaml @@ -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=]] Entries: [[ENTRIES=]] -# 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" diff --git a/test/tools/yaml2obj/ELF/section-headers-exclude.yaml b/test/tools/yaml2obj/ELF/section-headers-exclude.yaml index ce19696a35a..016af7e031a 100644 --- a/test/tools/yaml2obj/ELF/section-headers-exclude.yaml +++ b/test/tools/yaml2obj/ELF/section-headers-exclude.yaml @@ -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 diff --git a/tools/llvm-readobj/ELFDumper.cpp b/tools/llvm-readobj/ELFDumper.cpp index 1a6fa0d6e2d..bf2b642c695 100644 --- a/tools/llvm-readobj/ELFDumper.cpp +++ b/tools/llvm-readobj/ELFDumper.cpp @@ -318,6 +318,12 @@ protected: void printRelocatableStackSizes(std::function PrintHeader); void printNonRelocatableStackSizes(std::function PrintHeader); + /// Retrieves sections with corresponding relocation sections based on + /// IsMatch. + void getSectionAndRelocations( + std::function IsMatch, + llvm::MapVector &SecToRelocMap); + const object::ELFObjectFile &ObjF; const ELFFile &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> ShndxTables; Optional SONameOffset; @@ -1838,10 +1843,6 @@ ELFDumper::ELFDumper(const object::ELFObjectFile &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::printNonRelocatableStackSizes( } template -void ELFDumper::printRelocatableStackSizes( - std::function PrintHeader) { - // Build a map between stack size sections and their corresponding relocation - // sections. - llvm::MapVector StackSizeRelocMap; +void ELFDumper::getSectionAndRelocations( + std::function IsMatch, + llvm::MapVector &SecToRelocMap) { for (const Elf_Shdr &Sec : cantFail(Obj.sections())) { - StringRef SectionName; - if (Expected 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::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 +void ELFDumper::printRelocatableStackSizes( + std::function PrintHeader) { + // Build a map between stack size sections and their corresponding relocation + // sections. + llvm::MapVector StackSizeRelocMap; + auto IsMatch = [&](const Elf_Shdr &Sec) -> bool { + StringRef SectionName; + if (Expected 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 void LLVMELFDumper::printHashHistograms() { } template void LLVMELFDumper::printCGProfile() { - ListScope L(W, "CGProfile"); - if (!this->DotCGProfileSec) - return; + llvm::MapVector SecToRelocMap; - Expected> CGProfileOrErr = - this->Obj.template getSectionContentsAsArray( - *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> CGProfileOrErr = + this->Obj.template getSectionContentsAsArray(*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 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 &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); + } } } diff --git a/tools/obj2yaml/elf2yaml.cpp b/tools/obj2yaml/elf2yaml.cpp index a72020fb752..028758d68d9 100644 --- a/tools/obj2yaml/elf2yaml.cpp +++ b/tools/obj2yaml/elf2yaml.cpp @@ -1022,41 +1022,31 @@ ELFDumper::dumpCallGraphProfileSection(const Elf_Shdr *Shdr) { if (!ContentOrErr) return ContentOrErr.takeError(); ArrayRef Content = *ContentOrErr; - + const uint32_t SizeOfEntry = ELFYAML::getDefaultShEntSize( + 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 Entries(Content.size() / 16); + std::vector 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 From = getSymbolName(Shdr->sh_link, FromSymIndex); - Expected 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);