summaryrefslogtreecommitdiffstats
path: root/sys/i386/i386
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2015-11-12 22:45:51 +0000
committerjhb <jhb@FreeBSD.org>2015-11-12 22:45:51 +0000
commit2285630285e9d969da6a43fe0dbb58bb71fff2f6 (patch)
tree4c6c11e1fed1ad4f8cca85f9135fadae35c74d91 /sys/i386/i386
parent5b5d335fed990b7c6249d5063886fa5990382ffa (diff)
downloadFreeBSD-src-2285630285e9d969da6a43fe0dbb58bb71fff2f6.zip
FreeBSD-src-2285630285e9d969da6a43fe0dbb58bb71fff2f6.tar.gz
MFC 285773,285775,285776:
Various fixes for stack unwinding in DDB on x86. 285773: Remove some dead code from DDB's amd64 stack unwinder. The amd64 port copied some code from i386 to fetch function arguments and display them in backtraces. However, it was commented out and can't easily be implemented since the function arguments are passed in registers rather than on the stack in amd64. Remove it in preparation for some bug fixes in this area. 285775: Improve stack unwinding on i386 and amd64 after an IP fault. If we can't find a symbol corresponding to the faulting instruction, assume that the previously-executed function is a call and attempt to find the calling function using the return address on the stack. Otherwise we end up associating the last stack frame with the current call, which is incorrect and causes the unwinder to skip printing of the calling function, resulting in a confusing backtrace. 285776: 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.
Diffstat (limited to 'sys/i386/i386')
-rw-r--r--sys/i386/i386/db_trace.c27
1 files changed, 21 insertions, 6 deletions
diff --git a/sys/i386/i386/db_trace.c b/sys/i386/i386/db_trace.c
index 822cc56..644925d 100644
--- a/sys/i386/i386/db_trace.c
+++ b/sys/i386/i386/db_trace.c
@@ -390,7 +390,7 @@ db_nextframe(struct i386_frame **fp, db_addr_t *ip, struct thread *td)
static int
db_backtrace(struct thread *td, struct trapframe *tf, struct i386_frame *frame,
- db_addr_t pc, int count)
+ db_addr_t pc, register_t sp, int count)
{
struct i386_frame *actframe;
#define MAXNARG 16
@@ -447,7 +447,21 @@ db_backtrace(struct thread *td, struct trapframe *tf, struct i386_frame *frame,
*/
actframe = frame;
if (first) {
- if (tf != NULL) {
+ first = FALSE;
+ if (sym == C_DB_SYM_NULL && sp != 0) {
+ /*
+ * If a symbol couldn't be found, we've probably
+ * jumped to a bogus location, so try and use
+ * the return address to find our caller.
+ */
+ db_print_stack_entry(name, 0, 0, 0, pc,
+ NULL);
+ pc = db_get_value(sp, 4, FALSE);
+ if (db_search_symbol(pc, DB_STGY_PROC,
+ &offset) == C_DB_SYM_NULL)
+ break;
+ continue;
+ } else if (tf != NULL) {
instr = db_get_value(pc, 4, FALSE);
if ((instr & 0xffffff) == 0x00e58955) {
/* pushl %ebp; movl %esp, %ebp */
@@ -475,7 +489,6 @@ db_backtrace(struct thread *td, struct trapframe *tf, struct i386_frame *frame,
actframe);
break;
}
- first = FALSE;
}
argp = &actframe->f_arg0;
@@ -522,17 +535,19 @@ db_trace_self(void)
frame = (struct i386_frame *)ebp;
callpc = (db_addr_t)db_get_value((int)&frame->f_retaddr, 4, FALSE);
frame = frame->f_frame;
- db_backtrace(curthread, NULL, frame, callpc, -1);
+ db_backtrace(curthread, NULL, frame, callpc, 0, -1);
}
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,
- ctx->pcb_eip, count));
+ 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));
}
int
OpenPOWER on IntegriCloud