diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h index 8853c4a88b0b5..4b826bbf58f17 100644 --- a/llvm/include/llvm/BinaryFormat/ELF.h +++ b/llvm/include/llvm/BinaryFormat/ELF.h @@ -1798,6 +1798,7 @@ enum : unsigned { GNU_PROPERTY_AARCH64_FEATURE_1_AND = 0xc0000000, GNU_PROPERTY_AARCH64_FEATURE_PAUTH = 0xc0000001, GNU_PROPERTY_X86_FEATURE_1_AND = 0xc0000002, + GNU_PROPERTY_RISCV_FEATURE_1_AND = 0xc0000000, GNU_PROPERTY_X86_UINT32_OR_LO = 0xc0008000, GNU_PROPERTY_X86_FEATURE_2_NEEDED = GNU_PROPERTY_X86_UINT32_OR_LO + 1, @@ -1862,6 +1863,13 @@ enum : unsigned { GNU_PROPERTY_X86_ISA_1_V4 = 1 << 3, }; +// RISC-V processor feature bits. +enum : unsigned { + GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED = 1 << 0, + GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS = 1 << 1, + GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_FUNC_SIG = 1 << 2, +}; + // FreeBSD note types. enum { NT_FREEBSD_ABI_TAG = 1, diff --git a/llvm/test/tools/llvm-readobj/ELF/RISCV/note-gnu-property.yaml b/llvm/test/tools/llvm-readobj/ELF/RISCV/note-gnu-property.yaml new file mode 100644 index 0000000000000..f87ed762038c1 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/ELF/RISCV/note-gnu-property.yaml @@ -0,0 +1,45 @@ +# RUN: yaml2obj %s -DBITS=32 -DPR_PADDING= -o %t1 +# RUN: llvm-readelf --notes %t1 | FileCheck %s --check-prefix=GNU +# RUN: llvm-readobj --notes %t1 | FileCheck %s --check-prefix=LLVM + +# RUN: yaml2obj %s -DBITS=64 -DPR_PADDING=00000000 -o %t2 +# RUN: llvm-readelf --notes %t2 | FileCheck %s --check-prefix=GNU +# RUN: llvm-readobj --notes %t2 | FileCheck %s --check-prefix=LLVM + +# GNU: Displaying notes found in: .note.gnu.property +# GNU-NEXT: Owner Data size Description +# GNU-NEXT: GNU 0x{{([0-9a-z]{8})}} NT_GNU_PROPERTY_TYPE_0 (property note) +# GNU-NEXT: Properties: RISC-V feature: ZICFILP-unlabeled, ZICFISS, ZICFILP-func-sig + +# LLVM: NoteSections [ +# LLVM-NEXT: NoteSection { +# LLVM-NEXT: Name: .note.gnu.property +# LLVM-NEXT: Offset: +# LLVM-NEXT: Size: +# LLVM-NEXT: Notes [ +# LLVM-NEXT: { +# LLVM-NEXT: Owner: GNU +# LLVM-NEXT: Data size: +# LLVM-NEXT: Type: NT_GNU_PROPERTY_TYPE_0 (property note) +# LLVM-NEXT: Property [ +# LLVM-NEXT: RISC-V feature: ZICFILP-unlabeled, ZICFISS, ZICFILP-func-sig +# LLVM-NEXT: ] +# LLVM-NEXT: } +# LLVM-NEXT: ] +# LLVM-NEXT: } +# LLVM-NEXT: ] + +--- !ELF +FileHeader: + Class: ELFCLASS[[BITS]] + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_RISCV +Sections: + - Name: .note.gnu.property + Type: SHT_NOTE + Flags: [ SHF_ALLOC ] + Notes: + - Name: 'GNU' + Desc: '000000c00400000007000000[[PR_PADDING]]' + Type: 5 # NT_GNU_PROPERTY_TYPE_0 diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp index bfca65aad52b4..7806eea6a0c52 100644 --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -5333,7 +5333,8 @@ static bool printAArch64PAuthABICoreInfo(raw_ostream &OS, uint32_t DataSize, template static std::string getGNUProperty(uint32_t Type, uint32_t DataSize, - ArrayRef Data) { + ArrayRef Data, + typename ELFT::Half EMachine) { std::string str; raw_string_ostream OS(str); uint32_t PrData; @@ -5366,8 +5367,25 @@ static std::string getGNUProperty(uint32_t Type, uint32_t DataSize, return str; case GNU_PROPERTY_AARCH64_FEATURE_1_AND: case GNU_PROPERTY_X86_FEATURE_1_AND: - OS << ((Type == GNU_PROPERTY_AARCH64_FEATURE_1_AND) ? "aarch64 feature: " - : "x86 feature: "); + static_assert(GNU_PROPERTY_AARCH64_FEATURE_1_AND == + GNU_PROPERTY_RISCV_FEATURE_1_AND, + "GNU_PROPERTY_RISCV_FEATURE_1_AND should equal " + "GNU_PROPERTY_AARCH64_FEATURE_1_AND, otherwise " + "GNU_PROPERTY_RISCV_FEATURE_1_AND would be skipped!"); + + if (EMachine == EM_AARCH64 && Type == GNU_PROPERTY_AARCH64_FEATURE_1_AND) { + OS << "aarch64 feature: "; + } else if (EMachine == EM_RISCV && + Type == GNU_PROPERTY_RISCV_FEATURE_1_AND) { + OS << "RISC-V feature: "; + } else if ((EMachine == EM_386 || EMachine == EM_X86_64) && + Type == GNU_PROPERTY_X86_FEATURE_1_AND) { + OS << "x86 feature: "; + } else { + OS << format("", Type); + return str; + } + if (DataSize != 4) { OS << format("", DataSize); return str; @@ -5377,10 +5395,16 @@ static std::string getGNUProperty(uint32_t Type, uint32_t DataSize, OS << ""; return str; } - if (Type == GNU_PROPERTY_AARCH64_FEATURE_1_AND) { + + if (EMachine == EM_AARCH64) { DumpBit(GNU_PROPERTY_AARCH64_FEATURE_1_BTI, "BTI"); DumpBit(GNU_PROPERTY_AARCH64_FEATURE_1_PAC, "PAC"); DumpBit(GNU_PROPERTY_AARCH64_FEATURE_1_GCS, "GCS"); + } else if (EMachine == EM_RISCV) { + DumpBit(GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED, + "ZICFILP-unlabeled"); + DumpBit(GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS, "ZICFISS"); + DumpBit(GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_FUNC_SIG, "ZICFILP-func-sig"); } else { DumpBit(GNU_PROPERTY_X86_FEATURE_1_IBT, "IBT"); DumpBit(GNU_PROPERTY_X86_FEATURE_1_SHSTK, "SHSTK"); @@ -5441,7 +5465,8 @@ static std::string getGNUProperty(uint32_t Type, uint32_t DataSize, } template -static SmallVector getGNUPropertyList(ArrayRef Arr) { +static SmallVector +getGNUPropertyList(ArrayRef Arr, typename ELFT::Half EMachine) { using Elf_Word = typename ELFT::Word; SmallVector Properties; @@ -5459,8 +5484,8 @@ static SmallVector getGNUPropertyList(ArrayRef Arr) { Properties.push_back(str); break; } - Properties.push_back( - getGNUProperty(Type, DataSize, Arr.take_front(PaddedSize))); + Properties.push_back(getGNUProperty( + Type, DataSize, Arr.take_front(PaddedSize), EMachine)); Arr = Arr.drop_front(PaddedSize); } @@ -5512,7 +5537,7 @@ static StringRef getDescAsStringRef(ArrayRef Desc) { template static bool printGNUNote(raw_ostream &OS, uint32_t NoteType, - ArrayRef Desc) { + ArrayRef Desc, typename ELFT::Half EMachine) { // Return true if we were able to pretty-print the note, false otherwise. switch (NoteType) { default: @@ -5534,7 +5559,7 @@ static bool printGNUNote(raw_ostream &OS, uint32_t NoteType, break; case ELF::NT_GNU_PROPERTY_TYPE_0: OS << " Properties:"; - for (const std::string &Property : getGNUPropertyList(Desc)) + for (const std::string &Property : getGNUPropertyList(Desc, EMachine)) OS << " " << Property << "\n"; break; } @@ -6223,10 +6248,12 @@ template void GNUELFDumper::printNotes() { else OS << "Unknown note type: (" << format_hex(Type, 10) << ")\n"; + const typename ELFT::Half EMachine = this->Obj.getHeader().e_machine; + // Print the description, or fallback to printing raw bytes for unknown // owners/if we fail to pretty-print the contents. if (Name == "GNU") { - if (printGNUNote(OS, Type, Descriptor)) + if (printGNUNote(OS, Type, Descriptor, EMachine)) return Error::success(); } else if (Name == "FreeBSD") { if (std::optional N = @@ -7913,7 +7940,8 @@ template void LLVMELFDumper::printAddrsig() { template static bool printGNUNoteLLVMStyle(uint32_t NoteType, ArrayRef Desc, - ScopedPrinter &W) { + ScopedPrinter &W, + typename ELFT::Half EMachine) { // Return true if we were able to pretty-print the note, false otherwise. switch (NoteType) { default: @@ -7938,7 +7966,7 @@ static bool printGNUNoteLLVMStyle(uint32_t NoteType, ArrayRef Desc, break; case ELF::NT_GNU_PROPERTY_TYPE_0: ListScope D(W, "Property"); - for (const std::string &Property : getGNUPropertyList(Desc)) + for (const std::string &Property : getGNUPropertyList(Desc, EMachine)) W.printString(Property); break; } @@ -8057,10 +8085,11 @@ template void LLVMELFDumper::printNotes() { W.printString("Type", "Unknown (" + to_string(format_hex(Type, 10)) + ")"); + const typename ELFT::Half EMachine = this->Obj.getHeader().e_machine; // Print the description, or fallback to printing raw bytes for unknown // owners/if we fail to pretty-print the contents. if (Name == "GNU") { - if (printGNUNoteLLVMStyle(Type, Descriptor, W)) + if (printGNUNoteLLVMStyle(Type, Descriptor, W, EMachine)) return Error::success(); } else if (Name == "FreeBSD") { if (std::optional N =