static void writeUnroller(const struct Unroller* unroller) { if (unroller) { writeUnroller(unroller->last); fprintf(stderr, "%s", unroller->content); } }
static void unroll(struct Allocator_pvt* context, int includeAllocations, struct Unroller* unroller) { writeUnroller(unroller); const char* ident = (context->pub.fileName) ? context->pub.fileName : "UNKNOWN"; fprintf(stderr, "%s:%d [%lu] bytes%s\n", ident, context->pub.lineNum, context->allocatedHere, (context->pub.isFreeing) ? " (freeing)" : ""); struct Unroller childUnroller = { .content = ((context->nextSibling) ? "| " : " "), .last = unroller }; if (context->firstChild) { unroll(context->firstChild, includeAllocations, &childUnroller); } struct Allocator_Allocation_pvt* allocation = context->allocations; while (allocation && includeAllocations) { writeUnroller(&childUnroller); fprintf(stderr, "%s:%d [%lu] bytes at [0x%lx]\n", allocation->pub.fileName, allocation->pub.lineNum, allocation->pub.size, (long)(uintptr_t)allocation); allocation = allocation->next; } if (context->nextSibling) { unroll(context->nextSibling, includeAllocations, unroller); } } static inline uint64_t bytesAllocated(struct Allocator_pvt* ctx) { uint64_t bytes = ctx->allocatedHere; for (struct Allocator_pvt* child = ctx->firstChild; child; child = child->nextSibling) { bytes += bytesAllocated(child); } return bytes; }
static void unroll(struct MallocAllocator_pvt* context, struct Unroller* unroller) { writeUnroller(unroller); const char* ident = (context->identFile) ? strrchr(context->identFile, '/') : " UNKNOWN"; ident = ident ? ident + 1 : context->identFile; unsigned long realBytes = 0; struct MallocAllocator_Allocation* alloc = context->allocations; while (alloc) { realBytes += alloc->size; alloc = alloc->next; } fprintf(stderr, "%s:%d [%lu] = [%lu] bytes\n", ident, context->identLine, context->allocatedHere, realBytes); if (context->firstChild) { unroll(context->firstChild, &(struct Unroller) { .content = ((context->nextSibling) ? "| " : " "), .last = unroller });
static void unroll(struct Allocator_pvt* context, int includeAllocations, struct Unroller* unroller) { writeUnroller(unroller); const char* ident = (context->pub.fileName) ? context->pub.fileName : "UNKNOWN"; fprintf(stderr, "%s:%d [%lu] bytes%s\n", ident, context->pub.lineNum, context->allocatedHere, (context->pub.isFreeing) ? " (freeing)" : ""); struct Unroller childUnroller = { .content = ((context->nextSibling) ? "| " : " "), .last = unroller }; if (context->firstChild) { unroll(context->firstChild, includeAllocations, &childUnroller); } struct Allocator_Allocation_pvt* allocation = context->allocations; while (allocation && includeAllocations) { writeUnroller(&childUnroller); fprintf(stderr, "%s:%d [%lu] bytes at [0x%lx]\n", allocation->pub.fileName, allocation->pub.lineNum, allocation->pub.size, (long)(uintptr_t)allocation); allocation = allocation->next; } if (context->nextSibling) { unroll(context->nextSibling, includeAllocations, unroller); } } void Allocator_snapshot(struct Allocator* alloc, int includeAllocations) { // get the root allocator. struct Allocator_pvt* rootAlloc = Identity_check((struct Allocator_pvt*)alloc); while (rootAlloc->parent && rootAlloc->parent != rootAlloc) { rootAlloc = rootAlloc->parent; } fprintf(stderr, "----- %scjdns memory snapshot -----\n", ""); unroll(rootAlloc, includeAllocations, NULL); fprintf(stderr, "totalBytes [%ld] remaining [%ld]\n", (long)rootAlloc->rootAlloc->maxSpace, (long)rootAlloc->rootAlloc->spaceAvailable); fprintf(stderr, "----- %scjdns memory snapshot -----\n", "end "); } Gcc_NORETURN static void failure(struct Allocator_pvt* context, const char* message, const char* fileName, int lineNum) { Allocator_snapshot(&context->pub, 1); Assert_failure("%s:%d Fatal error: [%s]", fileName, lineNum, message); }