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