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