memtrack.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 503 行
C
503 行
/****************************************************************************
*
* Open Watcom Project
*
* Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
* ========================================================================
*
* This file contains Original Code and/or Modifications of Original
* Code as defined in and that are subject to the Sybase Open Watcom
* Public License version 1.0 (the 'License'). You may not use this file
* except in compliance with the License. BY USING THIS FILE YOU AGREE TO
* ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
* provided with the Original Code and Modifications, and is also
* available at www.sybase.com/developer/opensource.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
* NON-INFRINGEMENT. Please see the License for the specific language
* governing rights and limitations under the License.
*
* ========================================================================
*
* Description: WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
* DESCRIBE IT HERE!
*
****************************************************************************/
#include <stdarg.h>
#define ALLOC_BYTE 0xA5 /* the fill value for allocated memory */
#define FREED_BYTE 0xBD /* the fill value for freed memory */
#define TRACK_SIZE 0xFF0
enum { FALSE = 0==1, TRUE = 0==0 };
#ifndef FAR
#ifdef _EXTRA_MEM
#define FAR far
#else
#define FAR
#endif
#endif
typedef struct track_entry FAR * TRPTR;
typedef struct tracker {
TRPTR allocated_list;
unsigned long memory_in_use;
unsigned long max_memory_used;
void *(*alloc)(int);
void (*free)(void*);
void (*print_line)(char*,unsigned);
char name[1];
} tracker;
typedef struct track_entry {
TRPTR next;
void *mem;
void (*who)();
unsigned int size;
} track_entry;
#ifdef _SYS_CHKS
extern char MemOk(void *,int);
extern void *MemOtherOk();
#endif
#ifdef _EXTRA_MEM
extern void FAR * ExtMemAlloc(unsigned int);
#pragma aux ExtMemAlloc = \
0xB4 0x48 /* mov ax,048H */ \
0xCD 0x21 /* int 21H */ \
0x73 0x02 /* jnb L1 */ \
0x31 0xC0 /* xor ax,ax */ \
0x89 0xC2 /*L1: mov dx,ax */ \
0x31 0xC0 /* xor ax,ax */ \
parm routine [ bx ] \
;
extern unsigned int ExtMemAvail();
#pragma aux ExtMemAvail = \
0xBB 0xFF 0xFF /* mov bx,0FFFFH */ \
0xB4 0x48 /* mov ah,48H */ \
0xCD 0x21 /* int 21H */ \
0xD3 0xE3 /* shl bx,cl */ \
value [ bx ] \
;
extern void ExtMemFree(void FAR *);
#pragma aux ExtMemFree = \
0x06 /* push es */ \
0x8E 0xC2 /* mov es,dx */ \
0xB4 0x49 /* mov ah,49H */ \
0xCD 0x21 /* int 21H */ \
0x07 /* pop es */ \
parm routine [ dx ax ] \
;
static TRPTR TrkFrl;
static TRPTR ExtMem;
static TRPTR TrkBeg;
#endif
#if defined(__SMALL__) || defined(__MEDIUM__)
#define _POINTER_ADD( p, i ) ((void *)((char *)(p) + i))
#define _POINTER( p ) ((void *) p)
#else
#define _POINTER_ADD( p, i ) ((void *)((char huge *)(p) + i))
#define _POINTER( p ) ((void huge *) p)
#endif
#if defined(__COMPACT__) /* no near needed for "__SMALL__" */
#define CODE_PTR_TYPE void near *
#elif defined(__MEDIUM__) || defined (__LARGE__) || defined(__HUGE__)
#define CODE_PTR_TYPE void far *
#else
#define CODE_PTR_TYPE void *
#endif
#define TR_NO_ROUTINE ((void (*)())0)
static char *CopyStr( char *src, char *dest )
{
while( *dest = *src ) {
++src;
++dest;
}
return( dest );
}
static char *FormHex( char *ptr, unsigned long data, unsigned size )
{
char *str;
size *= 2;
ptr += size;
str = ptr;
for( ; size > 0; size-- ) {
*--str = "0123456789abcdef"[data & 0x0f];
data >>= 4;
}
return( ptr );
}
void TrPrt( tracker *trk, char *fmt, ... )
{
va_list args;
char buff[80];
char *ptr;
char ch;
unsigned ui;
unsigned long ul;
void *dp;
CODE_PTR_TYPE cp;
va_start( args, fmt );
ptr = buff;
for( ;; ) {
ch = *fmt++;
if( ch == '\0' ) break;
if( ch == '%' ) {
ch = *fmt++;
switch( ch ) {
case 'N': /* name of tracker invoker */
ptr = CopyStr( trk->name, ptr );
break;
case 'W': /* "%Na1(a2):" */
ptr = CopyStr( trk->name, ptr );
ptr = CopyStr( va_arg( args, char * ), ptr );
cp = va_arg( args, CODE_PTR_TYPE );
if( cp != TR_NO_ROUTINE ) {
*ptr++ = '(';
ptr = FormHex( ptr, (unsigned long)cp, sizeof( cp ) );
*ptr++ = ')';
}
*ptr++ = ':';
break;
case 'C': /* code pointer */
cp = va_arg( args, CODE_PTR_TYPE );
ptr = FormHex( ptr, (unsigned long)cp, sizeof( cp ) );
break;
case 'D': /* data pointer */
dp = va_arg( args, void * );
ptr = FormHex( ptr, (unsigned long)dp, sizeof( dp ) );
break;
case 'U': /* unsigned integer */
ui = va_arg( args, unsigned );
ptr = FormHex( ptr, (unsigned long)ui, sizeof( ui ) );
break;
case 'L': /* unsigned long */
ul = va_arg( args, unsigned long );
ptr = FormHex( ptr, (unsigned long)ul, sizeof( ul ) );
break;
default:
*ptr++ = ch;
break;
}
} else {
*ptr++ = ch;
}
}
va_end( args );
*ptr = '\0';
trk->print_line( buff, ptr - buff );
}
#pragma off(unreferenced);
static TRPTR AllocTrk( tracker *trk ) {
#pragma on(unreferenced);
/***********************************/
TRPTR entry;
#ifdef _EXTRA_MEM
if( TrkFrl != 0 ) {
entry = TrkFrl;
TrkFrl = TrkFrl->next;
} else {
entry = TrkBeg++;
}
#else
entry = trk->alloc( sizeof( track_entry ) );
#endif
return( entry );
}
#pragma off(unreferenced);
static void FreeTrk( TRPTR entry, tracker *trk ) {
#pragma on(unreferenced);
/*********************************************/
#ifdef _EXTRA_MEM
entry->next = TrkFrl;
TrkFrl = entry;
#else
trk->free( entry );
#endif
}
static void Fill( void *start, unsigned len, char filler ) {
/**********************************************************/
char *ptr;
ptr = start;
while( len != 0 ) {
*ptr++ = filler;
--len;
}
}
extern tracker *TrMemInit( char *name,
void *(*alloc)(int),
void (*free)(void *),
void (*print_line)(char *, unsigned) ){
tracker *trk;
char *p1;
p1 = name;
while( *p1 ) {
++p1;
}
trk = alloc( sizeof( tracker ) + ( p1 - name ) );
#ifdef _EXTRA_MEM
if( ExtMem == 0 ) {
ExtMem = ExtMemAlloc( TRACK_SIZE );
if( ExtMem == (void FAR *)0 ) {
ExtMem = ExtMemAlloc( ExtMemAvail() );
}
TrkFrl = 0;
TrkBeg = ExtMem;
}
#endif
if( trk == 0 ) return( 0 );
trk->allocated_list = 0;
trk->memory_in_use = 0;
trk->max_memory_used = 0;
trk->alloc = alloc;
trk->free = free;
trk->print_line = print_line;
CopyStr( name, trk->name );
return( trk );
}
extern void TrCheck( tracker *trk ) {
/***************************************/
TRPTR alloc;
alloc = trk->allocated_list;
while( alloc != 0 ) {
TrValidate( alloc->mem, TR_NO_ROUTINE, trk );
alloc = alloc->next;
}
}
extern void TrMemFini( tracker *trk ) {
/*****************************************/
unsigned chunks;
TRPTR alloc;
chunks = 0;
alloc = trk->allocated_list;
while( alloc != 0 ) {
++chunks;
alloc = alloc->next;
}
if( chunks != 0 ) {
TrPrt( trk, "%NMemFini: %U chunks (%L bytes) unfreed",
chunks, trk->memory_in_use );
}
while( trk->allocated_list != 0 ) {
TrValidate( trk->allocated_list->mem, TR_NO_ROUTINE, trk );
TrFree( trk->allocated_list->mem, trk );
}
trk->free( trk );
#ifdef _EXTRA_MEM
ExtMemFree( ExtMem );
#endif
}
extern void TrPrtUsage( tracker *trk ) {
/******************************************/
TrPrt( trk, "%N Memory usage: %L bytes", trk->max_memory_used );
}
extern void TrPrtMemUse( tracker *trk ) {
/*******************************************/
TRPTR alloc;
TrPrtUsage( trk );
alloc = trk->allocated_list;
if( alloc == 0 ) return;
TrPrt( trk, " Who Addr Size" );
TrPrt( trk, " ======== ======== ====" );
do {
TrPrt( trk, "&%C %D %U", alloc->who, alloc->mem, alloc->size );
alloc = alloc->next;
} while( alloc != 0 );
}
extern void *TrAlloc( unsigned size, void (*ra)(), tracker *trk ) {
/******************************************************************/
void *chunk;
TRPTR trchunk;
if( size == 0 ) {
TrPrt( trk, "%W size zero allocation", "Alloc", ra );
return( 0 );
}
chunk = trk->alloc( size + 1 );
if( chunk != 0 ) {
trchunk = AllocTrk( trk );
trchunk->next = trk->allocated_list;
trchunk->who = ra;
trchunk->size = size;
trchunk->mem = chunk;
trk->allocated_list = trchunk;
trk->memory_in_use += size;
if( trk->memory_in_use > trk->max_memory_used ) {
trk->max_memory_used = trk->memory_in_use;
}
Fill( chunk, size + 1, ALLOC_BYTE );
}
return( chunk );
}
static int ValidChunk( TRPTR entry, char *who, void (*ra)(), tracker *trk ) {
/****************************************************************************/
void *chunk;
chunk = entry->mem;
if( *((unsigned char *)_POINTER_ADD( chunk, entry->size )) != ALLOC_BYTE ) {
TrPrt( trk, "%W %D overrun allocation of %U bytes", who, ra,
chunk, entry->size );
return( FALSE );
#ifdef _SYS_CHKS
} else if( !MemOk( chunk, entry->size + 1 ) ) {
TrPrt( trk, "%W boundry tag hammered %D", who, ra, chunk );
return( FALSE );
} else if( ( chunk = MemOtherOk() ) != 0 ) {
TrPrt( trk, "%W bad free list entry at %D", who, ra, chunk );
return( FALSE );
#endif
}
return( TRUE );
}
extern int TrValidate( void *chunk, void (*ra)(), tracker *trk ) {
/*************************************************************************/
TRPTR entry;
entry = trk->allocated_list;
for(;;) {
if( entry == 0 ) {
TrPrt( trk, "%W unowned chunk %D", "Validate", ra, chunk );
return( FALSE );
}
if( _POINTER( entry->mem ) == _POINTER( chunk ) ) break;
entry = entry->next;
}
return( ValidChunk( entry, "Validate", ra, trk ) );
}
extern int TrChkRange( void *start, unsigned len,
void (*ra)(), tracker *trk ) {
TRPTR ptr;
void *end;
void *end_chunk;
ptr = trk->allocated_list;
for(;;) {
if( ptr == 0 ) {
TrPrt( trk, "%W %D not in any allocation", "ChkRange", ra, start );
return( FALSE );
}
end_chunk = _POINTER_ADD( ptr->mem, ptr->size );
if( _POINTER( start ) >= _POINTER( ptr->mem )
&& _POINTER( start ) < _POINTER( end_chunk ) ) break;
ptr = ptr->next;
}
end = _POINTER_ADD( start, len );
if( _POINTER( end ) > _POINTER( end_chunk ) ) {
TrPrt( trk, "%W %D+%U overruns allocation %D+%U", "ChkRange", ra,
start, len, ptr->mem, ptr->size );
return( FALSE );
}
return( ValidChunk( ptr, "ChkRange", ra, trk ) );
}
extern int TrFree( void *chunk, tracker *trk ) {
/*****************************************************/
return( TrFreeSize( chunk, 0, trk ) );
}
extern int TrFreeSize( void *chunk, unsigned given_size, tracker *trk ) {
/**************************************************************************/
unsigned size;
TRPTR entry;
TRPTR prev;
int ret;
if( chunk == 0 ) return( TRUE );
prev = 0;
entry = trk->allocated_list;
for(;;) {
if( entry == 0 ) {
TrPrt( trk, "%W unowned chunk %D", "Free", TR_NO_ROUTINE, chunk );
return( FALSE );
}
if( _POINTER( chunk ) == _POINTER( entry->mem ) ) break;
prev = entry;
entry = entry->next;
}
ret = ValidChunk( entry, "Free", TR_NO_ROUTINE, trk );
if( prev == 0 ) {
trk->allocated_list = entry->next;
} else {
prev->next = entry->next;
}
size = entry->size;
trk->memory_in_use -= size;
FreeTrk( entry, trk );
Fill( chunk, size + 1, FREED_BYTE );
trk->free( chunk );
if( given_size != 0 && given_size != size ) {
TrPrt( trk, "%W %D allocated %U, freed %U", "FreeSize", TR_NO_ROUTINE,
chunk, size, given_size );
return( FALSE );
}
return( ret );
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?