// // Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo // // The contents of this file are covered under the licence agreement in the // file "LICENCE" distributed with Cforall. // // interpose.c -- // // Author : Thierry Delisle // Created On : Wed Mar 29 16:10:31 2017 // Last Modified By : Peter A. Buhr // Last Modified On : Fri Jul 21 22:27:33 2017 // Update Count : 1 // #include #include extern "C" { #include #include #include #include #define __USE_GNU #include #undef __USE_GNU #include } #include "bits/debug.h" #include "bits/defs.h" #include "bits/signal.h" #include "startup.h" void __cfaabi_interpose_startup(void) __attribute__(( constructor( STARTUP_PRIORITY_CORE ) )); typedef void (*generic_fptr_t)(void); generic_fptr_t interpose_symbol( const char* symbol, const char *version ) { const char * error; static void * library; if ( ! library ) { #if defined( RTLD_NEXT ) library = RTLD_NEXT; #else // missing RTLD_NEXT => must hard-code library name, assuming libstdc++ library = dlopen( "libc.so.6", RTLD_LAZY ); error = dlerror(); if ( error ) { abortf( "interpose_symbol : failed to open libc, %s\n", error ); } #endif } // if union { generic_fptr_t fptr; void* ptr; } originalFunc; #if defined( _GNU_SOURCE ) if ( version ) { originalFunc.ptr = dlvsym( library, symbol, version ); } else { originalFunc.ptr = dlsym( library, symbol ); } #else originalFunc.ptr = dlsym( library, symbol ); #endif // _GNU_SOURCE error = dlerror(); if ( error ) abortf( "interpose_symbol : internal error, %s\n", error ); return originalFunc.fptr; } __typeof__( exit ) libc_exit __attribute__(( noreturn )); __typeof__( abort ) libc_abort __attribute__(( noreturn )); forall(dtype T) static inline void assign_ptr( T** symbol_ptr, const char * symbol_name, const char * version) { union { generic_fptr_t gp; T* tp; } u; u.gp = interpose_symbol( symbol_name, version ); *symbol_ptr = u.tp; } #define INIT_REALRTN( x, ver ) assign_ptr( (void**)&libc_##x, #x, ver) void sigHandler_segv ( __CFA_SIGPARMS__ ); void sigHandler_abort( __CFA_SIGPARMS__ ); void __cfaabi_interpose_startup() { const char *version = NULL; INIT_REALRTN( abort, version ); INIT_REALRTN( exit, version ); __kernel_sigaction( SIGSEGV, sigHandler_segv , SA_SIGINFO ); // Failure handler __kernel_sigaction( SIGBUS , sigHandler_segv , SA_SIGINFO ); // Failure handler __kernel_sigaction( SIGABRT, sigHandler_abort, SA_SIGINFO ); // Failure handler } //============================================================================================= // Terminating Signals logic //============================================================================================= extern "C" { void abort (void) __attribute__ ((__nothrow__, __leaf__, __noreturn__)) { abortf( NULL ); } void exit (int __status) __attribute__ ((__nothrow__, __leaf__, __noreturn__)) { libc_exit(__status); } } void abort( const char *fmt, va_list argp ) __attribute__ ((__nothrow__, __leaf__, __noreturn__)) { abortf( fmt, argp ); } void * kernel_abort (void) __attribute__ ((__nothrow__, __leaf__, __weak__)) { return NULL; } void kernel_abort_msg(void * data, char * buffer, int size) __attribute__ ((__nothrow__, __leaf__, __weak__)) {} enum { abort_text_size = 1024 }; static char abort_text[ abort_text_size ]; extern "C" { void abortf( const char fmt[], ... ) __attribute__ ((__nothrow__, __leaf__, __noreturn__)) { void * kernel_data = kernel_abort(); int len; if( fmt ) { va_list args; va_start( args, fmt ); len = vsnprintf( abort_text, abort_text_size, fmt, args ); va_end( args ); __cfaabi_dbg_bits_write( abort_text, len ); __cfaabi_dbg_bits_write( "\n", 1 ); } len = snprintf( abort_text, abort_text_size, "Cforall Runtime error (UNIX pid:%ld)\n", (long int)getpid() ); // use UNIX pid (versus getPid) __cfaabi_dbg_bits_write( abort_text, len ); kernel_abort_msg( kernel_data, abort_text, abort_text_size ); libc_abort(); } } // skip first 6 stack frames by default static void __kernel_backtrace() { // skip first N stack frames int start = 6; enum { Frames = 50 }; void * array[Frames]; int size = backtrace( array, Frames ); char ** messages = backtrace_symbols( array, size ); // find executable name *index( messages[0], '(' ) = '\0'; __cfaabi_dbg_bits_print_nolock( "Stack back trace for: %s\n", messages[0]); // skip last 2 stack frames after main for ( int i = start; i < size && messages != NULL; i += 1 ) { char * name = NULL; char * offset_begin = NULL; char * offset_end = NULL; for ( char *p = messages[i]; *p; ++p ) { // find parantheses and +offset if ( *p == '(' ) { name = p; } else if ( *p == '+' ) { offset_begin = p; } else if ( *p == ')' ) { offset_end = p; break; } } // if line contains symbol print it int frameNo = i - start; if ( name && offset_begin && offset_end && name < offset_begin ) { // delimit strings *name++ = '\0'; *offset_begin++ = '\0'; *offset_end++ = '\0'; __cfaabi_dbg_bits_print_nolock( "(%i) %s : %s + %s %s\n", frameNo, messages[i], name, offset_begin, offset_end); } // otherwise, print the whole line else { __cfaabi_dbg_bits_print_nolock( "(%i) %s\n", frameNo, messages[i] ); } } free( messages ); } void sigHandler_segv( __CFA_SIGPARMS__ ) { // skip first only 1 stack frames in case of segfault. abortf( "*CFA runtime error* program cfa-cpp terminated with %s\n", sig == SIGSEGV ? "segment fault." : "bus error." ); } void sigHandler_abort( __CFA_SIGPARMS__ ) { __kernel_backtrace(); // reset default signal handler __kernel_sigdefault( SIGABRT ); raise( SIGABRT ); } // Local Variables: // // mode: c // // tab-width: 4 // // End: //