Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | --- abort.c.orig 2010-09-07 22:42:56.000000000 -0700 +++ abort.c 2010-09-07 22:46:29.000000000 -0700 @@ -35,6 +35,7 @@ __FBSDID("$FreeBSD: src/lib/libc/stdlib/ #include "namespace.h" #include <signal.h> +#include <stdarg.h> #include <stdlib.h> #include <stddef.h> #include <unistd.h> @@ -43,11 +44,22 @@ __FBSDID("$FreeBSD: src/lib/libc/stdlib/ #include "libc_private.h" +#include "CrashReporterClient.h" +#include "_simple.h" + +extern void (*__cleanup)(); +extern void __abort(void) __dead2; + +#define TIMEOUT 10000 /* 10 milliseconds */ + void abort() { struct sigaction act; + if (!CRGetCrashLogMessage()) + CRSetCrashLogMessage("abort() called"); + /* * POSIX requires we flush stdio buffers on abort. * XXX ISO C requires that abort() be async-signal-safe. @@ -61,19 +73,90 @@ abort() * any errors -- ISO C doesn't allow abort to return anyway. */ sigdelset(&act.sa_mask, SIGABRT); - (void)_sigprocmask(SIG_SETMASK, &act.sa_mask, NULL); - (void)raise(SIGABRT); + + /* <rdar://problem/7397932> abort() should call pthread_kill to deliver a signal to the aborting thread + * This helps gdb focus on the thread calling abort() + */ + if (__is_threaded) { + /* Block all signals on all other threads */ + sigset_t fullmask; + sigfillset(&fullmask); + (void)_sigprocmask(SIG_SETMASK, &fullmask, NULL); + + /* <rdar://problem/8400096> Set the workqueue killable */ + __pthread_workqueue_setkill(1); + + (void)pthread_sigmask(SIG_SETMASK, &act.sa_mask, NULL); + (void)pthread_kill(pthread_self(), SIGABRT); + } else { + (void)_sigprocmask(SIG_SETMASK, &act.sa_mask, NULL); + (void)kill(getpid(), SIGABRT); + } + usleep(TIMEOUT); /* give time for signal to happen */ /* * If SIGABRT was ignored, or caught and the handler returns, do * it again, only harder. */ + __abort(); +} + +__private_extern__ void +__abort() +{ + struct sigaction act; + + if (!CRGetCrashLogMessage()) + CRSetCrashLogMessage("__abort() called"); act.sa_handler = SIG_DFL; act.sa_flags = 0; sigfillset(&act.sa_mask); (void)_sigaction(SIGABRT, &act, NULL); sigdelset(&act.sa_mask, SIGABRT); + + /* <rdar://problem/7397932> abort() should call pthread_kill to deliver a signal to the aborting thread + * This helps gdb focus on the thread calling abort() + */ + if (__is_threaded) { + /* Block all signals on all other threads */ + sigset_t fullmask; + sigfillset(&fullmask); + (void)_sigprocmask(SIG_SETMASK, &fullmask, NULL); + + /* <rdar://problem/8400096> Set the workqueue killable */ + __pthread_workqueue_setkill(1); + + (void)pthread_sigmask(SIG_SETMASK, &act.sa_mask, NULL); + (void)pthread_kill(pthread_self(), SIGABRT); + } else { + (void)_sigprocmask(SIG_SETMASK, &act.sa_mask, NULL); + (void)kill(getpid(), SIGABRT); + } + usleep(TIMEOUT); /* give time for signal to happen */ + + /* If for some reason SIGABRT was not delivered, we exit using __builtin_trap + * which generates an illegal instruction on i386: <rdar://problem/8400958> + * and SIGTRAP on arm. + */ + sigfillset(&act.sa_mask); + sigdelset(&act.sa_mask, SIGILL); + sigdelset(&act.sa_mask, SIGTRAP); (void)_sigprocmask(SIG_SETMASK, &act.sa_mask, NULL); - (void)raise(SIGABRT); - exit(1); + __builtin_trap(); +} + +__private_extern__ void +abort_report_np(const char *fmt, ...) +{ + _SIMPLE_STRING s; + va_list ap; + + if ((s = _simple_salloc()) != NULL) { + va_start(ap, fmt); + _simple_vsprintf(s, fmt, ap); + va_end(ap); + CRSetCrashLogMessage(_simple_string(s)); + } else + CRSetCrashLogMessage(fmt); /* the format string is better than nothing */ + abort(); } |