/*
- * File: eCrash.c
- * @author David Frascone
+ * author: David Frascone
*
- * eCrash Implementation
+ * 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.
+ * 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
+ * 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 <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <fcntl.h>
+#include <syslog.h>
#include <sys/types.h>
#include <sys/stat.h>
-#include <execinfo.h>
#include <pthread.h>
+#include <libcitadel.h>
+#include "server.h"
#include "sysdep_decls.h"
+#include "support.h"
+#include "config.h"
+#include "citserver.h"
#include "ecrash.h"
-#define NIY() printf("%s: Not Implemented Yet!\n", __FUNCTION__)
+#define NIY() printf("function not implemented yet!\n");
#ifdef HAVE_BACKTRACE
+#include <execinfo.h>
static eCrashParameters gbl_params;
-static int gbl_fd=-1;
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
*/
}
} // removeThreadFromList
-/*!
- * Output text to a fd, looping to avoid being interrupted.
- *
- * @param str String to output
- * @param bytes String length
- * @param fd File descriptor to write to
- *
- * @returns bytes written, or error on failure.
- */
-static int blockingWrite(char *str, int bytes, int fd)
-{
- int offset=0;
- int bytesWritten;
- int totalWritten = 0;
-
- while (bytes > 0) {
- bytesWritten = write(fd, &str[offset], bytes);
- if (bytesWritten < 1) break;
- totalWritten += bytesWritten;
- bytes -= bytesWritten;
- }
-
- return totalWritten;
-
-} // blockingWrite
/*!
* Print out a line of output to all our destinations
*
*/
static void outputPrintf(char *format, ...)
{
- // Our output line of text
- static char outputLine[MAX_LINE_LEN];
- //int bytesInLine;
va_list ap;
- //int return_value=0;
va_start(ap, format);
- return lprintf(CTDL_EMERG, format, ap);
-
-/*
- bytesInLine = vsnprintf(outputLine, MAX_LINE_LEN-1, format, ap);
- if (bytesInLine > -1 && bytesInLine < (MAX_LINE_LEN-1)) {
- // We're a happy camper -- start printing
- if (gbl_params.filename) {
- // append to our file -- hopefully it's been opened
- if (gbl_fd != -1) {
- if (blockingWrite(outputLine, bytesInLine, gbl_fd)) {
- return_value=-2;
- }
- }
- }
-
- // Write to our file pointer
- if (gbl_params.filep != NULL) {
- if (fwrite(outputLine, bytesInLine, 1, gbl_params.filep) != 1) {
- return_value=-3;
- }
- fflush(gbl_params.filep);
- }
-
- // Write to our fd
- if (gbl_params.fd != -1) {
- if (blockingWrite(outputLine, bytesInLine, gbl_params.fd)) {
- return_value=-4;
- }
- }
- } else {
- // We overran our string.
- return_value=-1;
- }
-*/
+ vsyslog(LOG_CRIT|LOG_NDELAY|LOG_MAIL, format, ap);
} // outputPrintf
-/*!
- * Initialize our output (open files, etc)
- *
- * This file initializes all output streams, since we're about
- * to have output.
- *
- */
-static void outputInit( void )
-{
- if (gbl_params.filename) {
- /* First try append */
- gbl_fd = open(gbl_params.filename, O_WRONLY|O_APPEND);
- if (gbl_fd < 0) {
- gbl_fd = open(gbl_params.filename, O_RDWR|O_CREAT,
- S_IREAD|S_IWRITE|S_IRGRP|S_IROTH); // 0644
- if (gbl_fd < 0) {
- gbl_fd = -1;
- }
- }
- }
-} // outputInit
-
-
-/*!
- * Finalize our output (close files, etc)
- *
- * This file closes all output streams.
- *
- */
-static void outputFini( void )
-{
-/* -> these seem to run into mutexes in the libc...
- if (gbl_fd > -1)
- close(gbl_fd);
-
- if (gbl_params.filep != NULL)
- fclose(gbl_params.filep);
-
- if (gbl_params.fd > -1)
- close(gbl_params.fd);
-*/
- // Just in case someone tries to call outputPrintf after outputFini
- gbl_fd = gbl_params.fd = -1;
- gbl_params.filep = NULL;
- sync();
-
-} // outputFini
-
-static void *lookupClosestSymbol(eCrashSymbolTable *table,
- void *address)
-{
- int addr;
- eCrashSymbol *last=NULL;
-
- // For now, use a linear lookup.
- DPRINTF(ECRASH_DEBUG_VERBOSE,
- "Looking for %p in %d symbols\n", address, table->numSymbols);
- for (addr=0; addr < table->numSymbols; addr++) {
- DPRINTF(ECRASH_DEBUG_VERBOSE,
- " Examining [%d] %p\n", addr,
- table->symbols[addr].address);
- if (table->symbols[addr].address > address) {
- break;
- }
- last = &table->symbols[addr];
- }
-
- // last will either be NULL, or the last address less than the
- // one we're looking for.
- DPRINTF(ECRASH_DEBUG_VERBOSE,
- "Returning %s (%p)\n", last?last->function:"(nil)",
- last?last->address:0);
- return last;
-
-} // lookupClosestSymbol
/*!
* Dump our backtrace into a global location
static void createGlobalBacktrace( void )
{
- gbl_backtraceEntries = backtrace(gbl_backtraceBuffer,
- gbl_params.maxStackDepth);
-
- /* This is NOT signal safe -- it calls malloc. We need to
- let the caller pass in a pointer to a symbol table inside of
- our params. TODO */
-
- if (!gbl_params.symbolTable) {
- if (gbl_params.useBacktraceSymbols != FALSE) {
- gbl_backtraceSymbols = backtrace_symbols(gbl_backtraceBuffer,
- gbl_backtraceEntries);
+ 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 */
/*!
int i;
for (i=0; i < gbl_backtraceEntries; i++) {
- if (gbl_params.symbolTable) {
- eCrashSymbol *symbol;
-
- symbol = lookupClosestSymbol(gbl_params.symbolTable,
- gbl_backtraceBuffer[i]);
-
- if (symbol) {
- outputPrintf("* Frame %02d: %s+%u\n",
- i, symbol->function,
- gbl_backtraceBuffer[i] - symbol->address);
- } else {
- outputPrintf("* Frame %02d: %p\n", i,
- gbl_backtraceBuffer[i]);
- }
+ if (gbl_backtraceSymbols != FALSE) {
+ outputPrintf("* Frame %02x: %s\n",
+ i, gbl_backtraceSymbols[i]);
} else {
- if (gbl_backtraceSymbols != FALSE) {
- outputPrintf("* Frame %02d: %s\n",
- i, gbl_backtraceSymbols[i]);
- } else {
- outputPrintf("* Frame %02d: %p\n", i,
- gbl_backtraceBuffer[i]);
- }
- } // symbolTable
+ outputPrintf("* Frame %02x: %p\n", i,
+ gbl_backtraceBuffer[i]);
+ }
}
} // outputGlobalBacktrace
*/
static void crash_handler(int signo)
{
- outputInit();
+ outputRawtrace();
outputPrintf("*********************************************************\n");
outputPrintf("* eCrash Crash Handler\n");
outputPrintf("*********************************************************\n");
outputPrintf("* eCrash Crash Handler\n");
outputPrintf("*********************************************************\n");
- outputFini();
-
exit(signo);
} // crash_handler
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));