[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