/* * Copyright 2002-2019 Intel Corporation. * * This software is provided to you as Sample Source Code as defined in the accompanying * End User License Agreement for the Intel(R) Software Development Products ("Agreement") * section 1.L. * * This software and the related documents are provided as is, with no express or implied * warranties, other than those that are expressly stated in the License. */ // features.h does not exist on FreeBSD and macOS* #ifdef TARGET_LINUX // features initializes the system's state, including the state of __USE_GNU #include #endif // If __USE_GNU is defined, we don't need to do anything. // If we defined it ourselves, we need to undefine it later. #ifndef __USE_GNU #define __USE_GNU #define APP_UNDEF_USE_GNU #endif #ifdef TARGET_LINUX #include #else #include #endif // If we defined __USE_GNU ourselves, we need to undefine it here. #ifdef APP_UNDEF_USE_GNU #undef __USE_GNU #undef APP_UNDEF_USE_GNU #endif #include #include #include #include #include #include #include pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_attr_t thread_attr; int p_safe_exit; void setup_signal_stack(void); void print_signal_stack(void); void install_signal_handler(void); void signal_handler(int, siginfo_t *, void *); void generate_segv(int val); void lock(); void unlock(); void *thread_gen_segv(void *); void printSignalMask() { sigset_t maskSet; int maskBits; #ifdef TARGET_MAC pthread_sigmask(0, NULL, &maskSet); #else sigprocmask(0, NULL, &maskSet); #endif int i; for (i=32; i>0; i--) maskBits = (maskBits << 1) | sigismember(&maskSet, i); printf("signal mask: 0x%08x\n", maskBits); } void setup_signal_stack() { int ret_val; stack_t ss; stack_t oss; ss.ss_sp = malloc(SIGSTKSZ); assert(ss.ss_sp && "malloc failure"); ss.ss_size = SIGSTKSZ; ss.ss_flags = 0; printf("ESP of alternate stack: %p, top: %p, size: %ld\n", ss.ss_sp, (unsigned char *)ss.ss_sp + ss.ss_size, ss.ss_size); ret_val = sigaltstack(&ss, &oss); if(ret_val) { perror("ERROR, failed to set sigaltstack"); exit(1); } printf("ESP of original stack: %p, top: %p, size: %ld, disabled = %s\n", oss.ss_sp, (unsigned char *)oss.ss_sp + oss.ss_size, oss.ss_size, (oss.ss_flags & SS_DISABLE) ? "true" : "false"); } void print_signal_stack() { int ret_val; stack_t oss; ret_val = sigaltstack(NULL, &oss); if(ret_val) { perror("ERROR, failed to read sigaltstack"); exit(1); } printf("ESP of original stack: %p, top: %p, size: %ld, disabled = %s\n", oss.ss_sp, (unsigned char *)oss.ss_sp + oss.ss_size, oss.ss_size, (oss.ss_flags & SS_DISABLE) ? "true" : "false"); } void install_signal_handler() { int ret_val; struct sigaction s_sigaction; struct sigaction *p_sigaction = &s_sigaction; /* Register the signal hander using the siginfo interface*/ p_sigaction->sa_sigaction = signal_handler; p_sigaction->sa_flags = SA_SIGINFO | SA_ONSTACK; /* Don't mask any other signals */ sigemptyset(&p_sigaction->sa_mask); ret_val = sigaction(SIGSEGV, p_sigaction, NULL); if(ret_val) { perror("ERROR, sigaction failed"); exit(1); } ret_val = sigaction(SIGBUS, p_sigaction, NULL); if(ret_val) { perror("ERROR, sigaction failed"); exit(1); } } void generate_segv(int val) { int *p = 0; p_safe_exit = (int)&&safe_exit; printf("EIP of segfault: %p (only accurate with if compiled with -O)\n", &&segfault); /* Encourage the compiler to put val into a register so that the statement after the 'segfault' label is more likely to be the exact location of a mov to 0x0 */ val++; segfault: *p = val; printf("ERROR!\n"); safe_exit: printf("EIP of safe exit: 0x%x\n", p_safe_exit); } void lock() { int ret_val; ret_val = pthread_mutex_lock(&mutex); if(ret_val) { perror("ERROR, pthread_mutex_lock failed"); } fflush(stdout); } void unlock() { int ret_val; fflush(stdout); ret_val = pthread_mutex_unlock(&mutex); if(ret_val) { perror("ERROR, pthread_mutex_unlock failed"); } } void signal_handler(int signum, siginfo_t *siginfo, void *_uctxt) { ucontext_t *uctxt = (ucontext_t *)_uctxt; ucontext_t signal_ctxt; #if defined(TARGET_MAC) printf("signal %d (captured EIP: 0x%x)\n", signum, uctxt->uc_mcontext->__ss.__eip); #else printf("signal %d (captured EIP: 0x%x)\n", signum, uctxt->uc_mcontext.gregs[REG_EIP]); #endif printSignalMask(); #if defined(TARGET_MAC) /* On macOS* ucontext routines are deprecated */ uctxt->uc_mcontext->__ss.__eip = p_safe_exit; #else int ret_val = getcontext(&signal_ctxt); if(ret_val) { perror("ERROR, getcontext failed"); exit(1); } printf("signal handler stack: 0x%0.8x\n", signal_ctxt.uc_mcontext.gregs[REG_ESP]); uctxt->uc_mcontext.gregs[REG_EIP] = p_safe_exit; #endif } void *thread_start(void *arg) { int ret_val; lock(); printf("thread arg = %d\n", (unsigned int)arg); if(arg) { setup_signal_stack(); } else { print_signal_stack(); } generate_segv(1); unlock(); if(arg == (void *)2) { pthread_t tid; void *thread_ret; ret_val = pthread_create(&tid, NULL, thread_start, NULL); if(ret_val) { perror("ERROR, pthread_create failed"); exit(1); } lock(); printf("created thread 0x%lx\n", (unsigned long)tid); unlock(); ret_val = pthread_join(tid, &thread_ret); if(ret_val) { perror("ERROR, pthread_join failed"); exit(1); } ret_val = pthread_create(&tid, NULL, thread_start, (void *)1); if(ret_val) { perror("ERROR, pthread_create failed"); exit(1); } lock(); printf("created thread 0x%lx\n", (unsigned long)tid); unlock(); ret_val = pthread_join(tid, &thread_ret); if(ret_val) { perror("ERROR, pthread_join failed"); exit(1); } } return 0; } int main(int argc, char **argv) { pthread_t tid; int ret_val; void *thread_ret; setup_signal_stack(); install_signal_handler(); ret_val = pthread_create(&tid, NULL, thread_start, NULL); if(ret_val) { perror("ERROR, pthread_create failed"); exit(1); } lock(); printf("created thread 0x%lx\n", (unsigned long)tid); unlock(); ret_val = pthread_join(tid, &thread_ret); if(ret_val) { perror("ERROR, pthread_join failed"); exit(1); } ret_val = pthread_create(&tid, NULL, thread_start, (void *)1); if(ret_val) { perror("ERROR, pthread_create failed"); exit(1); } lock(); printf("created thread 0x%lx\n", (unsigned long)tid); unlock(); ret_val = pthread_join(tid, &thread_ret); if(ret_val) { perror("ERROR, pthread_join failed"); exit(1); } ret_val = pthread_create(&tid, NULL, thread_start, (void *)2); if(ret_val) { perror("ERROR, pthread_create failed"); exit(1); } lock(); printf("created thread 0x%lx\n", (unsigned long)tid); unlock(); ret_val = pthread_join(tid, &thread_ret); if(ret_val) { perror("ERROR, pthread_join failed"); exit(1); } }