#include <stdio.h>
#include "config.h"
#include "lint.h"
#include "interpret.h"
#include "object.h"
#include "md.h"
/*
note: do not use MALLOC() etc. in this module. Unbridled recursion
will occur. (use malloc() etc. instead)
This module introduces quite a lot of overhead but it can be useful
for tracking down memory leaks or for catching the freeing on non-malloc'd
data. This module could easily be extended to allow the malloced memory
chunks to be tagged with a string label.
*/
#ifdef DEBUGMALLOC
static totals[MAX_CATEGORY];
int malloc_mask = 0;
static node_t **table;
unsigned int total_malloced = 0L;
unsigned int hiwater = 0L;
void
MDinit()
{
int j;
table = (node_t **)calloc(TABLESIZE, sizeof(node_t *));
for (j = 0; j < MAX_CATEGORY; j++) {
totals[j] = 0;
}
}
void
MDmalloc(node, size, tag, desc)
node_t *node;
int size;
int tag;
char *desc;
{
unsigned int h;
static int count = 0;
total_malloced += size;
if (total_malloced > hiwater) {
hiwater = total_malloced;
}
h = (unsigned int)node % TABLESIZE;
node->size = size;
node->next = table[h];
#ifdef DEBUGMALLOC_EXTENSIONS
if (tag < MAX_CATEGORY) {
totals[tag] += size;
}
node->tag = tag;
node->id = count++;
node->desc = desc ? desc : "default";
if (malloc_mask == node->tag) {
fprintf(stderr,"MDmalloc: %5d, [%-25s], %8x:(%d)\n",
node->tag, node->desc, (unsigned int)PTR(node), node->size);
fflush(stderr);
}
#endif
table[h] = node;
}
int
MDfree(ptr)
void *ptr;
{
unsigned int h;
node_t *entry, **oentry;
h = (unsigned int)ptr % TABLESIZE;
oentry = &table[h];
for (entry = *oentry; entry; oentry = &entry->next, entry = *oentry) {
if (entry == ptr) {
*oentry = entry->next;
total_malloced -= entry->size;
break;
}
}
if (entry) {
#ifdef DEBUGMALLOC_EXTENSIONS
if (entry->tag < MAX_CATEGORY) {
totals[entry->tag] -= entry->size;
}
if (malloc_mask == entry->tag) {
fprintf(stderr,"MDfree: %5d, [%-25s], %8x:(%d)\n",
entry->tag, entry->desc, (unsigned int)PTR(entry), entry->size);
fflush(stderr);
}
#endif
} else {
fprintf(stderr,
"md: debugmalloc: attempted to free non-malloc'd pointer %x\n",
(unsigned int)ptr);
#ifdef DEBUG
abort();
#endif
return 0;
}
return 1;
}
#ifdef DEBUGMALLOC_EXTENSIONS
void dump_debugmalloc(tfn, mask)
char *tfn;
int mask;
{
int j, total = 0, chunks = 0, total2 = 0;
char *fn;
node_t *entry;
FILE *fp;
fn = check_valid_path(tfn, current_object, "debugmalloc", 1);
if (!fn) {
add_message("Invalid path '%s' for writing.\n", tfn);
return;
}
fp = fopen(fn, "w");
if (!fp) {
add_message("Unable to open %s for writing.\n", fn);
return;
}
add_message("Dumping to %s ...",fn);
for (j = 0; j < TABLESIZE; j++) {
for (entry = table[j]; entry; entry = entry->next) {
if (!mask || (entry->tag == mask)) {
fprintf(fp,"%-20s: sz %7d: id %6d: tag %8d, a %8x\n",
entry->desc, entry->size, entry->id, entry->tag,
(unsigned int)PTR(entry));
total += entry->size;
chunks++;
}
}
}
fprintf(fp, "total = %8d\n", total);
fprintf(fp, "# chunks = %8d\n", chunks);
fprintf(fp, "ave. bytes per chunk = %7.2f\n\n", (float)total / chunks);
fprintf(fp, "categories:\n\n");
for (j = 0; j < MAX_CATEGORY; j++) {
fprintf(fp, "%4d: %10d\n", j, totals[j]);
total2 += totals[j];
}
fprintf(fp, "\ntotal = %11d\n", total2);
fclose(fp);
add_message(" done.\n");
add_message("total = %8d\n", total);
add_message("# chunks = %8d\n", chunks);
if (chunks) {
add_message("ave. bytes per chunk = %7.2f\n", (float)total / chunks);
}
}
#endif /* DEBUGMALLOC_EXTENSIONS */
void set_malloc_mask(mask)
int mask;
{
malloc_mask = mask;
}
#endif /* DEBUGMALLOC */