[llvm-readobj] Dump GNU_PROPERTY_X86_FEATURE_2_{NEEDED,USED} notes in .note.gnu.property

Summary: And change the output ("X86 features" -> "x86 feature") a bit.

Reviewers: grimar, xiangzhangllvm, hjl.tools, rupprecht

Reviewed By: rupprecht

Subscribers: rupprecht, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D58112

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@353908 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/llvm/BinaryFormat/ELF.h b/include/llvm/BinaryFormat/ELF.h
index 7783922..8e3860c 100644
--- a/include/llvm/BinaryFormat/ELF.h
+++ b/include/llvm/BinaryFormat/ELF.h
@@ -1351,13 +1351,26 @@
 enum : unsigned {
   GNU_PROPERTY_STACK_SIZE = 1,
   GNU_PROPERTY_NO_COPY_ON_PROTECTED = 2,
-  GNU_PROPERTY_X86_FEATURE_1_AND = 0xc0000002
+  GNU_PROPERTY_X86_FEATURE_1_AND = 0xc0000002,
+  GNU_PROPERTY_X86_FEATURE_2_NEEDED = 0xc0008001,
+  GNU_PROPERTY_X86_FEATURE_2_USED = 0xc0010001,
 };
 
-// CET properties
-enum {
+// x86 processor feature bits.
+enum : unsigned {
   GNU_PROPERTY_X86_FEATURE_1_IBT = 1 << 0,
-  GNU_PROPERTY_X86_FEATURE_1_SHSTK = 1 << 1
+  GNU_PROPERTY_X86_FEATURE_1_SHSTK = 1 << 1,
+
+  GNU_PROPERTY_X86_FEATURE_2_X86 = 1 << 0,
+  GNU_PROPERTY_X86_FEATURE_2_X87 = 1 << 1,
+  GNU_PROPERTY_X86_FEATURE_2_MMX = 1 << 2,
+  GNU_PROPERTY_X86_FEATURE_2_XMM = 1 << 3,
+  GNU_PROPERTY_X86_FEATURE_2_YMM = 1 << 4,
+  GNU_PROPERTY_X86_FEATURE_2_ZMM = 1 << 5,
+  GNU_PROPERTY_X86_FEATURE_2_FXSR = 1 << 6,
+  GNU_PROPERTY_X86_FEATURE_2_XSAVE = 1 << 7,
+  GNU_PROPERTY_X86_FEATURE_2_XSAVEOPT = 1 << 8,
+  GNU_PROPERTY_X86_FEATURE_2_XSAVEC = 1 << 9,
 };
 
 // AMD specific notes. (Code Object V2)
diff --git a/test/tools/llvm-readobj/note-gnu-property.s b/test/tools/llvm-readobj/note-gnu-property.s
index f409818..1d35274 100644
--- a/test/tools/llvm-readobj/note-gnu-property.s
+++ b/test/tools/llvm-readobj/note-gnu-property.s
@@ -3,44 +3,48 @@
 // RUN: llvm-readobj -elf-output-style GNU --notes %t | FileCheck %s --check-prefix=GNU
 // RUN: llvm-readobj -elf-output-style LLVM --notes %t | FileCheck %s --check-prefix=LLVM
 
-// GNU:      Displaying notes found at file offset 0x00000040 with length 0x000000b8:
+// GNU:      Displaying notes found at file offset 0x00000040 with length 0x000000d8:
 // GNU-NEXT:   Owner                 Data size       Description
-// GNU-NEXT:   GNU                   0x000000a8      NT_GNU_PROPERTY_TYPE_0 (property note)
+// GNU-NEXT:   GNU                   0x000000c8      NT_GNU_PROPERTY_TYPE_0 (property note)
 // GNU-NEXT:     Properties:  stack size: 0x100
 // GNU-NEXT:     stack size: 0x100
 // GNU-NEXT:     no copy on protected
-// GNU-NEXT:     X86 features: SHSTK
-// GNU-NEXT:     X86 features: IBT, SHSTK
-// GNU-NEXT:     X86 features: none
+// GNU-NEXT:     x86 feature: SHSTK
+// GNU-NEXT:     x86 feature: IBT, SHSTK
+// GNU-NEXT:     x86 feature: <None>
+// GNU-NEXT:     x86 feature needed: x86, x87
+// GNU-NEXT:     x86 feature used: XSAVEOPT, XSAVEC
 // GNU-NEXT:     <application-specific type 0xfefefefe>
 // GNU-NEXT:     stack size: <corrupt length: 0x0>
 // GNU-NEXT:     stack size: <corrupt length: 0x4>
 // GNU-NEXT:     no copy on protected <corrupt length: 0x1>
-// GNU-NEXT:     X86 features: <corrupt length: 0x0>
-// GNU-NEXT:     X86 features: IBT, <unknown flags: 0xf000f000>
+// GNU-NEXT:     x86 feature: <corrupt length: 0x0>
+// GNU-NEXT:     x86 feature: IBT, <unknown flags: 0xf000f000>
 // GNU-NEXT:     <corrupt type (0x2) datasz: 0x1>
 
 // LLVM:      Notes [
 // LLVM-NEXT:   NoteSection {
 // LLVM-NEXT:     Offset: 0x40
-// LLVM-NEXT:     Size: 0xB8
+// LLVM-NEXT:     Size: 0xD8
 // LLVM-NEXT:     Note {
 // LLVM-NEXT:       Owner: GNU
-// LLVM-NEXT:       Data size: 0xA8
+// LLVM-NEXT:       Data size: 0xC8
 // LLVM-NEXT:       Type: NT_GNU_PROPERTY_TYPE_0 (property note)
 // LLVM-NEXT:       Property [
 // LLVM-NEXT:         stack size: 0x100
 // LLVM-NEXT:         stack size: 0x100
 // LLVM-NEXT:         no copy on protected
-// LLVM-NEXT:         X86 features: SHSTK
-// LLVM-NEXT:         X86 features: IBT, SHSTK
-// LLVM-NEXT:         X86 features: none
+// LLVM-NEXT:         x86 feature: SHSTK
+// LLVM-NEXT:         x86 feature: IBT, SHSTK
+// LLVM-NEXT:         x86 feature: <None>
+// LLVM-NEXT:         x86 feature needed: x86, x87
+// LLVM-NEXT:         x86 feature used: XSAVEOPT, XSAVEC
 // LLVM-NEXT:         <application-specific type 0xfefefefe>
 // LLVM-NEXT:         stack size: <corrupt length: 0x0>
 // LLVM-NEXT:         stack size: <corrupt length: 0x4>
 // LLVM-NEXT:         no copy on protected <corrupt length: 0x1>
-// LLVM-NEXT:         X86 features: <corrupt length: 0x0>
-// LLVM-NEXT:         X86 features: IBT, <unknown flags: 0xf000f000>
+// LLVM-NEXT:         x86 feature: <corrupt length: 0x0>
+// LLVM-NEXT:         x86 feature: IBT, <unknown flags: 0xf000f000>
 // LLVM-NEXT:         <corrupt type (0x2) datasz: 0x1>
 // LLVM-NEXT:       ]
 // LLVM-NEXT:     }
@@ -86,6 +90,16 @@
   .long 4           /* Data size */
   .long 0           /* Empty flags, not an error */
   .p2align 3        /* Align to 8 byte for 64 bit */
+
+  .long 0xc0008001         /* Type: GNU_PROPERTY_X86_FEATURE_2_NEEDED */
+  .long 4                  /* Data size */
+  .long 0x00000003         /* X86 X87 */
+  .p2align 3               /* Align to 8 byte for 64 bit */
+
+  .long 0xc0010001         /* Type: GNU_PROPERTY_X86_FEATURE_2_USED */
+  .long 4                  /* Data size */
+  .long 0x00000300         /* XSAVEOPT XSAVEC */
+  .p2align 3               /* Align to 8 byte for 64 bit */
   
   /* All notes below are broken. Test we are able to report them. */
   
@@ -121,7 +135,7 @@
   .long 4                  /* Data size */
   .long 0xf000f001         /* GNU_PROPERTY_X86_FEATURE_1_IBT and bad bits */
   .p2align 3               /* Align to 8 byte for 64 bit */
-  
+
   /* GNU_PROPERTY_NO_COPY_ON_PROTECTED with pr_datasz and without data */
   .long 2           /* Type: GNU_PROPERTY_NO_COPY_ON_PROTECTED */
   .long 1           /* Data size (corrupted) */
diff --git a/tools/llvm-readobj/ELFDumper.cpp b/tools/llvm-readobj/ELFDumper.cpp
index deb8fe0..4f5fa2b 100644
--- a/tools/llvm-readobj/ELFDumper.cpp
+++ b/tools/llvm-readobj/ELFDumper.cpp
@@ -3650,6 +3650,16 @@
                                   ArrayRef<uint8_t> Data) {
   std::string str;
   raw_string_ostream OS(str);
+  uint32_t pr_data;
+  auto DumpBit = [&](uint32_t Flag, StringRef Name) {
+    if (pr_data & Flag) {
+      pr_data &= ~Flag;
+      OS << Name;
+      if (pr_data)
+        OS << ", ";
+    }
+  };
+
   switch (Type) {
   default:
     OS << format("<application-specific type 0x%x>", Type);
@@ -3669,31 +3679,46 @@
       OS << format(" <corrupt length: 0x%x>", DataSize);
     return OS.str();
   case GNU_PROPERTY_X86_FEATURE_1_AND:
-    OS << "X86 features: ";
+    OS << "x86 feature: ";
     if (DataSize != 4) {
       OS << format("<corrupt length: 0x%x>", DataSize);
       return OS.str();
     }
-    uint32_t CFProtection  =
-        support::endian::read32<ELFT::TargetEndianness>(Data.data());
-    if (CFProtection == 0) {
-      OS << "none";
+    pr_data = support::endian::read32<ELFT::TargetEndianness>(Data.data());
+    if (pr_data == 0) {
+      OS << "<None>";
       return OS.str();
     }
-    if (CFProtection & GNU_PROPERTY_X86_FEATURE_1_IBT) {
-      OS << "IBT";
-      CFProtection &= ~GNU_PROPERTY_X86_FEATURE_1_IBT;
-      if (CFProtection)
-        OS << ", ";
+    DumpBit(GNU_PROPERTY_X86_FEATURE_1_IBT, "IBT");
+    DumpBit(GNU_PROPERTY_X86_FEATURE_1_SHSTK, "SHSTK");
+    if (pr_data)
+      OS << format("<unknown flags: 0x%x>", pr_data);
+    return OS.str();
+  case GNU_PROPERTY_X86_FEATURE_2_NEEDED:
+  case GNU_PROPERTY_X86_FEATURE_2_USED:
+    OS << "x86 feature "
+       << (Type == GNU_PROPERTY_X86_FEATURE_2_NEEDED ? "needed: " : "used: ");
+    if (DataSize != 4) {
+      OS << format("<corrupt length: 0x%x>", DataSize);
+      return OS.str();
     }
-    if (CFProtection & GNU_PROPERTY_X86_FEATURE_1_SHSTK) {
-      OS << "SHSTK";
-      CFProtection &= ~GNU_PROPERTY_X86_FEATURE_1_SHSTK;
-      if (CFProtection)
-        OS << ", ";
+    pr_data = support::endian::read32<ELFT::TargetEndianness>(Data.data());
+    if (pr_data == 0) {
+      OS << "<None>";
+      return OS.str();
     }
-    if (CFProtection)
-      OS << format("<unknown flags: 0x%x>", CFProtection);
+    DumpBit(GNU_PROPERTY_X86_FEATURE_2_X86, "x86");
+    DumpBit(GNU_PROPERTY_X86_FEATURE_2_X87, "x87");
+    DumpBit(GNU_PROPERTY_X86_FEATURE_2_MMX, "MMX");
+    DumpBit(GNU_PROPERTY_X86_FEATURE_2_XMM, "XMM");
+    DumpBit(GNU_PROPERTY_X86_FEATURE_2_YMM, "YMM");
+    DumpBit(GNU_PROPERTY_X86_FEATURE_2_ZMM, "ZMM");
+    DumpBit(GNU_PROPERTY_X86_FEATURE_2_FXSR, "FXSR");
+    DumpBit(GNU_PROPERTY_X86_FEATURE_2_XSAVE, "XSAVE");
+    DumpBit(GNU_PROPERTY_X86_FEATURE_2_XSAVEOPT, "XSAVEOPT");
+    DumpBit(GNU_PROPERTY_X86_FEATURE_2_XSAVEC, "XSAVEC");
+    if (pr_data)
+      OS << format("<unknown flags: 0x%x>", pr_data);
     return OS.str();
   }
 }