[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[Crash-utility] x86 backtrace is dependent upon struct pt_regs at compile time



This problem has been reported before, but the discussion on it seemed
to move off track and I don't think that anyone really found the root cause.

The problem is that the x86 backtrace functionality in crash is
dependent upon the struct pt_regs taken from <asm/ptrace.h> at compile
time.  struct pt_regs changed in 2.6.20.  The result of this is that if
crash is compiled on 2.6.20 or later and subsequently used to look at a
2.6.19 or earlier dump, then exception frames are incorrectly displayed
and backtraces stop at them.

Here is an example of a 2.6.22-compiled crash displaying a trace from a
RHEL5 (2.6.18) dump:

crash> bt
PID: 3490   TASK: f7f5a000  CPU: 0   COMMAND: "insmod"
#0 [f664ddd0] crash_kexec at c0441c78
#1 [f664de14] die at c04064a4
#2 [f664de44] do_page_fault at c0605eea
#3 [f664de94] error_code (via page_fault) at c0405a6f
   EAX: 00000000  EBX: f8dd3400  ECX: 00200082  EDX: 00200000
   DS:  007b      ESI: f7bbeab0  ES:  007b      EDI: f7bbe800
   SS:  ffffe800      ESP: 00000000  EBP: f7bbead8
   CS:  0060      EIP: f8dd300d  ERR: ffffffff  EFLAGS: 00210296
crash>

Note that in the above, crash thinks that the exception frame is a user
mode one and not a kernel frame.

If crash was compiled on RHEL5 (2.6.18), then the trace looks like this:

crash> bt
PID: 3490   TASK: f7f5a000  CPU: 0   COMMAND: "insmod"
#0 [f664ddd0] crash_kexec at c0441c78
#1 [f664de14] die at c04064a4
#2 [f664de44] do_page_fault at c0605eea
#3 [f664de94] error_code (via page_fault) at c0405a6f
   EAX: 00000000  EBX: f8dd3400  ECX: 00200082  EDX: 00200000  EBP:
f7bbead8
   DS:  007b      ESI: f7bbeab0  ES:  007b      EDI: f7bbe800
   CS:  0060      EIP: f8dd300d  ERR: ffffffff  EFLAGS: 00210296
#4 [f664dec8] function2 at f8dd300d
#5 [f664dee0] sys_init_module at c043e717
#6 [f664dfb8] system_call at c0404ef8
   EAX: ffffffda  EBX: 0861a028  ECX: 00010144  EDX: 0861a018
   DS:  007b      ESI: 00000000  ES:  007b      EDI: 00307ff4
   SS:  007b      ESP: bfe5695c  EBP: bfe569a8
   CS:  0073      EIP: 00d37402  ERR: 00000080  EFLAGS: 00200206
crash>

A similar problem happens if crash is compiled on pre-2.6.20 and then
used to analyse a 2.6.20 or later dump.


Dave, I have attached a patch to this e-mail which removes the
dependence upon <asm/prtrace.h> from lkcd_x86_trace.c (which is used for
non-LKCD dumps as well as LKCD dumps by the way).  I notice that
eframe_init() in x86.c initialises several variables which correspond to
the struct pt_regs so I've had to make these external for
lkcd_x86_trace.c's use.  I have no problem in this being reworked if you
feel that these symbols really should be in defs.h (or any other rework
that you think is fit, for that matter).

Regards,

Alan Tyson, HP.

--- crash-4.0-4.12-orig/x86.c	2007-12-12 18:48:09.000000000 +0000
+++ crash-4.0-4.12/x86.c	2007-12-17 10:43:07.000000000 +0000
@@ -1009,22 +1009,22 @@ static void x86_init_hyper(int);
 static ulong x86_get_stackbase_hyper(ulong);
 static ulong x86_get_stacktop_hyper(ulong);
 
-static int INT_EFRAME_SS = 14;
-static int INT_EFRAME_ESP = 13;
-static int INT_EFRAME_EFLAGS = 12;   /* CS lcall7 */
-static int INT_EFRAME_CS = 11;       /* EIP lcall7 */
-static int INT_EFRAME_EIP = 10;      /* EFLAGS lcall7 */
-static int INT_EFRAME_ERR = 9;
-static int INT_EFRAME_ES = 8;
-static int INT_EFRAME_DS = 7;
-static int INT_EFRAME_EAX = 6;
-static int INT_EFRAME_EBP = 5;
-static int INT_EFRAME_EDI = 4;
-static int INT_EFRAME_ESI = 3;
-static int INT_EFRAME_EDX = 2;
-static int INT_EFRAME_ECX = 1;
-static int INT_EFRAME_EBX = 0;
-static int INT_EFRAME_GS = -1;
+       int INT_EFRAME_SS = 14;
+       int INT_EFRAME_ESP = 13;
+       int INT_EFRAME_EFLAGS = 12;   /* CS lcall7 */
+       int INT_EFRAME_CS = 11;       /* EIP lcall7 */
+       int INT_EFRAME_EIP = 10;      /* EFLAGS lcall7 */
+       int INT_EFRAME_ERR = 9;
+       int INT_EFRAME_ES = 8;
+       int INT_EFRAME_DS = 7;
+       int INT_EFRAME_EAX = 6;
+       int INT_EFRAME_EBP = 5;
+       int INT_EFRAME_EDI = 4;
+       int INT_EFRAME_ESI = 3;
+       int INT_EFRAME_EDX = 2;
+       int INT_EFRAME_ECX = 1;
+       int INT_EFRAME_EBX = 0;
+       int INT_EFRAME_GS = -1;
 
 #define MAX_USER_EFRAME_SIZE   (16)
 #define KERNEL_EFRAME_SIZE (INT_EFRAME_EFLAGS+1)
--- crash-4.0-4.12-orig/lkcd_x86_trace.c	2007-12-12 18:48:09.000000000 +0000
+++ crash-4.0-4.12/lkcd_x86_trace.c	2007-12-17 10:49:15.000000000 +0000
@@ -54,10 +54,9 @@ static int eframe_incr(kaddr_t, char *);
 static int find_trace(kaddr_t, kaddr_t, kaddr_t, kaddr_t, trace_t *, int);
 static void dump_stack_frame(trace_t *, sframe_t *, FILE *);
 static void print_trace(trace_t *, int, FILE *);
-struct pt_regs;
-static int eframe_type(struct pt_regs *);
+static int eframe_type(uaddr_t *);
 char *funcname_display(char *);
-static void print_eframe(FILE *, struct pt_regs *);
+static void print_eframe(FILE *, uaddr_t *);
 static void trace_banner(FILE *);
 static void print_kaddr(kaddr_t, FILE *, int);
 int do_text_list(kaddr_t, int, FILE *);
@@ -1122,7 +1121,6 @@ valid_ra_function(kaddr_t ra, char *func
         return(0);
 }
 
-#include <asm/ptrace.h>
 #ifndef REDHAT
 #include <asm/segment.h>
 #endif
@@ -1144,52 +1142,79 @@ valid_ra_function(kaddr_t ra, char *func
 #define __USER_DS       0x2B
 #endif
 
+extern int INT_EFRAME_SS;
+extern int INT_EFRAME_ESP;
+extern int INT_EFRAME_EFLAGS;
+extern int INT_EFRAME_CS;
+extern int INT_EFRAME_EIP;
+extern int INT_EFRAME_ERR;
+extern int INT_EFRAME_ES;
+extern int INT_EFRAME_DS;
+extern int INT_EFRAME_EAX;
+extern int INT_EFRAME_EBP;
+extern int INT_EFRAME_EDI;
+extern int INT_EFRAME_ESI;
+extern int INT_EFRAME_EDX;
+extern int INT_EFRAME_ECX;
+extern int INT_EFRAME_EBX;
+extern int INT_EFRAME_GS;
+
 /* 
  * Check if the exception frame is of kernel or user type 
  * Is checking only DS and CS values sufficient ?
  */
-int eframe_type(struct pt_regs *regs)
+
+int eframe_type(uaddr_t *int_eframe)
 {
-	if (((regs->xcs & 0xffff) == __KERNEL_CS) && 
-			((regs->xds & 0xffff) == __KERNEL_DS))
+	short xcs = (short)int_eframe[INT_EFRAME_CS];
+	short xds = (short)int_eframe[INT_EFRAME_DS];
+
+	if (((xcs & 0xffff) == __KERNEL_CS) && 
+			((xds & 0xffff) == __KERNEL_DS))
 		return KERNEL_EFRAME;
 #ifdef REDHAT
-	else if (((regs->xcs & 0xffff) == 0x60) && 
-			((regs->xds & 0xffff) == 0x68))
+	else if (((xcs & 0xffff) == 0x60) && 
+			((xds & 0xffff) == 0x68))
 		return KERNEL_EFRAME;
-        else if (((regs->xcs & 0xffff) == 0x60) &&
-                        ((regs->xds & 0xffff) == 0x7b))
-                return KERNEL_EFRAME;
-	else if (XEN() && ((regs->xcs & 0xffff) == 0x61) &&
-                        ((regs->xds & 0xffff) == 0x7b))
+	else if (((xcs & 0xffff) == 0x60) &&
+			((xds & 0xffff) == 0x7b))
+		return KERNEL_EFRAME;
+	else if (XEN() && ((xcs & 0xffff) == 0x61) &&
+			((xds & 0xffff) == 0x7b))
 		return KERNEL_EFRAME;
 #endif
-	else if (((regs->xcs & 0xffff) == __USER_CS) && 
-			((regs->xds & 0xffff) == __USER_DS))
+	else if (((xcs & 0xffff) == __USER_CS) && 
+			((xds & 0xffff) == __USER_DS))
 		return USER_EFRAME;
 #ifdef REDHAT
-	else if (((regs->xcs & 0xffff) == 0x73) && 
-			((regs->xds & 0xffff) == 0x7b))
+	else if (((xcs & 0xffff) == 0x73) && 
+			((xds & 0xffff) == 0x7b))
 		return USER_EFRAME;
 #endif
 	return -1;
 }
 
-void print_eframe(FILE *ofp, struct pt_regs *regs)
+void print_eframe(FILE *ofp, uaddr_t *regs)
 {
 	int type = eframe_type(regs);
 
 #ifdef REDHAT
 	x86_dump_eframe_common(NULL, (ulong *)regs, (type == KERNEL_EFRAME));
 #else
-	fprintf(ofp, "   ebx: %08lx   ecx: %08lx   edx: %08lx   esi: %08lx\n",
-			regs->ebx, regs->ecx, regs->edx, regs->esi);
-	fprintf(ofp, "   edi: %08lx   ebp: %08lx   eax: %08lx   ds:  %04x\n",
-			regs->edi, regs->ebp, regs->eax, regs->xds & 0xffff);
-	fprintf(ofp, "   es:  %04x       eip: %08lx   cs:  %04x       eflags: %08lx\n",
-		       regs->xes & 0xffff, regs->eip, regs->xcs & 0xffff, regs->eflags);	
+
+	fprintf(ofp, "   ebx: %08x   ecx: %08x   edx: %08x   esi: %08x\n",
+			regs[INT_EFRAME_EBX], regs[INT_EFRAME_ECX],
+			regs[INT_EFRAME_EDX], regs[INT_EFRAME_ESI]);
+	fprintf(ofp, "   edi: %08x   ebp: %08x   eax: %08x   ds:  %04x\n",
+			regs[INT_EFRAME_EDI], regs[INT_EFRAME_EBP],
+			regs[INT_EFRAME_EAX], regs[INT_EFRAME_DS] & 0xffff);
+	fprintf(ofp, "   es:  %04x       eip: %08x   cs:  %04x       eflags: %08x\n",
+			regs[INT_EFRAME_ES] & 0xffff, regs[INT_EFRAME_EIP],
+			regs[INT_EFRAME_CS] & 0xffff, regs[INT_EFRAME_EFLAGS]);	
 	if (type == USER_EFRAME)
-		fprintf(ofp, "   esp: %08lx   ss:  %04x\n", regs->esp, regs->xss);
+		fprintf(ofp, "   esp: %08x   ss:  %04x\n",
+			regs[INT_EFRAME_ESP], regs[INT_EFRAME_SS]);
+
 #endif
 }
 
@@ -1350,7 +1375,7 @@ find_trace(
 	int flag;
 	int interrupted_system_call = FALSE;
 	struct bt_info *bt = trace->bt;
-	struct pt_regs *pt;
+	uaddr_t *pt;
 #endif
 	sbp = trace->stack[curstkidx].ptr;
 	sbase = trace->stack[curstkidx].addr;
@@ -1624,14 +1649,14 @@ find_trace(
 				asp = (uaddr_t*)((uaddr_t)sbp + (STACK_SIZE - 
 							(saddr - sp)));
 				curframe = alloc_sframe(trace, flags);
-				ra = ((struct pt_regs *)asp)->eip;
-				frame_type = eframe_type((struct pt_regs*)asp);
+				ra = asp[INT_EFRAME_EIP];
+				frame_type = eframe_type(asp);
 				UPDATE_FRAME(func_name, pc, ra, sp, bp, asp, 
 						0, 0, (bp - sp + 4), EX_FRAME);
 
 				/* prepare for next kernel frame, if present */
 				if (frame_type == KERNEL_EFRAME) {
-					pc = ((struct pt_regs *)asp)->eip;
+					pc = asp[INT_EFRAME_EIP];
 					sp = curframe->fp+4;
 #ifdef REDHAT
 					bp = sp + get_framesize(pc, bt);
@@ -1650,20 +1675,20 @@ find_trace(
 				sp = curframe->fp + 4;
 				asp = (uaddr_t*)((uaddr_t)sbp + (STACK_SIZE - 
 						(saddr - sp)));
-				frame_type = eframe_type((struct pt_regs*)asp);
+				frame_type = eframe_type(asp);
 				if (frame_type == KERNEL_EFRAME)
 					bp = curframe->fp+(KERNEL_EFRAME_SZ-1)*4;
 				else 
 					bp = curframe->fp+(USER_EFRAME_SZ-1)*4;
 				curframe = alloc_sframe(trace, flags);
-				ra = ((struct pt_regs *)asp)->eip;
+				ra = asp[INT_EFRAME_EIP];
 				UPDATE_FRAME(func_name, pc, ra, sp, bp + 4, asp,
 			       	0, 0, curframe->fp - curframe->sp+4, EX_FRAME);
 
 				/* prepare for next kernel frame, if present */
 				if (frame_type == KERNEL_EFRAME) {
 					sp = curframe->fp + 4;
-					pc = ((struct pt_regs *)asp)->eip;
+					pc = asp[INT_EFRAME_EIP];
 #ifdef REDHAT
 					bp = sp + get_framesize(pc, bt);
 #else
@@ -1711,7 +1736,7 @@ find_trace(
 		 */
                 if ((bt->flags & BT_XEN_STOP_THIS_CPU) && bt->tc->mm_struct &&
                     STREQ(kl_funcname(curframe->pc), "hypervisor_callback")) {
-                	pt = (struct pt_regs *)(curframe->asp+1);
+                	pt = curframe->asp+1;
                         if (eframe_type(pt) == USER_EFRAME) {
 				if (program_context.debug >= 1)  /* pc above */
                         		error(INFO, 
@@ -1803,7 +1828,7 @@ print_trace(trace_t *trace, int flags, F
 #ifdef REDHAT
 	kaddr_t fp = 0;
 	kaddr_t last_fp, last_pc, next_fp, next_pc;
-	struct pt_regs *pt;
+	uaddr_t *pt;
 	struct bt_info *bt;
 
 	bt = trace->bt;
@@ -1864,7 +1889,7 @@ print_trace(trace_t *trace, int flags, F
 			fprintf(ofp, " [0x%x]\n", frmp->pc);
 #endif
 			if (frmp->flag & EX_FRAME) {
-				pt = (struct pt_regs *)frmp->asp;
+				pt = frmp->asp;
 				if (CRASHDEBUG(1))
 					fprintf(ofp, 
 					    " EXCEPTION FRAME: %lx\n", 
@@ -2259,7 +2284,7 @@ do_bt_reference_check(struct bt_info *bt
 		    (sp && (bt->ref->hexval == sp->value))) 
                         bt->ref->cmdflags |= BT_REF_FOUND;
                 if (frmp->flag & EX_FRAME) {
-			type = eframe_type((struct pt_regs *)frmp->asp);
+			type = eframe_type(frmp->asp);
 			x86_dump_eframe_common(bt, (ulong *)frmp->asp, 
 				(type == KERNEL_EFRAME));
 		}

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]