i386: stop guessing the address of the trap frame in ddb backtrace.
Save the address of the trap frame in %ebp on kernel entry. This automatically provides it in struct i386_frame.f_frame to unwinder. While there, more accurately handle the terminating frames, Reviewed by: avg, markj Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D22321
This commit is contained in:
parent
a7af4a3e7d
commit
006269f469
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=354647
@ -297,7 +297,6 @@ db_nextframe(struct i386_frame **fp, db_addr_t *ip, struct thread *td)
|
|||||||
{
|
{
|
||||||
struct trapframe *tf;
|
struct trapframe *tf;
|
||||||
int frame_type;
|
int frame_type;
|
||||||
int narg;
|
|
||||||
int eip, esp, ebp;
|
int eip, esp, ebp;
|
||||||
db_expr_t offset;
|
db_expr_t offset;
|
||||||
c_db_sym_t sym;
|
c_db_sym_t sym;
|
||||||
@ -317,14 +316,6 @@ db_nextframe(struct i386_frame **fp, db_addr_t *ip, struct thread *td)
|
|||||||
*/
|
*/
|
||||||
frame_type = NORMAL;
|
frame_type = NORMAL;
|
||||||
|
|
||||||
/*
|
|
||||||
* This is the number of arguments that a syscall / trap / interrupt
|
|
||||||
* service routine passes to its callee. This number is used only for
|
|
||||||
* special frame types. In most cases there is one argument: the trap
|
|
||||||
* frame address.
|
|
||||||
*/
|
|
||||||
narg = 1;
|
|
||||||
|
|
||||||
if (eip >= PMAP_TRM_MIN_ADDRESS) {
|
if (eip >= PMAP_TRM_MIN_ADDRESS) {
|
||||||
sym = db_search_symbol(eip - 1 - setidt_disp, DB_STGY_ANY,
|
sym = db_search_symbol(eip - 1 - setidt_disp, DB_STGY_ANY,
|
||||||
&offset);
|
&offset);
|
||||||
@ -338,8 +329,6 @@ db_nextframe(struct i386_frame **fp, db_addr_t *ip, struct thread *td)
|
|||||||
frame_type = TRAP;
|
frame_type = TRAP;
|
||||||
else if (strncmp(name, "Xatpic_intr", 11) == 0 ||
|
else if (strncmp(name, "Xatpic_intr", 11) == 0 ||
|
||||||
strncmp(name, "Xapic_isr", 9) == 0) {
|
strncmp(name, "Xapic_isr", 9) == 0) {
|
||||||
/* Additional argument: vector number. */
|
|
||||||
narg = 2;
|
|
||||||
frame_type = INTERRUPT;
|
frame_type = INTERRUPT;
|
||||||
} else if (strcmp(name, "Xlcall_syscall") == 0 ||
|
} else if (strcmp(name, "Xlcall_syscall") == 0 ||
|
||||||
strcmp(name, "Xint0x80_syscall") == 0)
|
strcmp(name, "Xint0x80_syscall") == 0)
|
||||||
@ -353,7 +342,6 @@ db_nextframe(struct i386_frame **fp, db_addr_t *ip, struct thread *td)
|
|||||||
strcmp(name, "Xrendezvous") == 0 ||
|
strcmp(name, "Xrendezvous") == 0 ||
|
||||||
strcmp(name, "Xipi_intr_bitmap_handler") == 0) {
|
strcmp(name, "Xipi_intr_bitmap_handler") == 0) {
|
||||||
/* No arguments. */
|
/* No arguments. */
|
||||||
narg = 0;
|
|
||||||
frame_type = INTERRUPT;
|
frame_type = INTERRUPT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -387,12 +375,22 @@ db_nextframe(struct i386_frame **fp, db_addr_t *ip, struct thread *td)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Point to base of trapframe which is just above the
|
* Point to base of trapframe which is just above the current
|
||||||
* current frame. Note that struct i386_frame already accounts for one
|
* frame. Pointer to it was put into %ebp by the kernel entry
|
||||||
* argument.
|
* code.
|
||||||
*/
|
*/
|
||||||
tf = (struct trapframe *)((char *)*fp + sizeof(struct i386_frame) +
|
tf = (struct trapframe *)(*fp)->f_frame;
|
||||||
4 * (narg - 1));
|
|
||||||
|
/*
|
||||||
|
* This can be the case for e.g. fork_trampoline, last frame
|
||||||
|
* of a kernel thread stack.
|
||||||
|
*/
|
||||||
|
if (tf == NULL) {
|
||||||
|
*ip = 0;
|
||||||
|
*fp = 0;
|
||||||
|
db_printf("--- kthread start\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
esp = get_esp(tf);
|
esp = get_esp(tf);
|
||||||
eip = tf->tf_eip;
|
eip = tf->tf_eip;
|
||||||
@ -413,15 +411,20 @@ db_nextframe(struct i386_frame **fp, db_addr_t *ip, struct thread *td)
|
|||||||
}
|
}
|
||||||
db_printf(", eip = %#r, esp = %#r, ebp = %#r ---\n", eip, esp, ebp);
|
db_printf(", eip = %#r, esp = %#r, ebp = %#r ---\n", eip, esp, ebp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Detect the last (trap) frame on the kernel stack, where we
|
||||||
|
* entered kernel from usermode. Terminate tracing in this
|
||||||
|
* case.
|
||||||
|
*/
|
||||||
switch (frame_type) {
|
switch (frame_type) {
|
||||||
case TRAP:
|
case TRAP:
|
||||||
case INTERRUPT:
|
case INTERRUPT:
|
||||||
if ((tf->tf_eflags & PSL_VM) != 0 ||
|
if (!TRAPF_USERMODE(tf))
|
||||||
(tf->tf_cs & SEL_RPL_MASK) != 0)
|
break;
|
||||||
ebp = 0;
|
/* FALLTHROUGH */
|
||||||
break;
|
|
||||||
case SYSCALL:
|
case SYSCALL:
|
||||||
ebp = 0;
|
ebp = 0;
|
||||||
|
eip = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -575,9 +578,12 @@ db_backtrace(struct thread *td, struct trapframe *tf, struct i386_frame *frame,
|
|||||||
* after printing the pc if it is the kernel.
|
* after printing the pc if it is the kernel.
|
||||||
*/
|
*/
|
||||||
if (frame == NULL || frame <= actframe) {
|
if (frame == NULL || frame <= actframe) {
|
||||||
sym = db_search_symbol(pc, DB_STGY_ANY, &offset);
|
if (pc != 0) {
|
||||||
db_symbol_values(sym, &name, NULL);
|
sym = db_search_symbol(pc, DB_STGY_ANY,
|
||||||
db_print_stack_entry(name, 0, 0, 0, pc, frame);
|
&offset);
|
||||||
|
db_symbol_values(sym, &name, NULL);
|
||||||
|
db_print_stack_entry(name, 0, 0, 0, pc, frame);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -157,6 +157,7 @@
|
|||||||
movw %es,(%esp)
|
movw %es,(%esp)
|
||||||
pushl $0
|
pushl $0
|
||||||
movw %fs,(%esp)
|
movw %fs,(%esp)
|
||||||
|
movl %esp,%ebp
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
.macro PUSH_FRAME
|
.macro PUSH_FRAME
|
||||||
|
Loading…
Reference in New Issue
Block a user