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