1 /****************************************************************************
2 *
3 *                            Open Watcom Project
4 *
5 *    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
6 *
7 *  ========================================================================
8 *
9 *    This file contains Original Code and/or Modifications of Original
10 *    Code as defined in and that are subject to the Sybase Open Watcom
11 *    Public License version 1.0 (the 'License'). You may not use this file
12 *    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
13 *    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
14 *    provided with the Original Code and Modifications, and is also
15 *    available at www.sybase.com/developer/opensource.
16 *
17 *    The Original Code and all software distributed under the License are
18 *    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
19 *    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
20 *    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
21 *    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
22 *    NON-INFRINGEMENT. Please see the License for the specific language
23 *    governing rights and limitations under the License.
24 *
25 *  ========================================================================
26 *
27 * Description:  Memory tracker - included only if TRMEM was set.
28 *
29 ****************************************************************************/
30 
31 
32 #include <stdarg.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <ctype.h>
37 
38 #if defined( _M_IX86 ) && defined(__WATCOMC__)
39 #include <i86.h>
40 #endif
41 
42 #include "trmem.h"
43 
44 typedef unsigned long   uint_32;
45 typedef unsigned        uint;
46 
47 #define MEMSET(p,c,l)   memset(p,c,l)
48 
49 /*
50     _PtrCmp( a, op, b ) compares two pointer as in ( a ) op ( b )
51 */
52 #if defined( M_I86CM ) || defined( M_I86LM ) || defined( M_I86HM )
53     #define _PtrAdd( p, i ) ((void *)((char __huge *)(p) + i))
54     #define _PtrSub( p, i ) ((void *)((char __huge *)(p) - i))
55     #define _PtrCmp(a,op,b) ((void __huge *)(a) op (void __huge *)(b))
56 #else
57     #define _PtrAdd( p, i ) ((void *)((char *)(p) + i))
58     #define _PtrSub( p, i ) ((void *)((char *)(p) - i))
59     #define _PtrCmp(a,op,b) ((void *)(a) op (void *)(b))
60 #endif
61 
62 
63 #define msg(a,b)     static const char MSG_##a[]=b
64 
65 msg(OUT_OF_MEMORY,      "Tracker out of memory" );
66 msg(CHUNK_BYTE_UNFREED, "%U chunks (%L bytes) unfreed" );
67 msg(SIZE_ZERO,          "%W size zero" );
68 msg(OVERRUN_ALLOCATION, "%W %D overrun allocation by %C of %U bytes" );
69 //msg(UNDERRUN_ALLOCATION,"%W %D underrun allocation by %C of %U bytes" );
70 msg(UNOWNED_CHUNK,      "%W unowned chunk %D" );
71 msg(NULL_PTR,           "%W NULL pointer" );
72 msg(NO_ROUTINE,         "Tracker was not given a %S routine!" );
73 msg(NOT_IN_ALLOCATION,  "%W %D not in any allocation" );
74 msg(OVERRUN_2,          "%W %D+%U overruns allocation %D+%U" );
75 msg(PRT_USAGE,          "Current usage: %L bytes; Peak usage: %L bytes" );
76 msg(MIN_ALLOC,          "%W allocation of %U less than minimum size" );
77 #if defined( M_I86LM ) || defined( M_I86HM )
78     msg(PRT_LIST_1,     "   Who      Addr    Size   Call   Contents" );
79     msg(PRT_LIST_2,     "========= ========= ==== ======== ===========================================" );
80 #else
81     msg(PRT_LIST_1,     "  Who      Addr     Size     Call     Contents" );
82     msg(PRT_LIST_2,     "======== ======== ======== ======== ===========================================" );
83 #endif
84 msg(PRT_LIST_3,         "%C %D %U %L %X" );
85 
86 #undef msg
87 
88 #define ALLOC_BYTE      0xA5
89 #define FREED_BYTE      0xBD
90 
91 /*
92    SIZE_DELTA is the maximum allowed difference between the requested size
93               for allocation and what was actually allocated.
94               It has been selected based on the assumption that the worst
95               case delta is a request of 1 byte that gets allocated as
96               64 bytes.  We can't cut it too close because skip list
97               allocators often have extreme minimum sizes.
98 */
99 #define SIZE_DELTA      64
100 
101 typedef struct Entry entry, *entry_ptr, **entry_ptr_ptr;
102 struct Entry {
103     entry_ptr       next;
104     void            *mem;
105     _trmem_who      who;
106     size_t          size;       // real size = tr ^ mem ^ who ^ size
107     uint_32         when;
108 };
109 
110 struct _trmem_internal {
111     entry_ptr   alloc_list;
112     uint_32     mem_used;
113     uint_32     max_mem;
114     uint_32     alloc_no;
115     void *      (*alloc)( size_t );
116     void        (*free)( void * );
117     void *      (*realloc)( void *, size_t );
118     void *      (*expand)( void *, size_t );
119     FILE *      prt_parm;
120     void        (*prt_line)( FILE *, const char *, size_t );
121     uint        flags;
122     size_t      min_alloc;
123 };
124 
125 static int isValidChunk( entry_ptr, const char *, _trmem_who, _trmem_hdl );
126 
127 #ifdef __WATCOMC__
128 #pragma warning 579 9;  // shut up pointer truncated warning
129 #endif
setSize(entry_ptr p,size_t size)130 static void setSize( entry_ptr p, size_t size )
131 {
132     p->size = size ^ (size_t)p->mem ^ (size_t)p->who ^ (size_t)p;
133 }
134 
getSize(entry_ptr p)135 static size_t getSize( entry_ptr p )
136 {
137     return( p->size ^ (size_t)p->mem ^ (size_t)p->who ^ (size_t)p );
138 }
139 
140 #ifdef __WATCOMC__
141 #pragma warning 579 4;  // reenable pointer truncated warning.
142 #endif
143 
stpcpy(char * dest,const char * src)144 static char *stpcpy( char *dest, const char *src )
145 {
146     *dest = *src;
147     while( *dest ) {
148         ++dest;
149         ++src;
150         *dest = *src;
151     }
152     return( dest );
153 }
154 
formHex(char * ptr,uint_32 data,uint size)155 static char *formHex( char *ptr, uint_32 data, uint size )
156 {
157     char            *str;
158 
159     size *= 2;
160     ptr += size;
161     str = ptr;
162     for( ; size > 0; size-- ) {
163         *--str = "0123456789abcdef"[data & 0x0f];
164         data >>= 4;
165     }
166     return( ptr );
167 }
168 
169 #if defined(M_I86LM) || defined(M_I86HM) || defined(M_I86MM) || defined(M_I86CM)
formFarPtr(char * ptr,void far * data)170 static char * formFarPtr( char *ptr, void far *data )
171 /***************************************************/
172 {
173     ptr = formHex( ptr, FP_SEG(data), 2 );
174     *ptr = ':';
175     ptr++;
176 #pragma warning 579 9;  // shut up pointer truncated warning for FP_OFF
177     return formHex( ptr, FP_OFF(data), sizeof( void near * ) );
178 #pragma warning 579 4;  // reenable pointer truncated warning
179 }
180 #endif
181 
formCodePtr(_trmem_hdl hdl,char * ptr,_trmem_who who)182 static char * formCodePtr( _trmem_hdl hdl, char *ptr, _trmem_who who )
183 {
184 #if defined( M_I86LM ) || defined( M_I86HM ) || defined( M_I86MM )
185     return formFarPtr( ptr, who );
186 #else
187     return formHex( ptr, (uint_32) who, sizeof(who) );
188 #endif
189 }
190 
trPrt(_trmem_hdl hdl,const char * fmt,...)191 static void trPrt( _trmem_hdl hdl, const char *fmt, ... )
192 {
193     va_list     args;
194     char        buff[100];
195     char *      ptr;
196     char        ch;
197     uint        ui;
198     uint_32     ul;
199     void        *dp;
200     _trmem_who  who;
201     char *      start;
202     char *      xptr;
203     int         i;
204     size_t      size;
205 
206     va_start( args, fmt );
207     ptr = buff;
208     for(;;) {
209         ch = *fmt++;
210         if( ch == '\0' ) break;
211         if( ch == '%' ) {
212             ch = *fmt++;
213             switch( ch ) {
214             case 'W':   /* "a1(a2):" */
215                 ptr = stpcpy( ptr, va_arg( args, const char * ) );
216                 who = va_arg( args, _trmem_who );
217                 if( who != _TRMEM_NO_ROUTINE ) {
218                     *ptr++ = '(';
219                     ptr = formHex( ptr, (uint_32)who, sizeof( who ) );
220                     *ptr++ = ')';
221                 }
222                 *ptr++ = ':';
223                 break;
224             case 'C':   /* code pointer */
225                 who = va_arg( args, _trmem_who );
226                 ptr = formCodePtr( hdl, ptr, who );
227                 break;
228             case 'D':   /* data pointer */
229                 dp = va_arg( args, void * );
230 #if defined( M_I86LM ) || defined( M_I86HM ) || defined( M_I86CM )
231                 ptr = formFarPtr( ptr, dp );
232 #else
233                 ptr = formHex( ptr, (uint_32)dp, sizeof( dp ) );
234 #endif
235                 break;
236             case 'S':   /* char * (string) pointer */
237                 ptr = stpcpy( ptr, va_arg( args, char * ) );
238                 break;
239             case 'U':   /* unsigned integer */
240                 ui = va_arg( args, uint );
241                 ptr = formHex( ptr, (uint_32)ui, sizeof( ui ) );
242                 break;
243             case 'L':   /* unsigned long */
244                 ul = va_arg( args, uint_32 );
245                 ptr = formHex( ptr, (uint_32)ul, sizeof( ul ) );
246                 break;
247             case 'X':   /* 14 bytes of hex data */
248                 start = va_arg( args, char* );
249                 size = va_arg( args, size_t );
250                 if( size > 14 ) size = 14;
251                 xptr = start;
252                 for( i=0; i<14; i++ ) {
253                     if( i < size ) {
254                         ptr = formHex( ptr, *xptr, sizeof( char ) );
255                         xptr++;
256                     } else {    // no more to print, so make things line up.
257                         *ptr = ' ';
258                         *(ptr + 1) = ' ';
259                         ptr += 2;
260                     }
261                     if( i == 7 ) {
262                         *ptr = ' ';
263                         ptr++;
264                     }
265                 }
266                 for( i=0; i < size; i++ ) {
267                     if( isprint( *start ) ) {
268                         *ptr = *start;
269                     } else {
270                         *ptr = '.';
271                     }
272                     ptr++;
273                     start++;
274                 }
275                 break;
276             default:
277                 *ptr++ = ch;
278                 break;
279             }
280         } else {
281            *ptr++ = ch;
282         }
283     }
284     va_end( args );
285     *ptr++ = '\n';
286     *ptr = '\0';
287     hdl->prt_line( hdl->prt_parm, buff, ptr - buff );
288 }
289 
allocEntry(_trmem_hdl hdl)290 static entry_ptr allocEntry( _trmem_hdl hdl )
291 {
292     entry_ptr   tr;
293 
294     tr = (entry_ptr) hdl->alloc( sizeof( entry ) );
295     if( tr == NULL && ( hdl->flags & _TRMEM_OUT_OF_MEMORY ) ) {
296         trPrt( hdl, MSG_OUT_OF_MEMORY );
297     }
298     return( tr );
299 }
300 
freeEntry(entry_ptr tr,_trmem_hdl hdl)301 static void freeEntry( entry_ptr tr, _trmem_hdl hdl )
302 {
303     hdl->free( tr );
304 }
305 
addToList(entry_ptr tr,_trmem_hdl hdl)306 static void addToList( entry_ptr tr, _trmem_hdl hdl )
307 {
308     tr->next = hdl->alloc_list;
309     hdl->alloc_list = tr;
310 }
311 
findOnList(void * mem,_trmem_hdl hdl)312 static entry_ptr findOnList( void *mem, _trmem_hdl hdl )
313 {
314     entry_ptr       walk;
315 
316     walk = hdl->alloc_list;
317     while( walk ) {
318         if( _PtrCmp( walk->mem, ==, mem ) ) {
319             return( walk );
320         }
321         walk = walk->next;
322     }
323     return( NULL );
324 }
325 
removeFromList(void * mem,_trmem_hdl hdl)326 static entry_ptr removeFromList( void *mem, _trmem_hdl hdl )
327 /**********************************************************/
328 {
329     entry_ptr_ptr   walk;
330     entry_ptr       found;
331 
332     walk = &hdl->alloc_list;
333     while( *walk ) {
334         //printf("removeFromList: item=%p, next=%p, mem=%p\n", *walk, (*walk)->next, (*walk)->mem );
335         if( _PtrCmp( (*walk)->mem, ==, mem ) ) {
336             found = *walk;
337             *walk = found->next;
338             return( found );
339         }
340         walk = &(*walk)->next;
341     }
342     return( NULL );
343 }
344 
_trmem_open(void * (* alloc)(size_t),void (* free)(void *),void * (* realloc)(void *,size_t),void * (* expand)(void *,size_t),FILE * prt_parm,void (* prt_line)(FILE *,const char *,size_t),unsigned flags)345 _trmem_hdl _trmem_open(
346     void *( *alloc )( size_t ),
347     void ( *free )( void * ),
348     void *( *realloc )( void *, size_t ),
349     void *( *expand )( void *, size_t ),
350     FILE  *prt_parm,
351     void ( *prt_line )( FILE *, const char *, size_t ),
352     unsigned flags )
353 /*****************************************************/
354 {
355     _trmem_hdl  hdl;
356 
357     hdl = (_trmem_hdl) alloc( sizeof( struct _trmem_internal ) );
358     if( hdl == NULL ) {
359         return( NULL );
360     }
361     hdl->alloc          = alloc;
362     hdl->free           = free;
363     hdl->realloc        = realloc;
364     hdl->expand         = expand;
365     hdl->prt_parm       = prt_parm;
366     hdl->prt_line       = prt_line;
367     hdl->flags          = flags;
368     hdl->alloc_list     = NULL;
369     hdl->mem_used       = 0;
370     hdl->max_mem        = 0;
371     hdl->min_alloc      = 0;
372     hdl->alloc_no       = 0;
373     return( hdl );
374 }
375 
_trmem_validate_all(_trmem_hdl hdl)376 int _trmem_validate_all( _trmem_hdl hdl )
377 /****************************************/
378 {
379     entry_ptr   walk;
380     int result = 1;
381 
382     walk = hdl->alloc_list;
383     while( walk ) {
384         //printf("trmem_validate_all: item=%p, next=%p, mem=%p\n", walk, walk->next, walk->mem );
385         if( !isValidChunk( walk, "Validate", 0, hdl ) ) {
386             result = 0;
387         }
388         walk = walk->next;
389     }
390     return result;
391 }
392 
_trmem_close(_trmem_hdl hdl)393 unsigned _trmem_close( _trmem_hdl hdl )
394 /*************************************/
395 {
396     uint        chunks;
397     uint_32     mem_used;
398     entry_ptr   walk;
399     entry_ptr   next;
400 
401     chunks = 0;
402     if( hdl->flags & _TRMEM_CLOSE_CHECK_FREE ) {
403         mem_used = hdl->mem_used;
404         walk = hdl->alloc_list;
405         while( walk ) {
406             //printf("trmem_close: item=%p, next=%p, mem=%p\n", walk, walk->next, walk->mem );
407             next = walk->next;
408             ++chunks;
409             _trmem_free( walk->mem, _TRMEM_NO_ROUTINE, hdl );
410             walk = next;
411         }
412         if( chunks ) {
413             trPrt( hdl, MSG_CHUNK_BYTE_UNFREED, chunks, mem_used );
414         }
415     } else {
416         walk = hdl->alloc_list;
417         while( walk ) {
418             next = walk->next;
419             ++chunks;
420             freeEntry( walk, hdl );
421             walk = next;
422         }
423     }
424     hdl->free( hdl );
425     return( chunks );
426 }
427 
_trmem_set_min_alloc(size_t size,_trmem_hdl hdl)428 void _trmem_set_min_alloc( size_t size, _trmem_hdl hdl )
429 /******************************************************/
430 {
431     hdl->min_alloc = size;
432 }
433 
_trmem_alloc(size_t size,_trmem_who who,_trmem_hdl hdl)434 void *_trmem_alloc( size_t size, _trmem_who who, _trmem_hdl hdl )
435 /***************************************************************/
436 {
437     void        *mem;
438     entry_ptr   tr;
439 
440     hdl->alloc_no += 1;
441     if( size == 0 && ( hdl->flags & _TRMEM_ALLOC_SIZE_0 ) ) {
442         trPrt( hdl, MSG_SIZE_ZERO, "Alloc", who );
443         return ( NULL );
444     } else if( size < hdl->min_alloc ) {
445         trPrt( hdl, MSG_MIN_ALLOC, "Alloc", who, size );
446     }
447     mem = hdl->alloc( size + 1 );
448     if( mem != NULL ) {
449         MEMSET( mem, ALLOC_BYTE, size + 1 );
450         tr = allocEntry( hdl );
451         if( tr != NULL ) {
452             tr->mem = mem;
453             tr->who = who;
454             tr->when = hdl->alloc_no;
455             setSize( tr, size );
456             addToList( tr, hdl );
457         }
458         hdl->mem_used += size;
459         if( hdl->mem_used > hdl->max_mem ) {
460             hdl->max_mem = hdl->mem_used;
461         }
462     }
463     return( mem );
464 }
465 
isValidChunk(entry_ptr tr,const char * rtn,_trmem_who who,_trmem_hdl hdl)466 static int isValidChunk( entry_ptr tr, const char *rtn,
467     _trmem_who who, _trmem_hdl hdl )
468 {
469     void *mem;
470     size_t size;
471     size_t blk_size;
472 
473     size = getSize( tr );
474     mem = tr->mem;
475     blk_size = *(size_t*)_PtrSub( mem, sizeof( size_t ) );
476 #ifndef __NETWARE__
477 #if 0
478     if(( blk_size & 1 ) == 0 ) {
479         trPrt( hdl, MSG_UNDERRUN_ALLOCATION, rtn, who, mem, tr->who, size );
480         return( 0 );
481     }
482     blk_size &= ~1;
483     if( size > blk_size || ( blk_size - size ) > SIZE_DELTA ) {
484         trPrt( hdl, MSG_UNDERRUN_ALLOCATION, rtn, who, mem, tr->who, size );
485         return( 0 );
486     }
487 #endif
488 #endif
489     if( *(unsigned char *)_PtrAdd( mem, size ) != ALLOC_BYTE ) {
490         trPrt( hdl, MSG_OVERRUN_ALLOCATION, rtn, who, mem, tr->who, size );
491         return( 0 );
492     }
493     return( 1 );
494 }
495 
_trmem_validate(void * mem,_trmem_who who,_trmem_hdl hdl)496 int _trmem_validate( void *mem, _trmem_who who, _trmem_hdl hdl )
497 /**************************************************************/
498 {
499     entry_ptr tr;
500 
501     tr = findOnList( mem, hdl );
502     if( tr == NULL ) {
503         trPrt( hdl, MSG_UNOWNED_CHUNK, "Validate", who, mem );
504         return( 0 );
505     }
506     return( isValidChunk( tr, "Validate", who, hdl ) );
507 }
508 
_trmem_free(void * mem,_trmem_who who,_trmem_hdl hdl)509 void _trmem_free( void *mem, _trmem_who who, _trmem_hdl hdl )
510 /***********************************************************/
511 {
512     entry_ptr   tr;
513     size_t      size;
514 
515     if( mem == NULL ) {
516         if( hdl->flags & _TRMEM_FREE_NULL ) {
517             trPrt( hdl, MSG_NULL_PTR, "Free", who );
518         }
519         hdl->free( mem );
520         return;
521     }
522     //printf("trmem_free: item=%p\n", mem );
523     tr = removeFromList( mem, hdl );
524     if( tr == NULL ) {
525         trPrt( hdl, MSG_UNOWNED_CHUNK, "Free", who, mem );
526         return;
527     }
528     isValidChunk( tr, "Free", who, hdl );
529     size = getSize( tr );
530     hdl->mem_used -= size;
531     MEMSET( mem, FREED_BYTE, size + 1 );
532     freeEntry( tr, hdl );
533     hdl->free( mem );
534 }
535 
ChangeAlloc(void * old,size_t size,_trmem_who who,_trmem_hdl hdl,void * (* fn)(void *,size_t),char * name)536 static void * ChangeAlloc( void *old, size_t size, _trmem_who who,
537                            _trmem_hdl hdl, void * (*fn)(void *,size_t),
538                            char * name )
539 /*********************************************************************/
540 {
541     entry_ptr   tr;
542     void *      new_block;
543     size_t      old_size;
544 
545     if( fn == (void *) _TRMEM_NO_ROUTINE ) {
546         trPrt( hdl, MSG_NO_ROUTINE, name );
547         return( NULL );
548     }
549 
550     if( size == 0 ) {
551         if( hdl->flags & _TRMEM_REALLOC_SIZE_0 ) {
552             trPrt( hdl, MSG_SIZE_ZERO, name, who );
553         }
554         if( old == NULL ) {
555             if( hdl->flags & _TRMEM_REALLOC_NULL ) {
556                 trPrt( hdl, MSG_NULL_PTR, name, who );
557             }
558             return( fn( NULL, 0 ) );
559         }
560 
561         /* old != NULL */
562         tr = removeFromList( old, hdl );
563         if( tr == NULL ) {
564             trPrt( hdl, MSG_UNOWNED_CHUNK, name, who, old );
565             return( NULL );
566         }
567         isValidChunk( tr, name, who, hdl );
568         size = getSize( tr );
569         hdl->mem_used -= size;
570         MEMSET( old, FREED_BYTE, size + 1 );
571         freeEntry( tr, hdl );
572         return( fn( old, 0 ) );
573     }
574 
575     /* size != 0 */
576     if( old == NULL ) {
577         if( hdl->flags & _TRMEM_REALLOC_NULL ) {
578             trPrt( hdl, MSG_NULL_PTR, name, who );
579         }
580         new_block = fn( NULL, size + 1 );
581         if( new_block != NULL ) {
582             MEMSET( new_block, ALLOC_BYTE, size + 1 );
583             tr = allocEntry( hdl );
584             if( tr != NULL ) {
585                 tr->mem = new_block;
586                 tr->who = who;
587                 setSize( tr, size );
588                 addToList( tr, hdl );
589             }
590             hdl->mem_used += size;
591             if( hdl->mem_used > hdl->max_mem ) {
592                 hdl->max_mem = hdl->mem_used;
593             }
594         }
595         return( new_block );
596     }
597 
598     /* old != NULL && size != 0 */
599     tr = removeFromList( old, hdl );
600     if( tr == NULL ) {
601         trPrt( hdl, MSG_UNOWNED_CHUNK, name, who, old );
602         return( NULL );
603     }
604     if( !isValidChunk( tr, name, who, hdl ) ) {
605         return( NULL );
606     }
607     new_block = fn( old, size + 1 );
608     if( new_block == NULL ) {
609         addToList( tr, hdl );   /* put back on list without change */
610         return( new_block );
611     }
612     old_size = getSize( tr );
613     if( size > old_size ) {
614         MEMSET(_PtrAdd( new_block, old_size ), ALLOC_BYTE, size + 1 - old_size);
615     } else {
616         *(unsigned char *)_PtrAdd( new_block, size ) = ALLOC_BYTE;
617     }
618     hdl->mem_used -= old_size;
619     hdl->mem_used += size;
620     if( hdl->mem_used > hdl->max_mem ) {
621         hdl->max_mem = hdl->mem_used;
622     }
623     tr->mem = new_block;
624     tr->who = who;
625     setSize( tr, size );
626     addToList( tr, hdl );
627     return( new_block );
628 }
629 
_trmem_realloc(void * old,size_t size,_trmem_who who,_trmem_hdl hdl)630 void *_trmem_realloc( void *old, size_t size, _trmem_who who, _trmem_hdl hdl )
631 /****************************************************************************/
632 {
633     return( ChangeAlloc( old, size, who, hdl, hdl->realloc, "Realloc" ) );
634 }
635 
_trmem_expand(void * old,size_t size,_trmem_who who,_trmem_hdl hdl)636 void *_trmem_expand( void *old, size_t size, _trmem_who who, _trmem_hdl hdl )
637 /***************************************************************************/
638 {
639     return( ChangeAlloc( old, size, who, hdl, hdl->expand, "Expand" ) );
640 }
641 
_trmem_strdup(const char * str,_trmem_who who,_trmem_hdl hdl)642 char *_trmem_strdup( const char *str, _trmem_who who, _trmem_hdl hdl )
643 /********************************************************************/
644 {
645     char    *mem;
646     size_t  len;
647 
648     len = strlen( str ) + 1;
649     mem = _trmem_alloc( len, who, hdl );
650     if( mem )
651         memcpy( mem, str, len );
652     return( mem );
653 }
654 
_trmem_chk_range(void * start,size_t len,_trmem_who who,_trmem_hdl hdl)655 int _trmem_chk_range( void *start, size_t len,
656                 _trmem_who who, _trmem_hdl hdl )
657 /**********************************************/
658 {
659     entry_ptr   tr;
660     void        *end;
661     void        *end_of_mem;
662 
663     tr = hdl->alloc_list;
664     for(;;) {
665         if( tr == 0 ) {
666             trPrt( hdl, MSG_NOT_IN_ALLOCATION, "ChkRange", who,
667                 start );
668             return( 0 );
669         }
670         end_of_mem = _PtrAdd( tr->mem, getSize( tr ) );
671         if( _PtrCmp( start, >=, tr->mem ) &&
672             _PtrCmp( start, < , end_of_mem ) ) break;
673         tr = tr->next;
674     }
675     end = _PtrAdd( start, len );
676     if( _PtrCmp( end, >, end_of_mem ) ) {
677         trPrt( hdl, MSG_OVERRUN_2, "ChkRange", who,
678             start, len, tr->mem, getSize( tr ) );
679         return( 0 );
680     }
681     return( isValidChunk( tr, "ChkRange", who, hdl ) );
682 }
683 
_trmem_prt_usage(_trmem_hdl hdl)684 void _trmem_prt_usage( _trmem_hdl hdl )
685 /*************************************/
686 {
687     trPrt( hdl, MSG_PRT_USAGE, hdl->mem_used, hdl->max_mem );
688 }
689 
_trmem_prt_list(_trmem_hdl hdl)690 unsigned _trmem_prt_list( _trmem_hdl hdl )
691 /****************************************/
692 {
693     entry_ptr   tr;
694     unsigned    chunks;
695     size_t      size;
696 
697     tr = hdl->alloc_list;
698     if( tr == 0 ) return( 0 );
699     _trmem_prt_usage( hdl );
700     trPrt( hdl, MSG_PRT_LIST_1 );
701     trPrt( hdl, MSG_PRT_LIST_2 );
702     chunks = 0;
703     do {
704         size = getSize( tr );
705         if( chunks < 20 ) {
706             trPrt( hdl
707                  , MSG_PRT_LIST_3
708                  , tr->who
709                  , tr->mem
710                  , size
711                  , tr->when
712                  , tr->mem
713                  , size );
714         }
715         ++chunks;
716         tr = tr->next;
717     } while( tr );
718     return( chunks );
719 }
720 
_trmem_msize(void * mem,_trmem_hdl hdl)721 size_t _trmem_msize( void *mem, _trmem_hdl hdl ) {
722 /************************************************/
723     return( getSize( findOnList( mem, hdl ) ) );
724 }
725 
_trmem_get_current_usage(_trmem_hdl hdl)726 unsigned long _trmem_get_current_usage( _trmem_hdl hdl ) {
727 /********************************************************/
728     return hdl->mem_used;
729 }
730 
_trmem_get_peak_usage(_trmem_hdl hdl)731 unsigned long _trmem_get_peak_usage( _trmem_hdl hdl ) {
732 /*****************************************************/
733     return hdl->max_mem;
734 }
735 
736 #ifndef __WATCOMC__
_trmem_guess_who(void * p)737 _trmem_who  _trmem_guess_who( void *p )
738 /*************************************/
739 {
740     return( (_trmem_who)*((void **)p-1) );
741 }
742 #endif
743 
744 #if !defined(_M_IX86) || !defined(__WATCOMC__)
_trmem_whoami(void)745 _trmem_who  _trmem_whoami( void )
746 /*******************************/
747 /* NYI: stubbed for now */
748 {
749     return 0;
750 }
751 #endif
752 
753 /*
754  * if TRMEM is defined, trmem functions are used which will help tracking
755  * memory usage.
756  */
757 
758 _trmem_hdl  hTrmem;
759 FILE        *FileTrmem;  /* file handle we'll write() to */
760 
761 #define TRMEM_LOGFN "~jwasm.trk"
762 
memLine(FILE * fh,const char * buf,unsigned size)763 static void memLine( FILE *fh, const char *buf, unsigned size )
764 /*************************************************************/
765 {
766     //fwrite( "***",1, 3, stderr );
767     //fwrite( buf, 1, size, stderr );
768     fwrite( buf, 1, size, fh );
769 }
770 
tm_Init(void)771 void tm_Init( void )
772 /******************/
773 {
774     if ( FileTrmem = fopen( TRMEM_LOGFN, "w" ) ) {
775         //hTrmem = _trmem_open( malloc, free, realloc, _expand, memFile, memLine,
776         hTrmem = _trmem_open( malloc, free, _TRMEM_NO_REALLOC, _TRMEM_NO_REALLOC, FileTrmem, memLine,
777                   _TRMEM_ALLOC_SIZE_0 | _TRMEM_FREE_NULL | _TRMEM_OUT_OF_MEMORY | _TRMEM_CLOSE_CHECK_FREE );
778         if( hTrmem == NULL ) {
779             printf("tm_Init: _trmem_open() failed\n" );
780             exit( EXIT_FAILURE );
781         }
782     } else {
783         printf("tm_Init: fopen(\"" TRMEM_LOGFN "\") failed [%u]\n", errno );
784         exit( EXIT_FAILURE );
785     }
786 }
787 
tm_Fini(void)788 void tm_Fini( void )
789 /******************/
790 {
791     /* if tm_Fini() is called, both hTrmem & memFile are != NULL */
792     _trmem_prt_list( hTrmem );
793     _trmem_close( hTrmem );
794     fclose( FileTrmem );
795 }
796 
797