diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -856,12 +856,23 @@ } template static void readCallGraphsFromObjectFiles() { + auto getIndex = [&](ObjFile *obj, uint32_t index) { + const Elf_Rel_Impl &rel = obj->cgProfileRela[index]; + return rel.getSymbol(config->isMips64EL); + }; + for (auto file : objectFiles) { auto *obj = cast>(file); - - for (const Elf_CGProfile_Impl &cgpe : obj->cgProfile) { - auto *fromSym = dyn_cast(&obj->getSymbol(cgpe.cgp_from)); - auto *toSym = dyn_cast(&obj->getSymbol(cgpe.cgp_to)); + if (obj->cgProfileRela.empty()) + continue; + if (obj->cgProfileRela.size() != obj->cgProfile.size() * 2) + fatal("number of relocations doesn't match Weights"); + for (uint32_t i = 0, size = obj->cgProfile.size(); i < size; ++i) { + const Elf_CGProfile_Impl &cgpe = obj->cgProfile[i]; + uint32_t fromIndex = getIndex(obj, i * 2); + uint32_t toIndex = getIndex(obj, i * 2 + 1); + auto *fromSym = dyn_cast(&obj->getSymbol(fromIndex)); + auto *toSym = dyn_cast(&obj->getSymbol(toIndex)); if (!fromSym || !toSym) continue; diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h --- a/lld/ELF/InputFiles.h +++ b/lld/ELF/InputFiles.h @@ -249,8 +249,10 @@ // Pointer to this input file's .llvm_addrsig section, if it has one. const Elf_Shdr *addrsigSec = nullptr; - // SHT_LLVM_CALL_GRAPH_PROFILE table + // SHT_LLVM_CALL_GRAPH_PROFILE table. ArrayRef cgProfile; + // SHT_LLVM_CALL_GRAPH_PROFILE relocations. + ArrayRef cgProfileRela; // Get cached DWARF information. DWARFCache *getDwarf(); diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -571,15 +571,19 @@ CHECK(obj.getSectionStringTable(objSections), this); std::vector> selectedGroups; + // SHT_LLVM_CALL_GRAPH_PROFILE Section Index. + size_t cgProfileSectionIndex = 0; for (size_t i = 0, e = objSections.size(); i < e; ++i) { if (this->sections[i] == &InputSection::discarded) continue; const Elf_Shdr &sec = objSections[i]; - if (sec.sh_type == ELF::SHT_LLVM_CALL_GRAPH_PROFILE) + if (sec.sh_type == ELF::SHT_LLVM_CALL_GRAPH_PROFILE) { cgProfile = check(obj.template getSectionContentsAsArray(sec)); + cgProfileSectionIndex = i; + } // SHF_EXCLUDE'ed sections are discarded by the linker. However, // if -r is given, we'll let the final link discard such sections. @@ -665,6 +669,13 @@ continue; const Elf_Shdr &sec = objSections[i]; + if (cgProfileSectionIndex && sec.sh_info == cgProfileSectionIndex) { + if (sec.sh_type == SHT_RELA) + cgProfileRela = CHECK(getObj().relas(sec), this); + else + warn(toString(this) + ": unsupported call graph section type"); + } + if (sec.sh_type == SHT_REL || sec.sh_type == SHT_RELA) this->sections[i] = createInputSection(sec); diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h --- a/llvm/include/llvm/BinaryFormat/ELF.h +++ b/llvm/include/llvm/BinaryFormat/ELF.h @@ -926,17 +926,17 @@ // 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/llvm/include/llvm/MC/MCELFStreamer.h b/llvm/include/llvm/MC/MCELFStreamer.h --- a/llvm/include/llvm/MC/MCELFStreamer.h +++ b/llvm/include/llvm/MC/MCELFStreamer.h @@ -85,7 +85,7 @@ 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/llvm/include/llvm/Object/ELFTypes.h b/llvm/include/llvm/Object/ELFTypes.h --- a/llvm/include/llvm/Object/ELFTypes.h +++ b/llvm/include/llvm/Object/ELFTypes.h @@ -737,8 +737,6 @@ 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/llvm/include/llvm/ObjectYAML/ELFYAML.h b/llvm/include/llvm/ObjectYAML/ELFYAML.h --- a/llvm/include/llvm/ObjectYAML/ELFYAML.h +++ b/llvm/include/llvm/ObjectYAML/ELFYAML.h @@ -516,17 +516,13 @@ }; // 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::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 @@ 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/llvm/lib/MC/ELFObjectWriter.cpp b/llvm/lib/MC/ELFObjectWriter.cpp --- a/llvm/lib/MC/ELFObjectWriter.cpp +++ b/llvm/lib/MC/ELFObjectWriter.cpp @@ -1127,14 +1127,6 @@ 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 @@ } } - 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 @@ 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/llvm/lib/MC/MCELFStreamer.cpp b/llvm/lib/MC/MCELFStreamer.cpp --- a/llvm/lib/MC/MCELFStreamer.cpp +++ b/llvm/lib/MC/MCELFStreamer.cpp @@ -477,7 +477,8 @@ } } -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 @@ } 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/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp --- a/llvm/lib/ObjectYAML/ELFEmitter.cpp +++ b/llvm/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 @@ 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/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp --- a/llvm/lib/ObjectYAML/ELFYAML.cpp +++ b/llvm/lib/ObjectYAML/ELFYAML.cpp @@ -1834,11 +1834,9 @@ 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/llvm/test/MC/ELF/cgprofile.s b/llvm/test/MC/ELF/cgprofile.s --- a/llvm/test/MC/ELF/cgprofile.s +++ b/llvm/test/MC/ELF/cgprofile.s @@ -15,22 +15,46 @@ .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 @@ # 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/llvm/test/Object/multiple-sections.yaml b/llvm/test/Object/multiple-sections.yaml --- a/llvm/test/Object/multiple-sections.yaml +++ b/llvm/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 @@ - 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/llvm/test/tools/llvm-readobj/ELF/call-graph-profile.test b/llvm/test/tools/llvm-readobj/ELF/call-graph-profile.test --- a/llvm/test/tools/llvm-readobj/ELF/call-graph-profile.test +++ b/llvm/test/tools/llvm-readobj/ELF/call-graph-profile.test @@ -26,17 +26,29 @@ 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 @@ # 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 @@ # 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 @@ 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 @@ - 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/llvm/test/tools/llvm-readobj/ELF/demangle.test b/llvm/test/tools/llvm-readobj/ELF/demangle.test --- a/llvm/test/tools/llvm-readobj/ELF/demangle.test +++ b/llvm/test/tools/llvm-readobj/ELF/demangle.test @@ -197,8 +197,17 @@ - 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/llvm/test/tools/obj2yaml/ELF/call-graph-profile-section.yaml b/llvm/test/tools/obj2yaml/ELF/call-graph-profile-section.yaml --- a/llvm/test/tools/obj2yaml/ELF/call-graph-profile-section.yaml +++ b/llvm/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 @@ - 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 @@ # 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 @@ ## 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 + - Name: .multiple.8.valid Type: SHT_LLVM_CALL_GRAPH_PROFILE - Content: "0000000100000002000000000000000300" - - Name: .multiple.16.invalid + Content: "0000000000000003" + - Name: .non.multiple.8 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 + Content: "000000000000000300" + - Name: .multiple.8.invalid 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/llvm/test/tools/yaml2obj/ELF/call-graph-profile-section.yaml b/llvm/test/tools/yaml2obj/ELF/call-graph-profile-section.yaml --- a/llvm/test/tools/yaml2obj/ELF/call-graph-profile-section.yaml +++ b/llvm/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 @@ - 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 @@ 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 @@ 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 @@ 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 @@ ## 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/llvm/test/tools/yaml2obj/ELF/section-headers-exclude.yaml b/llvm/test/tools/yaml2obj/ELF/section-headers-exclude.yaml --- a/llvm/test/tools/yaml2obj/ELF/section-headers-exclude.yaml +++ b/llvm/test/tools/yaml2obj/ELF/section-headers-exclude.yaml @@ -367,7 +367,7 @@ # 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/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -318,6 +318,12 @@ 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 @@ 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 @@ 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 @@ } 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 @@ 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::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 auto &CGMapEntry : SecToRelocMap) { + const Elf_Shdr *CGSection = CGMapEntry.first; + const Elf_Shdr *CGRelSection = CGMapEntry.second; - 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); + 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/llvm/tools/obj2yaml/elf2yaml.cpp b/llvm/tools/obj2yaml/elf2yaml.cpp --- a/llvm/tools/obj2yaml/elf2yaml.cpp +++ b/llvm/tools/obj2yaml/elf2yaml.cpp @@ -1022,41 +1022,31 @@ 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);