1 /* postmort - post mortem dump Author: C. W. Rose */
3 /* Postmort: perform post-mortem on PC Minix 1.7 core files.
7 /* The 1.5 core file structure is a struct mem_map, the segment memory map,
8 * followed by a struct proc, the process table, followed by a dump of the
9 * text, data, and stack segments.
11 * This is the 8086/Intel version; 386 and 68K will differ. It defaults to
12 * using the name 'core' for the core file, and 'a.out' for the symbol file.
13 * If there is no 'a.out', it will try and read the symbol table from
14 * 'symbol.out', then give up. A non-existant symbol table is not a fatal
15 * error unless the -s option was used.
17 * The PC 1.5 kernel dump routines are odd - they dump the memory maps twice,
18 * the second time as part of the kernel process table, and the kernel
19 * process table size must be a multiple of 4. Should a core file have a
20 * header with a magic number in future?
22 * The kernel include file paths need to be edited for each machine. */
24 #include <sys/types.h>
25 #include <minix/config.h>
26 #include <minix/const.h>
27 #include <minix/type.h>
28 #include <minix/ipc.h>
34 #undef EXTERN /* <minix/const.h> defined this */
35 #define EXTERN /* so we get proc & mproc */
36 #include "../../kernel/arch/i386/include/archtypes.h"
37 #include "../../kernel/const.h"
38 #include "../../kernel/type.h"
39 #include "../../kernel/proc.h"
40 #undef printf /* kernel's const.h defined this */
41 #include "../../servers/pm/mproc.h"
60 #define SYMB "symbol.out"
65 /* Global variables */
66 int opt_c
= FALSE
; /* name of core file */
67 int opt_d
= FALSE
; /* dump raw data and stack segments */
68 int opt_p
= FALSE
; /* dump the kernel process table */
69 int opt_s
= FALSE
; /* name of symbol file */
70 int opt_t
= FALSE
; /* trace back the stack */
71 int opt_x
= FALSE
; /* debugging flag */
73 char progname
[20]; /* program name */
74 char *segment_name
[] = { /* array of segment names */
80 int dbglvl
= 0; /* debugging level */
81 int maxsym
; /* maximum symbol number */
82 unsigned int baseptr
; /* reference copy of stack base pointer */
83 unsigned int stackptr
; /* reference copy of stack pointer */
84 long int lengths
[NR_LOCAL_SEGS
]; /* segment lengths */
85 long int bases
[NR_LOCAL_SEGS
]; /* segment base addresses */
87 struct sym
{ /* symbol table addresses and labels */
89 char label
[SYMLEN
+ 1];
92 /* Used by getopt(3) package */
93 extern int optind
, opterr
, optopt
;
96 _PROTOTYPE(int binary
, (int uc
, char *sp
));
97 _PROTOTYPE(void dump_all_segs
, (int fd
));
98 _PROTOTYPE(void dump_maps
, (struct mem_map
* mp
));
99 _PROTOTYPE(void dump_one_seg
, (int fd
, int segindex
));
100 _PROTOTYPE(void dump_proc_table
, (struct proc
* pt
));
101 _PROTOTYPE(void dump_registers
, (struct proc
* pt
));
102 _PROTOTYPE(void dump_sym_tab
, (struct sym
*st
));
103 _PROTOTYPE(void dump_stack
, (struct stackframe_s
* sp
));
104 _PROTOTYPE(int main
, (int argc
, char *argv
[]));
105 _PROTOTYPE(int parse_line
, (char *ps
));
106 _PROTOTYPE(int read_symbol
, (int fd
));
107 _PROTOTYPE(void stack_trace
, (int fd
));
108 _PROTOTYPE(void usage
, (void));
113 * Produce a binary representation of an 8-bit number.
122 uc
= (unsigned char) ucc
;
123 for (k
= 0x80, j
= 0; j
< 8; j
++) {
128 if (j
== 3) *sp
++ = '$';
137 /* D u m p _ a l l _ s e g s
139 * Dump all the segments except for text
141 void dump_all_segs(fd
)
147 start
= (long) (NR_LOCAL_SEGS
* sizeof(struct mem_map
)) + sizeof(struct proc
);
148 for (j
= 1; j
< NR_LOCAL_SEGS
; j
++) {
149 start
+= lengths
[j
- 1];
150 (void) lseek(fd
, start
, 0);
159 * Dump the memory maps
165 long int vir
, phy
, len
;
167 printf("\t Virtual\t Physical\tLength\n");
168 printf("\t address\t address\n");
169 for (j
= 0; j
< NR_LOCAL_SEGS
; j
++) {
170 vir
= (long) mp
[j
].mem_vir
<< CLICK_SHIFT
;
171 phy
= (long) mp
[j
].mem_phys
<< CLICK_SHIFT
;
172 len
= (long) mp
[j
].mem_len
<< CLICK_SHIFT
;
173 printf("%s:\t0x%08.8lx\t0x%08.8lx\t%8ld (0x%08.8lx)\n",
174 segment_name
[j
], vir
, phy
, len
, len
);
181 /* D u m p _ o n e _ s e g
183 * Dump a single segment
185 void dump_one_seg(fd
, segindex
)
188 unsigned char dlen
[LINE_LEN
];
189 int i
, amt
, amt_read
;
190 long int len
, offset
;
192 printf("%s segment\n\n", segment_name
[segindex
]);
193 len
= lengths
[segindex
];
195 for (offset
= 0; offset
< len
; offset
+= amt
) {
196 if ((len
- offset
) < LINE_LEN
) amt
= (int) (len
- offset
);
198 printf("Length %ld, offset %ld, amt %d\n", len
, offset
, amt
);
199 if ((amt_read
= read(fd
, (char *) dlen
, (unsigned int) amt
)) == -1) {
200 printf("Unexpected end of file\n");
203 printf("%08.8lx: ", bases
[segindex
] + offset
);
204 for (i
= 0; i
< amt_read
; i
++) {
205 if (i
== LINE_LEN
/ 2) printf("- ");
206 printf("%02.2x ", dlen
[i
]);
209 for (i
= 0; i
< amt_read
; i
++) {
210 if (isprint(dlen
[i
]))
211 (void) putchar((char) dlen
[i
]);
215 (void) putchar('\n');
216 if (dbglvl
> 0 && amt_read
!= amt
)
217 printf("wanted = %d, got = %d, offset = %ld\n",
218 amt
, amt_read
, offset
);
223 /* D u m p _ p r o c _ t a b l e
225 * Dump the entire kernel proc table
227 void dump_proc_table(pt
)
230 printf("Kernel process table entries:\n\n");
232 printf("Process' registers: 0x%04.4x\n", pt
->p_reg
); /* struct stackframe_s */
233 printf("Selector in gdt: 0x%04.4x\n", pt
->p_ldt_sel
); /* reg_t */
234 printf("Descriptors for code and data: 0x%04.4x\n", pt
->p_ldt
[2]); /* struct segdesc_s */
236 printf("Number of this process: 0x%04.4x\n", pt
->p_nr
); /* int */
238 printf("Nonzero if blocked by busy task: 0x%04.4x\n", pt
->p_ntf_blocked
); /* int */
239 printf("Nonzero if held by busy syscall: 0x%04.4x\n", pt
->p_ntf_held
); /* int */
240 printf("Next in chain of held-up processes: 0x%04.4x\n", pt
->p_ntf_nextheld
); /* struct proc * */
242 printf("SENDING, RECEIVING, etc.: 0x%04.4x\n", pt
->p_rts_flags
); /* int */
244 printf("Memory map: 0x%04.4x\n", pt
->p_map
[NR_LOCAL_SEGS
]); /* struct mem_map */
247 printf("Process id passed in from MM: 0x%04.4x\n", pt
->p_pid
); /* int */
250 printf("User time in ticks: %ld\n", pt
->user_time
); /* time_t */
251 printf("Sys time in ticks: %ld\n", pt
->sys_time
); /* time_t */
252 printf("Cumulative user time of children: %ld\n", pt
->child_utime
); /* time_t */
253 printf("Cumulative sys time of children: %ld\n", pt
->child_stime
); /* time_t */
254 printf("Ticks used in current quantum: %d\n", pt
->quantum_time
); /* int */
255 printf("Ticks used in last quantum: %d\n", pt
->quantum_last
); /* int */
256 printf("Current priority of the process: %d\n", pt
->curr_prio
); /* int */
257 printf("Base priority of the process: %d\n", pt
->base_prio
); /* int */
258 printf("Scale for profiling, 0 = none: %u\n", pt
->p_pscale
); /* unsigned */
259 printf("Profiling pc lower boundary: %d\n", pt
->p_plow
); /* vir_bytes */
260 printf("Profiling pc upper boundary: %d\n", pt
->p_phigh
); /* vir_bytes */
261 printf("Profiling buffer: %d\n", pt
->p_pbuf
); /* vir_bytes */
262 printf("Profiling buffer size: %d\n", pt
->p_psiz
); /* vir_bytes */
265 printf("First proc wishing to send: 0x%04.4x\n", pt
->p_callerq
); /* struct proc * */
266 printf("Link to next proc wishing to send: 0x%04.4x\n", pt
->p_sendlink
); /* struct proc * */
267 printf("Pointer to message buffer: 0x%04.4x\n", pt
->p_messbuf
); /* message * */
269 printf("Expecting message from: 0x%04.4x\n", pt
->p_getfrom_e
); /* int */
271 printf("Pointer to next ready process: 0x%04.4x\n", pt
->p_nextready
); /* struct proc * */
273 printf("Bit map for pending signals 1-16: 0x%04.4x\n", pt
->p_pending
); /* int */
275 printf("Count of pending/unfinished signals: 0x%04.4x\n", pt
->p_pendcount
); /* unsigned */
280 /* D u m p _ r e g i s t e r s
282 * Dump the registers from the proc table
284 void dump_registers(pt
)
290 /* Print the registers */
291 dump_stack(&pt
->p_reg
);
293 /* Build up a binary representation of the signal flags */
294 uc
= (pt
->p_pending
>> 8) & 0xff;
295 (void) binary((int) uc
, buff
);
297 uc
= pt
->p_pending
& 0xff;
298 (void) binary((int) uc
, buff
+ 10);
299 printf("Pending signals = %s\n", buff
);
303 /* D u m p _ s y m _ t a b
305 * Dump the symbol table
307 void dump_sym_tab(st
)
312 printf("Symbol table entries (text):\n\n");
313 for (j
= 0; j
< maxsym
; j
++)
314 printf("0x%08.8x T %s\n", symtab
[j
].addr
, symtab
[j
].label
);
318 /* D u m p _ s t a c k
320 * Dump the stack frame
323 struct stackframe_s
*sp
;
328 /* Build up the binary PSW representation */
329 uc
= (sp
->psw
>> 8) & 0xff;
330 (void) binary((int) uc
, buff
);
333 (void) binary((int) uc
, buff
+ 10);
335 /* Print all the information */
336 printf("Stack Frame:\tPC = %04.4x\t\t PSW = %s\n",
338 printf("\t\t\t\t\tStatus = ____ ODIT SZ_A _P_C\n");
340 printf(" ax bx cx dx di si\n");
341 printf(" %04.4x\t%04.4x\t%04.4x\t%04.4x\t%04.4x\t%04.4x\n",
342 sp
->retreg
, sp
->bx
, sp
->cx
, sp
->dx
, sp
->di
, sp
->si
);
343 printf(" sp bp ss\n");
344 printf(" %04.4x\t%04.4x\t%04.4x\n",
345 sp
->sp
, sp
->fp
, sp
->ss
);
346 printf(" cs ds es\n");
347 printf(" %04.4x\t%04.4x\t%04.4x\n",
348 sp
->cs
, sp
->ds
, sp
->es
);
350 /* Store for future reference */
354 printf("\nStack pointer 0x%x, Base pointer 0x%x\n", stackptr
, baseptr
);
367 char *cp
, corefile
[132], symbfile
[132];
368 struct proc proc_entry
;
369 struct mem_map mp_segs
[NR_LOCAL_SEGS
];
372 if ((cp
= strrchr(argv
[0], '/')) == (char *) NULL
)
376 strncpy(progname
, cp
, 19);
377 strncpy(corefile
, CORE
, 131);
378 strncpy(symbfile
, AOUT
, 131);
380 /* Parse arguments */
382 while ((j
= getopt(argc
, argv
, "c:dps:tx:")) != EOF
) {
386 strncpy(corefile
, optarg
, 131);
388 case 'd': opt_d
= TRUE
; break;
389 case 'p': opt_p
= TRUE
; break;
392 strncpy(symbfile
, optarg
, 131);
394 case 't': opt_t
= TRUE
; break;
396 dbglvl
= atoi(optarg
);
407 /* We must have a core file */
408 if ((fdc
= open(corefile
, O_RDONLY
)) == -1) {
409 fprintf(stderr
, "Cannot open %s\n", corefile
);
413 /* We'd like an a.out file or a symbol table */
414 if ((fds
= open(symbfile
, O_RDONLY
)) == -1) {
418 strncpy(symbfile
, AOUT
, 131);
419 if ((fds
= open(symbfile
, O_RDONLY
)) == -1)
422 j
= read_symbol(fds
);
425 j
= read_symbol(fds
);
427 /* Only fatal if we insisted */
428 if (opt_s
&& j
== FAILED
) {
429 fprintf(stderr
, "Cannot find symbols in %s\n", symbfile
);
433 /* Read the process table */
436 printf("Size of mproc entry %d\n", NR_LOCAL_SEGS
* sizeof(struct mem_map
));
437 printf("Size of process table %d\n", sizeof(proc_entry
));
439 if (read(fdc
, (char *) mp_segs
, sizeof(mp_segs
)) != sizeof(mp_segs
) ||
440 read(fdc
, (char *) &proc_entry
,
441 sizeof(struct proc
)) != sizeof(struct proc
)) {
442 fprintf(stderr
, "Cannot open %s\n", corefile
);
448 dump_maps(mp_segs
); /* duplicated in the kernel */
451 dump_maps(proc_entry
.p_map
);
454 dump_registers(&proc_entry
);
461 dump_proc_table(&proc_entry
);
465 dump_sym_tab(symtab
);
471 if (fds
!= -1) (void) close(fds
);
478 /* P a r s e _ l i n e
480 * Parse a line of the symbol table
489 /* We must have space in the table */
490 if (maxsym
== MAXSYM
) return(FAILED
);
492 /* Lines must be a minimum length to contain information */
493 if (strlen(ps
) < 8) return(FAILED
);
495 /* Lines must have a definite structure */
496 if (ps
[1] != ' ' || ps
[6] != ' ') return(FAILED
);
497 for (j
= 2; j
< 6; j
++)
498 if (!isxdigit(ps
[j
])) return(FAILED
);
499 if (sscanf(ps
, "%c %x %s", &c
, &u
, s
) != 3) return (FAILED
);
501 if (dbglvl
> 0) printf("Address 0x%04.4x, label %s\n", u
, s
);
503 /* Load the symbol table in sorted order */
504 for (j
= 0; j
< maxsym
; j
++) {
505 if (u
< symtab
[j
].addr
) {
506 for (k
= maxsym
; k
> j
; k
--) symtab
[k
] = symtab
[k
- 1];
511 strncpy(symtab
[j
].label
, s
, SYMLEN
);
518 /* R e a d _ s y m b o l
520 * Read the symbol table
525 char sym
[80], buff
[BUFSIZ
];
531 /* We collect only text symbols, since that's all that's needed here */
533 /* Initialise the buffer */
534 if ((j
= read(fd
, buff
, BUFSIZ
)) == 0 || j
== -1) return(FAILED
);
538 /* Find out what we've got */
539 ep
= (struct exec
*) buff
;
540 np
= (struct nlist
*) buff
;
542 /* Must be a separate symbol table */
544 if (buff
[k
] == 'T') {
545 for (m
= 0; m
< 78; m
++) {
548 if ((j
= read(fd
, buff
, BUFSIZ
)) == 0 || j
== -1)
552 if (buff
[k
] == '\n') break;
555 (void) parse_line(sym
);
558 if ((j
= read(fd
, buff
, BUFSIZ
)) == 0 || j
== -1)
563 } else if (ep
->a_syms
!= 0L) {
564 /* There's symbols in them thar hills */
565 offset
= 8 * sizeof(long) + ep
->a_text
+ ep
->a_data
;
566 if (lseek(fd
, offset
, 0) == -1L) return(FAILED
);
567 /* Symbols are in an unsorted list */
568 while (read(fd
, buff
, sizeof(struct nlist
)) == sizeof(struct nlist
)) {
569 if (np
->n_sclass
== (N_TEXT
+ C_EXT
)) { /* external text symbols */
570 for (j
= 0; j
< maxsym
; j
++) {
571 if (np
->n_value
< symtab
[j
].addr
) {
572 for (k
= maxsym
; k
> j
; k
--)
573 symtab
[k
] = symtab
[k
- 1];
577 symtab
[j
].addr
= np
->n_value
;
578 strncpy(symtab
[j
].label
, np
->n_name
, SYMLEN
);
579 if (maxsym
++ == MAXSYM
) break;
586 for (m
= 0; m
< maxsym
; m
++) printf("Addr 0x%04.4x, label %s\n",
587 symtab
[m
].addr
, symtab
[m
].label
);
588 printf("Maxsym %d\n", maxsym
);
594 /* S t a c k _ t r a c e
596 * Trace back down the stack frames.
598 * WARNING: very, very, non-portable code
604 unsigned int framepointer
, lastpointer
, returnvalue
, end
;
607 /* Bp actually gives the offset from the base of the data segment */
608 bp
= (long) (NR_LOCAL_SEGS
* sizeof(struct mem_map
)) + sizeof(struct proc
)
609 + lengths
[0] + lengths
[1] - bases
[2];
610 if ((offset
= lseek(fd
, bp
+ (long int) baseptr
, 0)) == -1L) return;
611 end
= (bases
[2] + lengths
[2] - 1) & 0xffff;
614 printf("Baseptr %x, End %x, Bp %ld, Offset %ld\n", baseptr
, end
, bp
, offset
);
616 /* Print the header, then try to backtrace */
617 printf("Stack back trace:\n\n");
618 printf("Frame address. Contents. Return address.");
619 if (maxsym
!= 0) printf(" Previous label.");
622 lastpointer
= baseptr
;
624 /* Read the frame pointer and return address values */
625 if (read(fd
, (char *) &framepointer
, sizeof(int)) == -1 ||
626 read(fd
, (char *) &returnvalue
, sizeof(int)) == -1)
629 /* Look up the return address - ignored if maxsym == 0 */
630 for (j
= 0; j
< maxsym
; j
++) {
631 if (symtab
[j
].addr
>= returnvalue
) break;
634 printf(" 0x%04.4x 0x%04.4x 0x%04.4x %s\n",
635 lastpointer
, framepointer
, returnvalue
,
636 (maxsym
== 0) ? "" : symtab
[j
].label
);
638 /* If the result is clearly invalid, quit */
639 if (framepointer
== 0 || framepointer
>= end
|| framepointer
<= lastpointer
)
642 /* Otherwise try to move to the next frame base */
643 lastpointer
= framepointer
;
644 if ((offset
= lseek(fd
, bp
+ (long int) framepointer
, 0)) == -1L || offset
== 0L)
656 fprintf(stderr
, "Usage: %s [-dpt] [-c corefile] [-s symbfile]\n", progname
);