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