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 @@ -126,6 +126,17 @@ llvm::yaml::Hex64 Val; }; +struct BBAddrMapEntry { + struct BBEntry { + llvm::yaml::Hex32 AddressOffset; + llvm::yaml::Hex32 Size; + llvm::yaml::Hex32 Metadata; + }; + llvm::yaml::Hex64 Address; + llvm::yaml::Hex32 NumBlocks; + Optional> BBEntries; +}; + struct StackSizeEntry { llvm::yaml::Hex64 Address; llvm::yaml::Hex64 Size; @@ -159,7 +170,8 @@ Fill, LinkerOptions, DependentLibraries, - CallGraphProfile + CallGraphProfile, + BBAddrMap }; ChunkKind Kind; @@ -227,6 +239,17 @@ static bool classof(const Chunk *S) { return S->Kind == ChunkKind::Fill; } }; +struct BBAddrMapSection : Section { + Optional Content; + Optional> Entries; + + BBAddrMapSection() : Section(ChunkKind::BBAddrMap) {} + + static bool classof(const Chunk *S) { + return S->Kind == ChunkKind::BBAddrMap; + } +}; + struct StackSizesSection : Section { Optional Content; Optional Size; @@ -579,6 +602,8 @@ } // end namespace llvm LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::StackSizeEntry) +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) @@ -740,6 +765,14 @@ static void mapping(IO &IO, ELFYAML::StackSizeEntry &Rel); }; +template <> struct MappingTraits { + static void mapping(IO &IO, ELFYAML::BBAddrMapEntry &Rel); +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, ELFYAML::BBAddrMapEntry::BBEntry &Rel); +}; + template <> struct MappingTraits { static void mapping(IO &IO, ELFYAML::GnuHashHeader &Rel); }; 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 @@ -272,6 +272,9 @@ void writeSectionContent(Elf_Shdr &SHeader, const ELFYAML::StackSizesSection &Section, ContiguousBlobAccumulator &CBA); + void writeSectionContent(Elf_Shdr &SHeader, + const ELFYAML::BBAddrMapSection &Section, + ContiguousBlobAccumulator &CBA); void writeSectionContent(Elf_Shdr &SHeader, const ELFYAML::HashSection &Section, ContiguousBlobAccumulator &CBA); @@ -730,6 +733,8 @@ writeSectionContent(SHeader, *S, CBA); } else if (auto S = dyn_cast(Sec)) { writeSectionContent(SHeader, *S, CBA); + } else if (auto S = dyn_cast(Sec)) { + writeSectionContent(SHeader, *S, CBA); } else { llvm_unreachable("Unknown section type"); } @@ -1291,6 +1296,28 @@ } } +template +void ELFState::writeSectionContent( + Elf_Shdr &SHeader, const ELFYAML::BBAddrMapSection &Section, + ContiguousBlobAccumulator &CBA) { + if (Section.Content) { + SHeader.sh_size = writeContent(CBA, Section.Content, None); + return; + } + + for (const ELFYAML::BBAddrMapEntry &E : *Section.Entries) { + CBA.write(E.Address, ELFT::TargetEndianness); + SHeader.sh_size += sizeof(uintX_t) + CBA.writeULEB128(E.NumBlocks); + if (!E.BBEntries.hasValue()) + continue; + for (const ELFYAML::BBAddrMapEntry::BBEntry &BBE : *E.BBEntries) { + SHeader.sh_size += CBA.writeULEB128(BBE.AddressOffset) + + CBA.writeULEB128(BBE.Size) + + CBA.writeULEB128(BBE.Metadata); + } + } +} + template void ELFState::writeSectionContent( Elf_Shdr &SHeader, const ELFYAML::LinkerOptionsSection &Section, 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 @@ -489,6 +489,7 @@ ECase(SHT_LLVM_SYMPART); ECase(SHT_LLVM_PART_EHDR); ECase(SHT_LLVM_PART_PHDR); + ECase(SHT_LLVM_BB_ADDR_MAP); ECase(SHT_GNU_ATTRIBUTES); ECase(SHT_GNU_HASH); ECase(SHT_GNU_verdef); @@ -1143,6 +1144,12 @@ IO.mapOptional("Info", Section.Info); } +static void sectionMapping(IO &IO, ELFYAML::BBAddrMapSection &Section) { + commonSectionMapping(IO, Section); + IO.mapOptional("Content", Section.Content); + IO.mapOptional("Entries", Section.Entries); +} + static void sectionMapping(IO &IO, ELFYAML::StackSizesSection &Section) { commonSectionMapping(IO, Section); IO.mapOptional("Content", Section.Content); @@ -1420,6 +1427,11 @@ Section.reset(new ELFYAML::CallGraphProfileSection()); sectionMapping(IO, *cast(Section.get())); break; + case ELF::SHT_LLVM_BB_ADDR_MAP: + if (!IO.outputting()) + Section.reset(new ELFYAML::BBAddrMapSection()); + sectionMapping(IO, *cast(Section.get())); + break; default: if (!IO.outputting()) { StringRef Name; @@ -1652,6 +1664,22 @@ IO.mapRequired("Size", E.Size); } +void MappingTraits::mapping( + IO &IO, ELFYAML::BBAddrMapEntry &E) { + assert(IO.getContext() && "The IO context is not initialized"); + IO.mapOptional("Address", E.Address, Hex64(0)); + IO.mapRequired("NumBlocks", E.NumBlocks); + IO.mapOptional("BBEntries", E.BBEntries); +} + +void MappingTraits::mapping( + IO &IO, ELFYAML::BBAddrMapEntry::BBEntry &E) { + assert(IO.getContext() && "The IO context is not initialized"); + IO.mapRequired("AddressOffset", E.AddressOffset); + IO.mapRequired("Size", E.Size); + IO.mapRequired("Metadata", E.Metadata); +} + void MappingTraits::mapping(IO &IO, ELFYAML::GnuHashHeader &E) { assert(IO.getContext() && "The IO context is not initialized"); diff --git a/llvm/test/tools/obj2yaml/ELF/bb-addr-map.yaml b/llvm/test/tools/obj2yaml/ELF/bb-addr-map.yaml new file mode 100644 --- /dev/null +++ b/llvm/test/tools/obj2yaml/ELF/bb-addr-map.yaml @@ -0,0 +1,62 @@ +## Check how obj2yaml produces YAML .llvm_bb_addr_map descriptions. + +## Check that obj2yaml uses the "Entries" tag to describe a .llvm_bb_addr_map section. + +# RUN: yaml2obj --docnum=1 %s -o %t1 +# RUN: obj2yaml %t1 | FileCheck %s --check-prefix=VALID + +# VALID: --- !ELF +# VALID-NEXT: FileHeader: +# VALID-NEXT: Class: ELFCLASS64 +# VALID-NEXT: Data: ELFDATA2LSB +# VALID-NEXT: Type: ET_EXEC +# VALID-NEXT: Sections: +# VALID-NEXT: - Name: .llvm_bb_addr_map +# VALID-NEXT: Type: SHT_LLVM_BB_ADDR_MAP +# VALID-NEXT: Entries: +# VALID-NEXT: - Address: 0x0000000000000010 +# VALID-NEXT: NumBlocks: 0x00000003 +# VALID-NEXT: BBEntries: +# VALID-NEXT: - AddressOffset: 0x00000001 +# VALID-NEXT: Size: 0x00000002 +# VALID-NEXT: Metadata: 0x00000003 +# VALID-NEXT: - AddressOffset: 0x00000004 +# VALID-NEXT: Size: 0x00000005 +# VALID-NEXT: Metadata: 0x00000006 +# VALID-NEXT: - AddressOffset: 0x00000007 +# VALID-NEXT: Size: 0x00000008 +# VALID-NEXT: Metadata: 0x00000009 +# VALID-NEXT: - Address: 0x0000000000000020 +# VALID-NEXT: NumBlocks: 0x00000001 +# VALID-NEXT: BBEntries: +# VALID-NEXT: - AddressOffset: 0x0000000A +# VALID-NEXT: Size: 0x0000000B +# VALID-NEXT: Metadata: 0x0000000C + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC +Sections: + - Name: .llvm_bb_addr_map + Type: SHT_LLVM_BB_ADDR_MAP + Entries: + - Address: 0x0000000000000010 + NumBlocks: 0x00000003 + BBEntries: + - AddressOffset: 0x00000001 + Size: 0x00000002 + Metadata: 0x00000003 + - AddressOffset: 0x00000004 + Size: 0x00000005 + Metadata: 0x00000006 + - AddressOffset: 0x00000007 + Size: 0x00000008 + Metadata: 0x00000009 + - Address: 0x0000000000000020 + NumBlocks: 0x00000001 + BBEntries: + - AddressOffset: 0x0000000A + Size: 0x0000000B + Metadata: 0x0000000C 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 @@ -100,6 +100,8 @@ Expected dumpMipsABIFlags(const Elf_Shdr *Shdr); Expected dumpStackSizesSection(const Elf_Shdr *Shdr); + Expected + dumpBBAddrMapSection(const Elf_Shdr *Shdr); Expected dumpPlaceholderSection(const Elf_Shdr *Shdr); @@ -506,6 +508,9 @@ case ELF::SHT_LLVM_CALL_GRAPH_PROFILE: return [this](const Elf_Shdr *S) { return dumpCallGraphProfileSection(S); }; + + case ELF::SHT_LLVM_BB_ADDR_MAP: + return [this](const Elf_Shdr *S) { return dumpBBAddrMapSection(S); }; case ELF::SHT_STRTAB: case ELF::SHT_SYMTAB: case ELF::SHT_DYNSYM: @@ -763,6 +768,47 @@ return S.release(); } +template +Expected +ELFDumper::dumpBBAddrMapSection(const Elf_Shdr *Shdr) { + auto S = std::make_unique(); + if (Error E = dumpCommonSection(Shdr, *S)) + return std::move(E); + + auto ContentOrErr = Obj.getSectionContents(*Shdr); + if (!ContentOrErr) + return ContentOrErr.takeError(); + + ArrayRef Content = *ContentOrErr; + DataExtractor Data(Content, Obj.isLE(), ELFT::Is64Bits ? 8 : 4); + + std::vector Entries; + DataExtractor::Cursor Cur(0); + while (Cur && Cur.tell() < Content.size()) { + uint64_t Address = Data.getAddress(Cur); + uint32_t NumBlocks = Data.getULEB128(Cur); + std::vector BBEntries; + for (uint32_t BlockID = 0; + Cur && Cur.tell() < Content.size() && BlockID < NumBlocks; ++BlockID) { + uint32_t Offset = Data.getULEB128(Cur); + uint32_t Size = Data.getULEB128(Cur); + uint32_t Metadata = Data.getULEB128(Cur); + BBEntries.push_back({Offset, Size, Metadata}); + } + Entries.push_back({Address, NumBlocks, BBEntries}); + } + + if (Content.empty() || !Cur) { + // If the section cannot be decoded, we dump it as an array of bytes. + consumeError(Cur.takeError()); + S->Content = yaml::BinaryRef(Content); + } else { + S->Entries = std::move(Entries); + } + + return S.release(); +} + template Expected ELFDumper::dumpAddrsigSection(const Elf_Shdr *Shdr) {