1 #include "dat.h" 2 #include "fns.h" 3 #include "interp.h" 4 #include "error.h" 5 6 enum 7 { 8 MAXPOOL = 4 9 }; 10 11 #define left u.s.bhl 12 #define right u.s.bhr 13 #define fwd u.s.bhf 14 #define prev u.s.bhv 15 #define parent u.s.bhp 16 17 #define RESERVED 512*1024 18 19 struct Pool 20 { 21 char* name; 22 int pnum; 23 ulong maxsize; 24 int quanta; 25 int chunk; 26 int monitor; 27 ulong ressize; /* restricted size */ 28 ulong cursize; 29 ulong arenasize; 30 ulong hw; 31 Lock l; 32 Bhdr* root; 33 Bhdr* chain; 34 ulong nalloc; 35 ulong nfree; 36 int nbrk; 37 int lastfree; 38 void (*move)(void*, void*); 39 }; 40 41 void* initbrk(ulong); 42 43 struct 44 { 45 int n; 46 Pool pool[MAXPOOL]; 47 /* Lock l; */ 48 } table = { 49 3, 50 { 51 { "main", 0, 32*1024*1024, 31, 512*1024, 0, 31*1024*1024 }, 52 { "heap", 1, 32*1024*1024, 31, 512*1024, 0, 31*1024*1024 }, 53 { "image", 2, 64*1024*1024+256, 31, 4*1024*1024, 1, 63*1024*1024 }, 54 } 55 }; 56 57 Pool* mainmem = &table.pool[0]; 58 Pool* heapmem = &table.pool[1]; 59 Pool* imagmem = &table.pool[2]; 60 61 static void _auditmemloc(char *, void *); 62 void (*auditmemloc)(char *, void *) = _auditmemloc; 63 static void _poolfault(void *, char *, ulong); 64 void (*poolfault)(void *, char *, ulong) = _poolfault; 65 66 /* non tracing 67 * 68 enum { 69 Npadlong = 0, 70 MallocOffset = 0, 71 ReallocOffset = 0 72 }; 73 * 74 */ 75 76 /* tracing */ 77 enum { 78 Npadlong = 2, 79 MallocOffset = 0, 80 ReallocOffset = 1 81 }; 82 83 enum { 84 Monitor = 1 85 }; 86 87 void (*memmonitor)(int, ulong, ulong, ulong) = nil; 88 #define MM(v,pc,base,size) if(!Monitor || memmonitor==nil){} else memmonitor((v),(pc),(base),(size)) 89 90 #define CKLEAK 0 91 int ckleak; 92 #define ML(v, sz, pc) if(CKLEAK && ckleak && v){ if(sz) fprint(2, "%lux %lux %lux\n", (ulong)v, (ulong)sz, (ulong)pc); else fprint(2, "%lux\n", (ulong)v); } 93 94 int 95 memusehigh(void) 96 { 97 return mainmem->cursize > mainmem->ressize || 98 heapmem->cursize > heapmem->ressize || 99 0 && imagmem->cursize > imagmem->ressize; 100 } 101 102 int 103 memlow(void) 104 { 105 return heapmem->cursize > (heapmem->maxsize)/2; 106 } 107 108 int 109 poolsetsize(char *s, int size) 110 { 111 int i; 112 113 for(i = 0; i < table.n; i++) { 114 if(strcmp(table.pool[i].name, s) == 0) { 115 table.pool[i].maxsize = size; 116 table.pool[i].ressize = size-RESERVED; 117 if(size < RESERVED) 118 panic("not enough memory"); 119 return 1; 120 } 121 } 122 return 0; 123 } 124 125 void 126 poolimmutable(void *v) 127 { 128 Bhdr *b; 129 130 D2B(b, v); 131 b->magic = MAGIC_I; 132 } 133 134 void 135 poolmutable(void *v) 136 { 137 Bhdr *b; 138 139 D2B(b, v); 140 b->magic = MAGIC_A; 141 ((Heap*)v)->color = mutator; 142 } 143 144 char* 145 poolname(Pool *p) 146 { 147 return p->name; 148 } 149 150 Bhdr* 151 poolchain(Pool *p) 152 { 153 return p->chain; 154 } 155 156 void 157 pooldel(Pool *p, Bhdr *t) 158 { 159 Bhdr *s, *f, *rp, *q; 160 161 if(t->parent == nil && p->root != t) { 162 t->prev->fwd = t->fwd; 163 t->fwd->prev = t->prev; 164 return; 165 } 166 167 if(t->fwd != t) { 168 f = t->fwd; 169 s = t->parent; 170 f->parent = s; 171 if(s == nil) 172 p->root = f; 173 else { 174 if(s->left == t) 175 s->left = f; 176 else 177 s->right = f; 178 } 179 180 rp = t->left; 181 f->left = rp; 182 if(rp != nil) 183 rp->parent = f; 184 rp = t->right; 185 f->right = rp; 186 if(rp != nil) 187 rp->parent = f; 188 189 t->prev->fwd = t->fwd; 190 t->fwd->prev = t->prev; 191 return; 192 } 193 194 if(t->left == nil) 195 rp = t->right; 196 else { 197 if(t->right == nil) 198 rp = t->left; 199 else { 200 f = t; 201 rp = t->right; 202 s = rp->left; 203 while(s != nil) { 204 f = rp; 205 rp = s; 206 s = rp->left; 207 } 208 if(f != t) { 209 s = rp->right; 210 f->left = s; 211 if(s != nil) 212 s->parent = f; 213 s = t->right; 214 rp->right = s; 215 if(s != nil) 216 s->parent = rp; 217 } 218 s = t->left; 219 rp->left = s; 220 s->parent = rp; 221 } 222 } 223 q = t->parent; 224 if(q == nil) 225 p->root = rp; 226 else { 227 if(t == q->left) 228 q->left = rp; 229 else 230 q->right = rp; 231 } 232 if(rp != nil) 233 rp->parent = q; 234 } 235 236 void 237 pooladd(Pool *p, Bhdr *q) 238 { 239 int size; 240 Bhdr *tp, *t; 241 242 q->magic = MAGIC_F; 243 244 q->left = nil; 245 q->right = nil; 246 q->parent = nil; 247 q->fwd = q; 248 q->prev = q; 249 250 t = p->root; 251 if(t == nil) { 252 p->root = q; 253 return; 254 } 255 256 size = q->size; 257 258 tp = nil; 259 while(t != nil) { 260 if(size == t->size) { 261 q->prev = t->prev; 262 q->prev->fwd = q; 263 q->fwd = t; 264 t->prev = q; 265 return; 266 } 267 tp = t; 268 if(size < t->size) 269 t = t->left; 270 else 271 t = t->right; 272 } 273 274 q->parent = tp; 275 if(size < tp->size) 276 tp->left = q; 277 else 278 tp->right = q; 279 } 280 281 static void* 282 dopoolalloc(Pool *p, ulong asize, ulong pc) 283 { 284 Bhdr *q, *t; 285 int alloc, ldr, ns, frag; 286 int osize, size; 287 288 if(asize >= 1024*1024*1024) /* for sanity and to avoid overflow */ 289 return nil; 290 size = asize; 291 osize = size; 292 size = (size + BHDRSIZE + p->quanta) & ~(p->quanta); 293 294 lock(&p->l); 295 p->nalloc++; 296 297 t = p->root; 298 q = nil; 299 while(t) { 300 if(t->size == size) { 301 t = t->fwd; 302 pooldel(p, t); 303 t->magic = MAGIC_A; 304 p->cursize += t->size; 305 if(p->cursize > p->hw) 306 p->hw = p->cursize; 307 unlock(&p->l); 308 if(p->monitor) 309 MM(p->pnum, pc, (ulong)B2D(t), size); 310 return B2D(t); 311 } 312 if(size < t->size) { 313 q = t; 314 t = t->left; 315 } 316 else 317 t = t->right; 318 } 319 if(q != nil) { 320 pooldel(p, q); 321 q->magic = MAGIC_A; 322 frag = q->size - size; 323 if(frag < (size>>2) && frag < 0x8000) { 324 p->cursize += q->size; 325 if(p->cursize > p->hw) 326 p->hw = p->cursize; 327 unlock(&p->l); 328 if(p->monitor) 329 MM(p->pnum, pc, (ulong)B2D(q), size); 330 return B2D(q); 331 } 332 /* Split */ 333 ns = q->size - size; 334 q->size = size; 335 B2T(q)->hdr = q; 336 t = B2NB(q); 337 t->size = ns; 338 B2T(t)->hdr = t; 339 pooladd(p, t); 340 p->cursize += q->size; 341 if(p->cursize > p->hw) 342 p->hw = p->cursize; 343 unlock(&p->l); 344 if(p->monitor) 345 MM(p->pnum, pc, (ulong)B2D(q), size); 346 return B2D(q); 347 } 348 349 ns = p->chunk; 350 if(size > ns) 351 ns = size; 352 ldr = p->quanta+1; 353 354 alloc = ns+ldr+ldr; 355 p->arenasize += alloc; 356 if(p->arenasize > p->maxsize) { 357 p->arenasize -= alloc; 358 ns = p->maxsize-p->arenasize-ldr-ldr; 359 ns &= ~p->quanta; 360 if (ns < size) { 361 if(poolcompact(p)) { 362 unlock(&p->l); 363 return poolalloc(p, osize); 364 } 365 366 unlock(&p->l); 367 print("arena %s too large: size %d cursize %lud arenasize %lud maxsize %lud\n", 368 p->name, size, p->cursize, p->arenasize, p->maxsize); 369 return nil; 370 } 371 alloc = ns+ldr+ldr; 372 p->arenasize += alloc; 373 } 374 375 p->nbrk++; 376 t = (Bhdr *)sbrk(alloc); 377 if(t == (void*)-1) { 378 p->nbrk--; 379 unlock(&p->l); 380 return nil; 381 } 382 #ifdef __NetBSD__ 383 /* Align allocations to 16 bytes */ 384 { 385 const size_t off = __builtin_offsetof(struct Bhdr, u.data) 386 + Npadlong*sizeof(ulong); 387 struct assert_align { 388 unsigned int align_ok : (off % 8 == 0) ? 1 : -1; 389 }; 390 391 const ulong align = (off - 1) % 16; 392 t = (Bhdr *)(((ulong)t + align) & ~align); 393 } 394 #else 395 /* Double alignment */ 396 t = (Bhdr *)(((ulong)t + 7) & ~7); 397 #endif 398 if(p->chain != nil && (char*)t-(char*)B2LIMIT(p->chain)-ldr == 0){ 399 /* can merge chains */ 400 if(0)print("merging chains %p and %p in %s\n", p->chain, t, p->name); 401 q = B2LIMIT(p->chain); 402 q->magic = MAGIC_A; 403 q->size = alloc; 404 B2T(q)->hdr = q; 405 t = B2NB(q); 406 t->magic = MAGIC_E; 407 p->chain->csize += alloc; 408 p->cursize += alloc; 409 unlock(&p->l); 410 poolfree(p, B2D(q)); /* for backward merge */ 411 return poolalloc(p, osize); 412 } 413 414 t->magic = MAGIC_E; /* Make a leader */ 415 t->size = ldr; 416 t->csize = ns+ldr; 417 t->clink = p->chain; 418 p->chain = t; 419 B2T(t)->hdr = t; 420 t = B2NB(t); 421 422 t->magic = MAGIC_A; /* Make the block we are going to return */ 423 t->size = size; 424 B2T(t)->hdr = t; 425 q = t; 426 427 ns -= size; /* Free the rest */ 428 if(ns > 0) { 429 q = B2NB(t); 430 q->size = ns; 431 B2T(q)->hdr = q; 432 pooladd(p, q); 433 } 434 B2NB(q)->magic = MAGIC_E; /* Mark the end of the chunk */ 435 436 p->cursize += t->size; 437 if(p->cursize > p->hw) 438 p->hw = p->cursize; 439 unlock(&p->l); 440 if(p->monitor) 441 MM(p->pnum, pc, (ulong)B2D(t), size); 442 return B2D(t); 443 } 444 445 void * 446 poolalloc(Pool *p, ulong asize) 447 { 448 Prog *prog; 449 450 if(p->cursize > p->ressize && (prog = currun()) != nil && prog->flags&Prestricted) 451 return nil; 452 return dopoolalloc(p, asize, getcallerpc(&p)); 453 } 454 455 void 456 poolfree(Pool *p, void *v) 457 { 458 Bhdr *b, *c; 459 extern Bhdr *ptr; 460 461 D2B(b, v); 462 if(p->monitor) 463 MM(p->pnum|(1<<8), getcallerpc(&p), (ulong)v, b->size); 464 465 lock(&p->l); 466 p->nfree++; 467 p->cursize -= b->size; 468 c = B2NB(b); 469 if(c->magic == MAGIC_F) { /* Join forward */ 470 if(c == ptr) 471 ptr = b; 472 pooldel(p, c); 473 c->magic = 0; 474 b->size += c->size; 475 B2T(b)->hdr = b; 476 } 477 478 c = B2PT(b)->hdr; 479 if(c->magic == MAGIC_F) { /* Join backward */ 480 if(b == ptr) 481 ptr = c; 482 pooldel(p, c); 483 b->magic = 0; 484 c->size += b->size; 485 b = c; 486 B2T(b)->hdr = b; 487 } 488 pooladd(p, b); 489 unlock(&p->l); 490 } 491 492 void * 493 poolrealloc(Pool *p, void *v, ulong size) 494 { 495 Bhdr *b; 496 void *nv; 497 int osize; 498 499 if(size >= 1024*1024*1024) /* for sanity and to avoid overflow */ 500 return nil; 501 if(size == 0){ 502 poolfree(p, v); 503 return nil; 504 } 505 SET(osize); 506 if(v != nil){ 507 lock(&p->l); 508 D2B(b, v); 509 osize = b->size - BHDRSIZE; 510 unlock(&p->l); 511 if(osize >= size) 512 return v; 513 } 514 nv = poolalloc(p, size); 515 if(nv != nil && v != nil){ 516 memmove(nv, v, osize); 517 poolfree(p, v); 518 } 519 return nv; 520 } 521 522 ulong 523 poolmsize(Pool *p, void *v) 524 { 525 Bhdr *b; 526 ulong size; 527 528 if(v == nil) 529 return 0; 530 lock(&p->l); 531 D2B(b, v); 532 size = b->size - BHDRSIZE; 533 unlock(&p->l); 534 return size; 535 } 536 537 static ulong 538 poolmax(Pool *p) 539 { 540 Bhdr *t; 541 ulong size; 542 543 lock(&p->l); 544 size = p->maxsize - p->cursize; 545 t = p->root; 546 if(t != nil) { 547 while(t->right != nil) 548 t = t->right; 549 if(size < t->size) 550 size = t->size; 551 } 552 if(size >= BHDRSIZE) 553 size -= BHDRSIZE; 554 unlock(&p->l); 555 return size; 556 } 557 558 ulong 559 poolmaxsize(void) 560 { 561 int i; 562 ulong total; 563 564 total = 0; 565 for(i = 0; i < nelem(table.pool); i++) 566 total += table.pool[i].maxsize; 567 return total; 568 } 569 570 int 571 poolread(char *va, int count, ulong offset) 572 { 573 Pool *p; 574 int n, i, signed_off; 575 576 n = 0; 577 signed_off = offset; 578 for(i = 0; i < table.n; i++) { 579 p = &table.pool[i]; 580 n += snprint(va+n, count-n, "%11lud %11lud %11lud %11lud %11lud %11d %11lud %s\n", 581 p->cursize, 582 p->maxsize, 583 p->hw, 584 p->nalloc, 585 p->nfree, 586 p->nbrk, 587 poolmax(p), 588 p->name); 589 590 if(signed_off > 0) { 591 signed_off -= n; 592 if(signed_off < 0) { 593 memmove(va, va+n+signed_off, -signed_off); 594 n = -signed_off; 595 } 596 else 597 n = 0; 598 } 599 600 } 601 return n; 602 } 603 604 void* 605 smalloc(size_t size) 606 { 607 void *v; 608 609 for(;;){ 610 v = malloc(size); 611 if(v != nil) 612 break; 613 if(0) 614 print("smalloc waiting from %lux\n", getcallerpc(&size)); 615 osenter(); 616 osmillisleep(100); 617 osleave(); 618 } 619 setmalloctag(v, getcallerpc(&size)); 620 setrealloctag(v, 0); 621 return v; 622 } 623 624 void* 625 kmalloc(size_t size) 626 { 627 void *v; 628 629 v = dopoolalloc(mainmem, size+Npadlong*sizeof(ulong), getcallerpc(&size)); 630 if(v != nil){ 631 ML(v, size, getcallerpc(&size)); 632 if(Npadlong){ 633 v = (ulong*)v+Npadlong; 634 setmalloctag(v, getcallerpc(&size)); 635 setrealloctag(v, 0); 636 } 637 memset(v, 0, size); 638 MM(0, getcallerpc(&size), (ulong)v, size); 639 } 640 return v; 641 } 642 643 644 645 void* 646 malloc(size_t size) 647 { 648 void *v; 649 650 v = poolalloc(mainmem, size+Npadlong*sizeof(ulong)); 651 if(v != nil){ 652 ML(v, size, getcallerpc(&size)); 653 if(Npadlong){ 654 v = (ulong*)v+Npadlong; 655 setmalloctag(v, getcallerpc(&size)); 656 setrealloctag(v, 0); 657 } 658 memset(v, 0, size); 659 MM(0, getcallerpc(&size), (ulong)v, size); 660 } else 661 print("malloc failed from %lux\n", getcallerpc(&size)); 662 return v; 663 } 664 665 void* 666 mallocz(ulong size, int clr) 667 { 668 void *v; 669 670 v = poolalloc(mainmem, size+Npadlong*sizeof(ulong)); 671 if(v != nil){ 672 ML(v, size, getcallerpc(&size)); 673 if(Npadlong){ 674 v = (ulong*)v+Npadlong; 675 setmalloctag(v, getcallerpc(&size)); 676 setrealloctag(v, 0); 677 } 678 if(clr) 679 memset(v, 0, size); 680 MM(0, getcallerpc(&size), (ulong)v, size); 681 } else 682 print("mallocz failed from %lux\n", getcallerpc(&size)); 683 return v; 684 } 685 686 void 687 free(void *v) 688 { 689 Bhdr *b; 690 691 if(v != nil) { 692 if(Npadlong) 693 v = (ulong*)v-Npadlong; 694 D2B(b, v); 695 ML(v, 0, 0); 696 MM(1<<8|0, getcallerpc(&v), (ulong)((ulong*)v+Npadlong), b->size); 697 poolfree(mainmem, v); 698 } 699 } 700 701 void* 702 realloc(void *v, size_t size) 703 { 704 void *nv; 705 706 if(size == 0) 707 return malloc(size); /* temporary change until realloc calls can be checked */ 708 if(v != nil) 709 v = (ulong*)v-Npadlong; 710 if(Npadlong!=0 && size!=0) 711 size += Npadlong*sizeof(ulong); 712 nv = poolrealloc(mainmem, v, size); 713 ML(v, 0, 0); 714 ML(nv, size, getcallerpc(&v)); 715 if(nv != nil) { 716 nv = (ulong*)nv+Npadlong; 717 setrealloctag(nv, getcallerpc(&v)); 718 if(v == nil) 719 setmalloctag(v, getcallerpc(&v)); 720 } else 721 print("realloc failed from %lux\n", getcallerpc(&v)); 722 return nv; 723 } 724 725 void 726 setmalloctag(void *v, ulong pc) 727 { 728 ulong *u; 729 730 USED(v); 731 USED(pc); 732 if(Npadlong <= MallocOffset || v == nil) 733 return; 734 u = v; 735 u[-Npadlong+MallocOffset] = pc; 736 } 737 738 ulong 739 getmalloctag(void *v) 740 { 741 USED(v); 742 if(Npadlong <= MallocOffset) 743 return ~0; 744 return ((ulong*)v)[-Npadlong+MallocOffset]; 745 } 746 747 void 748 setrealloctag(void *v, ulong pc) 749 { 750 ulong *u; 751 752 USED(v); 753 USED(pc); 754 if(Npadlong <= ReallocOffset || v == nil) 755 return; 756 u = v; 757 u[-Npadlong+ReallocOffset] = pc; 758 } 759 760 ulong 761 getrealloctag(void *v) 762 { 763 USED(v); 764 if(Npadlong <= ReallocOffset) 765 return ((ulong*)v)[-Npadlong+ReallocOffset]; 766 return ~0; 767 } 768 769 ulong 770 msize(void *v) 771 { 772 if(v == nil) 773 return 0; 774 return poolmsize(mainmem, (ulong*)v-Npadlong)-Npadlong*sizeof(ulong); 775 } 776 777 void* 778 calloc(size_t n, size_t szelem) 779 { 780 return malloc(n*szelem); 781 } 782 783 /* 784 void 785 pooldump(Pool *p) 786 { 787 Bhdr *b, *base, *limit, *ptr; 788 789 b = p->chain; 790 if(b == nil) 791 return; 792 base = b; 793 ptr = b; 794 limit = B2LIMIT(b); 795 796 while(base != nil) { 797 print("\tbase #%.8lux ptr #%.8lux", base, ptr); 798 if(ptr->magic == MAGIC_A || ptr->magic == MAGIC_I) 799 print("\tA%.5d\n", ptr->size); 800 else if(ptr->magic == MAGIC_E) 801 print("\tE\tL#%.8lux\tS#%.8lux\n", ptr->clink, ptr->csize); 802 else 803 print("\tF%.5d\tL#%.8lux\tR#%.8lux\tF#%.8lux\tP#%.8lux\tT#%.8lux\n", 804 ptr->size, ptr->left, ptr->right, ptr->fwd, ptr->prev, ptr->parent); 805 ptr = B2NB(ptr); 806 if(ptr >= limit) { 807 print("link to #%.8lux\n", base->clink); 808 base = base->clink; 809 if(base == nil) 810 break; 811 ptr = base; 812 limit = B2LIMIT(base); 813 } 814 } 815 } 816 */ 817 818 void 819 poolsetcompact(Pool *p, void (*move)(void*, void*)) 820 { 821 p->move = move; 822 } 823 824 int 825 poolcompact(Pool *pool) 826 { 827 Bhdr *base, *limit, *ptr, *end, *next; 828 int compacted, nb; 829 830 if(pool->move == nil || pool->lastfree == pool->nfree) 831 return 0; 832 833 pool->lastfree = pool->nfree; 834 835 base = pool->chain; 836 ptr = B2NB(base); /* First Block in arena has clink */ 837 limit = B2LIMIT(base); 838 compacted = 0; 839 840 pool->root = nil; 841 end = ptr; 842 while(base != nil) { 843 next = B2NB(ptr); 844 if(ptr->magic == MAGIC_A || ptr->magic == MAGIC_I) { 845 if(ptr != end) { 846 memmove(end, ptr, ptr->size); 847 pool->move(B2D(ptr), B2D(end)); 848 compacted = 1; 849 } 850 end = B2NB(end); 851 } 852 if(next >= limit) { 853 nb = (uchar*)limit - (uchar*)end; 854 if(nb > 0){ 855 if(nb < pool->quanta+1){ 856 print("poolcompact: leftover too small\n"); 857 abort(); 858 } 859 end->size = nb; 860 B2T(end)->hdr = end; 861 pooladd(pool, end); 862 } 863 base = base->clink; 864 if(base == nil) 865 break; 866 ptr = B2NB(base); 867 end = ptr; /* could do better by copying between chains */ 868 limit = B2LIMIT(base); 869 } else 870 ptr = next; 871 } 872 873 return compacted; 874 } 875 876 static void 877 _poolfault(void *v, char *msg, ulong c) 878 { 879 auditmemloc(msg, v); 880 panic("%s %lux (from %lux/%lux)", msg, v, getcallerpc(&v), c); 881 } 882 883 static void 884 dumpvl(char *msg, ulong *v, int n) 885 { 886 int i, l; 887 888 l = print("%s at %p: ", msg, v); 889 for (i = 0; i < n; i++) { 890 if (l >= 60) { 891 print("\n"); 892 l = print(" %p: ", v); 893 } 894 l += print(" %lux", *v++); 895 } 896 print("\n"); 897 } 898 899 static void 900 corrupted(char *str, char *msg, Pool *p, Bhdr *b, void *v) 901 { 902 print("%s(%p): pool %s CORRUPT: %s at %p'%lud(magic=%lux)\n", 903 str, v, p->name, msg, b, b->size, b->magic); 904 dumpvl("bad Bhdr", (ulong *)((ulong)b & ~3)-4, 10); 905 } 906 907 static void 908 _auditmemloc(char *str, void *v) 909 { 910 Pool *p; 911 Bhdr *bc, *ec, *b, *nb, *fb = nil; 912 char *fmsg, *msg; 913 ulong fsz; 914 915 SET(fsz); 916 SET(fmsg); 917 for (p = &table.pool[0]; p < &table.pool[nelem(table.pool)]; p++) { 918 lock(&p->l); 919 for (bc = p->chain; bc != nil; bc = bc->clink) { 920 if (bc->magic != MAGIC_E) { 921 unlock(&p->l); 922 corrupted(str, "chain hdr!=MAGIC_E", p, bc, v); 923 goto nextpool; 924 } 925 ec = B2LIMIT(bc); 926 if (((Bhdr*)v >= bc) && ((Bhdr*)v < ec)) 927 goto found; 928 } 929 unlock(&p->l); 930 nextpool: ; 931 } 932 print("%s: %p not in pools\n", str, v); 933 return; 934 935 found: 936 for (b = bc; b < ec; b = nb) { 937 switch(b->magic) { 938 case MAGIC_F: 939 msg = "free blk"; 940 break; 941 case MAGIC_I: 942 msg = "immutable block"; 943 break; 944 case MAGIC_A: 945 msg = "block"; 946 break; 947 default: 948 if (b == bc && b->magic == MAGIC_E) { 949 msg = "pool hdr"; 950 break; 951 } 952 unlock(&p->l); 953 corrupted(str, "bad magic", p, b, v); 954 goto badchunk; 955 } 956 if (b->size <= 0 || (b->size & p->quanta)) { 957 unlock(&p->l); 958 corrupted(str, "bad size", p, b, v); 959 goto badchunk; 960 } 961 if (fb != nil) 962 break; 963 nb = B2NB(b); 964 if ((Bhdr*)v < nb) { 965 fb = b; 966 fsz = b->size; 967 fmsg = msg; 968 } 969 } 970 unlock(&p->l); 971 if (b >= ec) { 972 if (b > ec) 973 corrupted(str, "chain size mismatch", p, b, v); 974 else if (b->magic != MAGIC_E) 975 corrupted(str, "chain end!=MAGIC_E", p, b, v); 976 } 977 badchunk: 978 if (fb != nil) { 979 print("%s: %p in %s:", str, v, p->name); 980 if (fb == v) 981 print(" is %s '%lux\n", fmsg, fsz); 982 else 983 print(" in %s at %p'%lux\n", fmsg, fb, fsz); 984 dumpvl("area", (ulong *)((ulong)v & ~3)-4, 20); 985 } 986 } 987 988 char * 989 poolaudit(char*(*audit)(int, Bhdr *)) 990 { 991 Pool *p; 992 Bhdr *bc, *ec, *b; 993 char *r = nil; 994 995 for (p = &table.pool[0]; p < &table.pool[nelem(table.pool)]; p++) { 996 lock(&p->l); 997 for (bc = p->chain; bc != nil; bc = bc->clink) { 998 if (bc->magic != MAGIC_E) { 999 unlock(&p->l); 1000 return "bad chain hdr"; 1001 } 1002 ec = B2LIMIT(bc); 1003 for (b = bc; b < ec; b = B2NB(b)) { 1004 if (b->size <= 0 || (b->size & p->quanta)) 1005 r = "bad size in bhdr"; 1006 else 1007 switch(b->magic) { 1008 case MAGIC_E: 1009 if (b != bc) { 1010 r = "unexpected MAGIC_E"; 1011 break; 1012 } 1013 case MAGIC_F: 1014 case MAGIC_A: 1015 case MAGIC_I: 1016 r = audit(p->pnum, b); 1017 break; 1018 default: 1019 r = "bad magic"; 1020 } 1021 if (r != nil) { 1022 unlock(&p->l); 1023 return r; 1024 } 1025 } 1026 if (b != ec || b->magic != MAGIC_E) { 1027 unlock(&p->l); 1028 return "bad chain ending"; 1029 } 1030 } 1031 unlock(&p->l); 1032 } 1033 return r; 1034 } 1035