diff options
Diffstat (limited to 'sys/amd64')
-rw-r--r-- | sys/amd64/amd64/db_interface.c | 314 | ||||
-rw-r--r-- | sys/amd64/amd64/db_trace.c | 416 | ||||
-rw-r--r-- | sys/amd64/include/db_machdep.h | 17 |
3 files changed, 259 insertions, 488 deletions
diff --git a/sys/amd64/amd64/db_interface.c b/sys/amd64/amd64/db_interface.c index f6bf21898193..67c8ae5c6549 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 6df1bd10034b..03842cb530eb 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 18b5e5d981f5..0a737ebb64bf 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) /* |