diff options
author | Marcel Moolenaar <marcel@FreeBSD.org> | 2004-07-10 23:47:20 +0000 |
---|---|---|
committer | Marcel Moolenaar <marcel@FreeBSD.org> | 2004-07-10 23:47:20 +0000 |
commit | 37224cd3fcb911d440e40dd8e1f31652e2452537 (patch) | |
tree | 533bc344dcaf70d30b9a52c0dc5327488516647b | |
parent | 5971a234e5b07f66372970c407b8085d6ad7904e (diff) |
Notes
29 files changed, 1689 insertions, 2343 deletions
diff --git a/sys/alpha/alpha/db_disasm.c b/sys/alpha/alpha/db_disasm.c index c54ec210cacbc..8d98121a8d2fc 100644 --- a/sys/alpha/alpha/db_disasm.c +++ b/sys/alpha/alpha/db_disasm.c @@ -813,26 +813,9 @@ register_name (ireg) * (optional) alternate format. Return address of start of * next instruction. */ -int alpha_print_instruction(db_addr_t, alpha_instruction, boolean_t); -db_addr_t -db_disasm(loc, altfmt) - db_addr_t loc; - boolean_t altfmt; -{ - alpha_instruction inst; - - inst.bits = db_get_value(loc, 4, 0); - - loc += alpha_print_instruction(loc, inst, altfmt); - return (loc); -} - -int -alpha_print_instruction(iadr, i, showregs) - db_addr_t iadr; - alpha_instruction i; - boolean_t showregs; +static int +alpha_print_instr(db_addr_t iadr, alpha_instruction i, boolean_t showregs) { const char *opcode; int ireg; @@ -1038,7 +1021,7 @@ loadstore_address: if (i.mem_format.opcode == op_ldah) signed_immediate <<= 16; db_printf(" <0x%lx>", signed_immediate + - db_register_value(DDB_REGS, i.mem_format.rs)); + db_register_value(i.mem_format.rs)); } break; case op_br: @@ -1084,10 +1067,23 @@ branch_displacement: db_printf(","); db_printf("%s=0x%lx", name_of_register[regnum[ireg]], - db_register_value(DDB_REGS, regnum[ireg])); + db_register_value(regnum[ireg])); } db_printf(">"); } db_printf("\n"); return (sizeof(alpha_instruction)); } + +db_addr_t +db_disasm(loc, altfmt) + db_addr_t loc; + boolean_t altfmt; +{ + alpha_instruction inst; + + inst.bits = db_get_value(loc, 4, 0); + + loc += alpha_print_instr(loc, inst, altfmt); + return (loc); +} diff --git a/sys/alpha/alpha/db_interface.c b/sys/alpha/alpha/db_interface.c index d11ad8fc3548c..7a7553f2ec5fa 100644 --- a/sys/alpha/alpha/db_interface.c +++ b/sys/alpha/alpha/db_interface.c @@ -50,14 +50,12 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> -#include <sys/proc.h> -#include <sys/reboot.h> #include <sys/systm.h> -#include <sys/kernel.h> #include <sys/cons.h> -#include <sys/ktr.h> -#include <sys/lock.h> +#include <sys/kdb.h> +#include <sys/kernel.h> #include <sys/pcpu.h> +#include <sys/proc.h> #include <sys/smp.h> #include <vm/vm.h> @@ -73,209 +71,104 @@ __FBSDID("$FreeBSD$"); #include <ddb/db_access.h> #include <ddb/db_sym.h> #include <ddb/db_variables.h> -#include <machine/setjmp.h> - -static jmp_buf *db_nofault = 0; -extern jmp_buf db_jmpbuf; -extern void gdb_handle_exception(db_regs_t *, int, int); - -#if 0 -extern char *trap_type[]; -extern int trap_types; -#endif - -int db_active; - -void ddbprinttrap(unsigned long, unsigned long, unsigned long, - unsigned long); +static db_varfcn_t db_frame; struct db_variable db_regs[] = { - { "v0", &ddb_regs.tf_regs[FRAME_V0], FCN_NULL }, - { "t0", &ddb_regs.tf_regs[FRAME_T0], FCN_NULL }, - { "t1", &ddb_regs.tf_regs[FRAME_T1], FCN_NULL }, - { "t2", &ddb_regs.tf_regs[FRAME_T2], FCN_NULL }, - { "t3", &ddb_regs.tf_regs[FRAME_T3], FCN_NULL }, - { "t4", &ddb_regs.tf_regs[FRAME_T4], FCN_NULL }, - { "t5", &ddb_regs.tf_regs[FRAME_T5], FCN_NULL }, - { "t6", &ddb_regs.tf_regs[FRAME_T6], FCN_NULL }, - { "t7", &ddb_regs.tf_regs[FRAME_T7], FCN_NULL }, - { "s0", &ddb_regs.tf_regs[FRAME_S0], FCN_NULL }, - { "s1", &ddb_regs.tf_regs[FRAME_S1], FCN_NULL }, - { "s2", &ddb_regs.tf_regs[FRAME_S2], FCN_NULL }, - { "s3", &ddb_regs.tf_regs[FRAME_S3], FCN_NULL }, - { "s4", &ddb_regs.tf_regs[FRAME_S4], FCN_NULL }, - { "s5", &ddb_regs.tf_regs[FRAME_S5], FCN_NULL }, - { "s6", &ddb_regs.tf_regs[FRAME_S6], FCN_NULL }, - { "a0", &ddb_regs.tf_regs[FRAME_A0], FCN_NULL }, - { "a1", &ddb_regs.tf_regs[FRAME_A1], FCN_NULL }, - { "a2", &ddb_regs.tf_regs[FRAME_A2], FCN_NULL }, - { "a3", &ddb_regs.tf_regs[FRAME_A3], FCN_NULL }, - { "a4", &ddb_regs.tf_regs[FRAME_A4], FCN_NULL }, - { "a5", &ddb_regs.tf_regs[FRAME_A5], FCN_NULL }, - { "t8", &ddb_regs.tf_regs[FRAME_T8], FCN_NULL }, - { "t9", &ddb_regs.tf_regs[FRAME_T9], FCN_NULL }, - { "t10", &ddb_regs.tf_regs[FRAME_T10], FCN_NULL }, - { "t11", &ddb_regs.tf_regs[FRAME_T11], FCN_NULL }, - { "ra", &ddb_regs.tf_regs[FRAME_RA], FCN_NULL }, - { "t12", &ddb_regs.tf_regs[FRAME_T12], FCN_NULL }, - { "at", &ddb_regs.tf_regs[FRAME_AT], FCN_NULL }, - { "gp", &ddb_regs.tf_regs[FRAME_GP], FCN_NULL }, - { "sp", &ddb_regs.tf_regs[FRAME_SP], FCN_NULL }, - { "pc", &ddb_regs.tf_regs[FRAME_PC], FCN_NULL }, - { "ps", &ddb_regs.tf_regs[FRAME_PS], FCN_NULL }, - { "ai", &ddb_regs.tf_regs[FRAME_T11], FCN_NULL }, - { "pv", &ddb_regs.tf_regs[FRAME_T12], FCN_NULL }, + { "v0", (db_expr_t *)FRAME_V0, db_frame }, + { "t0", (db_expr_t *)FRAME_T0, db_frame }, + { "t1", (db_expr_t *)FRAME_T1, db_frame }, + { "t2", (db_expr_t *)FRAME_T2, db_frame }, + { "t3", (db_expr_t *)FRAME_T3, db_frame }, + { "t4", (db_expr_t *)FRAME_T4, db_frame }, + { "t5", (db_expr_t *)FRAME_T5, db_frame }, + { "t6", (db_expr_t *)FRAME_T6, db_frame }, + { "t7", (db_expr_t *)FRAME_T7, db_frame }, + { "s0", (db_expr_t *)FRAME_S0, db_frame }, + { "s1", (db_expr_t *)FRAME_S1, db_frame }, + { "s2", (db_expr_t *)FRAME_S2, db_frame }, + { "s3", (db_expr_t *)FRAME_S3, db_frame }, + { "s4", (db_expr_t *)FRAME_S4, db_frame }, + { "s5", (db_expr_t *)FRAME_S5, db_frame }, + { "s6", (db_expr_t *)FRAME_S6, db_frame }, + { "a0", (db_expr_t *)FRAME_A0, db_frame }, + { "a1", (db_expr_t *)FRAME_A1, db_frame }, + { "a2", (db_expr_t *)FRAME_A2, db_frame }, + { "a3", (db_expr_t *)FRAME_A3, db_frame }, + { "a4", (db_expr_t *)FRAME_A4, db_frame }, + { "a5", (db_expr_t *)FRAME_A5, db_frame }, + { "t8", (db_expr_t *)FRAME_T8, db_frame }, + { "t9", (db_expr_t *)FRAME_T9, db_frame }, + { "t10", (db_expr_t *)FRAME_T10, db_frame }, + { "t11", (db_expr_t *)FRAME_T11, db_frame }, + { "ra", (db_expr_t *)FRAME_RA, db_frame }, + { "t12", (db_expr_t *)FRAME_T12, db_frame }, + { "at", (db_expr_t *)FRAME_AT, db_frame }, + { "gp", (db_expr_t *)FRAME_GP, db_frame }, + { "sp", (db_expr_t *)FRAME_SP, db_frame }, + { "pc", (db_expr_t *)FRAME_PC, db_frame }, + { "ps", (db_expr_t *)FRAME_PS, db_frame }, + { "ai", (db_expr_t *)FRAME_T11, db_frame }, + { "pv", (db_expr_t *)FRAME_T12, db_frame }, }; struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]); -/* - * Print trap reason. - */ -void -ddbprinttrap(a0, a1, a2, entry) - unsigned long a0, a1, a2, entry; +static int +db_frame(struct db_variable *vp, db_expr_t *valuep, int op) { - /* XXX Implement. */ - - printf("ddbprinttrap(0x%lx, 0x%lx, 0x%lx, 0x%lx)\n", a0, a1, a2, - entry); -} - -/* - * ddb_trap - field a kernel trap - */ -int -kdb_trap(a0, a1, a2, entry, regs) - unsigned long a0, a1, a2, entry; - db_regs_t *regs; -{ - int ddb_mode = !(boothowto & RB_GDB); - register_t s; - - /* - * Don't bother checking for usermode, since a benign entry - * by the kernel (call to Debugger() or a breakpoint) has - * already checked for usermode. If neither of those - * conditions exist, something Bad has happened. - */ - - if (entry != ALPHA_KENTRY_IF || - (a0 != ALPHA_IF_CODE_BUGCHK && a0 != ALPHA_IF_CODE_BPT - && a0 != ALPHA_IF_CODE_GENTRAP)) { -#if 0 - if (ddb_mode) { - db_printf("ddbprinttrap from 0x%lx\n", /* XXX */ - regs->tf_regs[FRAME_PC]); - ddbprinttrap(a0, a1, a2, entry); - /* - * Tell caller "We did NOT handle the trap." - * Caller should panic, or whatever. - */ - return (0); - } -#endif - if (db_nofault) { - jmp_buf *no_fault = db_nofault; - db_nofault = 0; - longjmp(*no_fault, 1); - } - } - - /* - * XXX Should switch to DDB's own stack, here. - */ - - ddb_regs = *regs; - - s = intr_disable(); - -#ifdef SMP -#ifdef DIAGNOSTIC - db_printf("stopping %x\n", PCPU_GET(other_cpus)); -#endif - stop_cpus(PCPU_GET(other_cpus)); -#ifdef DIAGNOSTIC - db_printf("stopped_cpus=%x\n", stopped_cpus); -#endif -#endif - - db_active++; - - if (ddb_mode) { - cndbctl(TRUE); /* DDB active, unblank video */ - db_trap(entry, a0); /* Where the work happens */ - cndbctl(FALSE); /* DDB inactive */ - } else - gdb_handle_exception(&ddb_regs, entry, a0); - - db_active--; - -#ifdef SMP - restart_cpus(stopped_cpus); -#endif - - intr_restore(s); - - *regs = ddb_regs; - - /* - * Tell caller "We HAVE handled the trap." - */ + if (kdb_frame == NULL) + return (0); + if (op == DB_VAR_GET) + *valuep = kdb_frame->tf_regs[(uintptr_t)vp->valuep]; + else + kdb_frame->tf_regs[(uintptr_t)vp->valuep] = *valuep; return (1); } /* * Read bytes from kernel address space for debugger. */ -void -db_read_bytes(addr, size, data) - vm_offset_t addr; - register size_t size; - register char *data; +int +db_read_bytes(vm_offset_t addr, size_t size, char *data) { - register char *src; - - db_nofault = &db_jmpbuf; - - src = (char *)addr; - while (size-- > 0) - *data++ = *src++; - - db_nofault = 0; + jmp_buf jb; + void *prev_jb; + char *src; + int ret; + + prev_jb = kdb_jmpbuf(jb); + ret = setjmp(jb); + if (ret == 0) { + src = (char *)addr; + while (size-- > 0) + *data++ = *src++; + } + (void)kdb_jmpbuf(prev_jb); + return (ret); } /* * Write bytes to kernel address space for debugger. */ -void -db_write_bytes(addr, size, data) - vm_offset_t addr; - register size_t size; - register char *data; -{ - register char *dst; - - db_nofault = &db_jmpbuf; - - dst = (char *)addr; - while (size-- > 0) - *dst++ = *data++; - alpha_pal_imb(); - - db_nofault = 0; -} - -void -Debugger(const char* msg) +int +db_write_bytes(vm_offset_t addr, size_t size, char *data) { - u_int saveintr; - - printf("%s\n", msg); - saveintr = alpha_pal_swpipl(ALPHA_PSL_IPL_HIGH); - __asm("call_pal 0x81"); /* XXX bugchk */ - alpha_pal_swpipl(saveintr); + jmp_buf jb; + void *prev_jb; + char *dst; + int ret; + + prev_jb = kdb_jmpbuf(jb); + ret = setjmp(jb); + if (ret == 0) { + dst = (char *)addr; + while (size-- > 0) + *dst++ = *data++; + alpha_pal_imb(); + } + (void)kdb_jmpbuf(prev_jb); + return (ret); } /* @@ -338,9 +231,7 @@ static int reg_to_frame[32] = { }; u_long -db_register_value(regs, regno) - db_regs_t *regs; - int regno; +db_register_value(int regno) { if (regno > 31 || regno < 0) { @@ -351,7 +242,7 @@ db_register_value(regs, regno) if (regno == 31) return (0); - return (regs->tf_regs[reg_to_frame[regno]]); + return (kdb_frame->tf_regs[reg_to_frame[regno]]); } /* @@ -446,19 +337,6 @@ db_inst_unconditional_flow_transfer(ins) return (FALSE); } -#if 0 -boolean_t -db_inst_spill(ins, regn) - int ins, regn; -{ - alpha_instruction insn; - - insn.bits = ins; - return ((insn.mem_format.opcode == op_stq) && - (insn.mem_format.rd == regn)); -} -#endif - boolean_t db_inst_load(ins) int ins; @@ -520,10 +398,7 @@ db_inst_store(ins) } db_addr_t -db_branch_taken(ins, pc, regs) - int ins; - db_addr_t pc; - db_regs_t *regs; +db_branch_taken(int ins, db_addr_t pc) { alpha_instruction insn; db_addr_t newpc; @@ -534,7 +409,7 @@ db_branch_taken(ins, pc, regs) * Jump format: target PC is (contents of instruction's "RB") & ~3. */ case op_j: - newpc = db_register_value(regs, insn.jump_format.rs) & ~3; + newpc = db_register_value(insn.jump_format.rs) & ~3; break; /* diff --git a/sys/alpha/alpha/db_trace.c b/sys/alpha/alpha/db_trace.c index 6eea6b19ef217..79ed437e0749c 100644 --- a/sys/alpha/alpha/db_trace.c +++ b/sys/alpha/alpha/db_trace.c @@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/kdb.h> #include <sys/proc.h> #include <sys/user.h> #include <sys/sysent.h> @@ -60,11 +61,6 @@ __FBSDID("$FreeBSD$"); #include <ddb/db_output.h> #include <alpha/alpha/db_instruction.h> -struct trace_request { - register_t ksp; - register_t pc; -}; - /* * Information about the `standard' Alpha function prologue. */ @@ -186,13 +182,15 @@ sym_is_trapsymbol(uintptr_t v) } static void -decode_syscall(int number, struct proc *p) +decode_syscall(int number, struct thread *td) { + struct proc *p; c_db_sym_t sym; db_expr_t diff; sy_call_t *f; const char *symname; + p = (td != NULL) ? td->td_proc : NULL; db_printf(" (%d", number); if (p != NULL && 0 <= number && number < p->p_sysent->sv_size) { f = p->p_sysent->sv_table[number].sy_call; @@ -205,99 +203,34 @@ decode_syscall(int number, struct proc *p) db_printf(")"); } -void -db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, char *modif) +static int +db_backtrace(struct thread *td, db_addr_t frame, db_addr_t pc, int count) { - db_addr_t callpc = 0, frame = 0, symval; struct prologue_info pi; - db_expr_t diff; + struct trapframe *tf; + const char *symname; c_db_sym_t sym; + db_expr_t diff; + db_addr_t symval; + u_long last_ipl, tfps; int i; - u_long tfps; - const char *symname; - struct pcb *pcbp; - struct trapframe *tf = NULL; - boolean_t ra_from_tf = FALSE; - boolean_t ra_from_pcb; - u_long last_ipl = ~0L; - struct proc *p = NULL; - struct thread *td = NULL; - boolean_t have_trapframe = FALSE; - pid_t pid; if (count == -1) - count = 65535; - - if (!have_addr) { - td = curthread; - p = td->td_proc; - addr = DDB_REGS->tf_regs[FRAME_SP] - FRAME_SIZE * 8; - tf = (struct trapframe *)addr; - have_trapframe = 1; - } else if (addr < KERNBASE) { - pid = (addr % 16) + ((addr >> 4) % 16) * 10 + - ((addr >> 8) % 16) * 100 + ((addr >> 12) % 16) * 1000 + - ((addr >> 16) % 16) * 10000; - /* - * The pcb for curproc is not valid at this point, - * so fall back to the default case. - */ - if (pid == curthread->td_proc->p_pid) { - td = curthread; - p = td->td_proc; - addr = DDB_REGS->tf_regs[FRAME_SP] - FRAME_SIZE * 8; - tf = (struct trapframe *)addr; - have_trapframe = 1; - } else { - /* sx_slock(&allproc_lock); */ - LIST_FOREACH(p, &allproc, p_list) { - if (p->p_pid == pid) - break; - } - /* sx_sunlock(&allproc_lock); */ - if (p == NULL) { - db_printf("pid %d not found\n", pid); - return; - } - if ((p->p_sflag & PS_INMEM) == 0) { - db_printf("pid %d swapped out\n", pid); - return; - } - pcbp = FIRST_THREAD_IN_PROC(p)->td_pcb; /* XXXKSE */ - addr = (db_expr_t)pcbp->pcb_hw.apcb_ksp; - callpc = pcbp->pcb_context[7]; - frame = addr; - } - } else { - struct trace_request *tr; - - tr = (struct trace_request *)addr; - if (tr->ksp < KERNBASE || tr->pc < KERNBASE) { - db_printf("alpha trace requires known PC =eject=\n"); - return; - } - callpc = tr->pc; - addr = tr->ksp; - frame = addr; - } + count = 1024; + last_ipl = ~0L; + tf = NULL; while (count--) { - if (have_trapframe) { - frame = (db_addr_t)tf + FRAME_SIZE * 8; - callpc = tf->tf_regs[FRAME_PC]; - ra_from_tf = TRUE; - have_trapframe = 0; - } - sym = db_search_symbol(callpc, DB_STGY_ANY, &diff); + sym = db_search_symbol(pc, DB_STGY_ANY, &diff); if (sym == DB_SYM_NULL) - break; + return (ENOENT); db_symbol_values(sym, &symname, (db_expr_t *)&symval); - if (callpc < symval) { - db_printf("symbol botch: callpc 0x%lx < " - "func 0x%lx (%s)\n", callpc, symval, symname); - return; + if (pc < symval) { + db_printf("symbol botch: pc 0x%lx < " + "func 0x%lx (%s)\n", pc, symval, symname); + return (0); } /* @@ -328,7 +261,7 @@ db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, char *m * debugger (for serious debugging). */ db_printf("%s() at ", symname); - db_printsym(callpc, DB_STGY_PROC); + db_printsym(pc, DB_STGY_PROC); db_printf("\n"); /* @@ -337,7 +270,6 @@ db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, char *m */ if (sym_is_trapsymbol(symval)) { tf = (struct trapframe *)frame; - for (i = 0; special_symbols[i].ss_val != 0; ++i) if (symval == special_symbols[i].ss_val) db_printf("--- %s", @@ -345,7 +277,7 @@ db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, char *m tfps = tf->tf_regs[FRAME_PS]; if (symval == (uintptr_t)&XentSys) - decode_syscall(tf->tf_regs[FRAME_V0], p); + decode_syscall(tf->tf_regs[FRAME_V0], td); if ((tfps & ALPHA_PSL_IPL_MASK) != last_ipl) { last_ipl = tfps & ALPHA_PSL_IPL_MASK; if (symval != (uintptr_t)&XentSys) @@ -356,7 +288,8 @@ db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, char *m db_printf("--- user mode ---\n"); break; /* Terminate search. */ } - have_trapframe = 1; + frame = (db_addr_t)(tf + 1); + pc = tf->tf_regs[FRAME_PC]; continue; } @@ -366,8 +299,8 @@ db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, char *m * * XXX How does this interact w/ alloca()?! */ - if (decode_prologue(callpc, symval, &pi)) - return; + if (decode_prologue(pc, symval, &pi)) + return (0); if ((pi.pi_regmask & (1 << 26)) == 0) { /* * No saved RA found. We might have RA from @@ -375,37 +308,56 @@ db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, char *m * in a leaf call). If not, we've found the * root of the call graph. */ - if (ra_from_tf) - callpc = tf->tf_regs[FRAME_RA]; + if (tf) + pc = tf->tf_regs[FRAME_RA]; else { db_printf("--- root of call graph ---\n"); break; } } else - callpc = *(u_long *)(frame + pi.pi_reg_offset[26]); - ra_from_tf = ra_from_pcb = FALSE; -#if 0 - /* - * The call was actually made at RA - 4; the PC is - * updated before being stored in RA. - */ - callpc -= 4; -#endif + pc = *(u_long *)(frame + pi.pi_reg_offset[26]); frame += pi.pi_frame_size; + tf = NULL; } + + return (0); } void -db_print_backtrace(void) +db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, + char *modif) { - struct trace_request tr; + struct thread *td; + + td = (have_addr) ? kdb_thr_lookup(addr) : kdb_thread; + if (td == NULL) { + db_printf("Thread %d not found\n", (int)addr); + return; + } + db_trace_thread(td, count); +} + +void +db_trace_self(void) +{ + register_t pc, sp; __asm __volatile( " mov $30,%0 \n" " lda %1,1f \n" "1:\n" - : "=r" (tr.ksp), "=r" (tr.pc)); - db_stack_trace_cmd((db_addr_t)&tr, 1, -1, NULL); + : "=r" (sp), "=r" (pc)); + db_backtrace(curthread, sp, pc, -1); +} + +int +db_trace_thread(struct thread *thr, int count) +{ + struct pcb *ctx; + + ctx = kdb_thr_ctx(thr); + return (db_backtrace(thr, ctx->pcb_hw.apcb_ksp, ctx->pcb_context[7], + count)); } int diff --git a/sys/alpha/include/db_machdep.h b/sys/alpha/include/db_machdep.h index d2c4837d21f5f..3f130ab1b94bd 100644 --- a/sys/alpha/include/db_machdep.h +++ b/sys/alpha/include/db_machdep.h @@ -31,54 +31,40 @@ #ifndef _ALPHA_DB_MACHDEP_H_ #define _ALPHA_DB_MACHDEP_H_ -/* - * Machine-dependent defines for new kernel debugger. - */ -#ifndef KLD_MODULE -#include "opt_ddb.h" -#endif - #include <sys/param.h> #include <vm/vm.h> #include <machine/frame.h> -#define DB_NO_AOUT +#define DB_NO_AOUT typedef vm_offset_t db_addr_t; /* address - unsigned */ typedef long db_expr_t; /* expression - signed */ -typedef struct trapframe db_regs_t; -#ifdef DDB -extern db_regs_t ddb_regs; /* register state */ -#endif -#define DDB_REGS (&ddb_regs) - -#define PC_REGS(regs) ((db_addr_t)(regs)->tf_regs[FRAME_PC]) +#define PC_REGS() ((db_addr_t)kdb_thrctx->pcb_context[7]) #define BKPT_INST 0x00000080 /* breakpoint instruction */ #define BKPT_SIZE (4) /* size of breakpoint inst */ #define BKPT_SET(inst) (BKPT_INST) -#define FIXUP_PC_AFTER_BREAK \ - (ddb_regs.tf_regs[FRAME_PC] -= BKPT_SIZE); +#define FIXUP_PC_AFTER_BREAK (kdb_frame->tf_regs[FRAME_PC] -= BKPT_SIZE); #define SOFTWARE_SSTEP 1 /* no hardware support */ -#define IS_BREAKPOINT_TRAP(type, code) ((type) == ALPHA_KENTRY_IF && \ - (code) == ALPHA_IF_CODE_BPT) + +#define IS_BREAKPOINT_TRAP(type, code) \ + ((type) == ALPHA_KENTRY_IF && (code) == ALPHA_IF_CODE_BPT) #define IS_WATCHPOINT_TRAP(type, code) 0 /* * Functions needed for software single-stepping. */ - -boolean_t db_inst_trap_return(int inst); -boolean_t db_inst_return(int inst); -boolean_t db_inst_call(int inst); -boolean_t db_inst_branch(int inst); -boolean_t db_inst_load(int inst); -boolean_t db_inst_store(int inst); -boolean_t db_inst_unconditional_flow_transfer(int inst); -db_addr_t db_branch_taken(int inst, db_addr_t pc, db_regs_t *regs); +boolean_t db_inst_trap_return(int inst); +boolean_t db_inst_return(int inst); +boolean_t db_inst_call(int inst); +boolean_t db_inst_branch(int inst); +boolean_t db_inst_load(int inst); +boolean_t db_inst_store(int inst); +boolean_t db_inst_unconditional_flow_transfer(int inst); +db_addr_t db_branch_taken(int inst, db_addr_t pc); #define inst_trap_return(ins) db_inst_trap_return(ins) #define inst_return(ins) db_inst_return(ins) @@ -88,15 +74,12 @@ db_addr_t db_branch_taken(int inst, db_addr_t pc, db_regs_t *regs); #define inst_store(ins) db_inst_store(ins) #define inst_unconditional_flow_transfer(ins) \ db_inst_unconditional_flow_transfer(ins) -#define branch_taken(ins, pc, regs) \ - db_branch_taken((ins), (pc), (regs)) +#define branch_taken(ins, pc) db_branch_taken(ins, pc) /* No delay slots on Alpha. */ #define next_instr_address(v, b) ((db_addr_t) ((b) ? (v) : ((v) + 4))) -u_long db_register_value(db_regs_t *, int); -int kdb_trap(unsigned long, unsigned long, unsigned long, - unsigned long, struct trapframe *); +u_long db_register_value(int); /* * Pretty arbitrary diff --git a/sys/amd64/amd64/db_interface.c b/sys/amd64/amd64/db_interface.c index f6bf218981930..67c8ae5c6549a 100644 --- a/sys/amd64/amd64/db_interface.c +++ b/sys/amd64/amd64/db_interface.c @@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$"); */ #include <sys/param.h> #include <sys/systm.h> +#include <sys/kdb.h> #include <sys/reboot.h> #include <sys/cons.h> #include <sys/pcpu.h> @@ -45,284 +46,95 @@ __FBSDID("$FreeBSD$"); #include <ddb/ddb.h> -#include <machine/setjmp.h> - -static jmp_buf *db_nofault = 0; -extern jmp_buf db_jmpbuf; - -extern void gdb_handle_exception(db_regs_t *, int, int); - -int db_active; -db_regs_t ddb_regs; - -static jmp_buf db_global_jmpbuf; - -/* - * kdb_trap - field a TRACE or BPT trap - */ -int -kdb_trap(int type, int code, struct amd64_saved_state *regs) -{ - u_long ef; - volatile int ddb_mode = !(boothowto & RB_GDB); - - /* - * XXX try to do nothing if the console is in graphics mode. - * Handle trace traps (and hardware breakpoints...) by ignoring - * them except for forgetting about them. Return 0 for other - * traps to say that we haven't done anything. The trap handler - * will usually panic. We should handle breakpoint traps for - * our breakpoints by disarming our breakpoints and fixing up - * %eip. - */ - if (cnunavailable() != 0 && ddb_mode) { - if (type == T_TRCTRAP) { - regs->tf_rflags &= ~PSL_T; - return (1); - } - return (0); - } - - ef = read_rflags(); - disable_intr(); - -#ifdef SMP - -#if defined(VERBOSE_CPUSTOP_ON_DDBBREAK) - db_printf("\nCPU%d stopping CPUs: 0x%08x...", PCPU_GET(cpuid), - PCPU_GET(other_cpus)); -#endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */ - - /* We stop all CPUs except ourselves (obviously) */ - stop_cpus(PCPU_GET(other_cpus)); - -#if defined(VERBOSE_CPUSTOP_ON_DDBBREAK) - db_printf(" stopped.\n"); -#endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */ - -#endif /* SMP */ - - switch (type) { - case T_BPTFLT: /* breakpoint */ - case T_TRCTRAP: /* debug exception */ - break; - - default: - /* - * XXX this is almost useless now. In most cases, - * trap_fatal() has already printed a much more verbose - * message. However, it is dangerous to print things in - * trap_fatal() - printf() might be reentered and trap. - * The debugger should be given control first. - */ - if (ddb_mode) - db_printf("kernel: type %d trap, code=%x\n", type, code); - - if (db_nofault) { - jmp_buf *no_fault = db_nofault; - db_nofault = 0; - longjmp(*no_fault, 1); - } - } - - /* - * This handles unexpected traps in ddb commands, including calls to - * non-ddb functions. db_nofault only applies to memory accesses by - * internal ddb commands. - */ - if (db_active) - longjmp(db_global_jmpbuf, 1); - - /* - * XXX We really should switch to a local stack here. - */ - ddb_regs = *regs; - - /* - * If in kernel mode, esp and ss are not saved, so dummy them up. - */ - if (ISPL(regs->tf_cs) == 0) { - ddb_regs.tf_rsp = (long)®s->tf_rsp; - ddb_regs.tf_ss = rss(); - } - - (void) setjmp(db_global_jmpbuf); - if (ddb_mode) { - if (!db_active) - cndbctl(TRUE); - db_active = 1; - db_trap(type, code); - cndbctl(FALSE); - } else { - db_active = 1; - gdb_handle_exception(&ddb_regs, type, code); - } - db_active = 0; - - regs->tf_rip = ddb_regs.tf_rip; - regs->tf_rflags = ddb_regs.tf_rflags; - regs->tf_rax = ddb_regs.tf_rax; - regs->tf_rcx = ddb_regs.tf_rcx; - regs->tf_rdx = ddb_regs.tf_rdx; - regs->tf_rbx = ddb_regs.tf_rbx; - - /* - * If in user mode, the saved ESP and SS were valid, restore them. - */ - if (ISPL(regs->tf_cs)) { - regs->tf_rsp = ddb_regs.tf_rsp; - regs->tf_ss = ddb_regs.tf_ss & 0xffff; - } - - regs->tf_rbp = ddb_regs.tf_rbp; - regs->tf_rsi = ddb_regs.tf_rsi; - regs->tf_rdi = ddb_regs.tf_rdi; - - regs->tf_r8 = ddb_regs.tf_r8; - regs->tf_r9 = ddb_regs.tf_r9; - regs->tf_r10 = ddb_regs.tf_r10; - regs->tf_r11 = ddb_regs.tf_r11; - regs->tf_r12 = ddb_regs.tf_r12; - regs->tf_r13 = ddb_regs.tf_r13; - regs->tf_r14 = ddb_regs.tf_r14; - regs->tf_r15 = ddb_regs.tf_r15; - -#if 0 - regs->tf_es = ddb_regs.tf_es & 0xffff; - regs->tf_fs = ddb_regs.tf_fs & 0xffff; -#endif - regs->tf_cs = ddb_regs.tf_cs & 0xffff; -#if 0 - regs->tf_ds = ddb_regs.tf_ds & 0xffff; -#endif - -#ifdef SMP - -#if defined(VERBOSE_CPUSTOP_ON_DDBBREAK) - db_printf("\nCPU%d restarting CPUs: 0x%08x...", PCPU_GET(cpuid), - stopped_cpus); -#endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */ - - /* Restart all the CPUs we previously stopped */ - if (stopped_cpus != PCPU_GET(other_cpus) && smp_started != 0) { - db_printf("whoa, other_cpus: 0x%08x, stopped_cpus: 0x%08x\n", - PCPU_GET(other_cpus), stopped_cpus); - panic("stop_cpus() failed"); - } - restart_cpus(stopped_cpus); - -#if defined(VERBOSE_CPUSTOP_ON_DDBBREAK) - db_printf(" restarted.\n"); -#endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */ - -#endif /* SMP */ - - write_rflags(ef); - - return (1); -} - /* * Read bytes from kernel address space for debugger. */ -void +int db_read_bytes(vm_offset_t addr, size_t size, char *data) { - char *src; - - db_nofault = &db_jmpbuf; - - src = (char *)addr; - while (size-- > 0) - *data++ = *src++; - - db_nofault = 0; + jmp_buf jb; + void *prev_jb; + char *src; + int ret; + + prev_jb = kdb_jmpbuf(jb); + ret = setjmp(jb); + if (ret == 0) { + src = (char *)addr; + while (size-- > 0) + *data++ = *src++; + } + (void)kdb_jmpbuf(prev_jb); + return (ret); } /* * Write bytes to kernel address space for debugger. */ -void +int db_write_bytes(vm_offset_t addr, size_t size, char *data) { - char *dst; - + jmp_buf jb; + void *prev_jb; + char *dst; pt_entry_t *ptep0 = NULL; pt_entry_t oldmap0 = 0; vm_offset_t addr1; pt_entry_t *ptep1 = NULL; pt_entry_t oldmap1 = 0; - - db_nofault = &db_jmpbuf; - - if (addr > trunc_page((vm_offset_t)btext) - size && - addr < round_page((vm_offset_t)etext)) { - - ptep0 = vtopte(addr); - oldmap0 = *ptep0; - *ptep0 |= PG_RW; - - /* Map another page if the data crosses a page boundary. */ - if ((*ptep0 & PG_PS) == 0) { - addr1 = trunc_page(addr + size - 1); - if (trunc_page(addr) != addr1) { - ptep1 = vtopte(addr1); - oldmap1 = *ptep1; - *ptep1 |= PG_RW; - } - } else { - addr1 = trunc_2mpage(addr + size - 1); - if (trunc_2mpage(addr) != addr1) { - ptep1 = vtopte(addr1); - oldmap1 = *ptep1; - *ptep1 |= PG_RW; + int ret; + + prev_jb = kdb_jmpbuf(jb); + ret = setjmp(jb); + if (ret == 0) { + if (addr > trunc_page((vm_offset_t)btext) - size && + addr < round_page((vm_offset_t)etext)) { + + ptep0 = vtopte(addr); + oldmap0 = *ptep0; + *ptep0 |= PG_RW; + + /* + * Map another page if the data crosses a page + * boundary. + */ + if ((*ptep0 & PG_PS) == 0) { + addr1 = trunc_page(addr + size - 1); + if (trunc_page(addr) != addr1) { + ptep1 = vtopte(addr1); + oldmap1 = *ptep1; + *ptep1 |= PG_RW; + } + } else { + addr1 = trunc_2mpage(addr + size - 1); + if (trunc_2mpage(addr) != addr1) { + ptep1 = vtopte(addr1); + oldmap1 = *ptep1; + *ptep1 |= PG_RW; + } + } + + invltlb(); } - } - - invltlb(); - } - dst = (char *)addr; + dst = (char *)addr; - while (size-- > 0) - *dst++ = *data++; + while (size-- > 0) + *dst++ = *data++; + } - db_nofault = 0; + (void)kdb_jmpbuf(prev_jb); if (ptep0) { - *ptep0 = oldmap0; + *ptep0 = oldmap0; - if (ptep1) - *ptep1 = oldmap1; + if (ptep1) + *ptep1 = oldmap1; - invltlb(); + invltlb(); } -} -/* - * XXX - * Move this to machdep.c and allow it to be called if any debugger is - * installed. - */ -void -Debugger(const char *msg) -{ - static volatile u_int in_Debugger; - - /* - * XXX - * Do nothing if the console is in graphics mode. This is - * OK if the call is for the debugger hotkey but not if the call - * is a weak form of panicing. - */ - if (cnunavailable() != 0 && !(boothowto & RB_GDB)) - return; - - if (atomic_cmpset_acq_int(&in_Debugger, 0, 1)) { - db_printf("Debugger(\"%s\")\n", msg); - breakpoint(); - atomic_store_rel_int(&in_Debugger, 0); - } + return (ret); } void diff --git a/sys/amd64/amd64/db_trace.c b/sys/amd64/amd64/db_trace.c index 6df1bd10034b2..03842cb530eb7 100644 --- a/sys/amd64/amd64/db_trace.c +++ b/sys/amd64/amd64/db_trace.c @@ -29,6 +29,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/kdb.h> #include <sys/proc.h> #include <sys/sysent.h> @@ -46,56 +47,134 @@ __FBSDID("$FreeBSD$"); #include <ddb/db_sym.h> #include <ddb/db_variables.h> -db_varfcn_t db_dr0; -db_varfcn_t db_dr1; -db_varfcn_t db_dr2; -db_varfcn_t db_dr3; -db_varfcn_t db_dr4; -db_varfcn_t db_dr5; -db_varfcn_t db_dr6; -db_varfcn_t db_dr7; +static db_varfcn_t db_dr0; +static db_varfcn_t db_dr1; +static db_varfcn_t db_dr2; +static db_varfcn_t db_dr3; +static db_varfcn_t db_dr4; +static db_varfcn_t db_dr5; +static db_varfcn_t db_dr6; +static db_varfcn_t db_dr7; +static db_varfcn_t db_frame; +static db_varfcn_t db_rsp; +static db_varfcn_t db_ss; /* * Machine register set. */ +#define DB_OFFSET(x) (db_expr_t *)offsetof(struct trapframe, x) struct db_variable db_regs[] = { - { "cs", &ddb_regs.tf_cs, FCN_NULL }, + { "cs", DB_OFFSET(tf_cs), db_frame }, #if 0 - { "ds", &ddb_regs.tf_ds, FCN_NULL }, - { "es", &ddb_regs.tf_es, FCN_NULL }, - { "fs", &ddb_regs.tf_fs, FCN_NULL }, - { "gs", &ddb_regs.tf_gs, FCN_NULL }, + { "ds", DB_OFFSET(tf_ds), db_frame }, + { "es", DB_OFFSET(tf_es), db_frame }, + { "fs", DB_OFFSET(tf_fs), db_frame }, + { "gs", DB_OFFSET(tf_gs), db_frame }, #endif - { "ss", &ddb_regs.tf_ss, FCN_NULL }, - { "rax", &ddb_regs.tf_rax, FCN_NULL }, - { "rcx", &ddb_regs.tf_rcx, FCN_NULL }, - { "rdx", &ddb_regs.tf_rdx, FCN_NULL }, - { "rbx", &ddb_regs.tf_rbx, FCN_NULL }, - { "rsp", &ddb_regs.tf_rsp, FCN_NULL }, - { "rbp", &ddb_regs.tf_rbp, FCN_NULL }, - { "rsi", &ddb_regs.tf_rsi, FCN_NULL }, - { "rdi", &ddb_regs.tf_rdi, FCN_NULL }, - { "r8", &ddb_regs.tf_r8, FCN_NULL }, - { "r9", &ddb_regs.tf_r9, FCN_NULL }, - { "r10", &ddb_regs.tf_r10, FCN_NULL }, - { "r11", &ddb_regs.tf_r11, FCN_NULL }, - { "r12", &ddb_regs.tf_r12, FCN_NULL }, - { "r13", &ddb_regs.tf_r13, FCN_NULL }, - { "r14", &ddb_regs.tf_r14, FCN_NULL }, - { "r15", &ddb_regs.tf_r15, FCN_NULL }, - { "rip", &ddb_regs.tf_rip, FCN_NULL }, - { "rflags", &ddb_regs.tf_rflags, FCN_NULL }, - { "dr0", NULL, db_dr0 }, - { "dr1", NULL, db_dr1 }, - { "dr2", NULL, db_dr2 }, - { "dr3", NULL, db_dr3 }, - { "dr4", NULL, db_dr4 }, - { "dr5", NULL, db_dr5 }, - { "dr6", NULL, db_dr6 }, - { "dr7", NULL, db_dr7 }, + { "ss", NULL, db_ss }, + { "rax", DB_OFFSET(tf_rax), db_frame }, + { "rcx", DB_OFFSET(tf_rcx), db_frame }, + { "rdx", DB_OFFSET(tf_rdx), db_frame }, + { "rbx", DB_OFFSET(tf_rbx), db_frame }, + { "rsp", NULL, db_rsp }, + { "rbp", DB_OFFSET(tf_rbp), db_frame }, + { "rsi", DB_OFFSET(tf_rsi), db_frame }, + { "rdi", DB_OFFSET(tf_rdi), db_frame }, + { "r8", DB_OFFSET(tf_r8), db_frame }, + { "r9", DB_OFFSET(tf_r9), db_frame }, + { "r10", DB_OFFSET(tf_r10), db_frame }, + { "r11", DB_OFFSET(tf_r11), db_frame }, + { "r12", DB_OFFSET(tf_r12), db_frame }, + { "r13", DB_OFFSET(tf_r13), db_frame }, + { "r14", DB_OFFSET(tf_r14), db_frame }, + { "r15", DB_OFFSET(tf_r15), db_frame }, + { "rip", DB_OFFSET(tf_rip), db_frame }, + { "rflags", DB_OFFSET(tf_rflags), db_frame }, + { "dr0", NULL, db_dr0 }, + { "dr1", NULL, db_dr1 }, + { "dr2", NULL, db_dr2 }, + { "dr3", NULL, db_dr3 }, + { "dr4", NULL, db_dr4 }, + { "dr5", NULL, db_dr5 }, + { "dr6", NULL, db_dr6 }, + { "dr7", NULL, db_dr7 }, }; struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]); +#define DB_DRX_FUNC(reg) \ +static int \ +db_ ## reg (vp, valuep, op) \ + struct db_variable *vp; \ + db_expr_t * valuep; \ + int op; \ +{ \ + if (op == DB_VAR_GET) \ + *valuep = r ## reg (); \ + else \ + load_ ## reg (*valuep); \ + return (1); \ +} + +DB_DRX_FUNC(dr0) +DB_DRX_FUNC(dr1) +DB_DRX_FUNC(dr2) +DB_DRX_FUNC(dr3) +DB_DRX_FUNC(dr4) +DB_DRX_FUNC(dr5) +DB_DRX_FUNC(dr6) +DB_DRX_FUNC(dr7) + +static __inline long +get_rsp(struct trapframe *tf) +{ + return ((ISPL(tf->tf_cs)) ? tf->tf_rsp : + (db_expr_t)tf + offsetof(struct trapframe, tf_rsp)); +} + +static int +db_frame(struct db_variable *vp, db_expr_t *valuep, int op) +{ + long *reg; + + if (kdb_frame == NULL) + return (0); + + reg = (long *)((uintptr_t)kdb_frame + (db_expr_t)vp->valuep); + if (op == DB_VAR_GET) + *valuep = *reg; + else + *reg = *valuep; + return (1); +} + +static int +db_rsp(struct db_variable *vp, db_expr_t *valuep, int op) +{ + + if (kdb_frame == NULL) + return (0); + + if (op == DB_VAR_GET) + *valuep = get_rsp(kdb_frame); + else if (ISPL(kdb_frame->tf_cs)) + kdb_frame->tf_rsp = *valuep; + return (1); +} + +static int +db_ss(struct db_variable *vp, db_expr_t *valuep, int op) +{ + + if (kdb_frame == NULL) + return (0); + + if (op == DB_VAR_GET) + *valuep = (ISPL(kdb_frame->tf_cs)) ? kdb_frame->tf_ss : rss(); + else if (ISPL(kdb_frame->tf_cs)) + kdb_frame->tf_ss = *valuep; + return (1); +} + /* * Stack trace. */ @@ -112,13 +191,10 @@ struct amd64_frame { #define INTERRUPT 2 #define SYSCALL 3 -static void db_nextframe(struct amd64_frame **, db_addr_t *, struct proc *); +static void db_nextframe(struct amd64_frame **, db_addr_t *, struct thread *); static int db_numargs(struct amd64_frame *); static void db_print_stack_entry(const char *, int, char **, long *, db_addr_t); -static void decode_syscall(int, struct proc *); -static void db_trace_one_stack(int count, boolean_t have_addr, - struct proc *p, struct amd64_frame *frame, db_addr_t callpc); - +static void decode_syscall(int, struct thread *); static char * watchtype_str(int type); int amd64_set_watch(int watchnum, unsigned int watchaddr, int size, int access, @@ -128,7 +204,6 @@ int db_md_set_watchpoint(db_expr_t addr, db_expr_t size); int db_md_clr_watchpoint(db_expr_t addr, db_expr_t size); void db_md_list_watchpoints(void); - /* * Figure out how many arguments were passed into the frame at "fp". */ @@ -189,16 +264,16 @@ db_print_stack_entry(name, narg, argnp, argp, callpc) } static void -decode_syscall(number, p) - int number; - struct proc *p; +decode_syscall(int number, struct thread *td) { + struct proc *p; c_db_sym_t sym; db_expr_t diff; sy_call_t *f; const char *symname; db_printf(" (%d", number); + p = (td != NULL) ? td->td_proc : NULL; if (p != NULL && 0 <= number && number < p->p_sysent->sv_size) { f = p->p_sysent->sv_table[number].sy_call; sym = db_search_symbol((db_addr_t)f, DB_STGY_ANY, &diff); @@ -214,10 +289,7 @@ decode_syscall(number, p) * Figure out the next frame up in the call stack. */ static void -db_nextframe(fp, ip, p) - struct amd64_frame **fp; /* in/out */ - db_addr_t *ip; /* out */ - struct proc *p; /* in */ +db_nextframe(struct amd64_frame **fp, db_addr_t *ip, struct thread *td) { struct trapframe *tf; int frame_type; @@ -265,8 +337,7 @@ db_nextframe(fp, ip, p) tf = (struct trapframe *)((long)*fp + 16); if (INKERNEL((long) tf)) { - rsp = (ISPL(tf->tf_cs) == SEL_UPL) ? - tf->tf_rsp : (long)&tf->tf_rsp; + rsp = get_rsp(tf); rip = tf->tf_rip; rbp = tf->tf_rbp; switch (frame_type) { @@ -275,7 +346,7 @@ db_nextframe(fp, ip, p) break; case SYSCALL: db_printf("--- syscall"); - decode_syscall(tf->tf_rax, p); + decode_syscall(tf->tf_rax, td); break; case INTERRUPT: db_printf("--- interrupt"); @@ -291,135 +362,26 @@ db_nextframe(fp, ip, p) *fp = (struct amd64_frame *) rbp; } -void -db_stack_trace_cmd(addr, have_addr, count, modif) - db_expr_t addr; - boolean_t have_addr; - db_expr_t count; - char *modif; +static int +db_backtrace(struct thread *td, struct trapframe *tf, + struct amd64_frame *frame, db_addr_t pc, int count) { - struct amd64_frame *frame; - struct proc *p; - struct pcb *pcb; - struct thread *td; - db_addr_t callpc; - pid_t pid; + struct amd64_frame *actframe; +#define MAXNARG 16 + char *argnames[MAXNARG], **argnp = NULL; + const char *name; + long *argp; + db_expr_t offset; + c_db_sym_t sym; + int narg; + boolean_t first; if (count == -1) count = 1024; - if (!have_addr) { - td = curthread; - p = td->td_proc; - frame = (struct amd64_frame *)ddb_regs.tf_rbp; - if (frame == NULL) - frame = (struct amd64_frame *)(ddb_regs.tf_rsp - 8); - callpc = (db_addr_t)ddb_regs.tf_rip; - } else if (!INKERNEL(addr)) { - pid = (addr % 16) + ((addr >> 4) % 16) * 10 + - ((addr >> 8) % 16) * 100 + ((addr >> 12) % 16) * 1000 + - ((addr >> 16) % 16) * 10000; - /* - * The pcb for curproc is not valid at this point, - * so fall back to the default case. - */ - if (pid == curthread->td_proc->p_pid) { - td = curthread; - p = td->td_proc; - frame = (struct amd64_frame *)ddb_regs.tf_rbp; - if (frame == NULL) - frame = (struct amd64_frame *) - (ddb_regs.tf_rsp - 8); - callpc = (db_addr_t)ddb_regs.tf_rip; - } else { - - /* sx_slock(&allproc_lock); */ - LIST_FOREACH(p, &allproc, p_list) { - if (p->p_pid == pid) - break; - } - /* sx_sunlock(&allproc_lock); */ - if (p == NULL) { - db_printf("pid %d not found\n", pid); - return; - } - if ((p->p_sflag & PS_INMEM) == 0) { - db_printf("pid %d swapped out\n", pid); - return; - } - pcb = FIRST_THREAD_IN_PROC(p)->td_pcb; /* XXXKSE */ - frame = (struct amd64_frame *)pcb->pcb_rbp; - if (frame == NULL) - frame = (struct amd64_frame *) - (pcb->pcb_rsp - 8); - callpc = (db_addr_t)pcb->pcb_rip; - } - } else { - p = NULL; - frame = (struct amd64_frame *)addr; - callpc = (db_addr_t)db_get_value((long)&frame->f_retaddr, 8, FALSE); - frame = frame->f_frame; - } - db_trace_one_stack(count, have_addr, p, frame, callpc); -} - -void -db_stack_thread(db_expr_t addr, boolean_t have_addr, - db_expr_t count, char *modif) -{ - struct amd64_frame *frame; - struct thread *td; - struct proc *p; - struct pcb *pcb; - db_addr_t callpc; - - if (!have_addr) - return; - if (!INKERNEL(addr)) { - printf("bad thread address"); - return; - } - td = (struct thread *)addr; - /* quick sanity check */ - if ((p = td->td_proc) != td->td_ksegrp->kg_proc) - return; - if (TD_IS_SWAPPED(td)) { - db_printf("thread at %p swapped out\n", td); - return; - } - if (td == curthread) { - frame = (struct amd64_frame *)ddb_regs.tf_rbp; - if (frame == NULL) - frame = (struct amd64_frame *)(ddb_regs.tf_rsp - 8); - callpc = (db_addr_t)ddb_regs.tf_rip; - } else { - pcb = td->td_pcb; - frame = (struct amd64_frame *)pcb->pcb_rbp; - if (frame == NULL) - frame = (struct amd64_frame *) (pcb->pcb_rsp - 8); - callpc = (db_addr_t)pcb->pcb_rip; - } - db_trace_one_stack(count, have_addr, p, frame, callpc); -} - -static void -db_trace_one_stack(int count, boolean_t have_addr, - struct proc *p, struct amd64_frame *frame, db_addr_t callpc) -{ - long *argp; - boolean_t first; - first = TRUE; while (count--) { - struct amd64_frame *actframe; - int narg; - const char * name; - db_expr_t offset; - c_db_sym_t sym; -#define MAXNARG 16 - char *argnames[MAXNARG], **argnp = NULL; - - sym = db_search_symbol(callpc, DB_STGY_ANY, &offset); + sym = db_search_symbol(pc, DB_STGY_ANY, &offset); db_symbol_values(sym, &name, NULL); /* @@ -435,37 +397,33 @@ db_trace_one_stack(int count, boolean_t have_addr, */ actframe = frame; if (first) { - if (!have_addr) { + if (tf != NULL) { int instr; - instr = db_get_value(callpc, 4, FALSE); + instr = db_get_value(pc, 4, FALSE); if ((instr & 0xffffffff) == 0xe5894855) { /* pushq %rbp; movq %rsp, %rbp */ - actframe = (struct amd64_frame *) - (ddb_regs.tf_rsp - 8); - } else if ((instr & 0x00ffffff) == 0x00e58948) { + actframe = (void *)(get_rsp(tf) - 8); + } else if ((instr & 0xffffff) == 0xe58948) { /* movq %rsp, %rbp */ - actframe = (struct amd64_frame *) - ddb_regs.tf_rsp; - if (ddb_regs.tf_rbp == 0) { - /* Fake caller's frame better. */ + actframe = (void *)get_rsp(tf); + if (tf->tf_rbp == 0) { + /* Fake frame better. */ frame = actframe; } - } else if ((instr & 0x000000ff) == 0x000000c3) { + } else if ((instr & 0xff) == 0xc3) { /* ret */ - actframe = (struct amd64_frame *) - (ddb_regs.tf_rsp - 8); + actframe = (void *)(get_rsp(tf) - 8); } else if (offset == 0) { - /* Probably a symbol in assembler code. */ - actframe = (struct amd64_frame *) - (ddb_regs.tf_rsp - 8); + /* Probably an assembler symbol. */ + actframe = (void *)(get_rsp(tf) - 8); } } else if (strcmp(name, "fork_trampoline") == 0) { /* * Don't try to walk back on a stack for a * process that hasn't actually been run yet. */ - db_print_stack_entry(name, 0, 0, 0, callpc); + db_print_stack_entry(name, 0, 0, 0, pc); break; } first = FALSE; @@ -479,60 +437,68 @@ db_trace_one_stack(int count, boolean_t have_addr, narg = db_numargs(frame); } - db_print_stack_entry(name, narg, argnp, argp, callpc); + db_print_stack_entry(name, narg, argnp, argp, pc); if (actframe != frame) { /* `frame' belongs to caller. */ - callpc = (db_addr_t) + pc = (db_addr_t) db_get_value((long)&actframe->f_retaddr, 8, FALSE); continue; } - db_nextframe(&frame, &callpc, p); + db_nextframe(&frame, &pc, td); - if (INKERNEL((long) callpc) && !INKERNEL((long) frame)) { - sym = db_search_symbol(callpc, DB_STGY_ANY, &offset); + if (INKERNEL((long)pc) && !INKERNEL((long)frame)) { + sym = db_search_symbol(pc, DB_STGY_ANY, &offset); db_symbol_values(sym, &name, NULL); - db_print_stack_entry(name, 0, 0, 0, callpc); + db_print_stack_entry(name, 0, 0, 0, pc); break; } if (!INKERNEL((long) frame)) { break; } } + + return (0); +} + +void +db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, + char *modif) +{ + struct thread *td; + + td = (have_addr) ? kdb_thr_lookup(addr) : kdb_thread; + if (td == NULL) { + db_printf("Thread %ld not found\n", addr); + return; + } + db_trace_thread(td, count); } void -db_print_backtrace(void) +db_trace_self(void) { - register_t ebp; + struct amd64_frame *frame; + db_addr_t callpc; + register_t rbp; - __asm __volatile("movq %%rbp,%0" : "=r" (ebp)); - db_stack_trace_cmd(ebp, 1, -1, NULL); + __asm __volatile("movq %%rbp,%0" : "=r" (rbp)); + frame = (struct amd64_frame *)rbp; + callpc = (db_addr_t)db_get_value((long)&frame->f_retaddr, 8, FALSE); + frame = frame->f_frame; + db_backtrace(curthread, NULL, frame, callpc, -1); } -#define DB_DRX_FUNC(reg) \ -int \ -db_ ## reg (vp, valuep, op) \ - struct db_variable *vp; \ - db_expr_t * valuep; \ - int op; \ -{ \ - if (op == DB_VAR_GET) \ - *valuep = r ## reg (); \ - else \ - load_ ## reg (*valuep); \ - return (0); \ -} +int +db_trace_thread(struct thread *thr, int count) +{ + struct pcb *ctx; -DB_DRX_FUNC(dr0) -DB_DRX_FUNC(dr1) -DB_DRX_FUNC(dr2) -DB_DRX_FUNC(dr3) -DB_DRX_FUNC(dr4) -DB_DRX_FUNC(dr5) -DB_DRX_FUNC(dr6) -DB_DRX_FUNC(dr7) + ctx = kdb_thr_ctx(thr); + return (db_backtrace(thr, NULL, (struct amd64_frame *)ctx->pcb_rbp, + ctx->pcb_rip, count)); +} int amd64_set_watch(watchnum, watchaddr, size, access, d) diff --git a/sys/amd64/include/db_machdep.h b/sys/amd64/include/db_machdep.h index 18b5e5d981f51..0a737ebb64bf8 100644 --- a/sys/amd64/include/db_machdep.h +++ b/sys/amd64/include/db_machdep.h @@ -30,30 +30,23 @@ #define _MACHINE_DB_MACHDEP_H_ #include <machine/frame.h> -#include <machine/psl.h> #include <machine/trap.h> -#define amd64_saved_state trapframe - typedef vm_offset_t db_addr_t; /* address - unsigned */ typedef long db_expr_t; /* expression - signed */ -typedef struct amd64_saved_state db_regs_t; -extern db_regs_t ddb_regs; /* register state */ -#define DDB_REGS (&ddb_regs) - -#define PC_REGS(regs) ((db_addr_t)(regs)->tf_rip) +#define PC_REGS() ((db_addr_t)kdb_thrctx->pcb_rip) #define BKPT_INST 0xcc /* breakpoint instruction */ #define BKPT_SIZE (1) /* size of breakpoint inst */ #define BKPT_SET(inst) (BKPT_INST) -#define BKPT_SKIP ddb_regs.tf_rip += 1 +#define BKPT_SKIP kdb_frame->tf_rip += 1 -#define FIXUP_PC_AFTER_BREAK ddb_regs.tf_rip -= 1; +#define FIXUP_PC_AFTER_BREAK kdb_frame->tf_rip -= 1; -#define db_clear_single_step(regs) ((regs)->tf_rflags &= ~PSL_T) -#define db_set_single_step(regs) ((regs)->tf_rflags |= PSL_T) +#define db_clear_single_step kdb_cpu_clear_singlestep +#define db_set_single_step kdb_cpu_set_singlestep #define IS_BREAKPOINT_TRAP(type, code) ((type) == T_BPTFLT) /* diff --git a/sys/conf/files b/sys/conf/files index 32ece0714a979..811f502f92012 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -249,25 +249,23 @@ crypto/rijndael/rijndael-api.c optional ipsec opencrypto/rmd160.c optional ipsec crypto/sha1.c optional ipsec crypto/sha2/sha2.c optional ipsec -ddb/db_access.c optional ddb -ddb/db_break.c optional ddb -ddb/db_command.c optional ddb -ddb/db_elf.c optional ddb -ddb/db_examine.c optional ddb -ddb/db_expr.c optional ddb -ddb/db_input.c optional ddb -ddb/db_kld.c optional ddb -ddb/db_lex.c optional ddb -ddb/db_output.c optional ddb -ddb/db_print.c optional ddb -ddb/db_ps.c optional ddb -ddb/db_run.c optional ddb -ddb/db_sym.c optional ddb -ddb/db_sysctl.c optional ddb -ddb/db_trap.c optional ddb -ddb/db_variables.c optional ddb -ddb/db_watch.c optional ddb -ddb/db_write_cmd.c optional ddb +ddb/db_access.c optional ddb +ddb/db_break.c optional ddb +ddb/db_command.c optional ddb +ddb/db_examine.c optional ddb +ddb/db_expr.c optional ddb +ddb/db_input.c optional ddb +ddb/db_lex.c optional ddb +ddb/db_main.c optional ddb +ddb/db_output.c optional ddb +ddb/db_print.c optional ddb +ddb/db_ps.c optional ddb +ddb/db_run.c optional ddb +ddb/db_sym.c optional ddb +ddb/db_thread.c optional ddb +ddb/db_variables.c optional ddb +ddb/db_watch.c optional ddb +ddb/db_write_cmd.c optional ddb dev/aac/aac.c optional aac dev/aac/aac_debug.c optional aac dev/aac/aac_disk.c optional aac diff --git a/sys/ddb/db_access.c b/sys/ddb/db_access.c index 15545deef6f25..d8224ada5a521 100644 --- a/sys/ddb/db_access.c +++ b/sys/ddb/db_access.c @@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> +#include <sys/kdb.h> #include <ddb/ddb.h> #include <ddb/db_access.h> @@ -58,7 +59,11 @@ db_get_value(addr, size, is_signed) register db_expr_t value; register int i; - db_read_bytes(addr, size, data); + if (db_read_bytes(addr, size, data) != 0) { + db_printf("*** error reading from address %llx ***\n", + (long long)addr); + kdb_reenter(); + } value = 0; #if BYTE_MSF @@ -96,6 +101,9 @@ db_put_value(addr, size, value) value >>= 8; } - db_write_bytes(addr, size, data); + if (db_write_bytes(addr, size, data) != 0) { + db_printf("*** error writing to address %llx ***\n", + (long long)addr); + kdb_reenter(); + } } - diff --git a/sys/ddb/db_break.c b/sys/ddb/db_break.c index 577e338c600a5..78f4f4f3039e9 100644 --- a/sys/ddb/db_break.c +++ b/sys/ddb/db_break.c @@ -367,46 +367,3 @@ db_map_addr(addr) #endif return kernel_map; } - -#ifdef ALT_BREAK_TO_DEBUGGER -/* - * Solaris implements a new BREAK which is initiated by a character sequence - * CR ~ ^b which is similar to a familiar pattern used on Sun servers by the - * Remote Console. - * - * Note that this function may be called from almost anywhere, with interrupts - * disabled and with unknown locks held, so it must not access data other than - * its arguments. Its up to the caller to ensure that the state variable is - * consistent. - */ - -#define KEY_CR 13 /* CR '\r' */ -#define KEY_TILDE 126 /* ~ */ -#define KEY_CRTLB 2 /* ^B */ - -int -db_alt_break(int data, int *state) -{ - int brk = 0; - - switch (data) { - case KEY_CR: - *state = KEY_TILDE; - break; - case KEY_TILDE: - if (*state == KEY_TILDE) - *state = KEY_CRTLB; - else - *state = 0; - break; - case KEY_CRTLB: - if (*state == KEY_CRTLB) - brk = 1; - /* FALLTHROUGH */ - default: - *state = 0; - break; - } - return (brk); -} -#endif diff --git a/sys/ddb/db_command.c b/sys/ddb/db_command.c index 70b35568dd754..954a0d3951b8f 100644 --- a/sys/ddb/db_command.c +++ b/sys/ddb/db_command.c @@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/linker_set.h> #include <sys/lock.h> +#include <sys/kdb.h> #include <sys/mutex.h> #include <sys/proc.h> #include <sys/reboot.h> @@ -58,7 +59,6 @@ __FBSDID("$FreeBSD$"); */ boolean_t db_cmd_loop_done; db_addr_t db_dot; -jmp_buf db_jmpbuf; db_addr_t db_last_addr; db_addr_t db_prev; db_addr_t db_next; @@ -67,7 +67,6 @@ SET_DECLARE(db_cmd_set, struct command); SET_DECLARE(db_show_cmd_set, struct command); static db_cmdfcn_t db_fncall; -static db_cmdfcn_t db_gdb; static db_cmdfcn_t db_kill; static db_cmdfcn_t db_reset; static db_cmdfcn_t db_watchdog; @@ -375,9 +374,6 @@ db_command(last_cmdp, cmd_table, aux_cmd_tablep, aux_cmd_tablep_end) */ static struct command db_show_all_cmds[] = { -#if 0 - { "threads", db_show_all_threads, 0, 0 }, -#endif { "procs", db_ps, 0, 0 }, { (char *)0 } }; @@ -386,10 +382,7 @@ static struct command db_show_cmds[] = { { "all", 0, 0, db_show_all_cmds }, { "registers", db_show_regs, 0, 0 }, { "breaks", db_listbreak_cmd, 0, 0 }, - { "thread", db_show_one_thread, 0, 0 }, -#if 0 - { "port", ipc_port_print, 0, 0 }, -#endif + { "threads", db_show_threads, 0, 0 }, { (char *)0, } }; @@ -421,29 +414,15 @@ static struct command db_command_table[] = { { "call", db_fncall, CS_OWN, 0 }, { "show", 0, 0, db_show_cmds }, { "ps", db_ps, 0, 0 }, - { "gdb", db_gdb, 0, 0 }, { "reset", db_reset, 0, 0 }, { "kill", db_kill, CS_OWN, 0 }, { "watchdog", db_watchdog, 0, 0 }, + { "thread", db_set_thread, CS_OWN, 0 }, { (char *)0, } }; static struct command *db_last_command = 0; -#if 0 -void -db_help_cmd() -{ - struct command *cmd = db_command_table; - - while (cmd->name != 0) { - db_printf("%-12s", cmd->name); - db_end_line(); - cmd++; - } -} -#endif - /* * At least one non-optional command must be implemented using * DB_COMMAND() so that db_cmd_set gets created. Here is one. @@ -464,8 +443,6 @@ db_command_loop() db_cmd_loop_done = 0; while (!db_cmd_loop_done) { - - (void) setjmp(db_jmpbuf); if (db_print_position() != 0) db_printf("\n"); @@ -484,7 +461,7 @@ db_error(s) if (s) db_printf("%s", s); db_flush_lex(); - longjmp(db_jmpbuf, 1); + kdb_reenter(); } @@ -553,32 +530,6 @@ db_fncall(dummy1, dummy2, dummy3, dummy4) db_printf("%#lr\n", (long)retval); } -/* Enter GDB remote protocol debugger on the next trap. */ - -void *gdb_arg = NULL; -cn_getc_t *gdb_getc; -cn_putc_t *gdb_putc; - -static void -db_gdb (dummy1, dummy2, dummy3, dummy4) - db_expr_t dummy1; - boolean_t dummy2; - db_expr_t dummy3; - char * dummy4; -{ - - if (gdb_arg == NULL) { - db_printf("No gdb port enabled. Set flag 0x80 on desired port\n"); - db_printf("in your configuration file (currently sio only).\n"); - return; - } - boothowto ^= RB_GDB; - - db_printf("Next trap will enter %s\n", - boothowto & RB_GDB ? "GDB remote protocol mode" - : "DDB debugger"); -} - static void db_kill(dummy1, dummy2, dummy3, dummy4) db_expr_t dummy1; diff --git a/sys/ddb/db_main.c b/sys/ddb/db_main.c new file mode 100644 index 0000000000000..32dd347afdca2 --- /dev/null +++ b/sys/ddb/db_main.c @@ -0,0 +1,226 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 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 + * 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 the + * rights to redistribute these changes. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/cons.h> +#include <sys/linker.h> +#include <sys/kdb.h> +#include <sys/kernel.h> +#include <sys/pcpu.h> +#include <sys/proc.h> +#include <sys/reboot.h> + +#include <machine/kdb.h> +#include <machine/pcb.h> +#include <machine/setjmp.h> + +#include <ddb/ddb.h> +#include <ddb/db_command.h> +#include <ddb/db_sym.h> + +static dbbe_init_f db_init; +static dbbe_trap_f db_trap; + +KDB_BACKEND(ddb, db_init, db_trace_self, db_trap); + +vm_offset_t ksym_start, ksym_end; + +boolean_t +X_db_line_at_pc(db_symtab_t *symtab, c_db_sym_t sym, char **file, int *line, + db_expr_t off) +{ + return (FALSE); +} + +c_db_sym_t +X_db_lookup(db_symtab_t *symtab, const char *symbol) +{ + c_linker_sym_t lsym; + Elf_Sym *sym; + + if (symtab->private == NULL) { + return ((c_db_sym_t)((!linker_ddb_lookup(symbol, &lsym)) + ? lsym : NULL)); + } else { + sym = (Elf_Sym *)symtab->start; + while ((char *)sym < symtab->end) { + if (sym->st_name != 0 && + !strcmp(symtab->private + sym->st_name, symbol)) + return ((c_db_sym_t)sym); + sym++; + } + } + return (NULL); +} + +c_db_sym_t +X_db_search_symbol(db_symtab_t *symtab, db_addr_t off, db_strategy_t strat, + db_expr_t *diffp) +{ + c_linker_sym_t lsym; + Elf_Sym *sym, *match; + unsigned long diff; + + if (symtab->private == NULL) { + if (!linker_ddb_search_symbol((caddr_t)off, &lsym, &diff)) { + *diffp = (db_expr_t)diff; + return ((c_db_sym_t)lsym); + } + return (NULL); + } + + diff = ~0UL; + match = NULL; + for (sym = (Elf_Sym*)symtab->start; (char*)sym < symtab->end; sym++) { + if (sym->st_name == 0) + continue; + if (off < sym->st_value) + continue; + if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT && + ELF_ST_TYPE(sym->st_info) != STT_FUNC && + ELF_ST_TYPE(sym->st_info) != STT_NOTYPE) + continue; + if ((off - sym->st_value) > diff) + continue; + if ((off - sym->st_value) < diff) { + diff = off - sym->st_value; + match = sym; + } else { + if (match == NULL) + match = sym; + else if (ELF_ST_BIND(match->st_info) == STB_LOCAL && + ELF_ST_BIND(sym->st_info) != STB_LOCAL) + match = sym; + } + if (diff == 0) { + if (strat == DB_STGY_PROC && + ELF_ST_TYPE(sym->st_info) == STT_FUNC && + ELF_ST_BIND(sym->st_info) != STB_LOCAL) + break; + if (strat == DB_STGY_ANY && + ELF_ST_BIND(sym->st_info) != STB_LOCAL) + break; + } + } + + *diffp = (match == NULL) ? off : diff; + return ((c_db_sym_t)match); +} + +boolean_t +X_db_sym_numargs(db_symtab_t *symtab, c_db_sym_t sym, int *nargp, + char **argp) +{ + return (FALSE); +} + +void +X_db_symbol_values(db_symtab_t *symtab, c_db_sym_t sym, const char **namep, + db_expr_t *valp) +{ + linker_symval_t lval; + + if (symtab->private == NULL) { + linker_ddb_symbol_values((c_linker_sym_t)sym, &lval); + if (namep != NULL) + *namep = (const char*)lval.name; + if (valp != NULL) + *valp = (db_expr_t)lval.value; + } else { + if (namep != NULL) + *namep = (const char *)symtab->private + + ((const Elf_Sym *)sym)->st_name; + if (valp != NULL) + *valp = (db_expr_t)((const Elf_Sym *)sym)->st_value; + } +} + +static int +db_init(void) +{ + uintptr_t symtab, strtab; + Elf_Size tabsz, strsz; + + if (ksym_end > ksym_start && ksym_start != 0) { + symtab = ksym_start; + tabsz = *((Elf_Size*)symtab)++; + strtab = symtab + tabsz; + strsz = *((Elf_Size*)strtab)++; + if (strtab + strsz <= ksym_end) { + db_add_symbol_table((char *)symtab, + (char *)(symtab + tabsz), "elf", (char *)strtab); + } + } + db_add_symbol_table(NULL, NULL, "kld", NULL); + return (1); /* We're the default debugger. */ +} + +static int +db_trap(int type, int code) +{ + jmp_buf jb; + void *prev_jb; + boolean_t bkpt, watchpt; + + /* + * Don't handle the trap if the console is unavailable (i.e. it + * is in graphics mode). + */ + if (cnunavailable()) + return (0); + + bkpt = IS_BREAKPOINT_TRAP(type, code); + watchpt = IS_WATCHPOINT_TRAP(type, code); + + if (db_stop_at_pc(&bkpt)) { + if (db_inst_count) { + db_printf("After %d instructions (%d loads, %d stores),\n", + db_inst_count, db_load_count, db_store_count); + } + prev_jb = kdb_jmpbuf(jb); + if (setjmp(jb) == 0) { + db_dot = PC_REGS(); + db_print_thread(); + if (bkpt) + db_printf("Breakpoint at\t"); + else if (watchpt) + db_printf("Watchpoint at\t"); + else + db_printf("Stopped at\t"); + db_print_loc_and_inst(db_dot); + } + db_command_loop(); + (void)kdb_jmpbuf(prev_jb); + } + + db_restart_at_pc(watchpt); + + return (1); +} diff --git a/sys/ddb/db_output.c b/sys/ddb/db_output.c index 464d9162cfe75..ff2734caad8c3 100644 --- a/sys/ddb/db_output.c +++ b/sys/ddb/db_output.c @@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> #include <sys/cons.h> +#include <sys/kdb.h> #include <sys/kernel.h> #include <sys/sysctl.h> @@ -112,9 +113,9 @@ db_putchar(c, arg) * If not in the debugger or the user requests it, output data to * both the console and the message buffer. */ - if (!db_active || ddb_use_printf) { + if (!kdb_active || ddb_use_printf) { printf("%c", c); - if (!db_active) + if (!kdb_active) return; if (c == '\r' || c == '\n') db_check_interrupt(); diff --git a/sys/ddb/db_print.c b/sys/ddb/db_print.c index 60282ad08278d..b173c8ca95e39 100644 --- a/sys/ddb/db_print.c +++ b/sys/ddb/db_print.c @@ -37,33 +37,33 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> +#include <sys/kdb.h> + +#include <machine/pcb.h> #include <ddb/ddb.h> #include <ddb/db_variables.h> #include <ddb/db_sym.h> void -db_show_regs(dummy1, dummy2, dummy3, dummy4) - db_expr_t dummy1; - boolean_t dummy2; - db_expr_t dummy3; - char * dummy4; +db_show_regs(db_expr_t _1, boolean_t _2, db_expr_t _3, char *_4) { - register struct db_variable *regp; - db_expr_t value, offset; - const char * name; + struct db_variable *regp; + db_expr_t value, offset; + const char *name; for (regp = db_regs; regp < db_eregs; regp++) { - db_read_variable(regp, &value); - db_printf("%-12s%#10lr", regp->name, (unsigned long)value); - db_find_xtrn_sym_and_offset((db_addr_t)value, &name, &offset); - if (name != NULL && offset <= (unsigned long)db_maxoff && - offset != value) { - db_printf("\t%s", name); - if (offset != 0) - db_printf("+%+#lr", (long)offset); - } - db_printf("\n"); + if (!db_read_variable(regp, &value)) + continue; + db_printf("%-12s%#10lr", regp->name, (unsigned long)value); + db_find_xtrn_sym_and_offset((db_addr_t)value, &name, &offset); + if (name != NULL && offset <= (unsigned long)db_maxoff && + offset != value) { + db_printf("\t%s", name); + if (offset != 0) + db_printf("+%+#lr", (long)offset); + } + db_printf("\n"); } - db_print_loc_and_inst(PC_REGS(DDB_REGS)); + db_print_loc_and_inst(PC_REGS()); } diff --git a/sys/ddb/db_ps.c b/sys/ddb/db_ps.c index f146cb380555f..47d4c7dc6e0b8 100644 --- a/sys/ddb/db_ps.c +++ b/sys/ddb/db_ps.c @@ -166,29 +166,3 @@ dumpthread(volatile struct proc *p, volatile struct thread *td) } else db_printf(" %s\n", p->p_comm); } - - -#define INKERNEL(va) (((vm_offset_t)(va)) >= USRSTACK) -void -db_show_one_thread(db_expr_t addr, boolean_t have_addr, - db_expr_t count, char *modif) -{ - struct proc *p; - struct thread *td; - - if (!have_addr) - td = curthread; - else if (!INKERNEL(addr)) { - printf("bad thread address"); - return; - } else - td = (struct thread *)addr; - /* quick sanity check */ - if ((p = td->td_proc) != td->td_ksegrp->kg_proc) - return; - printf("Proc %p ",p); - dumpthread(p, td); -#ifdef __i386__ - db_stack_thread((db_expr_t)td, 1, count, modif); -#endif -} diff --git a/sys/ddb/db_run.c b/sys/ddb/db_run.c index 79b148af4f62e..ab589d3870056 100644 --- a/sys/ddb/db_run.c +++ b/sys/ddb/db_run.c @@ -36,6 +36,10 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> +#include <sys/kdb.h> + +#include <machine/kdb.h> +#include <machine/pcb.h> #include <vm/vm.h> @@ -61,14 +65,10 @@ int db_load_count; int db_store_count; #ifndef db_set_single_step -extern void db_set_single_step(db_regs_t *regs); +void db_set_single_step(void); #endif #ifndef db_clear_single_step -extern void db_clear_single_step(db_regs_t *regs); -#endif - -#ifdef notused -static void db_single_step(db_regs_t *regs); +void db_clear_single_step(void); #endif boolean_t @@ -78,10 +78,10 @@ db_stop_at_pc(is_breakpoint) register db_addr_t pc; register db_breakpoint_t bkpt; - db_clear_single_step(DDB_REGS); + db_clear_single_step(); db_clear_breakpoints(); db_clear_watchpoints(); - pc = PC_REGS(DDB_REGS); + pc = PC_REGS(); #ifdef FIXUP_PC_AFTER_BREAK if (*is_breakpoint) { @@ -90,7 +90,7 @@ db_stop_at_pc(is_breakpoint) * machine requires it. */ FIXUP_PC_AFTER_BREAK - pc = PC_REGS(DDB_REGS); + pc = PC_REGS(); } #endif @@ -171,7 +171,7 @@ void db_restart_at_pc(watchpt) boolean_t watchpt; { - register db_addr_t pc = PC_REGS(DDB_REGS); + register db_addr_t pc = PC_REGS(); if ((db_run_mode == STEP_COUNT) || (db_run_mode == STEP_RETURN) || @@ -205,28 +205,16 @@ db_restart_at_pc(watchpt) * Step over breakpoint/watchpoint. */ db_run_mode = STEP_INVISIBLE; - db_set_single_step(DDB_REGS); + db_set_single_step(); } else { db_set_breakpoints(); db_set_watchpoints(); } } else { - db_set_single_step(DDB_REGS); + db_set_single_step(); } } -#ifdef notused -static void -db_single_step(regs) - db_regs_t *regs; -{ - if (db_run_mode == STEP_CONTINUE) { - db_run_mode = STEP_INVISIBLE; - db_set_single_step(regs); - } -} -#endif - #ifdef SOFTWARE_SSTEP /* * Software implementation of single-stepping. @@ -261,11 +249,10 @@ db_breakpoint_t db_not_taken_bkpt = 0; db_breakpoint_t db_taken_bkpt = 0; void -db_set_single_step(regs) - register db_regs_t *regs; +db_set_single_step(void) { - db_addr_t pc = PC_REGS(regs), brpc; - unsigned inst; + db_addr_t pc = PC_REGS(), brpc; + unsigned inst; /* * User was stopped at pc, e.g. the instruction @@ -273,28 +260,27 @@ db_set_single_step(regs) */ inst = db_get_value(pc, sizeof(int), FALSE); if (inst_branch(inst) || inst_call(inst)) { - brpc = branch_taken(inst, pc, regs); - if (brpc != pc) { /* self-branches are hopeless */ - db_taken_bkpt = db_set_temp_breakpoint(brpc); - } - pc = next_instr_address(pc,1); + brpc = branch_taken(inst, pc); + if (brpc != pc) { /* self-branches are hopeless */ + db_taken_bkpt = db_set_temp_breakpoint(brpc); + } + pc = next_instr_address(pc, 1); } - pc = next_instr_address(pc,0); + pc = next_instr_address(pc, 0); db_not_taken_bkpt = db_set_temp_breakpoint(pc); } void -db_clear_single_step(regs) - db_regs_t *regs; +db_clear_single_step(void) { if (db_not_taken_bkpt != 0) { - db_delete_temp_breakpoint(db_not_taken_bkpt); - db_not_taken_bkpt = 0; + db_delete_temp_breakpoint(db_not_taken_bkpt); + db_not_taken_bkpt = 0; } if (db_taken_bkpt != 0) { - db_delete_temp_breakpoint(db_taken_bkpt); - db_taken_bkpt = 0; + db_delete_temp_breakpoint(db_taken_bkpt); + db_taken_bkpt = 0; } } diff --git a/sys/ddb/db_thread.c b/sys/ddb/db_thread.c new file mode 100644 index 0000000000000..b58f0b09a7d30 --- /dev/null +++ b/sys/ddb/db_thread.c @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2004 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kdb.h> +#include <sys/proc.h> + +#include <machine/pcb.h> + +#include <ddb/ddb.h> +#include <ddb/db_command.h> +#include <ddb/db_sym.h> + +void +db_print_thread(void) +{ + db_printf("[thread %ld]\n", (long)kdb_thread->td_tid); +} + +void +db_set_thread(db_expr_t tid, boolean_t hastid, db_expr_t cnt, char *mod) +{ + struct thread *thr; + db_expr_t radix; + int err; + + /* + * We parse our own arguments. We don't like the default radix. + */ + radix = db_radix; + db_radix = 10; + hastid = db_expression(&tid); + db_radix = radix; + db_skip_to_eol(); + + if (hastid) { + thr = kdb_thr_lookup(tid); + if (thr != NULL) { + err = kdb_thr_select(thr); + if (err != 0) { + db_printf("unable to switch to thread %ld\n", + (long)thr->td_tid); + return; + } + db_dot = PC_REGS(); + } else { + db_printf("%d: invalid thread\n", (int)tid); + return; + } + } + + db_print_thread(); + db_print_loc_and_inst(PC_REGS()); +} + +void +db_show_threads(db_expr_t addr, boolean_t hasaddr, db_expr_t cnt, char *mod) +{ + jmp_buf jb; + void *prev_jb; + struct thread *thr; + int pager_quit; + + db_setup_paging(db_simple_pager, &pager_quit, DB_LINES_PER_PAGE); + + pager_quit = 0; + thr = kdb_thr_first(); + while (!pager_quit && thr != NULL) { + db_printf(" %6ld (%p) ", (long)thr->td_tid, thr); + prev_jb = kdb_jmpbuf(jb); + if (setjmp(jb) == 0) { + if (db_trace_thread(thr, 1) != 0) + db_printf("***\n"); + } + kdb_jmpbuf(prev_jb); + thr = kdb_thr_next(thr); + } +} diff --git a/sys/ddb/db_variables.c b/sys/ddb/db_variables.c index 1b283763e1770..cf8e2e73423c3 100644 --- a/sys/ddb/db_variables.c +++ b/sys/ddb/db_variables.c @@ -39,11 +39,6 @@ __FBSDID("$FreeBSD$"); #include <ddb/db_variables.h> static int db_find_variable(struct db_variable **varp); -static void db_write_variable(struct db_variable *, db_expr_t *); - -#ifdef notused -static int db_set_variable(db_expr_t value); -#endif static struct db_variable db_vars[] = { { "radix", &db_radix, FCN_NULL }, @@ -51,123 +46,107 @@ static struct db_variable db_vars[] = { { "maxwidth", &db_max_width, FCN_NULL }, { "tabstops", &db_tab_stop_width, FCN_NULL }, }; -static struct db_variable *db_evars = - db_vars + sizeof(db_vars)/sizeof(db_vars[0]); +static struct db_variable *db_evars = + db_vars + sizeof(db_vars)/sizeof(db_vars[0]); static int -db_find_variable(varp) - struct db_variable **varp; +db_find_variable(struct db_variable **varp) { - int t; struct db_variable *vp; + int t; t = db_read_token(); if (t == tIDENT) { - for (vp = db_vars; vp < db_evars; vp++) { - if (!strcmp(db_tok_string, vp->name)) { - *varp = vp; - return (1); + for (vp = db_vars; vp < db_evars; vp++) { + if (!strcmp(db_tok_string, vp->name)) { + *varp = vp; + return (1); + } } - } - for (vp = db_regs; vp < db_eregs; vp++) { - if (!strcmp(db_tok_string, vp->name)) { - *varp = vp; - return (1); + for (vp = db_regs; vp < db_eregs; vp++) { + if (!strcmp(db_tok_string, vp->name)) { + *varp = vp; + return (1); + } } - } } db_error("Unknown variable\n"); return (0); } int -db_get_variable(valuep) - db_expr_t *valuep; +db_get_variable(db_expr_t *valuep) { struct db_variable *vp; if (!db_find_variable(&vp)) - return (0); - - db_read_variable(vp, valuep); + return (0); - return (1); + return (db_read_variable(vp, valuep)); } -#ifdef notused -static int -db_set_variable(value) - db_expr_t value; +int +db_set_variable(db_expr_t value) { struct db_variable *vp; if (!db_find_variable(&vp)) - return (0); + return (0); - db_write_variable(vp, &value); - - return (1); + return (db_write_variable(vp, value)); } -#endif -void -db_read_variable(vp, valuep) - struct db_variable *vp; - db_expr_t *valuep; +int +db_read_variable(struct db_variable *vp, db_expr_t *valuep) { - db_varfcn_t *func = vp->fcn; + db_varfcn_t *func = vp->fcn; - if (func == FCN_NULL) - *valuep = *(vp->valuep); - else - (*func)(vp, valuep, DB_VAR_GET); + if (func == FCN_NULL) { + *valuep = *(vp->valuep); + return (1); + } + return ((*func)(vp, valuep, DB_VAR_GET)); } -static void -db_write_variable(vp, valuep) - struct db_variable *vp; - db_expr_t *valuep; +int +db_write_variable(struct db_variable *vp, db_expr_t value) { - db_varfcn_t *func = vp->fcn; + db_varfcn_t *func = vp->fcn; - if (func == FCN_NULL) - *(vp->valuep) = *valuep; - else - (*func)(vp, valuep, DB_VAR_SET); + if (func == FCN_NULL) { + *(vp->valuep) = value; + return (1); + } + return ((*func)(vp, &value, DB_VAR_SET)); } void -db_set_cmd(dummy1, dummy2, dummy3, dummy4) - db_expr_t dummy1; - boolean_t dummy2; - db_expr_t dummy3; - char * dummy4; +db_set_cmd(db_expr_t dummy1, boolean_t dummy2, db_expr_t dummy3, char *dummy4) { - db_expr_t value; struct db_variable *vp; - int t; + db_expr_t value; + int t; t = db_read_token(); if (t != tDOLLAR) { - db_error("Unknown variable\n"); - return; + db_error("Unknown variable\n"); + return; } if (!db_find_variable(&vp)) { - db_error("Unknown variable\n"); - return; + db_error("Unknown variable\n"); + return; } t = db_read_token(); if (t != tEQ) - db_unread_token(t); + db_unread_token(t); if (!db_expression(&value)) { - db_error("No value\n"); - return; - } - if (db_read_token() != tEOL) { - db_error("?\n"); + db_error("No value\n"); + return; } + if (db_read_token() != tEOL) + db_error("?\n"); - db_write_variable(vp, &value); + db_write_variable(vp, value); } diff --git a/sys/ddb/db_variables.h b/sys/ddb/db_variables.h index 6c05118efdd5a..7f7a463bdcfea 100644 --- a/sys/ddb/db_variables.h +++ b/sys/ddb/db_variables.h @@ -52,6 +52,7 @@ struct db_variable { extern struct db_variable db_regs[]; /* machine registers */ extern struct db_variable *db_eregs; -void db_read_variable(struct db_variable *, db_expr_t *); +int db_read_variable(struct db_variable *, db_expr_t *); +int db_write_variable(struct db_variable *, db_expr_t); #endif /* _!DDB_DB_VARIABLES_H_ */ diff --git a/sys/ddb/ddb.h b/sys/ddb/ddb.h index 1ef452cfd440d..c1ffff9c41d14 100644 --- a/sys/ddb/ddb.h +++ b/sys/ddb/ddb.h @@ -69,9 +69,7 @@ func_name(addr, have_addr, count, modif) \ db_expr_t count; \ char *modif; -extern char *esym; extern db_expr_t db_maxoff; -extern int db_active; extern int db_indent; extern int db_inst_count; extern int db_load_count; @@ -81,11 +79,9 @@ extern db_expr_t db_radix; extern db_expr_t db_max_width; extern db_expr_t db_tab_stop_width; +struct thread; struct vm_map; -#ifdef ALT_BREAK_TO_DEBUGGER -int db_alt_break(int, int *); -#endif void db_check_interrupt(void); void db_clear_watchpoints(void); db_addr_t db_disasm(db_addr_t loc, boolean_t altfmt); @@ -98,24 +94,23 @@ struct vm_map *db_map_addr(vm_offset_t); boolean_t db_map_current(struct vm_map *); boolean_t db_map_equal(struct vm_map *, struct vm_map *); void db_print_loc_and_inst(db_addr_t loc); +void db_print_thread(void); void db_printf(const char *fmt, ...) __printflike(1, 2); -void db_read_bytes(vm_offset_t addr, size_t size, char *data); +int db_read_bytes(vm_offset_t addr, size_t size, char *data); /* machine-dependent */ int db_readline(char *lstart, int lsize); void db_restart_at_pc(boolean_t watchpt); +int db_set_variable(db_expr_t value); void db_set_watchpoints(void); void db_setup_paging(db_page_calloutfcn_t *callout, void *arg, int maxlines); void db_skip_to_eol(void); boolean_t db_stop_at_pc(boolean_t *is_breakpoint); #define db_strcpy strcpy -void db_trap(int type, int code); +void db_trace_self(void); +int db_trace_thread(struct thread *, int); int db_value_of_name(const char *name, db_expr_t *valuep); -void db_write_bytes(vm_offset_t addr, size_t size, char *data); - /* machine-dependent */ -void db_stack_thread(db_expr_t addr, boolean_t have_addr, - db_expr_t count, char *modif); -void kdb_init(void); +int db_write_bytes(vm_offset_t addr, size_t size, char *data); db_cmdfcn_t db_breakpoint_cmd; db_cmdfcn_t db_continue_cmd; @@ -129,27 +124,18 @@ db_cmdfcn_t db_print_cmd; db_cmdfcn_t db_ps; db_cmdfcn_t db_search_cmd; db_cmdfcn_t db_set_cmd; +db_cmdfcn_t db_set_thread; db_cmdfcn_t db_show_regs; +db_cmdfcn_t db_show_threads; db_cmdfcn_t db_single_step_cmd; db_cmdfcn_t db_stack_trace_cmd; db_cmdfcn_t db_trace_until_call_cmd; db_cmdfcn_t db_trace_until_matching_cmd; db_cmdfcn_t db_watchpoint_cmd; db_cmdfcn_t db_write_cmd; -db_cmdfcn_t db_show_one_thread; - -#if 0 -db_cmdfcn_t db_help_cmd; -db_cmdfcn_t db_show_all_threads; -db_cmdfcn_t ipc_port_print; -db_cmdfcn_t vm_page_print; -#endif db_page_calloutfcn_t db_simple_pager; -/* Scare the user with backtrace of curthread to console. */ -void db_print_backtrace(void); - /* * Command table. */ @@ -164,14 +150,4 @@ struct command { struct command *more; /* another level of command */ }; -/* XXX: UGLY hack */ -#ifdef CN_DEAD -/* - * Routines to support GDB on an sio port. - */ -extern void *gdb_arg; -extern cn_getc_t *gdb_getc; -extern cn_putc_t *gdb_putc; -#endif - #endif /* !_DDB_DDB_H_ */ diff --git a/sys/i386/i386/db_interface.c b/sys/i386/i386/db_interface.c index a528502f2413d..02cf974f55841 100644 --- a/sys/i386/i386/db_interface.c +++ b/sys/i386/i386/db_interface.c @@ -32,290 +32,107 @@ __FBSDID("$FreeBSD$"); */ #include <sys/param.h> #include <sys/systm.h> -#include <sys/reboot.h> #include <sys/cons.h> +#include <sys/kdb.h> #include <sys/pcpu.h> #include <sys/proc.h> -#include <sys/smp.h> #include <machine/cpu.h> -#ifdef SMP -#include <machine/smptests.h> /** CPUSTOP_ON_DDBBREAK */ -#endif #include <vm/vm.h> #include <vm/pmap.h> #include <ddb/ddb.h> -#include <machine/setjmp.h> - -static jmp_buf *db_nofault = 0; -extern jmp_buf db_jmpbuf; - -extern void gdb_handle_exception(db_regs_t *, int, int); - -int db_active; -db_regs_t ddb_regs; - -static jmp_buf db_global_jmpbuf; - -/* - * kdb_trap - field a TRACE or BPT trap - */ -int -kdb_trap(int type, int code, struct i386_saved_state *regs) -{ - u_int ef; - volatile int ddb_mode = !(boothowto & RB_GDB); - - /* - * XXX try to do nothing if the console is in graphics mode. - * Handle trace traps (and hardware breakpoints...) by ignoring - * them except for forgetting about them. Return 0 for other - * traps to say that we haven't done anything. The trap handler - * will usually panic. We should handle breakpoint traps for - * our breakpoints by disarming our breakpoints and fixing up - * %eip. - */ - if (cnunavailable() != 0 && ddb_mode) { - if (type == T_TRCTRAP) { - regs->tf_eflags &= ~PSL_T; - return (1); - } - return (0); - } - - ef = read_eflags(); - disable_intr(); - -#ifdef SMP -#ifdef CPUSTOP_ON_DDBBREAK - -#if defined(VERBOSE_CPUSTOP_ON_DDBBREAK) - db_printf("\nCPU%d stopping CPUs: 0x%08x...", PCPU_GET(cpuid), - PCPU_GET(other_cpus)); -#endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */ - - /* We stop all CPUs except ourselves (obviously) */ - stop_cpus(PCPU_GET(other_cpus)); - -#if defined(VERBOSE_CPUSTOP_ON_DDBBREAK) - db_printf(" stopped.\n"); -#endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */ - -#endif /* CPUSTOP_ON_DDBBREAK */ -#endif /* SMP */ - - switch (type) { - case T_BPTFLT: /* breakpoint */ - case T_TRCTRAP: /* debug exception */ - break; - - default: - /* - * XXX this is almost useless now. In most cases, - * trap_fatal() has already printed a much more verbose - * message. However, it is dangerous to print things in - * trap_fatal() - printf() might be reentered and trap. - * The debugger should be given control first. - */ - if (ddb_mode) - db_printf("kernel: type %d trap, code=%x\n", type, code); - - if (db_nofault) { - jmp_buf *no_fault = db_nofault; - db_nofault = 0; - longjmp(*no_fault, 1); - } - } - - /* - * This handles unexpected traps in ddb commands, including calls to - * non-ddb functions. db_nofault only applies to memory accesses by - * internal ddb commands. - */ - if (db_active) - longjmp(db_global_jmpbuf, 1); - - /* - * XXX We really should switch to a local stack here. - */ - ddb_regs = *regs; - - /* - * If in kernel mode, esp and ss are not saved, so dummy them up. - */ - if (ISPL(regs->tf_cs) == 0) { - ddb_regs.tf_esp = (int)®s->tf_esp; - ddb_regs.tf_ss = rss(); - } - - (void) setjmp(db_global_jmpbuf); - if (ddb_mode) { - if (!db_active) - cndbctl(TRUE); - db_active = 1; - db_trap(type, code); - cndbctl(FALSE); - } else { - db_active = 1; - gdb_handle_exception(&ddb_regs, type, code); - } - db_active = 0; - - regs->tf_eip = ddb_regs.tf_eip; - regs->tf_eflags = ddb_regs.tf_eflags; - regs->tf_eax = ddb_regs.tf_eax; - regs->tf_ecx = ddb_regs.tf_ecx; - regs->tf_edx = ddb_regs.tf_edx; - regs->tf_ebx = ddb_regs.tf_ebx; - - /* - * If in user mode, the saved ESP and SS were valid, restore them. - */ - if (ISPL(regs->tf_cs)) { - regs->tf_esp = ddb_regs.tf_esp; - regs->tf_ss = ddb_regs.tf_ss & 0xffff; - } - - regs->tf_ebp = ddb_regs.tf_ebp; - regs->tf_esi = ddb_regs.tf_esi; - regs->tf_edi = ddb_regs.tf_edi; - regs->tf_es = ddb_regs.tf_es & 0xffff; - regs->tf_fs = ddb_regs.tf_fs & 0xffff; - regs->tf_cs = ddb_regs.tf_cs & 0xffff; - regs->tf_ds = ddb_regs.tf_ds & 0xffff; - -#ifdef SMP -#ifdef CPUSTOP_ON_DDBBREAK - -#if defined(VERBOSE_CPUSTOP_ON_DDBBREAK) - db_printf("\nCPU%d restarting CPUs: 0x%08x...", PCPU_GET(cpuid), - stopped_cpus); -#endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */ - - /* Restart all the CPUs we previously stopped */ - if (stopped_cpus != PCPU_GET(other_cpus) && smp_started != 0) { - db_printf("whoa, other_cpus: 0x%08x, stopped_cpus: 0x%08x\n", - PCPU_GET(other_cpus), stopped_cpus); - panic("stop_cpus() failed"); - } - restart_cpus(stopped_cpus); - -#if defined(VERBOSE_CPUSTOP_ON_DDBBREAK) - db_printf(" restarted.\n"); -#endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */ - -#endif /* CPUSTOP_ON_DDBBREAK */ -#endif /* SMP */ - - write_eflags(ef); - - return (1); -} - /* * Read bytes from kernel address space for debugger. */ -void +int db_read_bytes(vm_offset_t addr, size_t size, char *data) { - char *src; - - db_nofault = &db_jmpbuf; - - src = (char *)addr; - while (size-- > 0) - *data++ = *src++; - - db_nofault = 0; + jmp_buf jb; + void *prev_jb; + char *src; + int ret; + + prev_jb = kdb_jmpbuf(jb); + ret = setjmp(jb); + if (ret == 0) { + src = (char *)addr; + while (size-- > 0) + *data++ = *src++; + } + (void)kdb_jmpbuf(prev_jb); + return (ret); } /* * Write bytes to kernel address space for debugger. */ -void +int db_write_bytes(vm_offset_t addr, size_t size, char *data) { - char *dst; - - pt_entry_t *ptep0 = NULL; - pt_entry_t oldmap0 = 0; - vm_offset_t addr1; - pt_entry_t *ptep1 = NULL; - pt_entry_t oldmap1 = 0; - - db_nofault = &db_jmpbuf; - - if (addr > trunc_page((vm_offset_t)btext) - size && - addr < round_page((vm_offset_t)etext)) { - - ptep0 = pmap_pte(kernel_pmap, addr); - oldmap0 = *ptep0; - *ptep0 |= PG_RW; - - /* Map another page if the data crosses a page boundary. */ - if ((*ptep0 & PG_PS) == 0) { - addr1 = trunc_page(addr + size - 1); - if (trunc_page(addr) != addr1) { - ptep1 = pmap_pte(kernel_pmap, addr1); - oldmap1 = *ptep1; - *ptep1 |= PG_RW; - } - } else { - addr1 = trunc_4mpage(addr + size - 1); - if (trunc_4mpage(addr) != addr1) { - ptep1 = pmap_pte(kernel_pmap, addr1); - oldmap1 = *ptep1; - *ptep1 |= PG_RW; + jmp_buf jb; + void *prev_jb; + char *dst; + pt_entry_t *ptep0 = NULL; + pt_entry_t oldmap0 = 0; + vm_offset_t addr1; + pt_entry_t *ptep1 = NULL; + pt_entry_t oldmap1 = 0; + int ret; + + prev_jb = kdb_jmpbuf(jb); + ret = setjmp(jb); + if (ret == 0) { + if (addr > trunc_page((vm_offset_t)btext) - size && + addr < round_page((vm_offset_t)etext)) { + + ptep0 = pmap_pte(kernel_pmap, addr); + oldmap0 = *ptep0; + *ptep0 |= PG_RW; + + /* + * Map another page if the data crosses a page + * boundary. + */ + if ((*ptep0 & PG_PS) == 0) { + addr1 = trunc_page(addr + size - 1); + if (trunc_page(addr) != addr1) { + ptep1 = pmap_pte(kernel_pmap, addr1); + oldmap1 = *ptep1; + *ptep1 |= PG_RW; + } + } else { + addr1 = trunc_4mpage(addr + size - 1); + if (trunc_4mpage(addr) != addr1) { + ptep1 = pmap_pte(kernel_pmap, addr1); + oldmap1 = *ptep1; + *ptep1 |= PG_RW; + } + } + + invltlb(); } - } - - invltlb(); - } - dst = (char *)addr; + dst = (char *)addr; - while (size-- > 0) - *dst++ = *data++; + while (size-- > 0) + *dst++ = *data++; + } - db_nofault = 0; + (void)kdb_jmpbuf(prev_jb); if (ptep0) { - *ptep0 = oldmap0; + *ptep0 = oldmap0; - if (ptep1) - *ptep1 = oldmap1; + if (ptep1) + *ptep1 = oldmap1; - invltlb(); + invltlb(); } -} - -/* - * XXX - * Move this to machdep.c and allow it to be called if any debugger is - * installed. - */ -void -Debugger(const char *msg) -{ - static volatile u_int in_Debugger; - /* - * XXX - * Do nothing if the console is in graphics mode. This is - * OK if the call is for the debugger hotkey but not if the call - * is a weak form of panicing. - */ - if (cnunavailable() != 0 && !(boothowto & RB_GDB)) - return; - - if (atomic_cmpset_acq_int(&in_Debugger, 0, 1)) { - db_printf("Debugger(\"%s\")\n", msg); - breakpoint(); - atomic_store_rel_int(&in_Debugger, 0); - } + return (ret); } void diff --git a/sys/i386/i386/db_trace.c b/sys/i386/i386/db_trace.c index 84ed2d9a0404a..aaf11e0ce96bf 100644 --- a/sys/i386/i386/db_trace.c +++ b/sys/i386/i386/db_trace.c @@ -29,6 +29,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/kdb.h> #include <sys/proc.h> #include <sys/sysent.h> @@ -46,48 +47,123 @@ __FBSDID("$FreeBSD$"); #include <ddb/db_sym.h> #include <ddb/db_variables.h> -db_varfcn_t db_dr0; -db_varfcn_t db_dr1; -db_varfcn_t db_dr2; -db_varfcn_t db_dr3; -db_varfcn_t db_dr4; -db_varfcn_t db_dr5; -db_varfcn_t db_dr6; -db_varfcn_t db_dr7; +static db_varfcn_t db_dr0; +static db_varfcn_t db_dr1; +static db_varfcn_t db_dr2; +static db_varfcn_t db_dr3; +static db_varfcn_t db_dr4; +static db_varfcn_t db_dr5; +static db_varfcn_t db_dr6; +static db_varfcn_t db_dr7; +static db_varfcn_t db_esp; +static db_varfcn_t db_frame; +static db_varfcn_t db_ss; /* * Machine register set. */ +#define DB_OFFSET(x) (db_expr_t *)offsetof(struct trapframe, x) struct db_variable db_regs[] = { - { "cs", &ddb_regs.tf_cs, FCN_NULL }, - { "ds", &ddb_regs.tf_ds, FCN_NULL }, - { "es", &ddb_regs.tf_es, FCN_NULL }, - { "fs", &ddb_regs.tf_fs, FCN_NULL }, -#if 0 - { "gs", &ddb_regs.tf_gs, FCN_NULL }, -#endif - { "ss", &ddb_regs.tf_ss, FCN_NULL }, - { "eax", &ddb_regs.tf_eax, FCN_NULL }, - { "ecx", &ddb_regs.tf_ecx, FCN_NULL }, - { "edx", &ddb_regs.tf_edx, FCN_NULL }, - { "ebx", &ddb_regs.tf_ebx, FCN_NULL }, - { "esp", &ddb_regs.tf_esp, FCN_NULL }, - { "ebp", &ddb_regs.tf_ebp, FCN_NULL }, - { "esi", &ddb_regs.tf_esi, FCN_NULL }, - { "edi", &ddb_regs.tf_edi, FCN_NULL }, - { "eip", &ddb_regs.tf_eip, FCN_NULL }, - { "efl", &ddb_regs.tf_eflags, FCN_NULL }, - { "dr0", NULL, db_dr0 }, - { "dr1", NULL, db_dr1 }, - { "dr2", NULL, db_dr2 }, - { "dr3", NULL, db_dr3 }, - { "dr4", NULL, db_dr4 }, - { "dr5", NULL, db_dr5 }, - { "dr6", NULL, db_dr6 }, - { "dr7", NULL, db_dr7 }, + { "cs", DB_OFFSET(tf_cs), db_frame }, + { "ds", DB_OFFSET(tf_ds), db_frame }, + { "es", DB_OFFSET(tf_es), db_frame }, + { "fs", DB_OFFSET(tf_fs), db_frame }, + { "ss", NULL, db_ss }, + { "eax", DB_OFFSET(tf_eax), db_frame }, + { "ecx", DB_OFFSET(tf_ecx), db_frame }, + { "edx", DB_OFFSET(tf_edx), db_frame }, + { "ebx", DB_OFFSET(tf_ebx), db_frame }, + { "esp", NULL, db_esp }, + { "ebp", DB_OFFSET(tf_ebp), db_frame }, + { "esi", DB_OFFSET(tf_esi), db_frame }, + { "edi", DB_OFFSET(tf_edi), db_frame }, + { "eip", DB_OFFSET(tf_eip), db_frame }, + { "efl", DB_OFFSET(tf_eflags), db_frame }, + { "dr0", NULL, db_dr0 }, + { "dr1", NULL, db_dr1 }, + { "dr2", NULL, db_dr2 }, + { "dr3", NULL, db_dr3 }, + { "dr4", NULL, db_dr4 }, + { "dr5", NULL, db_dr5 }, + { "dr6", NULL, db_dr6 }, + { "dr7", NULL, db_dr7 }, }; struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]); +#define DB_DRX_FUNC(reg) \ +static int \ +db_ ## reg (vp, valuep, op) \ + struct db_variable *vp; \ + db_expr_t * valuep; \ + int op; \ +{ \ + if (op == DB_VAR_GET) \ + *valuep = r ## reg (); \ + else \ + load_ ## reg (*valuep); \ + return (1); \ +} + +DB_DRX_FUNC(dr0) +DB_DRX_FUNC(dr1) +DB_DRX_FUNC(dr2) +DB_DRX_FUNC(dr3) +DB_DRX_FUNC(dr4) +DB_DRX_FUNC(dr5) +DB_DRX_FUNC(dr6) +DB_DRX_FUNC(dr7) + +static __inline int +get_esp(struct trapframe *tf) +{ + return ((ISPL(tf->tf_cs)) ? tf->tf_esp : + (db_expr_t)tf + (uintptr_t)DB_OFFSET(tf_esp)); +} + +static int +db_frame(struct db_variable *vp, db_expr_t *valuep, int op) +{ + int *reg; + + if (kdb_frame == NULL) + return (0); + + reg = (int *)((uintptr_t)kdb_frame + (db_expr_t)vp->valuep); + if (op == DB_VAR_GET) + *valuep = *reg; + else + *reg = *valuep; + return (1); +} + +static int +db_esp(struct db_variable *vp, db_expr_t *valuep, int op) +{ + + if (kdb_frame == NULL) + return (0); + + if (op == DB_VAR_GET) + *valuep = get_esp(kdb_frame); + else if (ISPL(kdb_frame->tf_cs)) + kdb_frame->tf_esp = *valuep; + return (1); +} + +static int +db_ss(struct db_variable *vp, db_expr_t *valuep, int op) +{ + + if (kdb_frame == NULL) + return (0); + + if (op == DB_VAR_GET) + *valuep = (ISPL(kdb_frame->tf_cs)) ? kdb_frame->tf_ss : rss(); + else if (ISPL(kdb_frame->tf_cs)) + kdb_frame->tf_ss = *valuep; + return (1); +} + /* * Stack trace. */ @@ -104,13 +180,10 @@ struct i386_frame { #define INTERRUPT 2 #define SYSCALL 3 -static void db_nextframe(struct i386_frame **, db_addr_t *, struct proc *); +static void db_nextframe(struct i386_frame **, db_addr_t *, struct thread *); static int db_numargs(struct i386_frame *); static void db_print_stack_entry(const char *, int, char **, int *, db_addr_t); -static void decode_syscall(int, struct proc *); -static void db_trace_one_stack(int count, boolean_t have_addr, - struct proc *p, struct i386_frame *frame, db_addr_t callpc); - +static void decode_syscall(int, struct thread *); static char * watchtype_str(int type); int i386_set_watch(int watchnum, unsigned int watchaddr, int size, int access, @@ -120,7 +193,6 @@ int db_md_set_watchpoint(db_expr_t addr, db_expr_t size); int db_md_clr_watchpoint(db_expr_t addr, db_expr_t size); void db_md_list_watchpoints(void); - /* * Figure out how many arguments were passed into the frame at "fp". */ @@ -175,16 +247,16 @@ db_print_stack_entry(name, narg, argnp, argp, callpc) } static void -decode_syscall(number, p) - int number; - struct proc *p; +decode_syscall(int number, struct thread *td) { + struct proc *p; c_db_sym_t sym; db_expr_t diff; sy_call_t *f; const char *symname; db_printf(" (%d", number); + p = (td != NULL) ? td->td_proc : NULL; if (p != NULL && 0 <= number && number < p->p_sysent->sv_size) { f = p->p_sysent->sv_table[number].sy_call; sym = db_search_symbol((db_addr_t)f, DB_STGY_ANY, &diff); @@ -200,10 +272,7 @@ decode_syscall(number, p) * Figure out the next frame up in the call stack. */ static void -db_nextframe(fp, ip, p) - struct i386_frame **fp; /* in/out */ - db_addr_t *ip; /* out */ - struct proc *p; /* in */ +db_nextframe(struct i386_frame **fp, db_addr_t *ip, struct thread *td) { struct trapframe *tf; int frame_type; @@ -254,8 +323,7 @@ db_nextframe(fp, ip, p) tf = (struct trapframe *)((int)*fp + 8); if (INKERNEL((int) tf)) { - esp = (ISPL(tf->tf_cs) == SEL_UPL) ? - tf->tf_esp : (int)&tf->tf_esp; + esp = get_esp(tf); eip = tf->tf_eip; ebp = tf->tf_ebp; switch (frame_type) { @@ -264,7 +332,7 @@ db_nextframe(fp, ip, p) break; case SYSCALL: db_printf("--- syscall"); - decode_syscall(tf->tf_eax, p); + decode_syscall(tf->tf_eax, td); break; case INTERRUPT: db_printf("--- interrupt"); @@ -280,135 +348,26 @@ db_nextframe(fp, ip, p) *fp = (struct i386_frame *) ebp; } -void -db_stack_trace_cmd(addr, have_addr, count, modif) - db_expr_t addr; - boolean_t have_addr; - db_expr_t count; - char *modif; +static int +db_backtrace(struct thread *td, struct trapframe *tf, struct i386_frame *frame, + db_addr_t pc, int count) { - struct i386_frame *frame; - struct proc *p; - struct pcb *pcb; - struct thread *td; - db_addr_t callpc; - pid_t pid; + struct i386_frame *actframe; +#define MAXNARG 16 + char *argnames[MAXNARG], **argnp = NULL; + const char *name; + int *argp; + db_expr_t offset; + c_db_sym_t sym; + int narg; + boolean_t first; if (count == -1) count = 1024; - if (!have_addr) { - td = curthread; - p = td->td_proc; - frame = (struct i386_frame *)ddb_regs.tf_ebp; - if (frame == NULL) - frame = (struct i386_frame *)(ddb_regs.tf_esp - 4); - callpc = (db_addr_t)ddb_regs.tf_eip; - } else if (!INKERNEL(addr)) { - pid = (addr % 16) + ((addr >> 4) % 16) * 10 + - ((addr >> 8) % 16) * 100 + ((addr >> 12) % 16) * 1000 + - ((addr >> 16) % 16) * 10000; - /* - * The pcb for curproc is not valid at this point, - * so fall back to the default case. - */ - if (pid == curthread->td_proc->p_pid) { - td = curthread; - p = td->td_proc; - frame = (struct i386_frame *)ddb_regs.tf_ebp; - if (frame == NULL) - frame = (struct i386_frame *) - (ddb_regs.tf_esp - 4); - callpc = (db_addr_t)ddb_regs.tf_eip; - } else { - - /* sx_slock(&allproc_lock); */ - LIST_FOREACH(p, &allproc, p_list) { - if (p->p_pid == pid) - break; - } - /* sx_sunlock(&allproc_lock); */ - if (p == NULL) { - db_printf("pid %d not found\n", pid); - return; - } - if ((p->p_sflag & PS_INMEM) == 0) { - db_printf("pid %d swapped out\n", pid); - return; - } - pcb = FIRST_THREAD_IN_PROC(p)->td_pcb; /* XXXKSE */ - frame = (struct i386_frame *)pcb->pcb_ebp; - if (frame == NULL) - frame = (struct i386_frame *) - (pcb->pcb_esp - 4); - callpc = (db_addr_t)pcb->pcb_eip; - } - } else { - p = NULL; - frame = (struct i386_frame *)addr; - callpc = (db_addr_t)db_get_value((int)&frame->f_retaddr, 4, FALSE); - frame = frame->f_frame; - } - db_trace_one_stack(count, have_addr, p, frame, callpc); -} - -void -db_stack_thread(db_expr_t addr, boolean_t have_addr, - db_expr_t count, char *modif) -{ - struct i386_frame *frame; - struct thread *td; - struct proc *p; - struct pcb *pcb; - db_addr_t callpc; - - if (!have_addr) - return; - if (!INKERNEL(addr)) { - printf("bad thread address"); - return; - } - td = (struct thread *)addr; - /* quick sanity check */ - if ((p = td->td_proc) != td->td_ksegrp->kg_proc) - return; - if (TD_IS_SWAPPED(td)) { - db_printf("thread at %p swapped out\n", td); - return; - } - if (td == curthread) { - frame = (struct i386_frame *)ddb_regs.tf_ebp; - if (frame == NULL) - frame = (struct i386_frame *)(ddb_regs.tf_esp - 4); - callpc = (db_addr_t)ddb_regs.tf_eip; - } else { - pcb = td->td_pcb; - frame = (struct i386_frame *)pcb->pcb_ebp; - if (frame == NULL) - frame = (struct i386_frame *) (pcb->pcb_esp - 4); - callpc = (db_addr_t)pcb->pcb_eip; - } - db_trace_one_stack(count, have_addr, p, frame, callpc); -} - -static void -db_trace_one_stack(int count, boolean_t have_addr, - struct proc *p, struct i386_frame *frame, db_addr_t callpc) -{ - int *argp; - boolean_t first; - first = TRUE; while (count--) { - struct i386_frame *actframe; - int narg; - const char * name; - db_expr_t offset; - c_db_sym_t sym; -#define MAXNARG 16 - char *argnames[MAXNARG], **argnp = NULL; - - sym = db_search_symbol(callpc, DB_STGY_ANY, &offset); + sym = db_search_symbol(pc, DB_STGY_ANY, &offset); db_symbol_values(sym, &name, NULL); /* @@ -424,37 +383,33 @@ db_trace_one_stack(int count, boolean_t have_addr, */ actframe = frame; if (first) { - if (!have_addr) { + if (tf != NULL) { int instr; - instr = db_get_value(callpc, 4, FALSE); - if ((instr & 0x00ffffff) == 0x00e58955) { + instr = db_get_value(pc, 4, FALSE); + if ((instr & 0xffffff) == 0x00e58955) { /* pushl %ebp; movl %esp, %ebp */ - actframe = (struct i386_frame *) - (ddb_regs.tf_esp - 4); - } else if ((instr & 0x0000ffff) == 0x0000e589) { + actframe = (void *)(get_esp(tf) - 4); + } else if ((instr & 0xffff) == 0x0000e589) { /* movl %esp, %ebp */ - actframe = (struct i386_frame *) - ddb_regs.tf_esp; - if (ddb_regs.tf_ebp == 0) { - /* Fake caller's frame better. */ + actframe = (void *)get_esp(tf); + if (tf->tf_ebp == 0) { + /* Fake frame better. */ frame = actframe; } - } else if ((instr & 0x000000ff) == 0x000000c3) { + } else if ((instr & 0xff) == 0x000000c3) { /* ret */ - actframe = (struct i386_frame *) - (ddb_regs.tf_esp - 4); + actframe = (void *)(get_esp(tf) - 4); } else if (offset == 0) { - /* Probably a symbol in assembler code. */ - actframe = (struct i386_frame *) - (ddb_regs.tf_esp - 4); + /* Probably an assembler symbol. */ + actframe = (void *)(get_esp(tf) - 4); } } else if (strcmp(name, "fork_trampoline") == 0) { /* * Don't try to walk back on a stack for a * process that hasn't actually been run yet. */ - db_print_stack_entry(name, 0, 0, 0, callpc); + db_print_stack_entry(name, 0, 0, 0, pc); break; } first = FALSE; @@ -468,60 +423,68 @@ db_trace_one_stack(int count, boolean_t have_addr, narg = db_numargs(frame); } - db_print_stack_entry(name, narg, argnp, argp, callpc); + db_print_stack_entry(name, narg, argnp, argp, pc); if (actframe != frame) { /* `frame' belongs to caller. */ - callpc = (db_addr_t) + pc = (db_addr_t) db_get_value((int)&actframe->f_retaddr, 4, FALSE); continue; } - db_nextframe(&frame, &callpc, p); + db_nextframe(&frame, &pc, td); - if (INKERNEL((int) callpc) && !INKERNEL((int) frame)) { - sym = db_search_symbol(callpc, DB_STGY_ANY, &offset); + if (INKERNEL((int)pc) && !INKERNEL((int) frame)) { + sym = db_search_symbol(pc, DB_STGY_ANY, &offset); db_symbol_values(sym, &name, NULL); - db_print_stack_entry(name, 0, 0, 0, callpc); + db_print_stack_entry(name, 0, 0, 0, pc); break; } if (!INKERNEL((int) frame)) { break; } } + + return (0); +} + +void +db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, + char *modif) +{ + struct thread *td; + + td = (have_addr) ? kdb_thr_lookup(addr) : kdb_thread; + if (td == NULL) { + db_printf("Thread %d not found\n", addr); + return; + } + db_trace_thread(td, count); } void -db_print_backtrace(void) +db_trace_self(void) { + struct i386_frame *frame; + db_addr_t callpc; register_t ebp; __asm __volatile("movl %%ebp,%0" : "=r" (ebp)); - db_stack_trace_cmd(ebp, 1, -1, NULL); + frame = (struct i386_frame *)ebp; + callpc = (db_addr_t)db_get_value((int)&frame->f_retaddr, 4, FALSE); + frame = frame->f_frame; + db_backtrace(curthread, NULL, frame, callpc, -1); } -#define DB_DRX_FUNC(reg) \ -int \ -db_ ## reg (vp, valuep, op) \ - struct db_variable *vp; \ - db_expr_t * valuep; \ - int op; \ -{ \ - if (op == DB_VAR_GET) \ - *valuep = r ## reg (); \ - else \ - load_ ## reg (*valuep); \ - return (0); \ -} +int +db_trace_thread(struct thread *thr, int count) +{ + struct pcb *ctx; -DB_DRX_FUNC(dr0) -DB_DRX_FUNC(dr1) -DB_DRX_FUNC(dr2) -DB_DRX_FUNC(dr3) -DB_DRX_FUNC(dr4) -DB_DRX_FUNC(dr5) -DB_DRX_FUNC(dr6) -DB_DRX_FUNC(dr7) + ctx = kdb_thr_ctx(thr); + return (db_backtrace(thr, NULL, (struct i386_frame *)ctx->pcb_ebp, + ctx->pcb_eip, count)); +} int i386_set_watch(watchnum, watchaddr, size, access, d) diff --git a/sys/i386/include/db_machdep.h b/sys/i386/include/db_machdep.h index ba84fc6834e8e..6922908bc81ef 100644 --- a/sys/i386/include/db_machdep.h +++ b/sys/i386/include/db_machdep.h @@ -30,30 +30,23 @@ #define _MACHINE_DB_MACHDEP_H_ #include <machine/frame.h> -#include <machine/psl.h> #include <machine/trap.h> -#define i386_saved_state trapframe - typedef vm_offset_t db_addr_t; /* address - unsigned */ typedef int db_expr_t; /* expression - signed */ -typedef struct i386_saved_state db_regs_t; -extern db_regs_t ddb_regs; /* register state */ -#define DDB_REGS (&ddb_regs) - -#define PC_REGS(regs) ((db_addr_t)(regs)->tf_eip) +#define PC_REGS() ((db_addr_t)kdb_thrctx->pcb_eip) #define BKPT_INST 0xcc /* breakpoint instruction */ #define BKPT_SIZE (1) /* size of breakpoint inst */ #define BKPT_SET(inst) (BKPT_INST) -#define BKPT_SKIP ddb_regs.tf_eip += 1 +#define BKPT_SKIP kdb_frame->tf_eip += 1 -#define FIXUP_PC_AFTER_BREAK ddb_regs.tf_eip -= 1; +#define FIXUP_PC_AFTER_BREAK kdb_frame->tf_eip -= 1; -#define db_clear_single_step(regs) ((regs)->tf_eflags &= ~PSL_T) -#define db_set_single_step(regs) ((regs)->tf_eflags |= PSL_T) +#define db_clear_single_step kdb_cpu_clear_singlestep +#define db_set_single_step kdb_cpu_set_singlestep #define IS_BREAKPOINT_TRAP(type, code) ((type) == T_BPTFLT) /* diff --git a/sys/ia64/ia64/db_interface.c b/sys/ia64/ia64/db_interface.c index 525966fbc29d3..7d1bdc79dcadd 100644 --- a/sys/ia64/ia64/db_interface.c +++ b/sys/ia64/ia64/db_interface.c @@ -1,5 +1,3 @@ -/* $FreeBSD$ */ - /* * Mach Operating System * Copyright (c) 1992,1991,1990 Carnegie Mellon University @@ -28,29 +26,26 @@ * db_interface.c,v 2.4 1991/02/05 17:11:13 mrt (CMU) */ -/* - * Parts of this file are derived from Mach 3: - * - * File: alpha_instruction.c - * Author: Alessandro Forin, Carnegie Mellon University - * Date: 6/92 - */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); /* * Interface to DDB. */ #include <sys/param.h> -#include <sys/proc.h> -#include <sys/reboot.h> #include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/smp.h> #include <sys/cons.h> +#include <sys/kdb.h> #include <sys/ktr.h> +#include <sys/kernel.h> +#include <sys/proc.h> +#include <sys/reboot.h> +#include <sys/smp.h> #include <vm/vm.h> #include <machine/db_machdep.h> +#include <machine/frame.h> #include <machine/mutex.h> #include <machine/setjmp.h> @@ -61,433 +56,319 @@ #include <ia64/disasm/disasm.h> -static jmp_buf *db_nofault = 0; -extern jmp_buf db_jmpbuf; +#define TMPL_BITS 5 +#define TMPL_MASK ((1 << TMPL_BITS) - 1) +#define SLOT_BITS 41 +#define SLOT_COUNT 3 +#define SLOT_MASK ((1ULL << SLOT_BITS) - 1ULL) +#define SLOT_SHIFT(i) (TMPL_BITS+((i)<<3)+(i)) -extern void gdb_handle_exception(db_regs_t *, int); - -int db_active; -db_regs_t ddb_regs; - -static int db_get_rse_reg(struct db_variable *vp, db_expr_t *valuep, int op); -static int db_get_ip_reg(struct db_variable *vp, db_expr_t *valuep, int op); +static db_varfcn_t db_frame; +static db_varfcn_t db_getrse; +static db_varfcn_t db_getip; +#define DB_OFFSET(x) (db_expr_t *)offsetof(struct trapframe, x) struct db_variable db_regs[] = { - /* Misc control/app registers */ -#define DB_MISC_REGS 13 /* make sure this is correct */ - - {"ip", NULL, db_get_ip_reg}, - {"psr", (db_expr_t*) &ddb_regs.tf_special.psr, FCN_NULL}, - {"cr.isr", (db_expr_t*) &ddb_regs.tf_special.isr, FCN_NULL}, - {"cr.ifa", (db_expr_t*) &ddb_regs.tf_special.ifa, FCN_NULL}, - {"pr", (db_expr_t*) &ddb_regs.tf_special.pr, FCN_NULL}, - {"ar.rsc", (db_expr_t*) &ddb_regs.tf_special.rsc, FCN_NULL}, - {"ar.pfs", (db_expr_t*) &ddb_regs.tf_special.pfs, FCN_NULL}, - {"cr.ifs", (db_expr_t*) &ddb_regs.tf_special.cfm, FCN_NULL}, - {"ar.bspstore", (db_expr_t*) &ddb_regs.tf_special.bspstore, FCN_NULL}, - {"ndirty", (db_expr_t*) &ddb_regs.tf_special.ndirty, FCN_NULL}, - {"ar.rnat", (db_expr_t*) &ddb_regs.tf_special.rnat, FCN_NULL}, - {"ar.unat", (db_expr_t*) &ddb_regs.tf_special.unat, FCN_NULL}, - {"ar.fpsr", (db_expr_t*) &ddb_regs.tf_special.fpsr, FCN_NULL}, - - /* Branch registers */ - {"rp", (db_expr_t*) &ddb_regs.tf_special.rp, FCN_NULL}, - /* b1, b2, b3, b4, b5 are preserved */ - {"b6", (db_expr_t*) &ddb_regs.tf_scratch.br6, FCN_NULL}, - {"b7", (db_expr_t*) &ddb_regs.tf_scratch.br7, FCN_NULL}, - - /* Static registers */ - {"gp", (db_expr_t*) &ddb_regs.tf_special.gp, FCN_NULL}, - {"r2", (db_expr_t*) &ddb_regs.tf_scratch.gr2, FCN_NULL}, - {"r3", (db_expr_t*) &ddb_regs.tf_scratch.gr3, FCN_NULL}, - {"r8", (db_expr_t*) &ddb_regs.tf_scratch.gr8, FCN_NULL}, - {"r9", (db_expr_t*) &ddb_regs.tf_scratch.gr9, FCN_NULL}, - {"r10", (db_expr_t*) &ddb_regs.tf_scratch.gr10, FCN_NULL}, - {"r11", (db_expr_t*) &ddb_regs.tf_scratch.gr11, FCN_NULL}, - {"sp", (db_expr_t*) &ddb_regs.tf_special.sp, FCN_NULL}, - {"tp", (db_expr_t*) &ddb_regs.tf_special.tp, FCN_NULL}, - {"r14", (db_expr_t*) &ddb_regs.tf_scratch.gr14, FCN_NULL}, - {"r15", (db_expr_t*) &ddb_regs.tf_scratch.gr15, FCN_NULL}, - {"r16", (db_expr_t*) &ddb_regs.tf_scratch.gr16, FCN_NULL}, - {"r17", (db_expr_t*) &ddb_regs.tf_scratch.gr17, FCN_NULL}, - {"r18", (db_expr_t*) &ddb_regs.tf_scratch.gr18, FCN_NULL}, - {"r19", (db_expr_t*) &ddb_regs.tf_scratch.gr19, FCN_NULL}, - {"r20", (db_expr_t*) &ddb_regs.tf_scratch.gr20, FCN_NULL}, - {"r21", (db_expr_t*) &ddb_regs.tf_scratch.gr21, FCN_NULL}, - {"r22", (db_expr_t*) &ddb_regs.tf_scratch.gr22, FCN_NULL}, - {"r23", (db_expr_t*) &ddb_regs.tf_scratch.gr23, FCN_NULL}, - {"r24", (db_expr_t*) &ddb_regs.tf_scratch.gr24, FCN_NULL}, - {"r25", (db_expr_t*) &ddb_regs.tf_scratch.gr25, FCN_NULL}, - {"r26", (db_expr_t*) &ddb_regs.tf_scratch.gr26, FCN_NULL}, - {"r27", (db_expr_t*) &ddb_regs.tf_scratch.gr27, FCN_NULL}, - {"r28", (db_expr_t*) &ddb_regs.tf_scratch.gr28, FCN_NULL}, - {"r29", (db_expr_t*) &ddb_regs.tf_scratch.gr29, FCN_NULL}, - {"r30", (db_expr_t*) &ddb_regs.tf_scratch.gr30, FCN_NULL}, - {"r31", (db_expr_t*) &ddb_regs.tf_scratch.gr31, FCN_NULL}, - - /* Stacked registers */ - {"r32", (db_expr_t*) 32, db_get_rse_reg}, - {"r33", (db_expr_t*) 33, db_get_rse_reg}, - {"r34", (db_expr_t*) 34, db_get_rse_reg}, - {"r35", (db_expr_t*) 35, db_get_rse_reg}, - {"r36", (db_expr_t*) 36, db_get_rse_reg}, - {"r37", (db_expr_t*) 37, db_get_rse_reg}, - {"r38", (db_expr_t*) 38, db_get_rse_reg}, - {"r39", (db_expr_t*) 39, db_get_rse_reg}, - {"r40", (db_expr_t*) 40, db_get_rse_reg}, - {"r41", (db_expr_t*) 41, db_get_rse_reg}, - {"r42", (db_expr_t*) 42, db_get_rse_reg}, - {"r43", (db_expr_t*) 43, db_get_rse_reg}, - {"r44", (db_expr_t*) 44, db_get_rse_reg}, - {"r45", (db_expr_t*) 45, db_get_rse_reg}, - {"r46", (db_expr_t*) 46, db_get_rse_reg}, - {"r47", (db_expr_t*) 47, db_get_rse_reg}, - {"r48", (db_expr_t*) 48, db_get_rse_reg}, - {"r49", (db_expr_t*) 49, db_get_rse_reg}, - {"r50", (db_expr_t*) 50, db_get_rse_reg}, - {"r51", (db_expr_t*) 51, db_get_rse_reg}, - {"r52", (db_expr_t*) 52, db_get_rse_reg}, - {"r53", (db_expr_t*) 53, db_get_rse_reg}, - {"r54", (db_expr_t*) 54, db_get_rse_reg}, - {"r55", (db_expr_t*) 55, db_get_rse_reg}, - {"r56", (db_expr_t*) 56, db_get_rse_reg}, - {"r57", (db_expr_t*) 57, db_get_rse_reg}, - {"r58", (db_expr_t*) 58, db_get_rse_reg}, - {"r59", (db_expr_t*) 59, db_get_rse_reg}, - {"r60", (db_expr_t*) 60, db_get_rse_reg}, - {"r61", (db_expr_t*) 61, db_get_rse_reg}, - {"r62", (db_expr_t*) 62, db_get_rse_reg}, - {"r63", (db_expr_t*) 63, db_get_rse_reg}, - {"r64", (db_expr_t*) 64, db_get_rse_reg}, - {"r65", (db_expr_t*) 65, db_get_rse_reg}, - {"r66", (db_expr_t*) 66, db_get_rse_reg}, - {"r67", (db_expr_t*) 67, db_get_rse_reg}, - {"r68", (db_expr_t*) 68, db_get_rse_reg}, - {"r69", (db_expr_t*) 69, db_get_rse_reg}, - {"r70", (db_expr_t*) 70, db_get_rse_reg}, - {"r71", (db_expr_t*) 71, db_get_rse_reg}, - {"r72", (db_expr_t*) 72, db_get_rse_reg}, - {"r73", (db_expr_t*) 73, db_get_rse_reg}, - {"r74", (db_expr_t*) 74, db_get_rse_reg}, - {"r75", (db_expr_t*) 75, db_get_rse_reg}, - {"r76", (db_expr_t*) 76, db_get_rse_reg}, - {"r77", (db_expr_t*) 77, db_get_rse_reg}, - {"r78", (db_expr_t*) 78, db_get_rse_reg}, - {"r79", (db_expr_t*) 79, db_get_rse_reg}, - {"r80", (db_expr_t*) 80, db_get_rse_reg}, - {"r81", (db_expr_t*) 81, db_get_rse_reg}, - {"r82", (db_expr_t*) 82, db_get_rse_reg}, - {"r83", (db_expr_t*) 83, db_get_rse_reg}, - {"r84", (db_expr_t*) 84, db_get_rse_reg}, - {"r85", (db_expr_t*) 85, db_get_rse_reg}, - {"r86", (db_expr_t*) 86, db_get_rse_reg}, - {"r87", (db_expr_t*) 87, db_get_rse_reg}, - {"r88", (db_expr_t*) 88, db_get_rse_reg}, - {"r89", (db_expr_t*) 89, db_get_rse_reg}, - {"r90", (db_expr_t*) 90, db_get_rse_reg}, - {"r91", (db_expr_t*) 91, db_get_rse_reg}, - {"r92", (db_expr_t*) 92, db_get_rse_reg}, - {"r93", (db_expr_t*) 93, db_get_rse_reg}, - {"r94", (db_expr_t*) 94, db_get_rse_reg}, - {"r95", (db_expr_t*) 95, db_get_rse_reg}, - {"r96", (db_expr_t*) 96, db_get_rse_reg}, - {"r97", (db_expr_t*) 97, db_get_rse_reg}, - {"r98", (db_expr_t*) 98, db_get_rse_reg}, - {"r99", (db_expr_t*) 99, db_get_rse_reg}, - {"r100", (db_expr_t*) 100, db_get_rse_reg}, - {"r101", (db_expr_t*) 101, db_get_rse_reg}, - {"r102", (db_expr_t*) 102, db_get_rse_reg}, - {"r103", (db_expr_t*) 103, db_get_rse_reg}, - {"r104", (db_expr_t*) 104, db_get_rse_reg}, - {"r105", (db_expr_t*) 105, db_get_rse_reg}, - {"r106", (db_expr_t*) 106, db_get_rse_reg}, - {"r107", (db_expr_t*) 107, db_get_rse_reg}, - {"r108", (db_expr_t*) 108, db_get_rse_reg}, - {"r109", (db_expr_t*) 109, db_get_rse_reg}, - {"r110", (db_expr_t*) 110, db_get_rse_reg}, - {"r111", (db_expr_t*) 111, db_get_rse_reg}, - {"r112", (db_expr_t*) 112, db_get_rse_reg}, - {"r113", (db_expr_t*) 113, db_get_rse_reg}, - {"r114", (db_expr_t*) 114, db_get_rse_reg}, - {"r115", (db_expr_t*) 115, db_get_rse_reg}, - {"r116", (db_expr_t*) 116, db_get_rse_reg}, - {"r117", (db_expr_t*) 117, db_get_rse_reg}, - {"r118", (db_expr_t*) 118, db_get_rse_reg}, - {"r119", (db_expr_t*) 119, db_get_rse_reg}, - {"r120", (db_expr_t*) 120, db_get_rse_reg}, - {"r121", (db_expr_t*) 121, db_get_rse_reg}, - {"r122", (db_expr_t*) 122, db_get_rse_reg}, - {"r123", (db_expr_t*) 123, db_get_rse_reg}, - {"r124", (db_expr_t*) 124, db_get_rse_reg}, - {"r125", (db_expr_t*) 125, db_get_rse_reg}, - {"r126", (db_expr_t*) 126, db_get_rse_reg}, - {"r127", (db_expr_t*) 127, db_get_rse_reg}, + {"ip", NULL, db_getip}, + {"cr.ifs", DB_OFFSET(tf_special.cfm), db_frame}, + {"cr.ifa", DB_OFFSET(tf_special.ifa), db_frame}, + {"ar.bspstore", DB_OFFSET(tf_special.bspstore), db_frame}, + {"ndirty", DB_OFFSET(tf_special.ndirty), db_frame}, + {"rp", DB_OFFSET(tf_special.rp), db_frame}, + {"ar.pfs", DB_OFFSET(tf_special.pfs), db_frame}, + {"psr", DB_OFFSET(tf_special.psr), db_frame}, + {"cr.isr", DB_OFFSET(tf_special.isr), db_frame}, + {"pr", DB_OFFSET(tf_special.pr), db_frame}, + {"ar.rsc", DB_OFFSET(tf_special.rsc), db_frame}, + {"ar.rnat", DB_OFFSET(tf_special.rnat), db_frame}, + {"ar.unat", DB_OFFSET(tf_special.unat), db_frame}, + {"ar.fpsr", DB_OFFSET(tf_special.fpsr), db_frame}, + {"gp", DB_OFFSET(tf_special.gp), db_frame}, + {"sp", DB_OFFSET(tf_special.sp), db_frame}, + {"tp", DB_OFFSET(tf_special.tp), db_frame}, + {"b6", DB_OFFSET(tf_scratch.br6), db_frame}, + {"b7", DB_OFFSET(tf_scratch.br7), db_frame}, + {"r2", DB_OFFSET(tf_scratch.gr2), db_frame}, + {"r3", DB_OFFSET(tf_scratch.gr3), db_frame}, + {"r8", DB_OFFSET(tf_scratch.gr8), db_frame}, + {"r9", DB_OFFSET(tf_scratch.gr9), db_frame}, + {"r10", DB_OFFSET(tf_scratch.gr10), db_frame}, + {"r11", DB_OFFSET(tf_scratch.gr11), db_frame}, + {"r14", DB_OFFSET(tf_scratch.gr14), db_frame}, + {"r15", DB_OFFSET(tf_scratch.gr15), db_frame}, + {"r16", DB_OFFSET(tf_scratch.gr16), db_frame}, + {"r17", DB_OFFSET(tf_scratch.gr17), db_frame}, + {"r18", DB_OFFSET(tf_scratch.gr18), db_frame}, + {"r19", DB_OFFSET(tf_scratch.gr19), db_frame}, + {"r20", DB_OFFSET(tf_scratch.gr20), db_frame}, + {"r21", DB_OFFSET(tf_scratch.gr21), db_frame}, + {"r22", DB_OFFSET(tf_scratch.gr22), db_frame}, + {"r23", DB_OFFSET(tf_scratch.gr23), db_frame}, + {"r24", DB_OFFSET(tf_scratch.gr24), db_frame}, + {"r25", DB_OFFSET(tf_scratch.gr25), db_frame}, + {"r26", DB_OFFSET(tf_scratch.gr26), db_frame}, + {"r27", DB_OFFSET(tf_scratch.gr27), db_frame}, + {"r28", DB_OFFSET(tf_scratch.gr28), db_frame}, + {"r29", DB_OFFSET(tf_scratch.gr29), db_frame}, + {"r30", DB_OFFSET(tf_scratch.gr30), db_frame}, + {"r31", DB_OFFSET(tf_scratch.gr31), db_frame}, + {"r32", (db_expr_t*)0, db_getrse}, + {"r33", (db_expr_t*)1, db_getrse}, + {"r34", (db_expr_t*)2, db_getrse}, + {"r35", (db_expr_t*)3, db_getrse}, + {"r36", (db_expr_t*)4, db_getrse}, + {"r37", (db_expr_t*)5, db_getrse}, + {"r38", (db_expr_t*)6, db_getrse}, + {"r39", (db_expr_t*)7, db_getrse}, + {"r40", (db_expr_t*)8, db_getrse}, + {"r41", (db_expr_t*)9, db_getrse}, + {"r42", (db_expr_t*)10, db_getrse}, + {"r43", (db_expr_t*)11, db_getrse}, + {"r44", (db_expr_t*)12, db_getrse}, + {"r45", (db_expr_t*)13, db_getrse}, + {"r46", (db_expr_t*)14, db_getrse}, + {"r47", (db_expr_t*)15, db_getrse}, + {"r48", (db_expr_t*)16, db_getrse}, + {"r49", (db_expr_t*)17, db_getrse}, + {"r50", (db_expr_t*)18, db_getrse}, + {"r51", (db_expr_t*)19, db_getrse}, + {"r52", (db_expr_t*)20, db_getrse}, + {"r53", (db_expr_t*)21, db_getrse}, + {"r54", (db_expr_t*)22, db_getrse}, + {"r55", (db_expr_t*)23, db_getrse}, + {"r56", (db_expr_t*)24, db_getrse}, + {"r57", (db_expr_t*)25, db_getrse}, + {"r58", (db_expr_t*)26, db_getrse}, + {"r59", (db_expr_t*)27, db_getrse}, + {"r60", (db_expr_t*)28, db_getrse}, + {"r61", (db_expr_t*)29, db_getrse}, + {"r62", (db_expr_t*)30, db_getrse}, + {"r63", (db_expr_t*)31, db_getrse}, + {"r64", (db_expr_t*)32, db_getrse}, + {"r65", (db_expr_t*)33, db_getrse}, + {"r66", (db_expr_t*)34, db_getrse}, + {"r67", (db_expr_t*)35, db_getrse}, + {"r68", (db_expr_t*)36, db_getrse}, + {"r69", (db_expr_t*)37, db_getrse}, + {"r70", (db_expr_t*)38, db_getrse}, + {"r71", (db_expr_t*)39, db_getrse}, + {"r72", (db_expr_t*)40, db_getrse}, + {"r73", (db_expr_t*)41, db_getrse}, + {"r74", (db_expr_t*)42, db_getrse}, + {"r75", (db_expr_t*)43, db_getrse}, + {"r76", (db_expr_t*)44, db_getrse}, + {"r77", (db_expr_t*)45, db_getrse}, + {"r78", (db_expr_t*)46, db_getrse}, + {"r79", (db_expr_t*)47, db_getrse}, + {"r80", (db_expr_t*)48, db_getrse}, + {"r81", (db_expr_t*)49, db_getrse}, + {"r82", (db_expr_t*)50, db_getrse}, + {"r83", (db_expr_t*)51, db_getrse}, + {"r84", (db_expr_t*)52, db_getrse}, + {"r85", (db_expr_t*)53, db_getrse}, + {"r86", (db_expr_t*)54, db_getrse}, + {"r87", (db_expr_t*)55, db_getrse}, + {"r88", (db_expr_t*)56, db_getrse}, + {"r89", (db_expr_t*)57, db_getrse}, + {"r90", (db_expr_t*)58, db_getrse}, + {"r91", (db_expr_t*)59, db_getrse}, + {"r92", (db_expr_t*)60, db_getrse}, + {"r93", (db_expr_t*)61, db_getrse}, + {"r94", (db_expr_t*)62, db_getrse}, + {"r95", (db_expr_t*)63, db_getrse}, + {"r96", (db_expr_t*)64, db_getrse}, + {"r97", (db_expr_t*)65, db_getrse}, + {"r98", (db_expr_t*)66, db_getrse}, + {"r99", (db_expr_t*)67, db_getrse}, + {"r100", (db_expr_t*)68, db_getrse}, + {"r101", (db_expr_t*)69, db_getrse}, + {"r102", (db_expr_t*)70, db_getrse}, + {"r103", (db_expr_t*)71, db_getrse}, + {"r104", (db_expr_t*)72, db_getrse}, + {"r105", (db_expr_t*)73, db_getrse}, + {"r106", (db_expr_t*)74, db_getrse}, + {"r107", (db_expr_t*)75, db_getrse}, + {"r108", (db_expr_t*)76, db_getrse}, + {"r109", (db_expr_t*)77, db_getrse}, + {"r110", (db_expr_t*)78, db_getrse}, + {"r111", (db_expr_t*)79, db_getrse}, + {"r112", (db_expr_t*)80, db_getrse}, + {"r113", (db_expr_t*)81, db_getrse}, + {"r114", (db_expr_t*)82, db_getrse}, + {"r115", (db_expr_t*)83, db_getrse}, + {"r116", (db_expr_t*)84, db_getrse}, + {"r117", (db_expr_t*)85, db_getrse}, + {"r118", (db_expr_t*)86, db_getrse}, + {"r119", (db_expr_t*)87, db_getrse}, + {"r120", (db_expr_t*)88, db_getrse}, + {"r121", (db_expr_t*)89, db_getrse}, + {"r122", (db_expr_t*)90, db_getrse}, + {"r123", (db_expr_t*)91, db_getrse}, + {"r124", (db_expr_t*)92, db_getrse}, + {"r125", (db_expr_t*)93, db_getrse}, + {"r126", (db_expr_t*)94, db_getrse}, + {"r127", (db_expr_t*)95, db_getrse}, }; struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]); static int -db_get_rse_reg(struct db_variable *vp, db_expr_t *valuep, int op) +db_frame(struct db_variable *vp, db_expr_t *valuep, int op) +{ + uint64_t *reg; + + if (kdb_frame == NULL) + return (0); + reg = (uint64_t*)((uintptr_t)kdb_frame + (uintptr_t)vp->valuep); + if (op == DB_VAR_GET) + *valuep = *reg; + else + *reg = *valuep; + return (1); +} + +static int +db_getrse(struct db_variable *vp, db_expr_t *valuep, int op) { u_int64_t *reg; uint64_t bsp; int nats, regno, sof; - bsp = ddb_regs.tf_special.bspstore + ddb_regs.tf_special.ndirty; - regno = (db_expr_t)vp->valuep - 32; - sof = (int)(ddb_regs.tf_special.cfm & 0x7f); - nats = (sof - regno + 63 - ((int)(bsp >> 3) & 0x3f)) / 63; - - reg = (void*)(bsp - ((sof - regno + nats) << 3)); + if (kdb_frame == NULL) + return (0); - if (regno < sof) { - if (op == DB_VAR_GET) - *valuep = *reg; - else - *reg = *valuep; - } else { - if (op == DB_VAR_GET) - *valuep = 0xdeadbeefdeadbeef; - } + regno = (int)(intptr_t)valuep; + bsp = kdb_frame->tf_special.bspstore + kdb_frame->tf_special.ndirty; + sof = (int)(kdb_frame->tf_special.cfm & 0x7f); - return (0); -} + if (regno >= sof) + return (0); -static int -db_get_ip_reg(struct db_variable *vp, db_expr_t *valuep, int op) -{ - /* Read only */ + nats = (sof - regno + 63 - ((int)(bsp >> 3) & 0x3f)) / 63; + reg = (void*)(bsp - ((sof - regno + nats) << 3)); if (op == DB_VAR_GET) - *valuep = PC_REGS(DDB_REGS); - return 0; + *valuep = *reg; + else + *reg = *valuep; + return (1); } -#if 0 -/* - * Print trap reason. - */ -static void -ddbprinttrap(int vector) +static int +db_getip(struct db_variable *vp, db_expr_t *valuep, int op) { + u_long iip, slot; - /* XXX Implement. */ - - printf("ddbprinttrap(%d)\n", vector); -} -#endif - -#define CPUSTOP_ON_DDBBREAK -#define VERBOSE_CPUSTOP_ON_DDBBREAK + if (kdb_frame == NULL) + return (0); -/* - * ddb_trap - field a kernel trap - */ -int -kdb_trap(int vector, struct trapframe *regs) -{ - int ddb_mode = !(boothowto & RB_GDB); - register_t s; - - /* - * Don't bother checking for usermode, since a benign entry - * by the kernel (call to Debugger() or a breakpoint) has - * already checked for usermode. If neither of those - * conditions exist, something Bad has happened. - */ - - if (vector != IA64_VEC_BREAK - && vector != IA64_VEC_SINGLE_STEP_TRAP) { -#if 0 - if (ddb_mode) { - db_printf("ddbprinttrap from 0x%lx\n", /* XXX */ - regs->tf_regs[FRAME_PC]); - ddbprinttrap(a0, a1, a2, entry); - /* - * Tell caller "We did NOT handle the trap." - * Caller should panic, or whatever. - */ + if (op == DB_VAR_GET) { + iip = kdb_frame->tf_special.iip; + slot = (kdb_frame->tf_special.psr >> 41) & 3; + *valuep = iip + slot; + } else { + iip = *valuep & ~0xf; + slot = *valuep & 0xf; + if (slot > 2) return (0); - } -#endif - if (db_nofault) { - jmp_buf *no_fault = db_nofault; - db_nofault = 0; - longjmp(*no_fault, 1); - } - } - - /* - * XXX Should switch to DDB's own stack, here. - */ - - s = intr_disable(); - -#ifdef SMP -#ifdef CPUSTOP_ON_DDBBREAK - -#if defined(VERBOSE_CPUSTOP_ON_DDBBREAK) - db_printf("CPU%d stopping CPUs: 0x%08x...", PCPU_GET(cpuid), - PCPU_GET(other_cpus)); -#endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */ - - /* We stop all CPUs except ourselves (obviously) */ - stop_cpus(PCPU_GET(other_cpus)); - -#if defined(VERBOSE_CPUSTOP_ON_DDBBREAK) - db_printf(" stopped.\n"); -#endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */ - -#endif /* CPUSTOP_ON_DDBBREAK */ -#endif /* SMP */ - - ddb_regs = *regs; - - /* - * XXX pretend that registers outside the current frame don't exist. - */ - db_eregs = db_regs + DB_MISC_REGS + 3 + 27 + - (ddb_regs.tf_special.cfm & 0x7f); - - __asm __volatile("flushrs"); /* so we can look at them */ - - db_active++; - - if (ddb_mode) { - cndbctl(TRUE); /* DDB active, unblank video */ - db_trap(vector, 0); /* Where the work happens */ - cndbctl(FALSE); /* DDB inactive */ - } else - gdb_handle_exception(&ddb_regs, vector); - - db_active--; - -#ifdef SMP -#ifdef CPUSTOP_ON_DDBBREAK - -#if defined(VERBOSE_CPUSTOP_ON_DDBBREAK) - db_printf("CPU%d restarting CPUs: 0x%08x...", PCPU_GET(cpuid), - stopped_cpus); -#endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */ - - /* Restart all the CPUs we previously stopped */ - if (stopped_cpus != PCPU_GET(other_cpus) && smp_started != 0) { - db_printf("whoa, other_cpus: 0x%08x, stopped_cpus: 0x%08x\n", - PCPU_GET(other_cpus), stopped_cpus); - panic("stop_cpus() failed"); + kdb_frame->tf_special.iip = iip; + kdb_frame->tf_special.psr &= ~IA64_PSR_RI; + kdb_frame->tf_special.psr |= slot << 41; } - restart_cpus(stopped_cpus); - -#if defined(VERBOSE_CPUSTOP_ON_DDBBREAK) - db_printf(" restarted.\n"); -#endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */ - -#endif /* CPUSTOP_ON_DDBBREAK */ -#endif /* SMP */ - - *regs = ddb_regs; - - intr_restore(s); - - - /* - * Tell caller "We HAVE handled the trap." - */ return (1); } /* * Read bytes from kernel address space for debugger. */ -void +int db_read_bytes(vm_offset_t addr, size_t size, char *data) { - - db_nofault = &db_jmpbuf; - - if (addr < VM_MAX_ADDRESS) - copyin((char *)addr, data, size); - else - bcopy((char *)addr, data, size); - - db_nofault = 0; + jmp_buf jb; + void *prev_jb; + char *src; + int ret; + + prev_jb = kdb_jmpbuf(jb); + ret = setjmp(jb); + if (ret == 0) { + src = (char *)addr; + while (size-- > 0) + *data++ = *src++; + } + (void)kdb_jmpbuf(prev_jb); + return (ret); } /* * Write bytes to kernel address space for debugger. */ -void +int db_write_bytes(vm_offset_t addr, size_t size, char *data) { - - db_nofault = &db_jmpbuf; - - if (addr < VM_MAX_ADDRESS) - copyout(data, (char *)addr, size); - else - bcopy(data, (char *)addr, size); - - db_nofault = 0; + jmp_buf jb; + void *prev_jb; + char *dst; + int ret; + + prev_jb = kdb_jmpbuf(jb); + ret = setjmp(jb); + if (ret == 0) { + dst = (char *)addr; + while (size-- > 0) + *dst++ = *data++; + } + (void)kdb_jmpbuf(prev_jb); + return (ret); } void -Debugger(const char* msg) +db_bkpt_write(db_addr_t addr, BKPT_INST_TYPE *storage) { - printf("%s\n", msg); - __asm("break 0x80100"); -} + BKPT_INST_TYPE tmp; + db_addr_t loc; + int slot; -u_long -db_register_value(db_regs_t *regs, int regno) -{ - uint64_t *rsp; - uint64_t bsp; - int nats, sof; + slot = addr & 0xfUL; + if (slot >= SLOT_COUNT) + return; + loc = (addr & ~0xfUL) + (slot << 2); - if (regno == 0) - return (0); - if (regno == 1) - return (regs->tf_special.gp); - if (regno >= 2 && regno <= 3) - return ((®s->tf_scratch.gr2)[regno - 2]); - if (regno >= 8 && regno <= 11) - return ((®s->tf_scratch.gr8)[regno - 8]); - if (regno == 12) - return (regs->tf_special.sp); - if (regno == 13) - return (regs->tf_special.tp); - if (regno >= 14 && regno <= 31) - return ((®s->tf_scratch.gr14)[regno - 14]); - - sof = (int)(regs->tf_special.cfm & 0x7f); - if (regno >= 32 && regno < sof + 32) { - bsp = regs->tf_special.bspstore + regs->tf_special.ndirty; - regno -= 32; - nats = (sof - regno + 63 - ((int)(bsp >> 3) & 0x3f)) / 63; - rsp = (void*)(bsp - ((sof - regno + nats) << 3)); - return (*rsp); - } + db_read_bytes(loc, sizeof(BKPT_INST_TYPE), (char *)&tmp); + *storage = (tmp >> SLOT_SHIFT(slot)) & SLOT_MASK; - db_printf(" **** STRANGE REGISTER NUMBER %d **** ", regno); - return (0); + tmp &= ~(SLOT_MASK << SLOT_SHIFT(slot)); + tmp |= (0x84000 << 6) << SLOT_SHIFT(slot); + db_write_bytes(loc, sizeof(BKPT_INST_TYPE), (char *)&tmp); } void -db_write_breakpoint(vm_offset_t addr, u_int64_t *storage) +db_bkpt_clear(db_addr_t addr, BKPT_INST_TYPE *storage) { + BKPT_INST_TYPE tmp; + db_addr_t loc; + int slot; + + slot = addr & 0xfUL; + if (slot >= SLOT_COUNT) + return; + loc = (addr & ~0xfUL) + (slot << 2); + + db_read_bytes(loc, sizeof(BKPT_INST_TYPE), (char *)&tmp); + tmp &= ~(SLOT_MASK << SLOT_SHIFT(slot)); + tmp |= *storage << SLOT_SHIFT(slot); + db_write_bytes(loc, sizeof(BKPT_INST_TYPE), (char *)&tmp); } void -db_clear_breakpoint(vm_offset_t addr, u_int64_t *storage) +db_bkpt_skip(void) { -} -void -db_skip_breakpoint() -{ + if (kdb_frame == NULL) + return; - ddb_regs.tf_special.psr += IA64_PSR_RI_1; - if ((ddb_regs.tf_special.psr & IA64_PSR_RI) > IA64_PSR_RI_2) { - ddb_regs.tf_special.psr &= ~IA64_PSR_RI; - ddb_regs.tf_special.iip += 16; + kdb_frame->tf_special.psr += IA64_PSR_RI_1; + if ((kdb_frame->tf_special.psr & IA64_PSR_RI) > IA64_PSR_RI_2) { + kdb_frame->tf_special.psr &= ~IA64_PSR_RI; + kdb_frame->tf_special.iip += 16; } } diff --git a/sys/ia64/ia64/db_trace.c b/sys/ia64/ia64/db_trace.c index be301797e1f2b..11a2e5582771b 100644 --- a/sys/ia64/ia64/db_trace.c +++ b/sys/ia64/ia64/db_trace.c @@ -1,4 +1,5 @@ /*- + * Copyright (c) 2003, 2004 Marcel Moolenaar * Copyright (c) 2000-2001 Doug Rabson * All rights reserved. * @@ -27,8 +28,13 @@ */ #include <sys/param.h> +#include <sys/kdb.h> #include <sys/proc.h> + #include <machine/db_machdep.h> +#include <machine/frame.h> +#include <machine/md_var.h> +#include <machine/pcb.h> #include <machine/unwind.h> #include <machine/vmparam.h> @@ -38,14 +44,12 @@ #include <ddb/db_variables.h> #include <ddb/db_output.h> - int db_md_set_watchpoint(db_expr_t addr, db_expr_t size); int db_md_clr_watchpoint(db_expr_t addr, db_expr_t size); void db_md_list_watchpoints(void); -void -db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, - char *modif) +static int +db_backtrace(struct thread *td, struct pcb *pcb, int count) { struct unw_regstate rs; struct trapframe *tf; @@ -55,8 +59,7 @@ db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, c_db_sym_t sym; int args, error, i; - tf = &ddb_regs; - error = unw_create(&rs, tf); + error = unw_create_from_pcb(&rs, pcb); while (!error && count--) { error = unw_get_cfm(&rs, &cfm); if (!error) @@ -68,15 +71,14 @@ db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, if (error) break; - args = (cfm >> 7) & 0x7f; + args = IA64_CFM_SOL(cfm); if (args > 8) args = 8; error = unw_step(&rs); if (!error) { - error = unw_get_cfm(&rs, &pfs); - if (!error) { - i = (pfs & 0x7f) - ((pfs >> 7) & 0x7f); + if (!unw_get_cfm(&rs, &pfs)) { + i = IA64_CFM_SOF(pfs) - IA64_CFM_SOL(pfs); if (args > i) args = i; } @@ -115,15 +117,43 @@ db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, /* XXX ask if we should unwind across the trapframe. */ db_printf("--- trapframe at %p\n", tf); unw_delete(&rs); - error = unw_create(&rs, tf); + error = unw_create_from_frame(&rs, tf); } unw_delete(&rs); + return (error); } void -db_print_backtrace(void) +db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, + char *modif) { + struct thread *td; + + td = (have_addr) ? kdb_thr_lookup(addr) : kdb_thread; + if (td == NULL) { + db_printf("Thread %d not found\n", (int)addr); + return; + } + db_trace_thread(td, count); +} + +void +db_trace_self(void) +{ + struct pcb pcb; + + savectx(&pcb); + db_backtrace(curthread, &pcb, -1); +} + +int +db_trace_thread(struct thread *td, int count) +{ + struct pcb *ctx; + + ctx = kdb_thr_ctx(td); + return (db_backtrace(td, ctx, count)); } int diff --git a/sys/ia64/include/db_machdep.h b/sys/ia64/include/db_machdep.h index 4b801f6279bdd..25288cd331e27 100644 --- a/sys/ia64/include/db_machdep.h +++ b/sys/ia64/include/db_machdep.h @@ -1,66 +1,64 @@ -/* $FreeBSD$ */ -/* $NetBSD: db_machdep.h,v 1.6 1997/09/06 02:02:25 thorpej Exp $ */ - /* - * Copyright (c) 1995 Carnegie-Mellon University. + * Copyright (c) 2004 Marcel Moolenaar * All rights reserved. * - * Author: Chris G. Demetriou - * - * 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. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: * - * 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. + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. * - * Carnegie Mellon requests users of this software to return to + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * 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 the - * rights to redistribute these changes. + * $FreeBSD$ */ #ifndef _MACHINE_DB_MACHDEP_H_ #define _MACHINE_DB_MACHDEP_H_ -/* - * Machine-dependent defines for new kernel debugger. - */ - -#include <sys/param.h> -#include <vm/vm.h> -#include <machine/frame.h> #include <machine/ia64_cpu.h> -#define DB_NO_AOUT +/* We define some of our own commands. */ +#define DB_MACHINE_COMMANDS + +/* We use Elf64 symbols in DDB. */ +#define DB_ELFSIZE 64 -struct ia64_bundle; +/* Pretty arbitrary. */ +#define DB_SMALL_VALUE_MAX 0x7fffffff +#define DB_SMALL_VALUE_MIN (-0x400001) typedef vm_offset_t db_addr_t; /* address - unsigned */ typedef long db_expr_t; /* expression - signed */ -typedef struct trapframe db_regs_t; -extern db_regs_t ddb_regs; /* register state */ -#define DDB_REGS (&ddb_regs) -#define PC_REGS(regs) ((db_addr_t)(regs)->tf_special.iip + \ - (((regs)->tf_special.psr >> 41) & 3)) +#define PC_REGS() ((kdb_thrctx->pcb_special.__spare == 0) ? \ + kdb_thrctx->pcb_special.rp : \ + kdb_thrctx->pcb_special.iip + ((kdb_thrctx->pcb_special.psr>>41) & 3)) -#define BKPT_WRITE(addr, storage) db_write_breakpoint(addr, storage) -#define BKPT_CLEAR(addr, storage) db_clear_breakpoint(addr, storage) -#define BKPT_INST_TYPE u_int64_t +#define BKPT_WRITE(addr, storage) db_bkpt_write(addr, storage) +#define BKPT_CLEAR(addr, storage) db_bkpt_clear(addr, storage) +#define BKPT_SKIP db_bkpt_skip() +#define BKPT_INST_TYPE uint64_t -#define BKPT_SKIP db_skip_breakpoint() +void db_bkpt_write(db_addr_t, BKPT_INST_TYPE *storage); +void db_bkpt_clear(db_addr_t, uint64_t *storage); +void db_bkpt_skip(void); -#define db_clear_single_step(regs) ddb_regs.tf_special.psr &= ~IA64_PSR_SS -#define db_set_single_step(regs) ddb_regs.tf_special.psr |= IA64_PSR_SS +#define db_clear_single_step kdb_cpu_clear_singlestep +#define db_set_single_step kdb_cpu_set_singlestep #define IS_BREAKPOINT_TRAP(type, code) (type == IA64_VEC_BREAK) #define IS_WATCHPOINT_TRAP(type, code) 0 @@ -72,43 +70,7 @@ extern db_regs_t ddb_regs; /* register state */ #define inst_load(ins) (ins & 0) #define inst_store(ins) (ins & 0) #define inst_unconditional_flow_transfer(ins) (ins & 0) - -#define branch_taken(ins, pc, regs) pc - -/* - * Functions needed for software single-stepping. - */ - -/* No delay slots on Alpha. */ -#define next_instr_address(v, b) ((db_addr_t) ((b) ? (v) : ((v) + 4))) -u_long db_register_value(db_regs_t *, int); -int kdb_trap(int vector, struct trapframe *regs); - -u_int64_t *db_rse_current_frame(void); -u_int64_t *db_rse_previous_frame(u_int64_t *bsp, int sof); -u_int64_t *db_rse_register_address(u_int64_t *bsp, int regno); - -void db_read_bundle(db_addr_t addr, struct ia64_bundle *bp); -void db_write_bundle(db_addr_t addr, struct ia64_bundle *bp); -void db_write_breakpoint(db_addr_t addr, u_int64_t *storage); -void db_clear_breakpoint(db_addr_t addr, u_int64_t *storage); -void db_skip_breakpoint(void); - -/* - * Pretty arbitrary - */ -#define DB_SMALL_VALUE_MAX 0x7fffffff -#define DB_SMALL_VALUE_MIN (-0x400001) - -/* - * We define some of our own commands. - */ -#define DB_MACHINE_COMMANDS - -/* - * We use Elf64 symbols in DDB. - */ -#define DB_ELFSIZE 64 +#define branch_taken(ins, pc, regs) pc #endif /* _MACHINE_DB_MACHDEP_H_ */ diff --git a/sys/sparc64/include/db_machdep.h b/sys/sparc64/include/db_machdep.h index a31ec62d4b551..bb29debe249f6 100644 --- a/sys/sparc64/include/db_machdep.h +++ b/sys/sparc64/include/db_machdep.h @@ -38,23 +38,19 @@ typedef vm_offset_t db_addr_t; typedef long db_expr_t; -typedef struct trapframe db_regs_t; -extern db_regs_t ddb_regs; -#define DDB_REGS (&ddb_regs) - -#define PC_REGS(regs) ((db_addr_t)(regs)->tf_tpc) +#define PC_REGS() ((db_addr_t)kdb_thrctx->pcb_pc) #define BKPT_INST (0x91d03001) #define BKPT_SIZE (4) #define BKPT_SET(inst) (BKPT_INST) #define BKPT_SKIP do { \ - ddb_regs.tf_tpc = ddb_regs.tf_tnpc + 4; \ - ddb_regs.tf_tnpc += 8; \ + kdb_frame->tf_tpc = kdb_frame->tf_tnpc + 4; \ + kdb_frame->tf_tnpc += 8; \ } while (0) -#define db_clear_single_step(regs) -#define db_set_single_step(regs) +#define db_clear_single_step kdb_cpu_clear_singlestep +#define db_set_single_step kdb_cpu_set_singlestep #define IS_BREAKPOINT_TRAP(type, code) (type == T_BREAKPOINT) #define IS_WATCHPOINT_TRAP(type, code) (0) diff --git a/sys/sparc64/sparc64/db_interface.c b/sys/sparc64/sparc64/db_interface.c index b6a1e2032c0e0..77e1493652eb7 100644 --- a/sys/sparc64/sparc64/db_interface.c +++ b/sys/sparc64/sparc64/db_interface.c @@ -30,6 +30,7 @@ #include <sys/systm.h> #include <sys/reboot.h> #include <sys/cons.h> +#include <sys/kdb.h> #include <sys/ktr.h> #include <sys/linker_set.h> #include <sys/lock.h> @@ -51,66 +52,42 @@ #include <machine/atomic.h> #include <machine/setjmp.h> -static jmp_buf *db_nofault = 0; -extern jmp_buf db_jmpbuf; - -int db_active; -db_regs_t ddb_regs; - -static jmp_buf db_global_jmpbuf; -static int db_global_jmpbuf_valid; - int -kdb_trap(struct trapframe *tf) -{ - - if (db_global_jmpbuf_valid) - longjmp(db_global_jmpbuf, 1); - flushw(); - ddb_regs = *tf; - critical_enter(); - setjmp(db_global_jmpbuf); - db_global_jmpbuf_valid = TRUE; - atomic_add_acq_int(&db_active, 1); -#ifdef SMP - stop_cpus(PCPU_GET(other_cpus)); -#endif - cndbctl(TRUE); - db_trap(tf->tf_type, 0); - cndbctl(FALSE); - db_active--; -#ifdef SMP - restart_cpus(stopped_cpus); -#endif - db_global_jmpbuf_valid = FALSE; - critical_exit(); - *tf = ddb_regs; - TF_DONE(tf); - return (1); -} - -void db_read_bytes(vm_offset_t addr, size_t size, char *data) { + jmp_buf jb; + void *prev_jb; char *src; - - db_nofault = &db_jmpbuf; - src = (char *)addr; - while (size-- > 0) - *data++ = *src++; - db_nofault = NULL; + int ret; + + prev_jb = kdb_jmpbuf(jb); + ret = setjmp(jb); + if (ret == 0) { + src = (char *)addr; + while (size-- > 0) + *data++ = *src++; + } + (void)kdb_jmpbuf(prev_jb); + return (ret); } -void +int db_write_bytes(vm_offset_t addr, size_t size, char *data) { + jmp_buf jb; + void *prev_jb; char *dst; - - db_nofault = &db_jmpbuf; - dst = (char *)addr; - while (size-- > 0) - *dst++ = *data++; - db_nofault = NULL; + int ret; + + prev_jb = kdb_jmpbuf(jb); + ret = setjmp(jb); + if (ret == 0) { + dst = (char *)addr; + while (size-- > 0) + *dst++ = *data++; + } + (void)kdb_jmpbuf(prev_jb); + return (ret); } void diff --git a/sys/sparc64/sparc64/db_trace.c b/sys/sparc64/sparc64/db_trace.c index c57223fc62e75..ae538413cc92c 100644 --- a/sys/sparc64/sparc64/db_trace.c +++ b/sys/sparc64/sparc64/db_trace.c @@ -28,6 +28,7 @@ #include <sys/param.h> #include <sys/systm.h> +#include <sys/kdb.h> #include <sys/linker_set.h> #include <sys/proc.h> #include <sys/sysent.h> @@ -47,138 +48,89 @@ #include <ddb/db_variables.h> #include <ddb/db_watch.h> -static int db_print_trap(struct thread *td, struct trapframe *); -static void db_utrace(struct thread *td, struct trapframe *tf); - #define INKERNEL(va) \ ((va) >= VM_MIN_KERNEL_ADDRESS && (va) <= VM_MAX_KERNEL_ADDRESS) +static db_varfcn_t db_frame; + +#define DB_OFFSET(x) (db_expr_t *)offsetof(struct trapframe, x) struct db_variable db_regs[] = { - { "g0", &ddb_regs.tf_global[0], FCN_NULL }, - { "g1", &ddb_regs.tf_global[1], FCN_NULL }, - { "g2", &ddb_regs.tf_global[2], FCN_NULL }, - { "g3", &ddb_regs.tf_global[3], FCN_NULL }, - { "g4", &ddb_regs.tf_global[4], FCN_NULL }, - { "g5", &ddb_regs.tf_global[5], FCN_NULL }, - { "g6", &ddb_regs.tf_global[6], FCN_NULL }, - { "g7", &ddb_regs.tf_global[7], FCN_NULL }, - { "i0", &ddb_regs.tf_out[0], FCN_NULL }, - { "i1", &ddb_regs.tf_out[1], FCN_NULL }, - { "i2", &ddb_regs.tf_out[2], FCN_NULL }, - { "i3", &ddb_regs.tf_out[3], FCN_NULL }, - { "i4", &ddb_regs.tf_out[4], FCN_NULL }, - { "i5", &ddb_regs.tf_out[5], FCN_NULL }, - { "i6", &ddb_regs.tf_out[6], FCN_NULL }, - { "i7", &ddb_regs.tf_out[7], FCN_NULL }, - { "tnpc", &ddb_regs.tf_tnpc, FCN_NULL }, - { "tpc", &ddb_regs.tf_tpc, FCN_NULL }, - { "tstate", &ddb_regs.tf_tstate, FCN_NULL }, + { "g0", DB_OFFSET(tf_global[0]), db_frame }, + { "g1", DB_OFFSET(tf_global[1]), db_frame }, + { "g2", DB_OFFSET(tf_global[2]), db_frame }, + { "g3", DB_OFFSET(tf_global[3]), db_frame }, + { "g4", DB_OFFSET(tf_global[4]), db_frame }, + { "g5", DB_OFFSET(tf_global[5]), db_frame }, + { "g6", DB_OFFSET(tf_global[6]), db_frame }, + { "g7", DB_OFFSET(tf_global[7]), db_frame }, + { "i0", DB_OFFSET(tf_out[0]), db_frame }, + { "i1", DB_OFFSET(tf_out[1]), db_frame }, + { "i2", DB_OFFSET(tf_out[2]), db_frame }, + { "i3", DB_OFFSET(tf_out[3]), db_frame }, + { "i4", DB_OFFSET(tf_out[4]), db_frame }, + { "i5", DB_OFFSET(tf_out[5]), db_frame }, + { "i6", DB_OFFSET(tf_out[6]), db_frame }, + { "i7", DB_OFFSET(tf_out[7]), db_frame }, + { "tnpc", DB_OFFSET(tf_tnpc), db_frame }, + { "tpc", DB_OFFSET(tf_tpc), db_frame }, + { "tstate", DB_OFFSET(tf_tstate), db_frame }, }; struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]); -void -db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, - char *modif) +static int +db_frame(struct db_variable *vp, db_expr_t *valuep, int op) { - struct trapframe *tf; - struct frame *fp; - struct proc *p; - struct thread *td; - const char *name; - c_db_sym_t sym; - db_expr_t offset; - db_expr_t value; - db_addr_t npc; - db_addr_t pc; - int trap; - int user; - pid_t pid; + uint64_t *reg; - trap = 0; - user = 0; - npc = 0; - if (count == -1) - count = 1024; - td = curthread; - p = td->td_proc; - /* - * Provide an /a modifier to pass the stack address instead of a PID - * as argument. - * Note that, if this address is not on the stack of curthread, the - * printed data may be wrong (at the moment, this applies only to the - * sysent list). - */ - if (!have_addr) - addr = DDB_REGS->tf_out[6]; - else if (strcmp(modif, "a") != 0) { - /* - * addr was parsed as hex, convert so it is interpreted as - * decimal (ugh). - */ - pid = (addr % 16) + ((addr >> 4) % 16) * 10 + - ((addr >> 8) % 16) * 100 + ((addr >> 12) % 16) * 1000 + - ((addr >> 16) % 16) * 10000; - /* - * The pcb for curproc is not valid at this point, - * so fall back to the default case. - */ - if (pid == curthread->td_proc->p_pid) { - td = curthread; - p = td->td_proc; - addr = DDB_REGS->tf_out[6]; - } else { - /* sx_slock(&allproc_lock); */ - LIST_FOREACH(p, &allproc, p_list) { - if (p->p_pid == pid) - break; - } - /* sx_sunlock(&allproc_lock); */ - if (p == NULL) { - db_printf("pid %d not found\n", pid); - return; - } - if ((p->p_sflag & PS_INMEM) == 0) { - db_printf("pid %d swapped out\n", pid); - return; - } - td = FIRST_THREAD_IN_PROC(p); /* XXXKSE */ - addr = td->td_pcb->pcb_sp; - } - } - fp = (struct frame *)(addr + SPOFF); + if (kdb_frame == NULL) + return (0); + reg = (uint64_t*)((uintptr_t)kdb_frame + (uintptr_t)vp->valuep); + if (op == DB_VAR_GET) + *valuep = *reg; + else + *reg = *valuep; + return (1); +} - while (count-- && !user) { - pc = (db_addr_t)db_get_value((db_addr_t)&fp->fr_pc, - sizeof(fp->fr_pc), FALSE); - if (trap) { - pc = npc; - trap = 0; +/* + * User stack trace (debugging aid). + */ +static void +db_utrace(struct thread *td, struct trapframe *tf) +{ + struct pcb *pcb; + db_addr_t sp, rsp, o7, pc; + int i, found; + + pcb = td->td_pcb; + sp = db_get_value((db_addr_t)&tf->tf_sp, sizeof(tf->tf_sp), FALSE); + o7 = db_get_value((db_addr_t)&tf->tf_out[7], sizeof(tf->tf_out[7]), + FALSE); + pc = db_get_value((db_addr_t)&tf->tf_tpc, sizeof(tf->tf_tpc), FALSE); + db_printf("user trace: trap %%o7=%#lx\n", o7); + while (sp != 0) { + db_printf("pc %#lx, sp %#lx\n", pc, sp); + /* First, check whether the frame is in the pcb. */ + found = 0; + for (i = 0; i < pcb->pcb_nsaved; i++) { + if (pcb->pcb_rwsp[i] == sp) { + found = 1; + sp = pcb->pcb_rw[i].rw_in[6]; + pc = pcb->pcb_rw[i].rw_in[7]; + break; + } } - if (!INKERNEL((vm_offset_t)pc)) - break; - sym = db_search_symbol(pc, DB_STGY_ANY, &offset); - if (sym == C_DB_SYM_NULL) { - value = 0; - name = NULL; - } else - db_symbol_values(sym, &name, &value); - if (name == NULL) - name = "(null)"; - fp = (struct frame *)(db_get_value((db_addr_t)&fp->fr_fp, - sizeof(fp->fr_fp), FALSE) + SPOFF); - if (bcmp(name, "tl0_", 4) == 0 || - bcmp(name, "tl1_", 4) == 0) { - tf = (struct trapframe *)(fp + 1); - npc = db_get_value((db_addr_t)&tf->tf_tpc, - sizeof(tf->tf_tpc), FALSE); - user = db_print_trap(td, tf); - trap = 1; - } else { - db_printf("%s() at ", name); - db_printsym(pc, DB_STGY_PROC); - db_printf("\n"); + if (!found) { + rsp = sp + SPOFF; + sp = 0; + if (copyin((void *)(rsp + offsetof(struct frame, fr_fp)), + &sp, sizeof(sp)) != 0 || + copyin((void *)(rsp + offsetof(struct frame, fr_pc)), + &pc, sizeof(pc)) != 0) + break; } } + db_printf("done\n"); } static int @@ -265,52 +217,88 @@ db_print_trap(struct thread *td, struct trapframe *tf) return (user); } -/* - * User stack trace (debugging aid). - */ -static void -db_utrace(struct thread *td, struct trapframe *tf) +static int +db_backtrace(struct thread *td, struct frame *fp, int count) { - struct pcb *pcb; - db_addr_t sp, rsp, o7, pc; - int i, found; + struct trapframe *tf; + const char *name; + c_db_sym_t sym; + db_expr_t offset; + db_expr_t value; + db_addr_t npc; + db_addr_t pc; + int trap; + int user; - pcb = td->td_pcb; - sp = db_get_value((db_addr_t)&tf->tf_sp, sizeof(tf->tf_sp), FALSE); - o7 = db_get_value((db_addr_t)&tf->tf_out[7], sizeof(tf->tf_out[7]), - FALSE); - pc = db_get_value((db_addr_t)&tf->tf_tpc, sizeof(tf->tf_tpc), FALSE); - db_printf("user trace: trap %%o7=%#lx\n", o7); - while (sp != 0) { - db_printf("pc %#lx, sp %#lx\n", pc, sp); - /* First, check whether the frame is in the pcb. */ - found = 0; - for (i = 0; i < pcb->pcb_nsaved; i++) { - if (pcb->pcb_rwsp[i] == sp) { - found = 1; - sp = pcb->pcb_rw[i].rw_in[6]; - pc = pcb->pcb_rw[i].rw_in[7]; - break; - } + if (count == -1) + count = 1024; + + trap = 0; + user = 0; + npc = 0; + while (count-- && !user) { + pc = (db_addr_t)db_get_value((db_addr_t)&fp->fr_pc, + sizeof(fp->fr_pc), FALSE); + if (trap) { + pc = npc; + trap = 0; } - if (!found) { - rsp = sp + SPOFF; - sp = 0; - if (copyin((void *)(rsp + offsetof(struct frame, fr_fp)), - &sp, sizeof(sp)) != 0 || - copyin((void *)(rsp + offsetof(struct frame, fr_pc)), - &pc, sizeof(pc)) != 0) - break; + if (!INKERNEL((vm_offset_t)pc)) + break; + sym = db_search_symbol(pc, DB_STGY_ANY, &offset); + if (sym == C_DB_SYM_NULL) { + value = 0; + name = NULL; + } else + db_symbol_values(sym, &name, &value); + if (name == NULL) + name = "(null)"; + fp = (struct frame *)(db_get_value((db_addr_t)&fp->fr_fp, + sizeof(fp->fr_fp), FALSE) + SPOFF); + if (bcmp(name, "tl0_", 4) == 0 || + bcmp(name, "tl1_", 4) == 0) { + tf = (struct trapframe *)(fp + 1); + npc = db_get_value((db_addr_t)&tf->tf_tpc, + sizeof(tf->tf_tpc), FALSE); + user = db_print_trap(td, tf); + trap = 1; + } else { + db_printf("%s() at ", name); + db_printsym(pc, DB_STGY_PROC); + db_printf("\n"); } } - db_printf("done\n"); + return (0); } void -db_print_backtrace(void) +db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, + char *modif) +{ + struct thread *td; + + td = (have_addr) ? kdb_thr_lookup(addr) : kdb_thread; + if (td == NULL) { + db_printf("Thread %d not found\n", (int)addr); + return; + } + db_trace_thread(td, count); +} + +void +db_trace_self(void) +{ + db_expr_t addr; + + addr = (db_expr_t)__builtin_frame_address(1); + db_backtrace(curthread, (struct frame *)(addr + SPOFF), -1); +} + +int +db_trace_thread(struct thread *td, int count) { - u_long *sp; + struct pcb *ctx; - sp = __builtin_frame_address(1); - db_stack_trace_cmd((db_expr_t)sp, TRUE, -1, "a"); + ctx = kdb_thr_ctx(td); + return (db_backtrace(td, (struct frame*)(ctx->pcb_sp + SPOFF), count)); } |