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:
Konstantin Belousov 2019-11-12 15:56:27 +00:00
parent a7af4a3e7d
commit 006269f469
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=354647
2 changed files with 31 additions and 24 deletions

View File

@ -297,7 +297,6 @@ db_nextframe(struct i386_frame **fp, db_addr_t *ip, struct thread *td)
{
struct trapframe *tf;
int frame_type;
int narg;
int eip, esp, ebp;
db_expr_t offset;
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;
/*
* 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) {
sym = db_search_symbol(eip - 1 - setidt_disp, DB_STGY_ANY,
&offset);
@ -338,8 +329,6 @@ db_nextframe(struct i386_frame **fp, db_addr_t *ip, struct thread *td)
frame_type = TRAP;
else if (strncmp(name, "Xatpic_intr", 11) == 0 ||
strncmp(name, "Xapic_isr", 9) == 0) {
/* Additional argument: vector number. */
narg = 2;
frame_type = INTERRUPT;
} else if (strcmp(name, "Xlcall_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, "Xipi_intr_bitmap_handler") == 0) {
/* No arguments. */
narg = 0;
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
* current frame. Note that struct i386_frame already accounts for one
* argument.
* Point to base of trapframe which is just above the current
* frame. Pointer to it was put into %ebp by the kernel entry
* code.
*/
tf = (struct trapframe *)((char *)*fp + sizeof(struct i386_frame) +
4 * (narg - 1));
tf = (struct trapframe *)(*fp)->f_frame;
/*
* 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);
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);
/*
* Detect the last (trap) frame on the kernel stack, where we
* entered kernel from usermode. Terminate tracing in this
* case.
*/
switch (frame_type) {
case TRAP:
case INTERRUPT:
if ((tf->tf_eflags & PSL_VM) != 0 ||
(tf->tf_cs & SEL_RPL_MASK) != 0)
ebp = 0;
break;
if (!TRAPF_USERMODE(tf))
break;
/* FALLTHROUGH */
case SYSCALL:
ebp = 0;
eip = 0;
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.
*/
if (frame == NULL || frame <= actframe) {
sym = db_search_symbol(pc, DB_STGY_ANY, &offset);
db_symbol_values(sym, &name, NULL);
db_print_stack_entry(name, 0, 0, 0, pc, frame);
if (pc != 0) {
sym = db_search_symbol(pc, DB_STGY_ANY,
&offset);
db_symbol_values(sym, &name, NULL);
db_print_stack_entry(name, 0, 0, 0, pc, frame);
}
break;
}
}

View File

@ -157,6 +157,7 @@
movw %es,(%esp)
pushl $0
movw %fs,(%esp)
movl %esp,%ebp
.endm
.macro PUSH_FRAME