diff --git a/llvm/docs/Extensions.rst b/llvm/docs/Extensions.rst --- a/llvm/docs/Extensions.rst +++ b/llvm/docs/Extensions.rst @@ -401,11 +401,23 @@ metadata. This information can be used to map binary profiles (like perf profiles) directly to machine basic blocks. This section is emitted with ``-basic-block-sections=labels`` and will contain -a BB address map table for every function which may be constructed as follows: +a BB address map table for every function. + +The ``SHT_LLVM_BB_ADDR_MAP`` type provides backward compatibility to allow +reading older versions of the BB address map generated by older compilers. Each +function entry starts with a version byte which specifies the encoding version +to use. The following versioning schemes are currently supported. + +Version 1 (newest): basic block address offsets are computed relative to the end +of previous blocks. + +Example: .. code-block:: gas .section ".llvm_bb_addr_map","",@llvm_bb_addr_map + .byte 1 # version number + .byte 0 # feature byte (reserved for future use) .quad .Lfunc_begin0 # address of the function .byte 2 # number of basic blocks # BB record for BB_0 @@ -413,11 +425,30 @@ .uleb128 .LBB_END0_0-.Lfunc_begin0 # BB_0 size .byte x # BB_0 metadata # BB record for BB_1 - .uleb128 .LBB0_1-.Lfunc_begin0 # BB_1 offset relative to function entry - .uleb128 .LBB_END0_1-.Lfunc_begin0 # BB_1 size + .uleb128 .LBB0_1-.LBB_END0_0 # BB_1 offset relative to the end of last block (BB_0). + .uleb128 .LBB_END0_1-.LBB0_1 # BB_1 size .byte y # BB_1 metadata -This creates a BB address map table for a function with two basic blocks. +Version 0: basic block address offsets are computed relative to the function +address. This uses the unversioned ``SHT_LLVM_BB_ADDR_MAP_V0`` section type and +is semantically equivalent to using ``SHT_LLVM_BB_ADDR_MAP`` with a zero +version field. + +Example: + +.. code-block:: gas + + .section ".llvm_bb_addr_map","",@llvm_bb_addr_map_v0 + .quad .Lfunc_begin0 # address of the function + .byte 2 # number of basic blocks + # BB record for BB_0 + .uleb128 .Lfunc_beign0-.Lfunc_begin0 # BB_0 offset relative to the function entry (always zero) + .uleb128 .LBB_END0_0-.Lfunc_begin0 # BB_0 size + .byte x # BB_0 metadata + # BB record for BB_1 + .uleb128 .LBB0_1-.Lfunc_begin0 # BB_1 offset relative to the function entry + .uleb128 .LBB_END0_1-.LBB0_1 # BB_1 size + .byte y # BB_1 metadata CodeView-Dependent ------------------ 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 @@ -981,12 +981,15 @@ 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. + 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_V0 = + 0x6fff4c08, // LLVM Basic Block Address Map (old version kept for + // backward-compatibility). SHT_LLVM_CALL_GRAPH_PROFILE = 0x6fff4c09, // LLVM Call Graph Profile. + SHT_LLVM_BB_ADDR_MAP = 0x6fff4c0a, // LLVM Basic Block Address Map. // 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/MCContext.h b/llvm/include/llvm/MC/MCContext.h --- a/llvm/include/llvm/MC/MCContext.h +++ b/llvm/include/llvm/MC/MCContext.h @@ -172,6 +172,9 @@ /// for the LocalLabelVal and adds it to the map if needed. unsigned GetInstance(unsigned LocalLabelVal); + /// LLVM_BB_ADDR_MAP version to emit. + uint8_t BBAddrMapVersion = 1; + /// The file name of the log file from the environment variable /// AS_SECURE_LOG_FILE. Which must be set before the .secure_log_unique /// directive is used or it is an error. @@ -679,6 +682,8 @@ // Create and save a copy of STI and return a reference to the copy. MCSubtargetInfo &getSubtargetCopy(const MCSubtargetInfo &STI); + uint8_t getBBAddrMapVersion() const { return BBAddrMapVersion; } + /// @} /// \name Dwarf Management 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 @@ -161,6 +161,8 @@ llvm::yaml::Hex64 Size; llvm::yaml::Hex64 Metadata; }; + uint8_t Version; + llvm::yaml::Hex8 Feature; llvm::yaml::Hex64 Address; Optional NumBlocks; Optional> BBEntries; diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -1309,19 +1309,27 @@ OutStreamer->pushSection(); OutStreamer->switchSection(BBAddrMapSection); + OutStreamer->AddComment("version"); + OutStreamer->emitInt8(OutStreamer->getContext().getBBAddrMapVersion()); + OutStreamer->AddComment("feature"); + OutStreamer->emitInt8(0); + OutStreamer->AddComment("function address"); OutStreamer->emitSymbolValue(FunctionSymbol, getPointerSize()); - // Emit the total number of basic blocks in this function. + OutStreamer->AddComment("number of basic blocks"); OutStreamer->emitULEB128IntValue(MF.size()); + const MCSymbol *PrevMBBEndSymbol = FunctionSymbol; // Emit BB Information for each basic block in the funciton. for (const MachineBasicBlock &MBB : MF) { const MCSymbol *MBBSymbol = MBB.isEntryBlock() ? FunctionSymbol : MBB.getSymbol(); - // Emit the basic block offset. - emitLabelDifferenceAsULEB128(MBBSymbol, FunctionSymbol); + // Emit the basic block offset relative to the end of the previous block. + // This is zero unless the block is padded due to alignment. + emitLabelDifferenceAsULEB128(MBBSymbol, PrevMBBEndSymbol); // Emit the basic block size. When BBs have alignments, their size cannot // always be computed from their offsets. emitLabelDifferenceAsULEB128(MBB.getEndSymbol(), MBBSymbol); OutStreamer->emitULEB128IntValue(getBBAddrMapMetadata(MBB)); + PrevMBBEndSymbol = MBB.getEndSymbol(); } OutStreamer->popSection(); } diff --git a/llvm/lib/CodeGen/BasicBlockSections.cpp b/llvm/lib/CodeGen/BasicBlockSections.cpp --- a/llvm/lib/CodeGen/BasicBlockSections.cpp +++ b/llvm/lib/CodeGen/BasicBlockSections.cpp @@ -60,7 +60,7 @@ // Basic Block Labels // ================== // -// With -fbasic-block-sections=labels, we emit the offsets of BB addresses of +// With -fbasic-block-sections=labels, we encode the offsets of BB addresses of // every function into the .llvm_bb_addr_map section. Along with the function // symbols, this allows for mapping of virtual addresses in PMU profiles back to // the corresponding basic blocks. This logic is implemented in AsmPrinter. This diff --git a/llvm/lib/MC/MCSectionELF.cpp b/llvm/lib/MC/MCSectionELF.cpp --- a/llvm/lib/MC/MCSectionELF.cpp +++ b/llvm/lib/MC/MCSectionELF.cpp @@ -165,6 +165,8 @@ OS << "llvm_sympart"; else if (Type == ELF::SHT_LLVM_BB_ADDR_MAP) OS << "llvm_bb_addr_map"; + else if (Type == ELF::SHT_LLVM_BB_ADDR_MAP_V0) + OS << "llvm_bb_addr_map_v0"; else report_fatal_error("unsupported type 0x" + Twine::utohexstr(Type) + " for section " + getName()); diff --git a/llvm/lib/Object/ELF.cpp b/llvm/lib/Object/ELF.cpp --- a/llvm/lib/Object/ELF.cpp +++ b/llvm/lib/Object/ELF.cpp @@ -295,6 +295,7 @@ STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_SYMPART); STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_PART_EHDR); STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_PART_PHDR); + STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_BB_ADDR_MAP_V0); STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_BB_ADDR_MAP); STRINGIFY_ENUM_CASE(ELF, SHT_GNU_ATTRIBUTES); STRINGIFY_ENUM_CASE(ELF, SHT_GNU_HASH); @@ -640,7 +641,6 @@ DataExtractor::Cursor Cur(0); Error ULEBSizeErr = Error::success(); - // Helper to extract and decode the next ULEB128 value as uint32_t. // Returns zero and sets ULEBSizeErr if the ULEB128 value exceeds the uint32_t // limit. @@ -660,18 +660,34 @@ return static_cast(Value); }; + uint8_t Version = 0; while (!ULEBSizeErr && Cur && Cur.tell() < Content.size()) { + if (Sec.sh_type == ELF::SHT_LLVM_BB_ADDR_MAP) { + Version = Data.getU8(Cur); + if (!Cur) + break; + if (Version > 1) + return createError("unsupported SHT_LLVM_BB_ADDR_MAP version: " + + Twine(static_cast(Version))); + Data.getU8(Cur); // Feature byte + } uintX_t Address = static_cast(Data.getAddress(Cur)); uint32_t NumBlocks = ReadULEB128AsUInt32(); std::vector BBEntries; + uint32_t PrevBBEndOffset = 0; for (uint32_t BlockID = 0; !ULEBSizeErr && Cur && (BlockID < NumBlocks); ++BlockID) { uint32_t Offset = ReadULEB128AsUInt32(); uint32_t Size = ReadULEB128AsUInt32(); uint32_t Metadata = ReadULEB128AsUInt32(); + if (Version >= 1) { + // Offset is calculated relative to the end of the previous BB. + Offset += PrevBBEndOffset; + PrevBBEndOffset = Offset + Size; + } BBEntries.push_back({Offset, Size, Metadata}); } - FunctionEntries.push_back({Address, BBEntries}); + FunctionEntries.push_back({Address, std::move(BBEntries)}); } // Either Cur is in the error state, or ULEBSizeError is set (not both), but // we join the two errors here to be safe. diff --git a/llvm/lib/Object/ELFObjectFile.cpp b/llvm/lib/Object/ELFObjectFile.cpp --- a/llvm/lib/Object/ELFObjectFile.cpp +++ b/llvm/lib/Object/ELFObjectFile.cpp @@ -678,7 +678,8 @@ std::vector BBAddrMaps; const auto &Sections = cantFail(EF.sections()); for (const Elf_Shdr &Sec : Sections) { - if (Sec.sh_type != ELF::SHT_LLVM_BB_ADDR_MAP) + if (Sec.sh_type != ELF::SHT_LLVM_BB_ADDR_MAP && + Sec.sh_type != ELF::SHT_LLVM_BB_ADDR_MAP_V0) continue; if (TextSectionIndex) { Expected TextSecOrErr = EF.getSection(Sec.sh_link); 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 @@ -1393,6 +1393,15 @@ return; for (const ELFYAML::BBAddrMapEntry &E : *Section.Entries) { + // Write version and feature values. + if (Section.Type == llvm::ELF::SHT_LLVM_BB_ADDR_MAP) { + if (E.Version > 1) + reportError("unsupported SHT_LLVM_BB_ADDR_MAP version: " + + Twine(static_cast(E.Version))); + CBA.write(E.Version); + CBA.write(E.Feature); + SHeader.sh_size += 2; + } // Write the address of the function. CBA.write(E.Address, ELFT::TargetEndianness); // Write number of BBEntries (number of basic blocks in the function). This 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 @@ -654,6 +654,7 @@ ECase(SHT_LLVM_SYMPART); ECase(SHT_LLVM_PART_EHDR); ECase(SHT_LLVM_PART_PHDR); + ECase(SHT_LLVM_BB_ADDR_MAP_V0); ECase(SHT_LLVM_BB_ADDR_MAP); ECase(SHT_GNU_ATTRIBUTES); ECase(SHT_GNU_HASH); @@ -1639,6 +1640,7 @@ Section.reset(new ELFYAML::CallGraphProfileSection()); sectionMapping(IO, *cast(Section.get())); break; + case ELF::SHT_LLVM_BB_ADDR_MAP_V0: case ELF::SHT_LLVM_BB_ADDR_MAP: if (!IO.outputting()) Section.reset(new ELFYAML::BBAddrMapSection()); @@ -1768,6 +1770,8 @@ void MappingTraits::mapping( IO &IO, ELFYAML::BBAddrMapEntry &E) { assert(IO.getContext() && "The IO context is not initialized"); + IO.mapRequired("Version", E.Version); + IO.mapOptional("Feature", E.Feature, Hex8(0)); IO.mapOptional("Address", E.Address, Hex64(0)); IO.mapOptional("NumBlocks", E.NumBlocks); IO.mapOptional("BBEntries", E.BBEntries); diff --git a/llvm/test/CodeGen/X86/basic-block-sections-labels-empty-function.ll b/llvm/test/CodeGen/X86/basic-block-sections-labels-empty-function.ll --- a/llvm/test/CodeGen/X86/basic-block-sections-labels-empty-function.ll +++ b/llvm/test/CodeGen/X86/basic-block-sections-labels-empty-function.ll @@ -18,4 +18,6 @@ ; CHECK: func: ; CHECK: .Lfunc_begin1: ; CHECK: .section .llvm_bb_addr_map,"o",@llvm_bb_addr_map,.text{{$}} -; CHECK: .quad .Lfunc_begin1 +; CHECK-NEXT: .byte 1 # version +; CHECK-NEXT: .byte 0 # feature +; CHECK-NEXT: .quad .Lfunc_begin1 # function address diff --git a/llvm/test/CodeGen/X86/basic-block-sections-labels-functions-sections.ll b/llvm/test/CodeGen/X86/basic-block-sections-labels-functions-sections.ll --- a/llvm/test/CodeGen/X86/basic-block-sections-labels-functions-sections.ll +++ b/llvm/test/CodeGen/X86/basic-block-sections-labels-functions-sections.ll @@ -10,7 +10,9 @@ ; CHECK-LABEL: _Z3barv: ; CHECK-NEXT: [[BAR_BEGIN:.Lfunc_begin[0-9]+]]: ; CHECK: .section .llvm_bb_addr_map,"o",@llvm_bb_addr_map,.text._Z3barv{{$}} -; CHECK-NEXT: .quad [[BAR_BEGIN]] +; CHECK-NEXT: .byte 1 # version +; CHECK-NEXT: .byte 0 # feature +; CHECK-NEXT: .quad [[BAR_BEGIN]] # function address define dso_local i32 @_Z3foov() { @@ -21,7 +23,9 @@ ; CHECK-LABEL: _Z3foov: ; CHECK-NEXT: [[FOO_BEGIN:.Lfunc_begin[0-9]+]]: ; CHECK: .section .llvm_bb_addr_map,"o",@llvm_bb_addr_map,.text._Z3foov{{$}} -; CHECK-NEXT: .quad [[FOO_BEGIN]] +; CHECK-NEXT: .byte 1 # version +; CHECK-NEXT: .byte 0 # feature +; CHECK-NEXT: .quad [[FOO_BEGIN]] # function address define linkonce_odr dso_local i32 @_Z4fooTIiET_v() comdat { @@ -32,4 +36,6 @@ ; CHECK-LABEL: _Z4fooTIiET_v: ; CHECK-NEXT: [[FOOCOMDAT_BEGIN:.Lfunc_begin[0-9]+]]: ; CHECK: .section .llvm_bb_addr_map,"Go",@llvm_bb_addr_map,_Z4fooTIiET_v,comdat,.text._Z4fooTIiET_v{{$}} -; CHECK-NEXT: .quad [[FOOCOMDAT_BEGIN]] +; CHECK-NEXT: .byte 1 # version +; CHECK-NEXT: .byte 0 # feature +; CHECK-NEXT: .quad [[FOOCOMDAT_BEGIN]] # function address diff --git a/llvm/test/CodeGen/X86/basic-block-sections-labels.ll b/llvm/test/CodeGen/X86/basic-block-sections-labels.ll --- a/llvm/test/CodeGen/X86/basic-block-sections-labels.ll +++ b/llvm/test/CodeGen/X86/basic-block-sections-labels.ll @@ -46,17 +46,19 @@ ; UNIQ: .section .llvm_bb_addr_map,"o",@llvm_bb_addr_map,.text._Z3bazb{{$}} ;; Verify that with -unique-section-names=false, the unique id of the text section gets assigned to the llvm_bb_addr_map section. ; NOUNIQ: .section .llvm_bb_addr_map,"o",@llvm_bb_addr_map,.text,unique,1 -; CHECK-NEXT: .quad .Lfunc_begin0 -; CHECK-NEXT: .byte 4 +; CHECK-NEXT: .byte 1 # version +; CHECK-NEXT: .byte 0 # feature +; CHECK-NEXT: .quad .Lfunc_begin0 # function address +; CHECK-NEXT: .byte 4 # number of basic blocks ; CHECK-NEXT: .uleb128 .Lfunc_begin0-.Lfunc_begin0 ; CHECK-NEXT: .uleb128 .LBB_END0_0-.Lfunc_begin0 ; CHECK-NEXT: .byte 8 -; CHECK-NEXT: .uleb128 .LBB0_1-.Lfunc_begin0 +; CHECK-NEXT: .uleb128 .LBB0_1-.LBB_END0_0 ; CHECK-NEXT: .uleb128 .LBB_END0_1-.LBB0_1 ; CHECK-NEXT: .byte 8 -; CHECK-NEXT: .uleb128 .LBB0_2-.Lfunc_begin0 +; CHECK-NEXT: .uleb128 .LBB0_2-.LBB_END0_1 ; CHECK-NEXT: .uleb128 .LBB_END0_2-.LBB0_2 ; CHECK-NEXT: .byte 1 -; CHECK-NEXT: .uleb128 .LBB0_3-.Lfunc_begin0 +; CHECK-NEXT: .uleb128 .LBB0_3-.LBB_END0_2 ; CHECK-NEXT: .uleb128 .LBB_END0_3-.LBB0_3 ; CHECK-NEXT: .byte 5 diff --git a/llvm/test/tools/llvm-objdump/X86/elf-bbaddrmap-disassemble-symbolize-operands.yaml b/llvm/test/tools/llvm-objdump/X86/elf-bbaddrmap-disassemble-symbolize-operands.yaml --- a/llvm/test/tools/llvm-objdump/X86/elf-bbaddrmap-disassemble-symbolize-operands.yaml +++ b/llvm/test/tools/llvm-objdump/X86/elf-bbaddrmap-disassemble-symbolize-operands.yaml @@ -80,18 +80,19 @@ Type: SHT_LLVM_BB_ADDR_MAP Link: .text Entries: - - Address: 0x4000 + - Version: 1 + Address: 0x4000 BBEntries: - AddressOffset: 0x0 Size: 0x1 Metadata: 0x1 - - AddressOffset: 0x1 + - AddressOffset: 0x0 Size: 0x6 Metadata: 0x0 - - AddressOffset: 0x8 - Size: 0x3 + - AddressOffset: 0x1 + Size: 0x4 Metadata: 0x0 - - AddressOffset: 0xc + - AddressOffset: 0x0 Size: 0x1 Metadata: 0x2 Symbols: @@ -130,33 +131,35 @@ Type: SHT_LLVM_BB_ADDR_MAP Link: .text.foo Entries: - - Address: 0x4000 + - Version: 1 + Address: 0x4000 BBEntries: - AddressOffset: 0x0 Size: 0x1 Metadata: 0x1 - - AddressOffset: 0x1 + - AddressOffset: 0x0 Size: 0x6 Metadata: 0x0 - - AddressOffset: 0x8 - Size: 0x3 + - AddressOffset: 0x1 + Size: 0x4 Metadata: 0x0 - - AddressOffset: 0xc + - AddressOffset: 0x0 Size: 0x1 Metadata: 0x2 - Name: bb_addr_map.bar Type: SHT_LLVM_BB_ADDR_MAP Link: .text.bar Entries: - - Address: 0x5000 + - Version: 1 + Address: 0x5000 BBEntries: - AddressOffset: 0x0 Size: 0x1 Metadata: 0x1 - - AddressOffset: 0x5 + - AddressOffset: 0x4 Size: 0x2 Metadata: 0x0 - - AddressOffset: 0x7 + - AddressOffset: 0x0 Size: 0x6 Metadata: 0x0 diff --git a/llvm/test/tools/llvm-readobj/ELF/bb-addr-map.test b/llvm/test/tools/llvm-readobj/ELF/bb-addr-map.test --- a/llvm/test/tools/llvm-readobj/ELF/bb-addr-map.test +++ b/llvm/test/tools/llvm-readobj/ELF/bb-addr-map.test @@ -1,75 +1,62 @@ ## This test checks how we handle the --bb-addr-map option. -# Check 64-bit: -# RUN: yaml2obj %s -DBITS=64 -DADDR=0x999999999 -o %t1.x64.o -# RUN: llvm-readobj %t1.x64.o --bb-addr-map 2>&1 | FileCheck %s -DADDR=0x999999999 -DFILE=%t1.x64.o --check-prefix=LLVM - +## Check 64-bit: +# RUN: yaml2obj --docnum=1 %s -DBITS=64 -DADDR=0x999999999 -o %t1.x64.o +# RUN: llvm-readobj %t1.x64.o --bb-addr-map 2>&1 | FileCheck %s -DADDR=0x999999999 -DFILE=%t1.x64.o --check-prefix=CHECK # RUN: llvm-readelf %t1.x64.o --bb-addr-map | FileCheck %s --check-prefix=GNU +## Check 64-bit: +# RUN: yaml2obj --docnum=1 %s -DBITS=64 -DADDR=0x999999999 -o %t1.v1.x64.o +# RUN: llvm-readobj %t1.v1.x64.o --bb-addr-map 2>&1 | FileCheck %s -DADDR=0x999999999 -DFILE=%t1.v1.x64.o --check-prefix=CHECK + ## Check 32-bit: -# RUN: yaml2obj %s -DBITS=32 -o %t1.x32.o -# RUN: llvm-readobj %t1.x32.o --bb-addr-map 2>&1 | FileCheck -DADDR=0x11111 %s -DFILE=%t1.x32.o --check-prefix=LLVM +# RUN: yaml2obj --docnum=1 %s -DBITS=32 -o %t1.x32.o +# RUN: llvm-readobj %t1.x32.o --bb-addr-map 2>&1 | FileCheck -DADDR=0x11111 %s -DFILE=%t1.x32.o --check-prefix=CHECK # RUN: llvm-readelf %t1.x32.o --bb-addr-map | FileCheck %s --check-prefix=GNU ## Check that a malformed section can be handled. -# RUN: yaml2obj %s -DBITS=32 -DSIZE=4 -o %t2.o -# RUN: llvm-readobj %t2.o --bb-addr-map 2>&1 | FileCheck %s -DOFFSET=0x00000004 -DFILE=%t2.o --check-prefix=TRUNCATED +# RUN: yaml2obj --docnum=1 %s -DBITS=32 -DSIZE=6 -o %t2.o +# RUN: llvm-readobj %t2.o --bb-addr-map 2>&1 | FileCheck %s -DOFFSET=0x00000006 -DFILE=%t2.o --check-prefix=TRUNCATED -# LLVM: BBAddrMap [ -# LLVM-NEXT: Function { -# LLVM-NEXT: At: [[ADDR]] -# LLVM-NEXT: warning: '[[FILE]]': could not identify function symbol for address ([[ADDR]]) in SHT_LLVM_BB_ADDR_MAP section with index 3 -# LLVM-NEXT: Name: -# LLVM-NEXT: BB entries [ -# LLVM-NEXT: { -# LLVM-NEXT: Offset: 0x0 -# LLVM-NEXT: Size: 0x1 -# LLVM-NEXT: HasReturn: No -# LLVM-NEXT: HasTailCall: Yes -# LLVM-NEXT: IsEHPad: No -# LLVM-NEXT: CanFallThrough: No -# LLVM-NEXT: } -# LLVM-NEXT: { -# LLVM-NEXT: Offset: 0x3 -# LLVM-NEXT: Size: 0x4 -# LLVM-NEXT: HasReturn: Yes -# LLVM-NEXT: HasTailCall: No -# LLVM-NEXT: IsEHPad: Yes -# LLVM-NEXT: CanFallThrough: No -# LLVM-NEXT: } -# LLVM-NEXT: ] -# LLVM-NEXT: } -# LLVM-NEXT: Function { -# LLVM-NEXT: At: 0x22222 -# LLVM-NEXT: Name: foo -# LLVM-NEXT: BB entries [ -# LLVM-NEXT: { -# LLVM-NEXT: Offset: 0x6 -# LLVM-NEXT: Size: 0x7 -# LLVM-NEXT: HasReturn: No -# LLVM-NEXT: HasTailCall: No -# LLVM-NEXT: IsEHPad: No -# LLVM-NEXT: CanFallThrough: Yes -# LLVM-NEXT: } -# LLVM-NEXT: ] -# LLVM-NEXT: } -# LLVM-NEXT: ] -# LLVM-NEXT: BBAddrMap [ -# LLVM-NEXT: Function { -# LLVM-NEXT: At: 0x33333 -# LLVM-NEXT: Name: bar -# LLVM-NEXT: BB entries [ -# LLVM-NEXT: { -# LLVM-NEXT: Offset: 0x9 -# LLVM-NEXT: Size: 0xA -# LLVM-NEXT: HasReturn: Yes -# LLVM-NEXT: HasTailCall: Yes -# LLVM-NEXT: IsEHPad: No -# LLVM-NEXT: CanFallThrough: Yes -# LLVM-NEXT: } -# LLVM-NEXT: ] -# LLVM-NEXT: } -# LLVM-NEXT: ] +# CHECK: BBAddrMap [ +# CHECK-NEXT: Function { +# CHECK-NEXT: At: [[ADDR]] +# CHECK-NEXT: warning: '[[FILE]]': could not identify function symbol for address ([[ADDR]]) in SHT_LLVM_BB_ADDR_MAP section with index 3 +# CHECK-NEXT: Name: +# CHECK-NEXT: BB entries [ +# CHECK-NEXT: { +# CHECK-NEXT: Offset: 0x0 +# CHECK-NEXT: Size: 0x1 +# CHECK-NEXT: HasReturn: No +# CHECK-NEXT: HasTailCall: Yes +# CHECK-NEXT: IsEHPad: No +# CHECK-NEXT: CanFallThrough: No +# CHECK-NEXT: } +# CHECK-NEXT: { +# CHECK-NEXT: Offset: 0x4 +# CHECK-NEXT: Size: 0x4 +# CHECK-NEXT: HasReturn: Yes +# CHECK-NEXT: HasTailCall: No +# CHECK-NEXT: IsEHPad: Yes +# CHECK-NEXT: CanFallThrough: No +# CHECK-NEXT: } +# CHECK-NEXT: ] +# CHECK-NEXT: } +# CHECK-NEXT: Function { +# CHECK-NEXT: At: 0x22222 +# CHECK-NEXT: Name: foo +# CHECK-NEXT: BB entries [ +# CHECK-NEXT: { +# CHECK-NEXT: Offset: 0x6 +# CHECK-NEXT: Size: 0x7 +# CHECK-NEXT: HasReturn: No +# CHECK-NEXT: HasTailCall: No +# CHECK-NEXT: IsEHPad: No +# CHECK-NEXT: CanFallThrough: Yes +# CHECK-NEXT: } +# CHECK-NEXT: ] +# CHECK-NEXT: } +# CHECK-NEXT: ] # GNU: GNUStyle::printBBAddrMaps not implemented @@ -90,6 +77,14 @@ # TRUNCATED-NEXT: IsEHPad: No # TRUNCATED-NEXT: CanFallThrough: Yes # TRUNCATED-NEXT: } +# TRUNCATED-NEXT: { +# TRUNCATED-NEXT: Offset: 0x1F +# TRUNCATED-NEXT: Size: 0xD +# TRUNCATED-NEXT: HasReturn: No +# TRUNCATED-NEXT: HasTailCall: Yes +# TRUNCATED-NEXT: IsEHPad: Yes +# TRUNCATED-NEXT: CanFallThrough: Yes +# TRUNCATED-NEXT: } # TRUNCATED-NEXT: ] # TRUNCATED-NEXT: } # TRUNCATED-NEXT: ] @@ -106,12 +101,13 @@ - Name: .text.bar Type: SHT_PROGBITS Flags: [SHF_ALLOC] - - Name: bb_addr_map_1 + - Name: .llvm_bb_addr_map Type: SHT_LLVM_BB_ADDR_MAP ShSize: [[SIZE=]] Link: .text Entries: - - Address: [[ADDR=0x11111]] + - Version: 1 + Address: [[ADDR=0x11111]] BBEntries: - AddressOffset: 0x0 Size: 0x1 @@ -119,23 +115,28 @@ - AddressOffset: 0x3 Size: 0x4 Metadata: 0x5 - - Address: 0x22222 + - Version: 1 + Address: 0x22222 BBEntries: - AddressOffset: 0x6 Size: 0x7 Metadata: 0x8 - - Name: dummy_section - Type: SHT_PROGBITS - Size: 16 - - Name: bb_addr_map_2 - Type: SHT_LLVM_BB_ADDR_MAP - Link: .text.bar + - Name: dummy_section + Type: SHT_PROGBITS + Size: 16 + - Name: '.llvm_bb_addr_map (1)' + Type: SHT_LLVM_BB_ADDR_MAP + Link: .text.bar Entries: - - Address: 0x33333 + - Version: 1 + Address: 0x33333 BBEntries: - AddressOffset: 0x9 Size: 0xa Metadata: 0xb + - AddressOffset: 0xc + Size: 0xd + Metadata: 0xe Symbols: - Name: foo Section: .text @@ -145,3 +146,67 @@ Section: .text.bar Type: STT_FUNC Value: 0x33333 + +## Check that using the SHT_LLVM_BB_ADDR_MAP_V0 section type generates the same +## result as using the SHT_LLVM_BB_ADDR_MAP section type with Version=0. +## The Version field is required even for SHT_LLVM_BB_ADDR_MAP_V0 but it +## should not impact the result. This unideal behavior will be gone once +## SHT_LLVM_BB_ADDR_MAP_V0 is deprecated. + +# RUN: yaml2obj --docnum=2 %s -DVERSION=255 -DSECTION_TYPE=SHT_LLVM_BB_ADDR_MAP_V0 -o %t2.type0 +# RUN: llvm-readobj %t2.type0 --bb-addr-map 2>&1 | FileCheck %s --check-prefix=V0 + +# RUN: yaml2obj --docnum=2 %s -DVERSION=0 -DSECTION_TYPE=SHT_LLVM_BB_ADDR_MAP -o %t2.version0 +# RUN: llvm-readobj %t2.version0 --bb-addr-map 2>&1 | FileCheck %s --check-prefix=V0 + +# V0: BBAddrMap [ +# V0-NEXT: Function { +# V0-NEXT: At: 0x11111 +# V0-NEXT: Name: foo +# V0-NEXT: BB entries [ +# V0-NEXT: { +# V0-NEXT: Offset: 0x1 +# V0-NEXT: Size: 0x2 +# V0-NEXT: HasReturn: +# V0-NEXT: HasTailCall: +# V0-NEXT: IsEHPad: +# V0-NEXT: CanFallThrough: +# V0-NEXT: } +# V0-NEXT: { +# V0-NEXT: Offset: 0x4 +# V0-NEXT: Size: 0x5 +# V0-NEXT: HasReturn: +# V0-NEXT: HasTailCall: +# V0-NEXT: IsEHPad: +# V0-NEXT: CanFallThrough: +# V0-NEXT: } +# V0-NEXT: ] +# V0-NEXT: } + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC +Sections: + - Name: .text.foo + Type: SHT_PROGBITS + Flags: [SHF_ALLOC] + - Name: .llvm_bb_addr_map + Type: [[SECTION_TYPE]] + Link: .text.foo + Entries: + - Version: [[VERSION]] + Address: 0x11111 + BBEntries: + - AddressOffset: 0x1 + Size: 0x2 + Metadata: 0x3 + - AddressOffset: 0x4 + Size: 0x5 + Metadata: 0x6 +Symbols: + - Name: foo + Section: .text.foo + Type: STT_FUNC + Value: 0x11111 diff --git a/llvm/test/tools/obj2yaml/ELF/bb-addr-map.yaml b/llvm/test/tools/obj2yaml/ELF/bb-addr-map.yaml --- a/llvm/test/tools/obj2yaml/ELF/bb-addr-map.yaml +++ b/llvm/test/tools/obj2yaml/ELF/bb-addr-map.yaml @@ -7,29 +7,33 @@ # VALID: --- !ELF # VALID-NEXT: FileHeader: -# VALID-NEXT: Class: ELFCLASS64 -# VALID-NEXT: Data: ELFDATA2LSB -# VALID-NEXT: Type: ET_EXEC +# 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: ## The 'Address' field is omitted when it's zero. +# VALID-NEXT: - Version: 1 +# VALID-NEXT: Feature: 0xFF # VALID-NEXT: BBEntries: -# VALID-NEXT: - AddressOffset: 0x1 -# VALID-NEXT: Size: 0x2 -# VALID-NEXT: Metadata: 0x3 -# VALID-NEXT: - AddressOffset: 0x4 -# VALID-NEXT: Size: 0x5 -# VALID-NEXT: Metadata: 0x6 -# VALID-NEXT: - AddressOffset: 0xFFFFFFFFFFFFFFF7 -# VALID-NEXT: Size: 0xFFFFFFFFFFFFFFF8 -# VALID-NEXT: Metadata: 0xFFFFFFFFFFFFFFF9 -# VALID-NEXT: - Address: 0xFFFFFFFFFFFFFF20 +# VALID-NEXT: - AddressOffset: 0x1 +# VALID-NEXT: Size: 0x2 +# VALID-NEXT: Metadata: 0x3 +# VALID-NEXT: - AddressOffset: 0x4 +# VALID-NEXT: Size: 0x5 +# VALID-NEXT: Metadata: 0x6 +# VALID-NEXT: - AddressOffset: 0xFFFFFFFFFFFFFFF7 +# VALID-NEXT: Size: 0xFFFFFFFFFFFFFFF8 +# VALID-NEXT: Metadata: 0xFFFFFFFFFFFFFFF9 +# VALID-NEXT: - Version: 1 +# VALID-NEXT: Feature: 0xEE +# VALID-NEXT: Address: 0xFFFFFFFFFFFFFF20 # VALID-NEXT: BBEntries: -# VALID-NEXT: - AddressOffset: 0xA -# VALID-NEXT: Size: 0xB -# VALID-NEXT: Metadata: 0xC +# VALID-NEXT: - AddressOffset: 0xA +# VALID-NEXT: Size: 0xB +# VALID-NEXT: Metadata: 0xC --- !ELF FileHeader: @@ -37,27 +41,31 @@ Data: ELFDATA2LSB Type: ET_EXEC Sections: - - Name: .llvm_bb_addr_map - Type: SHT_LLVM_BB_ADDR_MAP - ShSize: [[SIZE=]] + - Name: .llvm_bb_addr_map + Type: SHT_LLVM_BB_ADDR_MAP + ShSize: [[SIZE=]] Entries: - - Address: 0x0 - NumBlocks: [[NUMBLOCKS=]] + - Version: 1 + Feature: 0xFF + Address: 0x0 BBEntries: - - AddressOffset: 0x1 - Size: 0x2 - Metadata: 0x3 - - AddressOffset: 0x4 - Size: 0x5 - Metadata: 0x6 - - AddressOffset: 0xFFFFFFFFFFFFFFF7 - Size: 0xFFFFFFFFFFFFFFF8 - Metadata: 0xFFFFFFFFFFFFFFF9 - - Address: 0xFFFFFFFFFFFFFF20 + - AddressOffset: 0x1 + Size: 0x2 + Metadata: 0x3 + - AddressOffset: 0x4 + Size: 0x5 + Metadata: 0x6 + - AddressOffset: 0xFFFFFFFFFFFFFFF7 + Size: 0xFFFFFFFFFFFFFFF8 + Metadata: 0xFFFFFFFFFFFFFFF9 + - Version: 1 + Feature: 0xEE + Address: 0xFFFFFFFFFFFFFF20 + NumBlocks: [[NUMBLOCKS=]] BBEntries: - - AddressOffset: 0xA - Size: 0xB - Metadata: 0xC + - AddressOffset: 0xA + Size: 0xB + Metadata: 0xC ## Check obj2yaml can dump empty .llvm_bb_addr_map sections. @@ -95,18 +103,20 @@ # MULTI-NEXT: Data: ELFDATA2LSB # MULTI-NEXT: Type: ET_EXEC # MULTI-NEXT: Sections: -# MULTI-NEXT: - Name: .llvm_bb_addr_map -# MULTI-NEXT: Type: SHT_LLVM_BB_ADDR_MAP +# MULTI-NEXT: - Name: .llvm_bb_addr_map +# MULTI-NEXT: Type: SHT_LLVM_BB_ADDR_MAP # MULTI-NEXT: Entries: -## The 'Address' field is omitted when it's zero. -# MULTI-NEXT: - BBEntries: -# MULTI-NEXT: - AddressOffset: 0x1 -# MULTI-NEXT: Size: 0x2 -# MULTI-NEXT: Metadata: 0x3 -# MULTI-NEXT: - Name: '.llvm_bb_addr_map (1)' -# MULTI-NEXT: Type: SHT_LLVM_BB_ADDR_MAP +## Fields 'Address' and 'Feature' are omitted when they are zero. +# MULTI-NEXT: - Version: 0 +# MULTI-NEXT: BBEntries: +# MULTI-NEXT: - AddressOffset: 0x1 +# MULTI-NEXT: Size: 0x2 +# MULTI-NEXT: Metadata: 0x3 +# MULTI-NEXT: - Name: '.llvm_bb_addr_map (1)' +# MULTI-NEXT: Type: SHT_LLVM_BB_ADDR_MAP # MULTI-NEXT: Entries: -# MULTI-NEXT: - Address: 0x20 +# MULTI-NEXT: - Version: 0 +# MULTI-NEXT: Address: 0x20 # MULTI-NEXT: BBEntries: [] --- !ELF @@ -115,19 +125,23 @@ Data: ELFDATA2LSB Type: ET_EXEC Sections: - - Name: .llvm_bb_addr_map - Type: SHT_LLVM_BB_ADDR_MAP + - Name: .llvm_bb_addr_map + Type: SHT_LLVM_BB_ADDR_MAP Entries: -## Check that obj2yaml does not emit the Address field when it's zero. - - Address: 0x0 +## Check that obj2yaml does not emit the 'Address' and 'Feature' fields when +## they are zero. + - Version: 0 + Feature: 0x0 + Address: 0x0 BBEntries: - - AddressOffset: 0x1 - Size: 0x2 - Metadata: 0x3 - - Name: '.llvm_bb_addr_map (1)' - Type: SHT_LLVM_BB_ADDR_MAP + - AddressOffset: 0x1 + Size: 0x2 + Metadata: 0x3 + - Name: '.llvm_bb_addr_map (1)' + Type: SHT_LLVM_BB_ADDR_MAP Entries: - - Address: 0x20 + - Version: 0 + Address: 0x20 ## Check that obj2yaml uses the "Content" tag to describe an .llvm_bb_addr_map section ## when it can't extract the entries, for example, when the section is truncated, or @@ -141,11 +155,47 @@ # INVALID: --- !ELF # INVALID-NEXT: FileHeader: -# INVALID-NEXT: Class: ELFCLASS64 -# INVALID-NEXT: Data: ELFDATA2LSB -# INVALID-NEXT: Type: ET_EXEC +# INVALID-NEXT: Class: ELFCLASS64 +# INVALID-NEXT: Data: ELFDATA2LSB +# INVALID-NEXT: Type: ET_EXEC # INVALID-NEXT: Sections: -# INVALID-NEXT: - Name: .llvm_bb_addr_map -# INVALID-NEXT: Type: SHT_LLVM_BB_ADDR_MAP +# INVALID-NEXT: - Name: .llvm_bb_addr_map +# INVALID-NEXT: Type: SHT_LLVM_BB_ADDR_MAP # BADNUMBLOCKS-NEXT: Content: {{([[:xdigit:]]+)}}{{$}} -# TRUNCATED-NEXT: Content: '{{([[:xdigit:]]{16})}}'{{$}} +# TRUNCATED-NEXT: Content: {{([[:xdigit:]]{16})}}{{$}} + +## Check obj2yaml for SHT_LLVM_BB_ADDR_MAP_V0. +# RUN: yaml2obj --docnum=4 %s -o %t6 +# RUN: obj2yaml %t6 | FileCheck %s --check-prefix=V0 + +# V0: --- !ELF +# V0-NEXT: FileHeader: +# V0-NEXT: Class: ELFCLASS64 +# V0-NEXT: Data: ELFDATA2LSB +# V0-NEXT: Type: ET_EXEC +# V0-NEXT: Sections: +# V0-NEXT: - Name: .llvm_bb_addr_map +# V0-NEXT: Type: SHT_LLVM_BB_ADDR_MAP_V0 +# V0-NEXT: Entries: +# V0-NEXT: - Version: 0 +# V0-NEXT: Address: 0x1111 +# V0-NEXT: BBEntries: +# V0-NEXT: - AddressOffset: 0x1 +# V0-NEXT: Size: 0x2 +# V0-NEXT: Metadata: 0x3 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC +Sections: + - Name: .llvm_bb_addr_map + Type: SHT_LLVM_BB_ADDR_MAP_V0 + Entries: + - Version: 0 + Address: 0x1111 + BBEntries: + - AddressOffset: 0x1 + Size: 0x2 + Metadata: 0x3 diff --git a/llvm/test/tools/yaml2obj/ELF/bb-addr-map.yaml b/llvm/test/tools/yaml2obj/ELF/bb-addr-map.yaml --- a/llvm/test/tools/yaml2obj/ELF/bb-addr-map.yaml +++ b/llvm/test/tools/yaml2obj/ELF/bb-addr-map.yaml @@ -7,7 +7,7 @@ # CHECK: Section { # CHECK: Index: 1 # CHECK-NEXT: Name: .llvm_bb_addr_map (1) -# CHECK-NEXT: Type: SHT_LLVM_BB_ADDR_MAP (0x6FFF4C08) +# CHECK-NEXT: Type: SHT_LLVM_BB_ADDR_MAP (0x6FFF4C0A) # CHECK-NEXT: Flags [ (0x0) # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x0 @@ -36,7 +36,7 @@ # Case 4: Specify Entries. # CHECK: Name: .llvm_bb_addr_map (1) # CHECK: SectionData ( -# CHECK-NEXT: 0000: 20000000 00000000 01010203 +# CHECK-NEXT: 0000: 01002000 00000000 00000101 0203 # CHECK-NEXT: ) # Case 5: Specify Entries and omit the Address field. @@ -44,13 +44,13 @@ # CHECK: Address: # CHECK-SAME: {{^ 0x0$}} # CHECK: SectionData ( -# CHECK-NEXT: 0000: 00000000 00000000 01010203 +# CHECK-NEXT: 0000: 00000000 00000000 00000101 0203 # CHECK-NEXT: ) # Case 6: Override the NumBlocks field. # CHECK: Name: .llvm_bb_addr_map (1) # CHECK: SectionData ( -# CHECK-NEXT: 0000: 20000000 00000000 02010203 +# CHECK-NEXT: 0000: 01002000 00000000 00000201 0203 # CHECK-NEXT: ) --- !ELF @@ -71,47 +71,50 @@ ## 2) We can produce an empty .llvm_bb_addr_map section from a description ## with empty section content. - - Name: '.llvm_bb_addr_map (2)' - Type: SHT_LLVM_BB_ADDR_MAP + - Name: '.llvm_bb_addr_map (2)' + Type: SHT_LLVM_BB_ADDR_MAP ## 3) We can produce a zero .llvm_bb_addr_map section of a specific size when ## we specify the size only. - - Name: '.llvm_bb_addr_map (3)' - Type: SHT_LLVM_BB_ADDR_MAP - Size: 8 + - Name: '.llvm_bb_addr_map (3)' + Type: SHT_LLVM_BB_ADDR_MAP + Size: 8 ## 4) We can produce an .llvm_bb_addr_map section from a description with ## Entries. - - Name: '.llvm_bb_addr_map (4)' - Type: SHT_LLVM_BB_ADDR_MAP + - Name: '.llvm_bb_addr_map (4)' + Type: SHT_LLVM_BB_ADDR_MAP Entries: - - Address: 0x0000000000000020 + - Version: 1 + Address: 0x0000000000000020 BBEntries: - - AddressOffset: 0x00000001 - Size: 0x00000002 - Metadata: 0x00000003 + - AddressOffset: 0x00000001 + Size: 0x00000002 + Metadata: 0x00000003 ## 5) When specifying the description with Entries, the 'Address' field will be ## zero when omitted. - - Name: '.llvm_bb_addr_map (5)' - Type: SHT_LLVM_BB_ADDR_MAP + - Name: '.llvm_bb_addr_map (5)' + Type: SHT_LLVM_BB_ADDR_MAP Entries: - - BBEntries: - - AddressOffset: 0x00000001 - Size: 0x00000002 - Metadata: 0x00000003 + - Version: 0 + BBEntries: + - AddressOffset: 0x00000001 + Size: 0x00000002 + Metadata: 0x00000003 ## 6) We can override the NumBlocks field with a value different from the ## actual number of BB Entries. - - Name: '.llvm_bb_addr_map (6)' - Type: SHT_LLVM_BB_ADDR_MAP + - Name: '.llvm_bb_addr_map (6)' + Type: SHT_LLVM_BB_ADDR_MAP Entries: - - Address: 0x0000000000000020 + - Version: 1 + Address: 0x0000000000000020 NumBlocks: 2 BBEntries: - - AddressOffset: 0x00000001 - Size: 0x00000002 - Metadata: 0x00000003 + - AddressOffset: 0x00000001 + Size: 0x00000002 + Metadata: 0x00000003 ## Check we can't use Entries at the same time as either Content or Size. # RUN: not yaml2obj --docnum=2 -DCONTENT="00" %s 2>&1 | FileCheck %s --check-prefix=INVALID @@ -131,3 +134,20 @@ Entries: [] Content: [[CONTENT=]] Size: [[SIZE=]] + +## Check we can't use unsupported versions. +# RUN: not yaml2obj --docnum=3 %s 2>&1 | FileCheck %s --check-prefix=INVALID-VERSION + +# INVALID-VERSION: unsupported SHT_LLVM_BB_ADDR_MAP version: 2 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC +Sections: + - Name: '.llvm_bb_addr_map' + Type: SHT_LLVM_BB_ADDR_MAP + Entries: +## Specify unsupported version + - Version: 2 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 @@ -7028,8 +7028,10 @@ template void LLVMELFDumper::printBBAddrMaps() { bool IsRelocatable = this->Obj.getHeader().e_type == ELF::ET_REL; for (const Elf_Shdr &Sec : cantFail(this->Obj.sections())) { - if (Sec.sh_type != SHT_LLVM_BB_ADDR_MAP) + if (Sec.sh_type != SHT_LLVM_BB_ADDR_MAP && + Sec.sh_type != SHT_LLVM_BB_ADDR_MAP_V0) { continue; + } Optional FunctionSec = None; if (IsRelocatable) FunctionSec = 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 @@ -626,6 +626,7 @@ case ELF::SHT_LLVM_CALL_GRAPH_PROFILE: return [this](const Elf_Shdr *S) { return dumpCallGraphProfileSection(S); }; + case ELF::SHT_LLVM_BB_ADDR_MAP_V0: case ELF::SHT_LLVM_BB_ADDR_MAP: return [this](const Elf_Shdr *S) { return dumpBBAddrMapSection(S); }; case ELF::SHT_STRTAB: @@ -889,7 +890,18 @@ std::vector Entries; DataExtractor::Cursor Cur(0); + uint8_t Version = 0; + uint8_t Feature = 0; while (Cur && Cur.tell() < Content.size()) { + if (Shdr->sh_type == ELF::SHT_LLVM_BB_ADDR_MAP) { + Version = Data.getU8(Cur); + if (Cur && Version > 1) + return createStringError( + errc::invalid_argument, + "invalid SHT_LLVM_BB_ADDR_MAP section version: " + + Twine(static_cast(Version))); + Feature = Data.getU8(Cur); + } uint64_t Address = Data.getAddress(Cur); uint64_t NumBlocks = Data.getULEB128(Cur); std::vector BBEntries; @@ -900,7 +912,8 @@ uint64_t Metadata = Data.getULEB128(Cur); BBEntries.push_back({Offset, Size, Metadata}); } - Entries.push_back({Address, /*NumBlocks=*/{}, BBEntries}); + Entries.push_back( + {Version, Feature, Address, /*NumBlocks=*/{}, std::move(BBEntries)}); } if (!Cur) { diff --git a/llvm/unittests/Object/ELFObjectFileTest.cpp b/llvm/unittests/Object/ELFObjectFileTest.cpp --- a/llvm/unittests/Object/ELFObjectFileTest.cpp +++ b/llvm/unittests/Object/ELFObjectFileTest.cpp @@ -505,10 +505,11 @@ Data: ELFDATA2LSB Type: ET_EXEC Sections: - - Name: .llvm_bb_addr_map - Type: SHT_LLVM_BB_ADDR_MAP + - Type: SHT_LLVM_BB_ADDR_MAP + Name: .llvm_bb_addr_map Entries: - Address: 0x11111 + Version: 1 BBEntries: - AddressOffset: 0x0 Size: 0x1 @@ -533,9 +534,9 @@ // truncated. SmallString<128> TruncatedYamlString(CommonYamlString); TruncatedYamlString += R"( - ShSize: 0x8 + ShSize: 0xa )"; - DoCheck(TruncatedYamlString, "unable to decode LEB128 at offset 0x00000008: " + DoCheck(TruncatedYamlString, "unable to decode LEB128 at offset 0x0000000a: " "malformed uleb128, extends past end"); // Check that we can detect when the encoded BB entry fields exceed the UINT32 @@ -561,11 +562,11 @@ )"; DoCheck(OverInt32LimitYamlStrings[0], - "ULEB128 value at offset 0xc exceeds UINT32_MAX (0x100000000)"); + "ULEB128 value at offset 0xe exceeds UINT32_MAX (0x100000000)"); DoCheck(OverInt32LimitYamlStrings[1], - "ULEB128 value at offset 0x11 exceeds UINT32_MAX (0x100000000)"); + "ULEB128 value at offset 0x13 exceeds UINT32_MAX (0x100000000)"); DoCheck(OverInt32LimitYamlStrings[2], - "ULEB128 value at offset 0x16 exceeds UINT32_MAX (0x100000000)"); + "ULEB128 value at offset 0x18 exceeds UINT32_MAX (0x100000000)"); // Check the proper error handling when the section has fields exceeding // UINT32 and is also truncated. This is for checking that we don't generate @@ -574,24 +575,24 @@ 3, OverInt32LimitYamlStrings[1]); // Truncate before the end of the 5-byte field. OverInt32LimitAndTruncated[0] += R"( - ShSize: 0x15 + ShSize: 0x17 )"; // Truncate at the end of the 5-byte field. OverInt32LimitAndTruncated[1] += R"( - ShSize: 0x16 + ShSize: 0x18 )"; // Truncate after the end of the 5-byte field. OverInt32LimitAndTruncated[2] += R"( - ShSize: 0x17 + ShSize: 0x19 )"; DoCheck(OverInt32LimitAndTruncated[0], - "unable to decode LEB128 at offset 0x00000011: malformed uleb128, " + "unable to decode LEB128 at offset 0x00000013: malformed uleb128, " "extends past end"); DoCheck(OverInt32LimitAndTruncated[1], - "ULEB128 value at offset 0x11 exceeds UINT32_MAX (0x100000000)"); + "ULEB128 value at offset 0x13 exceeds UINT32_MAX (0x100000000)"); DoCheck(OverInt32LimitAndTruncated[2], - "ULEB128 value at offset 0x11 exceeds UINT32_MAX (0x100000000)"); + "ULEB128 value at offset 0x13 exceeds UINT32_MAX (0x100000000)"); // Check for proper error handling when the 'NumBlocks' field is overridden // with an out-of-range value. @@ -601,7 +602,7 @@ )"; DoCheck(OverLimitNumBlocks, - "ULEB128 value at offset 0x8 exceeds UINT32_MAX (0x100000000)"); + "ULEB128 value at offset 0xa exceeds UINT32_MAX (0x100000000)"); } // Test for the ELFObjectFile::readBBAddrMap API. @@ -617,7 +618,8 @@ Type: SHT_LLVM_BB_ADDR_MAP Link: 1 Entries: - - Address: 0x11111 + - Version: 1 + Address: 0x11111 BBEntries: - AddressOffset: 0x0 Size: 0x1 @@ -626,16 +628,18 @@ Type: SHT_LLVM_BB_ADDR_MAP Link: 1 Entries: - - Address: 0x22222 + - Version: 1 + Address: 0x22222 BBEntries: - AddressOffset: 0x0 Size: 0x2 Metadata: 0x4 - Name: .llvm_bb_addr_map - Type: SHT_LLVM_BB_ADDR_MAP + Type: SHT_LLVM_BB_ADDR_MAP_V0 # Link: 0 (by default) Entries: - - Address: 0x33333 + - Version: 0 + Address: 0x33333 BBEntries: - AddressOffset: 0x0 Size: 0x3 @@ -697,8 +701,9 @@ )"; DoCheckFails(InvalidLinkedYamlString, /*TextSectionIndex=*/1, - "unable to get the linked-to section for SHT_LLVM_BB_ADDR_MAP " - "section with index 3: invalid section index: 10"); + "unable to get the linked-to section for " + "SHT_LLVM_BB_ADDR_MAP_V0 section with index 3: invalid section " + "index: 10"); // Linked sections are not checked when we don't target a specific text // section. DoCheckSucceeds(InvalidLinkedYamlString, /*TextSectionIndex=*/None, @@ -711,7 +716,7 @@ )"; DoCheckFails(TruncatedYamlString, /*TextSectionIndex=*/None, - "unable to read SHT_LLVM_BB_ADDR_MAP section with index 3: " + "unable to read SHT_LLVM_BB_ADDR_MAP_V0 section with index 3: " "unable to decode LEB128 at offset 0x00000008: malformed " "uleb128, extends past end"); // Check that we can read the other section's bb-address-maps which are