diff options
Diffstat (limited to 'libc/stdlib')
-rw-r--r-- | libc/stdlib/abort.c | 75 |
1 files changed, 65 insertions, 10 deletions
diff --git a/libc/stdlib/abort.c b/libc/stdlib/abort.c index 7b7d6bb50..53abbd284 100644 --- a/libc/stdlib/abort.c +++ b/libc/stdlib/abort.c @@ -21,31 +21,86 @@ Cambridge, MA 02139, USA. */ #include <signal.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <unistd.h> #include <signal.h> #include <errno.h> + +/* Our last ditch effort to commit suicide */ +#if defined(__i386__) +#define ABORT_INSTRUCTION asm ("hlt") +#elif defined(__ia64__) +#define ABORT_INSTRUCTION asm ("break 0") +#elif defined(__mc68000__) +#define ABORT_INSTRUCTION asm ("illegal") +#elif defined(__mips__) +#define ABORT_INSTRUCTION asm ("break 255") +#elif defined(__s390__) +#define ABORT_INSTRUCTION asm (".word 0") +#elif defined(__sparc__) +#define ABORT_INSTRUCTION asm ("unimp 0xf00") +#elif defined(__x86_64__) +#define ABORT_INSTRUCTION asm ("hlt") +#else +#define ABORT_INSTRUCTION +#endif + typedef void (*vfuncp) (void); extern vfuncp __uClibc_cleanup; extern void _exit __P((int __status)) __attribute__ ((__noreturn__)); +static int been_there_done_that = 0; /* Cause an abnormal program termination with core-dump. */ void abort(void) { - sigset_t sigset; + sigset_t sigset; + + /* Unmask SIGABRT to be sure we can get it */ + if (__sigemptyset(&sigset) == 0 && __sigaddset(&sigset, SIGABRT) == 0) { + sigprocmask(SIG_UNBLOCK, &sigset, (sigset_t *) NULL); + } + + /* __uClibc_cleanup NULLs itself out after being called */ + if (__uClibc_cleanup) { + __uClibc_cleanup(); + } + + while (1) { + /* Try to suicide with a SIGABRT. */ + if (been_there_done_that == 0) { + been_there_done_that++; + raise(SIGABRT); + } + + /* Still here? Try to remove any signal handlers. */ + if (been_there_done_that == 1) { + struct sigaction act; - if (sigemptyset(&sigset) == 0 && sigaddset(&sigset, SIGABRT) == 0) { - sigprocmask(SIG_UNBLOCK, &sigset, (sigset_t *) NULL); + been_there_done_that++; + memset (&act, '\0', sizeof (struct sigaction)); + act.sa_handler = SIG_DFL; + __sigfillset (&act.sa_mask); + act.sa_flags = 0; + sigaction (SIGABRT, &act, NULL); } - if (__uClibc_cleanup) { /* Not already executing __uClibc_cleanup. */ - __uClibc_cleanup(); + /* Still here? Try to suicide with an illegal instruction */ + if (been_there_done_that == 2) { + been_there_done_that++; + ABORT_INSTRUCTION; } + /* Still here? Try to at least exit */ + if (been_there_done_that == 3) { + been_there_done_that++; + _exit (127); + } + + /* Still here? We're screwed. Sleepy time. Good night */ while (1) - if (raise(SIGABRT)) - /* If we can't signal ourselves, exit. */ - _exit(127); - /* If we signal ourselves and are still alive, - or can't exit, loop forever. */ + /* Try for ever and ever. */ + ABORT_INSTRUCTION; + } } + |