home *** CD-ROM | disk | FTP | other *** search
- /*
- * Mach Operating System
- * Copyright (c) 1992 Carnegie Mellon University
- * All Rights Reserved.
- *
- * Permission to use, copy, modify and distribute this software and its
- * documentation is hereby granted, provided that both the copyright
- * notice and this permission notice appear in all copies of the
- * software, derivative works or modified versions, and any portions
- * thereof, and that both notices appear in supporting documentation.
- *
- * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
- * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
- * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
- *
- * Carnegie Mellon requests users of this software to return to
- *
- * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
- * School of Computer Science
- * Carnegie Mellon University
- * Pittsburgh PA 15213-3890
- *
- * any improvements or extensions that they make and grant Carnegie Mellon
- * the rights to redistribute these changes.
- */
- /*
- * HISTORY
- * $Log: db_trace.c,v $
- * Revision 2.5 91/10/09 16:17:23 af
- * Added parens in initializers for db_regs.
- * [91/10/07 af]
- *
- * Revision 2.4 91/07/31 18:13:03 dbg
- * Stack switching support.
- * [91/07/12 dbg]
- *
- * Revision 2.3 91/03/16 14:58:27 rpd
- * Replaced db_jmpbuf with db_recover.
- * [91/03/14 rpd]
- *
- * Revision 2.2 90/08/27 22:11:36 dbg
- * Import ddb/db_sym.h.
- * [90/08/21 dbg]
- * Detect the bad return address at the end of the stack trace.
- * [90/08/07 dbg]
- * Rewrote for new debugger.
- * [90/07/23 dbg]
- *
- * Revision 2.3 90/05/29 18:38:17 rwd
- * Don't continue trace when cursym == NULL
- * [90/05/07 rwd]
- *
- * Revision 2.2 89/12/08 19:52:49 rwd
- * Make <thread>$C work correctly
- * [89/11/28 rwd]
- *
- * Revision 2.1 89/08/03 16:50:22 rwd
- * Created.
- *
- * 25-May-89 Randall Dean (rwd) at Carnegie-Mellon University
- * Added copyright to version originated by dbg. Fixed frame
- * tracing to recognize fp=0 as end.
- *
- */
-
- #include <mach/boolean.h>
- #include <machine/db_machdep.h>
- #include <ddb/db_access.h>
- #include <ddb/db_sym.h>
- #include <ddb/db_variables.h>
-
- #include <kern/thread.h>
-
- #include <machine/setjmp.h>
- extern jmp_buf_t *db_recover;
-
- /*
- * Register list
- */
- struct db_variable db_regs[] = {
- { "d0", (int *)&ddb_regs.d0, FCN_NULL },
- { "d1", (int *)&ddb_regs.d1, FCN_NULL },
- { "d2", (int *)&ddb_regs.d2, FCN_NULL },
- { "d3", (int *)&ddb_regs.d3, FCN_NULL },
- { "d4", (int *)&ddb_regs.d4, FCN_NULL },
- { "d5", (int *)&ddb_regs.d5, FCN_NULL },
- { "d6", (int *)&ddb_regs.d6, FCN_NULL },
- { "d7", (int *)&ddb_regs.d7, FCN_NULL },
- { "a0", (int *)&ddb_regs.a0, FCN_NULL },
- { "a1", (int *)&ddb_regs.a1, FCN_NULL },
- { "a2", (int *)&ddb_regs.a2, FCN_NULL },
- { "a3", (int *)&ddb_regs.a3, FCN_NULL },
- { "a4", (int *)&ddb_regs.a4, FCN_NULL },
- { "a5", (int *)&ddb_regs.a5, FCN_NULL },
- { "a6", (int *)&ddb_regs.a6, FCN_NULL },
- { "sp", (int *)&ddb_regs.sp, FCN_NULL },
- { "pc", (int *)&ddb_regs.pc, FCN_NULL },
- { "sr", (int *)&ddb_regs.sr, FCN_NULL }
- };
- struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
-
- #define MAXINT 0x7fffffff
-
- #define INKERNEL(va) (((vm_offset_t)(va)) >= VM_MIN_KERNEL_ADDRESS)
-
- #define printf db_printf
- #define get(addr, space) \
- (db_get_value((db_addr_t)(addr), sizeof(int), FALSE))
-
- #define NREGISTERS 48
-
- struct stackpos {
- int k_pc;
- int k_fp;
- int k_nargs;
- int k_entry;
- int k_caller;
- int k_flags;
- int k_regloc[NREGISTERS];
- };
- #define FR_SAVFP 0
- #define FR_SAVPC 4
- #define K_CALLTRAMP 1 /* for k_flags: caller is __sigtramp */
- #define K_SIGTRAMP 2 /* for k_flags: this is __sigtramp */
-
- stacktop(regs, sp)
- register struct mc68020_saved_state *regs;
- register struct stackpos *sp;
- {
- sp->k_regloc[0] = (int) ®s->d0;
- sp->k_regloc[1] = (int) ®s->d1;
- sp->k_regloc[2] = (int) ®s->d2;
- sp->k_regloc[3] = (int) ®s->d3;
- sp->k_regloc[4] = (int) ®s->d4;
- sp->k_regloc[5] = (int) ®s->d5;
- sp->k_regloc[6] = (int) ®s->d6;
- sp->k_regloc[7] = (int) ®s->d7;
- sp->k_regloc[8] = (int) ®s->a0;
- sp->k_regloc[9] = (int) ®s->a1;
- sp->k_regloc[10] = (int) ®s->a2;
- sp->k_regloc[11] = (int) ®s->a3;
- sp->k_regloc[12] = (int) ®s->a4;
- sp->k_regloc[13] = (int) ®s->a5;
-
- sp->k_fp = db_get_value((db_addr_t) ®s->a6,
- sizeof(int), FALSE);
- sp->k_pc = db_get_value((db_addr_t) ®s->pc,
- sizeof(int), FALSE);
- sp->k_flags = 0;
- findentry( sp );
- }
-
-
- /*
- The VAX has a very nice calling convention, and it is quite easy to
- find saved registers, and the number of parameters. We are not nearly
- so lucky. We must grub around in code for much of this information
- (remember the PDP-11?), and the saved register list seems to be
- especially hard to find.
- */
-
- #define HIWORD 0xffff0000
- #define LOWORD 0x0000ffff
- #define LINKA6 0x4e560000 /* link a6,#x */
- #define ADDLSP 0xdffc0000 /* addl #x,sp */
- #define ADDWSP 0xdefc0000 /* addw #x,sp */
- #define LEASP 0x4fef0000 /* lea sp@(x),sp*/
- #define TSTBSP 0x4a2f0000 /* tstb sp@(x) */
- #define INSMSK 0xfff80000
- #define MOVLSP 0x2e800000 /* movl dx,sp@ */
- #define MOVLD0 0x20000000 /* movl d0,dx */
- #define MOVLA0 0x20400000 /* movl d0,ax */
- #define MVLMSK 0xf1ff0000
- #define MOVEML 0x48d70000 /* moveml #x,sp@ */
- #define JSR 0x4eb80000 /* jsr x.[WL] */
- #define JSRPC 0x4eba0000 /* jsr PC@( ) */
- #define LONGBIT 0x00010000
- #define BSR 0x61000000 /* bsr x */
- #ifdef mc68020
- #define BSRL 0x61ff0000 /* bsrl x */
- #endif mc68020
- #define BYTE3 0x0000ff00
- #define LOBYTE 0x000000ff
- #define ADQMSK 0xf1ff0000
- #define ADDQSP 0x508f0000 /* addql #x,sp */
- #define ADDQWSP 0x504f0000 /* addqw #x,sp */
-
- struct nlist * trampsym = 0;
- struct nlist * funcsym = 0;
-
- nextframe(sp, kerneltrace)
- register struct stackpos *sp;
- int kerneltrace;
- {
- int val, regp, i;
- db_addr_t addr;
- db_addr_t calladdr;
- register int instruc;
- db_addr_t oldfp = sp->k_fp;
-
- /*
- * Find our entry point. Then find out
- * which registers we saved, and map them.
- * Our entry point is the address our caller called.
- */
-
- calladdr = sp->k_caller;
- addr = sp->k_entry;
- if (sp->k_flags & K_CALLTRAMP){
- #if 0
- /* we never set CALLTRAMP */
- /*
- * caller was sigtramp:
- * - no registers were saved;
- * - no new frame-pointer
- * - caller found in sigcontext structure.
- * - WE become sigtramp
- * - we have no parameters
- * MUCH MAGIC USED IN FINDING CALLER'S PC.
- */
- sp->k_pc = sp->k_caller;
- sp->k_entry = trampsym->n_value;
- sp->k_flags = 0;
- addr = get( sp->k_fp+(sizeof(int))*(11), DSP);
- sp->k_nargs = 0;
- #if DEBUG
- printf("nextframe: sigcontext at 0x%X, signaled at 0x%X\n",
- addr, sp->k_caller);
- #endif
- errflg = 0;
- #endif 0
- } else {
- if (addr == MAXINT){
- /* we don't know what registers are involved here--invalidate all */
- for(i=0; i<14; i++){
- sp->k_regloc[i] = -1;
- }
- } else {
- findregs( sp, addr );
- }
- /* find caller's pc and fp */
- sp->k_pc = calladdr;
- sp->k_fp = get(sp->k_fp+FR_SAVFP, DSP);
-
- /*
- now that we have assumed the identity of our caller, find
- how many longwords of argument WE were called with.
- */
- sp->k_flags = 0;
-
- /*
- * Don't dig around in user stack to find no. of args
- * and entry point if just tracing the kernel
- */
- if (kerneltrace && !INKERNEL(sp->k_fp)){
- sp->k_nargs = 0;
- sp->k_entry = MAXINT;
- }
- else
- findentry( sp );
- }
- if (sp->k_fp == 0 || oldfp == sp->k_fp)
- return 0;
- return (sp->k_fp);
- }
-
- findentry( sp )
- register struct stackpos *sp;
- {
- /*
- set the k_nargs and k_entry fields in the stackpos structure. This
- is called from stacktop() and from nextframe().
- our caller will do an addq or addl or addw to sp just after
- we return to pop off our arguments. find that instruction
- and extract the value.
- */
- register instruc;
- register val;
- db_addr_t addr, calladdr, nextword;
- jmp_buf_t db_jmpbuf;
- jmp_buf_t *savejmp = db_recover;
-
- if (_setjmp(db_recover = &db_jmpbuf)) {
- /* oops -- we touched something we ought not to have */
- /* cannot trace caller of "start" */
- sp->k_entry = MAXINT;
- sp->k_nargs = 0;
- db_recover = savejmp;
- return;
- }
-
- addr = get(sp->k_fp+FR_SAVPC, DSP);
- if (addr == 0) {
- /* oops -- we touched something we ought not to have */
- /* cannot trace caller of "start" */
- sp->k_entry = MAXINT;
- sp->k_nargs = 0;
- db_recover = savejmp;
- return;
- }
- instruc = get(addr-6, ISP);
- nextword = get(addr-4, ISP);
-
- db_recover = savejmp;
-
- if ((instruc&HIWORD) == (JSR | LONGBIT)) {
- /* longword offset here */
- sp->k_caller = addr-6;
- sp->k_entry = nextword;
- #ifdef mc68020
- } else if ((instruc&HIWORD) == BSRL) {
- /* longword self-relative offset */
- sp->k_caller = addr-6;
- sp->k_entry = nextword + (addr-4);
- #endif mc68020
- } else {
- instruc = nextword;
- if ((instruc&HIWORD) == JSR) {
- /* short word offset */
- sp->k_caller = addr-4;
- sp->k_entry = instruc & LOWORD;
- } else if ((instruc&HIWORD) == BSR ){
- /* short word, self-relative offset */
- sp->k_caller = addr-4;
- sp->k_entry = (addr-2) + (short)(instruc & LOWORD);
- } else if ((instruc&HIWORD) == JSRPC ){
- /* PC-relative, short word offset */
- sp->k_caller = addr-4;
- sp->k_entry = (addr-2) + (instruc & LOWORD);
- } else {
- if((instruc&BYTE3) == (BSR>>16)){
- /* byte, self-relative offset */
- sp->k_caller = addr-2;
- sp->k_entry = addr + (char)(instruc&LOBYTE);
- } else {
- /* was a call through a proc parameter */
- sp->k_caller = addr-2;
- sp->k_entry = MAXINT;
- /*
- * we know that sigtramp calls your signal catcher
- * this way -- see if this is the tramp: if so then:
- * - set the K_CALLTRAMP flag, for use by nextframe();
- * - take k_entry from __sigfunc array.
- */
- #if 0
- /* not in kernel */
- /*
- * the number (9) in the below expression is magic:
- * it is the number of stack items below callee`s fp and
- * sigtramp`s copy of the signal number.
- */
- if (trampsym && (findsym( sp->k_caller, ISYM), cursym == trampsym) ){
- int signl;
- sp->k_flags |= K_CALLTRAMP;
- if (funcsym){
- signl = get( sp->k_fp+(sizeof (int))*(9), DSP );
- sp->k_entry = get( funcsym->n_value+(sizeof(int(*)()))*signl, DSP);
- } else {
- sp->k_entry = -1;
- }
-
- errflg = 0;
- #ifdef DEBUG
- printf("Caller is sigtramp: signal is %d: entry is %x\n",
- signl, sp->k_entry);
- #endif
- }
- #ifdef DEBUG
- else
- printf("Non-tramp jsr a0@\n");
- #endif
- #endif 0
- }
- }
- }
- instruc = get(addr, ISP);
- /* on bad days, the compiler dumps a register move here */
- if ((instruc&MVLMSK) == MOVLA0 || (instruc&MVLMSK) == MOVLD0 ){
- instruc = get( addr+= 2, ISP);
- }
- if ((instruc&ADQMSK) == ADDQSP
- || (instruc&ADQMSK) == ADDQWSP){
- val = (instruc >> (16+9)) & 07;
- if (val==0)
- val = 8;
- } else if ((instruc&HIWORD) == ADDLSP){
- val = get(addr+2, ISP);
- } else if ((instruc&HIWORD) == ADDWSP || (instruc&HIWORD) == LEASP ){
- val = instruc&LOWORD;
- } else {
- val = 0;
- }
- sp->k_nargs = val/4;
-
- }
-
- /*
- * look at the procedure prolog of the current called procedure.
- * figure out which registers we saved, and where they are
- */
-
- findregs( sp , addr)
- register struct stackpos *sp;
- register db_addr_t addr;
- {
- register long instruc, val, i;
- int regp;
-
- instruc = get( addr, ISP);
- if ( (instruc&HIWORD) != LINKA6 )
- goto nolink;
- if (( instruc &= LOWORD) == 0) {
- /* look for addl */
- instruc = get(( addr += 4), ISP);
- if ( (instruc&HIWORD) == ADDLSP){
- instruc = get( addr+2, ISP);
- addr += 6;
- }
- /* else { frame size is zero } */
- } else {
- /* link offset was non-zero -- sign extend it */
- instruc <<= 16 ; instruc >>= 16;
- }
- /* we now have the negative frame size */
- regp = sp->k_fp + instruc;
- nolink:
- /* find which registers were saved */
- /* (expecting probe instruction next) */
- instruc = get( addr, ISP );
- if ((instruc&HIWORD) == TSTBSP)
- addr += 4;
- /* now we expect either a moveml or a movl */
- instruc = get( addr, ISP );
- if ((instruc&INSMSK) == MOVLSP){
- /* only saving one register */
- i = (instruc>>16) & 07;
- sp->k_regloc[i] = regp;
- } else if ((instruc&HIWORD) == MOVEML ) {
- /* saving multiple registers or unoptimized code */
- val = instruc & LOWORD;
- i = 0;
- while (val) {
- if (val & 1) {
- sp->k_regloc[i] = regp;
- regp += sizeof (int);
- }
- val >>= 1;
- i++;
- }
- }
- /* else{ no registers saved } */
-
- }
-
- /*
- * Frame tracing.
- */
- void
- db_stack_trace_cmd(addr, have_addr, count, modif)
- db_expr_t addr;
- int have_addr;
- db_expr_t count;
- char *modif;
- {
- int i, val, nargs, spa;
- db_addr_t regp;
- char * name;
- struct stackpos pos;
- boolean_t kernel_only = TRUE;
- boolean_t trace_thread = FALSE;
-
- {
- register char *cp = modif;
- register char c;
-
- while ((c = *cp++) != 0) {
- if (c == 't')
- trace_thread = TRUE;
- if (c == 'u')
- kernel_only = FALSE;
- }
- }
-
- if (count == -1)
- count = 65535;
-
- if (!have_addr) {
- stacktop(&ddb_regs, &pos);
- }
- else if (trace_thread) {
- /*
- * Get stack trace for kernel given thread address.
- */
- register thread_t th;
- register vm_offset_t stack;
-
- th = (thread_t) addr;
- stack = (vm_offset_t) get(&th->kernel_stack, 0);
- if (stack) {
- /*
- * registers are saved in kernel stack
- */
- pos.k_regloc[0] = 0;
- pos.k_regloc[1] = 0;
- pos.k_regloc[2] = (int) &STACK_MKS(stack)->d2;
- pos.k_regloc[3] = (int) &STACK_MKS(stack)->d3;
- pos.k_regloc[4] = (int) &STACK_MKS(stack)->d4;
- pos.k_regloc[5] = (int) &STACK_MKS(stack)->d5;
- pos.k_regloc[6] = (int) &STACK_MKS(stack)->d6;
- pos.k_regloc[7] = (int) &STACK_MKS(stack)->d7;
- pos.k_regloc[8] = 0;
- pos.k_regloc[9] = 0;
- pos.k_regloc[10] = (int) &STACK_MKS(stack)->a2;
- pos.k_regloc[11] = (int) &STACK_MKS(stack)->a3;
- pos.k_regloc[12] = (int) &STACK_MKS(stack)->a4;
- pos.k_regloc[13] = (int) &STACK_MKS(stack)->a5;
-
- pos.k_fp = db_get_value((db_addr_t) &STACK_MKS(stack)->sp,
- sizeof(int), FALSE);
- pos.k_pc = db_get_value((db_addr_t) &STACK_MKS(stack)->pc,
- sizeof(int), FALSE);
- pos.k_flags = 0;
- findentry( &pos );
- }
- else {
- /*
- * Only have user register state.
- */
- register pcb_t t_pcb;
- register struct mc68020_saved_state *user_regs;
-
- t_pcb = (pcb_t) get(&th->pcb, 0);
- user_regs = (struct mc68020_saved_state *)
- db_get_value((db_addr_t) &t_pcb->user_regs,
- sizeof(int), FALSE);
-
- stacktop(user_regs, &pos);
- }
- }
- else {
- pos.k_flags = 0;
- pos.k_fp = addr;
-
- pos.k_nargs = 0;
- pos.k_pc = MAXINT;
- pos.k_entry = MAXINT;
- /* sorry, we cannot find our registers without knowing our pc */
- for( i=0; i<NREGISTERS; pos.k_regloc[i++] = 0) ;
- findentry( &pos );
-
- }
- while (count) {
- count--;
-
- /* HACK */
- if (pos.k_pc == MAXINT) {
- name = "?";
- pos.k_pc = 0;
- }
- else {
- db_find_sym_and_offset(pos.k_pc, &name, &val);
- if (name == 0)
- name = "?";
- }
- printf("%s", name);
- if (pos.k_entry != MAXINT && name) {
- char * entry_name;
- int e_val;
-
- db_find_sym_and_offset(pos.k_entry, &entry_name, &e_val);
- if (entry_name != 0 && entry_name != name &&
- e_val != val) {
- printf("(?)\n");
- printf("%s", entry_name);
- }
- }
- printf("(");
- regp = pos.k_fp+FR_SAVFP+4;
- if ((nargs = pos.k_nargs)) {
- while (nargs--) {
- printf("%X", get(regp += 4, DSP));
- if (nargs)
- printf(",");
- }
- }
- if (val == MAXINT)
- printf(") at %X\n", pos.k_pc );
- else
- printf(") + %X\n", val);
-
- /*
- * Stop tracing if frame ptr no longer points into kernel
- * stack.
- */
- if (kernel_only && !INKERNEL(pos.k_fp))
- break;
- if (nextframe(&pos, kernel_only) == 0)
- break;
- }
- }
-
-