Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PAC][llvm-readobj][AArch64][ELF] Support GNU_PROPERTY_AARCH64_FEATURE_PAUTH #85231

Merged
merged 10 commits into from
Apr 2, 2024

Conversation

kovdan01
Copy link
Contributor

@kovdan01 kovdan01 commented Mar 14, 2024

This adds support for GNU_PROPERTY_AARCH64_FEATURE_PAUTH feature (as defined in ARM-software/abi-aa#240) handling in llvm-readobj and llvm-readelf. The following constants for supported platforms are also introduced:

  • AARCH64_PAUTH_PLATFORM_INVALID = 0x0
  • AARCH64_PAUTH_PLATFORM_BAREMETAL = 0x1
  • AARCH64_PAUTH_PLATFORM_LLVM_LINUX = 0x10000002

For the llvm_linux platform, output of the tools contains descriptions of PAuth features which are enabled/disabled depending on the version value. Version value bits correspond to the following LangOptions defined in #85232:

  • bit 0: PointerAuthIntrinsics;
  • bit 1: PointerAuthCalls;
  • bit 2: PointerAuthReturns;
  • bit 3: PointerAuthAuthTraps;
  • bit 4: PointerAuthVTPtrAddressDiscrimination;
  • bit 5: PointerAuthVTPtrTypeDiscrimination;
  • bit 6: PointerAuthInitFini.

Support for .note.AARCH64-PAUTH-ABI-tag is dropped since it's deleted
from the spec in ARM-software/abi-aa#250.

@kovdan01 kovdan01 requested a review from asl March 14, 2024 14:58
@kovdan01 kovdan01 force-pushed the pauth-gnuprop-readobj branch 2 times, most recently from ea59dbb to 54854fc Compare March 19, 2024 14:18
@kovdan01 kovdan01 changed the title [llvm-readobj][AArch64][ELF][PAC] Support GNU_PROPERTY_AARCH64_FEATURE_PAUTH [PAC][llvm-readobj][AArch64][ELF] Support GNU_PROPERTY_AARCH64_FEATURE_PAUTH Mar 19, 2024
…RE_PAUTH`

This adds support for `GNU_PROPERTY_AARCH64_FEATURE_PAUTH` feature
handling in llvm-readobj and llvm-readelf. The following constants for
supported platforms are also introduced:

- `AARCH64_PAUTH_PLATFORM_INVALID = 0x0`
- `AARCH64_PAUTH_PLATFORM_BAREMETAL = 0x1`
- `AARCH64_PAUTH_PLATFORM_LLVM_LINUX = 0x10000002`

For the llvm_linux platform, output of the tools contains descriptions of
PAuth features which are enabled/disabled depending on the version value.
Version value bits correspond to the following `LangOptions`:

- bit 0: `PointerAuthIntrinsics`;
- bit 1: `PointerAuthCalls`;
- bit 2: `PointerAuthReturns`;
- bit 3: `PointerAuthAuthTraps`;
- bit 4: `PointerAuthVTPtrAddressDiscrimination`;
- bit 5: `PointerAuthVTPtrTypeDiscrimination`;
- bit 6: `PointerAuthInitFini`.

Support for `.note.AARCH64-PAUTH-ABI-tag` is dropped since it's deleted
from the spec in ARM-software/abi-aa#250.
@llvmbot
Copy link
Member

llvmbot commented Mar 19, 2024

@llvm/pr-subscribers-llvm-binary-utilities

Author: Daniil Kovalev (kovdan01)

Changes

This adds support for GNU_PROPERTY_AARCH64_FEATURE_PAUTH feature (as defined in ARM-software/abi-aa#240) handling in llvm-readobj and llvm-readelf. The following constants for supported platforms are also introduced:

  • AARCH64_PAUTH_PLATFORM_INVALID = 0x0
  • AARCH64_PAUTH_PLATFORM_BAREMETAL = 0x1
  • AARCH64_PAUTH_PLATFORM_LLVM_LINUX = 0x10000002

For the llvm_linux platform, output of the tools contains descriptions of PAuth features which are enabled/disabled depending on the version value. Version value bits correspond to the following LangOptions defined in #85232:

  • bit 0: PointerAuthIntrinsics;
  • bit 1: PointerAuthCalls;
  • bit 2: PointerAuthReturns;
  • bit 3: PointerAuthAuthTraps;
  • bit 4: PointerAuthVTPtrAddressDiscrimination;
  • bit 5: PointerAuthVTPtrTypeDiscrimination;
  • bit 6: PointerAuthInitFini.

Support for .note.AARCH64-PAUTH-ABI-tag is dropped since it's deleted
from the spec in ARM-software/abi-aa#250.


Patch is 20.62 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/85231.diff

4 Files Affected:

  • (modified) llvm/include/llvm/BinaryFormat/ELF.h (+21-5)
  • (modified) llvm/test/tools/llvm-readobj/ELF/AArch64/aarch64-feature-pauth.s (+186-96)
  • (modified) llvm/test/tools/llvm-readobj/ELF/AArch64/aarch64-note-gnu-property.s (+2)
  • (modified) llvm/tools/llvm-readobj/ELFDumper.cpp (+80-60)
diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h
index bace3a92677a82..ca01be089c47f2 100644
--- a/llvm/include/llvm/BinaryFormat/ELF.h
+++ b/llvm/include/llvm/BinaryFormat/ELF.h
@@ -1710,11 +1710,6 @@ enum {
   NT_ANDROID_TYPE_MEMTAG = 4,
 };
 
-// ARM note types.
-enum {
-  NT_ARM_TYPE_PAUTH_ABI_TAG = 1,
-};
-
 // Memory tagging values used in NT_ANDROID_TYPE_MEMTAG notes.
 enum {
   // Enumeration to determine the tagging mode. In Android-land, 'SYNC' means
@@ -1738,6 +1733,7 @@ enum : unsigned {
   GNU_PROPERTY_STACK_SIZE = 1,
   GNU_PROPERTY_NO_COPY_ON_PROTECTED = 2,
   GNU_PROPERTY_AARCH64_FEATURE_1_AND = 0xc0000000,
+  GNU_PROPERTY_AARCH64_FEATURE_PAUTH = 0xc0000001,
   GNU_PROPERTY_X86_FEATURE_1_AND = 0xc0000002,
 
   GNU_PROPERTY_X86_UINT32_OR_LO = 0xc0008000,
@@ -1756,6 +1752,26 @@ enum : unsigned {
   GNU_PROPERTY_AARCH64_FEATURE_1_GCS = 1 << 2,
 };
 
+// aarch64 PAuth platforms.
+enum : unsigned {
+  AARCH64_PAUTH_PLATFORM_INVALID = 0x0,
+  AARCH64_PAUTH_PLATFORM_BAREMETAL = 0x1,
+  AARCH64_PAUTH_PLATFORM_LLVM_LINUX = 0x10000002,
+};
+
+// Bit positions of version flags for AARCH64_PAUTH_PLATFORM_LLVM_LINUX.
+enum : unsigned {
+  AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_INTRINSICS = 0,
+  AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_CALLS = 1,
+  AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_RETURNS = 2,
+  AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_AUTHTRAPS = 3,
+  AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_VPTRADDRDISCR = 4,
+  AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_VPTRTYPEDISCR = 5,
+  AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_INITFINI = 6,
+  AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_LAST =
+      AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_INITFINI,
+};
+
 // x86 processor feature bits.
 enum : unsigned {
   GNU_PROPERTY_X86_FEATURE_1_IBT = 1 << 0,
diff --git a/llvm/test/tools/llvm-readobj/ELF/AArch64/aarch64-feature-pauth.s b/llvm/test/tools/llvm-readobj/ELF/AArch64/aarch64-feature-pauth.s
index f28d92eae85754..3f171acde8eb92 100644
--- a/llvm/test/tools/llvm-readobj/ELF/AArch64/aarch64-feature-pauth.s
+++ b/llvm/test/tools/llvm-readobj/ELF/AArch64/aarch64-feature-pauth.s
@@ -1,98 +1,188 @@
 # RUN: rm -rf %t && split-file %s %t && cd %t
 
-# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu abi-tag.s       -o tag.o
-# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu abi-tag-short.s -o tag-short.o
-# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu abi-tag-long.s  -o tag-long.o
-
-# RUN: llvm-readelf --notes tag.o       | FileCheck --check-prefix NORMAL %s
-# RUN: llvm-readelf --notes tag-short.o | FileCheck --check-prefix SHORT  %s
-# RUN: llvm-readelf --notes tag-long.o  | FileCheck --check-prefix LONG   %s
-
-# NORMAL: AArch64 PAuth ABI tag: platform 0x2a, version 0x1
-# SHORT:  AArch64 PAuth ABI tag: <corrupted size: expected at least 16, got 12>
-# LONG:   AArch64 PAuth ABI tag: platform 0x2a, version 0x1, additional info 0xEFCDAB8967452301
-
-# RUN: llvm-readobj --notes tag.o       | FileCheck --check-prefix LLVM-NORMAL %s
-# RUN: llvm-readobj --notes tag-short.o | FileCheck --check-prefix LLVM-SHORT %s
-# RUN: llvm-readobj --notes tag-long.o  | FileCheck --check-prefix LLVM-LONG %s
-
-# LLVM-SHORT:      Notes [
-# LLVM-SHORT-NEXT:   NoteSection {
-# LLVM-SHORT-NEXT:     Name: .note.AARCH64-PAUTH-ABI-tag
-# LLVM-SHORT-NEXT:     Offset: 0x40
-# LLVM-SHORT-NEXT:     Size: 0x1C
-# LLVM-SHORT-NEXT:     Note {
-# LLVM-SHORT-NEXT:       Owner: ARM
-# LLVM-SHORT-NEXT:       Data size: 0xC
-# LLVM-SHORT-NEXT:       Type: NT_ARM_TYPE_PAUTH_ABI_TAG
-# LLVM-SHORT-NEXT:       Description data (
-# LLVM-SHORT-NEXT:         0000: 2A000000 00000000 01000000
-# LLVM-SHORT-NEXT:       )
-# LLVM-SHORT-NEXT:     }
-# LLVM-SHORT-NEXT:   }
-# LLVM-SHORT-NEXT: ]
-
-# LLVM-NORMAL:      Notes [
-# LLVM-NORMAL-NEXT:   NoteSection {
-# LLVM-NORMAL-NEXT:     Name: .note.AARCH64-PAUTH-ABI-tag
-# LLVM-NORMAL-NEXT:     Offset: 0x40
-# LLVM-NORMAL-NEXT:     Size: 0x20
-# LLVM-NORMAL-NEXT:     Note {
-# LLVM-NORMAL-NEXT:       Owner: ARM
-# LLVM-NORMAL-NEXT:       Data size: 0x10
-# LLVM-NORMAL-NEXT:       Type: NT_ARM_TYPE_PAUTH_ABI_TAG
-# LLVM-NORMAL-NEXT:       Platform: 42
-# LLVM-NORMAL-NEXT:       Version: 1
-# LLVM-NORMAL-NEXT:     }
-# LLVM-NORMAL-NEXT:   }
-# LLVM-NORMAL-NEXT: ]
-
-# LLVM-LONG:      Notes [
-# LLVM-LONG-NEXT:   NoteSection {
-# LLVM-LONG-NEXT:     Name: .note.AARCH64-PAUTH-ABI-tag
-# LLVM-LONG-NEXT:     Offset: 0x40
-# LLVM-LONG-NEXT:     Size: 0x28
-# LLVM-LONG-NEXT:     Note {
-# LLVM-LONG-NEXT:       Owner: ARM
-# LLVM-LONG-NEXT:       Data size: 0x18
-# LLVM-LONG-NEXT:       Type: NT_ARM_TYPE_PAUTH_ABI_TAG
-# LLVM-LONG-NEXT:       Platform: 42
-# LLVM-LONG-NEXT:       Version: 1
-# LLVM-LONG-NEXT:       Additional info: EFCDAB8967452301
-# LLVM-LONG-NEXT:     }
-# LLVM-LONG-NEXT:   }
-# LLVM-LONG-NEXT: ]
-
-#--- abi-tag.s
-
-.section ".note.AARCH64-PAUTH-ABI-tag", "a"
-.long 4
-.long 16
-.long 1
-.asciz "ARM"
-
-.quad 42         // platform
-.quad 1          // version
-
-#--- abi-tag-short.s
-
-.section ".note.AARCH64-PAUTH-ABI-tag", "a"
-.long 4
-.long 12
-.long 1
-.asciz "ARM"
-
-.quad 42
-.word 1
-
-#--- abi-tag-long.s
-
-.section ".note.AARCH64-PAUTH-ABI-tag", "a"
-.long 4
-.long 24
-.long 1
-.asciz "ARM"
-
-.quad 42         // platform
-.quad 1          // version
-.quad 0x0123456789ABCDEF // extra data
+#--- gnu-42-1.s
+
+.section ".note.gnu.property", "a"
+  .long 4           /* Name length is always 4 ("GNU") */
+  .long end - begin /* Data length */
+  .long 5           /* Type: NT_GNU_PROPERTY_TYPE_0 */
+  .asciz "GNU"      /* Name */
+  .p2align 3
+begin:
+  /* PAuth ABI property note */
+  .long 0xc0000001  /* Type: GNU_PROPERTY_AARCH64_FEATURE_PAUTH */
+  .long 16          /* Data size */
+  .quad 42          /* PAuth ABI platform */
+  .quad 1           /* PAuth ABI version */
+  .p2align 3        /* Align to 8 byte for 64 bit */
+end:
+
+# RUN: llvm-mc -filetype=obj -triple aarch64-linux-gnu gnu-42-1.s -o gnu-42-1.o
+# RUN: llvm-readelf --notes gnu-42-1.o | \
+# RUN:   FileCheck --check-prefix=ELF-GNU -DPLATFORM="0x2a (unknown)" -DVERSION=0x1 %s
+# RUN: llvm-readobj --notes gnu-42-1.o | \
+# RUN:   FileCheck --check-prefix=OBJ-GNU -DPLATFORM="0x2a (unknown)" -DVERSION=0x1 %s
+
+# ELF-GNU: Displaying notes found in: .note.gnu.property
+# ELF-GNU-NEXT:   Owner                 Data size	Description
+# ELF-GNU-NEXT:   GNU                   0x00000018	NT_GNU_PROPERTY_TYPE_0 (property note)
+# ELF-GNU-NEXT:   AArch64 PAuth ABI core info: platform [[PLATFORM]], version [[VERSION]]
+
+# OBJ-GNU:      Notes [
+# OBJ-GNU-NEXT:   NoteSection {
+# OBJ-GNU-NEXT:     Name: .note.gnu.property
+# OBJ-GNU-NEXT:     Offset: 0x40
+# OBJ-GNU-NEXT:     Size: 0x28
+# OBJ-GNU-NEXT:     Note {
+# OBJ-GNU-NEXT:       Owner: GNU
+# OBJ-GNU-NEXT:       Data size: 0x18
+# OBJ-GNU-NEXT:       Type: NT_GNU_PROPERTY_TYPE_0 (property note)
+# OBJ-GNU-NEXT:       Property [
+# OBJ-GNU-NEXT:         AArch64 PAuth ABI core info: platform [[PLATFORM]], version [[VERSION]]
+# OBJ-GNU-NEXT:       ]
+# OBJ-GNU-NEXT:     }
+# OBJ-GNU-NEXT:   }
+# OBJ-GNU-NEXT: ]
+
+#--- gnu-0-0.s
+
+.section ".note.gnu.property", "a"
+  .long 4           /* Name length is always 4 ("GNU") */
+  .long end - begin /* Data length */
+  .long 5           /* Type: NT_GNU_PROPERTY_TYPE_0 */
+  .asciz "GNU"      /* Name */
+  .p2align 3
+begin:
+  /* PAuth ABI property note */
+  .long 0xc0000001  /* Type: GNU_PROPERTY_AARCH64_FEATURE_PAUTH */
+  .long 16          /* Data size */
+  .quad 0           /* PAuth ABI platform */
+  .quad 0           /* PAuth ABI version */
+  .p2align 3        /* Align to 8 byte for 64 bit */
+end:
+
+# RUN: llvm-mc -filetype=obj -triple aarch64-linux-gnu gnu-0-0.s -o gnu-0-0.o
+# RUN: llvm-readelf --notes gnu-0-0.o | \
+# RUN:   FileCheck --check-prefix=ELF-GNU -DPLATFORM="0x0 (invalid)" -DVERSION=0x0 %s
+# RUN: llvm-readobj --notes gnu-0-0.o | \
+# RUN:   FileCheck --check-prefix=OBJ-GNU -DPLATFORM="0x0 (invalid)" -DVERSION=0x0 %s
+
+#--- gnu-1-0.s
+
+.section ".note.gnu.property", "a"
+  .long 4           /* Name length is always 4 ("GNU") */
+  .long end - begin /* Data length */
+  .long 5           /* Type: NT_GNU_PROPERTY_TYPE_0 */
+  .asciz "GNU"      /* Name */
+  .p2align 3
+begin:
+  /* PAuth ABI property note */
+  .long 0xc0000001  /* Type: GNU_PROPERTY_AARCH64_FEATURE_PAUTH */
+  .long 16          /* Data size */
+  .quad 1           /* PAuth ABI platform */
+  .quad 0           /* PAuth ABI version */
+  .p2align 3        /* Align to 8 byte for 64 bit */
+end:
+
+# RUN: llvm-mc -filetype=obj -triple aarch64-linux-gnu gnu-1-0.s -o gnu-1-0.o
+# RUN: llvm-readelf --notes gnu-1-0.o | \
+# RUN:   FileCheck --check-prefix=ELF-GNU -DPLATFORM="0x1 (baremetal)" -DVERSION=0x0 %s
+# RUN: llvm-readobj --notes gnu-1-0.o | \
+# RUN:   FileCheck --check-prefix=OBJ-GNU -DPLATFORM="0x1 (baremetal)" -DVERSION=0x0 %s
+
+#--- gnu-0x10000002-85.s
+
+.section ".note.gnu.property", "a"
+  .long 4           /* Name length is always 4 ("GNU") */
+  .long end - begin /* Data length */
+  .long 5           /* Type: NT_GNU_PROPERTY_TYPE_0 */
+  .asciz "GNU"      /* Name */
+  .p2align 3
+begin:
+  /* PAuth ABI property note */
+  .long 0xc0000001  /* Type: GNU_PROPERTY_AARCH64_FEATURE_PAUTH */
+  .long 16          /* Data size */
+  .quad 0x10000002  /* PAuth ABI platform */
+  .quad 85          /* PAuth ABI version */
+  .p2align 3        /* Align to 8 byte for 64 bit */
+end:
+
+# RUN: llvm-mc -filetype=obj -triple aarch64-linux-gnu gnu-0x10000002-85.s -o gnu-0x10000002-85.o
+# RUN: llvm-readelf --notes gnu-0x10000002-85.o | \
+# RUN:   FileCheck --check-prefix=ELF-GNU -DPLATFORM="0x10000002 (llvm_linux)" \
+# RUN:   -DVERSION="0x55 (PointerAuthIntrinsics, !PointerAuthCalls, PointerAuthReturns, !PointerAuthAuthTraps, PointerAuthVTPtrAddressDiscrimination, !PointerAuthVTPtrTypeDiscrimination, PointerAuthInitFini)" %s
+# RUN: llvm-readobj --notes gnu-0x10000002-85.o | \
+# RUN:   FileCheck --check-prefix=OBJ-GNU -DPLATFORM="0x10000002 (llvm_linux)" \
+# RUN:   -DVERSION="0x55 (PointerAuthIntrinsics, !PointerAuthCalls, PointerAuthReturns, !PointerAuthAuthTraps, PointerAuthVTPtrAddressDiscrimination, !PointerAuthVTPtrTypeDiscrimination, PointerAuthInitFini)" %s
+
+#--- gnu-short.s
+
+.section ".note.gnu.property", "a"
+  .long 4           /* Name length is always 4 ("GNU") */
+  .long end - begin /* Data length */
+  .long 5           /* Type: NT_GNU_PROPERTY_TYPE_0 */
+  .asciz "GNU"      /* Name */
+  .p2align 3
+begin:
+  /* PAuth ABI property note */
+  .long 0xc0000001  /* Type: GNU_PROPERTY_AARCH64_FEATURE_PAUTH */
+  .long 12          /* Data size */
+  .quad 42          /* PAuth ABI platform */
+  .word 1           /* PAuth ABI version */
+  .p2align 3        /* Align to 8 byte for 64 bit */
+end:
+
+# RUN: llvm-mc -filetype=obj -triple aarch64-linux-gnu gnu-short.s -o gnu-short.o
+# RUN: llvm-readelf --notes gnu-short.o | \
+# RUN:   FileCheck --check-prefix=ELF-GNU-ERR -DSIZE=28 -DDATASIZE=18 \
+# RUN:   -DERR="<corrupted size: expected 16, got 12>" %s
+# RUN: llvm-readobj --notes gnu-short.o | \
+# RUN:   FileCheck --check-prefix=OBJ-GNU-ERR -DSIZE=28 -DDATASIZE=18 \
+# RUN:   -DERR="<corrupted size: expected 16, got 12>" %s
+
+# ELF-GNU-ERR: Displaying notes found in: .note.gnu.property
+# ELF-GNU-ERR-NEXT:   Owner                 Data size	Description
+# ELF-GNU-ERR-NEXT:   GNU                   0x000000[[DATASIZE]]	NT_GNU_PROPERTY_TYPE_0 (property note)
+# ELF-GNU-ERR-NEXT:   AArch64 PAuth ABI core info: [[ERR]]
+
+# OBJ-GNU-ERR:      Notes [
+# OBJ-GNU-ERR-NEXT:   NoteSection {
+# OBJ-GNU-ERR-NEXT:     Name: .note.gnu.property
+# OBJ-GNU-ERR-NEXT:     Offset: 0x40
+# OBJ-GNU-ERR-NEXT:     Size: 0x[[SIZE]]
+# OBJ-GNU-ERR-NEXT:     Note {
+# OBJ-GNU-ERR-NEXT:       Owner: GNU
+# OBJ-GNU-ERR-NEXT:       Data size: 0x[[DATASIZE]]
+# OBJ-GNU-ERR-NEXT:       Type: NT_GNU_PROPERTY_TYPE_0 (property note)
+# OBJ-GNU-ERR-NEXT:       Property [
+# OBJ-GNU-ERR-NEXT:         AArch64 PAuth ABI core info: [[ERR]]
+# OBJ-GNU-ERR-NEXT:       ]
+# OBJ-GNU-ERR-NEXT:     }
+# OBJ-GNU-ERR-NEXT:   }
+# OBJ-GNU-ERR-NEXT: ]
+
+#--- gnu-long.s
+
+.section ".note.gnu.property", "a"
+  .long 4           /* Name length is always 4 ("GNU") */
+  .long end - begin /* Data length */
+  .long 5           /* Type: NT_GNU_PROPERTY_TYPE_0 */
+  .asciz "GNU"      /* Name */
+  .p2align 3
+begin:
+  /* PAuth ABI property note */
+  .long 0xc0000001  /* Type: GNU_PROPERTY_AARCH64_FEATURE_PAUTH */
+  .long 24          /* Data size */
+  .quad 42          /* PAuth ABI platform */
+  .quad 1           /* PAuth ABI version */
+  .quad 0x0123456789ABCDEF
+  .p2align 3        /* Align to 8 byte for 64 bit */
+end:
+
+# RUN: llvm-mc -filetype=obj -triple aarch64-linux-gnu gnu-long.s -o gnu-long.o
+# RUN: llvm-readelf --notes gnu-long.o | \
+# RUN:   FileCheck --check-prefix=ELF-GNU-ERR -DSIZE=30 -DDATASIZE=20 \
+# RUN:   -DERR="<corrupted size: expected 16, got 24>" %s
+# RUN: llvm-readobj --notes gnu-long.o | \
+# RUN:   FileCheck --check-prefix=OBJ-GNU-ERR -DSIZE=30 -DDATASIZE=20 \
+# RUN:   -DERR="<corrupted size: expected 16, got 24>" %s
diff --git a/llvm/test/tools/llvm-readobj/ELF/AArch64/aarch64-note-gnu-property.s b/llvm/test/tools/llvm-readobj/ELF/AArch64/aarch64-note-gnu-property.s
index 377e6f93448ca7..b517f0b3815547 100644
--- a/llvm/test/tools/llvm-readobj/ELF/AArch64/aarch64-note-gnu-property.s
+++ b/llvm/test/tools/llvm-readobj/ELF/AArch64/aarch64-note-gnu-property.s
@@ -1,3 +1,5 @@
+// See tests for GNU_PROPERTY_AARCH64_FEATURE_PAUTH in aarch64-feature-pauth.s
+
 // RUN: llvm-mc -filetype=obj -triple aarch64-linux-gnu %s -o %t
 // RUN: llvm-readelf --notes %t | FileCheck %s --check-prefix=GNU
 // RUN: llvm-readobj --notes %t | FileCheck %s --check-prefix=LLVM
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index e78732353cc877..ff620e944e1b56 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -5098,6 +5098,83 @@ template <class ELFT> void GNUELFDumper<ELFT>::printAddrsig() {
   }
 }
 
+template <class ELFT>
+static bool printAArch64PAuthABICoreInfo(raw_ostream &OS, uint32_t DataSize,
+                                         ArrayRef<uint8_t> Desc) {
+  OS << "    AArch64 PAuth ABI core info: ";
+  // DataSize - size without padding, Desc.size() - size with padding
+  if (DataSize != 16) {
+    OS << format("<corrupted size: expected 16, got %d>", DataSize);
+    return false;
+  }
+
+  uint64_t Platform =
+      support::endian::read64<ELFT::TargetEndianness>(Desc.data() + 0);
+  uint64_t Version =
+      support::endian::read64<ELFT::TargetEndianness>(Desc.data() + 8);
+
+  std::string PlatformDesc = [Platform]() {
+    switch (Platform) {
+    case AARCH64_PAUTH_PLATFORM_INVALID:
+      return "invalid";
+    case AARCH64_PAUTH_PLATFORM_BAREMETAL:
+      return "baremetal";
+    case AARCH64_PAUTH_PLATFORM_LLVM_LINUX:
+      return "llvm_linux";
+    default:
+      return "unknown";
+    }
+  }();
+
+  std::string VersionDesc = [Platform, Version]() -> std::string {
+    if (Platform != AARCH64_PAUTH_PLATFORM_LLVM_LINUX)
+      return "";
+    if (Version >= (1 << (AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_LAST + 1)))
+      return "unknown";
+    return std::string("") +
+           ((Version &
+             (1 << AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_INTRINSICS))
+                ? ""
+                : "!") +
+           "PointerAuthIntrinsics, " +
+           ((Version & (1 << AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_CALLS))
+                ? ""
+                : "!") +
+           "PointerAuthCalls, " +
+           ((Version & (1 << AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_RETURNS))
+                ? ""
+                : "!") +
+           "PointerAuthReturns, " +
+           ((Version &
+             (1 << AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_AUTHTRAPS))
+                ? ""
+                : "!") +
+           "PointerAuthAuthTraps, " +
+           ((Version &
+             (1 << AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_VPTRADDRDISCR))
+                ? ""
+                : "!") +
+           "PointerAuthVTPtrAddressDiscrimination, " +
+           ((Version &
+             (1 << AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_VPTRTYPEDISCR))
+                ? ""
+                : "!") +
+           "PointerAuthVTPtrTypeDiscrimination, " +
+           ((Version &
+             (1 << AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_INITFINI))
+                ? ""
+                : "!") +
+           "PointerAuthInitFini";
+  }();
+
+  OS << format("platform 0x%x (%s), version 0x%x", Platform,
+               PlatformDesc.c_str(), Version);
+  if (!VersionDesc.empty())
+    OS << format(" (%s)", VersionDesc.c_str());
+
+  return true;
+}
+
 template <typename ELFT>
 static std::string getGNUProperty(uint32_t Type, uint32_t DataSize,
                                   ArrayRef<uint8_t> Data) {
@@ -5155,6 +5232,9 @@ static std::string getGNUProperty(uint32_t Type, uint32_t DataSize,
     if (PrData)
       OS << format("<unknown flags: 0x%x>", PrData);
     return OS.str();
+  case GNU_PROPERTY_AARCH64_FEATURE_PAUTH:
+    printAArch64PAuthABICoreInfo<ELFT>(OS, DataSize, Data);
+    return OS.str();
   case GNU_PROPERTY_X86_FEATURE_2_NEEDED:
   case GNU_PROPERTY_X86_FEATURE_2_USED:
     OS << "x86 feature "
@@ -5356,31 +5436,6 @@ static bool printAndroidNote(raw_ostream &OS, uint32_t NoteType,
   return true;
 }
 
-template <class ELFT>
-static bool printAArch64Note(raw_ostream &OS, uint32_t NoteType,
-                             ArrayRef<uint8_t> Desc) {
-  if (NoteType != NT_ARM_TYPE_PAUTH_ABI_TAG)
-    return false;
-
-  OS << "    AArch64 PAuth ABI tag: ";
-  if (Desc.size() < 16) {
-    OS << format("<corrupted size: expected at least 16, got %d>", Desc.size());
-    return false;
-  }
-
-  uint64_t Platform =
-      support::endian::read64<ELFT::TargetEndianness>(Desc.data() + 0);
-  uint64_t Version =
-      support::endian::read64<ELFT::TargetEndianness>(Desc.data() + 8);
-  OS << format("platform 0x%" PRIx64 ", version 0x%" PRIx64, Platform, Version);
-
-  if (Desc.size() > 16)
-    OS << ", additional info 0x"
-       << toHex(ArrayRef<uint8_t>(Desc.data() + 16, Desc.size() - 16));
-
-  return true;
-}
-
 template <class ELFT>
 void GNUELFDumper<ELFT>::printMemtag(
     const ArrayRef<std::pair<std::string, std::string>> DynamicEntries,
@@ -5780,10 +5835,6 @@ const NoteType AndroidNoteTypes[] = {
      "NT_ANDROID_TYPE_MEMTAG (Android memory tagging information)"},
 };
 
-const NoteType ARMNoteTypes[] = {
-    {ELF::NT_ARM_TYPE_PAUTH_ABI_TAG, "NT_ARM_TYPE_PAUTH_ABI_TAG"},
-};
-
 const NoteType CoreNoteTypes[] = {
     {ELF::NT_PRSTATUS, "NT_PRSTATUS (prstatus structure)"},
     {ELF::NT_FPREGSET, "NT_FPREGSET (floating point registers)"},
@@ -5902,8 +5953,6 @@ StringRef getNoteTypeName(const typename ELFT::Note &Note, unsigned ELFType) {
     return FindNote(LLVMOMPOFFLOADNoteTypes);
   if (Name == "Android")
     return FindNote(AndroidNoteTypes);
-  if (Name == "ARM")
-    return FindNote(ARMNoteTypes);
 
   if (ELFType == ELF::ET_CORE)
     return FindNote(CoreNoteTypes);
@@ -6059,9 +6108,6 @@ template <class ELFT> void GNUELFDumper<ELFT>::printNotes() {
     } else if (Name == "Android") {
       if (printAndroidNote(OS, Type, Descriptor))
         return Error::success();
-    } else if (Name == "ARM") {
-      if (printAArch64Note<ELFT>(OS, Type, Descriptor))
-        return Error::success();
     }
     if (!Descriptor.empty()) {
       OS << "   description data:";
@@ -7699,29 +7745,6 @@ static bool printAndroidNoteLLVMStyle(uint32_t NoteType, ArrayRef<uint8_t> Desc,
   return true;
 }
 
-template <class ELFT>
-static bool printAarch64NoteLLVMStyle(uint32_t NoteType, ArrayRef<uint8_t> Desc,
-                                      ScopedPrinter &W) {
-  if (NoteType != NT_ARM_TYPE_PAUTH_ABI_TAG)
-    return false;
-
-  if (Desc.size() < 16)
-    return false;
-
-  uint64_t platform =
-      support::endian::read64<ELFT::TargetEndianness>(Desc.data() + 0);
-  uint64_t version =
-      support::endian::read64<ELFT::TargetEndianness>(Desc.data() + 8);
-  W.printNumber("Platform", platform);
-  W.printNumber("Version", version);
-
-  if (Desc.size() > 16)
-    W.printString("Additional info",
-                  toHex(ArrayRef<uint8_t>(Desc.data() ...
[truncated]


// Bit positions of version flags for AARCH64_PAUTH_PLATFORM_LLVM_LINUX.
enum : unsigned {
AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_INTRINSICS = 0,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where are these constants defined?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Invalid and baremetal platform values are reserved in https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst (constant names themselves are not defined there though). Regarding everything related to llvm_linux platform - it's not defined anywhere and I've defined it here since we need some sort of working ELF marking scheme to at least test things. If different constant names and/or values are preferred or there is some specification which needs to be updated correspondingly - please let me know.

uint64_t Version =
support::endian::read64<ELFT::TargetEndianness>(Desc.data() + 8);

std::string PlatformDesc = [Platform]() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider const StringRef instead of a mutable std::string

Copy link
Contributor Author

@kovdan01 kovdan01 Mar 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for suggestion. I've switched to const char * since we later use PlatformDesc as an argument for format(...) and expect it to be null-terminated. Storing null-terminated strings as const char * when we don't need anything except the pointer itself looks more clear in this context than calling .data() on StringRef and keeping in mind that in this particular case the StringRef's content is also null-terminated (while it's not guaranteed in other cases).

For VersionDesc, I still use std::string - it does not look safe to use StringRef or smth similar due to dangling references to a temporary.

See 8b56262

return "";
if (Version >= (1 << (AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_LAST + 1)))
return "unknown";
return std::string("") +
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Define a std::string, then do

if (...)
  Desc += ...
if (...)
  Desc += ...

is likely more readable

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for suggestion. I've switched to a slightly different approach. I've defined an array of flag names and then iterate over them in a loop and test each flag in the loop. Keeping in mind that we always have all flag names in the description and just add '!' for those which are disabled, it looks more clear.

See 8b56262

(1 << AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_INITFINI))
? ""
: "!") +
"PointerAuthInitFini";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is PointerAuthInitFini always part of the description?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if I got your question - all the flag names are always part of the description, we just add '!' for those which are not set. As for me, it's more clear for a user than only including in the description flags which are set and not including those which are not set - in this case, the user is not aware which flags are available and does not know which features are disabled.

Please let me know if I miss something.

@kovdan01 kovdan01 requested a review from MaskRay March 25, 2024 07:27
Copy link

✅ With the latest revision this PR passed the Python code formatter.

Copy link

✅ With the latest revision this PR passed the C/C++ code formatter.

#--- gnu-42-1.s

.section ".note.gnu.property", "a"
.long 4 /* Name length is always 4 ("GNU") */
Copy link
Member

@MaskRay MaskRay Mar 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// is shorter and more common since // is supported by all targets in GNU as.

# can be used on aarch64 if there is no leading non-whitespace character.

Copy link
Contributor Author

@kovdan01 kovdan01 Mar 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed, thanks, see 26c8586

In llvm/test/tools/llvm-readobj/ELF/AArch64/aarch64-note-gnu-property.s, which tests other GNU properties, /* */ is used. I can submit a subsequent PR changing that to // and # where applicable to keep things consistent. Please let me know what you think on this.

@kovdan01 kovdan01 requested a review from MaskRay March 26, 2024 18:22
@kovdan01
Copy link
Contributor Author

@MaskRay Please let me know if latest updates address your comments - it would be nice to get this merged shortly since it's a prerequisite for several other PRs.

@kovdan01
Copy link
Contributor Author

kovdan01 commented Apr 2, 2024

Previous buildkite failures related to the PR are fixed (renaming TargetEndianness to Endianness after 2763353), the current failure https://buildkite.com/llvm-project/github-pull-requests/builds/52289 in CodeGenHLSL/builtins/wave_get_lane_index_subcall.hlsl is unrelated, so merging.

@kovdan01 kovdan01 merged commit 5029949 into llvm:main Apr 2, 2024
3 of 4 checks passed
kovdan01 added a commit that referenced this pull request Apr 4, 2024
…RE_PAUTH` (#87545)

Reland #85231 after fixing build failure
https://lab.llvm.org/buildbot/#/builders/186/builds/15631.
Use `PRIx64` for format output of `uint64_t` as hex.
Original PR description below.

This adds support for `GNU_PROPERTY_AARCH64_FEATURE_PAUTH` feature (as
defined in ARM-software/abi-aa#240) handling in
llvm-readobj and llvm-readelf. The following constants for supported
platforms are also introduced:

- `AARCH64_PAUTH_PLATFORM_INVALID = 0x0`
- `AARCH64_PAUTH_PLATFORM_BAREMETAL = 0x1`
- `AARCH64_PAUTH_PLATFORM_LLVM_LINUX = 0x10000002`

For the llvm_linux platform, output of the tools contains descriptions
of PAuth features which are enabled/disabled depending on the version
value. Version value bits correspond to the following `LangOptions`
defined in #85232:

- bit 0: `PointerAuthIntrinsics`;
- bit 1: `PointerAuthCalls`;
- bit 2: `PointerAuthReturns`;
- bit 3: `PointerAuthAuthTraps`;
- bit 4: `PointerAuthVTPtrAddressDiscrimination`;
- bit 5: `PointerAuthVTPtrTypeDiscrimination`;
- bit 6: `PointerAuthInitFini`.

Support for `.note.AARCH64-PAUTH-ABI-tag` is dropped since it's deleted
from the spec in ARM-software/abi-aa#250.
kovdan01 added a commit that referenced this pull request Apr 4, 2024
#72714)

This patch adds lld support for:

- Dynamic R_AARCH64_AUTH_* relocations (without including RELR compressed AUTH
relocations) as described here:
https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst#auth-variant-dynamic-relocations

- .note.AARCH64-PAUTH-ABI-tag section as defined here
https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst#elf-marking

Depends on #72713 and #85231

---------

Co-authored-by: Peter Collingbourne <[email protected]>
Co-authored-by: Fangrui Song <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

3 participants