/* handler called when a function is exited */ void dbgExitFunc(dbgFuncDB_t *pFuncDB, int iStackPtrRestore, int iRet) { dbgThrdInfo_t *pThrd = dbgGetThrdInfo(); assert(iStackPtrRestore >= 0); assert(pFuncDB != NULL); assert(pFuncDB->magic == dbgFUNCDB_MAGIC); dbgFuncDBPrintActiveMutexes(pFuncDB, "WARNING: mutex still owned by us as we exit function, mutex: ", pthread_self()); if(bLogFuncFlow && dbgPrintNameIsInList((const uchar*)pFuncDB->file, printNameFileRoot)) { if(iRet == RS_RET_NO_IRET) dbgprintf("%s:%d: %s: exit: (no iRet)\n", pFuncDB->file, pFuncDB->line, pFuncDB->func); else dbgprintf("%s:%d: %s: exit: %d\n", pFuncDB->file, pFuncDB->line, pFuncDB->func, iRet); } pThrd->stackPtr = iStackPtrRestore; if(pThrd->stackPtr < 0) { dbgprintf("Stack pointer for thread %lx below 0 - resetting (some RETiRet still wrong!)\n", (long) pthread_self()); pThrd->stackPtr = 0; } }
/* handler called when a function is entered. This function creates a new * funcDB on the heap if the passed-in pointer is NULL. */ int dbgEntrFunc(dbgFuncDB_t **ppFuncDB, const char *file, const char *func, int line) { int iStackPtr = 0; /* TODO: find some better default, this one hurts the least, but it is not clean */ dbgThrdInfo_t *pThrd; dbgFuncDBListEntry_t *pFuncDBListEntry; unsigned int i; dbgFuncDB_t *pFuncDB; assert(ppFuncDB != NULL); assert(file != NULL); assert(func != NULL); pFuncDB = *ppFuncDB; assert((pFuncDB == NULL) || (pFuncDB->magic == dbgFUNCDB_MAGIC)); pThrd = dbgGetThrdInfo(); /* we must do this AFTER the mutexes are initialized! */ if(pFuncDB == NULL) { /* we do not yet have a funcDB and need to create a new one. We also add it * to the linked list of funcDBs. Please note that when a module is unloaded and * then reloaded again, we currently do not try to find its previous funcDB but * instead create a duplicate. While finding the past one is straightforward, it * opens up the question what to do with e.g. mutex data left in it. We do not * yet see any need to handle these questions, so duplicaton seems to be the right * thing to do. -- rgerhards, 2008-03-10 */ /* dbgprintf("%s:%d:%s: called first time, initializing FuncDB\n", pFuncDB->file, pFuncDB->line, pFuncDB->func); */ /* get a new funcDB and add it to the list (all of this is protected by the mutex) */ pthread_mutex_lock(&mutFuncDBList); if((pFuncDBListEntry = calloc(1, sizeof(dbgFuncDBListEntry_t))) == NULL) { dbgprintf("Error %d allocating memory for FuncDB List entry, not adding\n", errno); pthread_mutex_unlock(&mutFuncDBList); goto exit_it; } else { if((pFuncDB = calloc(1, sizeof(dbgFuncDB_t))) == NULL) { dbgprintf("Error %d allocating memory for FuncDB, not adding\n", errno); free(pFuncDBListEntry); pthread_mutex_unlock(&mutFuncDBList); goto exit_it; } else { pFuncDBListEntry->pFuncDB = pFuncDB; pFuncDBListEntry->pNext = pFuncDBListRoot; pFuncDBListRoot = pFuncDBListEntry; } } /* now intialize the funcDB * note that we duplicate the strings, because the address provided may go away * if a loadable module is unloaded! */ pFuncDB->magic = dbgFUNCDB_MAGIC; pFuncDB->file = strdup(file); pFuncDB->func = strdup(func); pFuncDB->line = line; pFuncDB->nTimesCalled = 0; for(i = 0 ; i < sizeof(pFuncDB->mutInfo)/sizeof(dbgFuncDBmutInfoEntry_t) ; ++i) { pFuncDB->mutInfo[i].lockLn = -1; /* set to not Locked */ } /* a round of safety checks... */ if(pFuncDB->file == NULL || pFuncDB->func == NULL) { dbgprintf("Error %d allocating memory for FuncDB, not adding\n", errno); /* do a little bit of cleanup */ if(pFuncDB->file != NULL) free(pFuncDB->file); if(pFuncDB->func != NULL) free(pFuncDB->func); free(pFuncDB); free(pFuncDBListEntry); pthread_mutex_unlock(&mutFuncDBList); goto exit_it; } /* done mutex-protected operations */ pthread_mutex_unlock(&mutFuncDBList); *ppFuncDB = pFuncDB; /* all went well, so we can update the caller */ } /* when we reach this point, we have a fully-initialized FuncDB! */ PREFER_ATOMIC_INC(pFuncDB->nTimesCalled); if(bLogFuncFlow && dbgPrintNameIsInList((const uchar*)pFuncDB->file, printNameFileRoot)) if(strcmp(pFuncDB->file, "stringbuf.c")) { /* TODO: make configurable */ dbgprintf("%s:%d: %s: enter\n", pFuncDB->file, pFuncDB->line, pFuncDB->func); } if(pThrd->stackPtr >= (int) (sizeof(pThrd->callStack) / sizeof(dbgFuncDB_t*))) { dbgprintf("%s:%d: %s: debug module: call stack for this thread full, suspending call tracking\n", pFuncDB->file, pFuncDB->line, pFuncDB->func); iStackPtr = pThrd->stackPtr; } else { iStackPtr = pThrd->stackPtr++; if(pThrd->stackPtr > pThrd->stackPtrMax) pThrd->stackPtrMax = pThrd->stackPtr; pThrd->callStack[iStackPtr] = pFuncDB; pThrd->lastLine[iStackPtr] = line; } exit_it: return iStackPtr; }