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