On Mon, 2008-11-17 at 15:30 -0500, Dave Anderson wrote: > ----- "Joe Porter" <joe.porter@xxxxxxxx> wrote: > > > Hello crash, > > > > The user_regs_struct was redefined in > > linux-2.6.24-git8/include/asm-x86/user_32.h. > > > > This results in the following error when opening 32 bit kdump > > crashfiles: > > ------------------------------------------------------------------------- > > please wait... (determining panic task) > > crash: invalid structure member offset: user_regs_struct_ebp > > FILE: netdump.c LINE: 687 FUNCTION: get_netdump_panic_task() > > > > [/sbin/crash] error trace: 80e09f4 => 8154159 => 814fc3f => 813ec75 > > > > 813ec75: OFFSET_verify+126 > > 814fc3f: get_netdump_panic_task+1196 > > 8154159: get_kdump_panic_task+11 > > 80e09f4: get_dumpfile_panic_task+153 > > -------------------------------------------------------------------- > > > > I've inserted a patch to crash-4.0-7.4/x86.c that fixes this for all > > linux-2.6.24-git8 > > and later kernels (2.6.25 -> 2.6.28-rc5). I've also inserted the > > kernel change that > > caused the breakage. > > > > The fix is bad because it breaks all kernels <= linux-2.6.24-git7. > > > > A better fix would be backward and forward compatible with all > > kernels, but since there > > was a lot of hardwired code revolving around the old 32 bit > > user_regs_struct I thought I > > would just submit this patch to expose the problem and maybe look for > > a better fix in the > > next crash update. > > Right -- it wouldn't be a "better fix", but rather the "only fix" > that's going to be acceptable. ... of course > > Does the new kernel that has the name changes end up using the > initial attempts to set the size, esp and ebp offsets? Or does > it always end up using the "if (!VALID_STRUCT())" section? It's > only going to use one or the other, depending upon whether the > user_regs_struct gets exported-to/included-in the debuginfo data. I did a binary search on all the kernels between 2.6.23 and 2.6.28-rc?. It was pretty clear that we were always going to get into this after 2.6.24-git8. After I figured out the names changed, I didn't take it any further than what you see in the patch. When I dropped in the new x86_user_regs_struct, the code wouldn't build without making the two little changes to the MEMBER_OFFSET_INIT calls. There were a lot of related changes to the elf core code and also in the 64 bit user_regs_struct. I assume the 64 bit kdump crashfiles still work either because the crash initialization code differs or because the 32 bit elf core stuff changed to cause the !VALID_STRUCT() call to come back true. I'm really not very familiar with crash and kdump. I'll attach a git7-git8 diff of some of the related code from asm-x86. I guess any final fix would need to take into account guarding against any other future changes like this ... if one could reasonably do so. I won't have much time to delve into it any more for at least a few more weeks. joe BTW I'm using kexec-tools-2.0.0.tar.gz and the build env is RHEL5.2. > > Dave > > > > > thx, joe > > > > --- crash-4.0-7.4.orig/x86.c 2008-10-14 09:35:40.000000000 -0400 > > +++ crash-4.0-7.4/x86.c 2008-11-17 13:37:40.000000000 -0500 > > @@ -1774,29 +1774,39 @@ > > machdep->flags |= OMIT_FRAME_PTR; > > STRUCT_SIZE_INIT(user_regs_struct, "user_regs_struct"); > > MEMBER_OFFSET_INIT(user_regs_struct_ebp, > > - "user_regs_struct", "ebp"); > > + "user_regs_struct", "bp"); > > MEMBER_OFFSET_INIT(user_regs_struct_esp, > > - "user_regs_struct", "esp"); > > + "user_regs_struct", "sp"); > > if (!VALID_STRUCT(user_regs_struct)) { > > /* Use this hardwired version -- sometimes the > > * debuginfo doesn't pick this up even though > > * it exists in the kernel; it shouldn't change. > > */ > > struct x86_user_regs_struct { > > - long ebx, ecx, edx, esi, edi, ebp, eax; > > - unsigned short ds, __ds, es, __es; > > - unsigned short fs, __fs, gs, __gs; > > - long orig_eax, eip; > > - unsigned short cs, __cs; > > - long eflags, esp; > > - unsigned short ss, __ss; > > + unsigned long bx; > > + unsigned long cx; > > + unsigned long dx; > > + unsigned long si; > > + unsigned long di; > > + unsigned long bp; > > + unsigned long ax; > > + unsigned long ds; > > + unsigned long es; > > + unsigned long fs; > > + unsigned long gs; > > + unsigned long orig_ax; > > + unsigned long ip; > > + unsigned long cs; > > + unsigned long flags; > > + unsigned long sp; > > + unsigned long ss; > > }; > > ASSIGN_SIZE(user_regs_struct) = > > sizeof(struct x86_user_regs_struct); > > ASSIGN_OFFSET(user_regs_struct_ebp) = > > - offsetof(struct x86_user_regs_struct, ebp); > > + offsetof(struct x86_user_regs_struct, bp); > > ASSIGN_OFFSET(user_regs_struct_esp) = > > - offsetof(struct x86_user_regs_struct, esp); > > + offsetof(struct x86_user_regs_struct, sp); > > } > > MEMBER_OFFSET_INIT(thread_struct_cr3, "thread_struct", "cr3"); > > STRUCT_SIZE_INIT(cpuinfo_x86, "cpuinfo_x86"); > > > > -------------------------------------------------------------------------------- > > > > --- linux-2.6.24-git7/include/asm-x86/user_32.h 2008-01-24 > > 17:58:37.000000000 -0500 > > +++ linux-2.6.24-git8/include/asm-x86/user_32.h 2008-11-11 > > 18:56:13.000000000 -0500 > > @@ -75,13 +75,23 @@ > > * doesn't use the extra segment registers) > > */ > > struct user_regs_struct { > > - long ebx, ecx, edx, esi, edi, ebp, eax; > > - unsigned short ds, __ds, es, __es; > > - unsigned short fs, __fs, gs, __gs; > > - long orig_eax, eip; > > - unsigned short cs, __cs; > > - long eflags, esp; > > - unsigned short ss, __ss; > > + unsigned long bx; > > + unsigned long cx; > > + unsigned long dx; > > + unsigned long si; > > + unsigned long di; > > + unsigned long bp; > > + unsigned long ax; > > + unsigned long ds; > > + unsigned long es; > > + unsigned long fs; > > + unsigned long gs; > > + unsigned long orig_ax; > > + unsigned long ip; > > + unsigned long cs; > > + unsigned long flags; > > + unsigned long sp; > > + unsigned long ss; > > }; > > > > /* When the kernel dumps core, it starts by dumping the user struct > > - > > > > -- > > Crash-utility mailing list > > Crash-utility@xxxxxxxxxx > > https://www.redhat.com/mailman/listinfo/crash-utility
--- linux-2.6.24-git7/include/asm-x86/compat.h 2008-01-24 17:58:37.000000000 -0500 +++ linux-2.6.24-git8/include/asm-x86/compat.h 2008-11-11 18:56:13.000000000 -0500 @@ -207,7 +207,7 @@ static __inline__ void __user *compat_alloc_user_space(long len) { struct pt_regs *regs = task_pt_regs(current); - return (void __user *)regs->rsp - len; + return (void __user *)regs->sp - len; } static inline int is_compat_task(void) --- linux-2.6.24-git7/include/asm-x86/elf.h 2008-01-24 17:58:37.000000000 -0500 +++ linux-2.6.24-git8/include/asm-x86/elf.h 2008-11-11 18:56:13.000000000 -0500 @@ -73,18 +73,23 @@ #endif #ifdef __KERNEL__ +#include <asm/vdso.h> -#ifdef CONFIG_X86_32 -#include <asm/processor.h> -#include <asm/system.h> /* for savesegment */ -#include <asm/desc.h> +extern unsigned int vdso_enabled; /* * This is used to ensure we don't load something for the wrong architecture. */ -#define elf_check_arch(x) \ +#define elf_check_arch_ia32(x) \ (((x)->e_machine == EM_386) || ((x)->e_machine == EM_486)) +#ifdef CONFIG_X86_32 +#include <asm/processor.h> +#include <asm/system.h> /* for savesegment */ +#include <asm/desc.h> + +#define elf_check_arch(x) elf_check_arch_ia32(x) + /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program starts %edx contains a pointer to a function which might be registered using `atexit'. This provides a mean for the dynamic linker to call DT_FINI functions for @@ -96,36 +101,38 @@ just to make things more deterministic. */ #define ELF_PLAT_INIT(_r, load_addr) do { \ - _r->ebx = 0; _r->ecx = 0; _r->edx = 0; \ - _r->esi = 0; _r->edi = 0; _r->ebp = 0; \ - _r->eax = 0; \ + _r->bx = 0; _r->cx = 0; _r->dx = 0; \ + _r->si = 0; _r->di = 0; _r->bp = 0; \ + _r->ax = 0; \ } while (0) -/* regs is struct pt_regs, pr_reg is elf_gregset_t (which is - now struct_user_regs, they are different) */ +/* + * regs is struct pt_regs, pr_reg is elf_gregset_t (which is + * now struct_user_regs, they are different) + */ -#define ELF_CORE_COPY_REGS(pr_reg, regs) \ - pr_reg[0] = regs->ebx; \ - pr_reg[1] = regs->ecx; \ - pr_reg[2] = regs->edx; \ - pr_reg[3] = regs->esi; \ - pr_reg[4] = regs->edi; \ - pr_reg[5] = regs->ebp; \ - pr_reg[6] = regs->eax; \ - pr_reg[7] = regs->xds & 0xffff; \ - pr_reg[8] = regs->xes & 0xffff; \ - pr_reg[9] = regs->xfs & 0xffff; \ - savesegment(gs,pr_reg[10]); \ - pr_reg[11] = regs->orig_eax; \ - pr_reg[12] = regs->eip; \ - pr_reg[13] = regs->xcs & 0xffff; \ - pr_reg[14] = regs->eflags; \ - pr_reg[15] = regs->esp; \ - pr_reg[16] = regs->xss & 0xffff; +#define ELF_CORE_COPY_REGS(pr_reg, regs) do { \ + pr_reg[0] = regs->bx; \ + pr_reg[1] = regs->cx; \ + pr_reg[2] = regs->dx; \ + pr_reg[3] = regs->si; \ + pr_reg[4] = regs->di; \ + pr_reg[5] = regs->bp; \ + pr_reg[6] = regs->ax; \ + pr_reg[7] = regs->ds & 0xffff; \ + pr_reg[8] = regs->es & 0xffff; \ + pr_reg[9] = regs->fs & 0xffff; \ + savesegment(gs, pr_reg[10]); \ + pr_reg[11] = regs->orig_ax; \ + pr_reg[12] = regs->ip; \ + pr_reg[13] = regs->cs & 0xffff; \ + pr_reg[14] = regs->flags; \ + pr_reg[15] = regs->sp; \ + pr_reg[16] = regs->ss & 0xffff; \ +} while (0); #define ELF_PLATFORM (utsname()->machine) #define set_personality_64bit() do { } while (0) -extern unsigned int vdso_enabled; #else /* CONFIG_X86_32 */ @@ -137,28 +144,57 @@ #define elf_check_arch(x) \ ((x)->e_machine == EM_X86_64) +#define compat_elf_check_arch(x) elf_check_arch_ia32(x) + +static inline void start_ia32_thread(struct pt_regs *regs, u32 ip, u32 sp) +{ + asm volatile("movl %0,%%fs" :: "r" (0)); + asm volatile("movl %0,%%es; movl %0,%%ds" : : "r" (__USER32_DS)); + load_gs_index(0); + regs->ip = ip; + regs->sp = sp; + regs->flags = X86_EFLAGS_IF; + regs->cs = __USER32_CS; + regs->ss = __USER32_DS; +} + +static inline void elf_common_init(struct thread_struct *t, + struct pt_regs *regs, const u16 ds) +{ + regs->ax = regs->bx = regs->cx = regs->dx = 0; + regs->si = regs->di = regs->bp = 0; + regs->r8 = regs->r9 = regs->r10 = regs->r11 = 0; + regs->r12 = regs->r13 = regs->r14 = regs->r15 = 0; + t->fs = t->gs = 0; + t->fsindex = t->gsindex = 0; + t->ds = t->es = ds; +} + #define ELF_PLAT_INIT(_r, load_addr) do { \ - struct task_struct *cur = current; \ - (_r)->rbx = 0; (_r)->rcx = 0; (_r)->rdx = 0; \ - (_r)->rsi = 0; (_r)->rdi = 0; (_r)->rbp = 0; \ - (_r)->rax = 0; \ - (_r)->r8 = 0; \ - (_r)->r9 = 0; \ - (_r)->r10 = 0; \ - (_r)->r11 = 0; \ - (_r)->r12 = 0; \ - (_r)->r13 = 0; \ - (_r)->r14 = 0; \ - (_r)->r15 = 0; \ - cur->thread.fs = 0; cur->thread.gs = 0; \ - cur->thread.fsindex = 0; cur->thread.gsindex = 0; \ - cur->thread.ds = 0; cur->thread.es = 0; \ + elf_common_init(¤t->thread, _r, 0); \ clear_thread_flag(TIF_IA32); \ } while (0) -/* regs is struct pt_regs, pr_reg is elf_gregset_t (which is - now struct_user_regs, they are different). Assumes current is the process - getting dumped. */ +#define COMPAT_ELF_PLAT_INIT(regs, load_addr) \ + elf_common_init(¤t->thread, regs, __USER_DS) +#define compat_start_thread(regs, ip, sp) do { \ + start_ia32_thread(regs, ip, sp); \ + set_fs(USER_DS); \ + } while (0) +#define COMPAT_SET_PERSONALITY(ex, ibcs2) do { \ + if (test_thread_flag(TIF_IA32)) \ + clear_thread_flag(TIF_ABI_PENDING); \ + else \ + set_thread_flag(TIF_ABI_PENDING); \ + current->personality |= force_personality32; \ + } while (0) +#define COMPAT_ELF_PLATFORM ("i686") + +/* + * regs is struct pt_regs, pr_reg is elf_gregset_t (which is + * now struct_user_regs, they are different). Assumes current is the process + * getting dumped. + */ #define ELF_CORE_COPY_REGS(pr_reg, regs) do { \ unsigned v; \ @@ -166,22 +202,22 @@ (pr_reg)[1] = (regs)->r14; \ (pr_reg)[2] = (regs)->r13; \ (pr_reg)[3] = (regs)->r12; \ - (pr_reg)[4] = (regs)->rbp; \ - (pr_reg)[5] = (regs)->rbx; \ + (pr_reg)[4] = (regs)->bp; \ + (pr_reg)[5] = (regs)->bx; \ (pr_reg)[6] = (regs)->r11; \ (pr_reg)[7] = (regs)->r10; \ (pr_reg)[8] = (regs)->r9; \ (pr_reg)[9] = (regs)->r8; \ - (pr_reg)[10] = (regs)->rax; \ - (pr_reg)[11] = (regs)->rcx; \ - (pr_reg)[12] = (regs)->rdx; \ - (pr_reg)[13] = (regs)->rsi; \ - (pr_reg)[14] = (regs)->rdi; \ - (pr_reg)[15] = (regs)->orig_rax; \ - (pr_reg)[16] = (regs)->rip; \ + (pr_reg)[10] = (regs)->ax; \ + (pr_reg)[11] = (regs)->cx; \ + (pr_reg)[12] = (regs)->dx; \ + (pr_reg)[13] = (regs)->si; \ + (pr_reg)[14] = (regs)->di; \ + (pr_reg)[15] = (regs)->orig_ax; \ + (pr_reg)[16] = (regs)->ip; \ (pr_reg)[17] = (regs)->cs; \ - (pr_reg)[18] = (regs)->eflags; \ - (pr_reg)[19] = (regs)->rsp; \ + (pr_reg)[18] = (regs)->flags; \ + (pr_reg)[19] = (regs)->sp; \ (pr_reg)[20] = (regs)->ss; \ (pr_reg)[21] = current->thread.fs; \ (pr_reg)[22] = current->thread.gs; \ @@ -189,15 +225,17 @@ asm("movl %%es,%0" : "=r" (v)); (pr_reg)[24] = v; \ asm("movl %%fs,%0" : "=r" (v)); (pr_reg)[25] = v; \ asm("movl %%gs,%0" : "=r" (v)); (pr_reg)[26] = v; \ -} while(0); +} while (0); /* I'm not sure if we can use '-' here */ #define ELF_PLATFORM ("x86_64") extern void set_personality_64bit(void); -extern int vdso_enabled; +extern unsigned int sysctl_vsyscall32; +extern int force_personality32; #endif /* !CONFIG_X86_32 */ +#define CORE_DUMP_USE_REGSET #define USE_ELF_CORE_DUMP #define ELF_EXEC_PAGESIZE 4096 @@ -232,43 +270,24 @@ struct task_struct; -extern int dump_task_regs (struct task_struct *, elf_gregset_t *); -extern int dump_task_fpu (struct task_struct *, elf_fpregset_t *); - -#define ELF_CORE_COPY_TASK_REGS(tsk, elf_regs) dump_task_regs(tsk, elf_regs) -#define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs) dump_task_fpu(tsk, elf_fpregs) +#define ARCH_DLINFO_IA32(vdso_enabled) \ +do if (vdso_enabled) { \ + NEW_AUX_ENT(AT_SYSINFO, VDSO_ENTRY); \ + NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_CURRENT_BASE); \ +} while (0) #ifdef CONFIG_X86_32 -extern int dump_task_extended_fpu (struct task_struct *, - struct user_fxsr_struct *); -#define ELF_CORE_COPY_XFPREGS(tsk, elf_xfpregs) \ - dump_task_extended_fpu(tsk, elf_xfpregs) -#define ELF_CORE_XFPREG_TYPE NT_PRXFPREG #define VDSO_HIGH_BASE (__fix_to_virt(FIX_VDSO)) -#define VDSO_CURRENT_BASE ((unsigned long)current->mm->context.vdso) -#define VDSO_PRELINK 0 - -#define VDSO_SYM(x) \ - (VDSO_CURRENT_BASE + (unsigned long)(x) - VDSO_PRELINK) - -#define VDSO_HIGH_EHDR ((const struct elfhdr *) VDSO_HIGH_BASE) -#define VDSO_EHDR ((const struct elfhdr *) VDSO_CURRENT_BASE) -extern void __kernel_vsyscall; - -#define VDSO_ENTRY VDSO_SYM(&__kernel_vsyscall) +#define ARCH_DLINFO ARCH_DLINFO_IA32(vdso_enabled) /* update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT entries changes */ -#define ARCH_DLINFO \ -do if (vdso_enabled) { \ - NEW_AUX_ENT(AT_SYSINFO, VDSO_ENTRY); \ - NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_CURRENT_BASE); \ -} while (0) - #else /* CONFIG_X86_32 */ +#define VDSO_HIGH_BASE 0xffffe000U /* CONFIG_COMPAT_VDSO address */ + /* 1GB for 64bit, 8MB for 32bit */ #define STACK_RND_MASK (test_thread_flag(TIF_IA32) ? 0x7ff : 0x3fffff) @@ -277,14 +296,31 @@ NEW_AUX_ENT(AT_SYSINFO_EHDR,(unsigned long)current->mm->context.vdso);\ } while (0) +#define AT_SYSINFO 32 + +#define COMPAT_ARCH_DLINFO ARCH_DLINFO_IA32(sysctl_vsyscall32) + +#define COMPAT_ELF_ET_DYN_BASE (TASK_UNMAPPED_BASE + 0x1000000) + #endif /* !CONFIG_X86_32 */ +#define VDSO_CURRENT_BASE ((unsigned long)current->mm->context.vdso) + +#define VDSO_ENTRY \ + ((unsigned long) VDSO32_SYMBOL(VDSO_CURRENT_BASE, vsyscall)) + struct linux_binprm; #define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1 extern int arch_setup_additional_pages(struct linux_binprm *bprm, int executable_stack); +extern int syscall32_setup_pages(struct linux_binprm *, int exstack); +#define compat_arch_setup_additional_pages syscall32_setup_pages + +extern unsigned long arch_randomize_brk(struct mm_struct *mm); +#define arch_randomize_brk arch_randomize_brk + #endif /* __KERNEL__ */ #endif --- linux-2.6.24-git7/include/asm-x86/user_32.h 2008-01-24 17:58:37.000000000 -0500 +++ linux-2.6.24-git8/include/asm-x86/user_32.h 2008-11-11 18:56:13.000000000 -0500 @@ -75,13 +75,23 @@ * doesn't use the extra segment registers) */ struct user_regs_struct { - long ebx, ecx, edx, esi, edi, ebp, eax; - unsigned short ds, __ds, es, __es; - unsigned short fs, __fs, gs, __gs; - long orig_eax, eip; - unsigned short cs, __cs; - long eflags, esp; - unsigned short ss, __ss; + unsigned long bx; + unsigned long cx; + unsigned long dx; + unsigned long si; + unsigned long di; + unsigned long bp; + unsigned long ax; + unsigned long ds; + unsigned long es; + unsigned long fs; + unsigned long gs; + unsigned long orig_ax; + unsigned long ip; + unsigned long cs; + unsigned long flags; + unsigned long sp; + unsigned long ss; }; /* When the kernel dumps core, it starts by dumping the user struct - --- linux-2.6.24-git7/include/asm-x86/user_64.h 2008-01-24 17:58:37.000000000 -0500 +++ linux-2.6.24-git8/include/asm-x86/user_64.h 2008-11-11 18:56:13.000000000 -0500 @@ -40,13 +40,13 @@ * and both the standard and SIMD floating point data can be accessed via * the new ptrace requests. In either case, changes to the FPU environment * will be reflected in the task's state as expected. - * + * * x86-64 support by Andi Kleen. */ /* This matches the 64bit FXSAVE format as defined by AMD. It is the same as the 32bit format defined by Intel, except that the selector:offset pairs for - data and eip are replaced with flat 64bit pointers. */ + data and eip are replaced with flat 64bit pointers. */ struct user_i387_struct { unsigned short cwd; unsigned short swd; @@ -65,13 +65,34 @@ * Segment register layout in coredumps. */ struct user_regs_struct { - unsigned long r15,r14,r13,r12,rbp,rbx,r11,r10; - unsigned long r9,r8,rax,rcx,rdx,rsi,rdi,orig_rax; - unsigned long rip,cs,eflags; - unsigned long rsp,ss; - unsigned long fs_base, gs_base; - unsigned long ds,es,fs,gs; -}; + unsigned long r15; + unsigned long r14; + unsigned long r13; + unsigned long r12; + unsigned long bp; + unsigned long bx; + unsigned long r11; + unsigned long r10; + unsigned long r9; + unsigned long r8; + unsigned long ax; + unsigned long cx; + unsigned long dx; + unsigned long si; + unsigned long di; + unsigned long orig_ax; + unsigned long ip; + unsigned long cs; + unsigned long flags; + unsigned long sp; + unsigned long ss; + unsigned long fs_base; + unsigned long gs_base; + unsigned long ds; + unsigned long es; + unsigned long fs; + unsigned long gs; +}; /* When the kernel dumps core, it starts by dumping the user struct - this will be used by gdb to figure out where the data and stack segments @@ -94,7 +115,7 @@ This is actually the bottom of the stack, the top of the stack is always found in the esp register. */ - long int signal; /* Signal that caused the core dump. */ + long int signal; /* Signal that caused the core dump. */ int reserved; /* No longer used */ int pad1; struct user_pt_regs * u_ar0; /* Used by gdb to help find the values for */
-- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility