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