1: /* 2: * U N I X 2 . 9 B S D C R A S H A N A L Y Z E R S U B S 3: * 4: * More proc struct flag changes. No progress (no effort either ;)) on 5: * getting the program to compile - 1999/9/14 6: * 7: * Another proc struct flag went away. Program still doesn't run or 8: * compile ;-( 1999/8/11 9: * 10: * The proc structure flags cleaned up. This program still doesn't run 11: * (or compile) under the current system. 1997/9/2 12: * 13: * All the tty delay bits went away. 1997/3/28 14: * 15: * 'LCASE' and 'LTILDE' went away. Some day this program should be 16: * rewritten to reflect the current system. 12/9/94 17: */ 18: 19: #include <stdio.h> 20: #include <sys/param.h> 21: #include <sys/fs.h> 22: #include <sys/mount.h> 23: #include <sys/inode.h> 24: #include <sys/stat.h> 25: #include <sys/dir.h> 26: #include <pwd.h> 27: #include <grp.h> 28: #include "crash.h" 29: 30: /* 31: * structure to access a word as bytes 32: */ 33: struct byteof { 34: char lobyte; 35: char hibyte; 36: }; 37: 38: /* These globals are used in crash.c */ 39: char *subhead; /* pntr to sub-heading */ 40: int line; /* current line number */ 41: 42: /* 43: * S T R O C T 44: * 45: * stroct Mark Kampe 7/2/75 46: * returns: int 47: * takes: *char 48: * it does: If string represents an octal integer, 49: * the value of that integer is returned. 50: * If not, a zero is returned. 51: * The string should be null terminated and 52: * contain no non-octal-numerics. 53: */ 54: int stroct(s1) 55: char *s1; 56: { 57: register char *p; 58: register char thisn; 59: register int value; 60: 61: p = s1; 62: value = 0; 63: while (thisn = *p++) 64: if ((thisn >= '0') && (thisn <= '7')) { 65: value <<= 3; 66: value += thisn - '0'; 67: } 68: else return(0); 69: 70: return(value); 71: } 72: 73: /* 74: * O C T O U T 75: * 76: * 77: * octout Mark Kampe 7/2/75 78: * returns: nothing 79: * takes: int 80: * it does: print the integer as a six digit 81: * octal number with leading zeroes 82: * as required. I wrote this because 83: * I found the octal output produced 84: * by printf to be very hard to read. 85: * maybe I'm a pervert, but I like the leading 86: * zeroes. If you dont, replace this 87: * routine with "printf("%6o",arg);" 88: * 89: */ 90: octout(value) 91: register unsigned value; 92: { 93: char outbuf[7]; 94: register char *c; 95: register int i; 96: 97: c = &outbuf[5]; 98: 99: for(i = 0; i<6; i++) { 100: *c-- = (value & 07) + '0'; 101: value >>= 3; 102: } 103: 104: outbuf[6] = 0; /* Null terminate string */ 105: printf("%s", outbuf ); 106: return; 107: } 108: /* 109: * L O C T O U T 110: * 111: * 112: * loctout John Stewart 3 Mar 83 113: * returns: nothing 114: * takes: long int 115: * it does: print the integer as an eleven digit 116: * octal number with leading zeroes 117: * as required. (See octout, above.) 118: * 119: */ 120: loctout(value) 121: long value; 122: { 123: char outbuf[12]; 124: register char *c; 125: register int i; 126: 127: c = &outbuf[10]; 128: 129: for(i = 0; i<10; i++) { 130: *c-- = (value & 07) + '0'; 131: value >>= 3; 132: } 133: /* no unsigned long on this machine */ 134: *outbuf = (value & 03) + '0'; 135: 136: outbuf[11] = 0; /* Null terminate string */ 137: printf("%s", outbuf ); 138: return; 139: } 140: 141: hexout(value) 142: unsigned value; 143: { 144: hexdump((long)value, 4); 145: } 146: 147: hexdump(value, digs) 148: long value; 149: register int digs; 150: { 151: char outbuf[12]; 152: register char *c; 153: register int i; 154: 155: c = &outbuf[digs]; 156: *c-- = 0; /* null terminate */ 157: for(; digs--;) { 158: *c-- = "0123456789ABCDEF"[value & 0x0f]; 159: value >>= 4; 160: } 161: 162: printf("%s", outbuf ); 163: return; 164: } 165: 166: /* 167: * B A R F 168: * 169: * 170: * Print a diagnostic, flush buffers, and exit 171: */ 172: barf( c1 ) 173: register char *c1; 174: { 175: printf("%s\n", c1); 176: exit(10); 177: } 178: 179: /* 180: * N E W P A G E 181: * 182: * 183: * New page processor 184: */ 185: newpage() { 186: static int page = 0; /* current page number */ 187: 188: page++; 189: line = 0; 190: putchar( NEWPAGE ); 191: 192: printf("\n\t\t* * * UNIX Crash Dump Analyzer * * *\t\tPage %d\n\n", 193: page); 194: printf("\t\t\t%s\n\n", subhead); 195: } 196: 197: 198: /* 199: * S H O W 200: * 201: * This routine takes an address and a format type, and arranges 202: * to have the value at the given address printed in the appropriate 203: * format. 204: * Mike Muuss, 6/28/77. 205: */ 206: 207: show( addr, fmt ) 208: register unsigned *addr; 209: register fmt; 210: { 211: register char *byte; 212: int i,j; 213: 214: switch( fmt ) { 215: 216: /* Special code to just return */ 217: case IGNORE: 218: return; 219: 220: /* Octal. Use Mark Kampe's nice routine */ 221: case OCT: 222: octout( *addr ); 223: return; 224: 225: /* Long Octal. Use John Stewart's nice routine */ 226: case LONGOCT: 227: loctout(*(long *)addr); 228: return; 229: 230: case HEXL: 231: hexdump(*(long *)addr, 8); 232: return; 233: case HEXW: 234: hexdump((long)*(int *)addr, 4); 235: return; 236: case HEXB: 237: hexdump((long)*(char *)addr, 2); 238: return; 239: 240: /* Interupt Address Symbolicaly */ 241: case TADDR: 242: symbol( *addr, ISYM, 0 ); 243: return; 244: case DADDR: 245: symbol( *addr, DSYM, 0 ); 246: return; 247: 248: 249: /* Decimal. Append a dot for ease of reading */ 250: case DEC: 251: printf("%6d.", *addr); 252: return; 253: 254: /* Unsigned Decimal */ 255: case UDEC: 256: printf("%6u.", *addr); 257: return; 258: 259: /* Show both halves of the word */ 260: case DEV: 261: printf("%2d./%2d.", ((struct byteof *)addr)->hibyte, 262: (((struct byteof *)addr)->lobyte)&0377); 263: return; 264: 265: /* Show the byte */ 266: case ONEBYTE: 267: byte = (char *) addr; /* better safe than sorry */ 268: printf("%6o", (*byte) & 0377 ); 269: return; 270: 271: /* Show printable characters */ 272: case CHARS: 273: byte = (char *) addr; 274: for( i=0; i < CBSIZE; i++ ) { 275: j = *byte++ & 0377; 276: if( (j<' ') || (j>'~') ) 277: printf("0%o", j); 278: else 279: putchar( j ); 280: putchar(' '); 281: } 282: return; 283: 284: /* Show the byte in decimal */ 285: case HALFDEC: 286: byte = (char *) addr; 287: j = *byte & 0377; 288: printf("%d.", j); 289: return; 290: 291: /* Show the long in decimal */ 292: case LONGDEC: 293: printf("%ld.", *((long *)addr)); 294: return; 295: 296: /* Just in case */ 297: default: 298: printf("I can't show that!"); 299: return; 300: 301: } 302: } 303: 304: /* 305: * P U T B I T S 306: * 307: * This routine accepts a table of 16 strings representing each 308: * bit in a word. For every bit set in the given word, the 309: * associated message is printed. 310: * Mike Muuss, 6/28/77. 311: */ 312: 313: putbits( array, word ) 314: register char *array[]; 315: register int word; 316: { 317: register int i; /* current bit # */ 318: 319: for( i=0; i<16; i++) 320: if( (word >> i) & 01 ) printf("%s", array[i] ); 321: } 322: 323: /* 324: * C O L 325: * 326: * Print a region in nice columns 327: * 328: * Each line is preceeded with 'indent' spaces, 329: * and 8 octal values are printed on each line. Output 330: * comences at 'base' and proceeds for 'offset' words. 331: */ 332: 333: col( indent, base, offset ) 334: register unsigned *base; 335: register offset; 336: { 337: register i; /* Current offset */ 338: int here; /* Current line pointer */ 339: int j; /* indent counter */ 340: 341: here = 50; /* force end of line */ 342: 343: for( i=0; i < offset; i++ ) { 344: if( ++here >= 8 ) { 345: /* End of Line */ 346: here = 0; 347: putchar( '\n' ); 348: j = indent; 349: while( j-- ) putchar( ' ' ); 350: } 351: else putchar ('\t'); 352: octout( *( base + i ) ); 353: } 354: } 355: 356: 357: /* 358: * E Q U A L 359: * 360: * 361: * Determine if the first 8 characters (or up to NULL if 362: * shorter than 8 chars) are equal. True return if yes. 363: */ 364: 365: equal( a, b ) 366: register char *a, *b; 367: { 368: register i; 369: register wrong; 370: 371: wrong = 0; 372: for( i=0; i < 8; i++ ) { 373: if( !*a && !*b ) break; 374: if( *a++ != *b++ ) wrong++; 375: } 376: if( wrong ) return( 0 ); /* mismatch */ 377: return( 1 ); /* match */ 378: } 379: 380: 381: /* 382: * P R I N T S 383: * 384: * This function converts the 'number' argument into decimal 385: * and outprintf it at location 'pointer'. Leading zeros are 386: * suppressed. 387: * Mike Muuss, 7/8/77. 388: */ 389: 390: char * 391: prints( pointer, number ) 392: register char *pointer; 393: register int number; 394: { 395: register left; /* whats left */ 396: 397: if( left = number/10 ) pointer = prints( pointer, left ); 398: *pointer++ = ( number%10 ) + '0'; 399: *pointer = 0; /* string terminator */ 400: return( pointer ); 401: } 402: 403: /* 404: * D I S P L A Y 405: * 406: * This routine takes a structure of 'display' format, 407: * and generates output for each element until an END element 408: * is encountered. The offset field is added to the base 409: * address of each structure element, in case this routine 410: * is being repeatedly called to display various structure 411: * elements from the core dump. 412: * Mike Muuss, 6/27/77. 413: */ 414: 415: display( table, offset ) 416: register struct display *table; 417: register offset; 418: { 419: 420: while( table -> fmt ) { 421: /* Display Prefix */ 422: printf("%s:\t", table -> msg ); 423: 424: /* 425: * Format item 426: * 427: * offset is taken to be a byte pointer 428: * place is now defined as a byte pointer 429: */ 430: show((unsigned *)((table->place)+offset), table->fmt); 431: if (table->routine) 432: (*table->routine)((table->place)+offset); 433: table++; 434: } 435: } 436: 437: /* 438: * P R I N T D E V 439: * 440: * This routine takes a pointer to a mount structure and spins through 441: * the /dev/directory look for a matching file with the same major/minor 442: * numbers. It also prints out the plain file name from the super-block. 443: * 444: */ 445: 446: #define DEVDIR "/dev" 447: 448: printdev(mp) 449: struct mount *mp; 450: { 451: struct stat stb; 452: register struct direct *dirent; 453: struct DIR *dirfd; 454: char filename[20]; 455: 456: dirfd = opendir(DEVDIR); 457: while ((dirent = readdir(dirfd)) != NULL) { 458: if (dirent->d_ino) { 459: sprintf(filename, "%s/%.*s", DEVDIR, 460: dirent->d_namlen, dirent->d_name); 461: if (stat(filename, &stb) == 0 && 462: (stb.st_mode & S_IFMT) == S_IFBLK && 463: stb.st_rdev == mp->m_dev) { 464: printf("\t%s\t%s\n", filename, 465: mp->m_filsys.fs_fsmnt); 466: break; 467: } 468: } 469: } 470: closedir(dirfd); 471: } 472: 473: /* 474: * Print a value a la the %b format of the kernel's printf 475: */ 476: printb(v, bits) 477: u_long v; 478: register char *bits; 479: { 480: register int i, any = 0; 481: register char c; 482: 483: if (v && bits) 484: if (*bits == 8) 485: printf("0%lo=", v); 486: else 487: if (*bits == 16) 488: printf("0x%lx=", v); 489: else 490: putchar(' '); 491: bits++; 492: if (v && bits) { 493: putchar('<'); 494: while (i = *bits++) { 495: if (v & (1 << (i-1))) { 496: if (any) 497: putchar(','); 498: any = 1; 499: for (; (c = *bits) > 32; bits++) 500: putchar(c); 501: } else 502: for (; *bits > 32; bits++) 503: ; 504: } 505: putchar('>'); 506: } 507: } 508: 509: /* 510: * Print out information about the PDR passed as argument 511: */ 512: 513: char *acffld[] = { 514: "non-resident", 515: "read-only", 516: "read-only", 517: "unused", 518: "read/write", 519: "read/write", 520: "read/write", 521: "unused" 522: }; 523: 524: pdrprint(pdr) 525: unsigned *pdr; 526: { 527: char plf, a, w, ed, acf; 528: 529: plf = (*pdr & 077400) >> 8; 530: a = (*pdr & 0200) >> 7; 531: w = (*pdr & 0100) >> 6; 532: ed = (*pdr & 010) >> 3; 533: acf = (*pdr & 07); 534: printf(" plf: %d.%s%s%s acf: 0%o %s", plf, (a ? " A" : ""), 535: (w ? " W" : ""), (ed ? " ED" : ""), acf, acffld[acf]); 536: } 537: 538: /* 539: * Print the uid passed 540: */ 541: 542: printuid(uid) 543: unsigned *uid; 544: { 545: struct passwd *pwd, *getpwuid(); 546: 547: pwd = getpwuid(*uid); 548: if (pwd) 549: printf("\t%s", pwd->pw_name); 550: } 551: 552: /* 553: * Print the gid passed 554: */ 555: 556: printgid(gid) 557: unsigned *gid; 558: { 559: struct group *gwd, *getgrgid(); 560: 561: gwd = getgrgid(*gid); 562: if (gwd) 563: printf("\t%s", gwd->gr_name); 564: } 565: 566: /* 567: * Print out sinals by name. 568: */ 569: 570: prtsig(sigm) 571: long *sigm; 572: { 573: #define SIGM_FLAGS "\0\1HUP\2INT\3QUIT\4ILL\5TRAP\6IOT\7EMT\10FPE\11KILL\12BUS\13SEGV\14SYS\15PIPE\16ALRM\17TERM\20URG\21STOP\22TSTP\23CONT\24CHLD\25TTIN\26TTOU\27IO\30XCPU\31XFSZ\32VTALRM\33PROF\34WINCH\36USR1\37USR2" 574: printb((u_long) *sigm, SIGM_FLAGS); 575: } 576: 577: /* 578: * Print out flags in the proc structure 579: */ 580: 581: procflg(flgs) 582: int *flgs; 583: { 584: #define PROC_FLAGS "\0\1SLOAD\2SSYS\3SLOCK\4SSWAP\5P_TRACED\6P_WAITED\7SULOCK\8P_SINTR\11SVFORK\12SVFPRNT\13SVFDONE\15P_TIMEOUT\16P_NOCLDSTOP\17P_SELECT" 585: printb((u_long) *flgs, PROC_FLAGS); 586: } 587: 588: /* 589: * Print out the flags in the tty structure 590: */ 591: 592: ttyflg(flgs) 593: unsigned *flgs; 594: { 595: #define TTY_FLAGS "\0\1TANDEM\2CBREAK\4ECHO\5CRMOD\6RAW\7ODDP\10EVENP\21CRTBS\22PRTERA\23CRTERA\25MDMBUF\26LITOUT\27TOSTOP\30FLUSHO\31NOHANG\32RTSCTS\33CRTKILL\34PASS8\35CTLECH\36PENDIN\DECCTQ" 596: printb((u_long) *flgs, TTY_FLAGS); 597: } 598: 599: ttystat(flgs) 600: unsigned *flgs; 601: { 602: #define TTY_STATE "\0\1TIMEOUT\2WOPEN\3ISOPEN\4FLUSH\5CARR_ON\6BUSY\7ASLEEP\10XCLUDE\11TTSTOP\12HUPCLS\13TBLOCK\14RCOLL\15WCOLL\16NBIO\17ASYNC\21BKSL\22QUOT\23ERASE\24LNCH\25TYPEN\26CNTTB" 603: printb((u_long) *flgs, TTY_STATE); 604: } 605: 606: /* 607: * Ths routine prints out the flags in the buf structure 608: */ 609: 610: bufflg(flgs) 611: unsigned *flgs; 612: { 613: #define BUF_FLAGS "\0\1READ\2DONE\3ERROR\4BUSY\5PHYS\6MAP\7WANTED\10AGE\11ASYNC\12DELWRI\13TAPE\14INVAL\15bad\16RH70\17UBAREMAP\18RAMREMAP" 614: printb((u_long) *flgs, BUF_FLAGS); 615: } 616: 617: /* 618: * This routine prints out the flags in the inode structure 619: */ 620: 621: inoflg(flgs) 622: unsigned *flgs; 623: { 624: #define INO_FLAGS "\0\1ILOCKED\2IUPD\3IACC\4IMOUNT\5IWANT\6ITEXT\7ICHG\10SHLOCK\11IEXLOCK\12ILWAIT\13IMOD\14IRENAME\15IPIPE\20IXMOD" 625: printb((u_long) *flgs, INO_FLAGS); 626: } 627: 628: /* 629: * This routine prints out the file mode from the inode structure 630: */ 631: 632: inomod(ip) 633: struct inode *ip; 634: { 635: char special = 0; 636: unsigned dev; 637: 638: show(&ip->i_mode, OCT); 639: switch (ip->i_mode & IFMT) { 640: case IFDIR: 641: printf(" (Directory)"); 642: break; 643: case IFCHR: 644: special++; 645: printf(" (Character Device)"); 646: break; 647: case IFBLK: 648: special++; 649: printf(" (Block Device)"); 650: break; 651: case IFREG: 652: printf(" (Regular)"); 653: break; 654: case IFLNK: 655: printf(" (Symbolic Link)"); 656: break; 657: case IFSOCK: 658: printf(" (Socket)"); 659: break; 660: case 0: 661: printf(" (Free-inode)"); 662: break; 663: default: 664: printf(" (Garbage!)"); 665: break; 666: } 667: if (special) { 668: printf("\tdev:\t"); 669: dev = (unsigned) ip->i_rdev; 670: show(&dev, DEV); 671: putchar('\n'); 672: } else { 673: printf("\tsize:\t"); 674: show(&ip->i_size, LONGDEC); 675: printf("\n\t\tlastr:\t"); 676: show(&ip->i_lastr, LONGDEC); 677: printf("\taddr[0]:\t"); 678: show(&ip->i_addr[0], LONGDEC); 679: } 680: putchar('\n'); 681: } 682: 683: /* 684: * Print out the processor status in a symbolic format 685: */ 686: 687: char *mode[] = { 688: "kernel", 689: "supervisor", 690: "illegal", 691: "user" 692: }; 693: 694: printps(ps) 695: unsigned ps; 696: { 697: char curmode, prevmode, cis, prio, t, n, z, v, c; 698: 699: curmode = (ps >> 14) & 03; 700: prevmode = (ps >> 12) & 03; 701: cis = (ps >> 8) & 01; 702: prio = (ps >> 5) & 07; 703: t = (ps >> 4) & 01; 704: n = (ps >> 3) & 01; 705: z = (ps >> 2) & 01; 706: v = (ps >> 1) & 01; 707: c = ps & 01; 708: 709: printf(" <%s %s%s spl: %d.%s%s%s%s%s>", mode[curmode], mode[prevmode], 710: (cis ? " CIS" : ""), prio, (t ? " T" : ""), (n ? " N" : ""), 711: (z ? " Z" : ""), (v ? " V" : ""), (c ? " C" : "")); 712: }