diff --git a/share/man/man4/ddb.4 b/share/man/man4/ddb.4 index cb883216f91..6b072ba1ee3 100644 --- a/share/man/man4/ddb.4 +++ b/share/man/man4/ddb.4 @@ -264,7 +264,9 @@ The location is also displayed in hex at the beginning of each line. display as an instruction .It Cm I display as an instruction with possible alternate formats depending on the -machine, but none of the supported architectures have an alternate format +machine. +On i386, this selects the alternate format for the instruction decoding +(16 bits in a 32-bit code segment and vice versa). .It Cm S display a symbol name for the pointer stored at the address .El diff --git a/sys/ddb/db_examine.c b/sys/ddb/db_examine.c index de2bbe4e773..a1e5a2858ab 100644 --- a/sys/ddb/db_examine.c +++ b/sys/ddb/db_examine.c @@ -241,7 +241,7 @@ db_print_loc_and_inst(db_addr_t loc) db_printsym(loc, DB_STGY_PROC); if (db_search_symbol(loc, DB_STGY_PROC, &off) != C_DB_SYM_NULL) { db_printf(":\t"); - (void)db_disasm(loc, true); + (void)db_disasm(loc, false); } } diff --git a/sys/i386/i386/db_disasm.c b/sys/i386/i386/db_disasm.c index 2b398da8e96..5728fe5def0 100644 --- a/sys/i386/i386/db_disasm.c +++ b/sys/i386/i386/db_disasm.c @@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$"); * Instruction disassembler. */ #include +#include #include #include @@ -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 7079e5688b8..3c0ac813ff6 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 4918ed232dd..4f5f4130f2a 100644 --- a/sys/i386/i386/db_trace.c +++ b/sys/i386/i386/db_trace.c @@ -421,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 diff --git a/sys/i386/include/db_machdep.h b/sys/i386/include/db_machdep.h index 3ab06486a3f..e8d1d8eab95 100644 --- a/sys/i386/include/db_machdep.h +++ b/sys/i386/include/db_machdep.h @@ -98,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_ */