xref: /onnv-gate/usr/src/lib/libast/common/vmalloc/vmdebug.c (revision 12068:08a39a083754)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*12068SRoger.Faulkner@Oracle.COM *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
184887Schin *                  David Korn <dgk@research.att.com>                   *
194887Schin *                   Phong Vo <kpv@research.att.com>                    *
204887Schin *                                                                      *
214887Schin ***********************************************************************/
224887Schin #if defined(_UWIN) && defined(_BLD_ast)
234887Schin 
_STUB_vmdebug()244887Schin void _STUB_vmdebug(){}
254887Schin 
264887Schin #else
274887Schin 
284887Schin #include	"vmhdr.h"
294887Schin 
304887Schin /*	Method to help with debugging. This does rigorous checks on
314887Schin **	addresses and arena integrity.
324887Schin **
334887Schin **	Written by Kiem-Phong Vo, kpv@research.att.com, 01/16/94.
344887Schin */
354887Schin 
364887Schin /* structure to keep track of file names */
374887Schin typedef struct _dbfile_s	Dbfile_t;
384887Schin struct _dbfile_s
394887Schin {	Dbfile_t*	next;
404887Schin 	char		file[1];
414887Schin };
424887Schin static Dbfile_t*	Dbfile;
434887Schin 
444887Schin /* global watch list */
454887Schin #define S_WATCH	32
464887Schin static int	Dbnwatch;
474887Schin static Void_t*	Dbwatch[S_WATCH];
484887Schin 
494887Schin /* types of warnings reported by dbwarn() */
504887Schin #define	DB_CHECK	0
514887Schin #define DB_ALLOC	1
524887Schin #define DB_FREE		2
534887Schin #define DB_RESIZE	3
544887Schin #define DB_WATCH	4
554887Schin #define DB_RESIZED	5
564887Schin 
574887Schin #define LONGV(x)	((Vmulong_t)(x))
584887Schin 
594887Schin static int Dbinit = 0;
604887Schin #define DBINIT()	(Dbinit ? 0 : (dbinit(), Dbinit=1) )
dbinit()614887Schin static void dbinit()
624887Schin {	int	fd;
634887Schin 	if((fd = vmtrace(-1)) >= 0)
644887Schin 		vmtrace(fd);
654887Schin }
664887Schin 
674887Schin static int	Dbfd = 2;	/* default warning file descriptor */
684887Schin #if __STD_C
vmdebug(int fd)694887Schin int vmdebug(int fd)
704887Schin #else
714887Schin int vmdebug(fd)
724887Schin int	fd;
734887Schin #endif
744887Schin {
754887Schin 	int	old = Dbfd;
764887Schin 	Dbfd = fd;
774887Schin 	return old;
784887Schin }
794887Schin 
804887Schin /* just an entry point to make it easy to set break point */
814887Schin #if __STD_C
vmdbwarn(Vmalloc_t * vm,char * mesg,int n)824887Schin static void vmdbwarn(Vmalloc_t* vm, char* mesg, int n)
834887Schin #else
844887Schin static void vmdbwarn(vm, mesg, n)
854887Schin Vmalloc_t*	vm;
864887Schin char*		mesg;
874887Schin int		n;
884887Schin #endif
894887Schin {
904887Schin 	reg Vmdata_t*	vd = vm->data;
914887Schin 
924887Schin 	write(Dbfd,mesg,n);
934887Schin 	if(vd->mode&VM_DBABORT)
944887Schin 		abort();
954887Schin }
964887Schin 
974887Schin /* issue a warning of some type */
984887Schin #if __STD_C
dbwarn(Vmalloc_t * vm,Void_t * data,int where,const char * file,int line,const Void_t * func,int type)994887Schin static void dbwarn(Vmalloc_t* vm, Void_t* data, int where,
1004887Schin 		   const char* file, int line, const Void_t* func, int type)
1014887Schin #else
1024887Schin static void dbwarn(vm, data, where, file, line, func, type)
1034887Schin Vmalloc_t*	vm;	/* region holding the block	*/
1044887Schin Void_t*		data;	/* data block			*/
1054887Schin int		where;	/* byte that was corrupted	*/
1064887Schin const char*	file;	/* file where call originates	*/
1074887Schin int		line;	/* line number of call		*/
1084887Schin const Void_t*	func;	/* function called from		*/
1094887Schin int		type;	/* operation being done		*/
1104887Schin #endif
1114887Schin {
1124887Schin 	char	buf[1024], *bufp, *endbuf, *s;
1134887Schin #define SLOP	64	/* enough for a message and an int */
1144887Schin 
1154887Schin 	DBINIT();
1164887Schin 
1174887Schin 	bufp = buf;
1184887Schin 	endbuf = buf + sizeof(buf);
1194887Schin 
1204887Schin 	if(type == DB_ALLOC)
1214887Schin 		bufp = (*_Vmstrcpy)(bufp, "alloc error", ':');
1224887Schin 	else if(type == DB_FREE)
1234887Schin 		bufp = (*_Vmstrcpy)(bufp, "free error", ':');
1244887Schin 	else if(type == DB_RESIZE)
1254887Schin 		bufp = (*_Vmstrcpy)(bufp, "resize error", ':');
1264887Schin 	else if(type == DB_CHECK)
1274887Schin 		bufp = (*_Vmstrcpy)(bufp, "corrupted data", ':');
1284887Schin 	else if(type == DB_WATCH)
1294887Schin 		bufp = (*_Vmstrcpy)(bufp, "alert", ':');
1304887Schin 
1314887Schin 	/* region info */
1324887Schin 	bufp = (*_Vmstrcpy)(bufp, "region", '=');
1334887Schin 	bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(VLONG(vm), 0), ':');
1344887Schin 
1354887Schin 	if(data)
1364887Schin 	{	bufp = (*_Vmstrcpy)(bufp,"block",'=');
1374887Schin 		bufp = (*_Vmstrcpy)(bufp,(*_Vmitoa)(VLONG(data),0),':');
1384887Schin 	}
1394887Schin 
1404887Schin 	if(!data)
1414887Schin 	{	if(where == DB_ALLOC)
1424887Schin 			bufp = (*_Vmstrcpy)(bufp, "can't get memory", ':');
1434887Schin 		else	bufp = (*_Vmstrcpy)(bufp, "region is locked", ':');
1444887Schin 	}
1454887Schin 	else if(type == DB_FREE || type == DB_RESIZE)
1464887Schin 	{	if(where == 0)
1474887Schin 			bufp = (*_Vmstrcpy)(bufp, "unallocated block", ':');
1484887Schin 		else	bufp = (*_Vmstrcpy)(bufp, "already freed", ':');
1494887Schin 	}
1504887Schin 	else if(type == DB_WATCH)
1514887Schin 	{	bufp = (*_Vmstrcpy)(bufp, "size", '=');
1524887Schin 		bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(DBSIZE(data),-1), ':');
1534887Schin 		if(where == DB_ALLOC)
1544887Schin 			bufp = (*_Vmstrcpy)(bufp,"just allocated", ':');
1554887Schin 		else if(where == DB_FREE)
1564887Schin 			bufp = (*_Vmstrcpy)(bufp,"being freed", ':');
1574887Schin 		else if(where == DB_RESIZE)
1584887Schin 			bufp = (*_Vmstrcpy)(bufp,"being resized", ':');
1594887Schin 		else if(where == DB_RESIZED)
1604887Schin 			bufp = (*_Vmstrcpy)(bufp,"just resized", ':');
1614887Schin 	}
1624887Schin 	else if(type == DB_CHECK)
1634887Schin 	{	bufp = (*_Vmstrcpy)(bufp, "bad byte at", '=');
1644887Schin 		bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(LONGV(where),-1), ':');
1654887Schin 		if((s = DBFILE(data)) && (bufp + strlen(s) + SLOP) < endbuf)
1664887Schin 		{	bufp = (*_Vmstrcpy)(bufp,"allocated at", '=');
1674887Schin 			bufp = (*_Vmstrcpy)(bufp, s, ',');
1684887Schin 			bufp = (*_Vmstrcpy)(bufp,(*_Vmitoa)(LONGV(DBLINE(data)),-1),':');
1694887Schin 		}
1704887Schin 	}
1714887Schin 
1724887Schin 	/* location where offending call originates from */
1734887Schin 	if(file && file[0] && line > 0 && (bufp + strlen(file) + SLOP) < endbuf)
1744887Schin 	{	bufp = (*_Vmstrcpy)(bufp, "detected at", '=');
1754887Schin 		bufp = (*_Vmstrcpy)(bufp, file, ',');
1764887Schin 		bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(LONGV(line),-1), ',');
1774887Schin 		bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(VLONG(func),-1), ':');
1784887Schin 	}
1794887Schin 
180*12068SRoger.Faulkner@Oracle.COM 	*(bufp - 1) = '\n';
1814887Schin 	*bufp = '\0';
1824887Schin 
1834887Schin 	vmdbwarn(vm,buf,(bufp-buf));
1844887Schin }
1854887Schin 
1864887Schin /* check for watched address and issue warnings */
1874887Schin #if __STD_C
dbwatch(Vmalloc_t * vm,Void_t * data,const char * file,int line,const Void_t * func,int type)1884887Schin static void dbwatch(Vmalloc_t* vm, Void_t* data,
1894887Schin 		    const char* file, int line, const Void_t* func, int type)
1904887Schin #else
1914887Schin static void dbwatch(vm, data, file, line, func, type)
1924887Schin Vmalloc_t*	vm;
1934887Schin Void_t*		data;
1944887Schin const char*	file;
1954887Schin int		line;
1964887Schin const Void_t*	func;
1974887Schin int		type;
1984887Schin #endif
1994887Schin {
2004887Schin 	reg int		n;
2014887Schin 
2024887Schin 	for(n = Dbnwatch; n >= 0; --n)
2034887Schin 	{	if(Dbwatch[n] == data)
2044887Schin 		{	dbwarn(vm,data,type,file,line,func,DB_WATCH);
2054887Schin 			return;
2064887Schin 		}
2074887Schin 	}
2084887Schin }
2094887Schin 
2104887Schin /* record information about the block */
2114887Schin #if __STD_C
dbsetinfo(Vmuchar_t * data,size_t size,const char * file,int line)2124887Schin static void dbsetinfo(Vmuchar_t* data, size_t size, const char* file, int line)
2134887Schin #else
2144887Schin static void dbsetinfo(data, size, file, line)
2154887Schin Vmuchar_t*	data;	/* real address not the one from Vmbest	*/
2164887Schin size_t		size;	/* the actual requested size		*/
2174887Schin const char*	file;	/* file where the request came from	*/
2184887Schin int		line;	/* and line number			*/
2194887Schin #endif
2204887Schin {
2214887Schin 	reg Vmuchar_t	*begp, *endp;
2224887Schin 	reg Dbfile_t	*last, *db;
2234887Schin 
2244887Schin 	DBINIT();
2254887Schin 
2264887Schin 	/* find the file structure */
2274887Schin 	if(!file || !file[0])
2284887Schin 		db = NIL(Dbfile_t*);
2294887Schin 	else
2304887Schin 	{	for(last = NIL(Dbfile_t*), db = Dbfile; db; last = db, db = db->next)
2314887Schin 			if(strcmp(db->file,file) == 0)
2324887Schin 				break;
2334887Schin 		if(!db)
2344887Schin 		{	db = (Dbfile_t*)vmalloc(Vmheap,sizeof(Dbfile_t)+strlen(file));
2354887Schin 			if(db)
2364887Schin 			{	(*_Vmstrcpy)(db->file,file,0);
2374887Schin 				db->next = Dbfile;
2384887Schin 				Dbfile = db->next;
2394887Schin 			}
2404887Schin 		}
2414887Schin 		else if(last) /* move-to-front heuristic */
2424887Schin 		{	last->next = db->next;
2434887Schin 			db->next = Dbfile;
2444887Schin 			Dbfile = db->next;
2454887Schin 		}
2464887Schin 	}
2474887Schin 
2484887Schin 	DBSETFL(data,(db ? db->file : NIL(char*)),line);
2494887Schin 	DBSIZE(data) = size;
2504887Schin 	DBSEG(data)  = SEG(DBBLOCK(data));
2514887Schin 
2524887Schin 	DBHEAD(data,begp,endp);
2534887Schin 	while(begp < endp)
2544887Schin 		*begp++ = DB_MAGIC;
2554887Schin 	DBTAIL(data,begp,endp);
2564887Schin 	while(begp < endp)
2574887Schin 		*begp++ = DB_MAGIC;
2584887Schin }
2594887Schin 
2604887Schin /* Check to see if an address is in some data block of a region.
2614887Schin ** This returns -(offset+1) if block is already freed, +(offset+1)
2624887Schin ** if block is live, 0 if no match.
2634887Schin */
2644887Schin #if __STD_C
dbaddr(Vmalloc_t * vm,Void_t * addr)2654887Schin static long dbaddr(Vmalloc_t* vm, Void_t* addr)
2664887Schin #else
2674887Schin static long dbaddr(vm, addr)
2684887Schin Vmalloc_t*	vm;
2694887Schin Void_t*		addr;
2704887Schin #endif
2714887Schin {
2724887Schin 	reg Block_t	*b, *endb;
2734887Schin 	reg Seg_t*	seg;
2744887Schin 	reg Vmuchar_t*	data;
2754887Schin 	reg long	offset = -1L;
2764887Schin 	reg Vmdata_t*	vd = vm->data;
2778462SApril.Chin@Sun.COM 	reg int		local, inuse;
2784887Schin 
2798462SApril.Chin@Sun.COM 	SETINUSE(vd, inuse);
2804887Schin 	GETLOCAL(vd,local);
2814887Schin 	if(ISLOCK(vd,local) || !addr)
2828462SApril.Chin@Sun.COM 	{	CLRINUSE(vd, inuse);
2834887Schin 		return -1L;
2848462SApril.Chin@Sun.COM 	}
2854887Schin 	SETLOCK(vd,local);
2864887Schin 
2874887Schin 	b = endb = NIL(Block_t*);
2884887Schin 	for(seg = vd->seg; seg; seg = seg->next)
2894887Schin 	{	b = SEGBLOCK(seg);
2904887Schin 		endb = (Block_t*)(seg->baddr - sizeof(Head_t));
2914887Schin 		if((Vmuchar_t*)addr > (Vmuchar_t*)b &&
2924887Schin 		   (Vmuchar_t*)addr < (Vmuchar_t*)endb)
2934887Schin 			break;
2944887Schin 	}
2954887Schin 	if(!seg)
2964887Schin 		goto done;
2974887Schin 
2984887Schin 	if(local)	/* must be vmfree or vmresize checking address */
2994887Schin 	{	if(DBSEG(addr) == seg)
3004887Schin 		{	b = DBBLOCK(addr);
3014887Schin 			if(ISBUSY(SIZE(b)) && !ISJUNK(SIZE(b)) )
3024887Schin 				offset = 0;
3034887Schin 			else	offset = -2L;
3044887Schin 		}
3054887Schin 		goto done;
3064887Schin 	}
3074887Schin 
3084887Schin 	while(b < endb)
3094887Schin 	{	data = (Vmuchar_t*)DATA(b);
3104887Schin 		if((Vmuchar_t*)addr >= data && (Vmuchar_t*)addr < data+SIZE(b))
3114887Schin 		{	if(ISBUSY(SIZE(b)) && !ISJUNK(SIZE(b)) )
3124887Schin 			{	data = DB2DEBUG(data);
3134887Schin 				if((Vmuchar_t*)addr >= data &&
3144887Schin 				   (Vmuchar_t*)addr < data+DBSIZE(data))
3154887Schin 					offset =  (Vmuchar_t*)addr - data;
3164887Schin 			}
3174887Schin 			goto done;
3184887Schin 		}
3194887Schin 
3204887Schin 		b = (Block_t*)((Vmuchar_t*)DATA(b) + (SIZE(b)&~BITS) );
3214887Schin 	}
3224887Schin 
3234887Schin done:
3244887Schin 	CLRLOCK(vd,local);
3258462SApril.Chin@Sun.COM 	CLRINUSE(vd, inuse);
3264887Schin 	return offset;
3274887Schin }
3284887Schin 
3294887Schin 
3304887Schin #if __STD_C
dbsize(Vmalloc_t * vm,Void_t * addr)3314887Schin static long dbsize(Vmalloc_t* vm, Void_t* addr)
3324887Schin #else
3334887Schin static long dbsize(vm, addr)
3344887Schin Vmalloc_t*	vm;
3354887Schin Void_t*		addr;
3364887Schin #endif
3374887Schin {
3384887Schin 	reg Block_t	*b, *endb;
3394887Schin 	reg Seg_t*	seg;
3404887Schin 	reg long	size;
3414887Schin 	reg Vmdata_t*	vd = vm->data;
3428462SApril.Chin@Sun.COM 	reg int		inuse;
3434887Schin 
3448462SApril.Chin@Sun.COM 	SETINUSE(vd, inuse);
3454887Schin 	if(ISLOCK(vd,0))
3468462SApril.Chin@Sun.COM 	{	CLRINUSE(vd, inuse);
3474887Schin 		return -1L;
3488462SApril.Chin@Sun.COM 	}
3494887Schin 	SETLOCK(vd,0);
3504887Schin 
3514887Schin 	size = -1L;
3524887Schin 	for(seg = vd->seg; seg; seg = seg->next)
3534887Schin 	{	b = SEGBLOCK(seg);
3544887Schin 		endb = (Block_t*)(seg->baddr - sizeof(Head_t));
3554887Schin 		if((Vmuchar_t*)addr <= (Vmuchar_t*)b ||
3564887Schin 		   (Vmuchar_t*)addr >= (Vmuchar_t*)endb)
3574887Schin 			continue;
3584887Schin 		while(b < endb)
3594887Schin 		{	if(addr == (Void_t*)DB2DEBUG(DATA(b)))
3604887Schin 			{	if(ISBUSY(SIZE(b)) && !ISJUNK(SIZE(b)) )
3614887Schin 					size = (long)DBSIZE(addr);
3624887Schin 				goto done;
3634887Schin 			}
3644887Schin 
3654887Schin 			b = (Block_t*)((Vmuchar_t*)DATA(b) + (SIZE(b)&~BITS) );
3664887Schin 		}
3674887Schin 	}
3684887Schin done:
3694887Schin 	CLRLOCK(vd,0);
3708462SApril.Chin@Sun.COM 	CLRINUSE(vd, inuse);
3714887Schin 	return size;
3724887Schin }
3734887Schin 
3744887Schin #if __STD_C
dballoc(Vmalloc_t * vm,size_t size)3754887Schin static Void_t* dballoc(Vmalloc_t* vm, size_t size)
3764887Schin #else
3774887Schin static Void_t* dballoc(vm, size)
3784887Schin Vmalloc_t*	vm;
3794887Schin size_t		size;
3804887Schin #endif
3814887Schin {
3824887Schin 	reg size_t		s;
3834887Schin 	reg Vmuchar_t*		data;
3844887Schin 	reg char*		file;
3854887Schin 	reg int			line;
3864887Schin 	reg Void_t*		func;
3874887Schin 	reg Vmdata_t*		vd = vm->data;
3888462SApril.Chin@Sun.COM 	reg int			inuse;
3894887Schin 
3908462SApril.Chin@Sun.COM 	SETINUSE(vd, inuse);
3914887Schin 	VMFLF(vm,file,line,func);
3924887Schin 
3934887Schin 	if(ISLOCK(vd,0) )
3944887Schin 	{	dbwarn(vm,NIL(Vmuchar_t*),0,file,line,func,DB_ALLOC);
3958462SApril.Chin@Sun.COM 		CLRINUSE(vd, inuse);
3964887Schin 		return NIL(Void_t*);
3974887Schin 	}
3984887Schin 	SETLOCK(vd,0);
3994887Schin 
4004887Schin 	if(vd->mode&VM_DBCHECK)
4014887Schin 		vmdbcheck(vm);
4024887Schin 
4034887Schin 	s = ROUND(size,ALIGN) + DB_EXTRA;
4044887Schin 	if(s < sizeof(Body_t))	/* no tiny blocks during Vmdebug */
4054887Schin 		s = sizeof(Body_t);
4064887Schin 
4074887Schin 	if(!(data = (Vmuchar_t*)KPVALLOC(vm,s,(*(Vmbest->allocf))) ) )
4084887Schin 	{	dbwarn(vm,NIL(Vmuchar_t*),DB_ALLOC,file,line,func,DB_ALLOC);
4094887Schin 		goto done;
4104887Schin 	}
4114887Schin 
4124887Schin 	data = DB2DEBUG(data);
4134887Schin 	dbsetinfo(data,size,file,line);
4144887Schin 
4154887Schin 	if((vd->mode&VM_TRACE) && _Vmtrace)
4164887Schin 	{	vm->file = file; vm->line = line; vm->func = func;
4174887Schin 		(*_Vmtrace)(vm,NIL(Vmuchar_t*),data,size,0);
4184887Schin 	}
4194887Schin 
4204887Schin 	if(Dbnwatch > 0 )
4214887Schin 		dbwatch(vm,data,file,line,func,DB_ALLOC);
4224887Schin 
4234887Schin done:
4244887Schin 	CLRLOCK(vd,0);
4254887Schin 	ANNOUNCE(0, vm, VM_ALLOC, (Void_t*)data, vm->disc);
4268462SApril.Chin@Sun.COM 	CLRINUSE(vd, inuse);
4274887Schin 	return (Void_t*)data;
4284887Schin }
4294887Schin 
4304887Schin 
4314887Schin #if __STD_C
dbfree(Vmalloc_t * vm,Void_t * data)4324887Schin static int dbfree(Vmalloc_t* vm, Void_t* data )
4334887Schin #else
4344887Schin static int dbfree(vm, data )
4354887Schin Vmalloc_t*	vm;
4364887Schin Void_t*		data;
4374887Schin #endif
4384887Schin {
4394887Schin 	char*		file;
4404887Schin 	int		line;
4414887Schin 	Void_t*		func;
4424887Schin 	reg long	offset;
4434887Schin 	reg int		rv, *ip, *endip;
4444887Schin 	reg Vmdata_t*	vd = vm->data;
4458462SApril.Chin@Sun.COM 	reg int		inuse;
4464887Schin 
4478462SApril.Chin@Sun.COM 	SETINUSE(vd, inuse);
4484887Schin 	VMFLF(vm,file,line,func);
4494887Schin 
4504887Schin 	if(!data)
4518462SApril.Chin@Sun.COM 	{	CLRINUSE(vd, inuse);
4524887Schin 		return 0;
4538462SApril.Chin@Sun.COM 	}
4544887Schin 
4554887Schin 	if(ISLOCK(vd,0) )
4564887Schin 	{	dbwarn(vm,NIL(Vmuchar_t*),0,file,line,func,DB_FREE);
4578462SApril.Chin@Sun.COM 		CLRINUSE(vd, inuse);
4584887Schin 		return -1;
4594887Schin 	}
4604887Schin 	SETLOCK(vd,0);
4614887Schin 
4624887Schin 	if(vd->mode&VM_DBCHECK)
4634887Schin 		vmdbcheck(vm);
4644887Schin 
4654887Schin 	if((offset = KPVADDR(vm,data,dbaddr)) != 0)
466*12068SRoger.Faulkner@Oracle.COM 	{	dbwarn(vm,(Vmuchar_t*)data,offset == -1L ? 0 : 1,file,line,func,DB_FREE);
467*12068SRoger.Faulkner@Oracle.COM 		if(vm->disc->exceptf)
4684887Schin 			(void)(*vm->disc->exceptf)(vm,VM_BADADDR,data,vm->disc);
4694887Schin 		CLRLOCK(vd,0);
4708462SApril.Chin@Sun.COM 		CLRINUSE(vd, inuse);
4714887Schin 		return -1;
4724887Schin 	}
4734887Schin 
4744887Schin 	if(Dbnwatch > 0)
4754887Schin 		dbwatch(vm,data,file,line,func,DB_FREE);
4764887Schin 
4774887Schin 	if((vd->mode&VM_TRACE) && _Vmtrace)
4784887Schin 	{	vm->file = file; vm->line = line; vm->func = func;
4794887Schin 		(*_Vmtrace)(vm,(Vmuchar_t*)data,NIL(Vmuchar_t*),DBSIZE(data),0);
4804887Schin 	}
4814887Schin 
4824887Schin 	/* clear free space */
4834887Schin 	ip = (int*)data;
4844887Schin 	endip = ip + (DBSIZE(data)+sizeof(int)-1)/sizeof(int);
4854887Schin 	while(ip < endip)
4864887Schin 		*ip++ = 0;
4874887Schin 
4884887Schin 	rv = KPVFREE((vm), (Void_t*)DB2BEST(data), (*Vmbest->freef));
4894887Schin 	CLRLOCK(vd,0);
4904887Schin 	ANNOUNCE(0, vm, VM_FREE, data, vm->disc);
4918462SApril.Chin@Sun.COM 	CLRINUSE(vd, inuse);
4924887Schin 	return rv;
4934887Schin }
4944887Schin 
4954887Schin /*	Resizing an existing block */
4964887Schin #if __STD_C
dbresize(Vmalloc_t * vm,Void_t * addr,reg size_t size,int type)4974887Schin static Void_t* dbresize(Vmalloc_t* vm, Void_t* addr, reg size_t size, int type)
4984887Schin #else
4994887Schin static Void_t* dbresize(vm,addr,size,type)
5004887Schin Vmalloc_t*	vm;		/* region allocating from	*/
5014887Schin Void_t*		addr;		/* old block of data		*/
5024887Schin reg size_t	size;		/* new size			*/
5034887Schin int		type;		/* !=0 for movable, >0 for copy	*/
5044887Schin #endif
5054887Schin {
5064887Schin 	reg Vmuchar_t*	data;
5074887Schin 	reg size_t	s, oldsize;
5084887Schin 	reg long	offset;
5094887Schin 	char		*file, *oldfile;
5104887Schin 	int		line, oldline;
5114887Schin 	Void_t*		func;
5124887Schin 	reg Vmdata_t*	vd = vm->data;
5138462SApril.Chin@Sun.COM 	reg int		inuse;
5144887Schin 
5158462SApril.Chin@Sun.COM 	SETINUSE(vd, inuse);
5164887Schin 	if(!addr)
5174887Schin 	{	oldsize = 0;
5184887Schin 		data = (Vmuchar_t*)dballoc(vm,size);
5194887Schin 		goto done;
5204887Schin 	}
5214887Schin 	if(size == 0)
5224887Schin 	{	(void)dbfree(vm,addr);
5238462SApril.Chin@Sun.COM 		CLRINUSE(vd, inuse);
5244887Schin 		return NIL(Void_t*);
5254887Schin 	}
5264887Schin 
5274887Schin 	VMFLF(vm,file,line,func);
5284887Schin 
5294887Schin 	if(ISLOCK(vd,0) )
5304887Schin 	{	dbwarn(vm,NIL(Vmuchar_t*),0,file,line,func,DB_RESIZE);
5318462SApril.Chin@Sun.COM 		CLRINUSE(vd, inuse);
5324887Schin 		return NIL(Void_t*);
5334887Schin 	}
5344887Schin 	SETLOCK(vd,0);
5354887Schin 
5364887Schin 	if(vd->mode&VM_DBCHECK)
5374887Schin 		vmdbcheck(vm);
5384887Schin 
5394887Schin 	if((offset = KPVADDR(vm,addr,dbaddr)) != 0)
540*12068SRoger.Faulkner@Oracle.COM 	{	dbwarn(vm,(Vmuchar_t*)addr,offset == -1L ? 0 : 1,file,line,func,DB_RESIZE);
541*12068SRoger.Faulkner@Oracle.COM 		if(vm->disc->exceptf)
5424887Schin 			(void)(*vm->disc->exceptf)(vm,VM_BADADDR,addr,vm->disc);
5434887Schin 		CLRLOCK(vd,0);
5448462SApril.Chin@Sun.COM 		CLRINUSE(vd, inuse);
5454887Schin 		return NIL(Void_t*);
5464887Schin 	}
5474887Schin 
5484887Schin 	if(Dbnwatch > 0)
5494887Schin 		dbwatch(vm,addr,file,line,func,DB_RESIZE);
5504887Schin 
5514887Schin 	/* Vmbest data block */
5524887Schin 	data = DB2BEST(addr);
5534887Schin 	oldsize = DBSIZE(addr);
5544887Schin 	oldfile = DBFILE(addr);
5554887Schin 	oldline = DBLINE(addr);
5564887Schin 
5574887Schin 	/* do the resize */
5584887Schin 	s = ROUND(size,ALIGN) + DB_EXTRA;
5594887Schin 	if(s < sizeof(Body_t))
5604887Schin 		s = sizeof(Body_t);
5614887Schin 	data = (Vmuchar_t*)KPVRESIZE(vm,(Void_t*)data,s,
5624887Schin 				 (type&~VM_RSZERO),(*(Vmbest->resizef)) );
5634887Schin 	if(!data) /* failed, reset data for old block */
5644887Schin 	{	dbwarn(vm,NIL(Vmuchar_t*),DB_ALLOC,file,line,func,DB_RESIZE);
5654887Schin 		dbsetinfo((Vmuchar_t*)addr,oldsize,oldfile,oldline);
5664887Schin 	}
5674887Schin 	else
5684887Schin 	{	data = DB2DEBUG(data);
5694887Schin 		dbsetinfo(data,size,file,line);
5704887Schin 
5714887Schin 		if((vd->mode&VM_TRACE) && _Vmtrace)
5724887Schin 		{	vm->file = file; vm->line = line;
5734887Schin 			(*_Vmtrace)(vm,(Vmuchar_t*)addr,data,size,0);
5744887Schin 		}
5754887Schin 		if(Dbnwatch > 0)
5764887Schin 			dbwatch(vm,data,file,line,func,DB_RESIZED);
5774887Schin 	}
5784887Schin 
5794887Schin 	CLRLOCK(vd,0);
5804887Schin 	ANNOUNCE(0, vm, VM_RESIZE, (Void_t*)data, vm->disc);
5814887Schin 
5824887Schin done:	if(data && (type&VM_RSZERO) && size > oldsize)
5834887Schin 	{	reg Vmuchar_t *d = data+oldsize, *ed = data+size;
5844887Schin 		do { *d++ = 0; } while(d < ed);
5854887Schin 	}
5868462SApril.Chin@Sun.COM 	CLRINUSE(vd, inuse);
5874887Schin 	return (Void_t*)data;
5884887Schin }
5894887Schin 
5904887Schin /* compact any residual free space */
5914887Schin #if __STD_C
dbcompact(Vmalloc_t * vm)5924887Schin static int dbcompact(Vmalloc_t* vm)
5934887Schin #else
5944887Schin static int dbcompact(vm)
5954887Schin Vmalloc_t*	vm;
5964887Schin #endif
5974887Schin {
5984887Schin 	return (*(Vmbest->compactf))(vm);
5994887Schin }
6004887Schin 
6014887Schin /* check for memory overwrites over all live blocks */
6024887Schin #if __STD_C
vmdbcheck(Vmalloc_t * vm)6034887Schin int vmdbcheck(Vmalloc_t* vm)
6044887Schin #else
6054887Schin int vmdbcheck(vm)
6064887Schin Vmalloc_t*	vm;
6074887Schin #endif
6084887Schin {
6094887Schin 	reg Block_t	*b, *endb;
6104887Schin 	reg Seg_t*	seg;
6114887Schin 	int		rv;
6124887Schin 	reg Vmdata_t*	vd = vm->data;
6134887Schin 
6144887Schin 	/* check the meta-data of this region */
6154887Schin 	if(vd->mode & (VM_MTDEBUG|VM_MTBEST|VM_MTPROFILE))
6164887Schin 	{	if(_vmbestcheck(vd, NIL(Block_t*)) < 0)
6174887Schin 			return -1;
6184887Schin 		if(!(vd->mode&VM_MTDEBUG))
6194887Schin 			return 0;
6204887Schin 	}
6214887Schin 	else	return -1;
6224887Schin 
6234887Schin 	rv = 0;
6244887Schin 	for(seg = vd->seg; seg; seg = seg->next)
6254887Schin 	{	b = SEGBLOCK(seg);
6264887Schin 		endb = (Block_t*)(seg->baddr - sizeof(Head_t));
6274887Schin 		while(b < endb)
6284887Schin 		{	reg Vmuchar_t	*data, *begp, *endp;
6294887Schin 
6304887Schin 			if(ISJUNK(SIZE(b)) || !ISBUSY(SIZE(b)))
6314887Schin 				goto next;
6324887Schin 
6334887Schin 			data = DB2DEBUG(DATA(b));
6344887Schin 			if(DBISBAD(data))	/* seen this before */
6354887Schin 			{	rv += 1;
6364887Schin 				goto next;
6374887Schin 			}
6384887Schin 
6394887Schin 			DBHEAD(data,begp,endp);
6404887Schin 			for(; begp < endp; ++begp)
6414887Schin 				if(*begp != DB_MAGIC)
6424887Schin 					goto set_bad;
6434887Schin 
6444887Schin 			DBTAIL(data,begp,endp);
6454887Schin 			for(; begp < endp; ++begp)
6464887Schin 			{	if(*begp == DB_MAGIC)
6474887Schin 					continue;
6484887Schin 			set_bad:
6494887Schin 				dbwarn(vm,data,begp-data,NIL(char*),0,0,DB_CHECK);
6504887Schin 				DBSETBAD(data);
6514887Schin 				rv += 1;
6524887Schin 				goto next;
6534887Schin 			}
6544887Schin 
6554887Schin 		next:	b = (Block_t*)((Vmuchar_t*)DATA(b) + (SIZE(b)&~BITS));
6564887Schin 		}
6574887Schin 	}
6584887Schin 
6594887Schin 	return rv;
6604887Schin }
6614887Schin 
6624887Schin /* set/delete an address to watch */
6634887Schin #if __STD_C
vmdbwatch(Void_t * addr)6644887Schin Void_t* vmdbwatch(Void_t* addr)
6654887Schin #else
6664887Schin Void_t* vmdbwatch(addr)
6674887Schin Void_t*		addr;	/* address to insert			*/
6684887Schin #endif
6694887Schin {
6704887Schin 	reg int		n;
6714887Schin 	reg Void_t*	out;
6724887Schin 
6734887Schin 	out = NIL(Void_t*);
6744887Schin 	if(!addr)
6754887Schin 		Dbnwatch = 0;
6764887Schin 	else
6774887Schin 	{	for(n = Dbnwatch - 1; n >= 0; --n)
6784887Schin 			if(Dbwatch[n] == addr)
6794887Schin 				break;
6804887Schin 		if(n < 0)	/* insert */
6814887Schin 		{	if(Dbnwatch == S_WATCH)
6824887Schin 			{	/* delete left-most */
6834887Schin 				out = Dbwatch[0];
6844887Schin 				Dbnwatch -= 1;
6854887Schin 				for(n = 0; n < Dbnwatch; ++n)
6864887Schin 					Dbwatch[n] = Dbwatch[n+1];
6874887Schin 			}
6884887Schin 			Dbwatch[Dbnwatch] = addr;
6894887Schin 			Dbnwatch += 1;
6904887Schin 		}
6914887Schin 	}
6924887Schin 	return out;
6934887Schin }
6944887Schin 
6954887Schin #if __STD_C
dbalign(Vmalloc_t * vm,size_t size,size_t align)6964887Schin static Void_t* dbalign(Vmalloc_t* vm, size_t size, size_t align)
6974887Schin #else
6984887Schin static Void_t* dbalign(vm, size, align)
6994887Schin Vmalloc_t*	vm;
7004887Schin size_t		size;
7014887Schin size_t		align;
7024887Schin #endif
7034887Schin {
7044887Schin 	reg Vmuchar_t*		data;
7054887Schin 	reg size_t		s;
7064887Schin 	reg char*		file;
7074887Schin 	reg int			line;
7084887Schin 	reg Void_t*		func;
7094887Schin 	reg Vmdata_t*		vd = vm->data;
7108462SApril.Chin@Sun.COM 	reg int			inuse;
7114887Schin 
7128462SApril.Chin@Sun.COM 	SETINUSE(vd, inuse);
7134887Schin 	VMFLF(vm,file,line,func);
7144887Schin 
7154887Schin 	if(size <= 0 || align <= 0)
7168462SApril.Chin@Sun.COM 	{	CLRINUSE(vd, inuse);
7174887Schin 		return NIL(Void_t*);
7188462SApril.Chin@Sun.COM 	}
7194887Schin 
7204887Schin 	if(ISLOCK(vd,0) )
7218462SApril.Chin@Sun.COM 	{	CLRINUSE(vd, inuse);
7224887Schin 		return NIL(Void_t*);
7238462SApril.Chin@Sun.COM 	}
7244887Schin 	SETLOCK(vd,0);
7254887Schin 
7264887Schin 	if((s = ROUND(size,ALIGN) + DB_EXTRA) < sizeof(Body_t))
7274887Schin 		s = sizeof(Body_t);
7284887Schin 
7294887Schin 	if(!(data = (Vmuchar_t*)KPVALIGN(vm,s,align,(*(Vmbest->alignf)))) )
7304887Schin 		goto done;
7314887Schin 
7324887Schin 	data += DB_HEAD;
7334887Schin 	dbsetinfo(data,size,file,line);
7344887Schin 
7354887Schin 	if((vd->mode&VM_TRACE) && _Vmtrace)
7364887Schin 	{	vm->file = file; vm->line = line; vm->func = func;
7374887Schin 		(*_Vmtrace)(vm,NIL(Vmuchar_t*),data,size,align);
7384887Schin 	}
7394887Schin 
7404887Schin done:
7414887Schin 	CLRLOCK(vd,0);
7424887Schin 	ANNOUNCE(0, vm, VM_ALLOC, (Void_t*)data, vm->disc);
7438462SApril.Chin@Sun.COM 	CLRINUSE(vd, inuse);
7444887Schin 	return (Void_t*)data;
7454887Schin }
7464887Schin 
747*12068SRoger.Faulkner@Oracle.COM /* print statistics of region vm. If vm is NULL, use Vmregion */
748*12068SRoger.Faulkner@Oracle.COM #if __STD_C
vmdbstat(Vmalloc_t * vm)749*12068SRoger.Faulkner@Oracle.COM ssize_t vmdbstat(Vmalloc_t* vm)
750*12068SRoger.Faulkner@Oracle.COM #else
751*12068SRoger.Faulkner@Oracle.COM ssize_t vmdbstat(vm)
752*12068SRoger.Faulkner@Oracle.COM Vmalloc_t*	vm;
753*12068SRoger.Faulkner@Oracle.COM #endif
754*12068SRoger.Faulkner@Oracle.COM {	Vmstat_t	st;
755*12068SRoger.Faulkner@Oracle.COM 	char		buf[1024], *bufp;
756*12068SRoger.Faulkner@Oracle.COM 
757*12068SRoger.Faulkner@Oracle.COM 	vmstat(vm ? vm : Vmregion, &st);
758*12068SRoger.Faulkner@Oracle.COM 	bufp = buf;
759*12068SRoger.Faulkner@Oracle.COM 	bufp = (*_Vmstrcpy)(bufp, "n_busy", '=');
760*12068SRoger.Faulkner@Oracle.COM 	bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)((Vmulong_t)st.n_busy,-1), ',');
761*12068SRoger.Faulkner@Oracle.COM 	bufp = (*_Vmstrcpy)(bufp, " s_busy", '=');
762*12068SRoger.Faulkner@Oracle.COM 	bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(VLONG(st.s_busy),-1), '\n');
763*12068SRoger.Faulkner@Oracle.COM 	bufp = (*_Vmstrcpy)(bufp, "n_free", '=');
764*12068SRoger.Faulkner@Oracle.COM 	bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)((Vmulong_t)st.n_free,-1), ',');
765*12068SRoger.Faulkner@Oracle.COM 	bufp = (*_Vmstrcpy)(bufp, " s_free", '=');
766*12068SRoger.Faulkner@Oracle.COM 	bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(VLONG(st.s_free),-1), '\n');
767*12068SRoger.Faulkner@Oracle.COM 	bufp = (*_Vmstrcpy)(bufp, "m_busy", '=');
768*12068SRoger.Faulkner@Oracle.COM 	bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(VLONG(st.m_busy),-1), ',');
769*12068SRoger.Faulkner@Oracle.COM 	bufp = (*_Vmstrcpy)(bufp, " m_free", '=');
770*12068SRoger.Faulkner@Oracle.COM 	bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(VLONG(st.m_free),-1), '\n');
771*12068SRoger.Faulkner@Oracle.COM 	bufp = (*_Vmstrcpy)(bufp, "n_segment", '=');
772*12068SRoger.Faulkner@Oracle.COM 	bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)((Vmulong_t)st.n_seg,-1), ',');
773*12068SRoger.Faulkner@Oracle.COM 	bufp = (*_Vmstrcpy)(bufp, " extent", '=');
774*12068SRoger.Faulkner@Oracle.COM 	bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(VLONG(st.extent),-1), '\n');
775*12068SRoger.Faulkner@Oracle.COM 	*bufp = 0;
776*12068SRoger.Faulkner@Oracle.COM 	write(Dbfd, buf, strlen(buf));
777*12068SRoger.Faulkner@Oracle.COM 	return strlen(buf);
778*12068SRoger.Faulkner@Oracle.COM }
779*12068SRoger.Faulkner@Oracle.COM 
7804887Schin static Vmethod_t _Vmdebug =
7814887Schin {
7824887Schin 	dballoc,
7834887Schin 	dbresize,
7844887Schin 	dbfree,
7854887Schin 	dbaddr,
7864887Schin 	dbsize,
7874887Schin 	dbcompact,
7884887Schin 	dbalign,
7894887Schin 	VM_MTDEBUG
7904887Schin };
7914887Schin 
7924887Schin __DEFINE__(Vmethod_t*,Vmdebug,&_Vmdebug);
7934887Schin 
7944887Schin #ifdef NoF
7954887Schin NoF(vmdebug)
7964887Schin #endif
7974887Schin 
7984887Schin #endif
799