1N/A/***********************************************************************
1N/A* *
1N/A* This software is part of the ast package *
1N/A* Copyright (c) 1985-2011 AT&T Intellectual Property *
1N/A* and is licensed under the *
1N/A* Common Public License, Version 1.0 *
1N/A* by AT&T Intellectual Property *
1N/A* *
1N/A* A copy of the License is available at *
1N/A* http://www.opensource.org/licenses/cpl1.0.txt *
1N/A* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
1N/A* *
1N/A* Information and Software Systems Research *
1N/A* AT&T Research *
1N/A* Florham Park NJ *
1N/A* *
1N/A* Glenn Fowler <gsf@research.att.com> *
1N/A* David Korn <dgk@research.att.com> *
1N/A* Phong Vo <kpv@research.att.com> *
1N/A* *
1N/A***********************************************************************/
1N/A#if defined(_UWIN) && defined(_BLD_ast)
1N/A
1N/Avoid _STUB_vmdebug(){}
1N/A
1N/A#else
1N/A
1N/A#include "vmhdr.h"
1N/A
1N/A/* Method to help with debugging. This does rigorous checks on
1N/A** addresses and arena integrity.
1N/A**
1N/A** Written by Kiem-Phong Vo, kpv@research.att.com, 01/16/94.
1N/A*/
1N/A
1N/A/* structure to keep track of file names */
1N/Atypedef struct _dbfile_s Dbfile_t;
1N/Astruct _dbfile_s
1N/A{ Dbfile_t* next;
1N/A char file[1];
1N/A};
1N/Astatic Dbfile_t* Dbfile;
1N/A
1N/A/* global watch list */
1N/A#define S_WATCH 32
1N/Astatic int Dbnwatch;
1N/Astatic Void_t* Dbwatch[S_WATCH];
1N/A
1N/A/* types of warnings reported by dbwarn() */
1N/A#define DB_CHECK 0
1N/A#define DB_ALLOC 1
1N/A#define DB_FREE 2
1N/A#define DB_RESIZE 3
1N/A#define DB_WATCH 4
1N/A#define DB_RESIZED 5
1N/A
1N/A#define LONGV(x) ((Vmulong_t)(x))
1N/A
1N/Astatic int Dbinit = 0;
1N/A#define DBINIT() (Dbinit ? 0 : (dbinit(), Dbinit=1) )
1N/Astatic void dbinit()
1N/A{ int fd;
1N/A if((fd = vmtrace(-1)) >= 0)
1N/A vmtrace(fd);
1N/A}
1N/A
1N/Astatic int Dbfd = 2; /* default warning file descriptor */
1N/A#if __STD_C
1N/Aint vmdebug(int fd)
1N/A#else
1N/Aint vmdebug(fd)
1N/Aint fd;
1N/A#endif
1N/A{
1N/A int old = Dbfd;
1N/A Dbfd = fd;
1N/A return old;
1N/A}
1N/A
1N/A/* just an entry point to make it easy to set break point */
1N/A#if __STD_C
1N/Astatic void vmdbwarn(Vmalloc_t* vm, char* mesg, int n)
1N/A#else
1N/Astatic void vmdbwarn(vm, mesg, n)
1N/AVmalloc_t* vm;
1N/Achar* mesg;
1N/Aint n;
1N/A#endif
1N/A{
1N/A reg Vmdata_t* vd = vm->data;
1N/A
1N/A write(Dbfd,mesg,n);
1N/A if(vd->mode&VM_DBABORT)
1N/A abort();
1N/A}
1N/A
1N/A/* issue a warning of some type */
1N/A#if __STD_C
1N/Astatic void dbwarn(Vmalloc_t* vm, Void_t* data, int where,
1N/A const char* file, int line, const Void_t* func, int type)
1N/A#else
1N/Astatic void dbwarn(vm, data, where, file, line, func, type)
1N/AVmalloc_t* vm; /* region holding the block */
1N/AVoid_t* data; /* data block */
1N/Aint where; /* byte that was corrupted */
1N/Aconst char* file; /* file where call originates */
1N/Aint line; /* line number of call */
1N/Aconst Void_t* func; /* function called from */
1N/Aint type; /* operation being done */
1N/A#endif
1N/A{
1N/A char buf[1024], *bufp, *endbuf, *s;
1N/A#define SLOP 64 /* enough for a message and an int */
1N/A
1N/A DBINIT();
1N/A
1N/A bufp = buf;
1N/A endbuf = buf + sizeof(buf);
1N/A
1N/A if(type == DB_ALLOC)
1N/A bufp = (*_Vmstrcpy)(bufp, "alloc error", ':');
1N/A else if(type == DB_FREE)
1N/A bufp = (*_Vmstrcpy)(bufp, "free error", ':');
1N/A else if(type == DB_RESIZE)
1N/A bufp = (*_Vmstrcpy)(bufp, "resize error", ':');
1N/A else if(type == DB_CHECK)
1N/A bufp = (*_Vmstrcpy)(bufp, "corrupted data", ':');
1N/A else if(type == DB_WATCH)
1N/A bufp = (*_Vmstrcpy)(bufp, "alert", ':');
1N/A
1N/A /* region info */
1N/A bufp = (*_Vmstrcpy)(bufp, "region", '=');
1N/A bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(VLONG(vm), 0), ':');
1N/A
1N/A if(data)
1N/A { bufp = (*_Vmstrcpy)(bufp,"block",'=');
1N/A bufp = (*_Vmstrcpy)(bufp,(*_Vmitoa)(VLONG(data),0),':');
1N/A }
1N/A
1N/A if(!data)
1N/A { if(where == DB_ALLOC)
1N/A bufp = (*_Vmstrcpy)(bufp, "can't get memory", ':');
1N/A else bufp = (*_Vmstrcpy)(bufp, "region is locked", ':');
1N/A }
1N/A else if(type == DB_FREE || type == DB_RESIZE)
1N/A { if(where == 0)
1N/A bufp = (*_Vmstrcpy)(bufp, "unallocated block", ':');
1N/A else bufp = (*_Vmstrcpy)(bufp, "already freed", ':');
1N/A }
1N/A else if(type == DB_WATCH)
1N/A { bufp = (*_Vmstrcpy)(bufp, "size", '=');
1N/A bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(DBSIZE(data),-1), ':');
1N/A if(where == DB_ALLOC)
1N/A bufp = (*_Vmstrcpy)(bufp,"just allocated", ':');
1N/A else if(where == DB_FREE)
1N/A bufp = (*_Vmstrcpy)(bufp,"being freed", ':');
1N/A else if(where == DB_RESIZE)
1N/A bufp = (*_Vmstrcpy)(bufp,"being resized", ':');
1N/A else if(where == DB_RESIZED)
1N/A bufp = (*_Vmstrcpy)(bufp,"just resized", ':');
1N/A }
1N/A else if(type == DB_CHECK)
1N/A { bufp = (*_Vmstrcpy)(bufp, "bad byte at", '=');
1N/A bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(LONGV(where),-1), ':');
1N/A if((s = DBFILE(data)) && (bufp + strlen(s) + SLOP) < endbuf)
1N/A { bufp = (*_Vmstrcpy)(bufp,"allocated at", '=');
1N/A bufp = (*_Vmstrcpy)(bufp, s, ',');
1N/A bufp = (*_Vmstrcpy)(bufp,(*_Vmitoa)(LONGV(DBLINE(data)),-1),':');
1N/A }
1N/A }
1N/A
1N/A /* location where offending call originates from */
1N/A if(file && file[0] && line > 0 && (bufp + strlen(file) + SLOP) < endbuf)
1N/A { bufp = (*_Vmstrcpy)(bufp, "detected at", '=');
1N/A bufp = (*_Vmstrcpy)(bufp, file, ',');
1N/A bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(LONGV(line),-1), ',');
1N/A bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(VLONG(func),-1), ':');
1N/A }
1N/A
1N/A *(bufp - 1) = '\n';
1N/A *bufp = '\0';
1N/A
1N/A vmdbwarn(vm,buf,(bufp-buf));
1N/A}
1N/A
1N/A/* check for watched address and issue warnings */
1N/A#if __STD_C
1N/Astatic void dbwatch(Vmalloc_t* vm, Void_t* data,
1N/A const char* file, int line, const Void_t* func, int type)
1N/A#else
1N/Astatic void dbwatch(vm, data, file, line, func, type)
1N/AVmalloc_t* vm;
1N/AVoid_t* data;
1N/Aconst char* file;
1N/Aint line;
1N/Aconst Void_t* func;
1N/Aint type;
1N/A#endif
1N/A{
1N/A reg int n;
1N/A
1N/A for(n = Dbnwatch; n >= 0; --n)
1N/A { if(Dbwatch[n] == data)
1N/A { dbwarn(vm,data,type,file,line,func,DB_WATCH);
1N/A return;
1N/A }
1N/A }
1N/A}
1N/A
1N/A/* record information about the block */
1N/A#if __STD_C
1N/Astatic void dbsetinfo(Vmuchar_t* data, size_t size, const char* file, int line)
1N/A#else
1N/Astatic void dbsetinfo(data, size, file, line)
1N/AVmuchar_t* data; /* real address not the one from Vmbest */
1N/Asize_t size; /* the actual requested size */
1N/Aconst char* file; /* file where the request came from */
1N/Aint line; /* and line number */
1N/A#endif
1N/A{
1N/A reg Vmuchar_t *begp, *endp;
1N/A reg Dbfile_t *last, *db;
1N/A
1N/A DBINIT();
1N/A
1N/A /* find the file structure */
1N/A if(!file || !file[0])
1N/A db = NIL(Dbfile_t*);
1N/A else
1N/A { for(last = NIL(Dbfile_t*), db = Dbfile; db; last = db, db = db->next)
1N/A if(strcmp(db->file,file) == 0)
1N/A break;
1N/A if(!db)
1N/A { db = (Dbfile_t*)vmalloc(Vmheap,sizeof(Dbfile_t)+strlen(file));
1N/A if(db)
1N/A { (*_Vmstrcpy)(db->file,file,0);
1N/A db->next = Dbfile;
1N/A Dbfile = db->next;
1N/A }
1N/A }
1N/A else if(last) /* move-to-front heuristic */
1N/A { last->next = db->next;
1N/A db->next = Dbfile;
1N/A Dbfile = db->next;
1N/A }
1N/A }
1N/A
1N/A DBSETFL(data,(db ? db->file : NIL(char*)),line);
1N/A DBSIZE(data) = size;
1N/A DBSEG(data) = SEG(DBBLOCK(data));
1N/A
1N/A DBHEAD(data,begp,endp);
1N/A while(begp < endp)
1N/A *begp++ = DB_MAGIC;
1N/A DBTAIL(data,begp,endp);
1N/A while(begp < endp)
1N/A *begp++ = DB_MAGIC;
1N/A}
1N/A
1N/A/* Check to see if an address is in some data block of a region.
1N/A** This returns -(offset+1) if block is already freed, +(offset+1)
1N/A** if block is live, 0 if no match.
1N/A*/
1N/A#if __STD_C
1N/Astatic long dbaddr(Vmalloc_t* vm, Void_t* addr)
1N/A#else
1N/Astatic long dbaddr(vm, addr)
1N/AVmalloc_t* vm;
1N/AVoid_t* addr;
1N/A#endif
1N/A{
1N/A reg Block_t *b, *endb;
1N/A reg Seg_t* seg;
1N/A reg Vmuchar_t* data;
1N/A reg long offset = -1L;
1N/A reg Vmdata_t* vd = vm->data;
1N/A reg int local, inuse;
1N/A
1N/A SETINUSE(vd, inuse);
1N/A GETLOCAL(vd,local);
1N/A if(ISLOCK(vd,local) || !addr)
1N/A { CLRINUSE(vd, inuse);
1N/A return -1L;
1N/A }
1N/A SETLOCK(vd,local);
1N/A
1N/A b = endb = NIL(Block_t*);
1N/A for(seg = vd->seg; seg; seg = seg->next)
1N/A { b = SEGBLOCK(seg);
1N/A endb = (Block_t*)(seg->baddr - sizeof(Head_t));
1N/A if((Vmuchar_t*)addr > (Vmuchar_t*)b &&
1N/A (Vmuchar_t*)addr < (Vmuchar_t*)endb)
1N/A break;
1N/A }
1N/A if(!seg)
1N/A goto done;
1N/A
1N/A if(local) /* must be vmfree or vmresize checking address */
1N/A { if(DBSEG(addr) == seg)
1N/A { b = DBBLOCK(addr);
1N/A if(ISBUSY(SIZE(b)) && !ISJUNK(SIZE(b)) )
1N/A offset = 0;
1N/A else offset = -2L;
1N/A }
1N/A goto done;
1N/A }
1N/A
1N/A while(b < endb)
1N/A { data = (Vmuchar_t*)DATA(b);
1N/A if((Vmuchar_t*)addr >= data && (Vmuchar_t*)addr < data+SIZE(b))
1N/A { if(ISBUSY(SIZE(b)) && !ISJUNK(SIZE(b)) )
1N/A { data = DB2DEBUG(data);
1N/A if((Vmuchar_t*)addr >= data &&
1N/A (Vmuchar_t*)addr < data+DBSIZE(data))
1N/A offset = (Vmuchar_t*)addr - data;
1N/A }
1N/A goto done;
1N/A }
1N/A
1N/A b = (Block_t*)((Vmuchar_t*)DATA(b) + (SIZE(b)&~BITS) );
1N/A }
1N/A
1N/Adone:
1N/A CLRLOCK(vd,local);
1N/A CLRINUSE(vd, inuse);
1N/A return offset;
1N/A}
1N/A
1N/A
1N/A#if __STD_C
1N/Astatic long dbsize(Vmalloc_t* vm, Void_t* addr)
1N/A#else
1N/Astatic long dbsize(vm, addr)
1N/AVmalloc_t* vm;
1N/AVoid_t* addr;
1N/A#endif
1N/A{
1N/A reg Block_t *b, *endb;
1N/A reg Seg_t* seg;
1N/A reg long size;
1N/A reg Vmdata_t* vd = vm->data;
1N/A reg int inuse;
1N/A
1N/A SETINUSE(vd, inuse);
1N/A if(ISLOCK(vd,0))
1N/A { CLRINUSE(vd, inuse);
1N/A return -1L;
1N/A }
1N/A SETLOCK(vd,0);
1N/A
1N/A size = -1L;
1N/A for(seg = vd->seg; seg; seg = seg->next)
1N/A { b = SEGBLOCK(seg);
1N/A endb = (Block_t*)(seg->baddr - sizeof(Head_t));
1N/A if((Vmuchar_t*)addr <= (Vmuchar_t*)b ||
1N/A (Vmuchar_t*)addr >= (Vmuchar_t*)endb)
1N/A continue;
1N/A while(b < endb)
1N/A { if(addr == (Void_t*)DB2DEBUG(DATA(b)))
1N/A { if(ISBUSY(SIZE(b)) && !ISJUNK(SIZE(b)) )
1N/A size = (long)DBSIZE(addr);
1N/A goto done;
1N/A }
1N/A
1N/A b = (Block_t*)((Vmuchar_t*)DATA(b) + (SIZE(b)&~BITS) );
1N/A }
1N/A }
1N/Adone:
1N/A CLRLOCK(vd,0);
1N/A CLRINUSE(vd, inuse);
1N/A return size;
1N/A}
1N/A
1N/A#if __STD_C
1N/Astatic Void_t* dballoc(Vmalloc_t* vm, size_t size)
1N/A#else
1N/Astatic Void_t* dballoc(vm, size)
1N/AVmalloc_t* vm;
1N/Asize_t size;
1N/A#endif
1N/A{
1N/A reg size_t s;
1N/A reg Vmuchar_t* data;
1N/A reg char* file;
1N/A reg int line;
1N/A reg Void_t* func;
1N/A reg Vmdata_t* vd = vm->data;
1N/A reg int inuse;
1N/A
1N/A SETINUSE(vd, inuse);
1N/A VMFLF(vm,file,line,func);
1N/A
1N/A if(ISLOCK(vd,0) )
1N/A { dbwarn(vm,NIL(Vmuchar_t*),0,file,line,func,DB_ALLOC);
1N/A CLRINUSE(vd, inuse);
1N/A return NIL(Void_t*);
1N/A }
1N/A SETLOCK(vd,0);
1N/A
1N/A if(vd->mode&VM_DBCHECK)
1N/A vmdbcheck(vm);
1N/A
1N/A s = ROUND(size,ALIGN) + DB_EXTRA;
1N/A if(s < sizeof(Body_t)) /* no tiny blocks during Vmdebug */
1N/A s = sizeof(Body_t);
1N/A
1N/A if(!(data = (Vmuchar_t*)KPVALLOC(vm,s,(*(Vmbest->allocf))) ) )
1N/A { dbwarn(vm,NIL(Vmuchar_t*),DB_ALLOC,file,line,func,DB_ALLOC);
1N/A goto done;
1N/A }
1N/A
1N/A data = DB2DEBUG(data);
1N/A dbsetinfo(data,size,file,line);
1N/A
1N/A if((vd->mode&VM_TRACE) && _Vmtrace)
1N/A { vm->file = file; vm->line = line; vm->func = func;
1N/A (*_Vmtrace)(vm,NIL(Vmuchar_t*),data,size,0);
1N/A }
1N/A
1N/A if(Dbnwatch > 0 )
1N/A dbwatch(vm,data,file,line,func,DB_ALLOC);
1N/A
1N/Adone:
1N/A CLRLOCK(vd,0);
1N/A ANNOUNCE(0, vm, VM_ALLOC, (Void_t*)data, vm->disc);
1N/A CLRINUSE(vd, inuse);
1N/A return (Void_t*)data;
1N/A}
1N/A
1N/A
1N/A#if __STD_C
1N/Astatic int dbfree(Vmalloc_t* vm, Void_t* data )
1N/A#else
1N/Astatic int dbfree(vm, data )
1N/AVmalloc_t* vm;
1N/AVoid_t* data;
1N/A#endif
1N/A{
1N/A char* file;
1N/A int line;
1N/A Void_t* func;
1N/A reg long offset;
1N/A reg int rv, *ip, *endip;
1N/A reg Vmdata_t* vd = vm->data;
1N/A reg int inuse;
1N/A
1N/A SETINUSE(vd, inuse);
1N/A VMFLF(vm,file,line,func);
1N/A
1N/A if(!data)
1N/A { CLRINUSE(vd, inuse);
1N/A return 0;
1N/A }
1N/A
1N/A if(ISLOCK(vd,0) )
1N/A { dbwarn(vm,NIL(Vmuchar_t*),0,file,line,func,DB_FREE);
1N/A CLRINUSE(vd, inuse);
1N/A return -1;
1N/A }
1N/A SETLOCK(vd,0);
1N/A
1N/A if(vd->mode&VM_DBCHECK)
1N/A vmdbcheck(vm);
1N/A
1N/A if((offset = KPVADDR(vm,data,dbaddr)) != 0)
1N/A { dbwarn(vm,(Vmuchar_t*)data,offset == -1L ? 0 : 1,file,line,func,DB_FREE);
1N/A if(vm->disc->exceptf)
1N/A (void)(*vm->disc->exceptf)(vm,VM_BADADDR,data,vm->disc);
1N/A CLRLOCK(vd,0);
1N/A CLRINUSE(vd, inuse);
1N/A return -1;
1N/A }
1N/A
1N/A if(Dbnwatch > 0)
1N/A dbwatch(vm,data,file,line,func,DB_FREE);
1N/A
1N/A if((vd->mode&VM_TRACE) && _Vmtrace)
1N/A { vm->file = file; vm->line = line; vm->func = func;
1N/A (*_Vmtrace)(vm,(Vmuchar_t*)data,NIL(Vmuchar_t*),DBSIZE(data),0);
1N/A }
1N/A
1N/A /* clear free space */
1N/A ip = (int*)data;
1N/A endip = ip + (DBSIZE(data)+sizeof(int)-1)/sizeof(int);
1N/A while(ip < endip)
1N/A *ip++ = 0;
1N/A
1N/A rv = KPVFREE((vm), (Void_t*)DB2BEST(data), (*Vmbest->freef));
1N/A CLRLOCK(vd,0);
1N/A ANNOUNCE(0, vm, VM_FREE, data, vm->disc);
1N/A CLRINUSE(vd, inuse);
1N/A return rv;
1N/A}
1N/A
1N/A/* Resizing an existing block */
1N/A#if __STD_C
1N/Astatic Void_t* dbresize(Vmalloc_t* vm, Void_t* addr, reg size_t size, int type)
1N/A#else
1N/Astatic Void_t* dbresize(vm,addr,size,type)
1N/AVmalloc_t* vm; /* region allocating from */
1N/AVoid_t* addr; /* old block of data */
1N/Areg size_t size; /* new size */
1N/Aint type; /* !=0 for movable, >0 for copy */
1N/A#endif
1N/A{
1N/A reg Vmuchar_t* data;
1N/A reg size_t s, oldsize;
1N/A reg long offset;
1N/A char *file, *oldfile;
1N/A int line, oldline;
1N/A Void_t* func;
1N/A reg Vmdata_t* vd = vm->data;
1N/A reg int inuse;
1N/A
1N/A SETINUSE(vd, inuse);
1N/A if(!addr)
1N/A { oldsize = 0;
1N/A data = (Vmuchar_t*)dballoc(vm,size);
1N/A goto done;
1N/A }
1N/A if(size == 0)
1N/A { (void)dbfree(vm,addr);
1N/A CLRINUSE(vd, inuse);
1N/A return NIL(Void_t*);
1N/A }
1N/A
1N/A VMFLF(vm,file,line,func);
1N/A
1N/A if(ISLOCK(vd,0) )
1N/A { dbwarn(vm,NIL(Vmuchar_t*),0,file,line,func,DB_RESIZE);
1N/A CLRINUSE(vd, inuse);
1N/A return NIL(Void_t*);
1N/A }
1N/A SETLOCK(vd,0);
1N/A
1N/A if(vd->mode&VM_DBCHECK)
1N/A vmdbcheck(vm);
1N/A
1N/A if((offset = KPVADDR(vm,addr,dbaddr)) != 0)
1N/A { dbwarn(vm,(Vmuchar_t*)addr,offset == -1L ? 0 : 1,file,line,func,DB_RESIZE);
1N/A if(vm->disc->exceptf)
1N/A (void)(*vm->disc->exceptf)(vm,VM_BADADDR,addr,vm->disc);
1N/A CLRLOCK(vd,0);
1N/A CLRINUSE(vd, inuse);
1N/A return NIL(Void_t*);
1N/A }
1N/A
1N/A if(Dbnwatch > 0)
1N/A dbwatch(vm,addr,file,line,func,DB_RESIZE);
1N/A
1N/A /* Vmbest data block */
1N/A data = DB2BEST(addr);
1N/A oldsize = DBSIZE(addr);
1N/A oldfile = DBFILE(addr);
1N/A oldline = DBLINE(addr);
1N/A
1N/A /* do the resize */
1N/A s = ROUND(size,ALIGN) + DB_EXTRA;
1N/A if(s < sizeof(Body_t))
1N/A s = sizeof(Body_t);
1N/A data = (Vmuchar_t*)KPVRESIZE(vm,(Void_t*)data,s,
1N/A (type&~VM_RSZERO),(*(Vmbest->resizef)) );
1N/A if(!data) /* failed, reset data for old block */
1N/A { dbwarn(vm,NIL(Vmuchar_t*),DB_ALLOC,file,line,func,DB_RESIZE);
1N/A dbsetinfo((Vmuchar_t*)addr,oldsize,oldfile,oldline);
1N/A }
1N/A else
1N/A { data = DB2DEBUG(data);
1N/A dbsetinfo(data,size,file,line);
1N/A
1N/A if((vd->mode&VM_TRACE) && _Vmtrace)
1N/A { vm->file = file; vm->line = line;
1N/A (*_Vmtrace)(vm,(Vmuchar_t*)addr,data,size,0);
1N/A }
1N/A if(Dbnwatch > 0)
1N/A dbwatch(vm,data,file,line,func,DB_RESIZED);
1N/A }
1N/A
1N/A CLRLOCK(vd,0);
1N/A ANNOUNCE(0, vm, VM_RESIZE, (Void_t*)data, vm->disc);
1N/A
1N/Adone: if(data && (type&VM_RSZERO) && size > oldsize)
1N/A { reg Vmuchar_t *d = data+oldsize, *ed = data+size;
1N/A do { *d++ = 0; } while(d < ed);
1N/A }
1N/A CLRINUSE(vd, inuse);
1N/A return (Void_t*)data;
1N/A}
1N/A
1N/A/* compact any residual free space */
1N/A#if __STD_C
1N/Astatic int dbcompact(Vmalloc_t* vm)
1N/A#else
1N/Astatic int dbcompact(vm)
1N/AVmalloc_t* vm;
1N/A#endif
1N/A{
1N/A return (*(Vmbest->compactf))(vm);
1N/A}
1N/A
1N/A/* check for memory overwrites over all live blocks */
1N/A#if __STD_C
1N/Aint vmdbcheck(Vmalloc_t* vm)
1N/A#else
1N/Aint vmdbcheck(vm)
1N/AVmalloc_t* vm;
1N/A#endif
1N/A{
1N/A reg Block_t *b, *endb;
1N/A reg Seg_t* seg;
1N/A int rv;
1N/A reg Vmdata_t* vd = vm->data;
1N/A
1N/A /* check the meta-data of this region */
1N/A if(vd->mode & (VM_MTDEBUG|VM_MTBEST|VM_MTPROFILE))
1N/A { if(_vmbestcheck(vd, NIL(Block_t*)) < 0)
1N/A return -1;
1N/A if(!(vd->mode&VM_MTDEBUG))
1N/A return 0;
1N/A }
1N/A else return -1;
1N/A
1N/A rv = 0;
1N/A for(seg = vd->seg; seg; seg = seg->next)
1N/A { b = SEGBLOCK(seg);
1N/A endb = (Block_t*)(seg->baddr - sizeof(Head_t));
1N/A while(b < endb)
1N/A { reg Vmuchar_t *data, *begp, *endp;
1N/A
1N/A if(ISJUNK(SIZE(b)) || !ISBUSY(SIZE(b)))
1N/A goto next;
1N/A
1N/A data = DB2DEBUG(DATA(b));
1N/A if(DBISBAD(data)) /* seen this before */
1N/A { rv += 1;
1N/A goto next;
1N/A }
1N/A
1N/A DBHEAD(data,begp,endp);
1N/A for(; begp < endp; ++begp)
1N/A if(*begp != DB_MAGIC)
1N/A goto set_bad;
1N/A
1N/A DBTAIL(data,begp,endp);
1N/A for(; begp < endp; ++begp)
1N/A { if(*begp == DB_MAGIC)
1N/A continue;
1N/A set_bad:
1N/A dbwarn(vm,data,begp-data,NIL(char*),0,0,DB_CHECK);
1N/A DBSETBAD(data);
1N/A rv += 1;
1N/A goto next;
1N/A }
1N/A
1N/A next: b = (Block_t*)((Vmuchar_t*)DATA(b) + (SIZE(b)&~BITS));
1N/A }
1N/A }
1N/A
1N/A return rv;
1N/A}
1N/A
1N/A/* set/delete an address to watch */
1N/A#if __STD_C
1N/AVoid_t* vmdbwatch(Void_t* addr)
1N/A#else
1N/AVoid_t* vmdbwatch(addr)
1N/AVoid_t* addr; /* address to insert */
1N/A#endif
1N/A{
1N/A reg int n;
1N/A reg Void_t* out;
1N/A
1N/A out = NIL(Void_t*);
1N/A if(!addr)
1N/A Dbnwatch = 0;
1N/A else
1N/A { for(n = Dbnwatch - 1; n >= 0; --n)
1N/A if(Dbwatch[n] == addr)
1N/A break;
1N/A if(n < 0) /* insert */
1N/A { if(Dbnwatch == S_WATCH)
1N/A { /* delete left-most */
1N/A out = Dbwatch[0];
1N/A Dbnwatch -= 1;
1N/A for(n = 0; n < Dbnwatch; ++n)
1N/A Dbwatch[n] = Dbwatch[n+1];
1N/A }
1N/A Dbwatch[Dbnwatch] = addr;
1N/A Dbnwatch += 1;
1N/A }
1N/A }
1N/A return out;
1N/A}
1N/A
1N/A#if __STD_C
1N/Astatic Void_t* dbalign(Vmalloc_t* vm, size_t size, size_t align)
1N/A#else
1N/Astatic Void_t* dbalign(vm, size, align)
1N/AVmalloc_t* vm;
1N/Asize_t size;
1N/Asize_t align;
1N/A#endif
1N/A{
1N/A reg Vmuchar_t* data;
1N/A reg size_t s;
1N/A reg char* file;
1N/A reg int line;
1N/A reg Void_t* func;
1N/A reg Vmdata_t* vd = vm->data;
1N/A reg int inuse;
1N/A
1N/A SETINUSE(vd, inuse);
1N/A VMFLF(vm,file,line,func);
1N/A
1N/A if(size <= 0 || align <= 0)
1N/A { CLRINUSE(vd, inuse);
1N/A return NIL(Void_t*);
1N/A }
1N/A
1N/A if(ISLOCK(vd,0) )
1N/A { CLRINUSE(vd, inuse);
1N/A return NIL(Void_t*);
1N/A }
1N/A SETLOCK(vd,0);
1N/A
1N/A if((s = ROUND(size,ALIGN) + DB_EXTRA) < sizeof(Body_t))
1N/A s = sizeof(Body_t);
1N/A
1N/A if(!(data = (Vmuchar_t*)KPVALIGN(vm,s,align,(*(Vmbest->alignf)))) )
1N/A goto done;
1N/A
1N/A data += DB_HEAD;
1N/A dbsetinfo(data,size,file,line);
1N/A
1N/A if((vd->mode&VM_TRACE) && _Vmtrace)
1N/A { vm->file = file; vm->line = line; vm->func = func;
1N/A (*_Vmtrace)(vm,NIL(Vmuchar_t*),data,size,align);
1N/A }
1N/A
1N/Adone:
1N/A CLRLOCK(vd,0);
1N/A ANNOUNCE(0, vm, VM_ALLOC, (Void_t*)data, vm->disc);
1N/A CLRINUSE(vd, inuse);
1N/A return (Void_t*)data;
1N/A}
1N/A
1N/A/* print statistics of region vm. If vm is NULL, use Vmregion */
1N/A#if __STD_C
1N/Assize_t vmdbstat(Vmalloc_t* vm)
1N/A#else
1N/Assize_t vmdbstat(vm)
1N/AVmalloc_t* vm;
1N/A#endif
1N/A{ Vmstat_t st;
1N/A char buf[1024], *bufp;
1N/A
1N/A vmstat(vm ? vm : Vmregion, &st);
1N/A bufp = buf;
1N/A bufp = (*_Vmstrcpy)(bufp, "n_busy", '=');
1N/A bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)((Vmulong_t)st.n_busy,-1), ',');
1N/A bufp = (*_Vmstrcpy)(bufp, " s_busy", '=');
1N/A bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(VLONG(st.s_busy),-1), '\n');
1N/A bufp = (*_Vmstrcpy)(bufp, "n_free", '=');
1N/A bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)((Vmulong_t)st.n_free,-1), ',');
1N/A bufp = (*_Vmstrcpy)(bufp, " s_free", '=');
1N/A bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(VLONG(st.s_free),-1), '\n');
1N/A bufp = (*_Vmstrcpy)(bufp, "m_busy", '=');
1N/A bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(VLONG(st.m_busy),-1), ',');
1N/A bufp = (*_Vmstrcpy)(bufp, " m_free", '=');
1N/A bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(VLONG(st.m_free),-1), '\n');
1N/A bufp = (*_Vmstrcpy)(bufp, "n_segment", '=');
1N/A bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)((Vmulong_t)st.n_seg,-1), ',');
1N/A bufp = (*_Vmstrcpy)(bufp, " extent", '=');
1N/A bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(VLONG(st.extent),-1), '\n');
1N/A *bufp = 0;
1N/A write(Dbfd, buf, strlen(buf));
1N/A return strlen(buf);
1N/A}
1N/A
1N/Astatic Vmethod_t _Vmdebug =
1N/A{
1N/A dballoc,
1N/A dbresize,
1N/A dbfree,
1N/A dbaddr,
1N/A dbsize,
1N/A dbcompact,
1N/A dbalign,
1N/A VM_MTDEBUG
1N/A};
1N/A
1N/A__DEFINE__(Vmethod_t*,Vmdebug,&_Vmdebug);
1N/A
1N/A#ifdef NoF
1N/ANoF(vmdebug)
1N/A#endif
1N/A
1N/A#endif