diff --git a/android/LICENSE_COFFEECATCH b/android/LICENSE_COFFEECATCH deleted file mode 100644 index 1a44ae19c..000000000 --- a/android/LICENSE_COFFEECATCH +++ /dev/null @@ -1,23 +0,0 @@ -Copyright (c) 2013, Xavier Roche (http://www.httrack.com/) -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. - -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 THE COPYRIGHT HOLDER 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. diff --git a/android/cpp/coffeecatch.c b/android/cpp/coffeecatch.c deleted file mode 100644 index c5428aedc..000000000 --- a/android/cpp/coffeecatch.c +++ /dev/null @@ -1,1215 +0,0 @@ -/* CoffeeCatch, a tiny native signal handler/catcher for JNI code. - * (especially for Android/Dalvik) - * - * Copyright (c) 2013, Xavier Roche (http://www.httrack.com/) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. 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. - * - * 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 THE COPYRIGHT OWNER 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. - */ - -#ifdef __ANDROID__ -#define USE_UNWIND -#define USE_CORKSCREW -#endif - -/* #undef NO_USE_SIGALTSTACK */ -/* #undef USE_SILENT_SIGALTSTACK */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if (defined(USE_UNWIND) && !defined(USE_CORKSCREW)) -#include -#endif -#include -#include -#include - -/*#define NDK_DEBUG 1*/ -#if ( defined(NDK_DEBUG) && ( NDK_DEBUG == 1 ) ) -#define DEBUG(A) do { A; } while(0) -#define FD_ERRNO 2 -static void print(const char *const s) { - size_t count; - for(count = 0; s[count] != '\0'; count++) ; - /* write() is async-signal-safe. */ - (void) write(FD_ERRNO, s, count); -} -#else -#define DEBUG(A) -#endif - -/* Alternative stack size. */ -#define SIG_STACK_BUFFER_SIZE SIGSTKSZ - -#ifdef USE_UNWIND -/* Number of backtraces to get. */ -#define BACKTRACE_FRAMES_MAX 32 -#endif - -/* Signals to be caught. */ -#define SIG_CATCH_COUNT 7 -static const int native_sig_catch[SIG_CATCH_COUNT + 1] - = { SIGABRT, SIGILL, SIGTRAP, SIGBUS, SIGFPE, SIGSEGV -#ifdef SIGSTKFLT - , SIGSTKFLT -#endif - , 0 }; - -/* Maximum value of a caught signal. */ -#define SIG_NUMBER_MAX 32 - -#ifdef USE_CORKSCREW -typedef struct map_info_t map_info_t; -/* Extracted from Android's include/corkscrew/backtrace.h */ -typedef struct { - uintptr_t absolute_pc; - uintptr_t stack_top; - size_t stack_size; -} backtrace_frame_t; -typedef struct { - uintptr_t relative_pc; - uintptr_t relative_symbol_addr; - char* map_name; - char* symbol_name; - char* demangled_name; -} backtrace_symbol_t; -/* Extracted from Android's libcorkscrew/arch-arm/backtrace-arm.c */ -typedef ssize_t (*t_unwind_backtrace_signal_arch) -(siginfo_t* si, void* sc, const map_info_t* lst, backtrace_frame_t* bt, -size_t ignore_depth, size_t max_depth); -typedef map_info_t* (*t_acquire_my_map_info_list)(); -typedef void (*t_release_my_map_info_list)(map_info_t* milist); -typedef void (*t_get_backtrace_symbols)(const backtrace_frame_t* backtrace, - size_t frames, - backtrace_symbol_t* symbols); -typedef void (*t_free_backtrace_symbols)(backtrace_symbol_t* symbols, - size_t frames); -#endif - -/* Process-wide crash handler structure. */ -typedef struct native_code_global_struct { - /* Initialized. */ - int initialized; - - /* Lock. */ - pthread_mutex_t mutex; - - /* Backup of sigaction. */ - struct sigaction *sa_old; -} native_code_global_struct; -#define NATIVE_CODE_GLOBAL_INITIALIZER { 0, PTHREAD_MUTEX_INITIALIZER, NULL } - -/* Thread-specific crash handler structure. */ -typedef struct native_code_handler_struct { - /* Restore point context. */ - sigjmp_buf ctx; - int ctx_is_set; - - /* Alternate stack. */ - char *stack_buffer; - size_t stack_buffer_size; - stack_t stack_old; - - /* Signal code and info. */ - int code; - siginfo_t si; - ucontext_t uc; - - /* Uwind context. */ -#if (defined(USE_CORKSCREW)) - backtrace_frame_t frames[BACKTRACE_FRAMES_MAX]; -#elif (defined(USE_UNWIND)) - uintptr_t frames[BACKTRACE_FRAMES_MAX]; -#endif - size_t frames_size; - size_t frames_skip; - - /* Custom assertion failures. */ - const char *expression; - const char *file; - int line; - - /* Alarm was fired. */ - int alarm; -} native_code_handler_struct; - -/* Global crash handler structure. */ -static native_code_global_struct native_code_g = - NATIVE_CODE_GLOBAL_INITIALIZER; - -/* Thread variable holding context. */ -pthread_key_t native_code_thread; - -#if (defined(USE_UNWIND) && !defined(USE_CORKSCREW)) -/* Unwind callback */ -static _Unwind_Reason_Code -coffeecatch_unwind_callback(struct _Unwind_Context* context, void* arg) { - native_code_handler_struct *const s = (native_code_handler_struct*) arg; - - const uintptr_t ip = _Unwind_GetIP(context); - - DEBUG(print("called unwind callback\n")); - - if (ip != 0x0) { - if (s->frames_skip == 0) { - s->frames[s->frames_size] = ip; - s->frames_size++; - } else { - s->frames_skip--; - } - } - - if (s->frames_size == BACKTRACE_FRAMES_MAX) { - return _URC_END_OF_STACK; - } else { - DEBUG(print("returned _URC_OK\n")); - return _URC_OK; - } -} -#endif - -/* Use libcorkscrew to get a backtrace inside a signal handler. - Will only return a non-zero code on Android >= 4 (with libcorkscrew.so - being shipped) */ -#ifdef USE_CORKSCREW -static ssize_t coffeecatch_backtrace_signal(siginfo_t* si, void* sc, - backtrace_frame_t* frames, - size_t ignore_depth, - size_t max_depth) { - void *const libcorkscrew = dlopen("libcorkscrew.so", RTLD_LAZY | RTLD_LOCAL); - if (libcorkscrew != NULL) { - t_unwind_backtrace_signal_arch unwind_backtrace_signal_arch - = (t_unwind_backtrace_signal_arch) - dlsym(libcorkscrew, "unwind_backtrace_signal_arch"); - t_acquire_my_map_info_list acquire_my_map_info_list - = (t_acquire_my_map_info_list) - dlsym(libcorkscrew, "acquire_my_map_info_list"); - t_release_my_map_info_list release_my_map_info_list - = (t_release_my_map_info_list) - dlsym(libcorkscrew, "release_my_map_info_list"); - if (unwind_backtrace_signal_arch != NULL - && acquire_my_map_info_list != NULL - && release_my_map_info_list != NULL) { - map_info_t*const info = acquire_my_map_info_list(); - const ssize_t size = - unwind_backtrace_signal_arch(si, sc, info, frames, ignore_depth, - max_depth); - release_my_map_info_list(info); - return size; - } else { - DEBUG(print("symbols not founs in libcorkscrew.so\n")); - } - dlclose(libcorkscrew); - } else { - DEBUG(print("libcorkscrew.so could not be loaded\n")); - } - return -1; -} - -static void coffeecatch_backtrace_symbols(const backtrace_frame_t* backtrace, - size_t frames, - void (*fun)(void *arg, - const backtrace_symbol_t *sym), - void *arg) { - void *const libcorkscrew = dlopen("libcorkscrew.so", RTLD_LAZY | RTLD_LOCAL); - if (libcorkscrew != NULL) { - t_get_backtrace_symbols get_backtrace_symbols - = (t_get_backtrace_symbols) - dlsym(libcorkscrew, "get_backtrace_symbols"); - t_free_backtrace_symbols free_backtrace_symbols - = (t_free_backtrace_symbols) - dlsym(libcorkscrew, "free_backtrace_symbols"); - if (get_backtrace_symbols != NULL - && free_backtrace_symbols != NULL) { - backtrace_symbol_t symbols[BACKTRACE_FRAMES_MAX]; - size_t i; - if (frames > BACKTRACE_FRAMES_MAX) { - frames = BACKTRACE_FRAMES_MAX; - } - get_backtrace_symbols(backtrace, frames, symbols); - for(i = 0; i < frames; i++) { - fun(arg, &symbols[i]); - } - free_backtrace_symbols(symbols, frames); - } - dlclose(libcorkscrew); - } -} -#endif - -/* Call the old handler. */ -static void coffeecatch_call_old_signal_handler(const int code, siginfo_t *const si, - void * const sc) { - /* Call the "real" Java handler for JIT and internals. */ - if (code >= 0 && code < SIG_NUMBER_MAX) { - if (native_code_g.sa_old[code].sa_sigaction != NULL) { - native_code_g.sa_old[code].sa_sigaction(code, si, sc); - } else if (native_code_g.sa_old[code].sa_handler != NULL) { - native_code_g.sa_old[code].sa_handler(code); - } - } -} - -/* Unflag "on stack" */ -static void coffeecatch_revert_alternate_stack(void) { -#ifndef NO_USE_SIGALTSTACK - stack_t ss; - if (sigaltstack(NULL, &ss) == 0) { - ss.ss_flags &= ~SS_ONSTACK; - sigaltstack (&ss, NULL); - } -#endif -} - -/* Try to jump to userland. */ -static void coffeecatch_try_jump_userland(native_code_handler_struct* - const t, - const int code, - siginfo_t *const si, - void * const sc) { - (void) si; /* UNUSED */ - (void) sc; /* UNUSED */ - - /* Valid context ? */ - if (t != NULL && t->ctx_is_set) { - DEBUG(print("calling siglongjmp()\n")); - - /* Invalidate the context */ - t->ctx_is_set = 0; - - /* We need to revert the alternate stack before jumping. */ - coffeecatch_revert_alternate_stack(); - - /* - * Note on async-signal-safety of siglongjmp() [POSIX] : - * "Note that longjmp() and siglongjmp() are not in the list of - * async-signal-safe functions. This is because the code executing after - * longjmp() and siglongjmp() can call any unsafe functions with the same - * danger as calling those unsafe functions directly from the signal - * handler. Applications that use longjmp() and siglongjmp() from within - * signal handlers require rigorous protection in order to be portable. - * Many of the other functions that are excluded from the list are - * traditionally implemented using either malloc() or free() functions or - * the standard I/O library, both of which traditionally use data - * structures in a non-async-signal-safe manner. Since any combination of - * different functions using a common data structure can cause - * async-signal-safety problems, this volume of POSIX.1-2008 does not - * define the behavior when any unsafe function is called in a signal - * handler that interrupts an unsafe function." - */ - siglongjmp(t->ctx, code); - } -} - -static void coffeecatch_start_alarm(void) { - /* Ensure we do not deadlock. Default of ALRM is to die. - * (signal() and alarm() are signal-safe) */ - (void) alarm(30); -} - -static void coffeecatch_mark_alarm(native_code_handler_struct *const t) { - t->alarm = 1; -} - -/* Copy context infos (signal code, etc.) */ -static void coffeecatch_copy_context(native_code_handler_struct *const t, - const int code, siginfo_t *const si, - void *const sc) { - t->code = code; - t->si = *si; - if (sc != NULL) { - ucontext_t *const uc = (ucontext_t*) sc; - t->uc = *uc; - } else { - memset(&t->uc, 0, sizeof(t->uc)); - } - -#ifdef USE_UNWIND - /* Frame buffer initial position. */ - t->frames_size = 0; - - /* Skip us and the caller. */ - t->frames_skip = 2; - - /* Use the corkscrew library to extract the backtrace. */ -#ifdef USE_CORKSCREW - t->frames_size = coffeecatch_backtrace_signal(si, sc, t->frames, 0, - BACKTRACE_FRAMES_MAX); -#else - /* Unwind frames (equivalent to backtrace()) */ - _Unwind_Backtrace(coffeecatch_unwind_callback, t); -#endif - - if (t->frames_size != 0) { - DEBUG(print("called _Unwind_Backtrace()\n")); - } else { - DEBUG(print("called _Unwind_Backtrace(), but no traces\n")); - } -#endif -} - -/* Return the thread-specific native_code_handler_struct structure, or - * @c null if no such structure is available. */ -static native_code_handler_struct* coffeecatch_get() { - return (native_code_handler_struct*) - pthread_getspecific(native_code_thread); -} - -int coffeecatch_cancel_pending_alarm() { - native_code_handler_struct *const t = coffeecatch_get(); - if (t != NULL && t->alarm) { - t->alarm = 0; - /* "If seconds is 0, a pending alarm request, if any, is canceled." */ - alarm(0); - return 0; - } - return -1; -} - -/* Internal signal pass-through. Allows to peek the "real" crash before - * calling the Java handler. Remember than Java needs many of the signals - * (for the JIT, for test-free NullPointerException handling, etc.) - * We record the siginfo_t context in this function each time it is being - * called, to be able to know what error caused an issue. - */ -static void coffeecatch_signal_pass(const int code, siginfo_t *const si, - void *const sc) { - native_code_handler_struct *t; - - DEBUG(print("caught signal\n")); - - /* Call the "real" Java handler for JIT and internals. */ - coffeecatch_call_old_signal_handler(code, si, sc); - - /* Still here ? - * FIXME TODO: This is the Dalvik behavior - but is it the SunJVM one ? */ - - /* Ensure we do not deadlock. Default of ALRM is to die. - * (signal() and alarm() are signal-safe) */ - signal(code, SIG_DFL); - coffeecatch_start_alarm(); - - /* Available context ? */ - t = coffeecatch_get(); - if (t != NULL) { - /* An alarm() call was triggered. */ - coffeecatch_mark_alarm(t); - - /* Take note of the signal. */ - coffeecatch_copy_context(t, code, si, sc); - - /* Back to the future. */ - coffeecatch_try_jump_userland(t, code, si, sc); - } - - /* Nope. (abort() is signal-safe) */ - DEBUG(print("calling abort()\n")); - signal(SIGABRT, SIG_DFL); - abort(); -} - -/* Internal crash handler for abort(). Java calls abort() if its signal handler - * could not resolve the signal ; thus calling us through this handler. */ -static void coffeecatch_signal_abort(const int code, siginfo_t *const si, - void *const sc) { - native_code_handler_struct *t; - - (void) sc; /* UNUSED */ - - DEBUG(print("caught abort\n")); - - /* Ensure we do not deadlock. Default of ALRM is to die. - * (signal() and alarm() are signal-safe) */ - signal(code, SIG_DFL); - coffeecatch_start_alarm(); - - /* Available context ? */ - t = coffeecatch_get(); - if (t != NULL) { - /* An alarm() call was triggered. */ - coffeecatch_mark_alarm(t); - - /* Take note (real "abort()") */ - coffeecatch_copy_context(t, code, si, sc); - - /* Back to the future. */ - coffeecatch_try_jump_userland(t, code, si, sc); - } - - /* No such restore point, call old signal handler then. */ - DEBUG(print("calling old signal handler\n")); - coffeecatch_call_old_signal_handler(code, si, sc); - - /* Nope. (abort() is signal-safe) */ - DEBUG(print("calling abort()\n")); - abort(); -} - -/* Internal globals initialization. */ -static int coffeecatch_handler_setup_global(void) { - if (native_code_g.initialized++ == 0) { - size_t i; - struct sigaction sa_abort; - struct sigaction sa_pass; - - DEBUG(print("installing global signal handlers\n")); - - /* Setup handler structure. */ - memset(&sa_abort, 0, sizeof(sa_abort)); - sigemptyset(&sa_abort.sa_mask); - sa_abort.sa_sigaction = coffeecatch_signal_abort; - sa_abort.sa_flags = SA_SIGINFO | SA_ONSTACK; - - memset(&sa_pass, 0, sizeof(sa_pass)); - sigemptyset(&sa_pass.sa_mask); - sa_pass.sa_sigaction = coffeecatch_signal_pass; - sa_pass.sa_flags = SA_SIGINFO | SA_ONSTACK; - - /* Allocate */ - native_code_g.sa_old = calloc(sizeof(struct sigaction), SIG_NUMBER_MAX); - if (native_code_g.sa_old == NULL) { - return -1; - } - - /* Setup signal handlers for SIGABRT (Java calls abort()) and others. **/ - for (i = 0; native_sig_catch[i] != 0; i++) { - const int sig = native_sig_catch[i]; - const struct sigaction * const action = - sig == SIGABRT ? &sa_abort : &sa_pass; - assert(sig < SIG_NUMBER_MAX); - if (sigaction(sig, action, &native_code_g.sa_old[sig]) != 0) { - return -1; - } - } - - /* Initialize thread var. */ - if (pthread_key_create(&native_code_thread, NULL) != 0) { - return -1; - } - - DEBUG(print("installed global signal handlers\n")); - } - - /* OK. */ - return 0; -} - -/** - * Free a native_code_handler_struct structure. - **/ -static int coffeecatch_native_code_handler_struct_free(native_code_handler_struct *const t) { - int code = 0; - - if (t == NULL) { - return -1; - } - -#ifndef NO_USE_SIGALTSTACK - /* Restore previous alternative stack. */ - if (t->stack_old.ss_sp != NULL && sigaltstack(&t->stack_old, NULL) != 0) { -#ifndef USE_SILENT_SIGALTSTACK - code = -1; -#endif - } -#endif - - /* Free alternative stack */ - if (t->stack_buffer != NULL) { - free(t->stack_buffer); - t->stack_buffer = NULL; - t->stack_buffer_size = 0; - } - - /* Free structure. */ - free(t); - - return code; -} - -/** - * Create a native_code_handler_struct structure. - **/ -static native_code_handler_struct* coffeecatch_native_code_handler_struct_init(void) { - stack_t stack; - native_code_handler_struct *const t = - calloc(sizeof(native_code_handler_struct), 1); - - if (t == NULL) { - return NULL; - } - - DEBUG(print("installing thread alternative stack\n")); - - /* Initialize structure */ - t->stack_buffer_size = SIG_STACK_BUFFER_SIZE; - t->stack_buffer = malloc(t->stack_buffer_size); - if (t->stack_buffer == NULL) { - coffeecatch_native_code_handler_struct_free(t); - return NULL; - } - - /* Setup alternative stack. */ - memset(&stack, 0, sizeof(stack)); - stack.ss_sp = t->stack_buffer; - stack.ss_size = t->stack_buffer_size; - stack.ss_flags = 0; - -#ifndef NO_USE_SIGALTSTACK - /* Install alternative stack. This is thread-safe */ - if (sigaltstack(&stack, &t->stack_old) != 0) { -#ifndef USE_SILENT_SIGALTSTACK - coffeecatch_native_code_handler_struct_free(t); - return NULL; -#endif - } -#endif - - return t; -} - -/** - * Acquire the crash handler for the current thread. - * The coffeecatch_handler_cleanup() must be called to release allocated - * resources. - **/ -static int coffeecatch_handler_setup(int setup_thread) { - int code; - - DEBUG(print("setup for a new handler\n")); - - /* Initialize globals. */ - if (pthread_mutex_lock(&native_code_g.mutex) != 0) { - return -1; - } - code = coffeecatch_handler_setup_global(); - if (pthread_mutex_unlock(&native_code_g.mutex) != 0) { - return -1; - } - - /* Global initialization failed. */ - if (code != 0) { - return -1; - } - - /* Initialize locals. */ - if (setup_thread && coffeecatch_get() == NULL) { - native_code_handler_struct *const t = - coffeecatch_native_code_handler_struct_init(); - - if (t == NULL) { - return -1; - } - - DEBUG(print("installing thread alternative stack\n")); - - /* Set thread-specific value. */ - if (pthread_setspecific(native_code_thread, t) != 0) { - coffeecatch_native_code_handler_struct_free(t); - return -1; - } - - DEBUG(print("installed thread alternative stack\n")); - } - - /* OK. */ - return 0; -} - -/** - * Release the resources allocated by a previous call to - * coffeecatch_handler_setup(). - * This function must be called as many times as - * coffeecatch_handler_setup() was called to fully release allocated - * resources. - **/ -static int coffeecatch_handler_cleanup() { - /* Cleanup locals. */ - native_code_handler_struct *const t = coffeecatch_get(); - if (t != NULL) { - DEBUG(print("removing thread alternative stack\n")); - - /* Erase thread-specific value now (detach). */ - if (pthread_setspecific(native_code_thread, NULL) != 0) { - assert(! "pthread_setspecific() failed"); - } - - /* Free handler and reset slternate stack */ - if (coffeecatch_native_code_handler_struct_free(t) != 0) { - return -1; - } - - DEBUG(print("removed thread alternative stack\n")); - } - - /* Cleanup globals. */ - if (pthread_mutex_lock(&native_code_g.mutex) != 0) { - assert(! "pthread_mutex_lock() failed"); - } - assert(native_code_g.initialized != 0); - if (--native_code_g.initialized == 0) { - size_t i; - - DEBUG(print("removing global signal handlers\n")); - - /* Restore signal handler. */ - for(i = 0; native_sig_catch[i] != 0; i++) { - const int sig = native_sig_catch[i]; - assert(sig < SIG_NUMBER_MAX); - if (sigaction(sig, &native_code_g.sa_old[sig], NULL) != 0) { - return -1; - } - } - - /* Free old structure. */ - free(native_code_g.sa_old); - native_code_g.sa_old = NULL; - - /* Delete thread var. */ - if (pthread_key_delete(native_code_thread) != 0) { - assert(! "pthread_key_delete() failed"); - } - - DEBUG(print("removed global signal handlers\n")); - } - if (pthread_mutex_unlock(&native_code_g.mutex) != 0) { - assert(! "pthread_mutex_unlock() failed"); - } - - return 0; -} - -/** - * Get the signal associated with the crash. - */ -int coffeecatch_get_signal() { - const native_code_handler_struct* const t = coffeecatch_get(); - if (t != NULL) { - return t->code; - } else { - return -1; - } -} - -/* Signal descriptions. - See -*/ -static const char* coffeecatch_desc_sig(int sig, int code) { - switch(sig) { - case SIGILL: - switch(code) { - case ILL_ILLOPC: - return "Illegal opcode"; - case ILL_ILLOPN: - return "Illegal operand"; - case ILL_ILLADR: - return "Illegal addressing mode"; - case ILL_ILLTRP: - return "Illegal trap"; - case ILL_PRVOPC: - return "Privileged opcode"; - case ILL_PRVREG: - return "Privileged register"; - case ILL_COPROC: - return "Coprocessor error"; - case ILL_BADSTK: - return "Internal stack error"; - default: - return "Illegal operation"; - } - break; - case SIGFPE: - switch(code) { - case FPE_INTDIV: - return "Integer divide by zero"; - case FPE_INTOVF: - return "Integer overflow"; - case FPE_FLTDIV: - return "Floating-point divide by zero"; - case FPE_FLTOVF: - return "Floating-point overflow"; - case FPE_FLTUND: - return "Floating-point underflow"; - case FPE_FLTRES: - return "Floating-point inexact result"; - case FPE_FLTINV: - return "Invalid floating-point operation"; - case FPE_FLTSUB: - return "Subscript out of range"; - default: - return "Floating-point"; - } - break; - case SIGSEGV: - switch(code) { - case SEGV_MAPERR: - return "Address not mapped to object"; - case SEGV_ACCERR: - return "Invalid permissions for mapped object"; - default: - return "Segmentation violation"; - } - break; - case SIGBUS: - switch(code) { - case BUS_ADRALN: - return "Invalid address alignment"; - case BUS_ADRERR: - return "Nonexistent physical address"; - case BUS_OBJERR: - return "Object-specific hardware error"; - default: - return "Bus error"; - } - break; - case SIGTRAP: - switch(code) { - case TRAP_BRKPT: - return "Process breakpoint"; - case TRAP_TRACE: - return "Process trace trap"; - default: - return "Trap"; - } - break; - case SIGCHLD: - switch(code) { - case CLD_EXITED: - return "Child has exited"; - case CLD_KILLED: - return "Child has terminated abnormally and did not create a core file"; - case CLD_DUMPED: - return "Child has terminated abnormally and created a core file"; - case CLD_TRAPPED: - return "Traced child has trapped"; - case CLD_STOPPED: - return "Child has stopped"; - case CLD_CONTINUED: - return "Stopped child has continued"; - default: - return "Child"; - } - break; - case SIGPOLL: - switch(code) { - case POLL_IN: - return "Data input available"; - case POLL_OUT: - return "Output buffers available"; - case POLL_MSG: - return "Input message available"; - case POLL_ERR: - return "I/O error"; - case POLL_PRI: - return "High priority input available"; - case POLL_HUP: - return "Device disconnected"; - default: - return "Pool"; - } - break; - case SIGABRT: - return "Process abort signal"; - case SIGALRM: - return "Alarm clock"; - case SIGCONT: - return "Continue executing, if stopped"; - case SIGHUP: - return "Hangup"; - case SIGINT: - return "Terminal interrupt signal"; - case SIGKILL: - return "Kill"; - case SIGPIPE: - return "Write on a pipe with no one to read it"; - case SIGQUIT: - return "Terminal quit signal"; - case SIGSTOP: - return "Stop executing"; - case SIGTERM: - return "Termination signal"; - case SIGTSTP: - return "Terminal stop signal"; - case SIGTTIN: - return "Background process attempting read"; - case SIGTTOU: - return "Background process attempting write"; - case SIGUSR1: - return "User-defined signal 1"; - case SIGUSR2: - return "User-defined signal 2"; - case SIGPROF: - return "Profiling timer expired"; - case SIGSYS: - return "Bad system call"; - case SIGVTALRM: - return "Virtual timer expired"; - case SIGURG: - return "High bandwidth data is available at a socket"; - case SIGXCPU: - return "CPU time limit exceeded"; - case SIGXFSZ: - return "File size limit exceeded"; - default: - switch(code) { - case SI_USER: - return "Signal sent by kill()"; - case SI_QUEUE: - return "Signal sent by the sigqueue()"; - case SI_TIMER: - return "Signal generated by expiration of a timer set by timer_settime()"; - case SI_ASYNCIO: - return "Signal generated by completion of an asynchronous I/O request"; - case SI_MESGQ: - return - "Signal generated by arrival of a message on an empty message queue"; - default: - return "Unknown signal"; - } - break; - } -} - -/** - * Get the backtrace size. Returns 0 if no backtrace is available. - */ -size_t coffeecatch_get_backtrace_size(void) { -#ifdef USE_UNWIND - const native_code_handler_struct* const t = coffeecatch_get(); - if (t != NULL) { - return t->frames_size; - } else { - return 0; - } -#else - return 0; -#endif -} - -/** - * Get the th element of the backtrace, or 0 upon error. - */ -uintptr_t coffeecatch_get_backtrace(ssize_t index) { -#ifdef USE_UNWIND - const native_code_handler_struct* const t = coffeecatch_get(); - if (t != NULL) { - if (index < 0) { - index = t->frames_size + index; - } - if (index >= 0 && (size_t) index < t->frames_size) { -#ifdef USE_CORKSCREW - return t->frames[index].absolute_pc; -#else - return t->frames[index]; -#endif - } - } -#else - (void) index; -#endif - return 0; -} - -/** - * Get the program counter, given a pointer to a ucontext_t context. - **/ -static uintptr_t coffeecatch_get_pc_from_ucontext(const ucontext_t *uc) { -#if (defined(__arm__)) - return uc->uc_mcontext.arm_pc; -#elif (defined(__x86_64__)) - return uc->uc_mcontext.gregs[REG_RIP]; -#elif (defined(__i386)) - return uc->uc_mcontext.gregs[REG_EIP]; -#elif (defined (__ppc__)) || (defined (__powerpc__)) - return uc->uc_mcontext.regs->nip; -#elif (defined(__hppa__)) - return uc->uc_mcontext.sc_iaoq[0] & ~0x3UL; -#elif (defined(__sparc__) && defined (__arch64__)) - return uc->uc_mcontext.mc_gregs[MC_PC]; -#elif (defined(__sparc__) && !defined (__arch64__)) - return uc->uc_mcontext.gregs[REG_PC]; -#elif (defined(__mips__)) - return uc->uc_mcontext.gregs[31]; -#else -#error "Architecture is unknown, please report me!" -#endif -} - -/* Is this module name look like a DLL ? - FIXME: find a better way to do that... */ -static int coffeecatch_is_dll(const char *name) { - size_t i; - for(i = 0; name[i] != '\0'; i++) { - if (name[i + 0] == '.' && - name[i + 1] == 's' && - name[i + 2] == 'o' && - ( name[i + 3] == '\0' || name[i + 3] == '.') ) { - return 1; - } - } - return 0; -} - -/* Extract a line information on a PC address. */ -static void format_pc_address_cb(uintptr_t pc, - void (*fun)(void *arg, const char *module, - uintptr_t addr, - const char *function, - uintptr_t offset), void *arg) { - if (pc != 0) { - Dl_info info; - void * const addr = (void*) pc; - /* dladdr() returns 0 on error, and nonzero on success. */ - if (dladdr(addr, &info) != 0 && info.dli_fname != NULL) { - const uintptr_t near = (uintptr_t) info.dli_saddr; - const uintptr_t offs = pc - near; - const uintptr_t addr_rel = pc - (uintptr_t) info.dli_fbase; - /* We need the absolute address for the main module (?). - TODO FIXME to be investigated. */ - const uintptr_t addr_to_use = coffeecatch_is_dll(info.dli_fname) - ? addr_rel : pc; - fun(arg, info.dli_fname, addr_to_use, info.dli_sname, offs); - } else { - fun(arg, NULL, pc, NULL, 0); - } - } -} - -typedef struct t_print_fun { - char *buffer; - size_t buffer_size; -} t_print_fun; - -static void print_fun(void *arg, const char *module, uintptr_t uaddr, - const char *function, uintptr_t offset) { - t_print_fun *const t = (t_print_fun*) arg; - char *const buffer = t->buffer; - const size_t buffer_size = t->buffer_size; - const void*const addr = (void*) uaddr; - if (module == NULL) { - snprintf(buffer, buffer_size, "[at %p]", addr); - } else if (function != NULL) { - snprintf(buffer, buffer_size, "[at %s:%p (%s+0x%x)]", module, addr, - function, (int) offset); - } else { - snprintf(buffer, buffer_size, "[at %s:%p]", module, addr); - } -} - -/* Format a line information on a PC address. */ -static void format_pc_address(char *buffer, size_t buffer_size, uintptr_t pc) { - t_print_fun t; - t.buffer = buffer; - t.buffer_size = buffer_size; - format_pc_address_cb(pc, print_fun, &t); -} - -/** - * Get the full error message associated with the crash. - */ -const char* coffeecatch_get_message() { - const int error = errno; - const native_code_handler_struct* const t = coffeecatch_get(); - - /* Found valid handler. */ - if (t != NULL) { - char * const buffer = t->stack_buffer; - const size_t buffer_len = t->stack_buffer_size; - size_t buffer_offs = 0; - - const char* const posix_desc = - coffeecatch_desc_sig(t->si.si_signo, t->si.si_code); - - /* Assertion failure ? */ - if ((t->code == SIGABRT -#ifdef __ANDROID__ - /* See Android BUG #16672: - * "C assert() failure causes SIGSEGV when it should cause SIGABRT" */ - || (t->code == SIGSEGV && (uintptr_t) t->si.si_addr == 0xdeadbaad) -#endif - ) && t->expression != NULL) { - snprintf(&buffer[buffer_offs], buffer_len - buffer_offs, - "assertion '%s' failed at %s:%d", - t->expression, t->file, t->line); - buffer_offs += strlen(&buffer[buffer_offs]); - } - /* Signal */ - else { - snprintf(&buffer[buffer_offs], buffer_len - buffer_offs, "signal %d", - t->si.si_signo); - buffer_offs += strlen(&buffer[buffer_offs]); - - /* Description */ - snprintf(&buffer[buffer_offs], buffer_len - buffer_offs, " (%s)", - posix_desc); - buffer_offs += strlen(&buffer[buffer_offs]); - - /* Address of faulting instruction */ - if (t->si.si_signo == SIGILL || t->si.si_signo == SIGSEGV) { - snprintf(&buffer[buffer_offs], buffer_len - buffer_offs, " at address %p", - t->si.si_addr); - buffer_offs += strlen(&buffer[buffer_offs]); - } - } - - /* [POSIX] If non-zero, an errno value associated with this signal, - as defined in . */ - if (t->si.si_errno != 0) { - snprintf(&buffer[buffer_offs], buffer_len - buffer_offs, ": "); - buffer_offs += strlen(&buffer[buffer_offs]); - if (strerror_r(t->si.si_errno, &buffer[buffer_offs], - buffer_len - buffer_offs) == 0) { - snprintf(&buffer[buffer_offs], buffer_len - buffer_offs, - "unknown error"); - buffer_offs += strlen(&buffer[buffer_offs]); - } - } - - /* Sending process ID. */ - if (t->si.si_signo == SIGCHLD && t->si.si_pid != 0) { - snprintf(&buffer[buffer_offs], buffer_len - buffer_offs, - " (sent by pid %d)", (int) t->si.si_pid); - buffer_offs += strlen(&buffer[buffer_offs]); - } - - /* Faulting program counter location. */ - if (coffeecatch_get_pc_from_ucontext(&t->uc) != 0) { - const uintptr_t pc = coffeecatch_get_pc_from_ucontext(&t->uc); - snprintf(&buffer[buffer_offs], buffer_len - buffer_offs, " "); - buffer_offs += strlen(&buffer[buffer_offs]); - format_pc_address(&buffer[buffer_offs], buffer_len - buffer_offs, pc); - buffer_offs += strlen(&buffer[buffer_offs]); - } - - /* Return string. */ - buffer[buffer_offs] = '\0'; - return t->stack_buffer; - } else { - /* Static buffer in case of emergency */ - static char buffer[256]; -#ifdef _GNU_SOURCE - return strerror_r(error, &buffer[0], sizeof(buffer)); -#else - const int code = strerror_r(error, &buffer[0], sizeof(buffer)); - errno = error; - if (code == 0) { - return buffer; - } else { - return "unknown error during crash handler setup"; - } -#endif - } -} - -#if (defined(USE_CORKSCREW)) -typedef struct t_coffeecatch_backtrace_symbols_fun { - void (*fun)(void *arg, const char *module, uintptr_t addr, - const char *function, uintptr_t offset); - void *arg; -} t_coffeecatch_backtrace_symbols_fun; - -static void coffeecatch_backtrace_symbols_fun(void *arg, const backtrace_symbol_t *sym) { - t_coffeecatch_backtrace_symbols_fun *const bt = - (t_coffeecatch_backtrace_symbols_fun*) arg; - const char *symbol = sym->demangled_name != NULL - ? sym->demangled_name : sym->symbol_name; - const uintptr_t rel = sym->relative_pc - sym->relative_symbol_addr; - bt->fun(bt->arg, sym->map_name, sym->relative_pc, symbol, rel); -} -#endif - -/** - * Enumerate backtrace information. - */ -void coffeecatch_get_backtrace_info(void (*fun)(void *arg, - const char *module, - uintptr_t addr, - const char *function, - uintptr_t offset), void *arg) { - const native_code_handler_struct* const t = coffeecatch_get(); - if (t != NULL) { -#if (defined(USE_CORKSCREW)) - t_coffeecatch_backtrace_symbols_fun bt; - bt.fun = fun; - bt.arg = arg; - coffeecatch_backtrace_symbols(t->frames, t->frames_size, - coffeecatch_backtrace_symbols_fun, &bt); -#elif (defined(USE_UNWIND)) - size_t i; - for(i = 0; i < t->frames_size; i++) { - const uintptr_t pc = t->frames[i]; - format_pc_address_cb(pc, fun, arg); - } -#else - (void) fun; - (void) arg; -#endif - } -} - -/** - * Calls coffeecatch_handler_setup(1) to setup a crash handler, mark the - * context as valid, and return 0 upon success. - */ -int coffeecatch_setup() { - if (coffeecatch_handler_setup(1) == 0) { - native_code_handler_struct *const t = coffeecatch_get(); - assert(t != NULL); - t->ctx_is_set = 1; - return 0; - } else { - return -1; - } -} - -/** - * Calls coffeecatch_handler_cleanup() - */ -void coffeecatch_cleanup() { - native_code_handler_struct *const t = coffeecatch_get(); - assert(t != NULL); - t->ctx_is_set = 0; - coffeecatch_handler_cleanup(); -} - -sigjmp_buf* coffeecatch_get_ctx() { - native_code_handler_struct* t = coffeecatch_get(); - assert(t != NULL); - return &t->ctx; -} - -void coffeecatch_abort(const char* exp, const char* file, int line) { - native_code_handler_struct *const t = coffeecatch_get(); - if (t != NULL) { - t->expression = exp; - t->file = file; - t->line = line; - } - abort(); -} diff --git a/android/cpp/coffeecatch.c.orig b/android/cpp/coffeecatch.c.orig deleted file mode 100644 index 1889dc0b9..000000000 --- a/android/cpp/coffeecatch.c.orig +++ /dev/null @@ -1,1338 +0,0 @@ -/* CoffeeCatch, a tiny native signal handler/catcher for JNI code. - * (especially for Android/Dalvik) - * - * Copyright (c) 2013, Xavier Roche (http://www.httrack.com/) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. 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. - * - * 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 THE COPYRIGHT OWNER 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. - */ - -#ifdef __ANDROID__ -#define USE_UNWIND -#define USE_CORKSCREW -#endif - -/* #undef NO_USE_SIGALTSTACK */ -/* #undef USE_SILENT_SIGALTSTACK */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(__ANDROID__) && !defined(__BIONIC_HAVE_UCONTEXT_T) && \ - defined(__arm__) && !defined(__BIONIC_HAVE_STRUCT_SIGCONTEXT) -#include -#endif -#if (defined(USE_UNWIND) && !defined(USE_CORKSCREW)) -#include -#endif -#include -#include -#include - -/*#define NDK_DEBUG 1*/ -#if ( defined(NDK_DEBUG) && ( NDK_DEBUG == 1 ) ) -#define DEBUG(A) do { A; } while(0) -#define FD_ERRNO 2 -static void print(const char *const s) { - size_t count; - for(count = 0; s[count] != '\0'; count++) ; - /* write() is async-signal-safe. */ - (void) write(FD_ERRNO, s, count); -} -#else -#define DEBUG(A) -#endif - -/* Alternative stack size. */ -#define SIG_STACK_BUFFER_SIZE SIGSTKSZ - -#ifdef USE_UNWIND -/* Number of backtraces to get. */ -#define BACKTRACE_FRAMES_MAX 32 -#endif - -/* Signals to be caught. */ -#define SIG_CATCH_COUNT 7 -static const int native_sig_catch[SIG_CATCH_COUNT + 1] - = { SIGABRT, SIGILL, SIGTRAP, SIGBUS, SIGFPE, SIGSEGV -#ifdef SIGSTKFLT - , SIGSTKFLT -#endif - , 0 }; - -/* Maximum value of a caught signal. */ -#define SIG_NUMBER_MAX 32 - -#if (defined(__ANDROID__) && (!defined(__BIONIC_HAVE_UCONTEXT_T))) -#ifndef ucontext_h_seen -#define ucontext_h_seen - -/* stack_t definition */ -#include - -#if defined(__arm__) - -/* Taken from richard.quirk's header file. (Android does not have it) */ - -typedef struct ucontext { - unsigned long uc_flags; - struct ucontext *uc_link; - stack_t uc_stack; - struct sigcontext uc_mcontext; - unsigned long uc_sigmask; -} ucontext_t; - -#elif defined(__i386__) - -/* Taken from Google Breakpad. */ - -/* 80-bit floating-point register */ -struct _libc_fpreg { - unsigned short significand[4]; - unsigned short exponent; -}; - -/* Simple floating-point state, see FNSTENV instruction */ -struct _libc_fpstate { - unsigned long cw; - unsigned long sw; - unsigned long tag; - unsigned long ipoff; - unsigned long cssel; - unsigned long dataoff; - unsigned long datasel; - struct _libc_fpreg _st[8]; - unsigned long status; -}; - -typedef uint32_t greg_t; - -typedef struct { - uint32_t gregs[19]; - struct _libc_fpstate* fpregs; - uint32_t oldmask; - uint32_t cr2; -} mcontext_t; - -enum { - REG_GS = 0, - REG_FS, - REG_ES, - REG_DS, - REG_EDI, - REG_ESI, - REG_EBP, - REG_ESP, - REG_EBX, - REG_EDX, - REG_ECX, - REG_EAX, - REG_TRAPNO, - REG_ERR, - REG_EIP, - REG_CS, - REG_EFL, - REG_UESP, - REG_SS, -}; - -typedef struct ucontext { - uint32_t uc_flags; - struct ucontext* uc_link; - stack_t uc_stack; - mcontext_t uc_mcontext; -} ucontext_t; - -#elif defined(__mips__) - -/* Taken from Google Breakpad. */ - -typedef struct { - uint32_t regmask; - uint32_t status; - uint64_t pc; - uint64_t gregs[32]; - uint64_t fpregs[32]; - uint32_t acx; - uint32_t fpc_csr; - uint32_t fpc_eir; - uint32_t used_math; - uint32_t dsp; - uint64_t mdhi; - uint64_t mdlo; - uint32_t hi1; - uint32_t lo1; - uint32_t hi2; - uint32_t lo2; - uint32_t hi3; - uint32_t lo3; -} mcontext_t; - -typedef struct ucontext { - uint32_t uc_flags; - struct ucontext* uc_link; - stack_t uc_stack; - mcontext_t uc_mcontext; -} ucontext_t; - -#else -#error "Architecture is not supported (unknown ucontext layout)" -#endif - -#endif - -#ifdef USE_CORKSCREW -typedef struct map_info_t map_info_t; -/* Extracted from Android's include/corkscrew/backtrace.h */ -typedef struct { - uintptr_t absolute_pc; - uintptr_t stack_top; - size_t stack_size; -} backtrace_frame_t; -typedef struct { - uintptr_t relative_pc; - uintptr_t relative_symbol_addr; - char* map_name; - char* symbol_name; - char* demangled_name; -} backtrace_symbol_t; -/* Extracted from Android's libcorkscrew/arch-arm/backtrace-arm.c */ -typedef ssize_t (*t_unwind_backtrace_signal_arch) -(siginfo_t* si, void* sc, const map_info_t* lst, backtrace_frame_t* bt, -size_t ignore_depth, size_t max_depth); -typedef map_info_t* (*t_acquire_my_map_info_list)(); -typedef void (*t_release_my_map_info_list)(map_info_t* milist); -typedef void (*t_get_backtrace_symbols)(const backtrace_frame_t* backtrace, - size_t frames, - backtrace_symbol_t* symbols); -typedef void (*t_free_backtrace_symbols)(backtrace_symbol_t* symbols, - size_t frames); -#endif - -#endif - -/* Process-wide crash handler structure. */ -typedef struct native_code_global_struct { - /* Initialized. */ - int initialized; - - /* Lock. */ - pthread_mutex_t mutex; - - /* Backup of sigaction. */ - struct sigaction *sa_old; -} native_code_global_struct; -#define NATIVE_CODE_GLOBAL_INITIALIZER { 0, PTHREAD_MUTEX_INITIALIZER, NULL } - -/* Thread-specific crash handler structure. */ -typedef struct native_code_handler_struct { - /* Restore point context. */ - sigjmp_buf ctx; - int ctx_is_set; - - /* Alternate stack. */ - char *stack_buffer; - size_t stack_buffer_size; - stack_t stack_old; - - /* Signal code and info. */ - int code; - siginfo_t si; - ucontext_t uc; - - /* Uwind context. */ -#if (defined(USE_CORKSCREW)) - backtrace_frame_t frames[BACKTRACE_FRAMES_MAX]; -#elif (defined(USE_UNWIND)) - uintptr_t frames[BACKTRACE_FRAMES_MAX]; -#endif - size_t frames_size; - size_t frames_skip; - - /* Custom assertion failures. */ - const char *expression; - const char *file; - int line; - - /* Alarm was fired. */ - int alarm; -} native_code_handler_struct; - -/* Global crash handler structure. */ -static native_code_global_struct native_code_g = - NATIVE_CODE_GLOBAL_INITIALIZER; - -/* Thread variable holding context. */ -pthread_key_t native_code_thread; - -#if (defined(USE_UNWIND) && !defined(USE_CORKSCREW)) -/* Unwind callback */ -static _Unwind_Reason_Code -coffeecatch_unwind_callback(struct _Unwind_Context* context, void* arg) { - native_code_handler_struct *const s = (native_code_handler_struct*) arg; - - const uintptr_t ip = _Unwind_GetIP(context); - - DEBUG(print("called unwind callback\n")); - - if (ip != 0x0) { - if (s->frames_skip == 0) { - s->frames[s->frames_size] = ip; - s->frames_size++; - } else { - s->frames_skip--; - } - } - - if (s->frames_size == BACKTRACE_FRAMES_MAX) { - return _URC_END_OF_STACK; - } else { - DEBUG(print("returned _URC_OK\n")); - return _URC_OK; - } -} -#endif - -/* Use libcorkscrew to get a backtrace inside a signal handler. - Will only return a non-zero code on Android >= 4 (with libcorkscrew.so - being shipped) */ -#ifdef USE_CORKSCREW -static ssize_t coffeecatch_backtrace_signal(siginfo_t* si, void* sc, - backtrace_frame_t* frames, - size_t ignore_depth, - size_t max_depth) { - void *const libcorkscrew = dlopen("libcorkscrew.so", RTLD_LAZY | RTLD_LOCAL); - if (libcorkscrew != NULL) { - t_unwind_backtrace_signal_arch unwind_backtrace_signal_arch - = (t_unwind_backtrace_signal_arch) - dlsym(libcorkscrew, "unwind_backtrace_signal_arch"); - t_acquire_my_map_info_list acquire_my_map_info_list - = (t_acquire_my_map_info_list) - dlsym(libcorkscrew, "acquire_my_map_info_list"); - t_release_my_map_info_list release_my_map_info_list - = (t_release_my_map_info_list) - dlsym(libcorkscrew, "release_my_map_info_list"); - if (unwind_backtrace_signal_arch != NULL - && acquire_my_map_info_list != NULL - && release_my_map_info_list != NULL) { - map_info_t*const info = acquire_my_map_info_list(); - const ssize_t size = - unwind_backtrace_signal_arch(si, sc, info, frames, ignore_depth, - max_depth); - release_my_map_info_list(info); - return size; - } else { - DEBUG(print("symbols not founs in libcorkscrew.so\n")); - } - dlclose(libcorkscrew); - } else { - DEBUG(print("libcorkscrew.so could not be loaded\n")); - } - return -1; -} - -static void coffeecatch_backtrace_symbols(const backtrace_frame_t* backtrace, - size_t frames, - void (*fun)(void *arg, - const backtrace_symbol_t *sym), - void *arg) { - void *const libcorkscrew = dlopen("libcorkscrew.so", RTLD_LAZY | RTLD_LOCAL); - if (libcorkscrew != NULL) { - t_get_backtrace_symbols get_backtrace_symbols - = (t_get_backtrace_symbols) - dlsym(libcorkscrew, "get_backtrace_symbols"); - t_free_backtrace_symbols free_backtrace_symbols - = (t_free_backtrace_symbols) - dlsym(libcorkscrew, "free_backtrace_symbols"); - if (get_backtrace_symbols != NULL - && free_backtrace_symbols != NULL) { - backtrace_symbol_t symbols[BACKTRACE_FRAMES_MAX]; - size_t i; - if (frames > BACKTRACE_FRAMES_MAX) { - frames = BACKTRACE_FRAMES_MAX; - } - get_backtrace_symbols(backtrace, frames, symbols); - for(i = 0; i < frames; i++) { - fun(arg, &symbols[i]); - } - free_backtrace_symbols(symbols, frames); - } - dlclose(libcorkscrew); - } -} -#endif - -/* Call the old handler. */ -static void coffeecatch_call_old_signal_handler(const int code, siginfo_t *const si, - void * const sc) { - /* Call the "real" Java handler for JIT and internals. */ - if (code >= 0 && code < SIG_NUMBER_MAX) { - if (native_code_g.sa_old[code].sa_sigaction != NULL) { - native_code_g.sa_old[code].sa_sigaction(code, si, sc); - } else if (native_code_g.sa_old[code].sa_handler != NULL) { - native_code_g.sa_old[code].sa_handler(code); - } - } -} - -/* Unflag "on stack" */ -static void coffeecatch_revert_alternate_stack(void) { -#ifndef NO_USE_SIGALTSTACK - stack_t ss; - if (sigaltstack(NULL, &ss) == 0) { - ss.ss_flags &= ~SS_ONSTACK; - sigaltstack (&ss, NULL); - } -#endif -} - -/* Try to jump to userland. */ -static void coffeecatch_try_jump_userland(native_code_handler_struct* - const t, - const int code, - siginfo_t *const si, - void * const sc) { - (void) si; /* UNUSED */ - (void) sc; /* UNUSED */ - - /* Valid context ? */ - if (t != NULL && t->ctx_is_set) { - DEBUG(print("calling siglongjmp()\n")); - - /* Invalidate the context */ - t->ctx_is_set = 0; - - /* We need to revert the alternate stack before jumping. */ - coffeecatch_revert_alternate_stack(); - - /* - * Note on async-signal-safety of siglongjmp() [POSIX] : - * "Note that longjmp() and siglongjmp() are not in the list of - * async-signal-safe functions. This is because the code executing after - * longjmp() and siglongjmp() can call any unsafe functions with the same - * danger as calling those unsafe functions directly from the signal - * handler. Applications that use longjmp() and siglongjmp() from within - * signal handlers require rigorous protection in order to be portable. - * Many of the other functions that are excluded from the list are - * traditionally implemented using either malloc() or free() functions or - * the standard I/O library, both of which traditionally use data - * structures in a non-async-signal-safe manner. Since any combination of - * different functions using a common data structure can cause - * async-signal-safety problems, this volume of POSIX.1-2008 does not - * define the behavior when any unsafe function is called in a signal - * handler that interrupts an unsafe function." - */ - siglongjmp(t->ctx, code); - } -} - -static void coffeecatch_start_alarm(void) { - /* Ensure we do not deadlock. Default of ALRM is to die. - * (signal() and alarm() are signal-safe) */ - (void) alarm(30); -} - -static void coffeecatch_mark_alarm(native_code_handler_struct *const t) { - t->alarm = 1; -} - -/* Copy context infos (signal code, etc.) */ -static void coffeecatch_copy_context(native_code_handler_struct *const t, - const int code, siginfo_t *const si, - void *const sc) { - t->code = code; - t->si = *si; - if (sc != NULL) { - ucontext_t *const uc = (ucontext_t*) sc; - t->uc = *uc; - } else { - memset(&t->uc, 0, sizeof(t->uc)); - } - -#ifdef USE_UNWIND - /* Frame buffer initial position. */ - t->frames_size = 0; - - /* Skip us and the caller. */ - t->frames_skip = 2; - - /* Use the corkscrew library to extract the backtrace. */ -#ifdef USE_CORKSCREW - t->frames_size = coffeecatch_backtrace_signal(si, sc, t->frames, 0, - BACKTRACE_FRAMES_MAX); -#else - /* Unwind frames (equivalent to backtrace()) */ - _Unwind_Backtrace(coffeecatch_unwind_callback, t); -#endif - - if (t->frames_size != 0) { - DEBUG(print("called _Unwind_Backtrace()\n")); - } else { - DEBUG(print("called _Unwind_Backtrace(), but no traces\n")); - } -#endif -} - -/* Return the thread-specific native_code_handler_struct structure, or - * @c null if no such structure is available. */ -static native_code_handler_struct* coffeecatch_get() { - return (native_code_handler_struct*) - pthread_getspecific(native_code_thread); -} - -int coffeecatch_cancel_pending_alarm() { - native_code_handler_struct *const t = coffeecatch_get(); - if (t != NULL && t->alarm) { - t->alarm = 0; - /* "If seconds is 0, a pending alarm request, if any, is canceled." */ - alarm(0); - return 0; - } - return -1; -} - -/* Internal signal pass-through. Allows to peek the "real" crash before - * calling the Java handler. Remember than Java needs many of the signals - * (for the JIT, for test-free NullPointerException handling, etc.) - * We record the siginfo_t context in this function each time it is being - * called, to be able to know what error caused an issue. - */ -static void coffeecatch_signal_pass(const int code, siginfo_t *const si, - void *const sc) { - native_code_handler_struct *t; - - DEBUG(print("caught signal\n")); - - /* Call the "real" Java handler for JIT and internals. */ - coffeecatch_call_old_signal_handler(code, si, sc); - - /* Still here ? - * FIXME TODO: This is the Dalvik behavior - but is it the SunJVM one ? */ - - /* Ensure we do not deadlock. Default of ALRM is to die. - * (signal() and alarm() are signal-safe) */ - signal(code, SIG_DFL); - coffeecatch_start_alarm(); - - /* Available context ? */ - t = coffeecatch_get(); - if (t != NULL) { - /* An alarm() call was triggered. */ - coffeecatch_mark_alarm(t); - - /* Take note of the signal. */ - coffeecatch_copy_context(t, code, si, sc); - - /* Back to the future. */ - coffeecatch_try_jump_userland(t, code, si, sc); - } - - /* Nope. (abort() is signal-safe) */ - DEBUG(print("calling abort()\n")); - signal(SIGABRT, SIG_DFL); - abort(); -} - -/* Internal crash handler for abort(). Java calls abort() if its signal handler - * could not resolve the signal ; thus calling us through this handler. */ -static void coffeecatch_signal_abort(const int code, siginfo_t *const si, - void *const sc) { - native_code_handler_struct *t; - - (void) sc; /* UNUSED */ - - DEBUG(print("caught abort\n")); - - /* Ensure we do not deadlock. Default of ALRM is to die. - * (signal() and alarm() are signal-safe) */ - signal(code, SIG_DFL); - coffeecatch_start_alarm(); - - /* Available context ? */ - t = coffeecatch_get(); - if (t != NULL) { - /* An alarm() call was triggered. */ - coffeecatch_mark_alarm(t); - - /* Take note (real "abort()") */ - coffeecatch_copy_context(t, code, si, sc); - - /* Back to the future. */ - coffeecatch_try_jump_userland(t, code, si, sc); - } - - /* No such restore point, call old signal handler then. */ - DEBUG(print("calling old signal handler\n")); - coffeecatch_call_old_signal_handler(code, si, sc); - - /* Nope. (abort() is signal-safe) */ - DEBUG(print("calling abort()\n")); - abort(); -} - -/* Internal globals initialization. */ -static int coffeecatch_handler_setup_global(void) { - if (native_code_g.initialized++ == 0) { - size_t i; - struct sigaction sa_abort; - struct sigaction sa_pass; - - DEBUG(print("installing global signal handlers\n")); - - /* Setup handler structure. */ - memset(&sa_abort, 0, sizeof(sa_abort)); - sigemptyset(&sa_abort.sa_mask); - sa_abort.sa_sigaction = coffeecatch_signal_abort; - sa_abort.sa_flags = SA_SIGINFO | SA_ONSTACK; - - memset(&sa_pass, 0, sizeof(sa_pass)); - sigemptyset(&sa_pass.sa_mask); - sa_pass.sa_sigaction = coffeecatch_signal_pass; - sa_pass.sa_flags = SA_SIGINFO | SA_ONSTACK; - - /* Allocate */ - native_code_g.sa_old = calloc(sizeof(struct sigaction), SIG_NUMBER_MAX); - if (native_code_g.sa_old == NULL) { - return -1; - } - - /* Setup signal handlers for SIGABRT (Java calls abort()) and others. **/ - for (i = 0; native_sig_catch[i] != 0; i++) { - const int sig = native_sig_catch[i]; - const struct sigaction * const action = - sig == SIGABRT ? &sa_abort : &sa_pass; - assert(sig < SIG_NUMBER_MAX); - if (sigaction(sig, action, &native_code_g.sa_old[sig]) != 0) { - return -1; - } - } - - /* Initialize thread var. */ - if (pthread_key_create(&native_code_thread, NULL) != 0) { - return -1; - } - - DEBUG(print("installed global signal handlers\n")); - } - - /* OK. */ - return 0; -} - -/** - * Free a native_code_handler_struct structure. - **/ -static int coffeecatch_native_code_handler_struct_free(native_code_handler_struct *const t) { - int code = 0; - - if (t == NULL) { - return -1; - } - -#ifndef NO_USE_SIGALTSTACK - /* Restore previous alternative stack. */ - if (t->stack_old.ss_sp != NULL && sigaltstack(&t->stack_old, NULL) != 0) { -#ifndef USE_SILENT_SIGALTSTACK - code = -1; -#endif - } -#endif - - /* Free alternative stack */ - if (t->stack_buffer != NULL) { - free(t->stack_buffer); - t->stack_buffer = NULL; - t->stack_buffer_size = 0; - } - - /* Free structure. */ - free(t); - - return code; -} - -/** - * Create a native_code_handler_struct structure. - **/ -static native_code_handler_struct* coffeecatch_native_code_handler_struct_init(void) { - stack_t stack; - native_code_handler_struct *const t = - calloc(sizeof(native_code_handler_struct), 1); - - if (t == NULL) { - return NULL; - } - - DEBUG(print("installing thread alternative stack\n")); - - /* Initialize structure */ - t->stack_buffer_size = SIG_STACK_BUFFER_SIZE; - t->stack_buffer = malloc(t->stack_buffer_size); - if (t->stack_buffer == NULL) { - coffeecatch_native_code_handler_struct_free(t); - return NULL; - } - - /* Setup alternative stack. */ - memset(&stack, 0, sizeof(stack)); - stack.ss_sp = t->stack_buffer; - stack.ss_size = t->stack_buffer_size; - stack.ss_flags = 0; - -#ifndef NO_USE_SIGALTSTACK - /* Install alternative stack. This is thread-safe */ - if (sigaltstack(&stack, &t->stack_old) != 0) { -#ifndef USE_SILENT_SIGALTSTACK - coffeecatch_native_code_handler_struct_free(t); - return NULL; -#endif - } -#endif - - return t; -} - -/** - * Acquire the crash handler for the current thread. - * The coffeecatch_handler_cleanup() must be called to release allocated - * resources. - **/ -static int coffeecatch_handler_setup(int setup_thread) { - int code; - - DEBUG(print("setup for a new handler\n")); - - /* Initialize globals. */ - if (pthread_mutex_lock(&native_code_g.mutex) != 0) { - return -1; - } - code = coffeecatch_handler_setup_global(); - if (pthread_mutex_unlock(&native_code_g.mutex) != 0) { - return -1; - } - - /* Global initialization failed. */ - if (code != 0) { - return -1; - } - - /* Initialize locals. */ - if (setup_thread && coffeecatch_get() == NULL) { - native_code_handler_struct *const t = - coffeecatch_native_code_handler_struct_init(); - - if (t == NULL) { - return -1; - } - - DEBUG(print("installing thread alternative stack\n")); - - /* Set thread-specific value. */ - if (pthread_setspecific(native_code_thread, t) != 0) { - coffeecatch_native_code_handler_struct_free(t); - return -1; - } - - DEBUG(print("installed thread alternative stack\n")); - } - - /* OK. */ - return 0; -} - -/** - * Release the resources allocated by a previous call to - * coffeecatch_handler_setup(). - * This function must be called as many times as - * coffeecatch_handler_setup() was called to fully release allocated - * resources. - **/ -static int coffeecatch_handler_cleanup() { - /* Cleanup locals. */ - native_code_handler_struct *const t = coffeecatch_get(); - if (t != NULL) { - DEBUG(print("removing thread alternative stack\n")); - - /* Erase thread-specific value now (detach). */ - if (pthread_setspecific(native_code_thread, NULL) != 0) { - assert(! "pthread_setspecific() failed"); - } - - /* Free handler and reset slternate stack */ - if (coffeecatch_native_code_handler_struct_free(t) != 0) { - return -1; - } - - DEBUG(print("removed thread alternative stack\n")); - } - - /* Cleanup globals. */ - if (pthread_mutex_lock(&native_code_g.mutex) != 0) { - assert(! "pthread_mutex_lock() failed"); - } - assert(native_code_g.initialized != 0); - if (--native_code_g.initialized == 0) { - size_t i; - - DEBUG(print("removing global signal handlers\n")); - - /* Restore signal handler. */ - for(i = 0; native_sig_catch[i] != 0; i++) { - const int sig = native_sig_catch[i]; - assert(sig < SIG_NUMBER_MAX); - if (sigaction(sig, &native_code_g.sa_old[sig], NULL) != 0) { - return -1; - } - } - - /* Free old structure. */ - free(native_code_g.sa_old); - native_code_g.sa_old = NULL; - - /* Delete thread var. */ - if (pthread_key_delete(native_code_thread) != 0) { - assert(! "pthread_key_delete() failed"); - } - - DEBUG(print("removed global signal handlers\n")); - } - if (pthread_mutex_unlock(&native_code_g.mutex) != 0) { - assert(! "pthread_mutex_unlock() failed"); - } - - return 0; -} - -/** - * Get the signal associated with the crash. - */ -int coffeecatch_get_signal() { - const native_code_handler_struct* const t = coffeecatch_get(); - if (t != NULL) { - return t->code; - } else { - return -1; - } -} - -/* Signal descriptions. - See -*/ -static const char* coffeecatch_desc_sig(int sig, int code) { - switch(sig) { - case SIGILL: - switch(code) { - case ILL_ILLOPC: - return "Illegal opcode"; - case ILL_ILLOPN: - return "Illegal operand"; - case ILL_ILLADR: - return "Illegal addressing mode"; - case ILL_ILLTRP: - return "Illegal trap"; - case ILL_PRVOPC: - return "Privileged opcode"; - case ILL_PRVREG: - return "Privileged register"; - case ILL_COPROC: - return "Coprocessor error"; - case ILL_BADSTK: - return "Internal stack error"; - default: - return "Illegal operation"; - } - break; - case SIGFPE: - switch(code) { - case FPE_INTDIV: - return "Integer divide by zero"; - case FPE_INTOVF: - return "Integer overflow"; - case FPE_FLTDIV: - return "Floating-point divide by zero"; - case FPE_FLTOVF: - return "Floating-point overflow"; - case FPE_FLTUND: - return "Floating-point underflow"; - case FPE_FLTRES: - return "Floating-point inexact result"; - case FPE_FLTINV: - return "Invalid floating-point operation"; - case FPE_FLTSUB: - return "Subscript out of range"; - default: - return "Floating-point"; - } - break; - case SIGSEGV: - switch(code) { - case SEGV_MAPERR: - return "Address not mapped to object"; - case SEGV_ACCERR: - return "Invalid permissions for mapped object"; - default: - return "Segmentation violation"; - } - break; - case SIGBUS: - switch(code) { - case BUS_ADRALN: - return "Invalid address alignment"; - case BUS_ADRERR: - return "Nonexistent physical address"; - case BUS_OBJERR: - return "Object-specific hardware error"; - default: - return "Bus error"; - } - break; - case SIGTRAP: - switch(code) { - case TRAP_BRKPT: - return "Process breakpoint"; - case TRAP_TRACE: - return "Process trace trap"; - default: - return "Trap"; - } - break; - case SIGCHLD: - switch(code) { - case CLD_EXITED: - return "Child has exited"; - case CLD_KILLED: - return "Child has terminated abnormally and did not create a core file"; - case CLD_DUMPED: - return "Child has terminated abnormally and created a core file"; - case CLD_TRAPPED: - return "Traced child has trapped"; - case CLD_STOPPED: - return "Child has stopped"; - case CLD_CONTINUED: - return "Stopped child has continued"; - default: - return "Child"; - } - break; - case SIGPOLL: - switch(code) { - case POLL_IN: - return "Data input available"; - case POLL_OUT: - return "Output buffers available"; - case POLL_MSG: - return "Input message available"; - case POLL_ERR: - return "I/O error"; - case POLL_PRI: - return "High priority input available"; - case POLL_HUP: - return "Device disconnected"; - default: - return "Pool"; - } - break; - case SIGABRT: - return "Process abort signal"; - case SIGALRM: - return "Alarm clock"; - case SIGCONT: - return "Continue executing, if stopped"; - case SIGHUP: - return "Hangup"; - case SIGINT: - return "Terminal interrupt signal"; - case SIGKILL: - return "Kill"; - case SIGPIPE: - return "Write on a pipe with no one to read it"; - case SIGQUIT: - return "Terminal quit signal"; - case SIGSTOP: - return "Stop executing"; - case SIGTERM: - return "Termination signal"; - case SIGTSTP: - return "Terminal stop signal"; - case SIGTTIN: - return "Background process attempting read"; - case SIGTTOU: - return "Background process attempting write"; - case SIGUSR1: - return "User-defined signal 1"; - case SIGUSR2: - return "User-defined signal 2"; - case SIGPROF: - return "Profiling timer expired"; - case SIGSYS: - return "Bad system call"; - case SIGVTALRM: - return "Virtual timer expired"; - case SIGURG: - return "High bandwidth data is available at a socket"; - case SIGXCPU: - return "CPU time limit exceeded"; - case SIGXFSZ: - return "File size limit exceeded"; - default: - switch(code) { - case SI_USER: - return "Signal sent by kill()"; - case SI_QUEUE: - return "Signal sent by the sigqueue()"; - case SI_TIMER: - return "Signal generated by expiration of a timer set by timer_settime()"; - case SI_ASYNCIO: - return "Signal generated by completion of an asynchronous I/O request"; - case SI_MESGQ: - return - "Signal generated by arrival of a message on an empty message queue"; - default: - return "Unknown signal"; - } - break; - } -} - -/** - * Get the backtrace size. Returns 0 if no backtrace is available. - */ -size_t coffeecatch_get_backtrace_size(void) { -#ifdef USE_UNWIND - const native_code_handler_struct* const t = coffeecatch_get(); - if (t != NULL) { - return t->frames_size; - } else { - return 0; - } -#else - return 0; -#endif -} - -/** - * Get the th element of the backtrace, or 0 upon error. - */ -uintptr_t coffeecatch_get_backtrace(ssize_t index) { -#ifdef USE_UNWIND - const native_code_handler_struct* const t = coffeecatch_get(); - if (t != NULL) { - if (index < 0) { - index = t->frames_size + index; - } - if (index >= 0 && (size_t) index < t->frames_size) { -#ifdef USE_CORKSCREW - return t->frames[index].absolute_pc; -#else - return t->frames[index]; -#endif - } - } -#else - (void) index; -#endif - return 0; -} - -/** - * Get the program counter, given a pointer to a ucontext_t context. - **/ -static uintptr_t coffeecatch_get_pc_from_ucontext(const ucontext_t *uc) { -#if (defined(__arm__)) - return uc->uc_mcontext.arm_pc; -#elif (defined(__x86_64__)) - return uc->uc_mcontext.gregs[REG_RIP]; -#elif (defined(__i386)) - return uc->uc_mcontext.gregs[REG_EIP]; -#elif (defined (__ppc__)) || (defined (__powerpc__)) - return uc->uc_mcontext.regs->nip; -#elif (defined(__hppa__)) - return uc->uc_mcontext.sc_iaoq[0] & ~0x3UL; -#elif (defined(__sparc__) && defined (__arch64__)) - return uc->uc_mcontext.mc_gregs[MC_PC]; -#elif (defined(__sparc__) && !defined (__arch64__)) - return uc->uc_mcontext.gregs[REG_PC]; -#elif (defined(__mips__)) - return uc->uc_mcontext.gregs[31]; -#else -#error "Architecture is unknown, please report me!" -#endif -} - -/* Is this module name look like a DLL ? - FIXME: find a better way to do that... */ -static int coffeecatch_is_dll(const char *name) { - size_t i; - for(i = 0; name[i] != '\0'; i++) { - if (name[i + 0] == '.' && - name[i + 1] == 's' && - name[i + 2] == 'o' && - ( name[i + 3] == '\0' || name[i + 3] == '.') ) { - return 1; - } - } - return 0; -} - -/* Extract a line information on a PC address. */ -static void format_pc_address_cb(uintptr_t pc, - void (*fun)(void *arg, const char *module, - uintptr_t addr, - const char *function, - uintptr_t offset), void *arg) { - if (pc != 0) { - Dl_info info; - void * const addr = (void*) pc; - /* dladdr() returns 0 on error, and nonzero on success. */ - if (dladdr(addr, &info) != 0 && info.dli_fname != NULL) { - const uintptr_t near = (uintptr_t) info.dli_saddr; - const uintptr_t offs = pc - near; - const uintptr_t addr_rel = pc - (uintptr_t) info.dli_fbase; - /* We need the absolute address for the main module (?). - TODO FIXME to be investigated. */ - const uintptr_t addr_to_use = coffeecatch_is_dll(info.dli_fname) - ? addr_rel : pc; - fun(arg, info.dli_fname, addr_to_use, info.dli_sname, offs); - } else { - fun(arg, NULL, pc, NULL, 0); - } - } -} - -typedef struct t_print_fun { - char *buffer; - size_t buffer_size; -} t_print_fun; - -static void print_fun(void *arg, const char *module, uintptr_t uaddr, - const char *function, uintptr_t offset) { - t_print_fun *const t = (t_print_fun*) arg; - char *const buffer = t->buffer; - const size_t buffer_size = t->buffer_size; - const void*const addr = (void*) uaddr; - if (module == NULL) { - snprintf(buffer, buffer_size, "[at %p]", addr); - } else if (function != NULL) { - snprintf(buffer, buffer_size, "[at %s:%p (%s+0x%x)]", module, addr, - function, (int) offset); - } else { - snprintf(buffer, buffer_size, "[at %s:%p]", module, addr); - } -} - -/* Format a line information on a PC address. */ -static void format_pc_address(char *buffer, size_t buffer_size, uintptr_t pc) { - t_print_fun t; - t.buffer = buffer; - t.buffer_size = buffer_size; - format_pc_address_cb(pc, print_fun, &t); -} - -/** - * Get the full error message associated with the crash. - */ -const char* coffeecatch_get_message() { - const int error = errno; - const native_code_handler_struct* const t = coffeecatch_get(); - - /* Found valid handler. */ - if (t != NULL) { - char * const buffer = t->stack_buffer; - const size_t buffer_len = t->stack_buffer_size; - size_t buffer_offs = 0; - - const char* const posix_desc = - coffeecatch_desc_sig(t->si.si_signo, t->si.si_code); - - /* Assertion failure ? */ - if ((t->code == SIGABRT -#ifdef __ANDROID__ - /* See Android BUG #16672: - * "C assert() failure causes SIGSEGV when it should cause SIGABRT" */ - || (t->code == SIGSEGV && (uintptr_t) t->si.si_addr == 0xdeadbaad) -#endif - ) && t->expression != NULL) { - snprintf(&buffer[buffer_offs], buffer_len - buffer_offs, - "assertion '%s' failed at %s:%d", - t->expression, t->file, t->line); - buffer_offs += strlen(&buffer[buffer_offs]); - } - /* Signal */ - else { - snprintf(&buffer[buffer_offs], buffer_len - buffer_offs, "signal %d", - t->si.si_signo); - buffer_offs += strlen(&buffer[buffer_offs]); - - /* Description */ - snprintf(&buffer[buffer_offs], buffer_len - buffer_offs, " (%s)", - posix_desc); - buffer_offs += strlen(&buffer[buffer_offs]); - - /* Address of faulting instruction */ - if (t->si.si_signo == SIGILL || t->si.si_signo == SIGSEGV) { - snprintf(&buffer[buffer_offs], buffer_len - buffer_offs, " at address %p", - t->si.si_addr); - buffer_offs += strlen(&buffer[buffer_offs]); - } - } - - /* [POSIX] If non-zero, an errno value associated with this signal, - as defined in . */ - if (t->si.si_errno != 0) { - snprintf(&buffer[buffer_offs], buffer_len - buffer_offs, ": "); - buffer_offs += strlen(&buffer[buffer_offs]); - if (strerror_r(t->si.si_errno, &buffer[buffer_offs], - buffer_len - buffer_offs) == 0) { - snprintf(&buffer[buffer_offs], buffer_len - buffer_offs, - "unknown error"); - buffer_offs += strlen(&buffer[buffer_offs]); - } - } - - /* Sending process ID. */ - if (t->si.si_signo == SIGCHLD && t->si.si_pid != 0) { - snprintf(&buffer[buffer_offs], buffer_len - buffer_offs, - " (sent by pid %d)", (int) t->si.si_pid); - buffer_offs += strlen(&buffer[buffer_offs]); - } - - /* Faulting program counter location. */ - if (coffeecatch_get_pc_from_ucontext(&t->uc) != 0) { - const uintptr_t pc = coffeecatch_get_pc_from_ucontext(&t->uc); - snprintf(&buffer[buffer_offs], buffer_len - buffer_offs, " "); - buffer_offs += strlen(&buffer[buffer_offs]); - format_pc_address(&buffer[buffer_offs], buffer_len - buffer_offs, pc); - buffer_offs += strlen(&buffer[buffer_offs]); - } - - /* Return string. */ - buffer[buffer_offs] = '\0'; - return t->stack_buffer; - } else { - /* Static buffer in case of emergency */ - static char buffer[256]; -#ifdef _GNU_SOURCE - return strerror_r(error, &buffer[0], sizeof(buffer)); -#else - const int code = strerror_r(error, &buffer[0], sizeof(buffer)); - errno = error; - if (code == 0) { - return buffer; - } else { - return "unknown error during crash handler setup"; - } -#endif - } -} - -#if (defined(USE_CORKSCREW)) -typedef struct t_coffeecatch_backtrace_symbols_fun { - void (*fun)(void *arg, const char *module, uintptr_t addr, - const char *function, uintptr_t offset); - void *arg; -} t_coffeecatch_backtrace_symbols_fun; - -static void coffeecatch_backtrace_symbols_fun(void *arg, const backtrace_symbol_t *sym) { - t_coffeecatch_backtrace_symbols_fun *const bt = - (t_coffeecatch_backtrace_symbols_fun*) arg; - const char *symbol = sym->demangled_name != NULL - ? sym->demangled_name : sym->symbol_name; - const uintptr_t rel = sym->relative_pc - sym->relative_symbol_addr; - bt->fun(bt->arg, sym->map_name, sym->relative_pc, symbol, rel); -} -#endif - -/** - * Enumerate backtrace information. - */ -void coffeecatch_get_backtrace_info(void (*fun)(void *arg, - const char *module, - uintptr_t addr, - const char *function, - uintptr_t offset), void *arg) { - const native_code_handler_struct* const t = coffeecatch_get(); - if (t != NULL) { -#if (defined(USE_CORKSCREW)) - t_coffeecatch_backtrace_symbols_fun bt; - bt.fun = fun; - bt.arg = arg; - coffeecatch_backtrace_symbols(t->frames, t->frames_size, - coffeecatch_backtrace_symbols_fun, &bt); -#elif (defined(USE_UNWIND)) - size_t i; - for(i = 0; i < t->frames_size; i++) { - const uintptr_t pc = t->frames[i]; - format_pc_address_cb(pc, fun, arg); - } -#else - (void) fun; - (void) arg; -#endif - } -} - -/** - * Calls coffeecatch_handler_setup(1) to setup a crash handler, mark the - * context as valid, and return 0 upon success. - */ -int coffeecatch_setup() { - if (coffeecatch_handler_setup(1) == 0) { - native_code_handler_struct *const t = coffeecatch_get(); - assert(t != NULL); - t->ctx_is_set = 1; - return 0; - } else { - return -1; - } -} - -/** - * Calls coffeecatch_handler_cleanup() - */ -void coffeecatch_cleanup() { - native_code_handler_struct *const t = coffeecatch_get(); - assert(t != NULL); - t->ctx_is_set = 0; - coffeecatch_handler_cleanup(); -} - -sigjmp_buf* coffeecatch_get_ctx() { - native_code_handler_struct* t = coffeecatch_get(); - assert(t != NULL); - return &t->ctx; -} - -void coffeecatch_abort(const char* exp, const char* file, int line) { - native_code_handler_struct *const t = coffeecatch_get(); - if (t != NULL) { - t->expression = exp; - t->file = file; - t->line = line; - } - abort(); -} diff --git a/android/cpp/coffeecatch_r10c.diff b/android/cpp/coffeecatch_r10c.diff deleted file mode 100644 index ddee5b329..000000000 --- a/android/cpp/coffeecatch_r10c.diff +++ /dev/null @@ -1,216 +0,0 @@ -diff --git a/coffeecatch.c b/coffeecatch.c -index 448fe0f..f39fcdb 100644 ---- a/coffeecatch.c -+++ b/coffeecatch.c -@@ -43,10 +43,7 @@ - #include - #include - #include --#if defined(__ANDROID__) && !defined(__BIONIC_HAVE_UCONTEXT_T) && \ -- defined(__arm__) && !defined(__BIONIC_HAVE_STRUCT_SIGCONTEXT) --#include --#endif -+#include - #if (defined(USE_UNWIND) && !defined(USE_CORKSCREW)) - #include - #endif -@@ -88,154 +85,34 @@ static const int native_sig_catch[SIG_CATCH_COUNT + 1] - /* Maximum value of a caught signal. */ - #define SIG_NUMBER_MAX 32 - --#if (defined(__ANDROID__) && (!defined(__BIONIC_HAVE_UCONTEXT_T))) --#ifndef ucontext_h_seen --#define ucontext_h_seen -- --/* stack_t definition */ --#include -- --#if defined(__arm__) -- --/* Taken from richard.quirk's header file. (Android does not have it) */ -- --typedef struct ucontext { -- unsigned long uc_flags; -- struct ucontext *uc_link; -- stack_t uc_stack; -- struct sigcontext uc_mcontext; -- unsigned long uc_sigmask; --} ucontext_t; -- --#elif defined(__i386__) -- --/* Taken from Google Breakpad. */ -- --/* 80-bit floating-point register */ --struct _libc_fpreg { -- unsigned short significand[4]; -- unsigned short exponent; --}; -- --/* Simple floating-point state, see FNSTENV instruction */ --struct _libc_fpstate { -- unsigned long cw; -- unsigned long sw; -- unsigned long tag; -- unsigned long ipoff; -- unsigned long cssel; -- unsigned long dataoff; -- unsigned long datasel; -- struct _libc_fpreg _st[8]; -- unsigned long status; --}; -- --typedef uint32_t greg_t; -- --typedef struct { -- uint32_t gregs[19]; -- struct _libc_fpstate* fpregs; -- uint32_t oldmask; -- uint32_t cr2; --} mcontext_t; -- --enum { -- REG_GS = 0, -- REG_FS, -- REG_ES, -- REG_DS, -- REG_EDI, -- REG_ESI, -- REG_EBP, -- REG_ESP, -- REG_EBX, -- REG_EDX, -- REG_ECX, -- REG_EAX, -- REG_TRAPNO, -- REG_ERR, -- REG_EIP, -- REG_CS, -- REG_EFL, -- REG_UESP, -- REG_SS, --}; -- --typedef struct ucontext { -- uint32_t uc_flags; -- struct ucontext* uc_link; -- stack_t uc_stack; -- mcontext_t uc_mcontext; --} ucontext_t; -- --#elif defined(__mips__) -- --/* Taken from Google Breakpad. */ -- --typedef struct { -- uint32_t regmask; -- uint32_t status; -- uint64_t pc; -- uint64_t gregs[32]; -- uint64_t fpregs[32]; -- uint32_t acx; -- uint32_t fpc_csr; -- uint32_t fpc_eir; -- uint32_t used_math; -- uint32_t dsp; -- uint64_t mdhi; -- uint64_t mdlo; -- uint32_t hi1; -- uint32_t lo1; -- uint32_t hi2; -- uint32_t lo2; -- uint32_t hi3; -- uint32_t lo3; --} mcontext_t; -- --typedef struct ucontext { -- uint32_t uc_flags; -- struct ucontext* uc_link; -- stack_t uc_stack; -- mcontext_t uc_mcontext; --} ucontext_t; -- --#else --#error "Architecture is not supported (unknown ucontext layout)" --#endif -- --#endif -- - #ifdef USE_CORKSCREW - typedef struct map_info_t map_info_t; - /* Extracted from Android's include/corkscrew/backtrace.h */ --typedef struct { -- uintptr_t absolute_pc; -- uintptr_t stack_top; -- size_t stack_size; --} backtrace_frame_t; --typedef struct { -- uintptr_t relative_pc; -- uintptr_t relative_symbol_addr; -- char* map_name; -- char* symbol_name; -- char* demangled_name; -+typedef struct { -+ uintptr_t absolute_pc; -+ uintptr_t stack_top; -+ size_t stack_size; -+} backtrace_frame_t; -+typedef struct { -+ uintptr_t relative_pc; -+ uintptr_t relative_symbol_addr; -+ char* map_name; -+ char* symbol_name; -+ char* demangled_name; - } backtrace_symbol_t; - /* Extracted from Android's libcorkscrew/arch-arm/backtrace-arm.c */ --typedef ssize_t (*t_unwind_backtrace_signal_arch) --(siginfo_t* si, void* sc, const map_info_t* lst, backtrace_frame_t* bt, --size_t ignore_depth, size_t max_depth); --typedef map_info_t* (*t_acquire_my_map_info_list)(); --typedef void (*t_release_my_map_info_list)(map_info_t* milist); --typedef void (*t_get_backtrace_symbols)(const backtrace_frame_t* backtrace, -+typedef ssize_t (*t_unwind_backtrace_signal_arch) -+(siginfo_t* si, void* sc, const map_info_t* lst, backtrace_frame_t* bt, -+size_t ignore_depth, size_t max_depth); -+typedef map_info_t* (*t_acquire_my_map_info_list)(); -+typedef void (*t_release_my_map_info_list)(map_info_t* milist); -+typedef void (*t_get_backtrace_symbols)(const backtrace_frame_t* backtrace, - size_t frames, - backtrace_symbol_t* symbols); - typedef void (*t_free_backtrace_symbols)(backtrace_symbol_t* symbols, - size_t frames); - #endif - --#endif -- - /* Process-wide crash handler structure. */ - typedef struct native_code_global_struct { - /* Initialized. */ -@@ -341,7 +218,7 @@ static ssize_t coffeecatch_backtrace_signal(siginfo_t* si, void* sc, - && acquire_my_map_info_list != NULL - && release_my_map_info_list != NULL) { - map_info_t*const info = acquire_my_map_info_list(); -- const ssize_t size = -+ const ssize_t size = - unwind_backtrace_signal_arch(si, sc, info, frames, ignore_depth, - max_depth); - release_my_map_info_list(info); -@@ -1073,12 +950,12 @@ static uintptr_t coffeecatch_get_pc_from_ucontext(const ucontext_t *uc) { - return uc->uc_mcontext.regs->nip; - #elif (defined(__hppa__)) - return uc->uc_mcontext.sc_iaoq[0] & ~0x3UL; --#elif (defined(__sparc__) && defined (__arch64__)) -- return uc->uc_mcontext.mc_gregs[MC_PC]; --#elif (defined(__sparc__) && !defined (__arch64__)) -- return uc->uc_mcontext.gregs[REG_PC]; --#elif (defined(__mips__)) -- return uc->uc_mcontext.gregs[31]; -+#elif (defined(__sparc__) && defined (__arch64__)) -+ return uc->uc_mcontext.mc_gregs[MC_PC]; -+#elif (defined(__sparc__) && !defined (__arch64__)) -+ return uc->uc_mcontext.gregs[REG_PC]; -+#elif (defined(__mips__)) -+ return uc->uc_mcontext.gregs[31]; - #else - #error "Architecture is unknown, please report me!" - #endif \ No newline at end of file diff --git a/android/cpp/coffeejni.c b/android/cpp/coffeejni.c deleted file mode 100644 index 6dc9db5fa..000000000 --- a/android/cpp/coffeejni.c +++ /dev/null @@ -1,185 +0,0 @@ -/* CoffeeCatch, a tiny native signal handler/catcher for JNI code. - * (especially for Android/Dalvik) - * - * Copyright (c) 2013, Xavier Roche (http://www.httrack.com/) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. 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. - * - * 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 THE COPYRIGHT OWNER 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. - */ - -#ifndef COFFEECATCH_JNI_H -#define COFFEECATCH_JNI_H - -#include -#include -#include -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct t_bt_fun { - JNIEnv* env; - jclass cls; - jclass cls_ste; - jmethodID cons_ste; - jobjectArray elements; - size_t size; - size_t index; -} t_bt_fun; - -static char* bt_print(const char *function, uintptr_t offset) { - if (function != NULL) { - char buffer[256]; - snprintf(buffer, sizeof(buffer), "%s:%p", function, (void*) offset); - return strdup(buffer); - } else { - return ""; - } -} - -static char* bt_addr(uintptr_t addr) { - char buffer[32]; - snprintf(buffer, sizeof(buffer), "%p", (void*) addr); - return strdup(buffer); -} - -#define IS_VALID_CLASS_CHAR(C) ( \ - ((C) >= 'a' && (C) <= 'z') \ - || ((C) >= 'A' && (C) <= 'Z') \ - || ((C) >= '0' && (C) <= '9') \ - || (C) == '_' \ - ) - -static char* bt_module(const char *module) { - if (module != NULL) { - size_t i; - char *copy; - if (*module == '/') { - module++; - } - copy = strdup(module); - /* Pseudo-java-class. */ - for(i = 0; copy[i] != '\0'; i++) { - if (copy[i] == '/') { - copy[i] = '.'; - } else if (!IS_VALID_CLASS_CHAR(copy[i])) { - copy[i] = '_'; - } - } - return copy; - } else { - return ""; - } -} - -static void bt_fun(void *arg, const char *module, uintptr_t addr, - const char *function, uintptr_t offset) { - t_bt_fun *const t = (t_bt_fun*) arg; - JNIEnv*const env = t->env; - jstring declaringClass = (*env)->NewStringUTF(env, bt_module(module)); - jstring methodName = (*env)->NewStringUTF(env, bt_addr(addr)); - jstring fileName = (*env)->NewStringUTF(env, bt_print(function, offset)); - const int lineNumber = function != NULL ? 0 : -2; /* "-2" is "inside JNI code" */ - jobject trace = (*env)->NewObject(env, t->cls_ste, t->cons_ste, - declaringClass, methodName, fileName, - lineNumber); - if (t->index < t->size) { - (*t->env)->SetObjectArrayElement(t->env, t->elements, t->index++, trace); - } -} - -void coffeecatch_throw_exception(JNIEnv* env) { - jclass cls = (*env)->FindClass(env, "java/lang/Error"); - jclass cls_ste = (*env)->FindClass(env, "java/lang/StackTraceElement"); - - jmethodID cons = (*env)->GetMethodID(env, cls, "", "(Ljava/lang/String;)V"); - jmethodID cons_cause = (*env)->GetMethodID(env, cls, "", "(Ljava/lang/String;Ljava/lang/Throwable;)V"); - jmethodID cons_ste = (*env)->GetMethodID(env, cls_ste, "", - "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)V"); - jmethodID meth_sste = (*env)->GetMethodID(env, cls, "setStackTrace", - "([Ljava/lang/StackTraceElement;)V"); - - /* Exception message. */ - const char*const message = coffeecatch_get_message(); - jstring str = (*env)->NewStringUTF(env, strdup(message)); - - /* Final exception. */ - jthrowable exception; - - /* Add pseudo-stack trace. */ - const ssize_t bt_size = coffeecatch_get_backtrace_size(); - - assert(cls != NULL); - assert(cls_ste != NULL); - assert(cons != NULL); - assert(cons_cause != NULL); - assert(cons_ste != NULL); - assert(meth_sste != NULL); - - assert(message != NULL); - assert(str != NULL); - - /* Can we produce a stack trace ? */ - if (bt_size > 0) { - /* Create secondary exception. */ - jthrowable cause = (jthrowable) (*env)->NewObject(env, cls, cons, str); - - /* Stack trace. */ - jobjectArray elements = - (*env)->NewObjectArray(env, bt_size, cls_ste, NULL); - if (elements != NULL) { - t_bt_fun t; - t.env = env; - t.cls = cls; - t.cls_ste = cls_ste; - t.cons_ste = cons_ste; - t.elements = elements; - t.index = 0; - t.size = bt_size; - coffeecatch_get_backtrace_info(bt_fun, &t); - (*env)->CallVoidMethod(env, cause, meth_sste, elements); - } - - /* Primary exception */ - exception = (jthrowable) (*env)->NewObject(env, cls, cons_cause, str, cause); - } else { - /* Simple exception */ - exception = (jthrowable) (*env)->NewObject(env, cls, cons, str); - } - - /* Throw exception. */ - if (exception != NULL) { - (*env)->Throw(env, exception); - } else { - (*env)->ThrowNew(env, cls, strdup(message)); - } -} - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/android/cpp/jni.cpp b/android/cpp/jni.cpp index d62621ae6..b08acb649 100644 --- a/android/cpp/jni.cpp +++ b/android/cpp/jni.cpp @@ -12,8 +12,6 @@ #include #include -#include - #include #include #include @@ -23,16 +21,6 @@ #pragma clang diagnostic ignored "-Wunused-parameter" -#define CPP_TRY_JNI(ENV, CODE) \ - try { \ - CODE; \ - } \ - catch (std::exception e) { \ - std::string msg("Unhandled C++ exception: "); \ - msg.append(e.what()); \ - throw_error(ENV, msg.c_str()); \ - } - namespace mbgl { namespace android { @@ -185,12 +173,7 @@ nativeCreate(JNIEnv *env, jobject obj, jstring cachePath_, jstring dataPath_, js cachePath = std_string_from_jstring(env, cachePath_); dataPath = std_string_from_jstring(env, dataPath_); apkPath = std_string_from_jstring(env, apkPath_); - NativeMapView *nativeMapView = nullptr; - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, nativeMapView = new NativeMapView(env, obj))); - if (nativeMapView == nullptr) { - throw_error(env, "Unable to create NativeMapView."); - return 0; - } + NativeMapView *nativeMapView = new NativeMapView(env, obj); jlong mapViewPtr = reinterpret_cast(nativeMapView); return mapViewPtr; } @@ -207,9 +190,7 @@ void JNICALL nativeInitializeDisplay(JNIEnv *env, jobject obj, jlong nativeMapVi mbgl::Log::Debug(mbgl::Event::JNI, "nativeInitializeDisplay"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - bool ret = false; - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, ret = nativeMapView->initializeDisplay())); - if (!ret) { + if (!nativeMapView->initializeDisplay()) { throw_error(env, "Unable to initialize GL display."); } } @@ -218,16 +199,14 @@ void JNICALL nativeTerminateDisplay(JNIEnv *env, jobject obj, jlong nativeMapVie mbgl::Log::Debug(mbgl::Event::JNI, "nativeTerminateDisplay"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, nativeMapView->terminateDisplay())); + nativeMapView->terminateDisplay(); } void JNICALL nativeInitializeContext(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { mbgl::Log::Debug(mbgl::Event::JNI, "nativeInitializeContext"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - bool ret = false; - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, ret = nativeMapView->initializeContext())); - if (!ret) { + if (!nativeMapView->initializeContext()) { throw_error(env, "Unable to initialize GL context."); } } @@ -236,7 +215,7 @@ void JNICALL nativeTerminateContext(JNIEnv *env, jobject obj, jlong nativeMapVie mbgl::Log::Debug(mbgl::Event::JNI, "nativeTerminateContext"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, nativeMapView->terminateContext())); + nativeMapView->terminateContext(); } void JNICALL @@ -244,10 +223,8 @@ nativeCreateSurface(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jobject su mbgl::Log::Debug(mbgl::Event::JNI, "nativeCreateSurface"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - bool ret = false; - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, ret = nativeMapView->createSurface( - ANativeWindow_fromSurface(env, surface)))); - if (!ret) { + + if (!nativeMapView->createSurface(ANativeWindow_fromSurface(env, surface))) { throw_error(env, "Unable to create GL surface."); } } @@ -256,79 +233,77 @@ void JNICALL nativeDestroySurface(JNIEnv *env, jobject obj, jlong nativeMapViewP mbgl::Log::Debug(mbgl::Event::JNI, "nativeDestroySurface"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, nativeMapView->destroySurface())); + nativeMapView->destroySurface(); } void JNICALL nativeStart(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { mbgl::Log::Debug(mbgl::Event::JNI, "nativeStart"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, nativeMapView->start())); + nativeMapView->start(); } void JNICALL nativeStop(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { mbgl::Log::Debug(mbgl::Event::JNI, "nativeStop"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, nativeMapView->stop())); + nativeMapView->stop(); } void JNICALL nativePause(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { mbgl::Log::Debug(mbgl::Event::JNI, "nativePause"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, nativeMapView->pause())); + nativeMapView->pause(); } void JNICALL nativeResume(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { mbgl::Log::Debug(mbgl::Event::JNI, "nativeResume"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, nativeMapView->resume())); + nativeMapView->resume(); } void JNICALL nativeRun(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { mbgl::Log::Debug(mbgl::Event::JNI, "nativeRun"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, nativeMapView->getMap().run())); + nativeMapView->getMap().run(); } void JNICALL nativeRerender(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { mbgl::Log::Debug(mbgl::Event::JNI, "nativeRerender"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, nativeMapView->getMap().rerender())); + nativeMapView->getMap().rerender(); } void JNICALL nativeUpdate(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { mbgl::Log::Debug(mbgl::Event::JNI, "nativeUpdate"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, nativeMapView->getMap().update())); + nativeMapView->getMap().update(); } void JNICALL nativeTerminate(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { mbgl::Log::Debug(mbgl::Event::JNI, "nativeTerminate"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, nativeMapView->getMap().terminate())); + nativeMapView->getMap().terminate(); } jboolean JNICALL nativeNeedsSwap(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { mbgl::Log::Debug(mbgl::Event::JNI, "nativeNeedsSwap"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - jboolean ret = false; - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, ret = nativeMapView->getMap().needsSwap())); - return ret; + return nativeMapView->getMap().needsSwap(); } void JNICALL nativeSwapped(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { mbgl::Log::Debug(mbgl::Event::JNI, "nativeSwapped"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, (nativeMapView->getMap().swapped()))); + nativeMapView->getMap().swapped(); } void JNICALL nativeResize(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jint width, jint height, @@ -340,7 +315,7 @@ void JNICALL nativeResize(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jint assert(width <= UINT16_MAX); assert(height <= UINT16_MAX); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, nativeMapView->getMap().resize(width, height, ratio))); + nativeMapView->getMap().resize(width, height, ratio); } void JNICALL nativeResize(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jint width, jint height, @@ -356,8 +331,7 @@ void JNICALL nativeResize(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jint assert(fbWidth <= UINT16_MAX); assert(fbHeight <= UINT16_MAX); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, nativeMapView->getMap().resize(width, height, ratio, - fbWidth, fbHeight))); + nativeMapView->getMap().resize(width, height, ratio, fbWidth, fbHeight); } void JNICALL @@ -365,18 +339,14 @@ nativeSetAppliedClasses(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jobjec mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetAppliedClasses"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, nativeMapView->getMap().setAppliedClasses( - std_vector_string_from_jobject(env, classes)))); + nativeMapView->getMap().setAppliedClasses(std_vector_string_from_jobject(env, classes)); } jobject JNICALL nativeGetAppliedClasses(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { mbgl::Log::Debug(mbgl::Event::JNI, "nativeGetAppliedClasses"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - jobject ret = nullptr; - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, ret = std_vector_string_to_jobject( - env, nativeMapView->getMap().getAppliedClasses()))); - return ret; + return std_vector_string_to_jobject(env, nativeMapView->getMap().getAppliedClasses()); } void JNICALL nativeSetDefaultTransitionDuration(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, @@ -385,26 +355,21 @@ void JNICALL nativeSetDefaultTransitionDuration(JNIEnv *env, jobject obj, jlong assert(nativeMapViewPtr != 0); assert(milliseconds >= 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - COFFEE_TRY_JNI( - env, CPP_TRY_JNI(env, nativeMapView->getMap().setDefaultTransitionDuration(milliseconds))); + nativeMapView->getMap().setDefaultTransitionDuration(milliseconds); } jlong JNICALL nativeGetDefaultTransitionDuration(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { mbgl::Log::Debug(mbgl::Event::JNI, "nativeGetDefaultTransitionDuration"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - jlong ret = 0; - COFFEE_TRY_JNI(env, - CPP_TRY_JNI(env, ret = nativeMapView->getMap().getDefaultTransitionDuration())); - return ret; + return nativeMapView->getMap().getDefaultTransitionDuration(); } void JNICALL nativeSetStyleURL(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jstring url) { mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetStyleURL"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, nativeMapView->getMap().setStyleURL( - std_string_from_jstring(env, url)))); + nativeMapView->getMap().setStyleURL(std_string_from_jstring(env, url)); } void JNICALL nativeSetStyleJSON(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, @@ -412,19 +377,15 @@ void JNICALL nativeSetStyleJSON(JNIEnv *env, jobject obj, jlong nativeMapViewPtr mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetStyleJSON"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, nativeMapView->getMap().setStyleJSON( - std_string_from_jstring(env, newStyleJson), - std_string_from_jstring(env, base)))); + nativeMapView->getMap().setStyleJSON(std_string_from_jstring(env, newStyleJson), + std_string_from_jstring(env, base)); } jstring JNICALL nativeGetStyleJSON(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { mbgl::Log::Debug(mbgl::Event::JNI, "nativeGetStyleJSON"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - jstring ret = nullptr; - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, ret = std_string_to_jstring( - env, nativeMapView->getMap().getStyleJSON()))); - return ret; + return std_string_to_jstring(env, nativeMapView->getMap().getStyleJSON()); } void JNICALL @@ -432,26 +393,21 @@ nativeSetAccessToken(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jstring a mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetAccessToken"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, nativeMapView->getFileSource().setAccessToken( - std_string_from_jstring(env, accessToken)))); + nativeMapView->getFileSource().setAccessToken(std_string_from_jstring(env, accessToken)); } jstring JNICALL nativeGetAccessToken(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { mbgl::Log::Debug(mbgl::Event::JNI, "nativeGetAccessToken"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - jstring ret = nullptr; - COFFEE_TRY_JNI(env, - CPP_TRY_JNI(env, ret = std_string_to_jstring( - env, nativeMapView->getFileSource().getAccessToken()))); - return ret; + return std_string_to_jstring(env, nativeMapView->getFileSource().getAccessToken()); } void JNICALL nativeCancelTransitions(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { mbgl::Log::Debug(mbgl::Event::JNI, "nativeCancelTransitions"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, nativeMapView->getMap().cancelTransitions())); + nativeMapView->getMap().cancelTransitions(); } void JNICALL nativeMoveBy(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jdouble dx, jdouble dy, @@ -459,7 +415,7 @@ void JNICALL nativeMoveBy(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jdou mbgl::Log::Debug(mbgl::Event::JNI, "nativeMoveBy"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, nativeMapView->getMap().moveBy(dx, dy, duration))); + nativeMapView->getMap().moveBy(dx, dy, duration); } void JNICALL nativeSetLonLat(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jobject lonLat, @@ -480,7 +436,7 @@ void JNICALL nativeSetLonLat(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, j return; } - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, nativeMapView->getMap().setLonLat(lon, lat, duration))); + nativeMapView->getMap().setLonLat(lon, lat, duration); } jobject JNICALL nativeGetLonLat(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { @@ -488,7 +444,7 @@ jobject JNICALL nativeGetLonLat(JNIEnv *env, jobject obj, jlong nativeMapViewPtr assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); double lon = 0.0, lat = 0.0; - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, nativeMapView->getMap().getLonLat(lon, lat))); + nativeMapView->getMap().getLonLat(lon, lat); jobject ret = env->NewObject(lonLatClass, lonLatConstructorId, lon, lat); if (ret == nullptr) { @@ -503,21 +459,21 @@ void JNICALL nativeStartPanning(JNIEnv *env, jobject obj, jlong nativeMapViewPtr mbgl::Log::Debug(mbgl::Event::JNI, "nativeStartPanning"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, nativeMapView->getMap().startPanning())); + nativeMapView->getMap().startPanning(); } void JNICALL nativeStopPanning(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { mbgl::Log::Debug(mbgl::Event::JNI, "nativeStopPanning"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, nativeMapView->getMap().stopPanning())); + nativeMapView->getMap().stopPanning(); } void JNICALL nativeResetPosition(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { mbgl::Log::Debug(mbgl::Event::JNI, "nativeResetPosition"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, nativeMapView->getMap().resetPosition())); + nativeMapView->getMap().resetPosition(); } void JNICALL nativeScaleBy(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jdouble ds, jdouble cx, @@ -525,7 +481,7 @@ void JNICALL nativeScaleBy(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jdo mbgl::Log::Debug(mbgl::Event::JNI, "nativeScaleBy"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, nativeMapView->getMap().scaleBy(ds, cx, cy, duration))); + nativeMapView->getMap().scaleBy(ds, cx, cy, duration); } void JNICALL nativeSetScale(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jdouble scale, @@ -533,17 +489,14 @@ void JNICALL nativeSetScale(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jd mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetScale"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - COFFEE_TRY_JNI(env, - CPP_TRY_JNI(env, nativeMapView->getMap().setScale(scale, cx, cy, duration))); + nativeMapView->getMap().setScale(scale, cx, cy, duration); } jdouble JNICALL nativeGetScale(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { mbgl::Log::Debug(mbgl::Event::JNI, "nativeGetScale"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - jdouble ret = 0.0; - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, ret = nativeMapView->getMap().getScale())); - return ret; + return nativeMapView->getMap().getScale(); } void JNICALL @@ -551,16 +504,14 @@ nativeSetZoom(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jdouble zoom, jd mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetZoom"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, nativeMapView->getMap().setZoom(zoom, duration))); + nativeMapView->getMap().setZoom(zoom, duration); } jdouble JNICALL nativeGetZoom(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { mbgl::Log::Debug(mbgl::Event::JNI, "nativeGetZoom"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - jdouble ret = 0.0; - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, ret = nativeMapView->getMap().getZoom())); - return ret; + return nativeMapView->getMap().getZoom(); } void JNICALL nativeSetLonLatZoom(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, @@ -587,8 +538,7 @@ void JNICALL nativeSetLonLatZoom(JNIEnv *env, jobject obj, jlong nativeMapViewPt return; } - COFFEE_TRY_JNI( - env, CPP_TRY_JNI(env, nativeMapView->getMap().setLonLatZoom(lon, lat, zoom, duration))); + nativeMapView->getMap().setLonLatZoom(lon, lat, zoom, duration); } jobject JNICALL nativeGetLonLatZoom(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { @@ -596,7 +546,7 @@ jobject JNICALL nativeGetLonLatZoom(JNIEnv *env, jobject obj, jlong nativeMapVie assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); double lon = 0.0, lat = 0.0, zoom = 0.0; - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, nativeMapView->getMap().getLonLatZoom(lon, lat, zoom))); + nativeMapView->getMap().getLonLatZoom(lon, lat, zoom); jobject ret = env->NewObject(lonLatZoomClass, lonLatZoomConstructorId, lon, lat, zoom); if (ret == nullptr) { @@ -611,39 +561,35 @@ void JNICALL nativeResetZoom(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { mbgl::Log::Debug(mbgl::Event::JNI, "nativeResetZoom"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, nativeMapView->getMap().resetZoom())); + nativeMapView->getMap().resetZoom(); } void JNICALL nativeStartScaling(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { mbgl::Log::Debug(mbgl::Event::JNI, "nativeStartScaling"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, nativeMapView->getMap().startScaling())); + nativeMapView->getMap().startScaling(); } void JNICALL nativeStopScaling(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { mbgl::Log::Debug(mbgl::Event::JNI, "nativeStopScaling"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, nativeMapView->getMap().stopScaling())); + return nativeMapView->getMap().stopScaling(); } jdouble JNICALL nativeGetMinZoom(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { mbgl::Log::Debug(mbgl::Event::JNI, "nativeGetMinZoom"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - jdouble ret = 0.0; - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, ret = nativeMapView->getMap().getMinZoom())); - return ret; + return nativeMapView->getMap().getMinZoom(); } jdouble JNICALL nativeGetMaxZoom(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { mbgl::Log::Debug(mbgl::Event::JNI, "nativeGetMaxZoom"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - jdouble ret = 0.0; - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, ret = nativeMapView->getMap().getMaxZoom())); - return ret; + return nativeMapView->getMap().getMaxZoom(); } void JNICALL nativeRotateBy(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jdouble sx, @@ -651,8 +597,7 @@ void JNICALL nativeRotateBy(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jd mbgl::Log::Debug(mbgl::Event::JNI, "nativeRotateBy"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - COFFEE_TRY_JNI(env, - CPP_TRY_JNI(env, nativeMapView->getMap().rotateBy(sx, sy, ex, ey, duration))); + nativeMapView->getMap().rotateBy(sx, sy, ex, ey, duration); } void JNICALL nativeSetBearing(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jdouble degrees, @@ -660,7 +605,7 @@ void JNICALL nativeSetBearing(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetBearing"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, nativeMapView->getMap().setBearing(degrees, duration))); + nativeMapView->getMap().setBearing(degrees, duration); } void JNICALL nativeSetBearing(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jdouble degrees, @@ -668,62 +613,58 @@ void JNICALL nativeSetBearing(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetBearing"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, nativeMapView->getMap().setBearing(degrees, cx, cy))); + nativeMapView->getMap().setBearing(degrees, cx, cy); } jdouble JNICALL nativeGetBearing(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { mbgl::Log::Debug(mbgl::Event::JNI, "nativeGetBearing"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - jdouble ret = 0.0; - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, ret = nativeMapView->getMap().getBearing())); - return ret; + return nativeMapView->getMap().getBearing(); } void JNICALL nativeResetNorth(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { mbgl::Log::Debug(mbgl::Event::JNI, "nativeResetNorth"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, nativeMapView->getMap().resetNorth())); + nativeMapView->getMap().resetNorth(); } void JNICALL nativeStartRotating(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { mbgl::Log::Debug(mbgl::Event::JNI, "nativeStartRotating"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, nativeMapView->getMap().startRotating())); + nativeMapView->getMap().startRotating(); } void JNICALL nativeStopRotating(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { mbgl::Log::Debug(mbgl::Event::JNI, "nativeStopRotating"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, nativeMapView->getMap().stopRotating())); + nativeMapView->getMap().stopRotating(); } void JNICALL nativeSetDebug(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jboolean debug) { mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetDebug"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, nativeMapView->getMap().setDebug(debug); - nativeMapView->enableFps(debug))); + nativeMapView->getMap().setDebug(debug); + nativeMapView->enableFps(debug); } void JNICALL nativeToggleDebug(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { mbgl::Log::Debug(mbgl::Event::JNI, "nativeToggleDebug"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, nativeMapView->getMap().toggleDebug(); - nativeMapView->enableFps(nativeMapView->getMap().getDebug()))); + nativeMapView->getMap().toggleDebug(); + nativeMapView->enableFps(nativeMapView->getMap().getDebug()); } jboolean JNICALL nativeGetDebug(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { mbgl::Log::Debug(mbgl::Event::JNI, "nativeGetDebug"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - jboolean ret = false; - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, ret = nativeMapView->getMap().getDebug())); - return ret; + return nativeMapView->getMap().getDebug(); } void JNICALL @@ -731,7 +672,7 @@ nativeSetReachability(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jboolean mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetReachability"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - COFFEE_TRY_JNI(env, CPP_TRY_JNI(env, nativeMapView->getFileSource().setReachability(status))); + nativeMapView->getFileSource().setReachability(status); } } diff --git a/android/mapboxgl-app.gyp b/android/mapboxgl-app.gyp index 938546636..60ec22164 100644 --- a/android/mapboxgl-app.gyp +++ b/android/mapboxgl-app.gyp @@ -10,8 +10,6 @@ 'sources': [ './cpp/native_map_view.cpp', './cpp/jni.cpp', - './cpp/coffeecatch.c', - './cpp/coffeejni.c', ], 'cflags_cc': [ '-I<(boost_root)/include', diff --git a/include/coffeecatch/coffeecatch.h b/include/coffeecatch/coffeecatch.h deleted file mode 100644 index 3aa00ddd4..000000000 --- a/include/coffeecatch/coffeecatch.h +++ /dev/null @@ -1,226 +0,0 @@ -/* CoffeeCatch, a tiny native signal handler/catcher for JNI code. - * (especially for Android/Dalvik) - * - * Copyright (c) 2013, Xavier Roche (http://www.httrack.com/) - * All rights reserved. - * See the "License" section below for the licensing terms. - * - * Description: - * - * Allows to "gracefully" recover from a signal (segv, sibus...) as if it was - * a Java exception. It will not gracefully recover from allocator/mutexes - * corruption etc., however, but at least "most" gentle crashes (null pointer - * dereferencing, integer division, stack overflow etc.) should be handled - * without too much troubles. - * - * The handler is thread-safe, but client must have exclusive control on the - * signal handlers (ie. the library is installing its own signal handlers on - * top of the existing ones). - * - * You must build all your libraries with `-funwind-tables', to get proper - * unwinding information on all binaries. On ARM, you may also use the - * `--no-merge-exidx-entries` linker switch, to solve certain issues with - * unwinding (the switch is possibly not needed anymore). - * On Android, this can be achieved by using this line in the Android.mk file - * in each library block: - * LOCAL_CFLAGS := -funwind-tables -Wl,--no-merge-exidx-entries - * - * Example: - * - * COFFEE_TRY() { - * call_some_native_function() - * } COFFEE_CATCH() { - * const char*const message = coffeecatch_get_message(); - * jclass cls = (*env)->FindClass(env, "java/lang/RuntimeException"); - * (*env)->ThrowNew(env, cls, strdup(message)); - * } COFFEE_END(); - * - * Implementation notes: - * - * Currently the library is installing both alternate stack and signal - * handlers for known signals (SIGABRT, SIGILL, SIGTRAP, SIGBUS, SIGFPE, - * SIGSEGV, SIGSTKFLT), and is using sigsetjmp()/siglongjmp() to return to - * "userland" (compared to signal handler context). As a security, an alarm - * is started as soon as a fatal signal is detected (ie. not something the - * JVM will handle) to kill the process after a grace period. Be sure your - * program will exit quickly after the error is caught, or call alarm(0) - * to cancel the pending time-bomb. - * The signal handlers had to be written with caution, because the virtual - * machine might be using signals (including SEGV) to handle JIT compiler, - * and some clever optimizations (such as NullPointerException handling) - * We are using several signal-unsafe functions, namely: - * - siglongjmp() to return to userland - * - pthread_getspecific() to get thread-specific setup - * - * License: - * - * Copyright (c) 2013, Xavier Roche (http://www.httrack.com/) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. 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. - * - * 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 THE COPYRIGHT OWNER 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. - */ - -#ifndef COFFEECATCH_H -#define COFFEECATCH_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Setup crash handler to enter in a protected section. If a recognized signal - * is received in this section, the execution will be diverted to the - * COFFEE_CATCH() block. - * - * Note: you MUST use the following pattern when using this macro: - * COFFEE_TRY() { - * .. protected section without exit point - * } COFFEE_CATCH() { - * .. handler section without exit point - * } COFFEE_END(); - * - * You can not exit the protected section block, or the handler section block, - * using statements such as "return", because the cleanup code would not be - * executed. - * - * It is advised to enclose this complete try/catch/end block in a dedicated - * function declared extern or __attribute__ ((noinline)). - * - * Example: - * - * void my_native_function(JNIEnv* env, jobject object, jint *retcode) { - * COFFEE_TRY() { - * *retcode = call_dangerous_function(env, object); - * } COFFEE_CATCH() { - * const char*const message = coffeecatch_get_message(); - * jclass cls = (*env)->FindClass(env, "java/lang/RuntimeException"); - * (*env)->ThrowNew(env, cls, strdup(message)); - * *retcode = -1; - * } COFFEE_END(); - * } - * - * In addition, the following restrictions MUST be followed: - * - the function must be declared extern, or with the special attribute - * __attribute__ ((noinline)). - * - you must not use local variables before the complete try/catch/end block, - * or define them as "volatile". - * - your function should not ignore the crash silently, as the library will - * ensure the process is killed after a grace period (typically 30s) to - * prevent any deadlock that may occur if the crash was caught inside a - * non-signal-safe function, for example (such as malloc()). - * -COFFEE_TRY() - **/ - -/** - * Declare the signal handler block. This block will be executed if a signal - * was received, and recognized, in the previous COFFEE_TRY() {} section. - * You may call audit functions in this block, such as coffeecatch_get_signal() - * or coffeecatch_get_message(). - * -COFFEE_CATCH() - **/ - -/** - * Declare the end of the COFFEE_TRY()/COFFEE_CATCH() section. - * Diagnostic functions must not be called beyond this point. - * -COFFEE_END() - **/ - -/** - * Get the signal associated with the crash. - * This function can only be called inside a COFFEE_CATCH() block. - */ -extern int coffeecatch_get_signal(void); - -/** - * Get the full error message associated with the crash. - * This function can only be called inside a COFFEE_CATCH() block, and the - * returned pointer is only valid within this block. (you may want to copy - * the string in a static buffer, or use strdup()) - */ -const char* coffeecatch_get_message(void); - -/** - * Raise an abort() signal in the current thread. If the current code section - * is protected, the 'exp', 'file' and 'line' information are stored for - * further audit. - */ -extern void coffeecatch_abort(const char* exp, const char* file, int line); - -/** - * Assertion check. If the expression is false, an abort() signal is raised - * using coffeecatch_abort(). - */ -#define coffeecatch_assert(EXP) (void)( (EXP) || (coffeecatch_abort(#EXP, __FILE__, __LINE__), 0) ) - -/** - * Get the backtrace size, or 0 upon error. - * This function can only be called inside a COFFEE_CATCH() block. - */ -extern size_t coffeecatch_get_backtrace_size(void); - -/** - * Get the backtrace pointer, or 0 upon error. - * This function can only be called inside a COFFEE_CATCH() block. - */ -extern uintptr_t coffeecatch_get_backtrace(ssize_t index); - -/** - * Enumerate the backtrace with information. - * This function can only be called inside a COFFEE_CATCH() block. - */ -extern void coffeecatch_get_backtrace_info(void (*fun)(void *arg, - const char *module, - uintptr_t addr, - const char *function, - uintptr_t offset), void *arg); - -/** - * Cancel any pending alarm() triggered after a signal was caught. - * Calling this function is dangerous, because it exposes the process to - * a possible deadlock if the signal was caught due to internal low-level - * library error (mutex being in a locked state, for example). - */ -extern int coffeecatch_cancel_pending_alarm(void); - -/** Internal functions & definitions, not to be used directly. **/ -#include -extern int coffeecatch_setup(void); -extern sigjmp_buf* coffeecatch_get_ctx(void); -extern void coffeecatch_cleanup(void); -#define COFFEE_TRY() \ - if (coffeecatch_setup() == 0 \ - && sigsetjmp(*coffeecatch_get_ctx(), 1) == 0) -#define COFFEE_CATCH() else -#define COFFEE_END() coffeecatch_cleanup() -/** End of internal functions & definitions. **/ - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/include/coffeecatch/coffeejni.h b/include/coffeecatch/coffeejni.h deleted file mode 100644 index 3d7fe1b28..000000000 --- a/include/coffeecatch/coffeejni.h +++ /dev/null @@ -1,133 +0,0 @@ -/* CoffeeCatch, a tiny native signal handler/catcher for JNI code. - * (especially for Android/Dalvik) - * - * Copyright (c) 2013, Xavier Roche (http://www.httrack.com/) - * All rights reserved. - * See the "License" section below for the licensing terms. - * - * Description: - * - * Allows to "gracefully" recover from a signal (segv, sibus...) as if it was - * a Java exception. It will not gracefully recover from allocator/mutexes - * corruption etc., however, but at least "most" gentle crashes (null pointer - * dereferencing, integer division, stack overflow etc.) should be handled - * without too much troubles. - * - * The handler is thread-safe, but client must have exclusive control on the - * signal handlers (ie. the library is installing its own signal handlers on - * top of the existing ones). - * - * You must build all your libraries with `-funwind-tables', to get proper - * unwinding information on all binaries. On ARM, you may also use the - * `--no-merge-exidx-entries` linker switch, to solve certain issues with - * unwinding (the switch is possibly not needed anymore). - * On Android, this can be achieved by using this line in the Android.mk file - * in each library block: - * LOCAL_CFLAGS := -funwind-tables -Wl,--no-merge-exidx-entries - * - * Example: - * COFFEE_TRY_JNI(env, *retcode = call_dangerous_function(env, object)); - * - * Implementation notes: - * - * Currently the library is installing both alternate stack and signal - * handlers for known signals (SIGABRT, SIGILL, SIGTRAP, SIGBUS, SIGFPE, - * SIGSEGV, SIGSTKFLT), and is using sigsetjmp()/siglongjmp() to return to - * "userland" (compared to signal handler context). As a security, an alarm - * is started as soon as a fatal signal is detected (ie. not something the - * JVM will handle) to kill the process after a grace period. Be sure your - * program will exit quickly after the error is caught, or call alarm(0) - * to cancel the pending time-bomb. - * The signal handlers had to be written with caution, because the virtual - * machine might be using signals (including SEGV) to handle JIT compiler, - * and some clever optimizations (such as NullPointerException handling) - * We are using several signal-unsafe functions, namely: - * - siglongjmp() to return to userland - * - pthread_getspecific() to get thread-specific setup - * - * License: - * - * Copyright (c) 2013, Xavier Roche (http://www.httrack.com/) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. 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. - * - * 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 THE COPYRIGHT OWNER 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. - */ - -#ifndef COFFEECATCH_JNI_H -#define COFFEECATCH_JNI_H - -#include - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Setup crash handler to enter in a protected section. If a recognized signal - * is received in this section, an appropriate native Java Error will be - * raised. - * - * You can not exit the protected section block CODE_TO_BE_EXECUTED, using - * statements such as "return", because the cleanup code would not be - * executed. - * - * It is advised to enclose the complete CODE_TO_BE_EXECUTED block in a - * dedicated function declared extern or __attribute__ ((noinline)). - * - * You must build all your libraries with `-funwind-tables', to get proper - * unwinding information on all binaries. On Android, this can be achieved - * by using this line in the Android.mk file in each library block: - * LOCAL_CFLAGS := -funwind-tables - * - * Example: - * - * void my_native_function(JNIEnv* env, jobject object, jint *retcode) { - * COFFEE_TRY_JNI(env, *retcode = call_dangerous_function(env, object)); - * } - * - * In addition, the following restrictions MUST be followed: - * - the function must be declared extern, or with the special attribute - * __attribute__ ((noinline)). - * - you must not use local variables before the COFFEE_TRY_JNI block, - * or define them as "volatile". - * -COFFEE_TRY_JNI(JNIEnv* env, CODE_TO_BE_EXECUTED) - */ - -/** Internal functions & definitions, not to be used directly. **/ -extern void coffeecatch_throw_exception(JNIEnv* env); -#define COFFEE_TRY_JNI(ENV, CODE) \ - do { \ - COFFEE_TRY() { \ - CODE; \ - } COFFEE_CATCH() { \ - coffeecatch_throw_exception(ENV); \ - } COFFEE_END(); \ - } while(0) -/** End of internal functions & definitions. **/ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index 94ee72da6..f5948fbb2 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -33,10 +33,6 @@ #include -#ifdef __ANDROID__ - #include -#endif - // Check libuv library version. const static bool uvVersionCheck = []() { const unsigned int version = uv_version(); @@ -267,10 +263,6 @@ void Map::resume() { } void Map::run() { -#ifdef __ANDROID__ - COFFEE_TRY() { -#endif - if (mode == Mode::None) { #ifndef NDEBUG mapThread = mainThread; @@ -309,12 +301,6 @@ void Map::run() { mode = Mode::None; fileSource.clearLoop(); } -#ifdef __ANDROID__ - } COFFEE_CATCH() { - Log::Error(Event::Crash, "Map::run() crash:\n%s", coffeecatch_get_message()); - abort(); - } -#endif } void Map::checkForPause() {