Determine the operand/address size of %cs in a new function

db_segsize().

Use db_segsize() to set the default operand/address size for
disassembling.  Allow overriding this with the "alternate" display
format /I.  The API of db_disasm() should be debooleanized to pass a
more general request (amd64 needs overrides to sizes of 16, 32, and
64, but this commit doesn't implement anything for amd64 since much
larger changes are needed to restore the amd64 disassmbler's support
for non-default sizes).

Fix db_print_loc_and_inst() to ask for the normal format and not the
alternate in normal operation.

This is most useful for vm86 mode, but also works for 16-bit protected
mode.

Use db_segsize() to avoid trying to print a garbage stack trace if %cs
is 16 bits.  Print something like the stack trace termination message
for a trap boundary instead.

Document that the alternate format is now useful on i386.
This commit is contained in:
bde 2016-09-25 16:30:29 +00:00
parent 94a237c17c
commit 7d8ccb0c00
6 changed files with 52 additions and 4 deletions

View File

@ -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

View File

@ -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);
}
}

View File

@ -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);
if (altfmt) {
short_addr = TRUE;
size = WORD;
}
else {
short_addr = FALSE;
size = LONG;
}
seg = NULL;
/*

View File

@ -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)
{

View File

@ -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

View File

@ -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_ */