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:
parent
9d4650295f
commit
e95f07384c
@ -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 */
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user