1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2025 Intel Corporation 4 */ 5 #define _GNU_SOURCE 6 7 #include <err.h> 8 #include <signal.h> 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <string.h> 12 #include <sys/ucontext.h> 13 14 #ifdef __x86_64__ 15 # define REG_IP REG_RIP 16 #else 17 # define REG_IP REG_EIP 18 #endif 19 20 static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), int flags) 21 { 22 struct sigaction sa; 23 24 memset(&sa, 0, sizeof(sa)); 25 sa.sa_sigaction = handler; 26 sa.sa_flags = SA_SIGINFO | flags; 27 sigemptyset(&sa.sa_mask); 28 29 if (sigaction(sig, &sa, 0)) 30 err(1, "sigaction"); 31 32 return; 33 } 34 35 static void sigtrap(int sig, siginfo_t *info, void *ctx_void) 36 { 37 ucontext_t *ctx = (ucontext_t *)ctx_void; 38 static unsigned int loop_count_on_same_ip; 39 static unsigned long last_trap_ip; 40 41 if (last_trap_ip == ctx->uc_mcontext.gregs[REG_IP]) { 42 printf("\tTrapped at %016lx\n", last_trap_ip); 43 44 /* 45 * If the same IP is hit more than 10 times in a row, it is 46 * _considered_ an infinite loop. 47 */ 48 if (++loop_count_on_same_ip > 10) { 49 printf("[FAIL]\tDetected SIGTRAP infinite loop\n"); 50 exit(1); 51 } 52 53 return; 54 } 55 56 loop_count_on_same_ip = 0; 57 last_trap_ip = ctx->uc_mcontext.gregs[REG_IP]; 58 printf("\tTrapped at %016lx\n", last_trap_ip); 59 } 60 61 int main(int argc, char *argv[]) 62 { 63 sethandler(SIGTRAP, sigtrap, 0); 64 65 /* 66 * Set the Trap Flag (TF) to single-step the test code, therefore to 67 * trigger a SIGTRAP signal after each instruction until the TF is 68 * cleared. 69 * 70 * Because the arithmetic flags are not significant here, the TF is 71 * set by pushing 0x302 onto the stack and then popping it into the 72 * flags register. 73 * 74 * Four instructions in the following asm code are executed with the 75 * TF set, thus the SIGTRAP handler is expected to run four times. 76 */ 77 printf("[RUN]\tSIGTRAP infinite loop detection\n"); 78 asm volatile( 79 #ifdef __x86_64__ 80 /* 81 * Avoid clobbering the redzone 82 * 83 * Equivalent to "sub $128, %rsp", however -128 can be encoded 84 * in a single byte immediate while 128 uses 4 bytes. 85 */ 86 "add $-128, %rsp\n\t" 87 #endif 88 "push $0x302\n\t" 89 "popf\n\t" 90 "nop\n\t" 91 "nop\n\t" 92 "push $0x202\n\t" 93 "popf\n\t" 94 #ifdef __x86_64__ 95 "sub $-128, %rsp\n\t" 96 #endif 97 ); 98 99 printf("[OK]\tNo SIGTRAP infinite loop detected\n"); 100 return 0; 101 } 102