diff options
author | Rainer Gerhards <rgerhards@adiscon.com> | 2008-01-22 20:25:48 +0000 |
---|---|---|
committer | Rainer Gerhards <rgerhards@adiscon.com> | 2008-01-22 20:25:48 +0000 |
commit | 3ab9ce1b9f30e901735576a4c89faf4521d4b08e (patch) | |
tree | 6fc1b45987d5df74a07e9b5572771d964d2b5d3a | |
parent | 6ba75629051613c43b5d7cbc937a8243b250886c (diff) | |
download | rsyslog-3ab9ce1b9f30e901735576a4c89faf4521d4b08e.tar.gz rsyslog-3ab9ce1b9f30e901735576a4c89faf4521d4b08e.tar.xz rsyslog-3ab9ce1b9f30e901735576a4c89faf4521d4b08e.zip |
added thread-specific call stack to debug interface
-rw-r--r-- | debug.c | 144 | ||||
-rw-r--r-- | debug.h | 19 |
2 files changed, 150 insertions, 13 deletions
@@ -39,6 +39,7 @@ #include <signal.h> #include <errno.h> #include <pthread.h> +#include <assert.h> #include "rsyslog.h" #include "debug.h" @@ -47,6 +48,82 @@ int Debug; /* debug flag - read-only after startup */ int debugging_on = 0; /* read-only, except on sig USR1 */ +static FILE *stddbg; + +typedef struct dbgCallStack_s { + pthread_t thrd; + const char* callStack[100000]; + int stackPtr; + struct dbgCallStack_s *pNext; + struct dbgCallStack_s *pPrev; +} dbgCallStack_t; +static dbgCallStack_t *dbgCallStackListRoot = NULL; +static dbgCallStack_t *dbgCallStackListLast = NULL; +static pthread_mutex_t mutCallStack = PTHREAD_MUTEX_INITIALIZER; + +static pthread_key_t keyCallStack; + +/* destructor for a call stack object */ +static void dbgCallStackDestruct(void *arg) +{ + dbgCallStack_t *pStack = (dbgCallStack_t*) arg; + + dbgprintf("destructor for debug call stack %p called\n", pStack); + if(pStack->pPrev != NULL) + pStack->pPrev->pNext = pStack->pNext; + if(pStack->pNext != NULL) + pStack->pNext->pPrev = pStack->pPrev; + if(pStack == dbgCallStackListRoot) + dbgCallStackListRoot = pStack->pNext; + if(pStack == dbgCallStackListLast) + dbgCallStackListLast = pStack->pNext; + free(pStack); +} + + +/* print a thread's call stack + */ +static void dbgCallStackPrint(dbgCallStack_t *pStack) +{ + int i; + + /* TODO: mutex guard! */ + dbgprintf("\nRecorded Call Order for Thread 0x%lx (%p):\n", (unsigned long) pStack->thrd, pStack); + for(i = 0 ; i < pStack->stackPtr ; i++) { + dbgprintf("%s()\n", pStack->callStack[i]); + } + dbgprintf("NOTE: not all calls may have been recorded.\n"); +} + + +/* get ptr to call stack - if none exists, create a new stack + */ +static dbgCallStack_t *dbgGetCallStack(void) +{ + dbgCallStack_t *pStack; + + pthread_mutex_lock(&mutCallStack); + if((pStack = pthread_getspecific(keyCallStack)) == NULL) { + /* construct object */ + pStack = calloc(1, sizeof(dbgCallStack_t)); + pStack->thrd = pthread_self(); + (void) pthread_setspecific(keyCallStack, pStack); +fprintf(stdout, "dbgGetCallStack Create thrd %lx, pstack %p, thrd %lx\n", (unsigned long) pthread_self(), pStack, pStack->thrd); + if(dbgCallStackListRoot == NULL) { + dbgCallStackListRoot = pStack; + dbgCallStackListLast = pStack; + } else { + pStack->pPrev = dbgCallStackListLast; + dbgCallStackListLast->pNext = pStack; + dbgCallStackListLast = pStack; + } + } + pthread_mutex_unlock(&mutCallStack); + return pStack; +} + + + /* handler for SIGSEGV - MUST terminiate the app, but does so in a somewhat * more meaningful way. * rgerhards, 2008-01-22 @@ -56,6 +133,7 @@ sigsegvHdlr(int signum) { struct sigaction sigAct; char *signame; + dbgCallStack_t *pStack; if(signum == SIGSEGV) { signame = " (SIGSEGV)"; @@ -63,9 +141,14 @@ sigsegvHdlr(int signum) signame = ""; } - fprintf(stderr, "Signal %d%s occured, execution must be terminated %d.\n", signum, signame, SIGSEGV); - fflush(stderr); + dbgprintf("Signal %d%s occured, execution must be terminated %d.\n", signum, signame, SIGSEGV); + + /* stack info */ + for(pStack = dbgCallStackListRoot ; pStack != NULL ; pStack = pStack->pNext) { + dbgCallStackPrint(pStack); + } + fflush(stddbg); /* re-instantiate original handler ... */ memset(&sigAct, 0, sizeof (sigAct)); sigemptyset(&sigAct.sa_mask); @@ -73,11 +156,11 @@ sigsegvHdlr(int signum) sigaction(SIGSEGV, &sigAct, NULL); /* and call it */ - int i= raise(signum); - printf("raise returns %d, errno %d: %s\n", i, errno, strerror(errno)); + int ir = raise(signum); + printf("raise returns %d, errno %d: %s\n", ir, errno, strerror(errno)); /* we should never arrive here - but we provide some code just in case... */ - fprintf(stderr, "sigsegvHdlr: oops, returned from raise(), doing exit(), something really wrong...\n"); + dbgprintf("sigsegvHdlr: oops, returned from raise(), doing exit(), something really wrong...\n"); exit(1); } @@ -105,29 +188,64 @@ dbgprintf(char *fmt, ...) */ if(ptLastThrdID != pthread_self()) { if(!bWasNL) { - fprintf(stdout, "\n"); + fprintf(stddbg, "\n"); bWasNL = 1; } ptLastThrdID = pthread_self(); } if(bWasNL) { - fprintf(stdout, "%8.8x: ", (unsigned int) pthread_self()); - //fprintf(stderr, "%8.8x: ", (unsigned int) pthread_self()); + fprintf(stddbg, "%8.8x: ", (unsigned int) pthread_self()); } bWasNL = (*(fmt + strlen(fmt) - 1) == '\n') ? 1 : 0; va_start(ap, fmt); - vfprintf(stdout, fmt, ap); - //vfprintf(stderr, fmt, ap); + vfprintf(stddbg, fmt, ap); va_end(ap); - //fflush(stderr); - fflush(stdout); + fflush(stddbg); return; } -/* */ +/* handler called when a function is entered + */ +void dbgEntrFunc(char* file, int line, const char* func) +{ + dbgCallStack_t *pStack = dbgGetCallStack(); + + dbgprintf("%s:%d: %s: enter\n", file, line, func); + pStack->callStack[pStack->stackPtr++] = func; + dbgprintf("stack %d\n", pStack->stackPtr); + assert(pStack->stackPtr < (int) (sizeof(pStack->callStack) / sizeof(const char*))); + +} + + +/* handler called when a function is exited + */ +void dbgExitFunc(char* file, int line, const char* func) +{ + dbgCallStack_t *pStack = dbgGetCallStack(); + + dbgprintf("%s:%d: %s: exit\n", file, line, func); + pStack->stackPtr--; + assert(pStack->stackPtr > 0); +} + +rsRetVal dbgClassInit(void) +{ + stddbg = stdout; + (void) pthread_key_create(&keyCallStack, dbgCallStackDestruct); + return RS_RET_OK; +} + + +rsRetVal dbgClassExit(void) +{ + pthread_key_delete(keyCallStack); + //(void) pthread_key_create(&keyCallStack, dbgCallStackDestructor); + return RS_RET_OK; +} /* * vi:set ai: */ @@ -30,7 +30,26 @@ extern int Debug; /* debug flag - read-only after startup */ extern int debugging_on; /* read-only, except on sig USR1 */ /* prototypes */ +rsRetVal dbgClassInit(void); void sigsegvHdlr(int signum); void dbgprintf(char *fmt, ...) __attribute__((format(printf,1, 2))); +void dbgEntrFunc(char* file, int line, const char* func); +void dbgExitFunc(char* file, int line, const char* func); + +/* macros */ +#if 1 /* DEV debug: set to 1 to get a rough call trace -- rgerhards, 2008-01-13 */ +# define BEGINfunc dbgEntrFunc(__FILE__, __LINE__, __func__); +# define ENDfunc dbgExitFunc(__FILE__, __LINE__, __func__); +#else +# define BEGINfunc +# define ENDfunc +#endif +#if 1 /* DEV debug: set to 1 to enable -- rgerhards, 2008-01-13 */ +# define RUNLOG dbgprintf("%s:%d: %s: log point\n", __FILE__, __LINE__, __func__) +# define RUNLOG_VAR(fmt, x) dbgprintf("%s:%d: %s: var '%s'[%s]: " fmt "\n", __FILE__, __LINE__, __func__, #x, fmt, x) +#else +# define RUNLOG +# define RUNLOG_VAR(x) +#endif #endif /* #ifndef DEBUG_H_INCLUDED */ |