diff options
Diffstat (limited to 'sys/i386')
-rw-r--r-- | sys/i386/i386/db_disasm.c | 13 | ||||
-rw-r--r-- | sys/i386/i386/db_interface.c | 24 | ||||
-rw-r--r-- | sys/i386/i386/db_trace.c | 55 | ||||
-rw-r--r-- | sys/i386/i386/trap.c | 41 | ||||
-rw-r--r-- | sys/i386/i386/vm86.c | 8 | ||||
-rw-r--r-- | sys/i386/include/db_machdep.h | 19 |
6 files changed, 130 insertions, 30 deletions
diff --git a/sys/i386/i386/db_disasm.c b/sys/i386/i386/db_disasm.c index 2b398da..5728fe5 100644 --- a/sys/i386/i386/db_disasm.c +++ b/sys/i386/i386/db_disasm.c @@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$"); * Instruction disassembler. */ #include <sys/param.h> +#include <sys/kdb.h> #include <ddb/ddb.h> #include <ddb/db_access.h> @@ -1168,9 +1169,17 @@ db_disasm(db_addr_t loc, bool altfmt) int len; struct i_addr address; + if (db_segsize(kdb_frame) == 16) + altfmt = !altfmt; get_value_inc(inst, loc, 1, FALSE); - short_addr = FALSE; - size = LONG; + if (altfmt) { + short_addr = TRUE; + size = WORD; + } + else { + short_addr = FALSE; + size = LONG; + } seg = NULL; /* diff --git a/sys/i386/i386/db_interface.c b/sys/i386/i386/db_interface.c index 7079e56..3c0ac81 100644 --- a/sys/i386/i386/db_interface.c +++ b/sys/i386/i386/db_interface.c @@ -135,6 +135,30 @@ db_write_bytes(vm_offset_t addr, size_t size, char *data) return (ret); } +int +db_segsize(struct trapframe *tfp) +{ + struct proc_ldt *plp; + struct segment_descriptor *sdp; + int sel; + + if (tfp == NULL) + return (32); + if (tfp->tf_eflags & PSL_VM) + return (16); + sel = tfp->tf_cs & 0xffff; + if (sel == GSEL(GCODE_SEL, SEL_KPL)) + return (32); + /* Rare cases follow. User mode cases are currently unreachable. */ + if (ISLDT(sel)) { + plp = curthread->td_proc->p_md.md_ldt; + sdp = (plp != NULL) ? &plp->ldt_sd : &ldt[0].sd; + } else { + sdp = &gdt[PCPU_GET(cpuid) * NGDT].sd; + } + return (sdp[IDXSEL(sel)].sd_def32 == 0 ? 16 : 32); +} + void db_show_mdpcpu(struct pcpu *pc) { diff --git a/sys/i386/i386/db_trace.c b/sys/i386/i386/db_trace.c index 3563579..4f5f413 100644 --- a/sys/i386/i386/db_trace.c +++ b/sys/i386/i386/db_trace.c @@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$"); #include <sys/sysent.h> #include <machine/cpu.h> +#include <machine/frame.h> #include <machine/md_var.h> #include <machine/pcb.h> #include <machine/reg.h> @@ -81,8 +82,7 @@ struct db_variable *db_eregs = db_regs + nitems(db_regs); 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)); + return (TF_HAS_STACKREGS(tf) ? tf->tf_esp : (intptr_t)&tf->tf_esp); } static int @@ -104,12 +104,32 @@ db_frame(struct db_variable *vp, db_expr_t *valuep, int op) static int db_frame_seg(struct db_variable *vp, db_expr_t *valuep, int op) { + struct trapframe_vm86 *tfp; + int off; uint16_t *reg; if (kdb_frame == NULL) return (0); - reg = (uint16_t *)((uintptr_t)kdb_frame + (db_expr_t)vp->valuep); + off = (intptr_t)vp->valuep; + if (kdb_frame->tf_eflags & PSL_VM) { + tfp = (void *)kdb_frame; + switch ((intptr_t)vp->valuep) { + case (intptr_t)DB_OFFSET(tf_cs): + reg = (uint16_t *)&tfp->tf_cs; + break; + case (intptr_t)DB_OFFSET(tf_ds): + reg = (uint16_t *)&tfp->tf_vm86_ds; + break; + case (intptr_t)DB_OFFSET(tf_es): + reg = (uint16_t *)&tfp->tf_vm86_es; + break; + case (intptr_t)DB_OFFSET(tf_fs): + reg = (uint16_t *)&tfp->tf_vm86_fs; + break; + } + } else + reg = (uint16_t *)((uintptr_t)kdb_frame + off); if (op == DB_VAR_GET) *valuep = *reg; else @@ -126,7 +146,7 @@ db_esp(struct db_variable *vp, db_expr_t *valuep, int op) if (op == DB_VAR_GET) *valuep = get_esp(kdb_frame); - else if (ISPL(kdb_frame->tf_cs)) + else if (TF_HAS_STACKREGS(kdb_frame)) kdb_frame->tf_esp = *valuep; return (1); } @@ -134,7 +154,16 @@ db_esp(struct db_variable *vp, db_expr_t *valuep, int op) static int db_gs(struct db_variable *vp, db_expr_t *valuep, int op) { + struct trapframe_vm86 *tfp; + if (kdb_frame != NULL && kdb_frame->tf_eflags & PSL_VM) { + tfp = (void *)kdb_frame; + if (op == DB_VAR_GET) + *valuep = tfp->tf_vm86_gs; + else + tfp->tf_vm86_gs = *valuep; + return (1); + } if (op == DB_VAR_GET) *valuep = rgs(); else @@ -150,8 +179,9 @@ db_ss(struct db_variable *vp, db_expr_t *valuep, int op) 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)) + *valuep = TF_HAS_STACKREGS(kdb_frame) ? kdb_frame->tf_ss : + rss(); + else if (TF_HAS_STACKREGS(kdb_frame)) kdb_frame->tf_ss = *valuep; return (1); } @@ -391,6 +421,17 @@ db_backtrace(struct thread *td, struct trapframe *tf, struct i386_frame *frame, int instr, narg; boolean_t first; + if (db_segsize(tf) == 16) { + db_printf( +"--- 16-bit%s, cs:eip = %#x:%#x, ss:esp = %#x:%#x, ebp = %#x, tf = %p ---\n", + (tf->tf_eflags & PSL_VM) ? " (vm86)" : "", + tf->tf_cs, tf->tf_eip, + TF_HAS_STACKREGS(tf) ? tf->tf_ss : rss(), + TF_HAS_STACKREGS(tf) ? tf->tf_esp : (intptr_t)&tf->tf_esp, + tf->tf_ebp, tf); + return (0); + } + /* * If an indirect call via an invalid pointer caused a trap, * %pc contains the invalid address while the return address @@ -408,7 +449,7 @@ db_backtrace(struct thread *td, struct trapframe *tf, struct i386_frame *frame, * Find where the trap frame actually ends. * It won't contain tf_esp or tf_ss unless crossing rings. */ - if (ISPL(kdb_frame->tf_cs)) + if (TF_HAS_STACKREGS(kdb_frame)) instr = (int)(kdb_frame + 1); else instr = (int)&kdb_frame->tf_esp; diff --git a/sys/i386/i386/trap.c b/sys/i386/i386/trap.c index c540a49..3decfd43 100644 --- a/sys/i386/i386/trap.c +++ b/sys/i386/i386/trap.c @@ -189,7 +189,10 @@ trap(struct trapframe *frame) #endif struct thread *td = curthread; struct proc *p = td->td_proc; - int i = 0, ucode = 0, code; +#ifdef KDB + register_t dr6; +#endif + int i = 0, ucode = 0; u_int type; register_t addr = 0; vm_offset_t eva; @@ -267,7 +270,8 @@ trap(struct trapframe *frame) * interrupts disabled until they are accidentally * enabled later. */ - if (ISPL(frame->tf_cs) == SEL_UPL || (frame->tf_eflags & PSL_VM)) + if (TRAPF_USERMODE(frame) && + (curpcb->pcb_flags & PCB_VM86CALL) == 0) uprintf( "pid %ld (%s): trap %d with interrupts disabled\n", (long)curproc->p_pid, curthread->td_name, type); @@ -291,7 +295,6 @@ trap(struct trapframe *frame) } } eva = 0; - code = frame->tf_err; if (type == T_PAGEFLT) { /* * For some Cyrix CPUs, %cr2 is clobbered by @@ -307,9 +310,7 @@ trap(struct trapframe *frame) enable_intr(); } - if ((ISPL(frame->tf_cs) == SEL_UPL) || - ((frame->tf_eflags & PSL_VM) && - !(curpcb->pcb_flags & PCB_VM86CALL))) { + if (TRAPF_USERMODE(frame) && (curpcb->pcb_flags & PCB_VM86CALL) == 0) { /* user trap */ td->td_pticks = 0; @@ -335,6 +336,7 @@ trap(struct trapframe *frame) goto out; } #endif +user_trctrap_out: frame->tf_eflags &= ~PSL_T; i = SIGTRAP; ucode = (type == T_TRCTRAP ? TRAP_TRACE : TRAP_BRKPT); @@ -360,6 +362,11 @@ trap(struct trapframe *frame) case T_STKFLT: /* stack fault */ if (frame->tf_eflags & PSL_VM) { i = vm86_emulate((struct vm86frame *)frame); + if (i == SIGTRAP) { + type = T_TRCTRAP; + load_dr6(rdr6() | 0x4000); + goto user_trctrap_out; + } if (i == 0) goto user; break; @@ -461,7 +468,7 @@ trap(struct trapframe *frame) goto userout; #else /* !POWERFAIL_NMI */ /* machine/parity/power fail/"kitchen sink" faults */ - if (isa_nmi(code) == 0) { + if (isa_nmi(frame->tf_err) == 0) { #ifdef KDB /* * NMI can be hooked up to a pushbutton @@ -566,6 +573,11 @@ trap(struct trapframe *frame) case T_STKFLT: /* stack fault */ if (frame->tf_eflags & PSL_VM) { i = vm86_emulate((struct vm86frame *)frame); + if (i == SIGTRAP) { + type = T_TRCTRAP; + load_dr6(rdr6() | 0x4000); + goto kernel_trctrap; + } if (i != 0) /* * returns to original process @@ -654,6 +666,7 @@ trap(struct trapframe *frame) break; case T_TRCTRAP: /* trace trap */ +kernel_trctrap: if (frame->tf_eip == (int)IDTVEC(lcall_syscall)) { /* * We've just entered system mode via the @@ -687,7 +700,7 @@ trap(struct trapframe *frame) * Reset breakpoint bits because the * processor doesn't */ - load_dr6(rdr6() & 0xfffffff0); + load_dr6(rdr6() & ~0xf); goto out; } /* @@ -699,7 +712,10 @@ trap(struct trapframe *frame) * Otherwise, debugger traps "can't happen". */ #ifdef KDB - if (kdb_trap(type, 0, frame)) + /* XXX %dr6 is not quite reentrant. */ + dr6 = rdr6(); + load_dr6(dr6 & ~0x4000); + if (kdb_trap(type, dr6, frame)) goto out; #endif break; @@ -715,7 +731,7 @@ trap(struct trapframe *frame) goto out; #else /* !POWERFAIL_NMI */ /* machine/parity/power fail/"kitchen sink" faults */ - if (isa_nmi(code) == 0) { + if (isa_nmi(frame->tf_err) == 0) { #ifdef KDB /* * NMI can be hooked up to a pushbutton @@ -953,7 +969,7 @@ trap_fatal(frame, eva) } printf("instruction pointer = 0x%x:0x%x\n", frame->tf_cs & 0xffff, frame->tf_eip); - if ((ISPL(frame->tf_cs) == SEL_UPL) || (frame->tf_eflags & PSL_VM)) { + if (TF_HAS_STACKREGS(frame)) { ss = frame->tf_ss & 0xffff; esp = frame->tf_esp; } else { @@ -1107,7 +1123,8 @@ syscall(struct trapframe *frame) ksiginfo_t ksi; #ifdef DIAGNOSTIC - if (ISPL(frame->tf_cs) != SEL_UPL) { + if (!(TRAPF_USERMODE(frame) && + (curpcb->pcb_flags & PCB_VM86CALL) == 0)) { panic("syscall"); /* NOT REACHED */ } diff --git a/sys/i386/i386/vm86.c b/sys/i386/i386/vm86.c index 93ff855..baa1912 100644 --- a/sys/i386/i386/vm86.c +++ b/sys/i386/i386/vm86.c @@ -171,7 +171,7 @@ vm86_emulate(vmf) PUSHL((vmf->vmf_eflags & PUSH_MASK) | PSL_IOPL, vmf); vmf->vmf_ip += inc_ip; - return (0); + return (retcode); case POPF: temp_flags = POPL(vmf) & POP_MASK; @@ -185,7 +185,7 @@ vm86_emulate(vmf) } else { vmf->vmf_eflags &= ~PSL_VIF; } - return (0); + return (retcode); } break; @@ -203,7 +203,7 @@ vm86_emulate(vmf) case INTn: break; - /* VME if trying to set PSL_TF, or PSL_I when VIP is set */ + /* VME if trying to set PSL_T, or PSL_I when VIP is set */ case POPF: temp_flags = POP(vmf) & POP_MASK; vmf->vmf_flags = (vmf->vmf_flags & ~POP_MASK) @@ -218,7 +218,7 @@ vm86_emulate(vmf) } return (retcode); - /* VME if trying to set PSL_TF, or PSL_I when VIP is set */ + /* VME if trying to set PSL_T, or PSL_I when VIP is set */ case IRET: vmf->vmf_ip = POP(vmf); vmf->vmf_cs = POP(vmf); diff --git a/sys/i386/include/db_machdep.h b/sys/i386/include/db_machdep.h index 27207a8..e8d1d8e 100644 --- a/sys/i386/include/db_machdep.h +++ b/sys/i386/include/db_machdep.h @@ -35,7 +35,10 @@ typedef vm_offset_t db_addr_t; /* address - unsigned */ typedef int db_expr_t; /* expression - signed */ -#define PC_REGS() ((db_addr_t)kdb_thrctx->pcb_eip) +#define PC_REGS() ((db_addr_t)(kdb_frame->tf_eflags & PSL_VM ? \ + (kdb_frame->tf_eip & 0xffff) + \ + ((kdb_frame->tf_cs & 0xffff) << 4) : \ + kdb_frame->tf_eip)) #define BKPT_INST 0xcc /* breakpoint instruction */ #define BKPT_SIZE (1) /* size of breakpoint inst */ @@ -56,12 +59,16 @@ do { \ #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) /* - * Watchpoints are not supported. The debug exception type is in %dr6 - * and not yet in the args to this macro. + * The debug exception type is copied from %dr6 to 'code' and used to + * disambiguate single step traps. Watchpoints have no special support. + * Our hardware breakpoints are not well integrated with ddb and are too + * different from watchpoints. ddb treats them as unknown traps with + * unknown addresses and doesn't turn them off while it is running. */ -#define IS_WATCHPOINT_TRAP(type, code) 0 +#define IS_BREAKPOINT_TRAP(type, code) ((type) == T_BPTFLT) +#define IS_SSTEP_TRAP(type, code) ((type) == T_TRCTRAP && (code) & 0x4000) +#define IS_WATCHPOINT_TRAP(type, code) 0 #define I_CALL 0xe8 #define I_CALLI 0xff @@ -91,4 +98,6 @@ do { \ #define DB_SMALL_VALUE_MAX 0x7fffffff #define DB_SMALL_VALUE_MIN (-0x400001) +int db_segsize(struct trapframe *tfp); + #endif /* !_MACHINE_DB_MACHDEP_H_ */ |