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