/[zanavi_public1]/navit/navit/coffeecatch.c
ZANavi

Contents of /navit/navit/coffeecatch.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 56 - (show annotations) (download)
Sun Mar 19 08:44:36 2017 UTC (7 years ago) by zoff99
File MIME type: text/plain
File size: 42947 byte(s)
updates
1 /* CoffeeCatch, a tiny native signal handler/catcher for JNI code.
2 * (especially for Android/Dalvik)
3 *
4 * Copyright (c) 2013, Xavier Roche (http://www.httrack.com/)
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright notice, this
11 * list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 /*
29 *
30 * from revision:
31 * https://github.com/xroche/coffeecatch/blob/e64ca5a1be03795baecb3242f37a80da2f138ff1/coffeecatch.c
32 *
33 */
34
35 #ifdef __ANDROID__
36 #define USE_UNWIND
37 #define USE_CORKSCREW
38 #define USE_LIBUNWIND
39 #endif
40
41 /* #undef NO_USE_SIGALTSTACK */
42 /* #undef USE_SILENT_SIGALTSTACK */
43
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <stdint.h>
47 #include <unistd.h>
48 #include <string.h>
49 #include <errno.h>
50 #include <sys/types.h>
51 #include <assert.h>
52 #include <signal.h>
53 #include <setjmp.h>
54 #if defined(__ANDROID__) && !defined(__BIONIC_HAVE_UCONTEXT_T) && \
55 defined(__arm__) && !defined(__BIONIC_HAVE_STRUCT_SIGCONTEXT)
56 #include <asm/sigcontext.h>
57 #endif
58 #if (defined(USE_UNWIND) && !defined(USE_CORKSCREW))
59 #include <unwind.h>
60 #endif
61 #include <pthread.h>
62 #include <dlfcn.h>
63 #include "coffeecatch.h"
64
65 /*#define NDK_DEBUG 1*/
66 #if ( defined(NDK_DEBUG) && ( NDK_DEBUG == 1 ) )
67 #define DEBUG(A) do { A; } while(0)
68 #define FD_ERRNO 2
69 static void print(const char *const s) {
70 size_t count;
71 for(count = 0; s[count] != '\0'; count++) ;
72 /* write() is async-signal-safe. */
73 (void) write(FD_ERRNO, s, count);
74 }
75 #else
76 #define DEBUG(A)
77 #endif
78
79 /* Alternative stack size. */
80 #define SIG_STACK_BUFFER_SIZE SIGSTKSZ
81
82 #ifdef USE_UNWIND
83 /* Number of backtraces to get. */
84 #define BACKTRACE_FRAMES_MAX 32
85 #endif
86
87 /* Signals to be caught. */
88 #define SIG_CATCH_COUNT 7
89 static const int native_sig_catch[SIG_CATCH_COUNT + 1]
90 = { SIGABRT, SIGILL, SIGTRAP, SIGBUS, SIGFPE, SIGSEGV
91 #ifdef SIGSTKFLT
92 , SIGSTKFLT
93 #endif
94 , 0 };
95
96 /* Maximum value of a caught signal. */
97 #define SIG_NUMBER_MAX 32
98
99 #if defined(__ANDROID__)
100 #ifndef ucontext_h_seen
101 #define ucontext_h_seen
102
103 /* stack_t definition */
104 #include <asm/signal.h>
105
106 #if defined(__arm__)
107
108 /* Taken from richard.quirk's header file. (Android does not have it) */
109
110 #if !defined(__BIONIC_HAVE_UCONTEXT_T)
111 typedef struct ucontext {
112 unsigned long uc_flags;
113 struct ucontext *uc_link;
114 stack_t uc_stack;
115 struct sigcontext uc_mcontext;
116 unsigned long uc_sigmask;
117 } ucontext_t;
118 #endif
119
120 #elif defined(__aarch64__)
121
122 #elif defined(__i386__)
123
124 /* Taken from Google Breakpad. */
125
126
127
128 // --- Zoff -----------------------------
129 // --- Zoff -----------------------------
130 #if 0
131
132 /* 80-bit floating-point register */
133 struct _libc_fpreg {
134 unsigned short significand[4];
135 unsigned short exponent;
136 };
137
138 /* Simple floating-point state, see FNSTENV instruction */
139 struct _libc_fpstate {
140 unsigned long cw;
141 unsigned long sw;
142 unsigned long tag;
143 unsigned long ipoff;
144 unsigned long cssel;
145 unsigned long dataoff;
146 unsigned long datasel;
147 struct _libc_fpreg _st[8];
148 unsigned long status;
149 };
150
151 typedef uint32_t greg_t;
152
153 typedef struct {
154 uint32_t gregs[19];
155 struct _libc_fpstate* fpregs;
156 uint32_t oldmask;
157 uint32_t cr2;
158 } mcontext_t;
159
160 enum {
161 REG_GS = 0,
162 REG_FS,
163 REG_ES,
164 REG_DS,
165 REG_EDI,
166 REG_ESI,
167 REG_EBP,
168 REG_ESP,
169 REG_EBX,
170 REG_EDX,
171 REG_ECX,
172 REG_EAX,
173 REG_TRAPNO,
174 REG_ERR,
175 REG_EIP,
176 REG_CS,
177 REG_EFL,
178 REG_UESP,
179 REG_SS,
180 };
181
182 #endif
183 // --- Zoff -----------------------------
184 // --- Zoff -----------------------------
185
186
187 #if !defined(__BIONIC_HAVE_UCONTEXT_T)
188 typedef struct ucontext {
189 uint32_t uc_flags;
190 struct ucontext* uc_link;
191 stack_t uc_stack;
192 mcontext_t uc_mcontext;
193 } ucontext_t;
194 #endif
195
196 #elif defined(__mips__)
197
198 /* Taken from Google Breakpad. */
199
200
201
202
203 // TODO: android studio ----------
204 // TODO: android studio ----------
205 #if 0
206 typedef struct {
207 uint32_t regmask;
208 uint32_t status;
209 uint64_t pc;
210 uint64_t gregs[32];
211 uint64_t fpregs[32];
212 uint32_t acx;
213 uint32_t fpc_csr;
214 uint32_t fpc_eir;
215 uint32_t used_math;
216 uint32_t dsp;
217 uint64_t mdhi;
218 uint64_t mdlo;
219 uint32_t hi1;
220 uint32_t lo1;
221 uint32_t hi2;
222 uint32_t lo2;
223 uint32_t hi3;
224 uint32_t lo3;
225 } mcontext_t;
226 #endif
227 // TODO: android studio ----------
228 // TODO: android studio ----------
229
230
231
232 // TODO: android studio ----------
233 // TODO: android studio ----------
234 #if 0
235 #if defined(__i386__)
236 #include <setjmp.h>
237 void siglongjmp(jmp_buf env, int val);
238 int sigsetjmp(jmp_buf env, int savemask);
239 void siglongjmp(jmp_buf env, int val)
240 {
241 longjmp(env, val);
242 }
243 int sigsetjmp(jmp_buf env, int savemask)
244 {
245 return setjmp(env);
246 }
247 #endif
248 #endif
249 // TODO: android studio ----------
250 // TODO: android studio ----------
251
252
253
254
255 #if !defined(__BIONIC_HAVE_UCONTEXT_T)
256 typedef struct ucontext {
257 uint32_t uc_flags;
258 struct ucontext* uc_link;
259 stack_t uc_stack;
260 mcontext_t uc_mcontext;
261 } ucontext_t;
262 #endif
263
264 #else
265 #error "Architecture is not supported (unknown ucontext layout)"
266 #endif
267
268 #endif
269
270 #ifdef USE_CORKSCREW
271 typedef struct map_info_t map_info_t;
272 /* Extracted from Android's include/corkscrew/backtrace.h */
273 typedef struct {
274 uintptr_t absolute_pc;
275 uintptr_t stack_top;
276 size_t stack_size;
277 } backtrace_frame_t;
278 typedef struct {
279 uintptr_t relative_pc;
280 uintptr_t relative_symbol_addr;
281 char* map_name;
282 char* symbol_name;
283 char* demangled_name;
284 } backtrace_symbol_t;
285 /* Extracted from Android's libcorkscrew/arch-arm/backtrace-arm.c */
286 typedef ssize_t (*t_unwind_backtrace_signal_arch)
287 (siginfo_t* si, void* sc, const map_info_t* lst, backtrace_frame_t* bt,
288 size_t ignore_depth, size_t max_depth);
289 typedef map_info_t* (*t_acquire_my_map_info_list)();
290 typedef void (*t_release_my_map_info_list)(map_info_t* milist);
291 typedef void (*t_get_backtrace_symbols)(const backtrace_frame_t* backtrace,
292 size_t frames,
293 backtrace_symbol_t* symbols);
294 typedef void (*t_free_backtrace_symbols)(backtrace_symbol_t* symbols,
295 size_t frames);
296 #endif
297
298 #endif
299
300 /* Process-wide crash handler structure. */
301 typedef struct native_code_global_struct {
302 /* Initialized. */
303 int initialized;
304
305 /* Lock. */
306 pthread_mutex_t mutex;
307
308 /* Backup of sigaction. */
309 struct sigaction *sa_old;
310 } native_code_global_struct;
311 #define NATIVE_CODE_GLOBAL_INITIALIZER { 0, PTHREAD_MUTEX_INITIALIZER, NULL }
312
313 /* Thread-specific crash handler structure. */
314 typedef struct native_code_handler_struct {
315 /* Restore point context. */
316 sigjmp_buf ctx;
317 int ctx_is_set;
318 int reenter;
319
320 /* Alternate stack. */
321 char *stack_buffer;
322 size_t stack_buffer_size;
323 stack_t stack_old;
324
325 /* Signal code and info. */
326 int code;
327 siginfo_t si;
328 ucontext_t uc;
329
330 /* Uwind context. */
331 #if (defined(USE_CORKSCREW))
332 backtrace_frame_t frames[BACKTRACE_FRAMES_MAX];
333 #elif (defined(USE_UNWIND))
334 uintptr_t frames[BACKTRACE_FRAMES_MAX];
335 #endif
336 #ifdef USE_LIBUNWIND
337 void* uframes[BACKTRACE_FRAMES_MAX];
338 #endif
339 size_t frames_size;
340 size_t frames_skip;
341
342 /* Custom assertion failures. */
343 const char *expression;
344 const char *file;
345 int line;
346
347 /* Alarm was fired. */
348 int alarm;
349 } native_code_handler_struct;
350
351 /* Global crash handler structure. */
352 static native_code_global_struct native_code_g =
353 NATIVE_CODE_GLOBAL_INITIALIZER;
354
355 /* Thread variable holding context. */
356 pthread_key_t native_code_thread;
357
358 #if (defined(USE_UNWIND) && !defined(USE_CORKSCREW))
359 /* Unwind callback */
360 static _Unwind_Reason_Code
361 coffeecatch_unwind_callback(struct _Unwind_Context* context, void* arg) {
362 native_code_handler_struct *const s = (native_code_handler_struct*) arg;
363
364 const uintptr_t ip = _Unwind_GetIP(context);
365
366 DEBUG(print("called unwind callback\n"));
367
368 if (ip != 0x0) {
369 if (s->frames_skip == 0) {
370 s->frames[s->frames_size] = ip;
371 s->frames_size++;
372 } else {
373 s->frames_skip--;
374 }
375 }
376
377 if (s->frames_size == BACKTRACE_FRAMES_MAX) {
378 return _URC_END_OF_STACK;
379 } else {
380 DEBUG(print("returned _URC_OK\n"));
381 return _URC_OK;
382 }
383 }
384 #endif
385
386 /* Use libcorkscrew to get a backtrace inside a signal handler.
387 Will only return a non-zero code on Android >= 4 (with libcorkscrew.so
388 being shipped) */
389 #ifdef USE_CORKSCREW
390 static size_t coffeecatch_backtrace_signal(siginfo_t* si, void* sc,
391 backtrace_frame_t* frames,
392 size_t ignore_depth,
393 size_t max_depth) {
394 void *const libcorkscrew = dlopen("libcorkscrew.so", RTLD_LAZY | RTLD_LOCAL);
395 if (libcorkscrew != NULL) {
396 t_unwind_backtrace_signal_arch unwind_backtrace_signal_arch
397 = (t_unwind_backtrace_signal_arch)
398 dlsym(libcorkscrew, "unwind_backtrace_signal_arch");
399 t_acquire_my_map_info_list acquire_my_map_info_list
400 = (t_acquire_my_map_info_list)
401 dlsym(libcorkscrew, "acquire_my_map_info_list");
402 t_release_my_map_info_list release_my_map_info_list
403 = (t_release_my_map_info_list)
404 dlsym(libcorkscrew, "release_my_map_info_list");
405 if (unwind_backtrace_signal_arch != NULL
406 && acquire_my_map_info_list != NULL
407 && release_my_map_info_list != NULL) {
408 map_info_t*const info = acquire_my_map_info_list();
409 const ssize_t size =
410 unwind_backtrace_signal_arch(si, sc, info, frames, ignore_depth,
411 max_depth);
412 release_my_map_info_list(info);
413 return size >= 0 ? size : 0;
414 } else {
415 DEBUG(print("symbols not found in libcorkscrew.so\n"));
416 }
417 dlclose(libcorkscrew);
418 } else {
419 DEBUG(print("libcorkscrew.so could not be loaded\n"));
420 }
421 return 0;
422 }
423
424 static int coffeecatch_backtrace_symbols(const backtrace_frame_t* backtrace,
425 size_t frames,
426 void (*fun)(void *arg,
427 const backtrace_symbol_t *sym),
428 void *arg) {
429 int success = 0;
430 void *const libcorkscrew = dlopen("libcorkscrew.so", RTLD_LAZY | RTLD_LOCAL);
431 if (libcorkscrew != NULL) {
432 t_get_backtrace_symbols get_backtrace_symbols
433 = (t_get_backtrace_symbols)
434 dlsym(libcorkscrew, "get_backtrace_symbols");
435 t_free_backtrace_symbols free_backtrace_symbols
436 = (t_free_backtrace_symbols)
437 dlsym(libcorkscrew, "free_backtrace_symbols");
438 if (get_backtrace_symbols != NULL
439 && free_backtrace_symbols != NULL) {
440 backtrace_symbol_t symbols[BACKTRACE_FRAMES_MAX];
441 size_t i;
442 if (frames > BACKTRACE_FRAMES_MAX) {
443 frames = BACKTRACE_FRAMES_MAX;
444 }
445 get_backtrace_symbols(backtrace, frames, symbols);
446 for(i = 0; i < frames; i++) {
447 fun(arg, &symbols[i]);
448 }
449 free_backtrace_symbols(symbols, frames);
450 success = 1;
451 } else {
452 DEBUG(print("symbols not found in libcorkscrew.so\n"));
453 }
454 dlclose(libcorkscrew);
455 } else {
456 DEBUG(print("libcorkscrew.so could not be loaded\n"));
457 }
458 return success;
459 }
460 #endif
461
462 /* Use libunwind to get a backtrace inside a signal handler.
463 Will only return a non-zero code on Android >= 5 (with libunwind.so
464 being shipped) */
465 #ifdef USE_LIBUNWIND
466 static ssize_t coffeecatch_unwind_signal(siginfo_t* si, void* sc,
467 void** frames,
468 size_t ignore_depth,
469 size_t max_depth) {
470 void *libunwind = dlopen("libunwind.so", RTLD_LAZY | RTLD_LOCAL);
471 if (libunwind != NULL) {
472 int (*backtrace)(void **buffer, int size) =
473 dlsym(libunwind, "unw_backtrace");
474 if (backtrace != NULL) {
475 int nb = backtrace(frames, max_depth);
476 if (nb > 0) {
477 }
478 return nb;
479 } else {
480 DEBUG(print("symbols not found in libunwind.so\n"));
481 }
482 dlclose(libunwind);
483 } else {
484 DEBUG(print("libunwind.so could not be loaded\n"));
485 }
486 return -1;
487 }
488 #endif
489
490 /* Call the old handler. */
491 static void coffeecatch_call_old_signal_handler(const int code, siginfo_t *const si,
492 void * const sc) {
493 /* Call the "real" Java handler for JIT and internals. */
494 if (code >= 0 && code < SIG_NUMBER_MAX) {
495 if (native_code_g.sa_old[code].sa_sigaction != NULL) {
496 native_code_g.sa_old[code].sa_sigaction(code, si, sc);
497 } else if (native_code_g.sa_old[code].sa_handler != NULL) {
498 native_code_g.sa_old[code].sa_handler(code);
499 }
500 }
501 }
502
503 /* Unflag "on stack" */
504 static void coffeecatch_revert_alternate_stack(void) {
505 #ifndef NO_USE_SIGALTSTACK
506 stack_t ss;
507 if (sigaltstack(NULL, &ss) == 0) {
508 ss.ss_flags &= ~SS_ONSTACK;
509 sigaltstack (&ss, NULL);
510 }
511 #endif
512 }
513
514 /* Try to jump to userland. */
515 static void coffeecatch_try_jump_userland(native_code_handler_struct*
516 const t,
517 const int code,
518 siginfo_t *const si,
519 void * const sc) {
520 (void) si; /* UNUSED */
521 (void) sc; /* UNUSED */
522
523 /* Valid context ? */
524 if (t != NULL && t->ctx_is_set) {
525 DEBUG(print("calling siglongjmp()\n"));
526
527 /* Invalidate the context */
528 t->ctx_is_set = 0;
529
530 /* We need to revert the alternate stack before jumping. */
531 coffeecatch_revert_alternate_stack();
532
533 /*
534 * Note on async-signal-safety of siglongjmp() [POSIX] :
535 * "Note that longjmp() and siglongjmp() are not in the list of
536 * async-signal-safe functions. This is because the code executing after
537 * longjmp() and siglongjmp() can call any unsafe functions with the same
538 * danger as calling those unsafe functions directly from the signal
539 * handler. Applications that use longjmp() and siglongjmp() from within
540 * signal handlers require rigorous protection in order to be portable.
541 * Many of the other functions that are excluded from the list are
542 * traditionally implemented using either malloc() or free() functions or
543 * the standard I/O library, both of which traditionally use data
544 * structures in a non-async-signal-safe manner. Since any combination of
545 * different functions using a common data structure can cause
546 * async-signal-safety problems, this volume of POSIX.1-2008 does not
547 * define the behavior when any unsafe function is called in a signal
548 * handler that interrupts an unsafe function."
549 */
550 siglongjmp(t->ctx, code);
551 }
552 }
553
554 static void coffeecatch_start_alarm(void) {
555 /* Ensure we do not deadlock. Default of ALRM is to die.
556 * (signal() and alarm() are signal-safe) */
557 (void) alarm(30);
558 }
559
560 static void coffeecatch_mark_alarm(native_code_handler_struct *const t) {
561 t->alarm = 1;
562 }
563
564 /* Copy context infos (signal code, etc.) */
565 static void coffeecatch_copy_context(native_code_handler_struct *const t,
566 const int code, siginfo_t *const si,
567 void *const sc) {
568 t->code = code;
569 t->si = *si;
570 if (sc != NULL) {
571 ucontext_t *const uc = (ucontext_t*) sc;
572 t->uc = *uc;
573 } else {
574 memset(&t->uc, 0, sizeof(t->uc));
575 }
576
577 #ifdef USE_UNWIND
578 /* Frame buffer initial position. */
579 t->frames_size = 0;
580
581 /* Skip us and the caller. */
582 t->frames_skip = 2;
583
584 /* Use the corkscrew library to extract the backtrace. */
585 #ifdef USE_CORKSCREW
586 t->frames_size = coffeecatch_backtrace_signal(si, sc, t->frames, 0,
587 BACKTRACE_FRAMES_MAX);
588 #else
589 /* Unwind frames (equivalent to backtrace()) */
590 _Unwind_Backtrace(coffeecatch_unwind_callback, t);
591 #endif
592
593 #ifdef USE_LIBUNWIND
594 if (t->frames_size == 0) {
595 size_t i;
596 t->frames_size = coffeecatch_unwind_signal(si, sc, t->uframes, 0,
597 BACKTRACE_FRAMES_MAX);
598 for(i = 0 ; i < t->frames_size ; i++) {
599 t->frames[i].absolute_pc = (uintptr_t) t->uframes[i];
600 t->frames[i].stack_top = 0;
601 t->frames[i].stack_size = 0;
602 }
603 }
604 #endif
605
606 if (t->frames_size != 0) {
607 DEBUG(print("called _Unwind_Backtrace()\n"));
608 } else {
609 DEBUG(print("called _Unwind_Backtrace(), but no traces\n"));
610 }
611 #endif
612 }
613
614 /* Return the thread-specific native_code_handler_struct structure, or
615 * @c null if no such structure is available. */
616 static native_code_handler_struct* coffeecatch_get() {
617 return (native_code_handler_struct*)
618 pthread_getspecific(native_code_thread);
619 }
620
621 int coffeecatch_cancel_pending_alarm() {
622 native_code_handler_struct *const t = coffeecatch_get();
623 if (t != NULL && t->alarm) {
624 t->alarm = 0;
625 /* "If seconds is 0, a pending alarm request, if any, is canceled." */
626 alarm(0);
627 return 0;
628 }
629 return -1;
630 }
631
632 /* Internal signal pass-through. Allows to peek the "real" crash before
633 * calling the Java handler. Remember than Java needs many of the signals
634 * (for the JIT, for test-free NullPointerException handling, etc.)
635 * We record the siginfo_t context in this function each time it is being
636 * called, to be able to know what error caused an issue.
637 */
638 static void coffeecatch_signal_pass(const int code, siginfo_t *const si,
639 void *const sc) {
640 native_code_handler_struct *t;
641
642 DEBUG(print("caught signal\n"));
643
644 /* Call the "real" Java handler for JIT and internals. */
645 coffeecatch_call_old_signal_handler(code, si, sc);
646
647 /* Still here ?
648 * FIXME TODO: This is the Dalvik behavior - but is it the SunJVM one ? */
649
650 /* Ensure we do not deadlock. Default of ALRM is to die.
651 * (signal() and alarm() are signal-safe) */
652 signal(code, SIG_DFL);
653 coffeecatch_start_alarm();
654
655 /* Available context ? */
656 t = coffeecatch_get();
657 if (t != NULL) {
658 /* An alarm() call was triggered. */
659 coffeecatch_mark_alarm(t);
660
661 /* Take note of the signal. */
662 coffeecatch_copy_context(t, code, si, sc);
663
664 /* Back to the future. */
665 coffeecatch_try_jump_userland(t, code, si, sc);
666 }
667
668 /* Nope. (abort() is signal-safe) */
669 DEBUG(print("calling abort()\n"));
670 signal(SIGABRT, SIG_DFL);
671 abort();
672 }
673
674 /* Internal crash handler for abort(). Java calls abort() if its signal handler
675 * could not resolve the signal ; thus calling us through this handler. */
676 static void coffeecatch_signal_abort(const int code, siginfo_t *const si,
677 void *const sc) {
678 native_code_handler_struct *t;
679
680 (void) sc; /* UNUSED */
681
682 DEBUG(print("caught abort\n"));
683
684 /* Ensure we do not deadlock. Default of ALRM is to die.
685 * (signal() and alarm() are signal-safe) */
686 signal(code, SIG_DFL);
687 coffeecatch_start_alarm();
688
689 /* Available context ? */
690 t = coffeecatch_get();
691 if (t != NULL) {
692 /* An alarm() call was triggered. */
693 coffeecatch_mark_alarm(t);
694
695 /* Take note (real "abort()") */
696 coffeecatch_copy_context(t, code, si, sc);
697
698 /* Back to the future. */
699 coffeecatch_try_jump_userland(t, code, si, sc);
700 }
701
702 /* No such restore point, call old signal handler then. */
703 DEBUG(print("calling old signal handler\n"));
704 coffeecatch_call_old_signal_handler(code, si, sc);
705
706 /* Nope. (abort() is signal-safe) */
707 DEBUG(print("calling abort()\n"));
708 abort();
709 }
710
711 /* Internal globals initialization. */
712 static int coffeecatch_handler_setup_global(void) {
713 if (native_code_g.initialized++ == 0) {
714 size_t i;
715 struct sigaction sa_abort;
716 struct sigaction sa_pass;
717
718 DEBUG(print("installing global signal handlers\n"));
719
720 /* Setup handler structure. */
721 memset(&sa_abort, 0, sizeof(sa_abort));
722 sigemptyset(&sa_abort.sa_mask);
723 sa_abort.sa_sigaction = coffeecatch_signal_abort;
724 sa_abort.sa_flags = SA_SIGINFO | SA_ONSTACK;
725
726 memset(&sa_pass, 0, sizeof(sa_pass));
727 sigemptyset(&sa_pass.sa_mask);
728 sa_pass.sa_sigaction = coffeecatch_signal_pass;
729 sa_pass.sa_flags = SA_SIGINFO | SA_ONSTACK;
730
731 /* Allocate */
732 native_code_g.sa_old = calloc(sizeof(struct sigaction), SIG_NUMBER_MAX);
733 if (native_code_g.sa_old == NULL) {
734 return -1;
735 }
736
737 /* Setup signal handlers for SIGABRT (Java calls abort()) and others. **/
738 for (i = 0; native_sig_catch[i] != 0; i++) {
739 const int sig = native_sig_catch[i];
740 const struct sigaction * const action =
741 sig == SIGABRT ? &sa_abort : &sa_pass;
742 assert(sig < SIG_NUMBER_MAX);
743 if (sigaction(sig, action, &native_code_g.sa_old[sig]) != 0) {
744 return -1;
745 }
746 }
747
748 /* Initialize thread var. */
749 if (pthread_key_create(&native_code_thread, NULL) != 0) {
750 return -1;
751 }
752
753 DEBUG(print("installed global signal handlers\n"));
754 }
755
756 /* OK. */
757 return 0;
758 }
759
760 /**
761 * Free a native_code_handler_struct structure.
762 **/
763 static int coffeecatch_native_code_handler_struct_free(native_code_handler_struct *const t) {
764 int code = 0;
765
766 if (t == NULL) {
767 return -1;
768 }
769
770 #ifndef NO_USE_SIGALTSTACK
771 /* Restore previous alternative stack. */
772 if (t->stack_old.ss_sp != NULL && sigaltstack(&t->stack_old, NULL) != 0) {
773 #ifndef USE_SILENT_SIGALTSTACK
774 code = -1;
775 #endif
776 }
777 #endif
778
779 /* Free alternative stack */
780 if (t->stack_buffer != NULL) {
781 free(t->stack_buffer);
782 t->stack_buffer = NULL;
783 t->stack_buffer_size = 0;
784 }
785
786 /* Free structure. */
787 free(t);
788
789 return code;
790 }
791
792 /**
793 * Create a native_code_handler_struct structure.
794 **/
795 static native_code_handler_struct* coffeecatch_native_code_handler_struct_init(void) {
796 stack_t stack;
797 native_code_handler_struct *const t =
798 calloc(sizeof(native_code_handler_struct), 1);
799
800 if (t == NULL) {
801 return NULL;
802 }
803
804 DEBUG(print("installing thread alternative stack\n"));
805
806 /* Initialize structure */
807 t->stack_buffer_size = SIG_STACK_BUFFER_SIZE;
808 t->stack_buffer = malloc(t->stack_buffer_size);
809 if (t->stack_buffer == NULL) {
810 coffeecatch_native_code_handler_struct_free(t);
811 return NULL;
812 }
813
814 /* Setup alternative stack. */
815 memset(&stack, 0, sizeof(stack));
816 stack.ss_sp = t->stack_buffer;
817 stack.ss_size = t->stack_buffer_size;
818 stack.ss_flags = 0;
819
820 #ifndef NO_USE_SIGALTSTACK
821 /* Install alternative stack. This is thread-safe */
822 if (sigaltstack(&stack, &t->stack_old) != 0) {
823 #ifndef USE_SILENT_SIGALTSTACK
824 coffeecatch_native_code_handler_struct_free(t);
825 return NULL;
826 #endif
827 }
828 #endif
829
830 return t;
831 }
832
833 /**
834 * Acquire the crash handler for the current thread.
835 * The coffeecatch_handler_cleanup() must be called to release allocated
836 * resources.
837 **/
838 static int coffeecatch_handler_setup(int setup_thread) {
839 int code;
840
841 DEBUG(print("setup for a new handler\n"));
842
843 /* Initialize globals. */
844 if (pthread_mutex_lock(&native_code_g.mutex) != 0) {
845 return -1;
846 }
847 code = coffeecatch_handler_setup_global();
848 if (pthread_mutex_unlock(&native_code_g.mutex) != 0) {
849 return -1;
850 }
851
852 /* Global initialization failed. */
853 if (code != 0) {
854 return -1;
855 }
856
857 /* Initialize locals. */
858 if (setup_thread && coffeecatch_get() == NULL) {
859 native_code_handler_struct *const t =
860 coffeecatch_native_code_handler_struct_init();
861
862 if (t == NULL) {
863 return -1;
864 }
865
866 DEBUG(print("installing thread alternative stack\n"));
867
868 /* Set thread-specific value. */
869 if (pthread_setspecific(native_code_thread, t) != 0) {
870 coffeecatch_native_code_handler_struct_free(t);
871 return -1;
872 }
873
874 DEBUG(print("installed thread alternative stack\n"));
875 }
876
877 /* OK. */
878 return 0;
879 }
880
881 /**
882 * Release the resources allocated by a previous call to
883 * coffeecatch_handler_setup().
884 * This function must be called as many times as
885 * coffeecatch_handler_setup() was called to fully release allocated
886 * resources.
887 **/
888 static int coffeecatch_handler_cleanup() {
889 /* Cleanup locals. */
890 native_code_handler_struct *const t = coffeecatch_get();
891 if (t != NULL) {
892 DEBUG(print("removing thread alternative stack\n"));
893
894 /* Erase thread-specific value now (detach). */
895 if (pthread_setspecific(native_code_thread, NULL) != 0) {
896 assert(! "pthread_setspecific() failed");
897 }
898
899 /* Free handler and reset slternate stack */
900 if (coffeecatch_native_code_handler_struct_free(t) != 0) {
901 return -1;
902 }
903
904 DEBUG(print("removed thread alternative stack\n"));
905 }
906
907 /* Cleanup globals. */
908 if (pthread_mutex_lock(&native_code_g.mutex) != 0) {
909 assert(! "pthread_mutex_lock() failed");
910 }
911 assert(native_code_g.initialized != 0);
912 if (--native_code_g.initialized == 0) {
913 size_t i;
914
915 DEBUG(print("removing global signal handlers\n"));
916
917 /* Restore signal handler. */
918 for(i = 0; native_sig_catch[i] != 0; i++) {
919 const int sig = native_sig_catch[i];
920 assert(sig < SIG_NUMBER_MAX);
921 if (sigaction(sig, &native_code_g.sa_old[sig], NULL) != 0) {
922 return -1;
923 }
924 }
925
926 /* Free old structure. */
927 free(native_code_g.sa_old);
928 native_code_g.sa_old = NULL;
929
930 /* Delete thread var. */
931 if (pthread_key_delete(native_code_thread) != 0) {
932 assert(! "pthread_key_delete() failed");
933 }
934
935 DEBUG(print("removed global signal handlers\n"));
936 }
937 if (pthread_mutex_unlock(&native_code_g.mutex) != 0) {
938 assert(! "pthread_mutex_unlock() failed");
939 }
940
941 return 0;
942 }
943
944 /**
945 * Get the signal associated with the crash.
946 */
947 int coffeecatch_get_signal() {
948 const native_code_handler_struct* const t = coffeecatch_get();
949 if (t != NULL) {
950 return t->code;
951 } else {
952 return -1;
953 }
954 }
955
956 /* Signal descriptions.
957 See <http://pubs.opengroup.org/onlinepubs/009696699/basedefs/signal.h.html>
958 */
959 static const char* coffeecatch_desc_sig(int sig, int code) {
960 switch(sig) {
961 case SIGILL:
962 switch(code) {
963 case ILL_ILLOPC:
964 return "Illegal opcode";
965 case ILL_ILLOPN:
966 return "Illegal operand";
967 case ILL_ILLADR:
968 return "Illegal addressing mode";
969 case ILL_ILLTRP:
970 return "Illegal trap";
971 case ILL_PRVOPC:
972 return "Privileged opcode";
973 case ILL_PRVREG:
974 return "Privileged register";
975 case ILL_COPROC:
976 return "Coprocessor error";
977 case ILL_BADSTK:
978 return "Internal stack error";
979 default:
980 return "Illegal operation";
981 }
982 break;
983 case SIGFPE:
984 switch(code) {
985 case FPE_INTDIV:
986 return "Integer divide by zero";
987 case FPE_INTOVF:
988 return "Integer overflow";
989 case FPE_FLTDIV:
990 return "Floating-point divide by zero";
991 case FPE_FLTOVF:
992 return "Floating-point overflow";
993 case FPE_FLTUND:
994 return "Floating-point underflow";
995 case FPE_FLTRES:
996 return "Floating-point inexact result";
997 case FPE_FLTINV:
998 return "Invalid floating-point operation";
999 case FPE_FLTSUB:
1000 return "Subscript out of range";
1001 default:
1002 return "Floating-point";
1003 }
1004 break;
1005 case SIGSEGV:
1006 switch(code) {
1007 case SEGV_MAPERR:
1008 return "Address not mapped to object";
1009 case SEGV_ACCERR:
1010 return "Invalid permissions for mapped object";
1011 default:
1012 return "Segmentation violation";
1013 }
1014 break;
1015 case SIGBUS:
1016 switch(code) {
1017 case BUS_ADRALN:
1018 return "Invalid address alignment";
1019 case BUS_ADRERR:
1020 return "Nonexistent physical address";
1021 case BUS_OBJERR:
1022 return "Object-specific hardware error";
1023 default:
1024 return "Bus error";
1025 }
1026 break;
1027 case SIGTRAP:
1028 switch(code) {
1029 case TRAP_BRKPT:
1030 return "Process breakpoint";
1031 case TRAP_TRACE:
1032 return "Process trace trap";
1033 default:
1034 return "Trap";
1035 }
1036 break;
1037 case SIGCHLD:
1038 switch(code) {
1039 case CLD_EXITED:
1040 return "Child has exited";
1041 case CLD_KILLED:
1042 return "Child has terminated abnormally and did not create a core file";
1043 case CLD_DUMPED:
1044 return "Child has terminated abnormally and created a core file";
1045 case CLD_TRAPPED:
1046 return "Traced child has trapped";
1047 case CLD_STOPPED:
1048 return "Child has stopped";
1049 case CLD_CONTINUED:
1050 return "Stopped child has continued";
1051 default:
1052 return "Child";
1053 }
1054 break;
1055 case SIGPOLL:
1056 switch(code) {
1057 case POLL_IN:
1058 return "Data input available";
1059 case POLL_OUT:
1060 return "Output buffers available";
1061 case POLL_MSG:
1062 return "Input message available";
1063 case POLL_ERR:
1064 return "I/O error";
1065 case POLL_PRI:
1066 return "High priority input available";
1067 case POLL_HUP:
1068 return "Device disconnected";
1069 default:
1070 return "Pool";
1071 }
1072 break;
1073 case SIGABRT:
1074 return "Process abort signal";
1075 case SIGALRM:
1076 return "Alarm clock";
1077 case SIGCONT:
1078 return "Continue executing, if stopped";
1079 case SIGHUP:
1080 return "Hangup";
1081 case SIGINT:
1082 return "Terminal interrupt signal";
1083 case SIGKILL:
1084 return "Kill";
1085 case SIGPIPE:
1086 return "Write on a pipe with no one to read it";
1087 case SIGQUIT:
1088 return "Terminal quit signal";
1089 case SIGSTOP:
1090 return "Stop executing";
1091 case SIGTERM:
1092 return "Termination signal";
1093 case SIGTSTP:
1094 return "Terminal stop signal";
1095 case SIGTTIN:
1096 return "Background process attempting read";
1097 case SIGTTOU:
1098 return "Background process attempting write";
1099 case SIGUSR1:
1100 return "User-defined signal 1";
1101 case SIGUSR2:
1102 return "User-defined signal 2";
1103 case SIGPROF:
1104 return "Profiling timer expired";
1105 case SIGSYS:
1106 return "Bad system call";
1107 case SIGVTALRM:
1108 return "Virtual timer expired";
1109 case SIGURG:
1110 return "High bandwidth data is available at a socket";
1111 case SIGXCPU:
1112 return "CPU time limit exceeded";
1113 case SIGXFSZ:
1114 return "File size limit exceeded";
1115 default:
1116 switch(code) {
1117 case SI_USER:
1118 return "Signal sent by kill()";
1119 case SI_QUEUE:
1120 return "Signal sent by the sigqueue()";
1121 case SI_TIMER:
1122 return "Signal generated by expiration of a timer set by timer_settime()";
1123 case SI_ASYNCIO:
1124 return "Signal generated by completion of an asynchronous I/O request";
1125 case SI_MESGQ:
1126 return
1127 "Signal generated by arrival of a message on an empty message queue";
1128 default:
1129 return "Unknown signal";
1130 }
1131 break;
1132 }
1133 }
1134
1135 /**
1136 * Get the backtrace size. Returns 0 if no backtrace is available.
1137 */
1138 size_t coffeecatch_get_backtrace_size(void) {
1139 #ifdef USE_UNWIND
1140 const native_code_handler_struct* const t = coffeecatch_get();
1141 if (t != NULL) {
1142 return t->frames_size;
1143 } else {
1144 return 0;
1145 }
1146 #else
1147 return 0;
1148 #endif
1149 }
1150
1151 /**
1152 * Get the <index>th element of the backtrace, or 0 upon error.
1153 */
1154 uintptr_t coffeecatch_get_backtrace(ssize_t index) {
1155 #ifdef USE_UNWIND
1156 const native_code_handler_struct* const t = coffeecatch_get();
1157 if (t != NULL) {
1158 if (index < 0) {
1159 index = t->frames_size + index;
1160 }
1161 if (index >= 0 && (size_t) index < t->frames_size) {
1162 #ifdef USE_CORKSCREW
1163 return t->frames[index].absolute_pc;
1164 #else
1165 return t->frames[index];
1166 #endif
1167 }
1168 }
1169 #else
1170 (void) index;
1171 #endif
1172 return 0;
1173 }
1174
1175 /**
1176 * Get the program counter, given a pointer to a ucontext_t context.
1177 **/
1178 static uintptr_t coffeecatch_get_pc_from_ucontext(const ucontext_t *uc) {
1179 #if (defined(__arm__))
1180 return uc->uc_mcontext.arm_pc;
1181 #elif defined(__aarch64__)
1182 return uc->uc_mcontext.pc;
1183 #elif (defined(__x86_64__))
1184 return uc->uc_mcontext.gregs[REG_RIP];
1185 #elif (defined(__i386))
1186 return uc->uc_mcontext.gregs[REG_EIP];
1187 #elif (defined (__ppc__)) || (defined (__powerpc__))
1188 return uc->uc_mcontext.regs->nip;
1189 #elif (defined(__hppa__))
1190 return uc->uc_mcontext.sc_iaoq[0] & ~0x3UL;
1191 #elif (defined(__sparc__) && defined (__arch64__))
1192 return uc->uc_mcontext.mc_gregs[MC_PC];
1193 #elif (defined(__sparc__) && !defined (__arch64__))
1194 return uc->uc_mcontext.gregs[REG_PC];
1195 #elif (defined(__mips__))
1196 return uc->uc_mcontext.gregs[31];
1197 #else
1198 #error "Architecture is unknown, please report me!"
1199 #endif
1200 }
1201
1202 /* Is this module name look like a DLL ?
1203 FIXME: find a better way to do that... */
1204 static int coffeecatch_is_dll(const char *name) {
1205 size_t i;
1206 for(i = 0; name[i] != '\0'; i++) {
1207 if (name[i + 0] == '.' &&
1208 name[i + 1] == 's' &&
1209 name[i + 2] == 'o' &&
1210 ( name[i + 3] == '\0' || name[i + 3] == '.') ) {
1211 return 1;
1212 }
1213 }
1214 return 0;
1215 }
1216
1217 /* Extract a line information on a PC address. */
1218 static void format_pc_address_cb(uintptr_t pc,
1219 void (*fun)(void *arg, const char *module,
1220 uintptr_t addr,
1221 const char *function,
1222 uintptr_t offset), void *arg) {
1223 if (pc != 0) {
1224 Dl_info info;
1225 void * const addr = (void*) pc;
1226 /* dladdr() returns 0 on error, and nonzero on success. */
1227 if (dladdr(addr, &info) != 0 && info.dli_fname != NULL) {
1228 const uintptr_t near = (uintptr_t) info.dli_saddr;
1229 const uintptr_t offs = pc - near;
1230 const uintptr_t addr_rel = pc - (uintptr_t) info.dli_fbase;
1231 /* We need the absolute address for the main module (?).
1232 TODO FIXME to be investigated. */
1233 const uintptr_t addr_to_use = coffeecatch_is_dll(info.dli_fname)
1234 ? addr_rel : pc;
1235 fun(arg, info.dli_fname, addr_to_use, info.dli_sname, offs);
1236 } else {
1237 fun(arg, NULL, pc, NULL, 0);
1238 }
1239 }
1240 }
1241
1242 typedef struct t_print_fun {
1243 char *buffer;
1244 size_t buffer_size;
1245 } t_print_fun;
1246
1247 static void print_fun(void *arg, const char *module, uintptr_t uaddr,
1248 const char *function, uintptr_t offset) {
1249 t_print_fun *const t = (t_print_fun*) arg;
1250 char *const buffer = t->buffer;
1251 const size_t buffer_size = t->buffer_size;
1252 const void*const addr = (void*) uaddr;
1253 if (module == NULL) {
1254 snprintf(buffer, buffer_size, "[at %p]", addr);
1255 } else if (function != NULL) {
1256 snprintf(buffer, buffer_size, "[at %s:%p (%s+0x%x)]", module, addr,
1257 function, (int) offset);
1258 } else {
1259 snprintf(buffer, buffer_size, "[at %s:%p]", module, addr);
1260 }
1261 }
1262
1263 /* Format a line information on a PC address. */
1264 static void format_pc_address(char *buffer, size_t buffer_size, uintptr_t pc) {
1265 t_print_fun t;
1266 t.buffer = buffer;
1267 t.buffer_size = buffer_size;
1268 format_pc_address_cb(pc, print_fun, &t);
1269 }
1270
1271 /**
1272 * Get the full error message associated with the crash.
1273 */
1274 const char* coffeecatch_get_message() {
1275 const int error = errno;
1276 const native_code_handler_struct* const t = coffeecatch_get();
1277
1278 /* Found valid handler. */
1279 if (t != NULL) {
1280 char * const buffer = t->stack_buffer;
1281 const size_t buffer_len = t->stack_buffer_size;
1282 size_t buffer_offs = 0;
1283
1284 const char* const posix_desc =
1285 coffeecatch_desc_sig(t->si.si_signo, t->si.si_code);
1286
1287 /* Assertion failure ? */
1288 if ((t->code == SIGABRT
1289 #ifdef __ANDROID__
1290 /* See Android BUG #16672:
1291 * "C assert() failure causes SIGSEGV when it should cause SIGABRT" */
1292 || (t->code == SIGSEGV && (uintptr_t) t->si.si_addr == 0xdeadbaad)
1293 #endif
1294 ) && t->expression != NULL) {
1295 snprintf(&buffer[buffer_offs], buffer_len - buffer_offs,
1296 "assertion '%s' failed at %s:%d",
1297 t->expression, t->file, t->line);
1298 buffer_offs += strlen(&buffer[buffer_offs]);
1299 }
1300 /* Signal */
1301 else {
1302 snprintf(&buffer[buffer_offs], buffer_len - buffer_offs, "signal %d",
1303 t->si.si_signo);
1304 buffer_offs += strlen(&buffer[buffer_offs]);
1305
1306 /* Description */
1307 snprintf(&buffer[buffer_offs], buffer_len - buffer_offs, " (%s)",
1308 posix_desc);
1309 buffer_offs += strlen(&buffer[buffer_offs]);
1310
1311 /* Address of faulting instruction */
1312 if (t->si.si_signo == SIGILL || t->si.si_signo == SIGSEGV) {
1313 snprintf(&buffer[buffer_offs], buffer_len - buffer_offs, " at address %p",
1314 t->si.si_addr);
1315 buffer_offs += strlen(&buffer[buffer_offs]);
1316 }
1317 }
1318
1319 /* [POSIX] If non-zero, an errno value associated with this signal,
1320 as defined in <errno.h>. */
1321 if (t->si.si_errno != 0) {
1322 snprintf(&buffer[buffer_offs], buffer_len - buffer_offs, ": ");
1323 buffer_offs += strlen(&buffer[buffer_offs]);
1324 if (strerror_r(t->si.si_errno, &buffer[buffer_offs],
1325 buffer_len - buffer_offs) == 0) {
1326 snprintf(&buffer[buffer_offs], buffer_len - buffer_offs,
1327 "unknown error");
1328 buffer_offs += strlen(&buffer[buffer_offs]);
1329 }
1330 }
1331
1332 /* Sending process ID. */
1333 if (t->si.si_signo == SIGCHLD && t->si.si_pid != 0) {
1334 snprintf(&buffer[buffer_offs], buffer_len - buffer_offs,
1335 " (sent by pid %d)", (int) t->si.si_pid);
1336 buffer_offs += strlen(&buffer[buffer_offs]);
1337 }
1338
1339 /* Faulting program counter location. */
1340 if (coffeecatch_get_pc_from_ucontext(&t->uc) != 0) {
1341 const uintptr_t pc = coffeecatch_get_pc_from_ucontext(&t->uc);
1342 snprintf(&buffer[buffer_offs], buffer_len - buffer_offs, " ");
1343 buffer_offs += strlen(&buffer[buffer_offs]);
1344 format_pc_address(&buffer[buffer_offs], buffer_len - buffer_offs, pc);
1345 buffer_offs += strlen(&buffer[buffer_offs]);
1346 }
1347
1348 /* Return string. */
1349 buffer[buffer_offs] = '\0';
1350 return t->stack_buffer;
1351 } else {
1352 /* Static buffer in case of emergency */
1353 static char buffer[256];
1354 #ifdef _GNU_SOURCE
1355 return strerror_r(error, &buffer[0], sizeof(buffer));
1356 #else
1357 const int code = strerror_r(error, &buffer[0], sizeof(buffer));
1358 errno = error;
1359 if (code == 0) {
1360 return buffer;
1361 } else {
1362 return "unknown error during crash handler setup";
1363 }
1364 #endif
1365 }
1366 }
1367
1368 #if (defined(USE_CORKSCREW))
1369 typedef struct t_coffeecatch_backtrace_symbols_fun {
1370 void (*fun)(void *arg, const char *module, uintptr_t addr,
1371 const char *function, uintptr_t offset);
1372 void *arg;
1373 } t_coffeecatch_backtrace_symbols_fun;
1374
1375 static void coffeecatch_backtrace_symbols_fun(void *arg, const backtrace_symbol_t *sym) {
1376 t_coffeecatch_backtrace_symbols_fun *const bt =
1377 (t_coffeecatch_backtrace_symbols_fun*) arg;
1378 const char *symbol = sym->demangled_name != NULL
1379 ? sym->demangled_name : sym->symbol_name;
1380 const uintptr_t rel = sym->relative_pc - sym->relative_symbol_addr;
1381 bt->fun(bt->arg, sym->map_name, sym->relative_pc, symbol, rel);
1382 }
1383 #endif
1384
1385 /**
1386 * Enumerate backtrace information.
1387 */
1388 void coffeecatch_get_backtrace_info(void (*fun)(void *arg,
1389 const char *module,
1390 uintptr_t addr,
1391 const char *function,
1392 uintptr_t offset), void *arg) {
1393 const native_code_handler_struct* const t = coffeecatch_get();
1394 if (t != NULL) {
1395 size_t i;
1396 #if (defined(USE_CORKSCREW))
1397 t_coffeecatch_backtrace_symbols_fun bt;
1398 bt.fun = fun;
1399 bt.arg = arg;
1400 if (coffeecatch_backtrace_symbols(t->frames, t->frames_size,
1401 coffeecatch_backtrace_symbols_fun,
1402 &bt)) {
1403 return;
1404 }
1405 #endif
1406 for(i = 0; i < t->frames_size; i++) {
1407 const uintptr_t pc = t->frames[i].absolute_pc;
1408 format_pc_address_cb(pc, fun, arg);
1409 }
1410 }
1411 }
1412
1413 /**
1414 * Returns 1 if we are already inside a coffeecatch block, 0 otherwise.
1415 */
1416 int coffeecatch_inside() {
1417 native_code_handler_struct *const t = coffeecatch_get();
1418 if (t != NULL && t->reenter > 0) {
1419 t->reenter++;
1420 return 1;
1421 }
1422 return 0;
1423 }
1424
1425 /**
1426 * Calls coffeecatch_handler_setup(1) to setup a crash handler, mark the
1427 * context as valid, and return 0 upon success.
1428 */
1429 int coffeecatch_setup() {
1430 if (coffeecatch_handler_setup(1) == 0) {
1431 native_code_handler_struct *const t = coffeecatch_get();
1432 assert(t != NULL);
1433 assert(t->reenter == 0);
1434 t->reenter = 1;
1435 t->ctx_is_set = 1;
1436 return 0;
1437 } else {
1438 return -1;
1439 }
1440 }
1441
1442 /**
1443 * Calls coffeecatch_handler_cleanup()
1444 */
1445 void coffeecatch_cleanup() {
1446 native_code_handler_struct *const t = coffeecatch_get();
1447 assert(t != NULL);
1448 assert(t->reenter > 0);
1449 t->reenter--;
1450 if (t->reenter == 0) {
1451 t->ctx_is_set = 0;
1452 coffeecatch_handler_cleanup();
1453 }
1454 }
1455
1456 sigjmp_buf* coffeecatch_get_ctx() {
1457 native_code_handler_struct* t = coffeecatch_get();
1458 assert(t != NULL);
1459 return &t->ctx;
1460 }
1461
1462 void coffeecatch_abort(const char* exp, const char* file, int line) {
1463 native_code_handler_struct *const t = coffeecatch_get();
1464 if (t != NULL) {
1465 t->expression = exp;
1466 t->file = file;
1467 t->line = line;
1468 }
1469 abort();
1470 }

   
Visit the ZANavi Wiki