diff --git a/llvm/docs/Extensions.rst b/llvm/docs/Extensions.rst --- a/llvm/docs/Extensions.rst +++ b/llvm/docs/Extensions.rst @@ -395,17 +395,29 @@ .. _partition: https://lld.llvm.org/Partitions.html -``SHT_LLVM_BB_ADDR_MAP`` Section (basic block address map) +``SHT_LLVM_BB_ADDR_MAP`` and ``SHT_LLVM_BB_ADDR_MAP_V0`` Sections (basic block address map) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This section stores the binary address of basic blocks along with other related 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,16 +425,35 @@ .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 ------------------ -``.cv_file`` Directive +``.cv_file`` Directive ^^^^^^^^^^^^^^^^^^^^^^ Syntax: ``.cv_file`` *FileNumber FileName* [ *checksum* ] [ *checksumkind* ] 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 @@ -985,8 +985,9 @@ 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_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 @@ -170,6 +170,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. @@ -673,6 +676,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,25 @@ OutStreamer->pushSection(); OutStreamer->switchSection(BBAddrMapSection); + // Emit the version and feature values. + OutStreamer->emitInt8(OutStreamer->getContext().getBBAddrMapVersion()); + OutStreamer->emitInt8(0); OutStreamer->emitSymbolValue(FunctionSymbol, getPointerSize()); // Emit the total number of basic blocks in this function. 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); @@ -636,11 +637,10 @@ return ContentsOrErr.takeError(); ArrayRef Content = *ContentsOrErr; DataExtractor Data(Content, isLE(), ELFT::Is64Bits ? 8 : 4); + DataExtractor::Cursor Cur(0); std::vector FunctionEntries; - 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,15 +660,32 @@ 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 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}); 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,8 +678,9 @@ 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); if (!TextSecOrErr) 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 @@ -1394,6 +1394,12 @@ return; for (const ELFYAML::BBAddrMapEntry &E : *Section.Entries) { + // Write version and feature values. + if (Section.Type == llvm::ELF::SHT_LLVM_BB_ADDR_MAP) { + 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); @@ -1640,6 +1641,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()); @@ -1769,6 +1771,8 @@ void MappingTraits::mapping( IO &IO, ELFYAML::BBAddrMapEntry &E) { assert(IO.getContext() && "The IO context is not initialized"); + IO.mapOptional("Version", E.Version, 0); + 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-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,7 @@ ; 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: .quad [[BAR_BEGIN]] define dso_local i32 @_Z3foov() { @@ -21,7 +21,7 @@ ; 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: .quad [[FOO_BEGIN]] define linkonce_odr dso_local i32 @_Z4fooTIiET_v() comdat { @@ -32,4 +32,4 @@ ; 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: .quad [[FOOCOMDAT_BEGIN]] 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: .byte 1 +; CHECK-NEXT: .byte 0 ; CHECK-NEXT: .quad .Lfunc_begin0 ; CHECK-NEXT: .byte 4 ; 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-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,80 +1,116 @@ ## 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 (version #0 encoding): +# RUN: yaml2obj %s -DBITS=64 -DVERSION=0 -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-prefixes=CHECK,V0 # RUN: llvm-readelf %t1.x64.o --bb-addr-map | FileCheck %s --check-prefix=GNU +## Check 64-bit (version #1 encoding): +# RUN: yaml2obj %s -DBITS=64 -DVERSION=1 -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-prefixes=CHECK,V1 + ## 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: llvm-readobj %t1.x32.o --bb-addr-map 2>&1 | FileCheck -DADDR=0x11111 %s -DFILE=%t1.x32.o --check-prefixes=CHECK,V1 # 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 %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 4 +# 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: { +# V0-NEXT: Offset: 0x3 +# V1-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: ] +# CHECK-NEXT: BBAddrMap [ +# CHECK-NEXT: Function { +# CHECK-NEXT: At: 0x33333 +# CHECK-NEXT: Name: bar +# CHECK-NEXT: BB entries [ +# CHECK-NEXT: { +# CHECK-NEXT: Offset: 0x9 +# CHECK-NEXT: Size: 0xA +# CHECK-NEXT: HasReturn: Yes +# CHECK-NEXT: HasTailCall: Yes +# CHECK-NEXT: IsEHPad: No +# CHECK-NEXT: CanFallThrough: Yes +# CHECK-NEXT: } +# CHECK-NEXT: { +# CHECK-NEXT: Offset: 0xC +# CHECK-NEXT: Size: 0xD +# CHECK-NEXT: HasReturn: No +# CHECK-NEXT: HasTailCall: Yes +# CHECK-NEXT: IsEHPad: Yes +# CHECK-NEXT: CanFallThrough: Yes +# CHECK-NEXT: } +# CHECK-NEXT: ] +# CHECK-NEXT: } +# CHECK-NEXT: ] +# CHECK-NEXT: BBAddrMap [ +# CHECK-NEXT: Function { +# CHECK-NEXT: At: 0x44444 +# CHECK-NEXT: Name: baz +# CHECK-NEXT: BB entries [ +# CHECK-NEXT: { +# CHECK-NEXT: Offset: 0xF +# CHECK-NEXT: Size: 0x10 +# CHECK-NEXT: HasReturn: +# CHECK-NEXT: HasTailCall +# CHECK-NEXT: IsEHPad: +# CHECK-NEXT: CanFallThrough: +# CHECK-NEXT: } +# CHECK-NEXT: { +# CHECK-NEXT: Offset: 0x12 +# CHECK-NEXT: Size: 0x13 +# CHECK-NEXT: HasReturn: +# CHECK-NEXT: HasTailCall: +# CHECK-NEXT: IsEHPad: +# CHECK-NEXT: CanFallThrough: +# CHECK-NEXT: } +# CHECK-NEXT: ] +# CHECK-NEXT: } +# CHECK-NEXT: ] # GNU: GNUStyle::printBBAddrMaps not implemented # TRUNCATED: BBAddrMap [ -# TRUNCATED-NEXT: warning: '[[FILE]]': unable to dump SHT_LLVM_BB_ADDR_MAP section with index 3: unable to decode LEB128 at offset [[OFFSET]]: malformed uleb128, extends past end +# TRUNCATED-NEXT: warning: '[[FILE]]': unable to dump SHT_LLVM_BB_ADDR_MAP section with index 4: unable to decode LEB128 at offset [[OFFSET]]: malformed uleb128, extends past end # TRUNCATED-NEXT: ] ## Check that the other valid section is properly dumped. # TRUNCATED-NEXT: BBAddrMap [ @@ -90,6 +126,14 @@ # TRUNCATED-NEXT: IsEHPad: No # TRUNCATED-NEXT: CanFallThrough: Yes # TRUNCATED-NEXT: } +# TRUNCATED-NEXT: { +# TRUNCATED-NEXT: Offset: 0xC +# 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 +150,16 @@ - Name: .text.bar Type: SHT_PROGBITS Flags: [SHF_ALLOC] - - Name: bb_addr_map_1 + - Name: .text.baz + Type: SHT_PROGBITS + Flags: [SHF_ALLOC] + - Name: .llvm_bb_addr_map Type: SHT_LLVM_BB_ADDR_MAP ShSize: [[SIZE=]] Link: .text Entries: - Address: [[ADDR=0x11111]] + Version: [[VERSION=1]] BBEntries: - AddressOffset: 0x0 Size: 0x1 @@ -127,7 +175,7 @@ - Name: dummy_section Type: SHT_PROGBITS Size: 16 - - Name: bb_addr_map_2 + - Name: '.llvm_bb_addr_map (1)' Type: SHT_LLVM_BB_ADDR_MAP Link: .text.bar Entries: @@ -136,6 +184,22 @@ - AddressOffset: 0x9 Size: 0xa Metadata: 0xb + - AddressOffset: 0xc + Size: 0xd + Metadata: 0xe + - Name: '.llvm_bb_addr_map (2)' +# Old section type + Type: SHT_LLVM_BB_ADDR_MAP_V0 + Link: .text.baz + Entries: + - Address: 0x44444 + BBEntries: + - AddressOffset: 0xf + Size: 0x10 + Metadata: 0x11 + - AddressOffset: 0x12 + Size: 0x13 + Metadata: 0x14 Symbols: - Name: foo Section: .text @@ -145,3 +209,7 @@ Section: .text.bar Type: STT_FUNC Value: 0x33333 + - Name: baz + Section: .text.baz + Type: STT_FUNC + Value: 0x44444 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 @@ -15,6 +15,8 @@ # 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 @@ -25,7 +27,9 @@ # VALID-NEXT: - AddressOffset: 0xFFFFFFFFFFFFFFF7 # VALID-NEXT: Size: 0xFFFFFFFFFFFFFFF8 # VALID-NEXT: Metadata: 0xFFFFFFFFFFFFFFF9 -# VALID-NEXT: - Address: 0xFFFFFFFFFFFFFF20 +# VALID-NEXT: - Version: 2 +# VALID-NEXT: Feature: 0xEE +# VALID-NEXT: Address: 0xFFFFFFFFFFFFFF20 # VALID-NEXT: BBEntries: # VALID-NEXT: - AddressOffset: 0xA # VALID-NEXT: Size: 0xB @@ -39,9 +43,11 @@ Sections: - Name: .llvm_bb_addr_map Type: SHT_LLVM_BB_ADDR_MAP - ShSize: [[SIZE=]] + ShSize: [[SIZE=]] Entries: - - Address: 0x0 + - Version: 1 + Feature: 0xFF + Address: 0x0 NumBlocks: [[NUMBLOCKS=]] BBEntries: - AddressOffset: 0x1 @@ -53,7 +59,9 @@ - AddressOffset: 0xFFFFFFFFFFFFFFF7 Size: 0xFFFFFFFFFFFFFFF8 Metadata: 0xFFFFFFFFFFFFFFF9 - - Address: 0xFFFFFFFFFFFFFF20 + - Version: 2 + Feature: 0xEE + Address: 0xFFFFFFFFFFFFFF20 BBEntries: - AddressOffset: 0xA Size: 0xB @@ -98,7 +106,7 @@ # 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. +## Fields 'Address', 'Version', and 'Feature' are omitted when theyr are zero. # MULTI-NEXT: - BBEntries: # MULTI-NEXT: - AddressOffset: 0x1 # MULTI-NEXT: Size: 0x2 @@ -118,8 +126,10 @@ - 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, Version, and Feature fields when it's zero. + - Version: 0 + Feature: 0x0 + Address: 0x0 BBEntries: - AddressOffset: 0x1 Size: 0x2 @@ -148,4 +158,38 @@ # 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: - 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: + - 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: 00002000 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: 00002000 00000000 00000201 0203 # CHECK-NEXT: ) --- !ELF 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 @@ -7029,7 +7029,7 @@ 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) 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,13 @@ 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); + Feature = Data.getU8(Cur); + } uint64_t Address = Data.getAddress(Cur); uint64_t NumBlocks = Data.getULEB128(Cur); std::vector BBEntries; @@ -900,7 +907,7 @@ 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=*/{}, 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,14 +505,8 @@ Data: ELFDATA2LSB Type: ET_EXEC Sections: - - Name: .llvm_bb_addr_map - Type: SHT_LLVM_BB_ADDR_MAP - Entries: - - Address: 0x11111 - BBEntries: - - AddressOffset: 0x0 - Size: 0x1 - Metadata: 0x2 + - Type: SHT_LLVM_BB_ADDR_MAP + Name: .llvm_bb_addr_map )"); auto DoCheck = [&](StringRef YamlString, const char *ErrMsg) { @@ -529,19 +523,45 @@ FailedWithMessage(ErrMsg)); }; + // Check that we can detect invalid and unsupported versions. + SmallVector, 2> InvalidVersionYamlStrings(2, CommonYamlString); + InvalidVersionYamlStrings[0] += R"( + Entries: + - Version: 2 +)"; + InvalidVersionYamlStrings[1] += R"( + Entries: + - Version: 255 +)"; + DoCheck(InvalidVersionYamlStrings[0], + "unsupported LLVM_BB_ADDR_MAP version: 2"); + DoCheck(InvalidVersionYamlStrings[1], + "unsupported LLVM_BB_ADDR_MAP version: 255"); + + SmallString<128> CommonValidYamlString(CommonYamlString); + CommonValidYamlString += R"( + Entries: + - Address: 0x11111 + Version: 1 + BBEntries: + - AddressOffset: 0x0 + Size: 0x1 + Metadata: 0x2 +)"; + // Check that we can detect the malformed encoding when the section is // truncated. - SmallString<128> TruncatedYamlString(CommonYamlString); + SmallString<128> TruncatedYamlString(CommonValidYamlString); 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 // limit. - SmallVector, 3> OverInt32LimitYamlStrings(3, - CommonYamlString); + SmallVector, 3> OverInt32LimitYamlStrings( + 3, CommonValidYamlString); OverInt32LimitYamlStrings[0] += R"( - AddressOffset: 0x100000000 Size: 0xFFFFFFFF @@ -561,11 +581,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,34 +594,34 @@ 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. - SmallString<128> OverLimitNumBlocks(CommonYamlString); + SmallString<128> OverLimitNumBlocks(CommonValidYamlString); OverLimitNumBlocks += R"( NumBlocks: 0x100000000 )"; 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 +637,8 @@ Type: SHT_LLVM_BB_ADDR_MAP Link: 1 Entries: - - Address: 0x11111 + - Version: 1 + Address: 0x11111 BBEntries: - AddressOffset: 0x0 Size: 0x1 @@ -626,13 +647,14 @@ 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 @@ -697,8 +719,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 +734,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