File Index
Files and directories
Sign in
FILE

sigtrap_loop.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/x86/sigtrap_loop.c C
  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}
~/ Read-only file preview.