/* Author: Mark Moraes <moraes@csri.toronto.edu> */
/*LINTLIBRARY*/
#include "defs.h"
#include "globals.h"
#include "sptree.h"
RCSID("$Id: leak.c,v 1.1.1.1 1998/02/10 21:01:46 mea Exp $")
/*
* These routines provide an interface for tracing memory leaks. The
* user can turn on leak tracing at any time by calling
* mal_leaktrace(1), after which every block allocated by
* _malloc()/_calloc()/_realloc()/_valloc()/_memalign() has a string
* (containing the filename and linenumber of the routine invoking it)
* stored in a database. When _free()/_cfree() is called on that block,
* the record is deleted from the database. The user can call
* mal_dumpleaktrace() to show the list of blocks allocated, and
* where they were allocated. The location of leaks can usually be
* detected from this.
*/
/*
* The tree implementation used to store the blocks is a splay-tree,
* using an implementation in C by Dave Brower (daveb@rtech.uucp),
* translated from Douglas Jones' original Pascal. However, any data
* structure that permits insert(), delete() and traverse()/apply() of
* key, value pairs should be suitable. Only this file needs to be
* changed.
*/
static SPTREE *sp = NULL;
/*
* num is a sequence number, incremented for ever block. min_num gets
* set to num after every dumpleaktrace - subsequent dumps do not print
* any blocks with sequence numbers less than min_num
*/
static unsigned long min_num = 0;
static unsigned long num = 0;
/*
* These are used by mal_contents to count number of allocated blocks and the
* number of bytes allocated. Better way to do this is to walk the heap
* rather than scan the splay tree.
*/
static unsigned long nmallocs;
static unsigned long nbytes;
static FILE *dumpfp = NULL;
/*
* Turns recording of FILE and LINE number of each call to
* malloc/free/realloc/calloc/cfree/memalign/valloc on (if value != 0)
* or off, (if value == 0)
*/
void
mal_leaktrace(value)
int value;
{
_malloc_leaktrace = (value != 0);
if (sp == NULL)
sp = __spinit();
}
/*
* The routine which actually does the printing. I know it is silly to
* print address in decimal, but sort doesn't read hex, so sorting the
* printed data by address is impossible otherwise. Urr. The format is
* FILE:LINE: sequence_number address_in_decimal (address_in_hex)
*/
void
__m_prnode(spblk)
SPBLK *spblk;
{
if ((unsigned long) spblk->datb < min_num)
return;
(void) sprintf(_malloc_statsbuf, "%s%8lu %8lu(0x%08lx)\n",
(char *) spblk->data, (unsigned long) spblk->datb,
(unsigned long) spblk->key, (unsigned long) spblk->key);
(void) fputs(_malloc_statsbuf, dumpfp);
}
/*
* Dumps all blocks which have been recorded.
*/
void
mal_dumpleaktrace(fp)
FILE *fp;
{
dumpfp = fp;
__spscan(__m_prnode, (SPBLK *) NULL, sp);
(void) fflush(dumpfp);
min_num = num;
}
/*
* Inserts a copy of a string keyed by the address addr into the tree
* that stores the leak trace information. The string is presumably of
* the form "file:linenumber:". It also stores a sequence number that
* gets incremented with each call to this routine.
*/
void
__m_install_record(addr, s)
univptr_t addr;
const char *s;
{
num++;
(void) __spadd(addr, strsave(s), (char *) num, sp);
}
/* Deletes the record keyed by addr if it exists */
void
__m_delete_record(addr)
univptr_t addr;
{
SPBLK *result;
if ((result = __splookup(addr, sp)) != NULL) {
free(result->data);
result->data = 0;
__spdelete(result, sp);
}
}
static void
__m_count(spblk)
SPBLK *spblk;
{
Word *p;
nmallocs++;
p = (Word *) spblk->key;
p -= HEADERWORDS;
CHECKALLOCPTR(p, "when checking in __m_count");
nbytes += SIZE(p) * sizeof(Word);
return;
}
void
mal_contents(fp)
FILE *fp;
{
nmallocs = 0;
nbytes = 0;
__spscan(__m_count, (SPBLK *) NULL, sp);
(void) sprintf(_malloc_statsbuf,
"%% %lu bytes %lu mallocs %lu vm\n",
nbytes, nmallocs, (ulong) sbrk(0));
(void) fputs(_malloc_statsbuf, fp);
(void) fflush(fp);
}
syntax highlighted by Code2HTML, v. 0.9.1