/* SB - Copyright 1982 by Ken Harrenstien, SRI International * This software is quasi-public; it may be used freely with * like software, but may NOT be sold or made part of licensed * products without permission of the author. In all cases * the source code and any modifications thereto must remain * available to any user. * * This is part of the SB library package. * Any software using the SB library must likewise be made * quasi-public, with freely available sources. */ #define PRINT /* Include printout stuff */ #include "sb.h" #include extern struct smblk *sbm_nfl; extern struct smblk *sbm_list; extern struct sdblk *sbx_nfl; #ifdef PRINT #define PRF(stmt) {if(p) stmt;} #define PRFBUG(str,stmt) {if(p) stmt;else return(str);} #define PRFBAD(str,stmt) {if(p) stmt; return(str);} #else #define PRF(stmt) ; #define PRFBUG(str,stmt) return(str); #define PRFBAD(str,stmt) return(str); #endif #ifndef NPTRS #define NPTRS (1000) /* Catch loops of period less than this. */ #endif int sbe_dec = 0; /* Set nonzero to use decimal printout */ struct ptab { int pt_pflag; /* Printflag value */ char *pt_err; /* Error string return */ int pt_xerr; /* Error index return */ int pt_hidx; /* Highest freelist entry */ int pt_nsto; /* # entries stored in table */ int pt_cnt; /* # of entry store attempts */ struct smblk *pt_tab[NPTRS]; }; _PROTOTYPE( char *sbe_sdtab, (struct ptab *pt, int p, int phys) ); _PROTOTYPE( char *sbe_schk, (struct sdblk *sd, struct ptab *pt) ); _PROTOTYPE( int sbe_tbent, (struct ptab *pt, struct smblk *sm) ); #define PTF_PRF 01 /* Do printout stuff */ #define PTF_OVFERR 02 /* Complain if table overflows */ #define PTF_SDPHYS 04 /* Follow SD phys links (else logical links) */ struct flgt { int flg_bit; int flg_chr; }; _PROTOTYPE( char *sbe_fstr, (int flags, struct flgt *fp) ); char *sbe_mvfy(), *sbe_mfl(), *sbe_mlst(); /* SBM */ char *sbe_sbvfy(), *sbe_sbs(); /* SBBUF */ char *sbe_svfy(), *sbe_sdlist(), *sbe_sdtab(), *sbe_schk(); /* SD */ char *sbe_fstr(); /* Misc utility */ /* SBE_MEM() - Print out memory usage list */ sbe_mem() { printf("\nMemory Usage:\n"); printf("\tsbm_nfl : %6o\n",sbm_nfl); printf("\tsbm_list: %6o\n",sbm_list); printf("\tsmblk nodes are %o bytes long.\n",sizeof (struct smblk)); sbe_mlst(1); /* Scan mem list, printing stuff. */ } /* SBE_MVFY() - Verify memory allocation structures * Returns error message (0 if no errors found). */ char * sbe_mvfy() { register char *res; if((res = sbe_mfl(0)) || (res = sbe_mlst(0))) return(res); return(0); } /* SBM Debugging Routines */ struct flgt smflgtab[] = { SM_USE, 'U', SM_NXM, 'N', SM_EXT, 'E', SM_MNODS,'M', SM_DNODS,'D', 0,0 }; static char smfhelp[] = "U-Used, N-NXM, E-External, M-SMnodes, D-SDnodes"; static char smhdline[] = "\ SM: back smaddr smlen smuse smflags"; /* SBE_MFL(printflag) - Verify/Print memory freelist * Returns error message (0 if no errors found). */ char * sbe_mfl(p) int p; { register struct smblk *sm; register int i; struct ptab smtab; /* For loop detection */ PRF(printf("Tracing SM node freelist --\n")) PRF(printf(" Maximum loop detection size is %d.", NPTRS)) if((sm = sbm_nfl) == 0) { PRF(printf("\n\tNo list.\n")) return(0); /* Null freelist is ok */ } smtab.pt_pflag = p ? PTF_PRF : 0; smtab.pt_nsto = smtab.pt_cnt = 0; i = 0; /* Print 8 addrs/line */ for(; sm; sm = sm->smforw) { PRF(printf("%s%7o->", (i==0 ? "\n " : ""), sm)) if(++i >= 8) i = 0; if(sbe_tbent(&smtab, sm) < 0) /* If hit loop, stop */ PRFBAD("SM freelist loop", printf("\nLOOP - %o seen as node %d!!\n", sm, smtab.pt_xerr)) if(sm->smflags) { PRF((i = 0, printf("\nFreelist node has flags:\n"))) PRFBUG("Free SM flagged", sbe_smp(sm, 0)) } } PRF(printf("\nEnd - %d nodes on SM freelist.\n", smtab.pt_cnt)) return(0); } /* SBE_MLST(printflag) - Verify/Print allocated memory list. * Returns error message (0 if no errors found). */ char * sbe_mlst(p) int p; { register struct smblk *sm, *smf, *smb; char *nextaddr; int i; struct ptab smtab; /* For loop detection */ PRF(printf("Tracing mem list -- \n")) if((sm = sbm_list) == 0) { PRF(printf("\tNo list?!\n")) if(sbm_nfl) /* Ensure rest are 0 too */ return("No mem list?!!"); return(0); } smtab.pt_pflag = p; smtab.pt_cnt = smtab.pt_nsto = 0; smb = 0; PRF(printf(" Flags: %s\n%s\n", smfhelp, smhdline)) for(; sm; sm = smf) { PRF(printf(" %6o: ",sm)) if(sbe_tbent(&smtab, sm) < 0) PRFBAD("Loop in mem list!!", printf("LOOP - seen as node %d!!\n", smtab.pt_xerr)) if(sm->smback == smb) PRF(printf("^ ")) /* Back ptr OK */ else PRFBUG("Bad back ptr!", printf("%6o BAD Backptr!!\n\t ",sm->smback)) if((sm->smflags&0377)!= SM_NID) PRFBUG("SM: bad node ID", printf("BAD - no node ID!\n\t ")) PRF(printf((sm->smflags&SM_USE) ? " " : "FREE ")) if(sm->smlen == 0) PRFBUG("SM: len 0", printf("Zero-length area!")) if((sm->smflags&SM_USE)==0 && rndrem(sm->smaddr - sbm_lowaddr)) PRFBUG("Bad free-mem block", printf("Bad free-mem block")) PRF(sbe_smp(sm, 1)) /* Print out rest of info */ if(nextaddr != sm->smaddr && smtab.pt_cnt != 1) /* 1st time needs init */ { PRFBUG("Alignment error!", printf("\t BAD!! %6o expected; ",nextaddr)) #if !(MINIX) PRF((i = sm->smaddr - nextaddr) > 0 ? printf("%d skipped.\n",i) : printf("%d overlapped.\n",-i)) #endif } nextaddr = sm->smaddr + sm->smlen; smf = sm->smforw; smb = sm; /* Save ptr to back */ } PRF(printf("End = %6o\n",nextaddr)) return(0); } #ifdef PRINT sbe_smp(sm,type) register struct smblk *sm; int type; { if(type==0) printf(" %6o: %s ", sm, ((sm->smflags&SM_USE) ? " " : "FREE")); printf("%6o: ", sm->smaddr); printf((sbe_dec ? "%5d. %5d." : "%6o %6o"), sm->smlen, sm->smuse); printf(" %7o = %s\n", sm->smflags, sbe_fstr(sm->smflags, smflgtab)); } #endif /*PRINT*/ /* SD (SBSTR) debugging routines */ struct flgt sdflgtab[] = { SD_LOCK, 'L', SD_LCK2, 'T', SD_MOD, '*', 0,0 }; static char sdfhelp[] = "\ flags: *-MOD (disk outofdate), L-LOCK, T-LCK2 (temp)"; static char sdhdline[] = "\ SD: slforw slback sdflgs sdforw sdback sdmem sdfile sdaddr sdlen"; /* SBE_SFL(printflag) - Verify/Print SD freelist * Returns error message (0 if no errors found). */ char * sbe_sfl(p) int p; { register struct sdblk *sd; register int i; struct ptab sdtab; /* For loop detection */ PRF(printf("Tracing SDBLK node freelist --\n")) PRF(printf(" Maximum loop detection size is %d.", NPTRS)) if((sd = sbx_nfl) == 0) { PRF(printf("\n\tNo list.\n")) return(0); /* Null freelist is ok */ } sdtab.pt_pflag = p ? PTF_PRF : 0; sdtab.pt_nsto = sdtab.pt_cnt = 0; i = 0; /* Print 8 addrs/line */ for(; sd; sd = sd->slforw) { PRF(printf("%s%7o->", (i==0 ? "\n " : ""), sd)) if(++i >= 8) i = 0; if(sbe_tbent(&sdtab, sd) < 0) /* If hit loop, stop */ PRFBAD("SD freelist loop", printf("\nLOOP - %o seen as node %d!!", sd, sdtab.pt_xerr)) if(sd->sdflags) { PRF((i = 0, printf("\nFreelist node has flags:\n"))) PRFBUG("Free SD flagged", sbe_psd(sd)) } } PRF(printf("\nEnd - %d nodes on SD freelist.\n", sdtab.pt_cnt)) return(0); } /* SBE_SDS() - Print out all sdblk data stuff */ sbe_sds() { int sbe_psd(); printf("Printout of all in-use SDBLKs:\n"); printf(" %s\n", sdfhelp); printf("%s\n", sdhdline); sbm_nfor(SM_DNODS,sizeof(struct sdblk),sbe_psd,0); printf("\n"); } /* SBE_PSD - Auxiliary for invocation by SBE_SDS above. */ sbe_psd(sd) register struct sdblk *sd; { register int flags; flags = sd->sdflags; printf("%c%c%c", ((flags&SD_MOD) ? '*' : ' '), ((flags&SD_LOCK) ? 'L' : ' '), ((flags&SD_LCK2) ? 'T' : ' ')); printf(" %7o: %6o %6o %6o %6o %6o %6o %6o %7lo %5ld.\n", sd, sd->slforw, sd->slback, sd->sdflags, sd->sdforw, sd->sdback, sd->sdmem, sd->sdfile, sd->sdaddr, sd->sdlen); return(0); } /* SBE_SVFY() - Verify all SD blocks * Returns error message (0 if no errors found). */ char * sbe_svfy() { register char *res; return((res = sbe_sdlist(0,0)) ? res : sbe_sdlist(0,1)); } /* SBE_SDLIST(printflag, physflag) - Verify/Print all SD blocks. * Show logical lists if physflag 0 * Show physical lists otherwise * Returns error message (0 if no errors found). */ char * sbe_sdlist(p,phys) int p, phys; { register char *res; struct ptab sdtab; /* The SDLIST table to use */ /* First put freelist in table, then scan for all * SD nodes. Each active node (not in table) gets * its entire list traced forward/backward and added to table. */ if(res = sbe_sdtab(&sdtab, p, phys)) /* Set up freelist table */ return(res); /* Freelist entered in table, now scan all SD's */ res = (char *)sbm_nfor(SM_DNODS,sizeof(struct sdblk), sbe_schk, &sdtab); PRF(printf("\n")) return(res); } /* SBE_SDTAB(tableptr, printflag, physflag) - Auxiliary for SBE_SDLIST. * Stuffs all freelist SDBLK addresses in table for dup detection. * Returns error message (0 if no errors found). */ char * sbe_sdtab(pt, p, phys) register struct ptab *pt; int p, phys; { register struct sdblk *sd; register int res; pt->pt_pflag = (p ? PTF_PRF : 0) | (phys ? PTF_SDPHYS : 0) | PTF_OVFERR; pt->pt_cnt = pt->pt_nsto = 0; /* Initialize */ /* Stick freelist in table */ for(sd = sbx_nfl; sd; sd = sd->slforw) { if(sbe_tbent(pt, sd) < 0) { if(pt->pt_xerr < 0) PRFBAD("SD freelist too long", printf("SD freelist too long (%d)\n", NPTRS)) PRFBAD("SD freelist loop", printf("SD freelist loop at %o\n", pt->pt_xerr)) } if(sd->sdflags) { PRF(printf("Bad free SD, non-zero flag:\n")) PRFBUG("Free SD flagged", sbe_psd(sd)) } } pt->pt_hidx = pt->pt_nsto; /* Set idx of 1st non-FL entry */ return(0); } /* SBE_SCHK(SDptr, tableptr) - Auxiliary for SBE_SDLIST. * If SD not already in table, verifies or prints * the complete physical or logical list it's on, and enters all * of its SDs into table (to prevent doing it again). * Returns 0 if no errors, else error string. ** There is a problem when the table overflows. The tbent routine ** wants to add it (wrapping around at bottom) in that case, because ** that still helps detect loops. But this routine wants to reset ** the table back (after scanning to head of list) and once it starts ** scanning forward again it will fail, because some of the SDs are ** still in the table due to the wraparound! Thus PTF_OVFERR is always ** set, in order to at least give the right error message. */ char * sbe_schk(sd, pt) register struct sdblk *sd; struct ptab *pt; { register struct sdblk *sdx; register struct smblk *sm; struct sbfile *savfile; chroff lastaddr; int p, res, savidx, phys; phys = pt->pt_pflag&PTF_SDPHYS; /* Set up physflag */ if(phys && (sd->sdfile == 0)) /* Ignore non-phys stuff if phys */ return(0); p = pt->pt_pflag&PTF_PRF; /* Set up printflag */ savidx = pt->pt_nsto; /* Remember initial extent of table */ if(sbe_tbent(pt, sd) < 0) { if(pt->pt_xerr >= 0) /* OK if already in table */ return(0); PRFBAD("Too many SDs", printf("Too many SDs for table (%d)\n", NPTRS)) } /* Now search backward for start of list */ while(sdx = (phys ? sd->sdback : sd->slback)) if(sbe_tbent(pt,sdx) >= 0) sd = sdx; else break; if(sdx) { if(pt->pt_xerr < 0) /* Table error? */ PRFBAD("Too many SDs", printf("Too many SDs for table (%d)\n",NPTRS)) PRF(printf("Backlist loop!! Dup'd node:%s\n", (pt->pt_xerr < pt->pt_hidx) ? "(on freelist!)" : "" )) PRFBUG((phys ? "Phys SD loop" : "SD loop"), sbe_psd(sdx)) } /* Reset table to flush nodes backed over */ pt->pt_cnt = pt->pt_nsto = savidx; /* SD now points to start of list. Begin stepping thru list... */ PRF(printf("---- %sList started: ", (phys ? "Phys " : ""))) if(phys) { savfile = sd->sdfile; PRF(printf(" SF: %o, fd= %d, ln= %ld\n", savfile,savfile->sffd,savfile->sflen)) if(savfile->sfptr1 != sd) PRFBUG("SFPTR1 bad", printf(" BAD!! Sfptr1 %o doesn't match SD %o!!\n", savfile->sfptr1, sd)) lastaddr = 0; } else PRF(printf("\n")) PRF(printf("%s\n", sdhdline)) for(sdx = 0; sd; (sdx = sd, sd = (phys ? sd->sdforw : sd->slforw))) { PRF(sbe_psd(sd)) /* Print it out */ if(sdx != (phys ? sd->sdback : sd->slback)) { if(phys) PRFBUG("PSD bad sdback",printf("\tBad phys backptr\n")) else PRFBUG("SD bad slback",printf("\tBad backptr\n")) } if((sd->sdflags&0377) != SD_NID) PRFBUG("Bad SD node ID", printf("\tBad node ID!\n")) if(sd->sdfile && (sd->sdlen < 0 || sd->sdaddr < 0)) PRFBUG("SD: neg len/addr", printf("\tNeg disk len/addr\n")) if(phys) goto dophys; /* Do special stuff for logical list */ if(sm = sd->sdmem) { if((sm->smflags&0377) != SM_NID) PRFBUG("SD: bad SM", printf("\nBad SMBLK ptr\n")) if((sd->sdflags&SD_MOD)==0 && sd->sdlen != sm->smuse) PRFBUG("SD != SM", printf("\tBad SMBLK? Len conflict\n")) if(sm->smlen < sm->smuse) PRFBUG("SD: SM len < use", printf("\tBad SMBLK, len < use\n")) } goto doboth; /* Skip phys stuff */ /* Do special stuff for phys list */ dophys: if(sd->sdfile != savfile) PRFBUG("SD: bad sdfile", printf("\tBad sdfile ptr! Shd be %o\n", savfile)) if(sd->sdaddr < lastaddr) PRFBUG("SD addr out of order", printf("\tBad disk addr, not in order!\n")) lastaddr = sd->sdaddr; /* Done with special phys stuff */ doboth: if(sbe_tbent(pt, sd) < 0) { if(pt->pt_xerr < 0) PRFBAD("Too many SDs", printf("Too many SDs for table (%d)\n",NPTRS)) PRFBUG("SD loop", printf("\tLOOP!! This SD already seen%s.\n", (pt->pt_xerr < pt->pt_hidx) ? " (on freelist!)" : "" )) break; } } PRF(printf("-----------\n")) return(0); } /* SBE_DSK(SFptr) - Print out disk usage list for specific file */ sbe_dsk(sfp) SBFILE *sfp; { printf("SBFILE printout not coded: %o\n",sfp); } /* SBBUF structure debugging routines */ struct flgt sbflgtab[] = { SB_OVW, 'O', SB_WRIT,'W', 0,0 }; static char sbfhelp[] = "O-Overwrite, W-Write"; /* SBE_SBVFY(SBptr) - Verify a SB-string. * Returns error message (0 if no errors found). */ char * sbe_sbvfy(sbp) SBBUF *sbp; { return(sbe_sbs(sbp,0)); } /* SBE_SBS(SBptr, printflag) - Verify/Print SBSTR data stuff * Returns error message (0 if no errors found). */ char * sbe_sbs(sbp,p) SBBUF *sbp; int p; { register SBBUF *sb; register struct smblk *sm; register struct sdblk *sd; sb = sbp; PRF(printf("SBSTR %o: ",sb)) if(sb == 0) PRFBUG(0,printf("Zero pointer???\n")) /* First print out cryptic summary in case pointers bomb * out farther on. */ PRF(printf(" (io,cur,r,w,f,.,+ = %o,%o,%d,%d,%o,%lo,%lo)\n", sb->sbiop, sb->sbcur, sb->sbrleft, sb->sbwleft, sb->sbflags, sb->sbdot, sb->sboff)) PRF(printf(" sbflags %5o = %s (%s)\n", sb->sbflags, sbe_fstr(sb->sbflags,sbflgtab), sbfhelp)) if(sd = sb->sbcur) /* Okay, now try getting pointers */ sm = sd->sdmem; else sm = 0; PRF(printf(" sbcur %6o",sd)) if(sd) { PRF(printf("\n %s\n ", sdhdline)) PRF(sbe_psd(sd)) if((sd->sdflags&0377) != SD_NID) PRFBUG("SBCUR not SD?",printf(" BAD SDBLK ID!! \n")) if(sm) { PRF(printf(" %s\n ", smhdline)) PRF(sbe_smp(sm,0)) if((sm->smflags&0377) != SM_NID) PRFBUG("SBCUR has bad SM", printf(" BAD SMBLK ID!!\n")) } } PRF(printf(" sbiop %6o",sb->sbiop)) if(sb->sbiop) { if(!sm || sb->sbiop < sm->smaddr || sb->sbiop > (sm->smaddr + sm->smlen)) PRFBUG("Bad SBIOP", printf(" BAD")) } else if(sb->sbrleft > 0 || sb->sbwleft > 0) PRFBUG("Bad SBIOP/cnts", printf(" BAD")) PRF(printf("\n")) PRF(printf(" sbrleft %5o = %5d.",sb->sbrleft, sb->sbrleft)) if(sb->sbrleft && ( !sm || sb->sbwleft || (sb->sbflags&SB_WRIT) || (sb->sbrleft != (sm->smuse - (sb->sbiop - sm->smaddr))) )) PRFBUG("Bad sbrleft", printf(" BAD")) PRF(printf("\n")) PRF(printf(" sbwleft %5o = %5d.", sb->sbwleft, sb->sbwleft)) if(sb->sbwleft && ( !sm || (sb->sbflags&SB_WRIT) == 0 || (sb->sbwleft > (sm->smlen - (sb->sbiop - sm->smaddr))) )) PRFBUG("Bad sbwleft", printf(" BAD")) PRF(printf("\n")) PRF(printf(" sbdot %7lo = %7ld.", sb->sbdot, sb->sbdot)) if(sb->sbdot < 0) PRFBUG("Bad sbdot", printf(" BAD")) PRF(printf("\n sboff %7lo = %7ld.\n", sb->sboff, sb->sboff)) PRF(printf(" I/O ptr loc: %ld.\n\n", sb_tell(sb))) return(0); } /* SBE_TBENT() - Auxiliary to add and check entries to a pointer table. * Note we assume here that smblk ptrs are used, although sdblks * can also be hacked. This wins as long as the two kinds of ptrs * are basically identical (saves horrible casting problems). * Returns index # if successful (between 0 and NPTRS-1 inclusive). * Otherwise an error (-1), with relevant info in pt_xerr: * -1 if out of room and flag set making it an error * 0-n if entry already existed. */ sbe_tbent(pt, sm) register struct ptab *pt; struct smblk *sm; { register struct smblk **smt; register int i; int p; p = pt->pt_pflag&PTF_PRF; /* Set up print flag */ smt = &(pt->pt_tab[0]); if(i = pt->pt_nsto) { do { if(sm == *smt++) { pt->pt_xerr = pt->pt_nsto - i; return(-1); } } while(--i); --smt; } i = pt->pt_cnt++; if(++(pt->pt_nsto) > NPTRS) { if(pt->pt_pflag&PTF_OVFERR) { pt->pt_err = "Ptrtab overflow"; pt->pt_xerr = -1; return(-1); } pt->pt_nsto = NPTRS; i %= NPTRS; } pt->pt_tab[i] = sm; return(i); } /* SBE_FSTR(flags, flagtab) - Auxiliary to convert flag word to a string * and return pointer to it. Handy for printfs. */ char * sbe_fstr(flags, fp) register int flags; register struct flgt *fp; { static char retstr[17]; /* Max of 16 flags */ register char *cp; cp = retstr; for(; fp->flg_bit; ++fp) *cp++ = (fp->flg_bit&flags) ? fp->flg_chr : ' '; *cp = 0; return(retstr); }