Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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
20static 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
35static 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
61int 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}