diff options
Diffstat (limited to 'bolt/test')
-rw-r--r-- | bolt/test/AArch64/negate-ra-state-disallow.s | 25 | ||||
-rw-r--r-- | bolt/test/AArch64/negate-ra-state-incorrect.s | 78 | ||||
-rw-r--r-- | bolt/test/AArch64/negate-ra-state-reorder.s | 73 | ||||
-rw-r--r-- | bolt/test/AArch64/negate-ra-state.s | 76 | ||||
-rw-r--r-- | bolt/test/AArch64/pacret-split-funcs.s | 54 | ||||
-rw-r--r-- | bolt/test/X86/fragment-alias.s | 13 | ||||
-rw-r--r-- | bolt/test/perf2bolt/AArch64/perf2bolt-spe.test | 3 | ||||
-rw-r--r-- | bolt/test/runtime/AArch64/negate-ra-state.cpp | 26 | ||||
-rw-r--r-- | bolt/test/runtime/AArch64/pacret-function-split.cpp | 42 |
9 files changed, 388 insertions, 2 deletions
diff --git a/bolt/test/AArch64/negate-ra-state-disallow.s b/bolt/test/AArch64/negate-ra-state-disallow.s new file mode 100644 index 0000000..95adb71 --- /dev/null +++ b/bolt/test/AArch64/negate-ra-state-disallow.s @@ -0,0 +1,25 @@ +# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown %s -o %t.o +# RUN: %clang %cflags %t.o -o %t.exe -Wl,-q +# RUN: not llvm-bolt %t.exe -o %t.exe.bolt --update-branch-protection=false 2>&1 | FileCheck %s + +# CHECK: BOLT-ERROR: --update-branch-protection is set to false, but foo contains .cfi-negate-ra-state + + .text + .globl foo + .p2align 2 + .type foo,@function +foo: + .cfi_startproc + hint #25 + .cfi_negate_ra_state + mov x1, #0 + hint #29 + .cfi_negate_ra_state + ret + .cfi_endproc + .size foo, .-foo + + .global _start + .type _start, %function +_start: + b foo diff --git a/bolt/test/AArch64/negate-ra-state-incorrect.s b/bolt/test/AArch64/negate-ra-state-incorrect.s new file mode 100644 index 0000000..14d2c38 --- /dev/null +++ b/bolt/test/AArch64/negate-ra-state-incorrect.s @@ -0,0 +1,78 @@ +# This test checks that MarkRAStates pass ignores functions with +# malformed .cfi_negate_ra_state sequences in the input binary. + +# The cases checked are: +# - extra .cfi_negate_ra_state in Signed state: checked in foo, +# - extra .cfi_negate_ra_state in Unsigned state: checked in bar, +# - missing .cfi_negate_ra_state from PSign or PAuth instructions: checked in baz. + +# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown %s -o %t.o +# RUN: %clang %cflags %t.o -o %t.exe -Wl,-q +# RUN: llvm-bolt %t.exe -o %t.exe.bolt --no-threads | FileCheck %s --check-prefix=CHECK-BOLT + +# CHECK-BOLT: BOLT-INFO: inconsistent RAStates in function foo: ptr authenticating inst encountered in Unsigned RA state +# CHECK-BOLT: BOLT-INFO: inconsistent RAStates in function bar: ptr signing inst encountered in Signed RA state +# CHECK-BOLT: BOLT-INFO: inconsistent RAStates in function baz: ptr sign/auth inst without .cfi_negate_ra_state + +# Check that the incorrect functions got ignored, so they are not in the new .text section +# RUN: llvm-objdump %t.exe.bolt -d -j .text | FileCheck %s --check-prefix=CHECK-OBJDUMP +# CHECK-OBJDUMP-NOT: <foo>: +# CHECK-OBJDUMP-NOT: <bar>: +# CHECK-OBJDUMP-NOT: <baz>: + + + .text + .globl foo + .p2align 2 + .type foo,@function +foo: + .cfi_startproc + hint #25 + .cfi_negate_ra_state + mov x1, #0 + .cfi_negate_ra_state // Incorrect CFI in signed state + hint #29 + .cfi_negate_ra_state + ret + .cfi_endproc + .size foo, .-foo + + .text + .globl bar + .p2align 2 + .type bar,@function +bar: + .cfi_startproc + mov x1, #0 + .cfi_negate_ra_state // Incorrect CFI in unsigned state + hint #25 + .cfi_negate_ra_state + mov x1, #0 + hint #29 + .cfi_negate_ra_state + ret + .cfi_endproc + .size bar, .-bar + + .text + .globl baz + .p2align 2 + .type baz,@function +baz: + .cfi_startproc + mov x1, #0 + hint #25 + .cfi_negate_ra_state + mov x1, #0 + hint #29 + // Missing .cfi_negate_ra_state + ret + .cfi_endproc + .size baz, .-baz + + .global _start + .type _start, %function +_start: + b foo + b bar + b baz diff --git a/bolt/test/AArch64/negate-ra-state-reorder.s b/bolt/test/AArch64/negate-ra-state-reorder.s new file mode 100644 index 0000000..2659f75 --- /dev/null +++ b/bolt/test/AArch64/negate-ra-state-reorder.s @@ -0,0 +1,73 @@ +# Checking that after reordering BasicBlocks, the generated OpNegateRAState instructions +# are placed where the RA state is different between two consecutive instructions. +# This case demonstrates, that the input might have a different amount than the output: +# input has 4, but output only has 3. + +# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown %s -o %t.o +# RUN: %clang %cflags %t.o -o %t.exe -Wl,-q +# RUN: llvm-bolt %t.exe -o %t.exe.bolt --no-threads --reorder-blocks=reverse \ +# RUN: --print-cfg --print-after-lowering --print-only foo | FileCheck %s + +# Check that the reordering succeeded. +# CHECK: Binary Function "foo" after building cfg { +# CHECK: BB Layout : .LBB00, .Ltmp2, .Ltmp0, .Ltmp1 +# CHECK: Binary Function "foo" after inst-lowering { +# CHECK: BB Layout : .LBB00, .Ltmp1, .Ltmp0, .Ltmp2 + + +# Check the generated CFIs. +# CHECK: OpNegateRAState +# CHECK-NEXT: mov x2, #0x6 + +# CHECK: autiasp +# CHECK-NEXT: OpNegateRAState +# CHECK-NEXT: ret + +# CHECK: paciasp +# CHECK-NEXT: OpNegateRAState + +# CHECK: DWARF CFI Instructions: +# CHECK-NEXT: 0: OpNegateRAState +# CHECK-NEXT: 1: OpNegateRAState +# CHECK-NEXT: 2: OpNegateRAState +# CHECK-NEXT: End of Function "foo" + + .text + .globl foo + .p2align 2 + .type foo,@function +foo: + .cfi_startproc + // RA is unsigned + mov x1, #0 + mov x1, #1 + mov x1, #2 + // jump into the signed "range" + b .Lmiddle +.Lback: +// sign RA + paciasp + .cfi_negate_ra_state + mov x2, #3 + mov x2, #4 + // skip unsigned instructions + b .Lcont + .cfi_negate_ra_state +.Lmiddle: +// RA is unsigned + mov x4, #5 + b .Lback + .cfi_negate_ra_state +.Lcont: +// continue in signed state + mov x2, #6 + autiasp + .cfi_negate_ra_state + ret + .cfi_endproc + .size foo, .-foo + + .global _start + .type _start, %function +_start: + b foo diff --git a/bolt/test/AArch64/negate-ra-state.s b/bolt/test/AArch64/negate-ra-state.s new file mode 100644 index 0000000..30786d4 --- /dev/null +++ b/bolt/test/AArch64/negate-ra-state.s @@ -0,0 +1,76 @@ +# Checking that .cfi-negate_ra_state directives are emitted in the same location as in the input in the case of no optimizations. + +# The foo and bar functions are a pair, with the first signing the return address, +# and the second authenticating it. We have a tailcall between the two. +# This is testing that BOLT can handle functions starting in signed RA state. + +# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown %s -o %t.o +# RUN: %clang %cflags %t.o -o %t.exe -Wl,-q +# RUN: llvm-bolt %t.exe -o %t.exe.bolt --no-threads --print-all | FileCheck %s --check-prefix=CHECK-BOLT + +# Check that the negate-ra-state at the start of bar is not discarded. +# If it was discarded, MarkRAState would report bar as having inconsistent RAStates. +# This is testing the handling of initialRAState on the BinaryFunction. +# CHECK-BOLT-NOT: BOLT-INFO: inconsistent RAStates in function foo +# CHECK-BOLT-NOT: BOLT-INFO: inconsistent RAStates in function bar + +# Check that OpNegateRAState CFIs are generated correctly. +# CHECK-BOLT: Binary Function "foo" after insert-negate-ra-state-pass { +# CHECK-BOLT: paciasp +# CHECK-BOLT-NEXT: OpNegateRAState + +# CHECK-BOLT: DWARF CFI Instructions: +# CHECK-BOLT-NEXT: 0: OpNegateRAState +# CHECK-BOLT-NEXT: End of Function "foo" + +# CHECK-BOLT: Binary Function "bar" after insert-negate-ra-state-pass { +# CHECK-BOLT: OpNegateRAState +# CHECK-BOLT-NEXT: mov x1, #0x0 +# CHECK-BOLT-NEXT: mov x1, #0x1 +# CHECK-BOLT-NEXT: autiasp +# CHECK-BOLT-NEXT: OpNegateRAState +# CHECK-BOLT-NEXT: ret + +# CHECK-BOLT: DWARF CFI Instructions: +# CHECK-BOLT-NEXT: 0: OpNegateRAState +# CHECK-BOLT-NEXT: 1: OpNegateRAState +# CHECK-BOLT-NEXT: End of Function "bar" + +# End of negate-ra-state insertion logs for foo and bar. +# CHECK: Binary Function "_start" after insert-negate-ra-state-pass { + +# Check that the functions are in the new .text section +# RUN: llvm-objdump %t.exe.bolt -d -j .text | FileCheck %s --check-prefix=CHECK-OBJDUMP +# CHECK-OBJDUMP: <foo>: +# CHECK-OBJDUMP: <bar>: + + + .text + .globl foo + .p2align 2 + .type foo,@function +foo: + .cfi_startproc + paciasp + .cfi_negate_ra_state + mov x1, #0 + b bar + .cfi_endproc + .size foo, .-foo + + + + .text + .globl bar + .p2align 2 + .type bar,@function +bar: + .cfi_startproc + .cfi_negate_ra_state // Indicating that RA is signed from the start of bar. + mov x1, #0 + mov x1, #1 + autiasp + .cfi_negate_ra_state + ret + .cfi_endproc + .size bar, .-bar diff --git a/bolt/test/AArch64/pacret-split-funcs.s b/bolt/test/AArch64/pacret-split-funcs.s new file mode 100644 index 0000000..27b34710 --- /dev/null +++ b/bolt/test/AArch64/pacret-split-funcs.s @@ -0,0 +1,54 @@ +# Checking that we generate an OpNegateRAState CFI after the split point, +# when splitting a region with signed RA state. +# We split at the fallthrough label. + +# REQUIRES: system-linux + +# RUN: %clang %s %cflags -march=armv8.3-a -Wl,-q -o %t +# RUN: link_fdata --no-lbr %s %t %t.fdata +# RUN: llvm-bolt %t -o %t.bolt --data %t.fdata -split-functions \ +# RUN: --print-only foo --print-split --print-all 2>&1 | FileCheck %s + +# Checking that we don't see any OpNegateRAState CFIs before the insertion pass. +# CHECK-NOT: OpNegateRAState +# CHECK: Binary Function "foo" after insert-negate-ra-state-pass + +# CHECK: paciasp +# CHECK-NEXT: OpNegateRAState + +# CHECK: ------- HOT-COLD SPLIT POINT ------- + +# CHECK: OpNegateRAState +# CHECK-NEXT: mov x0, #0x1 +# CHECK-NEXT: autiasp +# CHECK-NEXT: OpNegateRAState +# CHECK-NEXT: ret + +# End of the insert-negate-ra-state-pass logs +# CHECK: Binary Function "foo" after finalize-functions + + .text + .globl foo + .type foo, %function +foo: +.cfi_startproc +.entry_bb: +# FDATA: 1 foo #.entry_bb# 10 + paciasp + .cfi_negate_ra_state // indicating that paciasp changed the RA state to signed + cmp x0, #0 + b.eq .Lcold_bb1 +.Lfallthrough: // split point + mov x0, #1 + autiasp + .cfi_negate_ra_state // indicating that autiasp changed the RA state to unsigned + ret +.Lcold_bb1: // Instructions below are not important, they are just here so the cold block is not empty. + .cfi_negate_ra_state // ret has unsigned RA state, but the next inst (autiasp) has signed RA state + mov x0, #2 + retaa +.cfi_endproc + .size foo, .-foo + +## Force relocation mode. +.reloc 0, R_AARCH64_NONE diff --git a/bolt/test/X86/fragment-alias.s b/bolt/test/X86/fragment-alias.s new file mode 100644 index 0000000..3392dd5 --- /dev/null +++ b/bolt/test/X86/fragment-alias.s @@ -0,0 +1,13 @@ +## This test reproduces the issue where a fragment has the same address as +## parent function. +# RUN: llvm-mc --filetype=obj --triple x86_64-unknown-unknown %s -o %t.o +# RUN: %clang %cflags %t.o -o %t +# RUN: llvm-bolt %t -o %t.out 2>&1 | FileCheck %s +# CHECK: BOLT-WARNING: fragment maps to the same function as parent: main/1(*2) +.type main, @function +.type main.cold, @function +main.cold: +main: + ret +.size main, .-main +.size main.cold, .-main.cold diff --git a/bolt/test/perf2bolt/AArch64/perf2bolt-spe.test b/bolt/test/perf2bolt/AArch64/perf2bolt-spe.test index 91f5c85..1f44f75 100644 --- a/bolt/test/perf2bolt/AArch64/perf2bolt-spe.test +++ b/bolt/test/perf2bolt/AArch64/perf2bolt-spe.test @@ -6,7 +6,6 @@ RUN: %clang %cflags %p/../../Inputs/asm_foo.s %p/../../Inputs/asm_main.c -o %t.e RUN: perf record -e cycles -q -o %t.perf.data -- %t.exe 2> /dev/null -RUN: (perf2bolt -p %t.perf.data -o %t.perf.boltdata --spe %t.exe 2> /dev/null; exit 0) | FileCheck %s --check-prefix=CHECK-SPE-LBR +RUN: perf2bolt -p %t.perf.data -o %t.perf.boltdata --spe %t.exe | FileCheck %s --check-prefix=CHECK-SPE-LBR CHECK-SPE-LBR: PERF2BOLT: parse SPE branch events in LBR-format - diff --git a/bolt/test/runtime/AArch64/negate-ra-state.cpp b/bolt/test/runtime/AArch64/negate-ra-state.cpp new file mode 100644 index 0000000..60b0b08 --- /dev/null +++ b/bolt/test/runtime/AArch64/negate-ra-state.cpp @@ -0,0 +1,26 @@ +// REQUIRES: system-linux,bolt-runtime + +// RUN: %clangxx --target=aarch64-unknown-linux-gnu \ +// RUN: -mbranch-protection=pac-ret -Wl,-q %s -o %t.exe +// RUN: llvm-bolt %t.exe -o %t.bolt.exe +// RUN: %t.bolt.exe | FileCheck %s + +// CHECK: Exception caught: Exception from bar(). + +#include <cstdio> +#include <stdexcept> + +void bar() { throw std::runtime_error("Exception from bar()."); } + +void foo() { + try { + bar(); + } catch (const std::exception &e) { + printf("Exception caught: %s\n", e.what()); + } +} + +int main() { + foo(); + return 0; +} diff --git a/bolt/test/runtime/AArch64/pacret-function-split.cpp b/bolt/test/runtime/AArch64/pacret-function-split.cpp new file mode 100644 index 0000000..208fc5c --- /dev/null +++ b/bolt/test/runtime/AArch64/pacret-function-split.cpp @@ -0,0 +1,42 @@ +/* This test check that the negate-ra-state CFIs are properly emitted in case of + function splitting. The test checks two things: + - we split at the correct location: to test the feature, + we need to split *before* the bl __cxa_throw@PLT call is made, + so the unwinder has to unwind from the split (cold) part. + + - the BOLTed binary runs, and returns the string from foo. + +# REQUIRES: system-linux,bolt-runtime + +# FDATA: 1 main #split# 1 _Z3foov 0 0 1 + +# RUN: %clangxx --target=aarch64-unknown-linux-gnu \ +# RUN: -mbranch-protection=pac-ret %s -o %t.exe -Wl,-q +# RUN: link_fdata %s %t.exe %t.fdata +# RUN: llvm-bolt %t.exe -o %t.bolt --split-functions --split-eh \ +# RUN: --split-strategy=profile2 --split-all-cold --print-split \ +# RUN: --print-only=_Z3foov --data=%t.fdata 2>&1 | FileCheck \ +# RUN: --check-prefix=BOLT-CHECK %s +# RUN: %t.bolt | FileCheck %s --check-prefix=RUN-CHECK + +# BOLT-CHECK-NOT: bl __cxa_throw@PLT +# BOLT-CHECK: ------- HOT-COLD SPLIT POINT ------- +# BOLT-CHECK: bl __cxa_throw@PLT + +# RUN-CHECK: Exception caught: Exception from foo(). +*/ + +#include <cstdio> +#include <stdexcept> + +void foo() { throw std::runtime_error("Exception from foo()."); } + +int main() { + try { + __asm__ __volatile__("split:"); + foo(); + } catch (const std::exception &e) { + printf("Exception caught: %s\n", e.what()); + } + return 0; +} |