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 /* Double alignment */ 383 t = (Bhdr *)(((ulong)t + 7) & ~7); 384 385 if(p->chain != nil && (char*)t-(char*)B2LIMIT(p->chain)-ldr == 0){ 386 /* can merge chains */ 387 if(0)print("merging chains %p and %p in %s\n", p->chain, t, p->name); 388 q = B2LIMIT(p->chain); 389 q->magic = MAGIC_A; 390 q->size = alloc; 391 B2T(q)->hdr = q; 392 t = B2NB(q); 393 t->magic = MAGIC_E; 394 p->chain->csize += alloc; 395 p->cursize += alloc; 396 unlock(&p->l); 397 poolfree(p, B2D(q)); /* for backward merge */ 398 return poolalloc(p, osize); 399 } 400 401 t->magic = MAGIC_E; /* Make a leader */ 402 t->size = ldr; 403 t->csize = ns+ldr; 404 t->clink = p->chain; 405 p->chain = t; 406 B2T(t)->hdr = t; 407 t = B2NB(t); 408 409 t->magic = MAGIC_A; /* Make the block we are going to return */ 410 t->size = size; 411 B2T(t)->hdr = t; 412 q = t; 413 414 ns -= size; /* Free the rest */ 415 if(ns > 0) { 416 q = B2NB(t); 417 q->size = ns; 418 B2T(q)->hdr = q; 419 pooladd(p, q); 420 } 421 B2NB(q)->magic = MAGIC_E; /* Mark the end of the chunk */ 422 423 p->cursize += t->size; 424 if(p->cursize > p->hw) 425 p->hw = p->cursize; 426 unlock(&p->l); 427 if(p->monitor) 428 MM(p->pnum, pc, (ulong)B2D(t), size); 429 return B2D(t); 430 } 431 432 void * 433 poolalloc(Pool *p, ulong asize) 434 { 435 Prog *prog; 436 437 if(p->cursize > p->ressize && (prog = currun()) != nil && prog->flags&Prestricted) 438 return nil; 439 return dopoolalloc(p, asize, getcallerpc(&p)); 440 } 441 442 void 443 poolfree(Pool *p, void *v) 444 { 445 Bhdr *b, *c; 446 extern Bhdr *ptr; 447 448 D2B(b, v); 449 if(p->monitor) 450 MM(p->pnum|(1<<8), getcallerpc(&p), (ulong)v, b->size); 451 452 lock(&p->l); 453 p->nfree++; 454 p->cursize -= b->size; 455 c = B2NB(b); 456 if(c->magic == MAGIC_F) { /* Join forward */ 457 if(c == ptr) 458 ptr = b; 459 pooldel(p, c); 460 c->magic = 0; 461 b->size += c->size; 462 B2T(b)->hdr = b; 463 } 464 465 c = B2PT(b)->hdr; 466 if(c->magic == MAGIC_F) { /* Join backward */ 467 if(b == ptr) 468 ptr = c; 469 pooldel(p, c); 470 b->magic = 0; 471 c->size += b->size; 472 b = c; 473 B2T(b)->hdr = b; 474 } 475 pooladd(p, b); 476 unlock(&p->l); 477 } 478 479 void * 480 poolrealloc(Pool *p, void *v, ulong size) 481 { 482 Bhdr *b; 483 void *nv; 484 int osize; 485 486 if(size >= 1024*1024*1024) /* for sanity and to avoid overflow */ 487 return nil; 488 if(size == 0){ 489 poolfree(p, v); 490 return nil; 491 } 492 SET(osize); 493 if(v != nil){ 494 lock(&p->l); 495 D2B(b, v); 496 osize = b->size - BHDRSIZE; 497 unlock(&p->l); 498 if(osize >= size) 499 return v; 500 } 501 nv = poolalloc(p, size); 502 if(nv != nil && v != nil){ 503 memmove(nv, v, osize); 504 poolfree(p, v); 505 } 506 return nv; 507 } 508 509 ulong 510 poolmsize(Pool *p, void *v) 511 { 512 Bhdr *b; 513 ulong size; 514 515 if(v == nil) 516 return 0; 517 lock(&p->l); 518 D2B(b, v); 519 size = b->size - BHDRSIZE; 520 unlock(&p->l); 521 return size; 522 } 523 524 static ulong 525 poolmax(Pool *p) 526 { 527 Bhdr *t; 528 ulong size; 529 530 lock(&p->l); 531 size = p->maxsize - p->cursize; 532 t = p->root; 533 if(t != nil) { 534 while(t->right != nil) 535 t = t->right; 536 if(size < t->size) 537 size = t->size; 538 } 539 if(size >= BHDRSIZE) 540 size -= BHDRSIZE; 541 unlock(&p->l); 542 return size; 543 } 544 545 ulong 546 poolmaxsize(void) 547 { 548 int i; 549 ulong total; 550 551 total = 0; 552 for(i = 0; i < nelem(table.pool); i++) 553 total += table.pool[i].maxsize; 554 return total; 555 } 556 557 int 558 poolread(char *va, int count, ulong offset) 559 { 560 Pool *p; 561 int n, i, signed_off; 562 563 n = 0; 564 signed_off = offset; 565 for(i = 0; i < table.n; i++) { 566 p = &table.pool[i]; 567 n += snprint(va+n, count-n, "%11lud %11lud %11lud %11lud %11lud %11d %11lud %s\n", 568 p->cursize, 569 p->maxsize, 570 p->hw, 571 p->nalloc, 572 p->nfree, 573 p->nbrk, 574 poolmax(p), 575 p->name); 576 577 if(signed_off > 0) { 578 signed_off -= n; 579 if(signed_off < 0) { 580 memmove(va, va+n+signed_off, -signed_off); 581 n = -signed_off; 582 } 583 else 584 n = 0; 585 } 586 587 } 588 return n; 589 } 590 591 void* 592 smalloc(size_t size) 593 { 594 void *v; 595 596 for(;;){ 597 v = malloc(size); 598 if(v != nil) 599 break; 600 if(0) 601 print("smalloc waiting from %lux\n", getcallerpc(&size)); 602 osenter(); 603 osmillisleep(100); 604 osleave(); 605 } 606 setmalloctag(v, getcallerpc(&size)); 607 setrealloctag(v, 0); 608 return v; 609 } 610 611 void* 612 kmalloc(size_t size) 613 { 614 void *v; 615 616 v = dopoolalloc(mainmem, size+Npadlong*sizeof(ulong), getcallerpc(&size)); 617 if(v != nil){ 618 ML(v, size, getcallerpc(&size)); 619 if(Npadlong){ 620 v = (ulong*)v+Npadlong; 621 setmalloctag(v, getcallerpc(&size)); 622 setrealloctag(v, 0); 623 } 624 memset(v, 0, size); 625 MM(0, getcallerpc(&size), (ulong)v, size); 626 } 627 return v; 628 } 629 630 631 632 void* 633 malloc(size_t size) 634 { 635 void *v; 636 637 v = poolalloc(mainmem, size+Npadlong*sizeof(ulong)); 638 if(v != nil){ 639 ML(v, size, getcallerpc(&size)); 640 if(Npadlong){ 641 v = (ulong*)v+Npadlong; 642 setmalloctag(v, getcallerpc(&size)); 643 setrealloctag(v, 0); 644 } 645 memset(v, 0, size); 646 MM(0, getcallerpc(&size), (ulong)v, size); 647 } else 648 print("malloc failed from %lux\n", getcallerpc(&size)); 649 return v; 650 } 651 652 void* 653 mallocz(ulong size, int clr) 654 { 655 void *v; 656 657 v = poolalloc(mainmem, size+Npadlong*sizeof(ulong)); 658 if(v != nil){ 659 ML(v, size, getcallerpc(&size)); 660 if(Npadlong){ 661 v = (ulong*)v+Npadlong; 662 setmalloctag(v, getcallerpc(&size)); 663 setrealloctag(v, 0); 664 } 665 if(clr) 666 memset(v, 0, size); 667 MM(0, getcallerpc(&size), (ulong)v, size); 668 } else 669 print("mallocz failed from %lux\n", getcallerpc(&size)); 670 return v; 671 } 672 673 void 674 free(void *v) 675 { 676 Bhdr *b; 677 678 if(v != nil) { 679 if(Npadlong) 680 v = (ulong*)v-Npadlong; 681 D2B(b, v); 682 ML(v, 0, 0); 683 MM(1<<8|0, getcallerpc(&v), (ulong)((ulong*)v+Npadlong), b->size); 684 poolfree(mainmem, v); 685 } 686 } 687 688 void* 689 realloc(void *v, size_t size) 690 { 691 void *nv; 692 693 if(size == 0) 694 return malloc(size); /* temporary change until realloc calls can be checked */ 695 if(v != nil) 696 v = (ulong*)v-Npadlong; 697 if(Npadlong!=0 && size!=0) 698 size += Npadlong*sizeof(ulong); 699 nv = poolrealloc(mainmem, v, size); 700 ML(v, 0, 0); 701 ML(nv, size, getcallerpc(&v)); 702 if(nv != nil) { 703 nv = (ulong*)nv+Npadlong; 704 setrealloctag(nv, getcallerpc(&v)); 705 if(v == nil) 706 setmalloctag(v, getcallerpc(&v)); 707 } else 708 print("realloc failed from %lux\n", getcallerpc(&v)); 709 return nv; 710 } 711 712 void 713 setmalloctag(void *v, ulong pc) 714 { 715 ulong *u; 716 717 USED(v); 718 USED(pc); 719 if(Npadlong <= MallocOffset || v == nil) 720 return; 721 u = v; 722 u[-Npadlong+MallocOffset] = pc; 723 } 724 725 ulong 726 getmalloctag(void *v) 727 { 728 USED(v); 729 if(Npadlong <= MallocOffset) 730 return ~0; 731 return ((ulong*)v)[-Npadlong+MallocOffset]; 732 } 733 734 void 735 setrealloctag(void *v, ulong pc) 736 { 737 ulong *u; 738 739 USED(v); 740 USED(pc); 741 if(Npadlong <= ReallocOffset || v == nil) 742 return; 743 u = v; 744 u[-Npadlong+ReallocOffset] = pc; 745 } 746 747 ulong 748 getrealloctag(void *v) 749 { 750 USED(v); 751 if(Npadlong <= ReallocOffset) 752 return ((ulong*)v)[-Npadlong+ReallocOffset]; 753 return ~0; 754 } 755 756 ulong 757 msize(void *v) 758 { 759 if(v == nil) 760 return 0; 761 return poolmsize(mainmem, (ulong*)v-Npadlong)-Npadlong*sizeof(ulong); 762 } 763 764 void* 765 calloc(size_t n, size_t szelem) 766 { 767 return malloc(n*szelem); 768 } 769 770 /* 771 void 772 pooldump(Pool *p) 773 { 774 Bhdr *b, *base, *limit, *ptr; 775 776 b = p->chain; 777 if(b == nil) 778 return; 779 base = b; 780 ptr = b; 781 limit = B2LIMIT(b); 782 783 while(base != nil) { 784 print("\tbase #%.8lux ptr #%.8lux", base, ptr); 785 if(ptr->magic == MAGIC_A || ptr->magic == MAGIC_I) 786 print("\tA%.5d\n", ptr->size); 787 else if(ptr->magic == MAGIC_E) 788 print("\tE\tL#%.8lux\tS#%.8lux\n", ptr->clink, ptr->csize); 789 else 790 print("\tF%.5d\tL#%.8lux\tR#%.8lux\tF#%.8lux\tP#%.8lux\tT#%.8lux\n", 791 ptr->size, ptr->left, ptr->right, ptr->fwd, ptr->prev, ptr->parent); 792 ptr = B2NB(ptr); 793 if(ptr >= limit) { 794 print("link to #%.8lux\n", base->clink); 795 base = base->clink; 796 if(base == nil) 797 break; 798 ptr = base; 799 limit = B2LIMIT(base); 800 } 801 } 802 } 803 */ 804 805 void 806 poolsetcompact(Pool *p, void (*move)(void*, void*)) 807 { 808 p->move = move; 809 } 810 811 int 812 poolcompact(Pool *pool) 813 { 814 Bhdr *base, *limit, *ptr, *end, *next; 815 int compacted, nb; 816 817 if(pool->move == nil || pool->lastfree == pool->nfree) 818 return 0; 819 820 pool->lastfree = pool->nfree; 821 822 base = pool->chain; 823 ptr = B2NB(base); /* First Block in arena has clink */ 824 limit = B2LIMIT(base); 825 compacted = 0; 826 827 pool->root = nil; 828 end = ptr; 829 while(base != nil) { 830 next = B2NB(ptr); 831 if(ptr->magic == MAGIC_A || ptr->magic == MAGIC_I) { 832 if(ptr != end) { 833 memmove(end, ptr, ptr->size); 834 pool->move(B2D(ptr), B2D(end)); 835 compacted = 1; 836 } 837 end = B2NB(end); 838 } 839 if(next >= limit) { 840 nb = (uchar*)limit - (uchar*)end; 841 if(nb > 0){ 842 if(nb < pool->quanta+1){ 843 print("poolcompact: leftover too small\n"); 844 abort(); 845 } 846 end->size = nb; 847 B2T(end)->hdr = end; 848 pooladd(pool, end); 849 } 850 base = base->clink; 851 if(base == nil) 852 break; 853 ptr = B2NB(base); 854 end = ptr; /* could do better by copying between chains */ 855 limit = B2LIMIT(base); 856 } else 857 ptr = next; 858 } 859 860 return compacted; 861 } 862 863 static void 864 _poolfault(void *v, char *msg, ulong c) 865 { 866 auditmemloc(msg, v); 867 panic("%s %lux (from %lux/%lux)", msg, v, getcallerpc(&v), c); 868 } 869 870 static void 871 dumpvl(char *msg, ulong *v, int n) 872 { 873 int i, l; 874 875 l = print("%s at %p: ", msg, v); 876 for (i = 0; i < n; i++) { 877 if (l >= 60) { 878 print("\n"); 879 l = print(" %p: ", v); 880 } 881 l += print(" %lux", *v++); 882 } 883 print("\n"); 884 } 885 886 static void 887 corrupted(char *str, char *msg, Pool *p, Bhdr *b, void *v) 888 { 889 print("%s(%p): pool %s CORRUPT: %s at %p'%lud(magic=%lux)\n", 890 str, v, p->name, msg, b, b->size, b->magic); 891 dumpvl("bad Bhdr", (ulong *)((ulong)b & ~3)-4, 10); 892 } 893 894 static void 895 _auditmemloc(char *str, void *v) 896 { 897 Pool *p; 898 Bhdr *bc, *ec, *b, *nb, *fb = nil; 899 char *fmsg, *msg; 900 ulong fsz; 901 902 SET(fsz); 903 SET(fmsg); 904 for (p = &table.pool[0]; p < &table.pool[nelem(table.pool)]; p++) { 905 lock(&p->l); 906 for (bc = p->chain; bc != nil; bc = bc->clink) { 907 if (bc->magic != MAGIC_E) { 908 unlock(&p->l); 909 corrupted(str, "chain hdr!=MAGIC_E", p, bc, v); 910 goto nextpool; 911 } 912 ec = B2LIMIT(bc); 913 if (((Bhdr*)v >= bc) && ((Bhdr*)v < ec)) 914 goto found; 915 } 916 unlock(&p->l); 917 nextpool: ; 918 } 919 print("%s: %p not in pools\n", str, v); 920 return; 921 922 found: 923 for (b = bc; b < ec; b = nb) { 924 switch(b->magic) { 925 case MAGIC_F: 926 msg = "free blk"; 927 break; 928 case MAGIC_I: 929 msg = "immutable block"; 930 break; 931 case MAGIC_A: 932 msg = "block"; 933 break; 934 default: 935 if (b == bc && b->magic == MAGIC_E) { 936 msg = "pool hdr"; 937 break; 938 } 939 unlock(&p->l); 940 corrupted(str, "bad magic", p, b, v); 941 goto badchunk; 942 } 943 if (b->size <= 0 || (b->size & p->quanta)) { 944 unlock(&p->l); 945 corrupted(str, "bad size", p, b, v); 946 goto badchunk; 947 } 948 if (fb != nil) 949 break; 950 nb = B2NB(b); 951 if ((Bhdr*)v < nb) { 952 fb = b; 953 fsz = b->size; 954 fmsg = msg; 955 } 956 } 957 unlock(&p->l); 958 if (b >= ec) { 959 if (b > ec) 960 corrupted(str, "chain size mismatch", p, b, v); 961 else if (b->magic != MAGIC_E) 962 corrupted(str, "chain end!=MAGIC_E", p, b, v); 963 } 964 badchunk: 965 if (fb != nil) { 966 print("%s: %p in %s:", str, v, p->name); 967 if (fb == v) 968 print(" is %s '%lux\n", fmsg, fsz); 969 else 970 print(" in %s at %p'%lux\n", fmsg, fb, fsz); 971 dumpvl("area", (ulong *)((ulong)v & ~3)-4, 20); 972 } 973 } 974 975 char * 976 poolaudit(char*(*audit)(int, Bhdr *)) 977 { 978 Pool *p; 979 Bhdr *bc, *ec, *b; 980 char *r = nil; 981 982 for (p = &table.pool[0]; p < &table.pool[nelem(table.pool)]; p++) { 983 lock(&p->l); 984 for (bc = p->chain; bc != nil; bc = bc->clink) { 985 if (bc->magic != MAGIC_E) { 986 unlock(&p->l); 987 return "bad chain hdr"; 988 } 989 ec = B2LIMIT(bc); 990 for (b = bc; b < ec; b = B2NB(b)) { 991 if (b->size <= 0 || (b->size & p->quanta)) 992 r = "bad size in bhdr"; 993 else 994 switch(b->magic) { 995 case MAGIC_E: 996 if (b != bc) { 997 r = "unexpected MAGIC_E"; 998 break; 999 } 1000 case MAGIC_F: 1001 case MAGIC_A: 1002 case MAGIC_I: 1003 r = audit(p->pnum, b); 1004 break; 1005 default: 1006 r = "bad magic"; 1007 } 1008 if (r != nil) { 1009 unlock(&p->l); 1010 return r; 1011 } 1012 } 1013 if (b != ec || b->magic != MAGIC_E) { 1014 unlock(&p->l); 1015 return "bad chain ending"; 1016 } 1017 } 1018 unlock(&p->l); 1019 } 1020 return r; 1021 } 1022