1: /* 2: * U N I X 2 . 9 B S D C R A S H A N A L Y Z E R 3: * 4: * 5: * Name - 6: * crash -- analyze post-mortem or active system image 7: * 8: * Author - 9: * Mike Muuss, JHU EE 10: * 11: * Synopsis of options - 12: * 13: * -b Brief mode; skip general display of processes 14: * -d Crash dump contains swap image. (default?) 15: * -v Verbose; dump much information about each proc [future] 16: * -t TTY structs to be dumpped 17: * -i Incore inode table to be printed 18: * -c FILE Provide non-standard file name for system image input 19: * -s FILE Provide non-standard symboltable input 20: * -u ADDR Trace a process other than currently selected one 21: * -z Interrupt Trace displayed 22: * APS Print PS & PC at time of interupt 23: * 24: * 25: * 26: * synopsis: crash [aps] [-s sfile] [-c cfile] 27: * 28: * It examines a dump of unix which it looks for in the file 29: * sysdump. It prints out the contents of the general 30: * registers, the kernel stack and a traceback through the 31: * kernel stack. If an aps is specified, the ps and pc at 32: * time of interrupt are also printed out. The dump of the 33: * stack commences from a "reasonable" address and all addresses 34: * are relocated to virtual addresses by using the value of 35: * kdsa6 found in the dump. 36: * If the -s argument is found the following argument is taken 37: * to be the name of a file, containing a symbol table which 38: * should be used in interpreting text addresses. The default 39: * is "/unix". If the -c argument is found, the following argument 40: * is taken to be the name of a file which should be used instead 41: * of the default. 42: * 43: * R E V I S I O N H I S T O R Y 44: * 45: * ??/??/?? MJM More than I can tell 46: * 47: * 01/09/80 MJM Added C-list printing for JHU/UNIX clists. 48: * 49: * 12/11/80 MJM+RSM Modified to use new MOUNT structure. 50: * 51: * 12/16/80 RSM Ability to ask for text or data symbol on printout. 52: * 53: * 12/21/80 RSM Added ability to name-list an overlay file. 54: * 55: * 10/07/81 RSM Can now print longs in decimal format. 56: * I don't think this works--JCS 57: * 58: * 12/08/81 JCP+MJM The SYS Group 59: * Modified to work for Version 7 Vanilla UNIX 60: * 61: * 03/03/83 JCS Modified for 2.81 kernel 62: * Another new mount structure 63: * Made stack traces work with SRI overlaid kernel 64: * New p_flag values, uses USIZE 65: * Dump of some network stats (broke tty dump--Ritchie 66: * compiler is a crock) 67: * Print longs in octal format. 68: * 69: * 2/10/84 GLS Modified for 2.9 kernel 70: * Made it work with MENLO_KOV 71: * Output 2.9 clists. 72: * 73: */ 74: 75: #include <sys/param.h> 76: #include <stdio.h> 77: #include <sys/stat.h> 78: #include <sys/buf.h> 79: #include <sys/clist.h> 80: #include <sys/callout.h> 81: #include <sys/file.h> 82: #include <sys/fs.h> 83: #include <sys/ioctl.h> 84: 85: #define USIZEB (64*USIZE) 86: 87: /* 88: *-----The following three lines *must* remain together 89: */ 90: #include <sys/user.h> 91: struct user u; 92: char u_wasteXX[USIZEB-sizeof(struct user)]; /* STORAGE FOR KERNEL STACKS 93: * TO LOAD--must follow user.h 94: */ 95: #include <sys/proc.h> 96: #include <sys/text.h> 97: #include <sys/tty.h> 98: #include <sys/inode.h> 99: #include <sys/mount.h> 100: #include <sys/map.h> 101: #include <sys/msgbuf.h> 102: #include "crash.h" 103: 104: struct buf bfreelist; 105: struct proc *proc; /* NPROC */ 106: struct callout *callout; /* NCALL */ 107: 108: /* 109: * Interrupt Tracing Strutures - The SYS Group 110: */ 111: #ifdef INTRPT 112: /* 113: * to preserve the integrity of the trace information, the pointer and data 114: * area are fetched in the same read. This means the following two lines 115: * *MUST* appear in this order 116: */ 117: char *itrptr; /* pointer to next structure to use */ 118: struct itrace itrace[100]; /* max size of trace area */ 119: /* related kernel variables */ 120: char *itrstr; /* start of tracing area */ 121: char *itrend; /* end of tracing area */ 122: #endif INTRPT 123: 124: /* Actual core allocation for tty structures */ 125: int ndh11 = 0; 126: struct tty *dh11; /* NDH11 */ 127: int ndz11 = 0; 128: struct tty *dz11; /* NDZ11 */ 129: int nkl11 = 0; 130: struct tty *kl11; /* NKL11 */ 131: 132: 133: /* Global Variables */ 134: 135: struct msgbuf msgbuf; 136: char *panicstr; 137: unsigned saveps; /* ps after trap */ 138: long dumplo; /* Offset of swapspace on dump */ 139: unsigned nbuf; /* size of buffer cache */ 140: int ncallout; /* max simultaneous callouts */ 141: int nfile; /* Stored value of NFILE */ 142: int ninode; /* Stored value of NINODE */ 143: int nproc; /* Stored value of NPROC */ 144: int ntext; /* Stored value of NTEXT */ 145: int nswap; /* Number of swap blocks */ 146: int nmount; /* number of mountable file systems */ 147: int nclist; /* number of clists */ 148: long stime; /* crash time */ 149: long bootime; /* when system was booted */ 150: unsigned bpaddr; /* Location of actual buffers (clicks) */ 151: dev_t rootdev; /* device of the root */ 152: dev_t swapdev; /* swapping device */ 153: dev_t pipedev; /* pipe device */ 154: unsigned bsize; /* size of buffers */ 155: int cputype; /* type of cpu = 40, 44, 45, 60, or 70 */ 156: struct inode *rootdir; /* pointer to inode of root directory */ 157: struct proc *runq; /* head of linked list of running processes */ 158: int lbolt; /* clock ticks since time was last updated */ 159: int mpid; /* generic for unique process id's */ 160: bool_t runin; /* set when sched wants to swap someone in */ 161: bool_t runout; /* set when sched is out of work */ 162: bool_t runrun; /* reschedule at next opportunity */ 163: char curpri; /* p_pri of current process */ 164: size_t maxmem; /* actual max memory per process */ 165: size_t physmem; /* physical memory */ 166: u_short *lks; /* pointer to clock device */ 167: int updlock; /* lock for sync */ 168: daddr_t rablock; /* block to be read ahead */ 169: memaddr clststrt; /* Location of actual clists (clicks) */ 170: memaddr cfreebase; /* base of clists in kernel */ 171: unsigned clsize; /* Size of clists */ 172: short ucbclist; /* mapped out clist flag */ 173: 174: /* 175: * V7 (Stone knives & bear skins memorial) Clist structures. "cfree" conflicts 176: * with calloc's cfree ... 177: */ 178: struct cblock *cfree_; /* NCLIST */ 179: struct cblock *cfreelist; 180: int cbad; 181: 182: char *subhead; /* pntr to sub-heading */ 183: int line = 0; /* current line number */ 184: int kmem; /* Global FD of dump file */ 185: 186: int overlay; /* overlays found flag */ 187: int ovno, ovend; /* current overlay number */ 188: u_int aova, aovd; /* addresses of ova and ovd in core */ 189: unsigned ova[8], ovd[8]; /* overlay addresses and sizes */ 190: 191: /* Display table for Mounted Files */ 192: struct display mnt_tab[] = { 193: "\n\nDevice", (char *) &((struct mount *)0)->m_dev, DEV, 0, 194: "\tOn Inode", (char *) &((struct mount *)0)->m_inodp, OCT, 0, 195: END 196: }; 197: 198: #ifdef INTRPT 199: /* Display for Interrupt Tracing Feature (the SYS Group) */ 200: struct display itr_buf[] { 201: "", &itrace[0].intpc, OCT, 0, 202: "", &itrace[0].intpc, TADDR, 0, 203: "", &itrace[0].intps, OCT, 0, 204: "", &itrace[0].r0, OCT, 0, 205: "", &itrace[0].r0, TADDR, 0, 206: "", &itrace[0].savps, OCT, 0, 207: END 208: }; 209: #endif INTRPT 210: 211: /* Display table for Callouts */ 212: struct display cal_buf[] = { 213: "\nfunc", (char *) &((struct callout *)0)->c_func, OCT, 0, 214: " ", (char *) &((struct callout *)0)->c_func, TADDR, 0, 215: "\targ", (char *) &((struct callout *)0)->c_arg, DEC, 0, 216: "\ttime", (char *) &((struct callout *)0)->c_time,DEC, 0, 217: END 218: }; 219: 220: 221: /* Display for C-list display */ 222: struct display cl_buf[] = { 223: ": link", (char *) &((struct cblock *)0)->c_next, OCT, 0, 224: "\tCh", (char *) ((struct cblock *)0)->c_info, CHARS, 0, 225: END 226: }; 227: 228: int ttyflg(), ttystat(); 229: 230: /* Display for tty structures */ 231: struct display tty_buf[] = { 232: "\n\nMaj/Min", (char *) &((struct tty *)0)->t_dev, DEV, 0, 233: "\nFlags", (char *) &((struct tty *)0)->t_flags, OCT, ttyflg, 234: "\nAddr", (char *) &((struct tty *)0)->t_addr, OCT, 0, 235: "", (char *) &((struct tty *)0)->t_addr, DADDR, 0, 236: "\nDelct", (char *) &((struct tty *)0)->t_delct, HALFDEC, 0, 237: "\nLine", (char *) &((struct tty *)0)->t_line, HALFDEC, 0, 238: "\nCol", (char *) &((struct tty *)0)->t_col, HALFDEC, 0, 239: "\nState", (char *) &((struct tty *)0)->t_state, OCT, ttystat, 240: "\nIspeed", (char *) &((struct tty *)0)->t_ispeed, HALFDEC, 0, 241: "\tOspeed", (char *) &((struct tty *)0)->t_ospeed, HALFDEC, 0, 242: "\nRAW", (char *) &((struct tty *)0)->t_rawq.c_cc,DEC, 0, 243: "\tc_cf", (char *) &((struct tty *)0)->t_rawq.c_cf,OCT, 0, 244: "\tc_cl", (char *) &((struct tty *)0)->t_rawq.c_cl,OCT, 0, 245: "\nOUT", (char *) &((struct tty *)0)->t_outq.c_cc,DEC, 0, 246: "\tc_cf", (char *) &((struct tty *)0)->t_outq.c_cf,OCT, 0, 247: "\tc_cl", (char *) &((struct tty *)0)->t_outq.c_cl,OCT, 0, 248: "\nCAN", (char *) &((struct tty *)0)->t_canq.c_cc,DEC, 0, 249: "\tc_cf", (char *) &((struct tty *)0)->t_canq.c_cf,OCT, 0, 250: "\tc_cl", (char *) &((struct tty *)0)->t_canq.c_cl,OCT, 0, 251: END 252: }; 253: 254: /* Display table for Random Variables */ 255: struct display rv_tab[] = { 256: "\nRoot directory", (char *) &rootdir, OCT, 0, 257: "\nLightningbolt", (char *) &lbolt, DEC, 0, 258: "\nNext PID", (char *) &mpid, DEC, 0, 259: "\n runrun", &runrun, OCT, 0, 260: "\n runout", &runout, OCT, 0, 261: "\n runin", &runin, OCT, 0, 262: "\n curpri", &curpri, OCT, 0, 263: "\n maxmem", (char *) &maxmem, OCT, 0, 264: "\n physmem", (char *) &physmem, OCT, 0, 265: "\nClock addr", (char *) &lks, OCT, 0, 266: "\nRoot dev", (char *) &rootdev, DEV, 0, 267: "\nSwap Dev", (char *) &swapdev, DEV, 0, 268: "\nPipe Dev", (char *) &pipedev, DEV, 0, 269: "\nSwap Size", (char *) &nswap, DEC, 0, 270: "\nupdate() lock", (char *) &updlock, DEC, 0, 271: "\nReadahead blk", (char *) &rablock, OCT, 0, 272: "\n Max procs", (char *) &nproc, DEC, 0, 273: "\n Max inodes", (char *) &ninode, DEC, 0, 274: "\n Max files", (char *) &nfile, DEC, 0, 275: "\n Max texts", (char *) &ntext, DEC, 0, 276: "\n*cfreelist", (char *) &cfreelist, OCT, 0, 277: "\nSystem Buffer start click", (char *) &bpaddr, OCT, 0, 278: "\tNo. Buffers", (char *) &nbuf, DEC, 0, 279: "\tSize", (char *) &bsize, OCT, 0, 280: "\nClist start click", (char *) &clststrt, OCT, 0, 281: "\nClist start address",(char *) &cfreebase, OCT, 0, 282: "\tSize of area", (char *) &clsize, DEC, 0, 283: END 284: }; 285: 286: int pdrprint(), printuid(), printgid(); 287: 288: struct display ov_tab[] = { 289: "\n\nThe Kernel Overlay Information and Variables:\n\t__ovno", 290: (char *) &ovno, DEC, 0, 291: "\n\tOverlay #0 PAR", (char *) &ova[0], OCT, 0, 292: "\tPDR", (char *) &ovd[0], OCT, pdrprint, 293: "\n\tOverlay #1 PAR", (char *) &ova[1], OCT, 0, 294: "\tPDR", (char *) &ovd[1], OCT, pdrprint, 295: "\n\tOverlay #2 PAR", (char *) &ova[2], OCT, 0, 296: "\tPDR", (char *) &ovd[2], OCT, pdrprint, 297: "\n\tOverlay #3 PAR", (char *) &ova[3], OCT, 0, 298: "\tPDR", (char *) &ovd[3], OCT, pdrprint, 299: "\n\tOverlay #4 PAR", (char *) &ova[4], OCT, 0, 300: "\tPDR", (char *) &ovd[4], OCT, pdrprint, 301: "\n\tOverlay #5 PAR", (char *) &ova[5], OCT, 0, 302: "\tPDR", (char *) &ovd[5], OCT, pdrprint, 303: "\n\tOverlay #6 PAR", (char *) &ova[6], OCT, 0, 304: "\tPDR", (char *) &ovd[6], OCT, pdrprint, 305: "\n\tOverlay #7 PAR", (char *) &ova[7], OCT, 0, 306: "\tPDR", (char *) &ovd[7], OCT, pdrprint, 307: 308: "\n\tOverlay #8 PAR", (char *) &ova[8], OCT, 0, 309: "\tPDR", (char *) &ovd[8], OCT, pdrprint, 310: "\n\tOverlay #9 PAR", (char *) &ova[9], OCT, 0, 311: "\tPDR", (char *) &ovd[9], OCT, pdrprint, 312: "\n\tOverlay #a PAR", (char *) &ova[10], OCT, 0, 313: "\tPDR", (char *) &ovd[10], OCT, pdrprint, 314: "\n\tOverlay #b PAR", (char *) &ova[11], OCT, 0, 315: "\tPDR", (char *) &ovd[11], OCT, pdrprint, 316: "\n\tOverlay #c PAR", (char *) &ova[12], OCT, 0, 317: "\tPDR", (char *) &ovd[12], OCT, pdrprint, 318: "\n\tOverlay #d PAR", (char *) &ova[13], OCT, 0, 319: "\tPDR", (char *) &ovd[13], OCT, pdrprint, 320: "\n\tOverlay #e PAR", (char *) &ova[14], OCT, 0, 321: "\tPDR", (char *) &ovd[14], OCT, pdrprint, 322: "\n\tOverlay #f PAR", (char *) &ova[15], OCT, 0, 323: "\tPDR", (char *) &ovd[15], OCT, pdrprint, 324: END 325: }; 326: 327: int bufflg(); 328: 329: struct display buf_tab[] = { 330: "\nFlags", (char *) &((struct buf *)0)->b_flags, OCT, bufflg, 331: "\tdev", (char *) &((struct buf *)0)->b_dev, DEV, 0, 332: "\tbcount", (char *) &((struct buf *)0)->b_bcount, DEC, 0, 333: "\nxmem", &((struct buf *)0)->b_xmem, ONEBYTE, 0, 334: "\taddr", (char *) &((struct buf *)0)->b_un.b_addr, OCT, 0, 335: "\tblkno", (char *) &((struct buf *)0)->b_blkno, LONGDEC, 0, 336: "\nerror", &((struct buf *)0)->b_error, ONEBYTE, 0, 337: "\tresid", (char *) &((struct buf *)0)->b_resid, OCT, 0, 338: END 339: }; 340: 341: int inoflg(), inomod(); 342: 343: struct display inode_tab[] = { 344: "\ndev", (char *) &((struct inode *)0)->i_dev,DEV, 0, 345: "\tnumber", (char *) &((struct inode *)0)->i_number,DEC,0, 346: "\tcount", (char *) &((struct inode *)0)->i_count, DEC,0, 347: "\tflag", (char *) &((struct inode *)0)->i_flag, OCT,inoflg, 348: "\nnlink", (char *) &((struct inode *)0)->i_nlink, DEC,0, 349: "\tuid", (char *) &((struct inode *)0)->i_uid, UDEC,printuid, 350: "\tgid", (char *) &((struct inode *)0)->i_gid, UDEC,printgid, 351: "\nmode", (char *) NULL, IGNORE, inomod, 352: END 353: }; 354: 355: /* Display the USER Structure */ 356: /* 357: * note that on V7, the u.u_ar0 and u.u_qsav areas contain more than 358: * they do on V6 UNIX 359: * 360: * On V6 u.u_ar0[0] = saved R5 361: * u.u_ar0[1] = saved R6 362: * 363: * On V7 u.u_ar0[0] = saved R2 364: * u.u_ar0[1] = saved R3 365: * u.u_ar0[2] = saved R4 366: * u.u_ar0[3] = saved R5 367: * u.u_ar0[4] = saved R6 (stack pointer) 368: * 369: * for this reason, we declare the following labels, which must be used 370: * anywhere the saved registers are referenced 371: */ 372: #define R2 0 /* index of saved R2 */ 373: #define R3 1 374: #define R4 2 375: #define R5 3 376: #define R6 4 377: #define R1 5 378: 379: struct display u_tab[] = { 380: "\nsaved R5", (char *) &(u.u_rsave.val[R5]), OCT, 0, 381: "\tsaved R6", (char *) &(u.u_rsave.val[R6]), OCT, 0, 382: "\tsegflg", &(u.u_segflg), ONEBYTE, 0, 383: "\terror", &(u.u_error), HALFDEC, 0, 384: "\nuid", (char *) &(u.u_uid), UDEC, printuid, 385: "\nsvuid", (char *) &(u.u_svuid), UDEC, printuid, 386: "\nruid", (char *) &(u.u_ruid), UDEC, printuid, 387: "\tsvgid", (char *) &(u.u_svgid), UDEC, printgid, 388: "\trgid", (char *) &(u.u_rgid), UDEC, printgid, 389: "\tgroups", (char *) u.u_groups, UDEC, printgid, 390: "\nprocp", (char *) &(u.u_procp), OCT, 0, 391: "\tbase", (char *) &(u.u_base), OCT, 0, 392: "\tcount", (char *) &(u.u_count), DEC, 0, 393: "\toff", (char *) &(u.u_offset), HEXL, 0, 394: "\ncdir", (char *) &(u.u_cdir), OCT, 0, 395: "\tdirp", (char *) &(u.u_dirp), OCT, 0, 396: "\tpdir", (char *) &(u.u_pdir), OCT, 0, 397: "\targ0", (char *) &(u.u_arg[0]), OCT, 0, 398: "\narg1", (char *) &(u.u_arg[1]), OCT, 0, 399: "\targ2", (char *) &(u.u_arg[2]), OCT, 0, 400: "\targ3", (char *) &(u.u_arg[3]), OCT, 0, 401: "\targ4", (char *) &(u.u_arg[4]), OCT, 0, 402: "\narg5", (char *) &(u.u_arg[5]), OCT, 0, 403: "\ttsize", (char *) &(u.u_tsize), DEC, 0, 404: "\tdsize", (char *) &(u.u_dsize), DEC, 0, 405: "\tssize", (char *) &(u.u_ssize), DEC, 0, 406: "\nctty", (char *) &(u.u_ttyp), OCT, 0, 407: "\tttydev", (char *) &(u.u_ttyd), DEV, 0, 408: "\nsep", &(u.u_sep), ONEBYTE, 0, 409: "\tar0", (char *) &(u.u_ar0), OCT, 0, 410: END 411: }; 412: 413: int procflg(), prtsig(); 414: 415: /* Display table for Proc Structure */ 416: struct display proc_tab[] = { 417: "\nStat", (char *) &((struct proc *)0)->p_stat, ONEBYTE, 0, 418: "\tFlags", (char *) &((struct proc *)0)->p_flag, HEX, procflg, 419: "\nPri", (char *) &((struct proc *)0)->p_pri, HALFDEC, 0, 420: "\tSig", (char *) &((struct proc *)0)->p_sig, HEXL, 0, 421: "\tCursig", (char *) &((struct proc *)0)->p_cursig, HALFDEC, 0, 422: "\tUid", (char *) &((struct proc *)0)->p_uid, DEC, printuid, 423: "\nsigmask", (char *) &((struct proc *)0)->p_sigmask,HEXL, prtsig, 424: "\nsigignore", (char *) &((struct proc *)0)->p_sigignore,HEXL, prtsig, 425: "\nsigcatch", (char *) &((struct proc *)0)->p_sigcatch,HEXL, prtsig, 426: "\nTime", (char *) &((struct proc *)0)->p_time, HALFDEC, 0, 427: "\tcpu", (char *) &((struct proc *)0)->p_cpu, HALFDEC, 0, 428: "\tnice", (char *) &((struct proc *)0)->p_nice, HALFDEC, 0, 429: "\tpgrp", (char *) &((struct proc *)0)->p_pgrp, OCT, 0, 430: "\nPid", (char *) &((struct proc *)0)->p_pid, DEC, 0, 431: "\tPpid", (char *) &((struct proc *)0)->p_ppid, DEC, 0, 432: "\taddr", (char *) &((struct proc *)0)->p_addr, OCT, 0, 433: "\tdaddr", (char *) &((struct proc *)0)->p_daddr, OCT, 0, 434: "\tsaddr", (char *) &((struct proc *)0)->p_saddr, OCT, 0, 435: "\tdsize", (char *) &((struct proc *)0)->p_dsize, OCT, 0, 436: "\tssize", (char *) &((struct proc *)0)->p_ssize, OCT, 0, 437: "\ntextp", (char *) &((struct proc *)0)->p_textp, OCT, 0, 438: "\tWchan", (char *) &((struct proc *)0)->p_wchan, OCT, 0, 439: "", (char *) &((struct proc *)0)->p_wchan, DADDR, 0, 440: "\nRlink", (char *) &((struct proc *)0)->p_link, OCT, 0, 441: "\tClktim", (char *) &((struct proc *)0)->p_clktim, DEC, 0, 442: "\tSlptim", (char *) &((struct proc *)0)->p_slptime, HALFDEC, 0, 443: END 444: }; 445: 446: /* The Process Status word interpretation */ 447: char *pmsg1[] = { 448: "<null>", 449: "Sleeping (all cases)", 450: "Abandoned Wait State", 451: "*** Running ***", 452: "Being created", 453: "Being Terminated (ZOMB)", 454: "Ptrace Stopped", 455: "<eh?>" 456: }; 457: 458: /* The Process Flag Word bit table */ 459: char *p_bits[] = { 460: "in core, ", 461: "scheduler proc, ", 462: "locked in core, ", 463: "being swapped, ", 464: "being traced, ", 465: "WTED, ", 466: "ULOCK, ", 467: "OMASK,", 468: "VFORK, ", 469: "VFPRINT, ", 470: "VFDONE, ", 471: "timing out, ", 472: "detached, ", 473: "OUSIG, ", 474: "selecting, ", 475: }; 476: #define FLAG_MASK 037777 477: 478: 479: /* 480: * This table lists all of the dump variables to be fetched. 481: */ 482: 483: struct fetch fetchtab[] = { 484: 485: #ifdef INTRPT 486: /* interrupt tracing feature - The SYS Group */ 487: "_savptr", &itrptr, sizeof itrptr + sizeof itrace, 488: #endif 489: 490: "_bfreelist", (char *) &bfreelist, sizeof bfreelist, 491: "_nfile", (char *) &nfile, sizeof nfile, 492: "_nmount", (char *) &nmount, sizeof nmount, 493: "_nproc", (char *) &nproc, sizeof nproc, 494: "_ntext", (char *) &ntext, sizeof ntext, 495: "_nclist", (char *) &nclist, sizeof nclist, 496: "_nbuf", (char *) &nbuf, sizeof nbuf, 497: "_ncallout", (char *) &ncallout, sizeof ncallout, 498: "_u", (char *) &u, sizeof u, 499: "_bpaddr", (char *) &bpaddr, sizeof bpaddr, 500: "_bsize", (char *) &bsize, sizeof bsize, 501: "_ucb_cli", (char *) &ucbclist, sizeof ucbclist, 502: "_clststrt", (char *) &clststrt, sizeof clststrt, 503: "_cfree", (char *) &cfreebase, sizeof cfreebase, 504: "_ninode", (char *) &ninode, sizeof ninode, 505: 506: /* Random Variables */ 507: #ifdef notdef 508: "_dumplo", (char *) &dumplo, sizeof dumplo, 509: #endif notdef 510: "_rootdir", (char *) &rootdir, sizeof rootdir, 511: "_cputype", (char *) &cputype, sizeof cputype, 512: "_lbolt", (char *) &lbolt, sizeof lbolt, 513: "_time", (char *) &stime, sizeof stime, 514: "_boottim", (char *) &bootime, sizeof bootime, 515: "_mpid", (char *) &mpid, sizeof mpid, 516: "_runrun", (char *) &runrun, sizeof runrun, 517: "_runout", (char *) &runout, sizeof runout, 518: "_runin", (char *) &runin, sizeof runin, 519: "_curpri", (char *) &curpri, sizeof curpri, 520: "_maxmem", (char *) &maxmem, sizeof maxmem, 521: "_physmem", (char *) &physmem, sizeof physmem, 522: "_rootdev", (char *) &rootdev, sizeof rootdev, 523: "_swapdev", (char *) &swapdev, sizeof swapdev, 524: "_pipedev", (char *) &pipedev, sizeof pipedev, 525: "_nswap", (char *) &nswap, sizeof nswap, 526: "_updlock", (char *) &updlock, sizeof updlock, 527: "_rablock", (char *) &rablock, sizeof rablock, 528: "_msgbuf", (char *) &msgbuf, sizeof msgbuf, 529: "_panicst", (char *) &panicstr, sizeof panicstr, 530: END 531: }; 532: 533: struct fetch fetch1tab[] = { 534: "__ovno", (char *) &ovno, sizeof ovno, 535: END 536: }; 537: 538: /* 539: * This table lists all addresses to be fetched. 540: */ 541: 542: struct fetch fetchatab[] = { 543: "ova", (char *) &aova, sizeof *ova, 544: "ovd", (char *) &aovd, sizeof *ovd, 545: END 546: }; 547: 548: char *corref = "/core"; /* Default dump file */ 549: char *symref = "/unix"; 550: char *MIS_ARG = "Missing arg"; 551: 552: unsigned find(); int stroct(); 553: char *calloc(); 554: 555: /* Flag definitions */ 556: int bflg = 0; /* brief flag -- u only */ 557: int dflg = 0; /* Swapdev flag */ 558: int vflg = 0; /* verbose flag -- dump each proc */ 559: int tflg = 0; /* dump tty structs flag */ 560: int iflg = 0; /* dump inode table flag */ 561: #ifdef INTRPT 562: int trflg = 0; /* interrupt trace display flag */ 563: #endif INTRPT 564: 565: 566: /* 567: * M A I N 568: * 569: * Consume options and supervise the flow of control 570: * 571: */ 572: 573: main(argc,argv) 574: int argc; 575: char **argv; 576: { 577: static unsigned *up; /*!!! never initialized */ 578: register int i; 579: 580: int trapstack; 581: int u_addr; /* u block number */ 582: int u_death; /* death u */ 583: unsigned sp; 584: unsigned r5; 585: unsigned xbuf[8]; 586: 587: trapstack = 0; 588: u_addr = 0; 589: 590: /* parse off the arguments and do what we can with them */ 591: for(i=1; i<argc; i++) 592: if( *argv[i] == '-' ) { 593: switch( argv[i][1] ) { 594: 595: case 'c': 596: /* Coredump input file name */ 597: if ((i+1) >= argc) barf( MIS_ARG ); 598: corref = argv[++i]; 599: continue; 600: 601: case 's': 602: /* Symboltable input file name */ 603: if ((i+1) >= argc) barf( MIS_ARG ); 604: symref = argv[++i]; 605: continue; 606: 607: case 'u': 608: /* trace a process other than current (takes U addr) */ 609: if ((i+1) >= argc) barf( MIS_ARG ); 610: u_addr = stroct( argv[++i] ); 611: continue; 612: 613: case 'b': 614: /* Brief */ 615: bflg++; 616: continue; 617: 618: case 'd': 619: /* Dump includes swap area */ 620: dflg++; 621: continue; 622: 623: case 'v': /* do everything */ 624: /* Verbose */ 625: vflg++; 626: continue; 627: 628: case 't': 629: /* TTY structures */ 630: tflg++; 631: continue; 632: 633: case 'i': 634: /* Inode table */ 635: iflg++; 636: continue; 637: 638: #ifdef INTRPT 639: case 'z': 640: /* Interrupt Trace */ 641: trflg++; 642: continue; 643: #endif INTRPT 644: 645: default: 646: printf("Bad argument: %s\n", argv[i]); 647: 648: case 'h': 649: /* Help message */ 650: printf("Usage: crash [-i] [-d] -[t] [-c dumpfile] [-s symtab file] [-u u-addr]\n\n"); 651: exit(0); 652: } 653: 654: } else { 655: trapstack = stroct( argv[i] ); 656: if( trapstack == 0 ) 657: printf("Bad argument: %s\n", argv[i]); 658: } 659: 660: kmem = open(corref,0); 661: if (kmem < 0) { 662: printf("Unable to open %s\n",corref); 663: exit(-1); 664: } 665: 666: /* 667: * Load the symbol table 668: */ 669: getsym(symref); 670: 671: /* 672: * Load all of the shadow variables from the dump file, 673: * and print the header page. 674: */ 675: fetch(fetchtab); 676: 677: if (tflg) { 678: clsize = nclist * sizeof(struct cblock); 679: cfree_ = (struct cblock *)calloc(nclist,sizeof(struct cblock)); 680: if (cfree_ == (struct cblock *) NULL) { 681: printf("crash: out of memory getting cfree\n"); 682: exit(1); 683: } 684: /* CLIST loaded first, improve accuracy on dump running sys */ 685: if (!vf("_cfreeli", (char *) &cfreelist, sizeof cfreelist)) { 686: printf("could not find _cfreeli\n"); 687: exit(1); 688: } 689: if (ucbclist) 690: lseek(kmem, (off_t)ctob((long)clststrt), 0); /* clists click */ 691: else 692: lseek(kmem, (off_t) cfreebase, 0); /* clists in kernel */ 693: 694: read(kmem, (caddr_t) cfree_, clsize); 695: 696: vf("_nkl11", (char *) &nkl11, sizeof nkl11); 697: kl11 = (struct tty *) calloc(nkl11, sizeof(struct tty)); 698: if (kl11 == (struct tty *) NULL) { 699: printf("crash: out of memory in kl11\n"); 700: exit(1); 701: } 702: vf("_kl11", (char *) kl11, sizeof(struct tty)*nkl11); 703: if (vf("_ndh11", (char *) &ndh11, sizeof ndh11)) { 704: dh11 = (struct tty *) calloc(ndh11, sizeof(struct tty)); 705: if (dh11 == (struct tty *) NULL) { 706: printf("crash: out of memory in dh11\n"); 707: exit(1); 708: } 709: vf("_dh11", (char *) dh11, sizeof(struct tty)*ndh11); 710: } 711: if (vf("_ndz11", (char *) &ndz11, sizeof dz11)) { 712: dz11 = (struct tty *) calloc(ndz11, sizeof(struct tty)); 713: if (dz11 == (struct tty *) NULL) { 714: printf("crash: out of memory in dz11\n"); 715: exit(1); 716: } 717: vf("_dz11", (char *) dz11, sizeof(struct tty)*ndz11); 718: } 719: } 720: 721: /* 722: * Setup for MENLO_KOV 723: */ 724: if (overlay) { 725: fetch(fetch1tab); 726: fetcha(fetchatab); 727: vf("ova", (char *) ova, sizeof ova); 728: vf("ovd", (char *) ovd, sizeof ovd); 729: getpars(); 730: } 731: 732: /* Display general information */ 733: general(); 734: 735: /* dump the registers */ 736: subhead = "Registers & Stack Dump"; 737: saveps = find("saveps", 0); 738: lseek(kmem, (off_t) saveps, 0); 739: read(kmem, (caddr_t)&saveps, sizeof saveps); 740: newpage(); 741: printf("\tThe registers\n"); 742: lseek(kmem, (off_t)0300,0); 743: read(kmem,xbuf,sizeof xbuf); 744: printf("\nr0: "); octout(xbuf[0]); /* 2 */ 745: putchar(' '); if(!symbol(xbuf[0], DSYM, 0)) putchar('\t'); 746: printf("\tr1: "); octout(xbuf[1]); /* 3 */ 747: putchar(' '); if(!symbol(xbuf[1], DSYM, 0)) putchar('\t'); 748: printf("\tr2: "); octout(xbuf[2]); /* 4 */ 749: putchar(' '); if(!symbol(xbuf[2], DSYM, 0)) putchar('\t'); 750: printf("\nr3: "); octout(xbuf[3]); /* 5 */ 751: putchar(' '); if(!symbol(xbuf[3], DSYM, 0)) putchar('\t'); 752: printf("\tr4: "); octout(xbuf[4]); /* 6 */ 753: putchar(' '); if(!symbol(xbuf[4], DSYM, 0)) putchar('\t'); 754: printf("\tr5: "); octout(xbuf[5]); /* 7 */ 755: putchar(' '); if(!symbol(xbuf[5], DSYM, 0)) putchar('\t'); 756: printf("\nsp: "); octout(xbuf[6]); /* 8 */ 757: putchar(' '); if(!symbol(xbuf[6], DSYM, 0)) putchar('\t'); 758: printf("\tksda: "); octout(xbuf[7]); /* 9 */ 759: printf("\t\tps: "); octout(saveps); printps(saveps); 760: /* was: sp = xbuf[6] & 0177760; /*!!! why this mask?? */ 761: sp = xbuf[6] & 0177776; 762: r5 = xbuf[5]; 763: 764: /* 765: * Take a stack dump 766: */ 767: u_death = xbuf[7]; 768: if( u_addr == 0 ) 769: u_addr = u_death; 770: 771: /* lseek in u_addr core clicks (64 bytes) */ 772: lseek(kmem, (off_t)(unsigned)u_addr<<6,0); 773: read (kmem, &u, USIZEB); 774: 775: if (u_addr != u_death) { 776: sp = u.u_rsave.val[R6]; 777: r5 = u.u_rsave.val[R5]; 778: } 779: 780: printf ("\n\n u at 0%o, r5 = 0%o, sp = 0%o\n\n", u_addr, r5, sp); 781: 782: /* If an aps was specified, give ps, pc, sp at trap time */ 783: if (trapstack == 0) { 784: trapstack = sp; /* temporary */ 785: } 786: else { 787: printf("\n\n\timmediately prior to the trap:\n"); 788: printf("\nsp: "); octout((unsigned)sp+4); 789: printf("\tps: "); octout(up[1]); 790: printf("\tpc: "); octout(up[0]); 791: putchar(' '); 792: symbol(up[0], ISYM, 0); 793: } 794: 795: stackdump( sp-2, sp-4 ); /* current r5 and some number less */ 796: 797: /* Display Procsss information */ 798: if (!bflg) dprocs(); 799: 800: putchar('\n'); /* Flush buffer: The End */ 801: exit(0); 802: } 803: 804: 805: /* 806: * S T A C K D U M P 807: * 808: * This routine interprets the kernel stack in the 809: * user structure (_u). 810: */ 811: stackdump( r5, sp ) 812: unsigned r5, sp; 813: { 814: register unsigned *up; 815: register unsigned i; 816: 817: if ((sp < 0140000) || (sp > 0140000+USIZEB-18)) { 818: printf("\n\tsp(%0o) is unreasonable, 0140000 assumed\n", sp); 819: sp = 0140000; 820: /* since sp is bad, give him whole user area */ 821: } 822: 823: /* now give a dump of the stack, relocating as we go */ 824: printf("\n\n"); 825: printf("STACK: loc+00 loc+02 loc+04 loc+06 loc+10 loc+12 loc+14 loc+16"); 826: 827: for( i = sp & ~017; i < 0140000+USIZEB; i += 16) { 828: 829: up = (unsigned *) &u; 830: up += ((int)i - 0140000)>>1; /* damn pointer conversions */ 831: printf("\n"); octout(i); 832: printf(": "); octout(up[0]); 833: printf(" "); octout(up[1]); 834: printf(" "); octout(up[2]); 835: printf(" "); octout(up[3]); 836: printf(" "); octout(up[4]); 837: printf(" "); octout(up[5]); 838: printf(" "); octout(up[6]); 839: printf(" "); octout(up[7]); 840: } 841: 842: /* go back to beginning of stack space and give trace */ 843: printf("\n\n"); 844: printf("TRACE: old r2 old r3 old r4 "); 845: if (overlay) 846: printf("ovno "); 847: printf("old r5 old pc"); 848: i = sp; 849: while ((r5 > i) && (r5 < 0140000+USIZEB)) { 850: if (r5 == 0140000+USIZEB-18) break; 851: up = (unsigned *) &u; 852: up += ((int)r5 - 0140000)>>1; 853: printf("\n"); octout(r5); 854: printf(": "); 855: if (overlay) { 856: octout(up[-4]); 857: printf(" "); 858: } 859: octout(up[-3]); 860: printf(" "); octout(up[-2]); 861: printf(" "); octout(up[-1]); 862: printf(" "); octout(up[0]); 863: printf(" "); octout(up[1]); 864: putchar(' '); 865: symbol(up[1], ISYM, (overlay ? up[-1] : 0)); 866: i = r5 + 4; 867: r5 = up[0]; 868: } 869: putchar('\n'); 870: if (r5 != 0140000+USIZEB-18) 871: printf("\tThe dynamic chain is broken\n"); 872: } 873: 874: 875: /* 876: * G E N E R A L 877: * 878: * 879: * Display information of a general nature 880: */ 881: general() { 882: register int i; /* multi-function counter */ 883: register int j; 884: 885: /* Set up page heading */ 886: subhead = "General Information"; 887: newpage(); 888: 889: /* Tell general stuff */ 890: printf("UNIX Version 2.10bsd was running on a PDP-11/%d CPU\n", 891: cputype); 892: printf("when a crash occured at %s", ctime(&stime)); 893: printf("system booted at %s", ctime(&bootime)); 894: /* print panic message */ 895: panicpr(); 896: printf("\n\nThe `Random Variables' at time of crash:\n\n"); 897: display(rv_tab, 0); 898: if (overlay) 899: display(ov_tab, 0); 900: /* print contents of msgbf */ 901: msgbufpr(); 902: /* Display Mount Table */ 903: { 904: struct mount *mount; /* NMOUNT */ 905: register struct mount *mp; 906: 907: mount = (struct mount *) calloc(nmount, sizeof(struct mount)); 908: if (mount != (struct mount *) NULL) { 909: subhead = "The Mount Structure"; 910: newpage(); 911: if (vf("_mount", (char *)mount, 912: sizeof(struct mount)*nmount)) 913: for(mp = mount; mp < &mount[nmount]; mp++) 914: if (mp->m_dev) { 915: display(mnt_tab, mp); 916: printdev(mp); 917: } 918: free(mount); 919: } 920: } 921: 922: /* Display mbuf status info */ 923: dispnet(); 924: 925: /* Display the Callouts */ 926: if( tflg ) { 927: struct callout *cp; 928: 929: subhead = "The Callout Structure"; 930: newpage(); 931: callout = (struct callout *) calloc(ncallout, sizeof(struct callout)); 932: if (callout == (struct callout *) NULL) { 933: printf("crash: out of memory getting callout\n"); 934: exit(1); 935: } 936: vf("_callout", (char *) callout, sizeof(struct callout)*ncallout); 937: for(cp=callout; cp<&callout[ncallout]; cp++) 938: if (cp->c_func) 939: display( cal_buf, cp ); 940: free(callout); 941: } 942: 943: #ifdef INTRPT 944: /* Display Interrupt Trace */ 945: if( trflg ) { 946: itrstr = find( "_savstr", 1 ); 947: itrend = find( "_savend", 1 ); 948: subhead = "The Interrupt Trace (The SYS Group)"; 949: newpage(); 950: printf("\nEntry %d was the last trap processed\n", 951: (itrptr - itrstr)/(sizeof (struct itrace)) - 1 952: ); 953: 954: printf("\nEntry\tInt PC\t<address>\tInt PS\tTrap r0\t<address>\tTrap PS\n"); 955: for(i = 0; i < (itrend - itrstr)/(sizeof(struct itrace)); i++) 956: { 957: printf("\n%3d",i); 958: display( itr_buf, i*(sizeof (struct itrace)) ); 959: } 960: } 961: #endif 962: 963: /* If requested, dump tty structures and C-list */ 964: if( tflg ) { 965: struct tty *tp; 966: struct cblock *bp; 967: 968: subhead = "The KL-11 TTY Structures"; 969: newpage(); 970: line = 8; 971: for(tp=kl11; tp<&kl11[nkl11]; tp++) { 972: if( line > LINESPERPAGE ) { 973: newpage(); 974: line = 8; 975: } 976: display(tty_buf, tp ); 977: line += 13; 978: if( tp->t_rawq.c_cc > 0 ) { 979: bp = (struct cblock *)(tp->t_rawq.c_cf-1); 980: bp = (struct cblock *)((int)bp & ~CROUND); 981: chase( "RAW", bp); 982: } 983: if( tp->t_outq.c_cc > 0 ) { 984: bp = (struct cblock *)(tp->t_outq.c_cf-1); 985: bp = (struct cblock *)((int)bp & ~CROUND); 986: chase( "OUT", bp ); 987: } 988: if( tp->t_canq.c_cc > 0 ) { 989: bp = (struct cblock *)(tp->t_canq.c_cf-1); 990: bp = (struct cblock *)((int)bp & ~CROUND); 991: chase( "CAN", bp); 992: } 993: } 994: 995: if (ndh11 != 0) { 996: subhead = "The DH-11 TTY structures"; 997: newpage(); 998: line = 8; 999: for(tp=dh11; tp<&dh11[ndh11]; tp++) { 1000: if( line > LINESPERPAGE ) { 1001: newpage(); 1002: line = 8; 1003: } 1004: display(tty_buf, tp); 1005: line += 13; 1006: if( tp->t_rawq.c_cc > 0 ) { 1007: bp = (struct cblock *)(tp->t_rawq.c_cf-1); 1008: bp = (struct cblock *)((int)bp & ~CROUND); 1009: chase("RAW", bp); 1010: } 1011: if( tp->t_outq.c_cc > 0 ) { 1012: bp = (struct cblock *)(tp->t_outq.c_cf-1); 1013: bp = (struct cblock *)((int)bp & ~CROUND); 1014: chase( "OUT", bp); 1015: } 1016: if( tp->t_canq.c_cc > 0 ) { 1017: bp = (struct cblock *)(tp->t_canq.c_cf-1); 1018: bp = (struct cblock *)((int)bp & ~CROUND); 1019: chase( "CAN", bp); 1020: } 1021: } 1022: } 1023: 1024: if (ndz11 != 0) { 1025: subhead = "The DZ-11 TTY Structures"; 1026: newpage(); 1027: line = 8; 1028: for(tp=dz11; tp<&dz11[ndz11]; tp++) { 1029: if( line > LINESPERPAGE ) { 1030: newpage(); 1031: line = 8; 1032: } 1033: display(tty_buf, tp ); 1034: line += 13; 1035: if( tp->t_rawq.c_cc > 0 ) { 1036: bp = (struct cblock *)(tp->t_rawq.c_cf-1); 1037: bp = (struct cblock *)((int)bp & ~CROUND); 1038: chase( "RAW", bp ); 1039: } 1040: if( tp->t_outq.c_cc > 0 ) { 1041: bp = (struct cblock *)(tp->t_outq.c_cf-1); 1042: bp = (struct cblock *)((int)bp & ~CROUND); 1043: chase( "OUT", bp ); 1044: } 1045: if( tp->t_canq.c_cc > 0 ) { 1046: bp = (struct cblock *)(tp->t_canq.c_cf-1); 1047: bp = (struct cblock *)((int)bp & ~CROUND); 1048: chase( "CAN", &tp->t_canq ); 1049: } 1050: } 1051: } 1052: 1053: subhead = "The CBUF Freelist"; 1054: newpage(); 1055: line = 8; 1056: if( cfreelist != (struct cblock *) NULL ) 1057: chase( "Freelist", cfreelist); 1058: else 1059: printf("The freelist was empty\n"); 1060: } 1061: 1062: /* display the C-list */ 1063: if( tflg ) { 1064: struct cblock *cp; 1065: 1066: subhead = "The C-list"; 1067: newpage(); 1068: line = 8; 1069: if (ucbclist) 1070: j = (unsigned)0120000; 1071: else 1072: j = (unsigned)cfreebase; 1073: 1074: for(cp=cfree_; cp<&cfree_[nclist]; cp++) { 1075: putchar('\n'); 1076: octout( j ); 1077: display( cl_buf, cp); 1078: j += sizeof(struct cblock); 1079: line++; 1080: if (line > LINESPERPAGE) { 1081: newpage(); 1082: line = 8; 1083: } 1084: } 1085: } 1086: 1087: /* Display the in-core inode table */ 1088: if( iflg ) { 1089: struct buf *buf, *bp; /* NBUF */ 1090: struct inode *inode, *ip; /* NINODE */ 1091: 1092: buf = (struct buf *) calloc(nbuf, sizeof(struct buf)); 1093: if (buf == (struct buf *) NULL) { 1094: printf("crash: out of memory in buf\n"); 1095: exit(1); 1096: } 1097: subhead = "The BUF struct"; 1098: newpage(); 1099: line = 8; 1100: j = find("_buf", 1 ); 1101: if (vf("_buf", (char *) buf, sizeof(struct buf)*nbuf)) { 1102: for(bp = buf; bp < &buf[nbuf]; bp++) { 1103: if( line > LINESPERPAGE ) { 1104: newpage(); 1105: line = 8; 1106: } 1107: printf("\n\nBuf stored at 0%o\n", j); 1108: display(buf_tab, bp); 1109: line += 6; 1110: j += sizeof(struct buf); 1111: } 1112: } 1113: free(buf); 1114: 1115: inode = (struct inode *) calloc(ninode, sizeof(struct inode)); 1116: if (inode == (struct inode *) NULL) { 1117: printf("crash: out of memory in inode\n"); 1118: exit(1); 1119: } 1120: subhead = "The In-Core Inode Table"; 1121: newpage(); 1122: j = find( "_inode", 1 ); 1123: if (vf("_inode", (char *) inode, sizeof(struct inode)*ninode)) { 1124: for(ip = inode; ip<&inode[ninode]; ip++ ) { 1125: if (ip->i_count == 0) 1126: continue; 1127: if( line > LINESPERPAGE ) 1128: newpage(); 1129: printf("\n\nInode stored at %o\n", j); 1130: display(inode_tab, ip); 1131: line += 6; 1132: j += sizeof inode[0]; 1133: } 1134: } 1135: free(inode); 1136: } 1137: } 1138: 1139: /* 1140: * C H A S E 1141: * 1142: * This routine is used to chase down a c-list chain, 1143: * and display the data found there. 1144: * Note the external variable, clststrt or cfreebase. 1145: */ 1146: chase( msg, headp ) 1147: register struct cblock *headp; 1148: { 1149: register unsigned int cp; 1150: memaddr clstp, clstbase, clstend; 1151: 1152: if (ucbclist) 1153: clstbase = (memaddr)0120000; 1154: else 1155: clstbase = (memaddr)cfreebase; 1156: 1157: clstend = clstbase + clsize; 1158: printf("\n----The %s Queue-----\n", msg); 1159: line += 2; 1160: 1161: clstp = (unsigned) headp; 1162: cp = (unsigned) cfree_ + clstp - clstbase; 1163: while( clstp != 0 ) { 1164: putchar('\n'); 1165: line++; 1166: if (line > LINESPERPAGE) { 1167: newpage(); 1168: printf("\n----The %s Queue-----\n", msg); 1169: line = 8; 1170: } 1171: octout( clstp ); 1172: 1173: if( clstp > clstend || clstp < clstbase) 1174: barf(" cp exceeds limit"); 1175: display( cl_buf, cp ); 1176: 1177: clstp = (memaddr) ((struct cblock *)cp)->c_next; 1178: cp = (unsigned) cfree_ + clstp - clstbase; 1179: } 1180: } 1181: 1182: 1183: 1184: /* 1185: * D U S E R 1186: * 1187: * 1188: * Display the currently loaded User Structure 1189: */ 1190: duser() { 1191: 1192: printf("Name: %-15s\n", u.u_comm); 1193: display( u_tab, 0 ); 1194: printf("\n\nSignal Disposition:"); 1195: col( 0, (unsigned *)u.u_signal, NSIG ); 1196: printf("\n\nOpen file pointers"); 1197: col( 0, (unsigned *)u.u_ofile, NOFILE ); 1198: /**** 1199: printf("\n\nuisa:"); 1200: col( 0, (unsigned *)u.u_uisa, 16 ); 1201: printf("\n\nuisd:"); 1202: col( 0, (unsigned *)u.u_uisd, 16); 1203: ****/ 1204: } 1205: 1206: 1207: /* 1208: * D P R O C S 1209: * 1210: * Display information on each process 1211: * 1212: * For every line entry in the process table, 1213: * the ptable entry is displayed. Then the 1214: * per-process user structure is loaded into 1215: * this program's incore copy of the user structure. 1216: * Selected tidbits are displayed by duser(). 1217: * Mike Muuss, 7/8/77. 1218: */ 1219: 1220: dprocs() { 1221: register struct proc *p; 1222: register unsigned i; 1223: register unsigned loc; 1224: long baddr; /* dump byte addr */ 1225: 1226: 1227: proc = (struct proc *) calloc(nproc, sizeof(struct proc)); 1228: if (proc == (struct proc *) NULL) { 1229: printf("crash: out of memory getting proc\n"); 1230: exit(1); 1231: } 1232: vf("_proc", (char *) proc, sizeof(struct proc)*nproc); 1233: loc = find( "_proc", 1 ); /* base dump addr */ 1234: subhead = "Information on Pid XXXXX"; /* page header */ 1235: 1236: /* Consider each active entry */ 1237: for( i=0, p=proc; i<nproc; i++, p++, loc += sizeof(struct proc) ) { 1238: if( p->p_stat == 0 ) continue; 1239: 1240: prints( &subhead[19], p->p_pid); 1241: newpage(); 1242: 1243: printf("Entry for PID %d at ", p->p_pid); 1244: octout((unsigned) loc); 1245: printf("\nStatus was: %s on ", 1246: (p->p_stat > sizeof pmsg1 ? 1247: (char *)sprintf("%d", p->p_stat) : 1248: pmsg1[p->p_stat])); 1249: symbol(p->p_wchan, DSYM, 0); 1250: printf(" (0%o) wchan.\nFlags set were: ", p->p_wchan); 1251: putbits( p_bits, p->p_flag&FLAG_MASK ); /* interpret flags */ 1252: putchar('\n'); 1253: display( proc_tab, p ); 1254: putchar('\n'); 1255: 1256: /* Analyze the swapspace image */ 1257: if( p->p_flag & SLOAD ) { 1258: baddr = p->p_addr * 64L; 1259: } else { 1260: if( !dflg ) { 1261: printf("\nImage not avail.\n"); 1262: continue; 1263: } 1264: printf("\n Image retrieved from swapdev.\n"); 1265: baddr = ( p->p_addr ) * 512L; 1266: } 1267: 1268: lseek( kmem, (off_t) baddr, 0 ); 1269: read( kmem, &u, USIZEB ); 1270: 1271: /* Verify integrity of swap image, and if OK, print */ 1272: if( (unsigned)u.u_procp != loc ) { 1273: printf("\n----> Image Defective <----\n"); 1274: printf("\nu.u_procp="); octout((unsigned)u.u_procp); 1275: printf("\tbaddr="); loctout(baddr); 1276: continue; 1277: } 1278: duser(); 1279: 1280: /* eventually, I plan to print a core dump */ 1281: stackdump( (unsigned)u.u_rsave.val[R5], (unsigned)u.u_rsave.val[R6] ); 1282: } 1283: free(proc); 1284: } 1285: 1286: /* 1287: * print panicstr 1288: */ 1289: panicpr() 1290: { 1291: char pbuf[20]; 1292: register char ch; 1293: register int i; 1294: 1295: if (panicstr != (char *)0) { 1296: printf("\n\tpanicstr: \""); 1297: lseek(kmem,(off_t)(unsigned)panicstr,0); 1298: read(kmem,pbuf,sizeof pbuf); 1299: for (i=0; i<sizeof pbuf; i++) { 1300: if ((ch=pbuf[i]) == 0) 1301: break; 1302: if (ch < 040 || ch > 0177) { 1303: switch(ch) { 1304: case '\n': 1305: printf("\\n"); 1306: break; 1307: case '\r': 1308: printf("\\r"); 1309: break; 1310: case '\t': 1311: printf("\\t"); 1312: break; 1313: default: 1314: printf("\\%3o",ch); 1315: } 1316: } else { 1317: putchar(ch); 1318: } 1319: } 1320: putchar('"'); 1321: } else { 1322: printf("\n\tpanicstr is null"); 1323: } 1324: } 1325: 1326: /* 1327: * Print contents of msgbuf 1328: */ 1329: msgbufpr() 1330: { 1331: register int i; 1332: register int j; 1333: register char ch; 1334: 1335: printf("\n\nThe contents of msgbuf:"); 1336: for (i=0, j=0; i<MSG_BSIZE; i++) { 1337: if ((j++)%20 == 0) 1338: putchar('\n'); 1339: if ((ch=msgbuf.msg_bufc[i]) < 040 || ch > 0177) { 1340: switch(ch) { 1341: case '\n': 1342: printf(" \\n"); 1343: break; 1344: case '\r': 1345: printf(" \\r"); 1346: break; 1347: case '\t': 1348: printf(" \\t"); 1349: break; 1350: default: 1351: printf("\\%3o",ch); 1352: } 1353: } else { 1354: printf(" %c",ch); 1355: } 1356: } 1357: }