home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Geek Gadgets 1
/
ADE-1.bin
/
ade-dist
/
dbmalloc-1.14-src.tgz
/
tar.out
/
contrib
/
dbmalloc
/
stack.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-09-28
|
8KB
|
367 lines
/*
* (c) Copyright 1990, 1991, 1992 Conor P. Cahill (cpcahil@virtech.vti.com)
*
* This software may be distributed freely as long as the following conditions
* are met:
* * the distribution, or any derivative thereof, may not be
* included as part of a commercial product
* * full source code is provided including this copyright
* * there is no charge for the software itself (there may be
* a minimal charge for the copying or distribution effort)
* * this copyright notice is not modified or removed from any
* source file
*/
#include <stdio.h>
#include "mallocin.h"
#include "tostring.h"
#define STACK_ALLOC 100 /* allocate 100 elements at a time */
#ifndef lint
static
char rcs_hdr[] = "$Id: stack.c,v 1.7 1992/08/22 16:27:13 cpcahil Exp $";
#endif
#define OUTBUFSIZE 128
#define ERRSTR "I/O error durring stack dump"
#define WRITEOUT(fd,str,len) if( write(fd,str,(WRTSIZE)(len)) != (len) ) \
{ \
VOIDCAST write(2,ERRSTR,\
(WRTSIZE)strlen(ERRSTR));\
exit(120); \
}
#define COPY(s,t,buf,len) while( (*(s) = *((t)++) ) \
&& ( (s) < ((buf)+(len)-5) ) ) { (s)++; }
/*
* stack.c - this file contains info used to maintain the malloc stack
* trees that the user may use to identify where malloc is called
* from. Ideally, we would like to be able to read the stack
* ourselves, but that is very system dependent.
*
* The user interface to the stack routines will be as follows:
*
* #define malloc_enter(a) StackEnter(a,__FILE__,__LINE__)
* #define malloc_leave(a) StackLeave(a,__FILE__,__LINE__)
*
* NOTE: These functions depend upon the fact that they are called in a
* symentric manner. If you skip one of them, you will not have valid
* information maintained in the stack.
*
* Rather than keep a segment of the stack in each malloc region, we will
* maintain a stack tree here and the malloc segment will have a pointer
* to the current leaf of the tree. This should save considerably on the
* amount of space taken up by maintaining this tree.
*/
struct stack * current;
struct stack root_node;
/*
* local function prototpyes
*/
struct stack * StackNew __STDCARGS(( CONST char * func, CONST char * file,
int line));
int StackMatch __STDCARGS((struct stack * this,CONST char * func,
CONST char * file, int line ));
/*
* stk_enter() - called when one enters a new function. This function adds the
* specified function as a new entry (unless it is already in the
* list, in which case it just sets the current pointer).
*/
void
StackEnter( func, file, line )
CONST char * func;
CONST char * file;
int line;
{
int match;
struct stack * this;
/*
* if there are no current entries yet
*/
if( current == NULL )
{
this = &root_node;
}
else
{
this = current;
}
/*
* if there are no entries below this func yet,
*/
if( this->below == NULL )
{
this->below = StackNew(func,file,line);
this->below->above = this;
current = this->below;
}
else
{
/*
* drop down to the next level and look around for the
* specified function.
*/
this = this->below;
/*
* scan across this level looking for a match
*/
while( ( ! (match=StackMatch(this,func,file,line)) )
&& (this->beside != NULL) )
{
this = this->beside;
}
/*
* if we found the entry
*/
if( match )
{
current = this;
}
else
{
current = this->beside = StackNew(func,file,line);
this->beside->above = this->above;
}
}
} /* StackEnter(... */
/*
* StackNew() - allocate a new stack structure and fill in the default values.
* This is here as a function so that we can manage a list of
* entries and therefore don't have to call malloc too often.
*
* NOTE: this function does not link the current function to the tree. That
* must be done by the calling function.
*/
struct stack *
StackNew(func,file,line)
CONST char * func;
CONST char * file;
int line;
{
static SIZETYPE alloccnt;
static SIZETYPE cnt;
static struct stack * data;
struct mlist * mptr;
static struct stack * this;
static int call_counter;
/*
* if it is time to allocate more entries
*/
if( cnt == alloccnt )
{
/*
* reset the counters
*/
cnt = 0;
alloccnt = STACK_ALLOC;
/*
* go allocate the data
*/
data = (struct stack *)malloc(
(SIZETYPE)(alloccnt*sizeof(*data)) );
/*
* if we failed to get the data, tell the user about it
*/
if( data == NULL )
{
malloc_errno = M_CODE_NOMORE_MEM;
malloc_fatal("StackNew",file,line,(struct mlist *)NULL);
}
/*
* change the id information put in by malloc so that the
* record appears as a stack record (and doesn't get confused
* with other memory leaks)
*/
mptr = (struct mlist *) (((char *)data) - M_SIZE);
mptr->id = call_counter++;
SETTYPE(mptr,M_T_STACK);
}
/*
* grab next element off of the list
*/
this = data + cnt;
/*
* setup the new structure and attach it to the tree
*/
this->above = this->below = this->beside = NULL;
this->func = func;
this->file = file;
this->line = line;
/*
* increment the count since we used yet another entry
*/
cnt++;
/*
* return the pointer to the new entry
*/
return(this);
} /* StackNew(... */
/*
* StackMatch() - determine if the specified stack entry matches the specified
* set of func,file, and line. We have to compare all three in
* order to ensure that we get the correct function even if
* there are two functions with the same name (or the caller
* specified the wrong name on the arguement list)
*/
int
StackMatch(this,func,file,line)
struct stack * this;
CONST char * func;
CONST char * file;
int line;
{
return( (strcmp(this->func,func) == 0)
&& (strcmp(this->file,file) == 0)
&& (this->line == line ) ) ;
} /* StackMatch(... */
/*
* StackLeave() - leave the current stack level (called at the end of a
* function.
*/
void
StackLeave( func, file, line )
CONST char * func;
CONST char * file;
int line;
{
if( current == NULL )
{
malloc_errno = M_CODE_STK_NOCUR;
malloc_fatal("stk_leave", file, line, (struct mlist *)NULL);
}
else if( strcmp(func,current->func) != 0 )
{
malloc_errno = M_CODE_STK_BADFUNC;
malloc_fatal("stk_leave", file, line, (struct mlist *)NULL);
}
else
{
current = current->above;
}
} /* StackLeave(... */
/*
* StackCurrent() - get the current stack pointer
*/
struct stack *
StackCurrent()
{
return( current );
} /* StackCurrent(... */
/*
* StackDump() - dump the stack from the specified node
*/
void
StackDump(fd, msg, node )
int fd;
CONST char * msg;
struct stack * node;
{
char outbuf[OUTBUFSIZE];
char * s;
CONST char * t;
/*
* if there is nothing to show, just return
*/
if( (node == NULL) || (node == &root_node) )
{
return;
}
/*
* if caller specified a message to print out, print it out
*/
if( msg )
{
WRITEOUT(fd,msg,strlen(msg));
}
/*
* Ok, we have the info, so lets print it out
*/
do
{
WRITEOUT(fd," -> ",12);
s = outbuf;
/*
* perform some simple sanity checking on the node pointer
*/
if( (((DATATYPE *)node) < malloc_data_start)
|| (((DATATYPE *)node) > malloc_data_end)
|| ((((long)node) & 0x1) != 0) )
{
WRITEOUT(fd,"INVALID/BROKEN STACK CHAIN!!!\n",30);
break;
}
/*
* build the string for this level
*/
s = outbuf;
t = node->func;
COPY(s,t,outbuf,OUTBUFSIZE);
t = "() in ";
COPY(s,t,outbuf,OUTBUFSIZE);
t = node->file;
COPY(s,t,outbuf,OUTBUFSIZE);
*s++ = '(';
s += tostring(s,(ULONG) node->line,0,10,' ');
*s++ = ')';
*s++ = '\n';
/*
* write out the string
*/
WRITEOUT(fd,outbuf,s-outbuf);
/*
* move up one level in the stack
*/
node = node->above;
/*
* until we get to the top of the tree
*/
} while( (node != NULL) && (node != &root_node) );
} /* StackDump(... */