The i386 "call" instruction works as follows: it pushes

the return address on the stack and only then "dereferences" %pc.
Therefore, in the case of a call to an invalid address, we arrive
to the trap handler with the invalid value in tf_eip.  This used
to prevent db_backtrace() from assigning the most recent and interesting
frame on the stack to the right spot in the right function, from
which the invalid call was attempted.

Try to detect and work around that by recovering the return address
from the stack.

The work-around requires the fault address be passed to db_backtrace().
Smuggle it as tf_err.

MFC after:	1 month
Sponsored by:	RiNet (Cronyx Plus LLC)
This commit is contained in:
yar 2006-06-18 12:07:00 +00:00
parent 9d4650295f
commit e95f07384c
2 changed files with 28 additions and 3 deletions

View File

@ -401,9 +401,33 @@ db_backtrace(struct thread *td, struct trapframe *tf, struct i386_frame *frame,
int *argp;
db_expr_t offset;
c_db_sym_t sym;
int narg, quit;
int instr, narg, quit;
boolean_t first;
/*
* If an indirect call via an invalid pointer caused a trap,
* %pc contains the invalid address while the return address
* of the unlucky caller has been saved by CPU on the stack
* just before the trap frame. In this case, try to recover
* the caller's address so that the first frame is assigned
* to the right spot in the right function, for that is where
* the failure actually happened.
*
* This trick depends on the fault address stashed in tf_err
* by trap_fatal() before entering KDB.
*/
if (kdb_frame && pc == kdb_frame->tf_err) {
/*
* 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))
instr = (int)(kdb_frame + 1);
else
instr = (int)&kdb_frame->tf_esp;
pc = db_get_value(instr, 4, FALSE);
}
if (count == -1)
count = 1024;
@ -428,8 +452,6 @@ db_backtrace(struct thread *td, struct trapframe *tf, struct i386_frame *frame,
actframe = frame;
if (first) {
if (tf != NULL) {
int instr;
instr = db_get_value(pc, 4, FALSE);
if ((instr & 0xffffff) == 0x00e58955) {
/* pushl %ebp; movl %esp, %ebp */

View File

@ -858,10 +858,13 @@ trap_fatal(frame, eva)
if (debugger_on_panic || kdb_active) {
register_t eflags;
eflags = intr_disable();
frame->tf_err = eva; /* smuggle fault address to ddb */
if (kdb_trap(type, 0, frame)) {
frame->tf_err = code; /* restore error code */
intr_restore(eflags);
return;
}
frame->tf_err = code; /* restore error code */
intr_restore(eflags);
}
#endif