Let the unwinder handle faults during function prologues or epilogues.

The i386 and amd64 DDB stack unwinders contain code to detect and handle
the case where the first frame is not completely set up or torn down. This
code was accidentally unused however, since db_backtrace() was never called
with a non-NULL trap frame. This change fixes that.

Also remove get_rsp() from the amd64 code. It appears to have come from
i386, which needs to take into account whether the exception triggered a
CPL switch, since SS:ESP is only pushed onto the stack if so. On amd64,
SS:RSP is pushed regardless, so get_rsp() was doing the wrong thing for
kernel-mode exceptions. As a result, we can also remove custom print
functions for these registers.

Reviewed by:	jhb
Sponsored by:	EMC / Isilon Storage Division
Differential Revision:	https://reviews.freebsd.org/D2881
This commit is contained in:
Mark Johnston 2015-07-21 23:22:23 +00:00
parent f8a757d016
commit a5cbf8b9c0
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=285776
2 changed files with 13 additions and 46 deletions

View File

@ -61,8 +61,6 @@ 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;
CTASSERT(sizeof(struct dbreg) == sizeof(((struct pcpu *)NULL)->pc_dbreg));
@ -76,12 +74,12 @@ struct db_variable db_regs[] = {
{ "es", DB_OFFSET(tf_es), db_frame },
{ "fs", DB_OFFSET(tf_fs), db_frame },
{ "gs", DB_OFFSET(tf_gs), db_frame },
{ "ss", NULL, db_ss },
{ "ss", DB_OFFSET(tf_ss), db_frame },
{ "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 },
{ "rsp", DB_OFFSET(tf_rsp), db_frame },
{ "rbp", DB_OFFSET(tf_rbp), db_frame },
{ "rsi", DB_OFFSET(tf_rsi), db_frame },
{ "rdi", DB_OFFSET(tf_rdi), db_frame },
@ -130,13 +128,6 @@ 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)
{
@ -153,34 +144,6 @@ db_frame(struct db_variable *vp, db_expr_t *valuep, int op)
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);
}
#define NORMAL 0
#define TRAP 1
#define INTERRUPT 2
@ -304,7 +267,7 @@ db_nextframe(struct amd64_frame **fp, db_addr_t *ip, struct thread *td)
tf = (struct trapframe *)((long)*fp + 16);
if (INKERNEL((long) tf)) {
rsp = get_rsp(tf);
rsp = tf->tf_rsp;
rip = tf->tf_rip;
rbp = tf->tf_rbp;
switch (frame_type) {
@ -380,20 +343,20 @@ db_backtrace(struct thread *td, struct trapframe *tf, struct amd64_frame *frame,
instr = db_get_value(pc, 4, FALSE);
if ((instr & 0xffffffff) == 0xe5894855) {
/* pushq %rbp; movq %rsp, %rbp */
actframe = (void *)(get_rsp(tf) - 8);
actframe = (void *)(tf->tf_rsp - 8);
} else if ((instr & 0xffffff) == 0xe58948) {
/* movq %rsp, %rbp */
actframe = (void *)get_rsp(tf);
actframe = (void *)tf->tf_rsp;
if (tf->tf_rbp == 0) {
/* Fake frame better. */
frame = actframe;
}
} else if ((instr & 0xff) == 0xc3) {
/* ret */
actframe = (void *)(get_rsp(tf) - 8);
actframe = (void *)(tf->tf_rsp - 8);
} else if (offset == 0) {
/* Probably an assembler symbol. */
actframe = (void *)(get_rsp(tf) - 8);
actframe = (void *)(tf->tf_rsp - 8);
}
} else if (strcmp(name, "fork_trampoline") == 0) {
/*
@ -448,9 +411,11 @@ int
db_trace_thread(struct thread *thr, int count)
{
struct pcb *ctx;
struct trapframe *tf;
ctx = kdb_thr_ctx(thr);
return (db_backtrace(thr, NULL, (struct amd64_frame *)ctx->pcb_rbp,
tf = thr == kdb_thread ? kdb_frame : NULL;
return (db_backtrace(thr, tf, (struct amd64_frame *)ctx->pcb_rbp,
ctx->pcb_rip, ctx->pcb_rsp, count));
}

View File

@ -541,9 +541,11 @@ int
db_trace_thread(struct thread *thr, int count)
{
struct pcb *ctx;
struct trapframe *tf;
ctx = kdb_thr_ctx(thr);
return (db_backtrace(thr, NULL, (struct i386_frame *)ctx->pcb_ebp,
tf = thr == kdb_thread ? kdb_frame : NULL;
return (db_backtrace(thr, tf, (struct i386_frame *)ctx->pcb_ebp,
ctx->pcb_eip, ctx->pcb_esp, count));
}