diff --git a/lib/diagnostics.cpp b/lib/diagnostics.cpp index c00a6704e8..b20222c3ac 100644 --- a/lib/diagnostics.cpp +++ b/lib/diagnostics.cpp @@ -64,6 +64,20 @@ #include "diagnostics.h" +#ifdef ANDROID +// for signal handler backtrace +unwind_backtrace_signal_arch_t unwind_backtrace_signal_arch; +acquire_my_map_info_list_t acquire_my_map_info_list; +release_my_map_info_list_t release_my_map_info_list; +get_backtrace_symbols_t get_backtrace_symbols; +free_backtrace_symbols_t free_backtrace_symbols; +load_symbol_table_t load_symbol_table; +free_symbol_table_t free_symbol_table; +find_symbol_t find_symbol; +format_backtrace_line_t format_backtrace_line; +#endif + + #if defined(_WIN32) && defined(_MSC_VER) static _CrtMemState start_snapshot; @@ -92,6 +106,9 @@ static double max_stderr_file_size = 2048*1024; static double stdout_file_size = 0; static double max_stdout_file_size = 2048*1024; +#ifdef ANDROID +static void *libhandle; +#endif #if defined(_WIN32) && defined(_DEBUG) @@ -224,7 +241,6 @@ int diagnostics_init( boinc_copy(stdout_log, stdout_archive); } - // Redirect stderr and/or stdout, if requested // if (flags & BOINC_DIAG_REDIRECTSTDERR) { @@ -297,6 +313,28 @@ int diagnostics_init( #endif // defined(_WIN32) +#ifdef ANDROID +#define resolve_func(l,x) \ + x=(x##_t)dlsym(l,#x); \ + if (!x) {\ + fprintf(stderr,"Unable to resolve function %s\n",#x); \ + unwind_backtrace_signal_arch=NULL; \ + } + + if ((libhandle=dlopen("libcorkscrew.so",RTLD_NOW|RTLD_GLOBAL))) { + resolve_func(libhandle,unwind_backtrace_signal_arch); + resolve_func(libhandle,acquire_my_map_info_list); + resolve_func(libhandle,release_my_map_info_list); + resolve_func(libhandle,get_backtrace_symbols); + resolve_func(libhandle,free_backtrace_symbols); + resolve_func(libhandle,format_backtrace_line); + resolve_func(libhandle,load_symbol_table); + resolve_func(libhandle,free_symbol_table); + resolve_func(libhandle,find_symbol); + } else { + fprintf(stderr,"stackdumps unavailable\n"); + } +#endif // ANDROID // Install unhandled exception filters and signal traps. if (BOINC_SUCCESS != boinc_install_signal_handlers()) { @@ -425,6 +463,12 @@ int diagnostics_finish() { #endif // defined(_DEBUG) #endif // defined(_WIN32) +#ifdef ANDROID + if (libhandle) { + dlclose(libhandle); + } +#endif + // Set initalization flag to false. diagnostics_initialized = false; @@ -542,12 +586,12 @@ int diagnostics_cycle_logs() { // Set a signal handler only if it is not currently ignored // -extern "C" void boinc_set_signal_handler(int sig, void(*handler)(int)) { +extern "C" void boinc_set_signal_handler(int sig, handler_t handler) { #if HAVE_SIGACTION struct sigaction temp; sigaction(sig, NULL, &temp); if (temp.sa_handler != SIG_IGN) { - temp.sa_handler = handler; + temp.sa_handler = (sighandler_t)handler; // sigemptyset(&temp.sa_mask); sigaction(sig, &temp, NULL); } @@ -584,7 +628,33 @@ void set_signal_exit_code(int x) { signal_exit_code = x; } +#ifdef ANDROID +extern pthread_t timer_thread_handle; +extern pthread_t worker_thread_handle; +const char *argv0; + +static char *xtoa(size_t x) { + static char buf[20]; + static char hex[]="0123456789abcdef"; + int n; + buf[19]=0; + n=18; + while (x) { + buf[n--]=hex[x&0xf]; + x/=0x10; + } + buf[n--]='x'; + buf[n]='0'; + return buf+n; +} + +#endif + +#ifdef HAVE_SIGACTION +void boinc_catch_signal(int signal, struct siginfo *siginfo, void *sigcontext) { +#else void boinc_catch_signal(int signal) { +#endif switch(signal) { case SIGHUP: fprintf(stderr, "SIGHUP: terminal line hangup\n"); return; @@ -601,6 +671,24 @@ void boinc_catch_signal(int signal) { return; default: fprintf(stderr, "unknown signal %d\n", signal); break; } +#ifdef ANDROID + // per-thread signal masking doesn't work + // on old (pre-4.1) versions of Android. + // If we're handling this signal in the timer thread, + // send signal explicitly to worker thread. + // + if (pthread_self() == timer_thread_handle) { + fprintf(stderr,"for worker thread sent to timer thread. Reflecting.\n"); + pthread_kill(worker_thread_handle, signal); +#if defined(HAVE_SIGACTION) + sigset_t unblock; + sigemptyset(&unblock); + sigaddset(&unblock,signal); + sigprocmask(SIG_UNBLOCK,&unblock,NULL); +#endif + return; + } +#endif #ifdef __GLIBC__ void *array[64]; @@ -628,6 +716,62 @@ void boinc_catch_signal(int signal) { PrintBacktrace(); #endif +#ifdef ANDROID + // this is some dark undocumented Android voodoo that uses libcorkscrew.so + // minimal use of library functions because they may not work in an signal + // handler. +#define DUMP_LINE_LEN 256 + static backtrace_frame_t backtrace[64]; + static backtrace_symbol_t backtrace_symbols[64]; + if (unwind_backtrace_signal_arch != NULL) { + map_info_t *map_info=acquire_my_map_info_list(); + ssize_t size=unwind_backtrace_signal_arch(siginfo,sigcontext,map_info,backtrace,0,64); + get_backtrace_symbols(backtrace,size,backtrace_symbols); + char line[DUMP_LINE_LEN]; + for (int i=0;istart; + strlcat(line," (",DUMP_LINE_LEN); + strlcat(line,symbol->name,DUMP_LINE_LEN); + strlcat(line,"+",DUMP_LINE_LEN); + strlcat(line,xtoa(offset),DUMP_LINE_LEN); + strlcat(line,")",DUMP_LINE_LEN); + line[DUMP_LINE_LEN-1]=0; + } else { + strlcat(line, " (\?\?\?)",DUMP_LINE_LEN); + } + if (symbols) free_symbol_table(symbols); + } + if (backtrace[i].absolute_pc) { + strlcat(line," [",DUMP_LINE_LEN); + strlcat(line,xtoa(*reinterpret_cast(backtrace[i].absolute_pc)),DUMP_LINE_LEN); + strlcat(line,"]",DUMP_LINE_LEN); + } + strlcat(line,"\n",DUMP_LINE_LEN); + write(fileno(stderr),line,strlen(line)); + fflush(stderr); + } + } +#endif // ANDROID + fprintf(stderr, "\nExiting...\n"); _exit(signal_exit_code); } diff --git a/lib/diagnostics.h b/lib/diagnostics.h index 46f65d671c..4409178842 100644 --- a/lib/diagnostics.h +++ b/lib/diagnostics.h @@ -30,6 +30,10 @@ #endif #endif +#ifdef HAVE_DLFCN_H +#include +#endif + // flags for boinc_init_diagnostics() // @@ -117,9 +121,15 @@ extern UINT WINAPI diagnostics_unhandled_exception_monitor(LPVOID lpParameter); extern LONG CALLBACK boinc_catch_signal(EXCEPTION_POINTERS *ExceptionInfo); extern void boinc_catch_signal_invalid_parameter(const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t pReserved); #else +#ifdef HAVE_SIGACTION +typedef void (*handler_t)(int, struct siginfo *, void *); +extern void boinc_catch_signal(int signal, struct siginfo *siginfo, void *sigcontext); +#else +typedef void (*handler_t)(int); extern void boinc_catch_signal(int signal); -extern void boinc_set_signal_handler(int sig, void(*handler)(int)); -extern void boinc_set_signal_handler_force(int sig, void(*handler)(int)); +#endif +extern void boinc_set_signal_handler(int sig, handler_t handler); +extern void boinc_set_signal_handler_force(int sig, handler_t handler); #endif @@ -134,6 +144,74 @@ extern void set_signal_exit_code(int); } #endif +#ifdef ANDROID +// Yes, these are undocumented android functions located +// libcorkscrew.so . They may not always be there, but it's better than +// nothing. And we've got source so we could reimplement them if necessary. +extern const char *argv0; + +typedef struct map_info_t map_info_t; + +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; + +typedef struct { + uintptr_t start; + uintptr_t end; + char* name; +} symbol_t; + +typedef struct { + symbol_t* symbols; + size_t num_symbols; +} symbol_table_t; + + +typedef ssize_t (*unwind_backtrace_signal_arch_t)( + siginfo_t *, void *, const map_info_t *, backtrace_frame_t *, + size_t , size_t + ); +extern unwind_backtrace_signal_arch_t unwind_backtrace_signal_arch; + +typedef map_info_t *(*acquire_my_map_info_list_t)(); +extern acquire_my_map_info_list_t acquire_my_map_info_list; + +typedef void (*release_my_map_info_list_t)(map_info_t *); +extern release_my_map_info_list_t release_my_map_info_list; + +typedef void (*get_backtrace_symbols_t)( + const backtrace_frame_t *, size_t, backtrace_symbol_t * + ); +extern get_backtrace_symbols_t get_backtrace_symbols; + +typedef void (*free_backtrace_symbols_t)(backtrace_symbol_t* symbols, +size_t frames); +extern free_backtrace_symbols_t free_backtrace_symbols; + +typedef symbol_table_t *(*load_symbol_table_t)(const char *); +extern load_symbol_table_t load_symbol_table; + +typedef void (*free_symbol_table_t)(symbol_table_t *); +extern free_symbol_table_t free_symbol_table; + +typedef symbol_t *(*find_symbol_t)(const symbol_table_t *, uintptr_t ); +extern find_symbol_t find_symbol; + +typedef void (* format_backtrace_line_t)(unsigned, const backtrace_frame_t *, const backtrace_symbol_t *, char *, size_t); +extern format_backtrace_line_t format_backtrace_line; + +#endif // ANDROID #ifdef _WIN32