1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1985-2012 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Eclipse Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.eclipse.org/org/documents/epl-v10.html *
11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * Glenn Fowler <gsf@research.att.com> *
18 * David Korn <dgk@research.att.com> *
19 * Phong Vo <kpv@research.att.com> *
20 * *
21 ***********************************************************************/
22 #if defined(_UWIN) && defined(_BLD_ast)
23
_STUB_vmdebug()24 void _STUB_vmdebug(){}
25
26 #else
27
28 #include "vmhdr.h"
29
30 /* Method to help with debugging. This does rigorous checks on
31 ** addresses and arena integrity.
32 **
33 ** Written by Kiem-Phong Vo, kpv@research.att.com, 01/16/94.
34 */
35
36 /* structure to keep track of file names */
37 typedef struct _dbfile_s Dbfile_t;
38 struct _dbfile_s
39 { Dbfile_t* next;
40 char file[1];
41 };
42 static Dbfile_t* Dbfile;
43
44 /* global watch list */
45 #define S_WATCH 32
46 static int Dbnwatch;
47 static Void_t* Dbwatch[S_WATCH];
48
49 /* types of warnings reported by dbwarn() */
50 #define DB_CHECK 0
51 #define DB_ALLOC 1
52 #define DB_FREE 2
53 #define DB_RESIZE 3
54 #define DB_WATCH 4
55 #define DB_RESIZED 5
56
57 static int Dbinit = 0;
58 #define DBINIT() (Dbinit ? 0 : (dbinit(), Dbinit=1) )
dbinit()59 static void dbinit()
60 { int fd;
61 if((fd = vmtrace(-1)) >= 0)
62 vmtrace(fd);
63 }
64
65 static int Dbfd = 2; /* default warning file descriptor */
66 #if __STD_C
vmdebug(int fd)67 int vmdebug(int fd)
68 #else
69 int vmdebug(fd)
70 int fd;
71 #endif
72 {
73 int old = Dbfd;
74 Dbfd = fd;
75 return old;
76 }
77
78
79 /* just an entry point to make it easy to set break point */
80 #if __STD_C
vmdbwarn(Vmalloc_t * vm,char * mesg,int n)81 static void vmdbwarn(Vmalloc_t* vm, char* mesg, int n)
82 #else
83 static void vmdbwarn(vm, mesg, n)
84 Vmalloc_t* vm;
85 char* mesg;
86 int n;
87 #endif
88 {
89 reg Vmdata_t* vd = vm->data;
90
91 write(Dbfd,mesg,n);
92 if(vd->mode&VM_DBABORT)
93 abort();
94 }
95
96 /* issue a warning of some type */
97 #if __STD_C
dbwarn(Vmalloc_t * vm,Void_t * data,int where,char * file,int line,Void_t * func,int type)98 static void dbwarn(Vmalloc_t* vm, Void_t* data, int where,
99 char* file, int line, Void_t* func, int type)
100 #else
101 static void dbwarn(vm, data, where, file, line, func, type)
102 Vmalloc_t* vm; /* region holding the block */
103 Void_t* data; /* data block */
104 int where; /* byte that was corrupted */
105 char* file; /* file where call originates */
106 int line; /* line number of call */
107 Void_t* func; /* function called from */
108 int type; /* operation being done */
109 #endif
110 {
111 char buf[1024], *bufp, *endbuf, *s;
112 #define SLOP 64 /* enough for a message and an int */
113
114 DBINIT();
115
116 bufp = buf;
117 endbuf = buf + sizeof(buf);
118
119 if(type == DB_ALLOC)
120 bufp = (*_Vmstrcpy)(bufp, "alloc error", ':');
121 else if(type == DB_FREE)
122 bufp = (*_Vmstrcpy)(bufp, "free error", ':');
123 else if(type == DB_RESIZE)
124 bufp = (*_Vmstrcpy)(bufp, "resize error", ':');
125 else if(type == DB_CHECK)
126 bufp = (*_Vmstrcpy)(bufp, "corrupted data", ':');
127 else if(type == DB_WATCH)
128 bufp = (*_Vmstrcpy)(bufp, "alert", ':');
129
130 /* region info */
131 bufp = (*_Vmstrcpy)(bufp, "region", '=');
132 bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(VLONG(vm), 0), ':');
133
134 if(data)
135 { bufp = (*_Vmstrcpy)(bufp,"block",'=');
136 bufp = (*_Vmstrcpy)(bufp,(*_Vmitoa)(VLONG(data),0),':');
137 }
138
139 if(!data)
140 { if(where == DB_ALLOC)
141 bufp = (*_Vmstrcpy)(bufp, "can't get memory", ':');
142 else bufp = (*_Vmstrcpy)(bufp, "region is locked", ':');
143 }
144 else if(type == DB_FREE || type == DB_RESIZE)
145 { if(where == 0)
146 bufp = (*_Vmstrcpy)(bufp, "unallocated block", ':');
147 else bufp = (*_Vmstrcpy)(bufp, "already freed", ':');
148 }
149 else if(type == DB_WATCH)
150 { bufp = (*_Vmstrcpy)(bufp, "size", '=');
151 bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)((Vmulong_t)DBSIZE(data),-1), ':');
152 if(where == DB_ALLOC)
153 bufp = (*_Vmstrcpy)(bufp,"just allocated", ':');
154 else if(where == DB_FREE)
155 bufp = (*_Vmstrcpy)(bufp,"being freed", ':');
156 else if(where == DB_RESIZE)
157 bufp = (*_Vmstrcpy)(bufp,"being resized", ':');
158 else if(where == DB_RESIZED)
159 bufp = (*_Vmstrcpy)(bufp,"just resized", ':');
160 }
161 else if(type == DB_CHECK)
162 { bufp = (*_Vmstrcpy)(bufp, "bad byte at", '=');
163 bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(VLONG(where),-1), ':');
164 if((s = DBFILE(data)) && (bufp + strlen(s) + SLOP) < endbuf)
165 { bufp = (*_Vmstrcpy)(bufp,"allocated at", '=');
166 bufp = (*_Vmstrcpy)(bufp, s, ',');
167 bufp = (*_Vmstrcpy)(bufp,(*_Vmitoa)(VLONG(DBLINE(data)),-1),':');
168 }
169 }
170
171 /* location where offending call originates from */
172 if(file && file[0] && line > 0 && (bufp + strlen(file) + SLOP) < endbuf)
173 { bufp = (*_Vmstrcpy)(bufp, "detected at", '=');
174 bufp = (*_Vmstrcpy)(bufp, file, ',');
175 bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(VLONG(line),-1), ',');
176 bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(VLONG(func),-1), ':');
177 }
178
179 *bufp++ = '\n';
180 *bufp = '\0';
181
182 vmdbwarn(vm,buf,(int)(bufp-buf));
183 }
184
185 /* check for watched address and issue warnings */
186 #if __STD_C
dbwatch(Vmalloc_t * vm,Void_t * data,char * file,int line,Void_t * func,int type)187 static void dbwatch(Vmalloc_t* vm, Void_t* data,
188 char* file, int line, Void_t* func, int type)
189 #else
190 static void dbwatch(vm, data, file, line, func, type)
191 Vmalloc_t* vm;
192 Void_t* data;
193 char* file;
194 int line;
195 Void_t* func;
196 int type;
197 #endif
198 {
199 reg int n;
200
201 for(n = Dbnwatch; n >= 0; --n)
202 { if(Dbwatch[n] == data)
203 { dbwarn(vm,data,type,file,line,func,DB_WATCH);
204 return;
205 }
206 }
207 }
208
209 /* record information about the block */
210 #if __STD_C
dbsetinfo(Vmuchar_t * data,size_t size,char * file,int line)211 static void dbsetinfo(Vmuchar_t* data, size_t size, char* file, int line)
212 #else
213 static void dbsetinfo(data, size, file, line)
214 Vmuchar_t* data; /* real address not the one from Vmbest */
215 size_t size; /* the actual requested size */
216 char* file; /* file where the request came from */
217 int line; /* and line number */
218 #endif
219 {
220 reg Vmuchar_t *begp, *endp;
221 reg Dbfile_t *last, *db;
222
223 DBINIT();
224
225 /* find the file structure */
226 if(!file || !file[0])
227 db = NIL(Dbfile_t*);
228 else
229 { for(last = NIL(Dbfile_t*), db = Dbfile; db; last = db, db = db->next)
230 if(strcmp(db->file,file) == 0)
231 break;
232 if(!db)
233 { db = (Dbfile_t*)vmalloc(Vmheap,sizeof(Dbfile_t)+strlen(file));
234 if(db)
235 { (*_Vmstrcpy)(db->file,file,0);
236 db->next = Dbfile;
237 Dbfile = db;
238 }
239 }
240 else if(last) /* move-to-front heuristic */
241 { last->next = db->next;
242 db->next = Dbfile;
243 Dbfile = db;
244 }
245 }
246
247 DBSETFL(data,(db ? db->file : NIL(char*)),line);
248 DBSIZE(data) = size;
249 DBSEG(data) = SEG(DBBLOCK(data));
250
251 DBHEAD(data,begp,endp);
252 while(begp < endp)
253 *begp++ = DB_MAGIC;
254 DBTAIL(data,begp,endp);
255 while(begp < endp)
256 *begp++ = DB_MAGIC;
257 }
258
259 /* Check to see if an address is in some data block of a region.
260 ** This returns -(offset+1) if block is already freed, +(offset+1)
261 ** if block is live, 0 if no match.
262 */
263 #if __STD_C
dbaddr(Vmalloc_t * vm,Void_t * addr,int local)264 static long dbaddr(Vmalloc_t* vm, Void_t* addr, int local)
265 #else
266 static long dbaddr(vm, addr, local)
267 Vmalloc_t* vm;
268 Void_t* addr;
269 int local;
270 #endif
271 {
272 reg Block_t *b, *endb;
273 reg Seg_t *seg;
274 reg Vmuchar_t *data;
275 reg long offset = -1L;
276 reg Vmdata_t *vd = vm->data;
277
278 SETLOCK(vm, local);
279
280 b = endb = NIL(Block_t*);
281 for(seg = vd->seg; seg; seg = seg->next)
282 { b = SEGBLOCK(seg);
283 endb = (Block_t*)(seg->baddr - sizeof(Head_t));
284 if((Vmuchar_t*)addr > (Vmuchar_t*)b &&
285 (Vmuchar_t*)addr < (Vmuchar_t*)endb)
286 break;
287 }
288 if(!seg)
289 goto done;
290
291 if(local) /* must be vmfree or vmresize checking address */
292 { if(DBSEG(addr) == seg)
293 { b = DBBLOCK(addr);
294 if(ISBUSY(SIZE(b)) && !ISJUNK(SIZE(b)) )
295 offset = 0;
296 else offset = -2L;
297 }
298 goto done;
299 }
300
301 while(b < endb)
302 { data = (Vmuchar_t*)DATA(b);
303 if((Vmuchar_t*)addr >= data && (Vmuchar_t*)addr < data+SIZE(b))
304 { if(ISBUSY(SIZE(b)) && !ISJUNK(SIZE(b)) )
305 { data = DB2DEBUG(data);
306 if((Vmuchar_t*)addr >= data &&
307 (Vmuchar_t*)addr < data+DBSIZE(data))
308 offset = (long)((Vmuchar_t*)addr - data);
309 }
310 goto done;
311 }
312
313 b = (Block_t*)((Vmuchar_t*)DATA(b) + (SIZE(b)&~BITS) );
314 }
315
316 done:
317 CLRLOCK(vm, local);
318 return offset;
319 }
320
321
322 #if __STD_C
dbsize(Vmalloc_t * vm,Void_t * addr,int local)323 static long dbsize(Vmalloc_t* vm, Void_t* addr, int local)
324 #else
325 static long dbsize(vm, addr, local)
326 Vmalloc_t* vm;
327 Void_t* addr;
328 int local;
329 #endif
330 {
331 Block_t *b, *endb;
332 Seg_t *seg;
333 long size;
334 Vmdata_t *vd = vm->data;
335
336 SETLOCK(vm, local);
337
338 size = -1L;
339 for(seg = vd->seg; seg; seg = seg->next)
340 { b = SEGBLOCK(seg);
341 endb = (Block_t*)(seg->baddr - sizeof(Head_t));
342 if((Vmuchar_t*)addr <= (Vmuchar_t*)b ||
343 (Vmuchar_t*)addr >= (Vmuchar_t*)endb)
344 continue;
345 while(b < endb)
346 { if(addr == (Void_t*)DB2DEBUG(DATA(b)))
347 { if(ISBUSY(SIZE(b)) && !ISJUNK(SIZE(b)) )
348 size = (long)DBSIZE(addr);
349 goto done;
350 }
351
352 b = (Block_t*)((Vmuchar_t*)DATA(b) + (SIZE(b)&~BITS) );
353 }
354 }
355
356 done:
357 CLRLOCK(vm, local);
358 return size;
359 }
360
361 #if __STD_C
dballoc(Vmalloc_t * vm,size_t size,int local)362 static Void_t* dballoc(Vmalloc_t* vm, size_t size, int local)
363 #else
364 static Void_t* dballoc(vm, size, local)
365 Vmalloc_t* vm;
366 size_t size;
367 int local;
368 #endif
369 {
370 size_t s;
371 Vmuchar_t *data;
372 char *file;
373 int line;
374 Void_t *func;
375 Vmdata_t *vd = vm->data;
376 VMFLF(vm,file,line,func);
377
378 SETLOCK(vm, local);
379
380 if(vd->mode&VM_DBCHECK)
381 vmdbcheck(vm);
382
383 s = ROUND(size,ALIGN) + DB_EXTRA;
384 if(s < sizeof(Body_t)) /* no tiny blocks during Vmdebug */
385 s = sizeof(Body_t);
386
387 if(!(data = (Vmuchar_t*)KPVALLOC(vm,s,(*(Vmbest->allocf))) ) )
388 { dbwarn(vm,NIL(Vmuchar_t*),DB_ALLOC,file,line,func,DB_ALLOC);
389 goto done;
390 }
391
392 data = DB2DEBUG(data);
393 dbsetinfo(data,size,file,line);
394
395 if((vd->mode&VM_TRACE) && _Vmtrace)
396 { vm->file = file; vm->line = line; vm->func = func;
397 (*_Vmtrace)(vm,NIL(Vmuchar_t*),data,size,0);
398 }
399
400 if(Dbnwatch > 0 )
401 dbwatch(vm,data,file,line,func,DB_ALLOC);
402
403 done:
404 CLRLOCK(vm, local);
405
406 return (Void_t*)data;
407 }
408
409
410 #if __STD_C
dbfree(Vmalloc_t * vm,Void_t * data,int local)411 static int dbfree(Vmalloc_t* vm, Void_t* data, int local )
412 #else
413 static int dbfree(vm, data, local )
414 Vmalloc_t* vm;
415 Void_t* data;
416 int local;
417 #endif
418 {
419 char *file;
420 int line;
421 Void_t *func;
422 long offset;
423 int rv, *ip, *endip;
424 Vmdata_t *vd = vm->data;
425 VMFLF(vm,file,line,func);
426
427 if(!data)
428 return 0;
429
430 SETLOCK(vm, local);
431
432 if(vd->mode&VM_DBCHECK)
433 vmdbcheck(vm);
434
435 if((offset = KPVADDR(vm,data,dbaddr)) != 0)
436 { dbwarn(vm,(Vmuchar_t*)data,offset == -1L ? 0 : 1,file,line,func,DB_FREE);
437 rv = -1;
438 }
439 else
440 { if(Dbnwatch > 0)
441 dbwatch(vm,data,file,line,func,DB_FREE);
442
443 if((vd->mode&VM_TRACE) && _Vmtrace)
444 { vm->file = file; vm->line = line; vm->func = func;
445 (*_Vmtrace)(vm,(Vmuchar_t*)data,NIL(Vmuchar_t*),DBSIZE(data),0);
446 }
447
448 /* clear free space */
449 ip = (int*)data;
450 endip = ip + (DBSIZE(data)+sizeof(int)-1)/sizeof(int);
451 while(ip < endip)
452 *ip++ = 0;
453
454 rv = KPVFREE((vm), (Void_t*)DB2BEST(data), (*Vmbest->freef));
455 }
456
457 CLRLOCK(vm, local);
458 return rv;
459 }
460
461 /* Resizing an existing block */
462 #if __STD_C
dbresize(Vmalloc_t * vm,Void_t * addr,reg size_t size,int type,int local)463 static Void_t* dbresize(Vmalloc_t* vm, Void_t* addr, reg size_t size, int type, int local)
464 #else
465 static Void_t* dbresize(vm, addr, size, type, local)
466 Vmalloc_t* vm; /* region allocating from */
467 Void_t* addr; /* old block of data */
468 reg size_t size; /* new size */
469 int type; /* !=0 for movable, >0 for copy */
470 int local;
471 #endif
472 {
473 Vmuchar_t *data;
474 long offset;
475 size_t s, oldsize;
476 char *file, *oldfile;
477 int line, oldline;
478 Void_t *func;
479 Vmdata_t *vd = vm->data;
480 VMFLF(vm,file,line,func);
481
482 if(!addr)
483 { vm->file = file; vm->line = line;
484 data = (Vmuchar_t*)dballoc(vm, size, local);
485 if(data && (type&VM_RSZERO) )
486 memset((Void_t*)data, 0, size);
487 return data;
488 }
489 if(size == 0)
490 { vm->file = file; vm->line = line;
491 (void)dbfree(vm, addr, local);
492 return NIL(Void_t*);
493 }
494
495 SETLOCK(vm, local);
496
497 if(vd->mode&VM_DBCHECK)
498 vmdbcheck(vm);
499
500 if((offset = KPVADDR(vm,addr,dbaddr)) != 0)
501 { dbwarn(vm,(Vmuchar_t*)addr,offset == -1L ? 0 : 1,file,line,func,DB_RESIZE);
502 data = NIL(Vmuchar_t*);
503 }
504 else
505 { if(Dbnwatch > 0)
506 dbwatch(vm,addr,file,line,func,DB_RESIZE);
507
508 /* Vmbest data block */
509 data = DB2BEST(addr);
510 oldsize = DBSIZE(addr);
511 oldfile = DBFILE(addr);
512 oldline = DBLINE(addr);
513
514 /* do the resize */
515 s = ROUND(size,ALIGN) + DB_EXTRA;
516 if(s < sizeof(Body_t))
517 s = sizeof(Body_t);
518 data = (Vmuchar_t*)KPVRESIZE(vm,(Void_t*)data,s,
519 (type&~VM_RSZERO),(*(Vmbest->resizef)) );
520 if(!data) /* failed, reset data for old block */
521 { dbwarn(vm,NIL(Vmuchar_t*),DB_ALLOC,file,line,func,DB_RESIZE);
522 dbsetinfo((Vmuchar_t*)addr,oldsize,oldfile,oldline);
523 }
524 else
525 { data = DB2DEBUG(data);
526 dbsetinfo(data,size,file,line);
527
528 if((vd->mode&VM_TRACE) && _Vmtrace)
529 { vm->file = file; vm->line = line;
530 (*_Vmtrace)(vm,(Vmuchar_t*)addr,data,size,0);
531 }
532 if(Dbnwatch > 0)
533 dbwatch(vm,data,file,line,func,DB_RESIZED);
534 }
535
536 if(data && (type&VM_RSZERO) && size > oldsize)
537 { Vmuchar_t *d = data+oldsize, *ed = data+size;
538 do { *d++ = 0; } while(d < ed);
539 }
540 }
541
542 CLRLOCK(vm, local);
543
544 return (Void_t*)data;
545 }
546
547 /* compact any residual free space */
548 #if __STD_C
dbcompact(Vmalloc_t * vm,int local)549 static int dbcompact(Vmalloc_t* vm, int local)
550 #else
551 static int dbcompact(vm, local)
552 Vmalloc_t* vm;
553 int local;
554 #endif
555 {
556 return (*(Vmbest->compactf))(vm, local);
557 }
558
559 /* check for memory overwrites over all live blocks */
560 #if __STD_C
vmdbcheck(Vmalloc_t * vm)561 int vmdbcheck(Vmalloc_t* vm)
562 #else
563 int vmdbcheck(vm)
564 Vmalloc_t* vm;
565 #endif
566 {
567 reg Block_t *b, *endb;
568 reg Seg_t* seg;
569 int rv;
570 reg Vmdata_t* vd = vm->data;
571
572 /* check the meta-data of this region */
573 if(vd->mode & (VM_MTDEBUG|VM_MTBEST|VM_MTPROFILE))
574 { if(_vmbestcheck(vd, NIL(Block_t*)) < 0)
575 return -1;
576 if(!(vd->mode&VM_MTDEBUG) )
577 return 0;
578 }
579 else return -1;
580
581 rv = 0;
582 for(seg = vd->seg; seg; seg = seg->next)
583 { b = SEGBLOCK(seg);
584 endb = (Block_t*)(seg->baddr - sizeof(Head_t));
585 while(b < endb)
586 { reg Vmuchar_t *data, *begp, *endp;
587
588 if(ISJUNK(SIZE(b)) || !ISBUSY(SIZE(b)))
589 goto next;
590
591 data = DB2DEBUG(DATA(b));
592 if(DBISBAD(data)) /* seen this before */
593 { rv += 1;
594 goto next;
595 }
596
597 DBHEAD(data,begp,endp);
598 for(; begp < endp; ++begp)
599 if(*begp != DB_MAGIC)
600 goto set_bad;
601
602 DBTAIL(data,begp,endp);
603 for(; begp < endp; ++begp)
604 { if(*begp == DB_MAGIC)
605 continue;
606 set_bad:
607 dbwarn(vm,data,(long)(begp-data),vm->file,vm->line,0,DB_CHECK);
608 DBSETBAD(data);
609 rv += 1;
610 goto next;
611 }
612
613 next: b = (Block_t*)((Vmuchar_t*)DATA(b) + (SIZE(b)&~BITS));
614 }
615 }
616
617 return rv;
618 }
619
620 /* set/delete an address to watch */
621 #if __STD_C
vmdbwatch(Void_t * addr)622 Void_t* vmdbwatch(Void_t* addr)
623 #else
624 Void_t* vmdbwatch(addr)
625 Void_t* addr; /* address to insert */
626 #endif
627 {
628 reg int n;
629 reg Void_t* out;
630
631 out = NIL(Void_t*);
632 if(!addr)
633 Dbnwatch = 0;
634 else
635 { for(n = Dbnwatch - 1; n >= 0; --n)
636 if(Dbwatch[n] == addr)
637 break;
638 if(n < 0) /* insert */
639 { if(Dbnwatch == S_WATCH)
640 { /* delete left-most */
641 out = Dbwatch[0];
642 Dbnwatch -= 1;
643 for(n = 0; n < Dbnwatch; ++n)
644 Dbwatch[n] = Dbwatch[n+1];
645 }
646 Dbwatch[Dbnwatch] = addr;
647 Dbnwatch += 1;
648 }
649 }
650 return out;
651 }
652
653 #if __STD_C
dbalign(Vmalloc_t * vm,size_t size,size_t align,int local)654 static Void_t* dbalign(Vmalloc_t* vm, size_t size, size_t align, int local)
655 #else
656 static Void_t* dbalign(vm, size, align, local)
657 Vmalloc_t* vm;
658 size_t size;
659 size_t align;
660 int local;
661 #endif
662 {
663 Vmuchar_t *data;
664 size_t s;
665 char *file;
666 int line;
667 Void_t *func;
668 Vmdata_t *vd = vm->data;
669 VMFLF(vm,file,line,func);
670
671 if(size <= 0 || align <= 0)
672 return NIL(Void_t*);
673
674 SETLOCK(vm, local);
675
676 if((s = ROUND(size,ALIGN) + DB_EXTRA) < sizeof(Body_t))
677 s = sizeof(Body_t);
678
679 if((data = (Vmuchar_t*)KPVALIGN(vm,s,align,(*(Vmbest->alignf)))) )
680 { data += DB_HEAD;
681 dbsetinfo(data,size,file,line);
682
683 if((vd->mode&VM_TRACE) && _Vmtrace)
684 { vm->file = file; vm->line = line; vm->func = func;
685 (*_Vmtrace)(vm,NIL(Vmuchar_t*),data,size,align);
686 }
687 }
688
689 CLRLOCK(vm, local);
690
691 return (Void_t*)data;
692 }
693
694 /* print statistics of region vm. If vm is NULL, use Vmregion */
695 #if __STD_C
vmdbstat(Vmalloc_t * vm)696 ssize_t vmdbstat(Vmalloc_t* vm)
697 #else
698 ssize_t vmdbstat(vm)
699 Vmalloc_t* vm;
700 #endif
701 { Vmstat_t st;
702 char buf[1024], *bufp;
703
704 vmstat(vm ? vm : Vmregion, &st);
705 bufp = buf;
706 bufp = (*_Vmstrcpy)(bufp, "n_busy", '=');
707 bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(VLONG(st.n_busy),-1), ',');
708 bufp = (*_Vmstrcpy)(bufp, " s_busy", '=');
709 bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(VLONG(st.s_busy),-1), '\n');
710 bufp = (*_Vmstrcpy)(bufp, "n_free", '=');
711 bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(VLONG(st.n_free),-1), ',');
712 bufp = (*_Vmstrcpy)(bufp, " s_free", '=');
713 bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(VLONG(st.s_free),-1), '\n');
714 bufp = (*_Vmstrcpy)(bufp, "m_busy", '=');
715 bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(VLONG(st.m_busy),-1), ',');
716 bufp = (*_Vmstrcpy)(bufp, " m_free", '=');
717 bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(VLONG(st.m_free),-1), '\n');
718 bufp = (*_Vmstrcpy)(bufp, "n_segment", '=');
719 bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(VLONG(st.n_seg),-1), ',');
720 bufp = (*_Vmstrcpy)(bufp, " extent", '=');
721 bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(VLONG(st.extent),-1), '\n');
722 *bufp = 0;
723 write(Dbfd, buf, strlen(buf));
724 return strlen(buf);
725 }
726
727 static Vmethod_t _Vmdebug =
728 {
729 dballoc,
730 dbresize,
731 dbfree,
732 dbaddr,
733 dbsize,
734 dbcompact,
735 dbalign,
736 VM_MTDEBUG
737 };
738
739 __DEFINE__(Vmethod_t*,Vmdebug,&_Vmdebug);
740
741 #ifdef NoF
742 NoF(vmdebug)
743 #endif
744
745 #endif
746