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

Dave Anderson anderson at redhat.com
Wed Dec 19 14:53:12 UTC 2007


Alan Tyson wrote:
> 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.

Yeah, that thread was more a discussion on how the pt_regs
actually get saved on the kernel stack in entry.S.

> 
> 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.

Nice catch...

> 
> 
> 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).  

Right -- that file was originally adapted from the LKCD lcrash
sources, and I was simply trying to give credit where credit
was due...

> 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).

Yeah, I'll probably do that, and the changes you made in the
non-REDHAT section of lkcd_x86_trace.c:print_eframe() are
irrelevant since they don't get compiled.  But it looks
good -- I appreciate the leg-work you've done here.

Thanks,
   Dave

> 
> 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));
>  		}
> 
> 
> ------------------------------------------------------------------------
> 
> --
> Crash-utility mailing list
> Crash-utility at redhat.com
> https://www.redhat.com/mailman/listinfo/crash-utility





More information about the Crash-utility mailing list