1050 lines
30 KiB
C
1050 lines
30 KiB
C
/*
|
||
* $QNXtpLicenseC:
|
||
* Copyright 2007, QNX Software Systems. All Rights Reserved.
|
||
*
|
||
* You must obtain a written license from and pay applicable license fees to QNX
|
||
* Software Systems before you may reproduce, modify or distribute this software,
|
||
* or any work that includes all or part of this software. Free development
|
||
* licenses are available for evaluation and non-commercial purposes. For more
|
||
* information visit http://licensing.qnx.com or email licensing@qnx.com.
|
||
*
|
||
* This file may contain contributions from others. Please review this entire
|
||
* file for other proprietary rights or license notices, as well as the QNX
|
||
* Development Suite License Guide at http://licensing.qnx.com/license-guide/
|
||
* for other information.
|
||
* $
|
||
*/
|
||
|
||
|
||
|
||
|
||
|
||
/*
|
||
* (c) Copyright 1990, 1991 Conor P. Cahill (uunet!virtech!cpcahil).
|
||
* You may copy, distribute, and use this software as long as this
|
||
* copyright statement is not removed.
|
||
*/
|
||
#include <stdio.h>
|
||
#include <errno.h>
|
||
#include <inttypes.h>
|
||
#include "malloc-lib.h"
|
||
#include "mallocint.h"
|
||
#include "tostring.h"
|
||
|
||
|
||
#define MA_PADDING (__ROUND(sizeof(Dhead), _MALLOC_ALIGN)-sizeof(Dhead))
|
||
|
||
typedef
|
||
struct chain_totals {
|
||
int c_entries;
|
||
int c_size;
|
||
} chain_total_t;
|
||
|
||
int __malloc_detail;
|
||
|
||
int writeFully(int fd, const char *buf, size_t n);
|
||
void _malloc_event(const char *event, const char *funcname, const char *file,
|
||
int line, const void *link, int type);
|
||
|
||
/*
|
||
* various macro definitions used within this module.
|
||
*/
|
||
|
||
#define WRITEOUT(fd,str,len) if( writeFully(fd,str,(unsigned)(len)) != (len) ) \
|
||
{ \
|
||
(void) writeFully(2,ERRSTR,\
|
||
(unsigned)strlen(ERRSTR));\
|
||
exit(120); \
|
||
}
|
||
|
||
#define DETAIL_NONE 0
|
||
#define DETAIL_NOT_SET_YET -1
|
||
#define DETAIL_ST_COL (sizeof(DETAIL_HDR_3)-1)
|
||
#define ERRSTR "I/O Error on malloc dump file descriptor\n"
|
||
#define FILE_LEN 20
|
||
#define LIST_ALL 1
|
||
#define LIST_SOME 2
|
||
#define LIST_UNREFERENCED 3
|
||
#define NUM_BYTES 7
|
||
#define TITLE1 " Dump of Malloc Chain "
|
||
#define TITLE2 " Dump of Leaked Heap Memory "
|
||
|
||
#define DETAIL_HDR_1 \
|
||
" ACTUAL SIZE "
|
||
#define DETAIL_HDR_2 \
|
||
" PTR NEXT PREV FLAGS INT HEX "
|
||
#define DETAIL_HDR_3 \
|
||
"-------- -------- -------- ---------- -------- --------- "
|
||
|
||
#define NORMAL_HDR_1 \
|
||
"POINTER FILE WHERE LINE ALLOC DATA HEX DUMP \n"
|
||
#define NORMAL_HDR_2 \
|
||
"TO DATA ALLOCATED NUMBER FUNCT LENGTH OF BYTES 1-7 \n"
|
||
#define NORMAL_HDR_3 \
|
||
"-------- -------------------- -------- -------------- ------- --------------\n"
|
||
|
||
#define THISBUFSIZE (sizeof(NORMAL_HDR_3)+sizeof(DETAIL_HDR_3))
|
||
|
||
|
||
/*
|
||
* Function: malloc_dump()
|
||
*
|
||
* Purpose: to dump a printed copy of the malloc chain and
|
||
* associated data elements
|
||
*
|
||
* Arguments: fd - file descriptor to write data to
|
||
*
|
||
* Returns: nothing of any use
|
||
*
|
||
* Narrative: Just print out all the data
|
||
*
|
||
*/
|
||
void
|
||
malloc_dump(int fd)
|
||
{
|
||
malloc_list_items(fd,LIST_ALL,0L,0L);
|
||
}
|
||
|
||
/*
|
||
* Function: malloc_list()
|
||
*
|
||
* Purpose: to dump a printed copy of the malloc chain and
|
||
* associated data elements
|
||
*
|
||
* Arguments: fd - file descriptor to write data to
|
||
* histid1 - id of the first record to display
|
||
* histid2 - id one above the last record to display
|
||
*
|
||
* Returns: nothing of any use
|
||
*
|
||
* Narrative: Just call malloc_list_items to display the data
|
||
*
|
||
*/
|
||
void
|
||
malloc_list(int fd, ulong_t histid1, ulong_t histid2)
|
||
{
|
||
malloc_list_items(fd, LIST_SOME, histid1, histid2);
|
||
}
|
||
|
||
chain_total_t malloc_list_chain_items(int, int, ulong_t, ulong_t,
|
||
arena_range_t *, chain_t *, int, char *);
|
||
static void write_column_headers(int fd, int detail);
|
||
|
||
chain_total_t malloc_list_chain_items_bands(int fd, int list_type,
|
||
ulong_t histid1, ulong_t histid2, arena_range_t *range,
|
||
chain_t *chain, int detail, char *buffer)
|
||
{
|
||
/* Look through the bands */
|
||
int nb;
|
||
Band *band;
|
||
chain_total_t total;
|
||
|
||
total.c_entries = 0;
|
||
total.c_size = 0;
|
||
|
||
for (nb = 0; nb < *__pnband; nb++)
|
||
{
|
||
arena_range_t new_range;
|
||
Block *bp = NULL;
|
||
chain_total_t ctotal;
|
||
chain_total_t round_total;
|
||
int free_count = 0, free_size = 0;
|
||
int esize;
|
||
char buffer1[THISBUFSIZE];
|
||
|
||
round_total.c_entries = 0;
|
||
round_total.c_size = 0;
|
||
band = __pBands[nb];
|
||
esize = band->nbpe + SB_OVERHEAD();
|
||
|
||
sprintf(buffer, "\n\nBAND %x, small buffer size %u:\n\n",
|
||
(uint_t)band, band->nbpe);
|
||
WRITEOUT(fd, buffer, strlen(buffer));
|
||
|
||
/*
|
||
* For each Block on the allocated list
|
||
*/
|
||
for (bp = band->alist; bp; bp = bp->next)
|
||
{
|
||
ctotal.c_entries = 0;
|
||
new_range.r_start = (char *)(bp + 1);
|
||
new_range.r_end = new_range.r_start + esize*band->nalloc;
|
||
new_range.r_type = RANGE_BLOCK;
|
||
new_range.un.r_block = bp;
|
||
ctotal = malloc_list_chain_items(fd, list_type, histid1,
|
||
histid2, &new_range, &bp->malloc_chain,
|
||
detail, buffer);
|
||
round_total.c_entries += ctotal.c_entries;
|
||
round_total.c_size += ctotal.c_size;
|
||
free_count += bp->navail;
|
||
free_size += bp->navail * band->nbpe;
|
||
if (ctotal.c_entries > 0)
|
||
buffer[0] = '\0'; // inhibit header
|
||
}
|
||
|
||
/*
|
||
* For each Block on the depleted list
|
||
*/
|
||
for (bp = band->dlist; bp; bp = bp->next)
|
||
{
|
||
ctotal.c_entries = 0;
|
||
new_range.r_start = (char *)(bp + 1);
|
||
new_range.r_end = new_range.r_start + esize*band->nalloc;
|
||
new_range.r_type = RANGE_BLOCK;
|
||
new_range.un.r_block = bp;
|
||
ctotal = malloc_list_chain_items(fd, list_type, histid1,
|
||
histid2, &new_range, &bp->malloc_chain, detail,
|
||
buffer);
|
||
round_total.c_entries += ctotal.c_entries;
|
||
round_total.c_size += ctotal.c_size;
|
||
if (ctotal.c_entries > 0)
|
||
buffer[0] = '\0'; // inhibit header
|
||
}
|
||
if( list_type == LIST_SOME || list_type == LIST_ALL )
|
||
{
|
||
sprintf(buffer1, "\n%d Allocated entries %u bytes\n",
|
||
round_total.c_entries, round_total.c_size);
|
||
WRITEOUT(fd,buffer1,strlen(buffer1));
|
||
sprintf(buffer1, "\n%d Free entries %u bytes\n", free_count, free_size);
|
||
WRITEOUT(fd,buffer1,strlen(buffer1));
|
||
}
|
||
else if (list_type == LIST_UNREFERENCED)
|
||
{
|
||
sprintf(buffer1, "\n%d Leaked entries %u bytes\n",
|
||
round_total.c_entries, round_total.c_size);
|
||
WRITEOUT(fd,buffer1,strlen(buffer1));
|
||
}
|
||
total.c_entries += round_total.c_entries;
|
||
total.c_size += round_total.c_size;
|
||
}
|
||
return(total);
|
||
}
|
||
|
||
/*
|
||
* Function: malloc_list_chain_items()
|
||
*
|
||
* Purpose: to dump a printed copy of a malloc chain and
|
||
* associated data elements
|
||
*
|
||
* Arguments: fd - file descriptor to write data to
|
||
* list_type - type of list (all records, or a selected list)
|
||
* histid1 - first id to list (if type is some)
|
||
* histid2 - one above last id to list
|
||
* chain - the chain to dump
|
||
*
|
||
* Returns: nothing of any use
|
||
*
|
||
* Narrative: Just print out all the data
|
||
*
|
||
* Notes: This function is implemented using low level calls because
|
||
* of the likelyhood that the malloc tree is damaged when it
|
||
* is called. (Lots of things in the c library use malloc and
|
||
* we don't want to get into a catch-22).
|
||
*
|
||
*/
|
||
chain_total_t
|
||
malloc_list_chain_items(int fd, int list_type,
|
||
ulong_t histid1, ulong_t histid2,
|
||
arena_range_t *range, chain_t *chain, int detail, char *buffer)
|
||
{
|
||
void exit();
|
||
char * func;
|
||
int i;
|
||
DebugInfo_t * ptr;
|
||
Flink * flink;
|
||
chain_total_t total;
|
||
int printed_header=0;
|
||
|
||
total.c_entries = 0;
|
||
total.c_size = 0;
|
||
|
||
/*
|
||
* for each element in the trace
|
||
*/
|
||
for(flink = chain->head; flink; flink = flink->f_next)
|
||
{
|
||
ptr = &((Dhead *)flink)->d_debug;
|
||
|
||
if ((ptr->flag & M_INUSE) != 0
|
||
&& (list_type == LIST_SOME || list_type == LIST_ALL))
|
||
{
|
||
total.c_entries ++;
|
||
total.c_size += (ulong_t)_msize((Dhead *)flink+1);
|
||
}
|
||
if (range->r_type == RANGE_ARENA
|
||
&& flink->f_prev != NULL
|
||
&& ((char *)flink->f_prev + DH_LEN(flink->f_prev)) != (char *)flink) {
|
||
Flink *fp;
|
||
Flink *gap = (Flink *)((char *)flink->f_prev + DH_LEN(flink->f_prev));
|
||
int found = 0;
|
||
/*
|
||
* We have a gap.
|
||
* Look in the free lists, then check for a Block
|
||
*/
|
||
for (i=0; i < __flist_nbins ; i++) {
|
||
Flink *fp_list;
|
||
Flink *curflistptr;
|
||
curflistptr = __malloc_getflistptr();
|
||
fp_list = &(curflistptr[i]);
|
||
for (fp = fp_list->f_next;
|
||
!found && fp != fp_list; fp = fp->f_next)
|
||
{
|
||
if (fp == gap) {
|
||
found = 1;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/*
|
||
* if this item is not in use and we are not in detail mode or
|
||
* we are not in list-all mode.
|
||
*/
|
||
if(((ptr->flag & M_INUSE) == 0)
|
||
&& ((detail == DETAIL_NONE) || (list_type != LIST_ALL)) )
|
||
{
|
||
continue;
|
||
}
|
||
|
||
/*
|
||
* else if we are only listing a range of items, check to see
|
||
* if this item is in the correct range. if not, skip it
|
||
*/
|
||
else if( (list_type == LIST_SOME)
|
||
&& ( (ptr->hist_id < histid1)
|
||
|| (ptr->hist_id >= histid2)) )
|
||
{
|
||
continue;
|
||
}
|
||
else if (list_type == LIST_UNREFERENCED)
|
||
{
|
||
if ((ptr->flag & M_INUSE) == 0 || (ptr->flag & M_REFERENCED) != 0)
|
||
{
|
||
continue;
|
||
}
|
||
//if ((!(ptr->dbg)) || (ptr->dbg->tid < 0))
|
||
//continue;
|
||
if (!(ptr->callerpc_line))
|
||
continue;
|
||
total.c_entries++;
|
||
total.c_size += (ulong_t)_musize((Dhead *)flink+1);
|
||
_malloc_event("LEAK", "", NULL, (ulong_t)ptr->callerpc_line, flink, M_LEAK);
|
||
}
|
||
if (!printed_header) {
|
||
int len;
|
||
printed_header=1;
|
||
len = strlen(buffer);
|
||
if (len) {
|
||
write_column_headers(fd,detail);
|
||
}
|
||
}
|
||
|
||
/*
|
||
* fill in the string with blanks
|
||
*/
|
||
for(i=0; i < (sizeof(DETAIL_HDR_3)+sizeof(NORMAL_HDR_3)); i++)
|
||
{
|
||
buffer[i] = ' ';
|
||
}
|
||
|
||
/*
|
||
* handle detail output
|
||
*/
|
||
if( detail != DETAIL_NONE )
|
||
{
|
||
(void) tostring(buffer,
|
||
(ulong_t)ptr,8,B_HEX,' ');
|
||
(void) tostring(buffer+9,
|
||
(ulong_t)(flink->f_next),8,B_HEX,'0');
|
||
(void) tostring(buffer+18,
|
||
(ulong_t)(flink->f_prev),8,B_HEX,'0');
|
||
(void) tostring(buffer+27,
|
||
(ulong_t)ptr->flag,10,B_HEX,'0');
|
||
(void) tostring(buffer+38,
|
||
(ulong_t)_msize((Dhead *)flink+1),8,B_DEC,' ');
|
||
(void) tostring(buffer+47,
|
||
(ulong_t)_msize((Dhead *)flink+1),8,B_HEX,'0');
|
||
buffer[46] = '(';
|
||
buffer[56] = ')';
|
||
}
|
||
|
||
/*
|
||
* and now add in the normal stuff
|
||
*/
|
||
(void) tostring(buffer+detail,
|
||
(ulong_t) ((Dhead *)flink+1), 8, B_HEX, ' ');
|
||
|
||
/*
|
||
* if a file has been specified
|
||
*/
|
||
if( (ptr->file != NULL) && (ptr->file[0] != '\0') )
|
||
{
|
||
int len, j;
|
||
if ((len = strlen(ptr->file)) > FILE_LEN) {
|
||
buffer[detail+9] = '.';
|
||
buffer[detail+10] = '.';
|
||
buffer[detail+11] = '.';
|
||
for(i=len-(FILE_LEN-3), j=0; (j < FILE_LEN) && (ptr->file[i] != '\0'); i++, j++)
|
||
{
|
||
buffer[detail+12+j] = ptr->file[i];
|
||
}
|
||
} else {
|
||
for(i=0; (i < FILE_LEN) && (ptr->file[i] != '\0'); i++)
|
||
{
|
||
buffer[detail+9+i] = ptr->file[i];
|
||
}
|
||
}
|
||
|
||
(void) tostring(buffer+detail+30,
|
||
(ulong_t)ptr->callerpc_line,7,B_DEC, ' ');
|
||
}
|
||
else
|
||
{
|
||
if ((long)ptr->callerpc_line == -1)
|
||
{
|
||
for(i=0; i < (sizeof("unknown")-1); i++)
|
||
{
|
||
buffer[detail+9+i] = "unknown"[i];
|
||
}
|
||
}
|
||
else
|
||
{
|
||
(void) tostring(buffer+detail+30,
|
||
(ulong_t)ptr->callerpc_line,8,B_HEX, ' ');
|
||
}
|
||
}
|
||
|
||
/*
|
||
* determine name of function to use
|
||
*/
|
||
switch( GETTYPE(ptr) )
|
||
{
|
||
case M_T_MALLOC:
|
||
func = "malloc";
|
||
break;
|
||
|
||
case M_T_REALLOC:
|
||
func = "realloc";
|
||
break;
|
||
|
||
case M_T_CALLOC:
|
||
func = "calloc";
|
||
break;
|
||
|
||
default:
|
||
func = "unknown";
|
||
break;
|
||
}
|
||
|
||
/*
|
||
* copy the function name into the string.
|
||
*/
|
||
for( i=0; func[i] != '\0'; i++)
|
||
{
|
||
buffer[detail+39+i] = func[i];
|
||
}
|
||
|
||
/*
|
||
* add the call number
|
||
*/
|
||
buffer[detail+39+ i++] = '(';
|
||
i += tostring(buffer+detail+39+i,(ulong_t)ptr->id,0,B_DEC,' ');
|
||
buffer[detail+39+i] = ')';
|
||
|
||
/*
|
||
* display the length of the segment
|
||
*/
|
||
(void) tostring(buffer+detail+54,
|
||
(ulong_t)DH_ULEN(flink),7,B_DEC,' ');
|
||
|
||
/*
|
||
* display the first seven bytes of data
|
||
*/
|
||
for( i=0; (i < NUM_BYTES) && (i < DH_ULEN(flink)); i++)
|
||
{
|
||
(void) tostring(buffer+detail + 62 + (i * 2),
|
||
((ulong_t)*((unsigned char *)(((Dhead *)flink)+1)+i)), 2, B_HEX, '0');
|
||
}
|
||
|
||
buffer[detail + sizeof(NORMAL_HDR_3)] = '\n';
|
||
WRITEOUT(fd,buffer,detail+sizeof(NORMAL_HDR_3)+1);
|
||
{
|
||
char buf[256];
|
||
int start=0;
|
||
int cnt=0;
|
||
for (i=0; i < 15; i++) {
|
||
buf[i]=' ';
|
||
start++;
|
||
}
|
||
buf[start+(cnt++)] = 'C';
|
||
buf[start+(cnt++)] = 'P';
|
||
buf[start+(cnt++)] = 'U';
|
||
buf[start+(cnt++)] = ':';
|
||
tostring(buf+start+cnt,(ptr->dbg->cpu),2,B_DEC,'0');
|
||
cnt+=2;
|
||
for (i=0; i < 2; i++) {
|
||
buf[start+cnt] = ' ';
|
||
cnt++;
|
||
}
|
||
buf[start+(cnt++)] = 'P';
|
||
buf[start+(cnt++)] = 'I';
|
||
buf[start+(cnt++)] = 'D';
|
||
buf[start+(cnt++)] = ':';
|
||
tostring(buf+start+cnt,(__tls()->__pid),10,B_DEC,'0');
|
||
cnt+=10;
|
||
for (i=0; i < 2; i++) {
|
||
buf[start+cnt] = ' ';
|
||
cnt++;
|
||
}
|
||
buf[start+(cnt++)] = 'T';
|
||
buf[start+(cnt++)] = 'I';
|
||
buf[start+(cnt++)] = 'D';
|
||
buf[start+(cnt++)] = ':';
|
||
tostring(buf+start+cnt,(ptr->dbg->tid),5,B_DEC,'0');
|
||
cnt+=5;
|
||
for (i=0; i < 2; i++) {
|
||
buf[start+cnt] = ' ';
|
||
cnt++;
|
||
}
|
||
buf[start+(cnt++)] = 'T';
|
||
buf[start+(cnt++)] = 'S';
|
||
buf[start+(cnt++)] = ':';
|
||
tostring64(buf+start+cnt,(ptr->dbg->ts),18,B_HEX,'0');
|
||
cnt+=18;
|
||
buf[start+(cnt++)]='\n';
|
||
WRITEOUT(fd,buf,start+cnt);
|
||
}
|
||
{
|
||
char buf[50];
|
||
int start=0;
|
||
__Dbg_Data *dd;
|
||
__Dbg_St *ds;
|
||
for (i=0; i < 21; i++) {
|
||
buf[i]=' ';
|
||
start++;
|
||
}
|
||
dd = ptr->dbg;
|
||
if (dd) {
|
||
ds = dd->bt;
|
||
i=0;
|
||
while (ds) {
|
||
buf[start+0]='B';
|
||
buf[start+1]='T';
|
||
buf[start+2]=' ';
|
||
tostring(buf+start+3,i+1,2,B_DEC,' ');
|
||
buf[start+5]=':';
|
||
buf[start+6]=' ';
|
||
tostring(buf+start+7,(ulong_t)(ds->line),10,B_HEX,'0');
|
||
buf[start+17]='\n';
|
||
WRITEOUT(fd,buf,start+18);
|
||
ds = ds->next;
|
||
if (ds && (ds->line == dd->bt->line))
|
||
break;
|
||
i++;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return total;
|
||
} /* malloc_list_chain_items(... */
|
||
|
||
/*
|
||
* Function: malloc_list_items()
|
||
*
|
||
* Purpose: to dump a printed copy of the malloc chain and
|
||
* associated data elements
|
||
*
|
||
* Arguments: fd - file descriptor to write data to
|
||
* list_type - type of list (all records, or a selected list)
|
||
* histid1 - first id to list (if type is some)
|
||
* histid2 - one above last id to list
|
||
*
|
||
* Returns: nothing of any use
|
||
*
|
||
* Narrative: Just print out all the data
|
||
*
|
||
* Notes: This function is implemented using low level calls because
|
||
* of the likelyhood that the malloc tree is damaged when it
|
||
* is called. (Lots of things in the c library use malloc and
|
||
* we don't want to get into a catch-22).
|
||
*
|
||
*/
|
||
|
||
static void
|
||
write_column_headers(int fd, int detail)
|
||
{
|
||
/*
|
||
* write out the column headers
|
||
*/
|
||
if( detail != DETAIL_NONE )
|
||
{
|
||
WRITEOUT(fd,DETAIL_HDR_1,sizeof(DETAIL_HDR_1)-1);
|
||
WRITEOUT(fd,NORMAL_HDR_1,sizeof(NORMAL_HDR_1)-1);
|
||
WRITEOUT(fd,DETAIL_HDR_2,sizeof(DETAIL_HDR_2)-1);
|
||
WRITEOUT(fd,NORMAL_HDR_2,sizeof(NORMAL_HDR_2)-1);
|
||
WRITEOUT(fd,DETAIL_HDR_3,sizeof(DETAIL_HDR_3)-1);
|
||
WRITEOUT(fd,NORMAL_HDR_3,sizeof(NORMAL_HDR_3)-1);
|
||
}
|
||
else
|
||
{
|
||
WRITEOUT(fd,NORMAL_HDR_1,sizeof(NORMAL_HDR_1)-1);
|
||
WRITEOUT(fd,NORMAL_HDR_2,sizeof(NORMAL_HDR_2)-1);
|
||
WRITEOUT(fd,NORMAL_HDR_3,sizeof(NORMAL_HDR_3)-1);
|
||
}
|
||
}
|
||
|
||
void
|
||
malloc_list_items(int fd, int list_type, ulong_t histid1, ulong_t histid2)
|
||
{
|
||
char buffer[THISBUFSIZE];
|
||
int detail;
|
||
void exit();
|
||
int i;
|
||
int loc;
|
||
Arena * ap;
|
||
Band * band;
|
||
int nb;
|
||
int arena_count = 0, arena_size = 0;
|
||
chain_total_t totals;
|
||
chain_total_t btotals;
|
||
chain_total_t running_arena_totals;
|
||
chain_total_t all_totals;
|
||
char buffer1[THISBUFSIZE];
|
||
arena_range_t range;
|
||
|
||
running_arena_totals.c_entries=0;
|
||
running_arena_totals.c_size=0;
|
||
all_totals.c_entries=0;
|
||
all_totals.c_size=0;
|
||
|
||
ENTER();
|
||
MALLOC_INIT();
|
||
|
||
/*
|
||
* See if they want full detail (includes internal pointer info)
|
||
*/
|
||
detail = ( __malloc_detail != 0 ) ? DETAIL_ST_COL : DETAIL_NONE;
|
||
|
||
/*
|
||
* fill the title line with asterisks
|
||
*/
|
||
for(i=0; i < (detail + sizeof(NORMAL_HDR_3)-1); i++) {
|
||
buffer[i] = '*';
|
||
}
|
||
buffer[i] = '\n';
|
||
buffer[i+1] = '\0';
|
||
|
||
/*
|
||
* add in the title (centered, of course)
|
||
*/
|
||
if (list_type == LIST_UNREFERENCED) {
|
||
loc = (i - sizeof(TITLE2)) / 2;
|
||
for(i=0; i < (sizeof(TITLE2)-1); i++) {
|
||
buffer[loc+i] = TITLE2[i];
|
||
}
|
||
} else {
|
||
loc = (i - sizeof(TITLE1)) / 2;
|
||
for(i=0; i < (sizeof(TITLE1)-1); i++) {
|
||
buffer[loc+i] = TITLE1[i];
|
||
}
|
||
}
|
||
|
||
/*
|
||
* and write it out
|
||
*/
|
||
WRITEOUT(fd,buffer,strlen(buffer));
|
||
|
||
/*
|
||
* Go through malloc chains for each Arena
|
||
*/
|
||
for (ap = __arenas.a_next; ap != &__arenas; ap = ap->a_next) {
|
||
Dhead *dp = (Dhead *)(ap+1);
|
||
Dhead *dpend;
|
||
int free_size = 0, free_count = 0;
|
||
|
||
if (ap->a_size < sizeof(*ap)) panic("a_size");
|
||
|
||
arena_count++;
|
||
arena_size += ap->a_size;
|
||
|
||
dpend = (Dhead *)((char *)ap + ap->a_size - sizeof(Dtail));
|
||
|
||
range.r_start = (char *)dp;
|
||
range.r_end = (char *)dpend;
|
||
range.r_type = RANGE_ARENA;
|
||
range.un.r_arena = ap;
|
||
|
||
sprintf(buffer, "\n\nARENA %x, size %u:\n\n", (uint_t)ap, ap->a_size);
|
||
WRITEOUT(fd, buffer, strlen(buffer));
|
||
|
||
totals =
|
||
malloc_list_chain_items(fd, list_type, histid1, histid2,
|
||
&range, &ap->a_malloc_chain, detail, buffer);
|
||
running_arena_totals.c_entries += totals.c_entries;
|
||
running_arena_totals.c_size += totals.c_size;
|
||
|
||
if( list_type == LIST_SOME || list_type == LIST_ALL )
|
||
{
|
||
Flink *fp;
|
||
|
||
sprintf(buffer1, "\n%d Allocated entries %u bytes\n",
|
||
totals.c_entries, totals.c_size);
|
||
WRITEOUT(fd,buffer1,strlen(buffer1));
|
||
|
||
sprintf(buffer1, "\n\nFree list:\n\n");
|
||
WRITEOUT(fd,buffer1,strlen(buffer1));
|
||
for (i=0; i < __flist_nbins ; i++) {
|
||
Flink *fp_list;
|
||
Flink *curflistptr;
|
||
curflistptr = __malloc_getflistptr();
|
||
fp_list = &(curflistptr[i]);
|
||
for (fp = fp_list->f_next; fp != fp_list; fp = fp->f_next)
|
||
{
|
||
if ((char *)fp >= range.r_start && (char *)fp <= range.r_end) {
|
||
free_count++; free_size += fp->f_size;
|
||
printf(" %p..%p\n", fp, (char *)fp + fp->f_size);
|
||
}
|
||
}
|
||
}
|
||
sprintf(buffer1, "\n%d Free entries %u bytes\n", free_count, free_size);
|
||
WRITEOUT(fd,buffer1,strlen(buffer1));
|
||
}
|
||
else if (list_type == LIST_UNREFERENCED)
|
||
{
|
||
sprintf(buffer1, "\n%d Leaked entries %u bytes\n",
|
||
totals.c_entries, totals.c_size);
|
||
WRITEOUT(fd,buffer1,strlen(buffer1));
|
||
}
|
||
}
|
||
if( list_type == LIST_SOME || list_type == LIST_ALL )
|
||
{
|
||
sprintf(buffer1, "\n%d Arenas %u bytes\n", arena_count, arena_size);
|
||
WRITEOUT(fd,buffer1,strlen(buffer1));
|
||
}
|
||
btotals =
|
||
malloc_list_chain_items_bands(fd, list_type, histid1, histid2,
|
||
&range, &ap->a_malloc_chain, detail, buffer);
|
||
if( list_type == LIST_SOME || list_type == LIST_ALL )
|
||
{
|
||
sprintf(buffer1, "\n%d Allocated Band entries %u bytes\n",
|
||
btotals.c_entries, btotals.c_size);
|
||
WRITEOUT(fd,buffer1,strlen(buffer1));
|
||
|
||
}
|
||
else if (list_type == LIST_UNREFERENCED)
|
||
{
|
||
sprintf(buffer1, "\n%d Leaked Band entries %u bytes\n",
|
||
btotals.c_entries, btotals.c_size);
|
||
WRITEOUT(fd,buffer1,strlen(buffer1));
|
||
}
|
||
|
||
/*
|
||
* Go through malloc chains for every Block in every Band
|
||
*/
|
||
for (nb = 0; nb < *__pnband; nb++)
|
||
{
|
||
Block *bp;
|
||
int free_count = 0, free_size = 0;
|
||
int esize;
|
||
|
||
band = __pBands[nb];
|
||
esize = band->nbpe + SB_OVERHEAD();
|
||
|
||
if (band->alist != NULL || band->dlist != NULL) {
|
||
sprintf(buffer1, "\n\nBAND %x, small buffer size %u:\n\n", (uint_t)band, band->nbpe);
|
||
WRITEOUT(fd,buffer1,strlen(buffer1));
|
||
}
|
||
|
||
totals.c_entries = 0;
|
||
totals.c_size = 0;
|
||
/*
|
||
* For each Block on the allocated list
|
||
*/
|
||
for (bp = band->alist; bp; bp = bp->next)
|
||
{
|
||
int entries = band->nalloc - bp->navail;
|
||
totals.c_entries += entries;
|
||
totals.c_size += (entries * band->nbpe);
|
||
free_count += bp->navail;
|
||
free_size += bp->navail * band->nbpe;
|
||
}
|
||
|
||
/*
|
||
* For each Block on the depleted list
|
||
*/
|
||
for (bp = band->dlist; bp; bp = bp->next)
|
||
{
|
||
totals.c_entries += band->nalloc;
|
||
totals.c_size += (band->nalloc * band->nbpe);
|
||
}
|
||
|
||
if ( (band->alist != NULL || band->dlist != NULL) )
|
||
{
|
||
if (list_type == LIST_SOME || list_type == LIST_ALL)
|
||
{
|
||
sprintf(buffer1, "\n%d Allocated entries %u bytes\n",
|
||
totals.c_entries, totals.c_size);
|
||
WRITEOUT(fd,buffer1,strlen(buffer1));
|
||
sprintf(buffer1, "\n%d Free entries %u bytes\n", free_count, free_size);
|
||
WRITEOUT(fd,buffer1,strlen(buffer1));
|
||
}
|
||
}
|
||
}
|
||
|
||
all_totals.c_entries += running_arena_totals.c_entries + btotals.c_entries;
|
||
all_totals.c_size += running_arena_totals.c_size + btotals.c_size;
|
||
|
||
if( list_type == LIST_SOME || list_type == LIST_ALL )
|
||
{
|
||
sprintf(buffer1, "\n%d Total Allocated entries %u bytes\n",
|
||
all_totals.c_entries, all_totals.c_size);
|
||
WRITEOUT(fd,buffer1,strlen(buffer1));
|
||
|
||
}
|
||
else if (list_type == LIST_UNREFERENCED)
|
||
{
|
||
sprintf(buffer1, "\n%d Total Leaked entries %u bytes\n",
|
||
all_totals.c_entries, all_totals.c_size);
|
||
WRITEOUT(fd,buffer1,strlen(buffer1));
|
||
}
|
||
|
||
if( detail != DETAIL_NONE )
|
||
{
|
||
WRITEOUT(fd,"Malloc start: ",19);
|
||
(void) tostring(buffer, (ulong_t) _malloc_start, 8, B_HEX, '0');
|
||
buffer[8] = '\n';
|
||
WRITEOUT(fd,buffer,9);
|
||
|
||
WRITEOUT(fd,"Malloc end: ", 19);
|
||
(void) tostring(buffer, (ulong_t) _malloc_end, 8, B_HEX, '0');
|
||
buffer[8] = '\n';
|
||
WRITEOUT(fd,buffer,9);
|
||
|
||
#if 0
|
||
WRITEOUT(fd,"Malloc data start: ", 19);
|
||
(void) tostring(buffer,(ulong_t) malloc_data_start,8,B_HEX,'0');
|
||
buffer[8] = '\n';
|
||
WRITEOUT(fd,buffer,9);
|
||
|
||
WRITEOUT(fd,"Malloc data end: ", 19);
|
||
(void) tostring(buffer,(ulong_t) malloc_data_end, 8, B_HEX, '0');
|
||
buffer[8] = '\n';
|
||
WRITEOUT(fd,buffer,9);
|
||
|
||
WRITEOUT(fd,"Malloc free list: ", 19);
|
||
(void) tostring(buffer, (ulong_t) malloc_freelist, 8,B_HEX,'0');
|
||
buffer[8] = '\n';
|
||
WRITEOUT(fd,buffer,9);
|
||
|
||
for( ptr=malloc_freelist->freenext; ptr != NULL; ptr = ptr->freenext)
|
||
{
|
||
WRITEOUT(fd," -> ", 19);
|
||
(void) tostring(buffer, (ulong_t) ptr, 8, B_HEX, '0');
|
||
buffer[8] = '\n';
|
||
WRITEOUT(fd,buffer,9);
|
||
}
|
||
|
||
#endif
|
||
}
|
||
|
||
WRITEOUT(fd,"\n",1);
|
||
LEAVE();
|
||
|
||
} /* malloc_dump(... */
|
||
|
||
|
||
/*
|
||
* $Log$
|
||
* Revision 1.17 2007/04/24 15:44:27 shiv
|
||
* PR:29730
|
||
* CI:cburgess
|
||
* CI:xtang
|
||
*
|
||
* this is part of work order WO790334 for IGT. Included enhancements
|
||
* for configurability of the memory allocator. Includes matching changes for
|
||
* lib/c/alloc and lib/malloc as usual. This is to bring head in line
|
||
* with the work committed to the branch.
|
||
*
|
||
* Revision 1.16 2006/09/28 19:05:57 alain
|
||
* PR:41782
|
||
* CI: shiv@qnx.com
|
||
* CI: cburgess@qnx.com
|
||
*
|
||
* Commiting the work done for IGT-CE on the head.
|
||
*
|
||
* Revision 1.15.2.1 2006/03/02 21:32:02 alain
|
||
*
|
||
*
|
||
* We should not call getenv() anywhere this can lead to potential deadlocks
|
||
* the strategy here is to do all the initialization upfront in the init code.
|
||
* Also some minor formatting fixes.
|
||
*
|
||
* Revision 1.15 2005/06/03 01:22:48 adanko
|
||
*
|
||
* Replace existing QNX copyright licence headers with macros as specified by
|
||
* the QNX Coding Standard. This is a change to source files in the head branch
|
||
* only.
|
||
*
|
||
* Note: only comments were changed.
|
||
*
|
||
* PR25328
|
||
*
|
||
* Revision 1.14 2005/02/25 03:03:37 shiv
|
||
* More fixes for the debug malloc, for the tools to work
|
||
* better.
|
||
* Modified Files:
|
||
* malloc-lib.h mallocint.h dbg/calloc.c dbg/dump.c dbg/m_init.c
|
||
* dbg/malloc_debug.c dbg/malloc_g.c dbg/mtrace.c dbg/realloc.c
|
||
* public/malloc_g/malloc.h
|
||
*
|
||
* Revision 1.13 2005/02/11 19:00:28 shiv
|
||
* Some more malloc_g changes.
|
||
* Modified Files:
|
||
* mallocint.h dbg/dump.c dbg/m_init.c dbg/m_perror.c
|
||
* dbg/malloc_g.c dbg/malloc_gc.c dbg/mtrace.c
|
||
*
|
||
* Revision 1.12 2005/01/19 16:53:00 shiv
|
||
* Slight mods to allow easier access to the free list
|
||
* to allow user land to gather information about allocator.
|
||
* Matching with libc checkin.
|
||
* Modified Files:
|
||
* dbg/dump.c dbg/malloc_chk.c dbg/malloc_g.c
|
||
*
|
||
* Revision 1.11 2005/01/16 20:38:45 shiv
|
||
* Latest DBG malloc code. Lots of cleanup/optimistions
|
||
* Modified Files:
|
||
* common.mk mallocint.h common/tostring.c dbg/analyze.c
|
||
* dbg/calloc.c dbg/dump.c dbg/free.c dbg/m_init.c
|
||
* dbg/malloc_chk.c dbg/malloc_chn.c dbg/malloc_g.c
|
||
* dbg/malloc_gc.c dbg/mallopt.c dbg/memory.c dbg/mtrace.c
|
||
* dbg/process.c dbg/realloc.c dbg/string.c
|
||
* public/malloc_g/malloc-lib.h public/malloc_g/malloc.h
|
||
* std/calloc.c std/free.c std/m_init.c std/malloc_wrapper.c
|
||
* std/mtrace.c std/realloc.c
|
||
* Added Files:
|
||
* dbg/dl_alloc.c dbg/malloc_control.c dbg/malloc_debug.c
|
||
* dbg/new.cc public/malloc_g/malloc-control.h
|
||
* public/malloc_g/malloc-debug.h
|
||
*
|
||
* Revision 1.10 2004/02/12 15:43:16 shiv
|
||
* Updated copyright/licenses
|
||
* Modified Files:
|
||
* common.mk debug.h malloc-lib.h mallocint.h tostring.h
|
||
* common/tostring.c dbg/analyze.c dbg/calloc.c dbg/context.h
|
||
* dbg/crc.c dbg/dump.c dbg/free.c dbg/m_init.c dbg/m_perror.c
|
||
* dbg/malloc_chk.c dbg/malloc_chn.c dbg/malloc_g.c
|
||
* dbg/malloc_gc.c dbg/mallopt.c dbg/memory.c dbg/mtrace.c
|
||
* dbg/process.c dbg/realloc.c dbg/string.c
|
||
* public/malloc/malloc.h public/malloc_g/malloc-lib.h
|
||
* public/malloc_g/malloc.h public/malloc_g/prototypes.h
|
||
* std/calloc.c std/context.h std/free.c std/m_init.c
|
||
* std/malloc_wrapper.c std/mtrace.c std/realloc.c test/memtest.c
|
||
* test/mtrace.c
|
||
*
|
||
* Revision 1.9 2003/10/27 14:27:38 shiv
|
||
* Fixed an error in the output of the initial bytes.
|
||
*
|
||
* Revision 1.8 2003/09/25 23:08:36 shiv
|
||
* One missed output print statement.
|
||
* Modified Files:
|
||
* dbg/dump.c
|
||
*
|
||
* Revision 1.7 2003/09/25 22:52:22 shiv
|
||
* Made output consistent for all types of leaks detected.
|
||
* Modified Files:
|
||
* dbg/dump.c
|
||
*
|
||
* Revision 1.6 2003/09/25 19:06:49 shiv
|
||
* Fixed several things in the malloc code including the
|
||
* leak detection for both small and large blocks. re-arranged
|
||
* a lot code, and removed pieces that were not necessary after the
|
||
* re-org. Modified the way in which the elf sections are read to
|
||
* determine where heap references could possibly be stored.
|
||
* set the optimisation for the debug variant at -O0, just so
|
||
* so that debugging the lib itself is a little easier.
|
||
* Modified Files:
|
||
* common.mk mallocint.h dbg/dump.c dbg/malloc_chk.c
|
||
* dbg/malloc_chn.c dbg/malloc_g.c dbg/malloc_gc.c dbg/mtrace.c
|
||
* dbg/process.c dbg/string.c
|
||
*
|
||
* Revision 1.5 2003/09/22 16:59:55 shiv
|
||
* Some fixes for the way the leak detection is done and reported.
|
||
* Modified Files:
|
||
* dbg/dump.c dbg/malloc_chk.c dbg/mtrace.c
|
||
*
|
||
* Revision 1.4 2003/07/30 13:10:28 sebastien
|
||
* Start fixing the memory leak detection (PR12920). This is
|
||
* again a partial fix, which properly matches the structures and alignement
|
||
* from the mainline library.
|
||
*
|
||
* One issue that remains is the scanning of "gaps" which are composed of
|
||
* multiple blocks. The gap scanning algorithm has to be updated to allow that.
|
||
*
|
||
* Revision 1.3 2003/06/05 15:21:14 shiv
|
||
* Some cleanup to match changes to the malloc code in
|
||
* libc.
|
||
*
|
||
* Revision 1.2 2000/02/15 22:01:07 furr
|
||
* Changed to a more reasonable heap marking algorithm for memory leak
|
||
* detection.
|
||
* - won't blow the stack
|
||
* Fixed up file and line printing in all dumps.
|
||
*
|
||
* Modified Files:
|
||
* mallocint.h dbg/dump.c dbg/malloc_g.c dbg/malloc_gc.c
|
||
* dbg/process.c dbg/tostring.c test/memtest.C
|
||
*
|
||
* Revision 1.1 2000/01/31 19:03:30 bstecher
|
||
* Create libmalloc.so and libmalloc_g.so libraries for everything. See
|
||
* Steve Furr for details.
|
||
*
|
||
* Revision 1.1 2000/01/28 22:32:44 furr
|
||
* libmalloc_g allows consistency checks and bounds checking of heap
|
||
* blocks allocated using malloc.
|
||
* Initial revision
|
||
*
|
||
* Added Files:
|
||
* Makefile analyze.c calloc_g.c crc.c dump.c free.c m_init.c
|
||
* m_perror.c malloc-config.c malloc_chk.c malloc_chn.c
|
||
* malloc_g.c malloc_gc.c mallopt.c memory.c process.c realloc.c
|
||
* string.c tostring.c inc/debug.h inc/mallocint.h inc/tostring.h
|
||
* inc/malloc_g/malloc inc/malloc_g/malloc.h
|
||
* inc/malloc_g/prototypes.h test/memtest.C test/memtest.c
|
||
* x86/Makefile x86/so/Makefile
|
||
*
|
||
* Revision 1.2 1996/08/18 21:00:20 furr
|
||
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>print the caller return address on errors
|
||
*
|
||
* Revision 1.1 1996/07/24 18:22:02 furr
|
||
* Initial revision
|
||
*
|
||
* Revision 1.9 1992/01/10 17:28:03 cpcahil
|
||
* Added support for overriding void datatype
|
||
*
|
||
* Revision 1.8 1991/12/04 09:23:36 cpcahil
|
||
* several performance enhancements including addition of free list
|
||
*
|
||
* Revision 1.7 91/11/25 14:41:52 cpcahil
|
||
* Final changes in preparation for patch 4 release
|
||
*
|
||
* Revision 1.6 91/11/24 00:49:25 cpcahil
|
||
* first cut at patch 4
|
||
*
|
||
* Revision 1.5 90/08/29 21:22:37 cpcahil
|
||
* miscellaneous lint fixes
|
||
*
|
||
* Revision 1.4 90/05/11 00:13:08 cpcahil
|
||
* added copyright statment
|
||
*
|
||
* Revision 1.3 90/02/24 21:50:07 cpcahil
|
||
* lots of lint fixes
|
||
*
|
||
* Revision 1.2 90/02/24 17:27:48 cpcahil
|
||
* changed $header to $Id to remove full path from rcs id string
|
||
*
|
||
* Revision 1.1 90/02/22 23:17:43 cpcahil
|
||
* Initial revision
|
||
*
|
||
*/
|