X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fecrash.c;fp=citadel%2Fecrash.c;h=0000000000000000000000000000000000000000;hb=c750a06a241dc2737fa68c24b340a1bd82894f74;hp=ec91a02e4418bc166e9e0289fc5834526b7cf8cc;hpb=82adc0fcf4da8e91ec4ff11f1a0f9d96449f85ad;p=citadel.git diff --git a/citadel/ecrash.c b/citadel/ecrash.c deleted file mode 100644 index ec91a02e4..000000000 --- a/citadel/ecrash.c +++ /dev/null @@ -1,516 +0,0 @@ -/* - * author: David Frascone - * - * eCrash Implementation - * - * eCrash will allow you to capture stack traces in the - * event of a crash, and write those traces to disk, stdout, - * or any other file handle. - * - * modified to integrate closer into citadel by Wilfried Goesgens - * - * vim: ts=4 - * - * This program is open source software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "sysdep.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "server.h" -#include "sysdep_decls.h" -#include "support.h" -#include "config.h" -#include "citserver.h" -#include "ecrash.h" - -#define NIY() printf("function not implemented yet!\n"); -#ifdef HAVE_BACKTRACE -#include -static eCrashParameters gbl_params; - -static int gbl_backtraceEntries; -static void **gbl_backtraceBuffer; -static char **gbl_backtraceSymbols; -static int gbl_backtraceDoneFlag = 0; - -static void *stack_frames[50]; -static size_t size, NThread; -static char **strings; - -/* - * Private structures for our thread list - */ -typedef struct thread_list_node{ - char *threadName; - pthread_t thread; - int backtraceSignal; - sighandler_t oldHandler; - struct thread_list_node *Next; -} ThreadListNode; - -static pthread_mutex_t ThreadListMutex = PTHREAD_MUTEX_INITIALIZER; -static ThreadListNode *ThreadList = NULL; - -/********************************************************************* - ********************************************************************* - ** P R I V A T E F U N C T I O N S - ********************************************************************* - ********************************************************************/ - - -/*! - * Insert a node into our threadList - * - * @param name Text string indicating our thread - * @param thread Our Thread Id - * @param signo Signal to create backtrace with - * @param old_handler Our old handler for signo - * - * @returns zero on success - */ -static int addThreadToList(char *name, pthread_t thread,int signo, - sighandler_t old_handler) -{ - ThreadListNode *node; - - node = malloc(sizeof(ThreadListNode)); - if (!node) return -1; - - DPRINTF(ECRASH_DEBUG_VERBOSE, - "Adding thread 0x%08x (%s)\n", (unsigned int)thread, name); - node->threadName = strdup(name); - node->thread = thread; - node->backtraceSignal = signo; - node->oldHandler = old_handler; - - /* And, add it to the list */ - pthread_mutex_lock(&ThreadListMutex); - node->Next = ThreadList; - ThreadList = node; - pthread_mutex_unlock(&ThreadListMutex); - - return 0; - -} // addThreadToList - -/*! - * Remove a node from our threadList - * - * @param thread Our Thread Id - * - * @returns zero on success - */ -static int removeThreadFromList(pthread_t thread) -{ - ThreadListNode *Probe, *Prev=NULL; - ThreadListNode *Removed = NULL; - - DPRINTF(ECRASH_DEBUG_VERBOSE, - "Removing thread 0x%08x from list . . .\n", (unsigned int)thread); - pthread_mutex_lock(&ThreadListMutex); - for (Probe=ThreadList;Probe != NULL; Probe = Probe->Next) { - if (Probe->thread == thread) { - // We found it! Unlink it and move on! - Removed = Probe; - if (Prev == NULL) { // head of list - ThreadList = Probe->Next; - } else { - // Prev != null, so we need to link around ourselves. - Prev->Next = Probe->Next; - } - Removed->Next = NULL; - break; - } - - Prev = Probe; - } - pthread_mutex_unlock(&ThreadListMutex); - - // Now, if something is in Removed, free it, and return success - if (Removed) { - DPRINTF(ECRASH_DEBUG_VERBOSE, - " Found %s -- removing\n", Removed->threadName); - // Reset the signal handler - signal(Removed->backtraceSignal, Removed->oldHandler); - - // And free the allocated memory - free (Removed->threadName); - free (Removed); - - return 0; - } else { - DPRINTF(ECRASH_DEBUG_VERBOSE, - " Not Found\n"); - return -1; // Not Found - } -} // removeThreadFromList - -/*! - * Print out a line of output to all our destinations - * - * One by one, output a line of text to all of our output destinations. - * - * Return failure if we fail to output to any of them. - * - * @param format Normal printf style vararg format - * - * @returns nothing// bytes written, or error on failure. - */ -static void outputPrintf(char *format, ...) -{ - va_list ap; - - va_start(ap, format); - - vsyslog(LOG_CRIT|LOG_NDELAY|LOG_MAIL, format, ap); -} // outputPrintf - - - -/*! - * Dump our backtrace into a global location - * - * This function will dump out our backtrace into our - * global holding area. - * - */ -static void createGlobalBacktrace( void ) -{ - - size = backtrace(stack_frames, sizeof(stack_frames) / sizeof(void*)); - for (NThread = 0; NThread < size; NThread++) - { - syslog(LOG_CRIT|LOG_NDELAY|LOG_MAIL, "RAW: %p ", stack_frames[NThread]); - } - strings = backtrace_symbols(stack_frames, size); - for (NThread = 0; NThread < size; NThread++) { - if (strings != NULL) { - syslog(LOG_CRIT|LOG_NDELAY|LOG_MAIL, "RAW: %p ", strings[NThread]); - } - } -} /* createGlobalBacktrace */ -static void outputRawtrace( void ) -{ - - size = backtrace(stack_frames, sizeof(stack_frames) / sizeof(void*)); - for (NThread = 0; NThread < size; NThread++) - { - syslog(LOG_CRIT|LOG_NDELAY|LOG_MAIL, "RAW: %p ", stack_frames[NThread]); - } -} /* createGlobalBacktrace */ - -/*! - * Print out (to all the fds, etc), or global backtrace - */ -static void outputGlobalBacktrace ( void ) -{ - int i; - - for (i=0; i < gbl_backtraceEntries; i++) { - if (gbl_backtraceSymbols != FALSE) { - outputPrintf("* Frame %02x: %s\n", - i, gbl_backtraceSymbols[i]); - } else { - outputPrintf("* Frame %02x: %p\n", i, - gbl_backtraceBuffer[i]); - } - } -} // outputGlobalBacktrace - -/*! - * Output our current stack's backtrace - */ -static void outputBacktrace( void ) -{ - createGlobalBacktrace(); - outputGlobalBacktrace(); -} /* outputBacktrace */ - -static void outputBacktraceThreads( void ) -{ - ThreadListNode *probe; - int i; - - // When we're backtracing, don't worry about the mutex . . hopefully - // we're in a safe place. - - for (probe=ThreadList; probe; probe=probe->Next) { - gbl_backtraceDoneFlag = 0; - pthread_kill(probe->thread, probe->backtraceSignal); - for (i=0; i < gbl_params.threadWaitTime; i++) { - if (gbl_backtraceDoneFlag) - break; - sleep(1); - } - if (gbl_backtraceDoneFlag) { - outputPrintf("* Backtrace of \"%s\" (0x%08x)\n", - probe->threadName, (unsigned int)probe->thread); - outputGlobalBacktrace(); - } else { - outputPrintf("* Error: unable to get backtrace of \"%s\" (0x%08x)\n", - probe->threadName, (unsigned int)probe->thread); - } - outputPrintf("*\n"); - } -} // outputBacktraceThreads - - -/*! - * Handle signals (crash signals) - * - * This function will catch all crash signals, and will output the - * crash dump. - * - * It will physically write (and sync) the current thread's information - * before it attempts to send signals to other threads. - * - * @param signum Signal received. - */ -static void crash_handler(int signo) -{ - outputRawtrace(); - outputPrintf("*********************************************************\n"); - outputPrintf("* eCrash Crash Handler\n"); - outputPrintf("*********************************************************\n"); - outputPrintf("*\n"); - outputPrintf("* Got a crash! signo=%d\n", signo); - outputPrintf("*\n"); - outputPrintf("* Offending Thread's Backtrace:\n"); - outputPrintf("*\n"); - outputBacktrace(); - outputPrintf("*\n"); - - if (gbl_params.dumpAllThreads != FALSE) { - outputBacktraceThreads(); - } - - outputPrintf("*\n"); - outputPrintf("*********************************************************\n"); - outputPrintf("* eCrash Crash Handler\n"); - outputPrintf("*********************************************************\n"); - - exit(signo); -} // crash_handler - -/*! - * Handle signals (bt signals) - * - * This function shoudl be called to generate a crashdump into our - * global area. Once the dump has been completed, this function will - * return after tickling a global. Since mutexes are not async - * signal safe, the main thread, after signaling us to generate our - * own backtrace, will sleep for a few seconds waiting for us to complete. - * - * @param signum Signal received. - */ -static void bt_handler(int signo) -{ - createGlobalBacktrace(); - gbl_backtraceDoneFlag=1; -} // bt_handler - -/*! - * Validate a passed-in symbol table - * - * For now, just print it out (if verbose), and make sure it's - * sorted and none of the pointers are zero. - */ -static int ValidateSymbolTable( void ) -{ - int i; - int rc=0; - unsigned long lastAddress =0; - - // Get out of here if the table is empty - if (!gbl_params.symbolTable) return 0; - - // Dump it in verbose mode - DPRINTF(ECRASH_DEBUG_VERBOSE, - "Symbol Table Provided with %d symbols\n", - gbl_params.symbolTable->numSymbols); - for (i=0; i < gbl_params.symbolTable->numSymbols; i++){ - // Dump it in verbose mode - DPRINTF(ECRASH_DEBUG_VERBOSE, - "%-30s %p\n", - gbl_params.symbolTable->symbols[i].function, - gbl_params.symbolTable->symbols[i].address); - if (lastAddress > - (unsigned long)gbl_params.symbolTable->symbols[i].address) { - DPRINTF(ECRASH_DEBUG_ERROR, - "Error: symbol table is not sorted (last=%p, current=%p)\n", - (void *)lastAddress, - gbl_params.symbolTable->symbols[i].address); - rc = -1; - } - - } // for - - return rc; - -} // ValidateSymbolTable - -/********************************************************************* - ********************************************************************* - ** P U B L I C F U N C T I O N S - ********************************************************************* - ********************************************************************/ - -/*! - * Initialize eCrash. - * - * This function must be called before calling any other eCrash - * functions. It sets up the global behavior of the system, and - * registers the calling thread for crash dumps. - * - * @param params Our input parameters. The passed in structure will be copied. - * - * @return Zero on success. - */ -int eCrash_Init(eCrashParameters *params) -{ - int sigIndex; - int ret = 0; -#ifdef DO_SIGNALS_RIGHT - sigset_t blocked; - struct sigaction act; -#endif - - DPRINTF(ECRASH_DEBUG_VERY_VERBOSE,"Init Starting params = %p\n", params); - - if (params == NULL) return -1; - // Allocate our backtrace area - gbl_backtraceBuffer = malloc(sizeof(void *) * (params->maxStackDepth+5)); - -#ifdef DO_SIGNALS_RIGHT - sigemptyset(&blocked); - act.sa_sigaction = crash_handler; - act.sa_mask = blocked; - act.sa_flags = SA_SIGINFO; -#endif - - if (params != NULL) { - // Make ourselves a global copy of params. - gbl_params = *params; - gbl_params.filename = strdup(params->filename); - - // Set our defaults, if they weren't specified - if (gbl_params.maxStackDepth == 0 ) - gbl_params.maxStackDepth = ECRASH_DEFAULT_STACK_DEPTH; - - if (gbl_params.defaultBacktraceSignal == 0 ) - gbl_params.defaultBacktraceSignal = ECRASH_DEFAULT_BACKTRACE_SIGNAL; - - if (gbl_params.threadWaitTime == 0 ) - gbl_params.threadWaitTime = ECRASH_DEFAULT_THREAD_WAIT_TIME; - - if (gbl_params.debugLevel == 0 ) - gbl_params.debugLevel = ECRASH_DEBUG_DEFAULT; - - // Copy our symbol table - if (gbl_params.symbolTable) { - DPRINTF(ECRASH_DEBUG_VERBOSE, - "symbolTable @ %p -- %d symbols\n", gbl_params.symbolTable, - gbl_params.symbolTable->numSymbols); - // Make a copy of our symbol table - gbl_params.symbolTable = malloc(sizeof(eCrashSymbolTable)); - memcpy(gbl_params.symbolTable, params->symbolTable, - sizeof(eCrashSymbolTable)); - - // Now allocate / copy the actual table. - gbl_params.symbolTable->symbols = malloc(sizeof(eCrashSymbol) * - gbl_params.symbolTable->numSymbols); - memcpy(gbl_params.symbolTable->symbols, - params->symbolTable->symbols, - sizeof(eCrashSymbol) * gbl_params.symbolTable->numSymbols); - - ValidateSymbolTable(); - } - - // And, finally, register for our signals - for (sigIndex=0; gbl_params.signals[sigIndex] != 0; sigIndex++) { - DPRINTF(ECRASH_DEBUG_VERY_VERBOSE, - " Catching signal[%d] %d\n", sigIndex, - gbl_params.signals[sigIndex]); - - // I know there's a better way to catch signals with pthreads. - // I'll do it later TODO - signal(gbl_params.signals[sigIndex], crash_handler); - } - } else { - DPRINTF(ECRASH_DEBUG_ERROR, " Error: Null Params!\n"); - ret = -1; - } - DPRINTF(ECRASH_DEBUG_VERY_VERBOSE, "Init Complete ret=%d\n", ret); - return ret; -} /* eCrash_Init */ - -/*! - * UnInitialize eCrash. - * - * This function may be called to de-activate eCrash, release the - * signal handlers, and free any memory allocated by eCrash. - * - * @return Zero on success. - */ -int eCrash_Uninit( void ) -{ - NIY(); - - return 0; -} /* eCrash_Uninit */ - -/*! - * Register a thread for backtracing on crash. - * - * This function must be called by any thread wanting it's stack - * dumped in the event of a crash. The thread my specify what - * signal should be used, or the default, SIGUSR1 will be used. - * - * @param signo Signal to use to generate dump (default: SIGUSR1) - * - * @return Zero on success. - */ -int eCrash_RegisterThread(char *name, int signo) -{ - sighandler_t old_handler; - - // Register for our signal - if (signo == 0) { - signo = gbl_params.defaultBacktraceSignal; - } - - old_handler = signal(signo, bt_handler); - return addThreadToList(name, pthread_self(), signo, old_handler); - -} /* eCrash_RegisterThread */ - -/*! - * Un-register a thread for stack dumps. - * - * This function may be called to un-register any previously - * registered thread. - * - * @return Zero on success. - */ -int eCrash_UnregisterThread( void ) -{ - return removeThreadFromList(pthread_self()); -} /* eCrash_UnregisterThread */ - -#endif