void test_util_addr2line() { const char * file = __FILE__; const char * func = __func__; int line; const int max_bt = 50; void *bt_addr[max_bt]; int size; char * func_name , * file_name; int line_nr; line = __LINE__ + 2; size = backtrace(bt_addr , max_bt); test_assert_int_equal( size , 4 ); test_assert_true( util_addr2line_lookup( bt_addr[0] , &func_name , &file_name , &line_nr)); test_assert_string_equal( func_name , func ); test_assert_int_equal( line , line_nr ); test_assert_string_equal( file_name , file ); }
void util_abort(const char * fmt , ...) { pthread_mutex_lock( &__abort_mutex ); /* Abort before unlock() */ { va_list ap; va_start(ap , fmt); printf("\n\n"); fprintf(stderr,"\n\n"); vfprintf(stderr , fmt , ap); va_end(ap); /* The backtrace is based on calling the external program addr2line; the call is based on util_fork_exec() which is currently only available on POSIX. */ const bool include_backtrace = true; if (include_backtrace) { const int max_bt = 50; char *executable; void *array[max_bt]; char **strings; char ** func_list; char ** file_line_list; int max_func_length = 0; int size,i; if (__abort_program_message != NULL) { fprintf(stderr,"--------------------------------------------------------------------------------\n"); fprintf(stderr,"%s",__abort_program_message); fprintf(stderr,"--------------------------------------------------------------------------------\n"); } fprintf(stderr,"\n"); fprintf(stderr,"****************************************************************************\n"); fprintf(stderr,"** **\n"); fprintf(stderr,"** A fatal error occured, and we have to abort. **\n"); fprintf(stderr,"** **\n"); fprintf(stderr,"** We now *try* to provide a backtrace, which would be very useful **\n"); fprintf(stderr,"** when debugging. The process of making a (human readable) backtrace **\n"); fprintf(stderr,"** is quite complex, among other things it involves several calls to the **\n"); fprintf(stderr,"** external program addr2line. We have arrived here because the program **\n"); fprintf(stderr,"** state is already quite broken, so the backtrace might be (seriously) **\n"); fprintf(stderr,"** broken as well. **\n"); fprintf(stderr,"** **\n"); fprintf(stderr,"****************************************************************************\n"); size = backtrace(array , max_bt); strings = backtrace_symbols(array , size); executable = util_bt_alloc_current_executable(strings[0]); if (executable != NULL) { fprintf(stderr,"Current executable : %s \n",executable); func_list = util_calloc(size , sizeof * func_list ); file_line_list = util_calloc(size , sizeof * file_line_list ); for (i=0; i < size; i++) { util_addr2line_lookup(executable , strings[i] , &func_list[i] , &file_line_list[i]); max_func_length = util_int_max(max_func_length , strlen(func_list[i])); } { char string_fmt[64]; sprintf(string_fmt, " #%s02d %s-%ds(..) in %ss \n" , "%" , "%" , max_func_length , "%"); fprintf(stderr , "--------------------------------------------------------------------------------\n"); for (i=0; i < size; i++) { int line_nr; if (util_sscanf_int(file_line_list[i] , &line_nr)) fprintf(stderr, string_fmt , i , func_list[i], file_line_list[i]); else fprintf(stderr, string_fmt , i , func_list[i], file_line_list[i]); } fprintf(stderr , "--------------------------------------------------------------------------------\n"); util_free_stringlist(func_list , size); util_free_stringlist(file_line_list , size); } } else fprintf(stderr,"Could not determine executable file for:%s - no backtrace. \n",strings[0]); free(strings); util_safe_free(executable); } if (getenv("UTIL_ABORT") != NULL) { fprintf(stderr , "Aborting ... \n"); abort(); } else { fprintf(stderr , "Exiting ... \n"); exit(1); } // Would have preferred abort() here - but that comes in conflict with the SIGABRT signal. } pthread_mutex_unlock( &__abort_mutex ); }