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