* Copyright (c) 2011-2021 Google, Inc. All rights reserved.
* Copyright (c) 2003-2010 VMware, Inc. All rights reserved.
* **********************************************************/
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of VMware, Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
* To use, define these, then include this file:
#define USE_LONGJMP 0
#define BLOCK_IN_HANDLER 0
#define USE_SIGSTACK 0
#define USE_TIMER 0
#include "signal-base.h"
*
*/
#include "tools.h"
#include <assert.h>
#include <stdio.h>
#include <math.h>
#include <unistd.h>
#include <signal.h>
#include <ucontext.h>
#include <sys/time.h>
#include <string.h>
typedef void (*handler_t)(int, siginfo_t *, void *);
#if USE_LONGJMP
# include <setjmp.h>
static sigjmp_buf env;
#endif
#if USE_SIGSTACK
# include <stdlib.h>
# if USE_TIMER
# define ALT_STACK_SIZE (SIGSTKSZ * 4)
# else
# define ALT_STACK_SIZE (SIGSTKSZ * 2)
# endif
#endif
#if USE_TIMER
# define ITERS 3500000
#else
# define ITERS 500000
#endif
#ifdef AARCHXX
# undef SIGRTMAX
# define SIGRTMAX 62
# undef __SIGRTMAX
# define __SIGRTMAX SIGRTMAX
#endif
static int a[ITERS];
* hide inside #if VERBOSE.
* timer hits won't be the same, just make sure we get at least one.
*/
#if USE_TIMER
static int timer_hits = 0;
#endif
#include <errno.h>
static void
#if defined(ARM) && !defined(USE_SIGSTACK)
__attribute__((target("arm")))
#endif
signal_handler(int sig, siginfo_t *siginfo, ucontext_t *ucxt)
{
#if VERBOSE
print("signal_handler: sig=%d, retaddr=0x%08x, ucxt=0x%08x\n", sig, *(&sig - 1),
ucxt);
#else
# if USE_TIMER
if (sig != SIGVTALRM)
# endif
print("in signal handler\n");
#endif
#if USE_SIGSTACK
stack_t sigstack;
sigstack.ss_sp = siginfo;
sigstack.ss_size = ALT_STACK_SIZE;
sigstack.ss_flags = SS_ONSTACK;
int rc = sigaltstack(&sigstack, NULL);
assert(rc == -1 && errno == EPERM);
#endif
switch (sig) {
case SIGSEGV: {
sigcontext_t *sc = SIGCXT_FROM_UCXT(ucxt);
void *pc = (void *)sc->SC_XIP;
#if VERBOSE
print("Got SIGSEGV @ 0x%08x\n", pc);
#else
print("Got SIGSEGV\n");
#endif
#if USE_LONGJMP
siglongjmp(env, 1);
#endif
break;
}
case SIGUSR1: {
sigcontext_t *sc = SIGCXT_FROM_UCXT(ucxt);
void *pc = (void *)sc->SC_XIP;
#if VERBOSE
print("Got SIGUSR1 @ 0x%08x\n", pc);
#else
print("Got SIGUSR1\n");
#endif
break;
}
#ifdef LINUX
case __SIGRTMAX: {
sigcontext_t *sc = SIGCXT_FROM_UCXT(ucxt);
void *pc = (void *)sc->SC_XIP;
* sources. */
# ifndef AARCHXX
assert(__SIGRTMAX == 64);
# endif
assert(__SIGRTMAX == SIGRTMAX);
# if VERBOSE
print("Got SIGRTMAX @ 0x%08x\n", pc);
# else
print("Got SIGRTMAX\n");
# endif
break;
}
#endif
#if USE_TIMER
case SIGVTALRM: {
sigcontext_t *sc = SIGCXT_FROM_UCXT(ucxt);
void *pc = (void *)sc->SC_XIP;
# if VERBOSE
print("Got SIGVTALRM @ 0x%08x\n", pc);
# endif
timer_hits++;
break;
}
#endif
default: assert(0);
}
}
static void
custom_intercept_signal(int sig, handler_t handler)
{
int rc;
struct sigaction act;
act.sa_sigaction = handler;
#if BLOCK_IN_HANDLER
rc = sigfillset(&act.sa_mask);
#else
rc = sigemptyset(&act.sa_mask);
#endif
ASSERT_NOERR(rc);
act.sa_flags = SA_SIGINFO | SA_ONSTACK;
rc = sigaction(sig, &act, NULL);
ASSERT_NOERR(rc);
}
int
#if defined(ARM) && !defined(BLOCK_IN_HANDLER)
__attribute__((target("arm")))
#endif
main(int argc, char *argv[])
{
double res = 0.;
int i, j, rc;
#if USE_SIGSTACK
stack_t sigstack;
#endif
#if USE_TIMER
struct itimerval t;
#endif
sigset_t mask = {
0,
};
sigemptyset(&mask);
sigaddset(&mask, SIGURG);
sigaddset(&mask, SIGALRM);
rc = sigprocmask(SIG_SETMASK, &mask, NULL);
ASSERT_NOERR(rc);
#if USE_SIGSTACK
sigstack.ss_sp = (char *)malloc(ALT_STACK_SIZE);
sigstack.ss_size = ALT_STACK_SIZE;
sigstack.ss_flags = 0;
rc = sigaltstack(&sigstack, NULL);
ASSERT_NOERR(rc);
# if VERBOSE
print("Set up sigstack: 0x%08x - 0x%08x\n", sigstack.ss_sp,
sigstack.ss_sp + sigstack.ss_size);
# endif
#endif
#if USE_TIMER
custom_intercept_signal(SIGVTALRM, (handler_t)signal_handler);
t.it_interval.tv_sec = 0;
t.it_interval.tv_usec = 10000;
t.it_value.tv_sec = 0;
t.it_value.tv_usec = 10000;
rc = setitimer(ITIMER_VIRTUAL, &t, NULL);
ASSERT_NOERR(rc);
#endif
custom_intercept_signal(SIGSEGV, (handler_t)signal_handler);
custom_intercept_signal(SIGUSR1, (handler_t)signal_handler);
custom_intercept_signal(SIGUSR2, (handler_t)SIG_IGN);
#ifdef LINUX
custom_intercept_signal(__SIGRTMAX, (handler_t)signal_handler);
#endif
res = cos(0.56);
print("Sending SIGUSR2\n");
kill(getpid(), SIGUSR2);
print("Sending SIGUSR1\n");
kill(getpid(), SIGUSR1);
#ifdef LINUX
print("Sending SIGRTMAX\n");
kill(getpid(), SIGRTMAX);
#else
print("Sending SIGRTMAX\n");
print("in signal handler\n");
print("Got SIGRTMAX\n");
#endif
print("Generating SIGSEGV\n");
#if USE_LONGJMP
res = sigsetjmp(env, 1);
if (res == 0) {
*((volatile int *)0) = 4;
}
#else
kill(getpid(), SIGSEGV);
#endif
for (i = 0; i < ITERS; i++) {
if (i % 2 == 0) {
res += cos(1. / (double)(i + 1));
} else {
res += sin(1. / (double)(i + 1));
}
j = (i << 4) / (i | 0x38);
a[i] += j;
}
print("%f\n", res);
sigset_t check_mask = {
0,
};
rc = sigprocmask(SIG_BLOCK, NULL, &check_mask);
ASSERT_NOERR(rc);
assert(memcmp(&mask, &check_mask, sizeof(mask)) == 0);
#if USE_TIMER
memset(&t, 0, sizeof(t));
rc = setitimer(ITIMER_VIRTUAL, &t, NULL);
ASSERT_NOERR(rc);
if (timer_hits == 0)
print("Got 0 timer hits!\n");
else
print("Got some timer hits!\n");
#endif
* after we disabled the itimer will be on the alt stack.
*/
#if USE_SIGSTACK && !USE_TIMER
stack_t check_stack;
rc = sigaltstack(NULL, &check_stack);
ASSERT_NOERR(rc);
assert(check_stack.ss_sp == sigstack.ss_sp &&
check_stack.ss_size == sigstack.ss_size &&
check_stack.ss_flags == sigstack.ss_flags);
free(sigstack.ss_sp);
#endif
return 0;
}