From a041d9898e6d699bd8c0c25482ec574feb03c547 Mon Sep 17 00:00:00 2001 From: "John Ankarstr\\xf6m" Date: Sat, 29 May 2021 12:54:47 +0200 Subject: First commit This is the original state of the released tarball for JWM 1.8, which will serve as my starting point for further modifications. --- src/debug.c | 396 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 396 insertions(+) create mode 100644 src/debug.c (limited to 'src/debug.c') diff --git a/src/debug.c b/src/debug.c new file mode 100644 index 0000000..6527abd --- /dev/null +++ b/src/debug.c @@ -0,0 +1,396 @@ +/*************************************************************************** + * Debug functions. + * Copyright (C) 2003 Joe Wingbermuehle + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ***************************************************************************/ + +#include "debug.h" + +/*************************************************************************** + * Emit a message. + ***************************************************************************/ +void Debug(const char *str, ...) { +#ifdef DEBUG + va_list ap; + va_start(ap, str); + + Assert(str); + + fprintf(stderr, "DEBUG: "); + vfprintf(stderr, str, ap); + fprintf(stderr, "\n"); + + va_end(ap); +#endif +} + +#ifdef DEBUG + +#define CHECKPOINT_LIST_SIZE 8 + +typedef struct MemoryType { + const char *file; + unsigned int line; + size_t size; + void *pointer; + struct MemoryType *next; +} MemoryType; + +static MemoryType *allocations = NULL; + +typedef struct ResourceType { + int resource; + const char *allocationFiles[CHECKPOINT_LIST_SIZE]; + unsigned int allocationLines[CHECKPOINT_LIST_SIZE]; + const char *releaseFiles[CHECKPOINT_LIST_SIZE]; + unsigned int releaseLines[CHECKPOINT_LIST_SIZE]; + unsigned int allocationOffset; + unsigned int releaseOffset; + size_t count; + struct ResourceType *next; +} ResourceType; + +static ResourceType *resources = NULL; + +static const char *checkpointFile[CHECKPOINT_LIST_SIZE]; +static unsigned int checkpointLine[CHECKPOINT_LIST_SIZE]; +static int checkpointOffset; + +static void DEBUG_PrintResourceStack(ResourceType *rp); + +/*************************************************************************** + * Start the debugger. + ***************************************************************************/ +void DEBUG_StartDebug(const char *file, unsigned int line) { + int x; + + Debug("%s[%u]: debug mode started", file, line); + + checkpointOffset = 0; + for(x = 0; x < CHECKPOINT_LIST_SIZE; x++) { + checkpointFile[x] = NULL; + checkpointLine[x] = 0; + } + +} + +/*************************************************************************** + * Stop the debugger. + ***************************************************************************/ +void DEBUG_StopDebug(const char *file, unsigned int line) { + MemoryType *mp; + ResourceType *rp; + unsigned int count = 0; + + Debug("%s[%u]: debug mode stopped", file, line); + + if(allocations) { + Debug("MEMORY: memory leaks follow"); + for(mp = allocations; mp; mp = mp->next) { + Debug(" %u bytes in %s at line %u", + mp->size, mp->file, mp->line); + ++count; + } + if(count == 1) { + Debug("MEMORY: 1 memory leak"); + } else { + Debug("MEMORY: %u memory leaks", count); + } + } else { + Debug("MEMORY: no memory leaks"); + } + + if(resources) { + for(rp = resources; rp; rp = rp->next) { + if(rp->count > 0) { + Debug("RESOURCE: resource %d has reference count %u", + rp->resource, rp->count); + DEBUG_PrintResourceStack(rp); + } + } + } + +} + +/*************************************************************************** + * Print the resource allocation/release stacks for a resource. + ***************************************************************************/ +void DEBUG_PrintResourceStack(ResourceType *rp) { + unsigned int x, offset; + + Debug(" Allocation stack: (oldest)"); + offset = rp->allocationOffset; + for(x = 0; x < CHECKPOINT_LIST_SIZE; x++) { + if(rp->allocationFiles[offset]) { + Debug(" %s line %u", rp->allocationFiles[offset], + rp->allocationLines[offset]); + } + offset = (offset + 1) % CHECKPOINT_LIST_SIZE; + } + Debug(" Release stack: (oldest)"); + offset = rp->releaseOffset; + for(x = 0; x < CHECKPOINT_LIST_SIZE; x++) { + if(rp->releaseFiles[offset]) { + Debug(" %s line %u", rp->releaseFiles[offset], + rp->releaseLines[offset]); + } + offset = (offset + 1) % CHECKPOINT_LIST_SIZE; + } +} + +/*************************************************************************** + * Set a checkpoint. + ***************************************************************************/ +void DEBUG_SetCheckpoint(const char *file, unsigned int line) { + + checkpointFile[checkpointOffset] = file; + checkpointLine[checkpointOffset] = line; + + checkpointOffset = (checkpointOffset + 1) % CHECKPOINT_LIST_SIZE; + +} + +/*************************************************************************** + * Display the location of the last checkpoint. + ***************************************************************************/ +void DEBUG_ShowCheckpoint() { + int x, offset; + + Debug("CHECKPOINT LIST (oldest)"); + offset = checkpointOffset; + for(x = 0; x < CHECKPOINT_LIST_SIZE; x++) { + if(checkpointFile[offset]) { + Debug(" %s[%u]", checkpointFile[offset], checkpointLine[offset]); + } + offset = (offset + 1) % CHECKPOINT_LIST_SIZE; + } + Debug("END OF CHECKPOINT LIST (most recent)"); + +} + +/*************************************************************************** + * Allocate memory and log. + ***************************************************************************/ +void *DEBUG_Allocate(size_t size, const char *file, unsigned int line) { + MemoryType *mp; + + if(size <= 0) { + Debug("MEMORY: %s[%u]: Attempt to allocate %d bytes of memory", + file, line, size); + } + + mp = (MemoryType*)malloc(sizeof(MemoryType)); + Assert(mp); + + mp->file = file; + mp->line = line; + mp->size = size; + + mp->pointer = malloc(size + sizeof(char)); + if(!mp->pointer) { + Debug("MEMORY: %s[%u]: Memory allocation failed (%d bytes)", + file, line, size); + Assert(0); + } + + /* Make uninitialized accesses easy to find. */ + memset(mp->pointer, 85, size); + + /* Canary value for buffer overflow checking. */ + ((char*)mp->pointer)[size] = 42; + + mp->next = allocations; + allocations = mp; + + return mp->pointer; +} + +/*************************************************************************** + * Reallocate memory and log. + ***************************************************************************/ +void *DEBUG_Reallocate(void *ptr, size_t size, const char *file, + unsigned int line) { + + MemoryType *mp; + + if(size <= 0) { + Debug("MEMORY: %s[%u]: Attempt to reallocate %d bytes of memory", + file, line, size); + } + if(!ptr) { + Debug("MEMORY: %s[%u]: Attempt to reallocate NULL pointer. " + "Calling Allocate...", file, line); + return DEBUG_Allocate(size, file, line); + } else { + + for(mp = allocations; mp; mp = mp->next) { + if(mp->pointer == ptr) { + + if(((char*)ptr)[mp->size] != 42) { + Debug("MEMORY: %s[%u]: The canary is dead.", file, line); + } + + mp->file = file; + mp->line = line; + mp->size = size; + mp->pointer = realloc(ptr, size + sizeof(char)); + if(!mp->pointer) { + Debug("MEMORY: %s[%u]: Failed to reallocate %d bytes.", + file, line, size); + Assert(0); + } + ((char*)mp->pointer)[size] = 42; + return mp->pointer; + } + } + + Debug("MEMORY: %s[%u]: Attempt to reallocate unallocated pointer", + file, line); + mp = malloc(sizeof(MemoryType)); + Assert(mp); + mp->file = file; + mp->line = line; + mp->size = size; + mp->pointer = malloc(size + sizeof(char)); + if(!mp->pointer) { + Debug("MEMORY: %s[%u]: Failed to reallocate %d bytes.", + file, line, size); + Assert(0); + } + memset(mp->pointer, 85, size); + ((char*)mp->pointer)[size] = 42; + + mp->next = allocations; + allocations = mp; + + return mp->pointer; + } + +} + +/*************************************************************************** + * Release memory and log. + ***************************************************************************/ +void DEBUG_Release(void **ptr, const char *file, unsigned int line) { + MemoryType *mp, *last; + + if(!ptr) { + Debug("MEMORY: %s[%u]: Invalid attempt to release", file, line); + } else if(!*ptr) { + Debug("MEMORY: %s[%u]: Attempt to delete NULL pointer", + file, line); + } else { + last = NULL; + for(mp = allocations; mp; mp = mp->next) { + if(mp->pointer == *ptr) { + if(last) { + last->next = mp->next; + } else { + allocations = mp->next; + } + + if(((char*)*ptr)[mp->size] != 42) { + Debug("MEMORY: %s[%u]: The canary is dead.", file, line); + } + + memset(*ptr, 0xFF, mp->size); + free(mp); + free(*ptr); + *ptr = NULL; + return; + } + last = mp; + } + Debug("MEMORY: %s[%u]: Attempt to delete unallocated pointer", + file, line); + memset(*ptr, 0xFF, mp->size); + free(*ptr); + + /* This address should cause a segfault or bus error. */ + *ptr = (void*)1; + + } +} + +/*************************************************************************** + * Add a resource. + ***************************************************************************/ +void DEBUG_AllocateResource(int resource, const char *file, + unsigned int line) { + + ResourceType *rp; + + for(rp = resources; rp; rp = rp->next) { + if(rp->resource == resource) { + + rp->allocationFiles[rp->allocationOffset] = file; + rp->allocationLines[rp->allocationOffset] = line; + rp->allocationOffset + = (rp->allocationOffset + 1) % CHECKPOINT_LIST_SIZE; + + ++rp->count; + return; + } + } + + rp = malloc(sizeof(ResourceType)); + memset(rp, 0, sizeof(ResourceType)); + rp->resource = resource; + rp->allocationFiles[0] = file; + rp->allocationLines[0] = line; + rp->allocationOffset = 1; + rp->releaseOffset = 0; + rp->count = 1; + + rp->next = resources; + resources = rp; + +} + +/*************************************************************************** + * Remove a resource. + ***************************************************************************/ +void DEBUG_ReleaseResource(int resource, const char *file, + unsigned int line) { + + ResourceType *rp; + + for(rp = resources; rp; rp = rp->next) { + if(rp->resource == resource) { + rp->releaseFiles[rp->releaseOffset] = file; + rp->releaseLines[rp->releaseOffset] = line; + rp->releaseOffset = (rp->releaseOffset + 1) % CHECKPOINT_LIST_SIZE; + if(rp->count <= 0) { + Debug("RESOURCE: Multiple attempts to release resource %d", + resource); + DEBUG_PrintResourceStack(rp); + } else { + --rp->count; + } + return; + } + } + + Debug("RESOURCE: Attempt to release unallocated resource %d", + resource); + Debug(" in %s at line %u", file, line); + +} + +#undef CHECKPOINT_LIST_SIZE + +#endif + -- cgit v1.2.3