From: Josh Stone Date: Sat, 26 Apr 2014 00:12:18 +0000 (-0700) Subject: runtime: Fix synthesized regs on ix86 X-Git-Tag: release-2.5~26 X-Git-Url: https://sourceware.org/git/?a=commitdiff_plain;h=6ddf07acac2a268788bfcdda219e42d74703a3cc;p=systemtap.git runtime: Fix synthesized regs on ix86 The ix86 register names and offsets in the inline asm of arch_unw_init_frame_info are now fixed, including stapconf to deal with fs/xfs/gs changes over time. x86_64 is updated to match the same style of access. --- diff --git a/buildrun.cxx b/buildrun.cxx index 22a7fcaac..a2f2197e4 100644 --- a/buildrun.cxx +++ b/buildrun.cxx @@ -329,6 +329,8 @@ compile_pass (systemtap_session& s) output_dual_exportconf(s, o, "alloc_vm_area", "free_vm_area", "STAPCONF_VM_AREA"); output_autoconf(s, o, "autoconf-procfs-owner.c", "STAPCONF_PROCFS_OWNER", NULL); output_autoconf(s, o, "autoconf-alloc-percpu-align.c", "STAPCONF_ALLOC_PERCPU_ALIGN", NULL); + output_autoconf(s, o, "autoconf-x86-fs.c", "STAPCONF_X86_FS", NULL); + output_autoconf(s, o, "autoconf-x86-xfs.c", "STAPCONF_X86_XFS", NULL); output_autoconf(s, o, "autoconf-x86-gs.c", "STAPCONF_X86_GS", NULL); output_autoconf(s, o, "autoconf-grsecurity.c", "STAPCONF_GRSECURITY", NULL); output_autoconf(s, o, "autoconf-trace-printk.c", "STAPCONF_TRACE_PRINTK", NULL); diff --git a/runtime/linux/autoconf-x86-fs.c b/runtime/linux/autoconf-x86-fs.c new file mode 100644 index 000000000..2d58760d2 --- /dev/null +++ b/runtime/linux/autoconf-x86-fs.c @@ -0,0 +1,5 @@ +#include + +#if defined (__i386__) +struct pt_regs regs = {.fs = 0x0}; +#endif diff --git a/runtime/linux/autoconf-x86-xfs.c b/runtime/linux/autoconf-x86-xfs.c new file mode 100644 index 000000000..0b83ecec0 --- /dev/null +++ b/runtime/linux/autoconf-x86-xfs.c @@ -0,0 +1,5 @@ +#include + +#if defined (__i386__) +struct pt_regs regs = {.xfs = 0x0}; +#endif diff --git a/runtime/unwind/i386.h b/runtime/unwind/i386.h index 4107d0e11..8d2a8e1a8 100644 --- a/runtime/unwind/i386.h +++ b/runtime/unwind/i386.h @@ -68,34 +68,54 @@ #define user_mode_vm(regs) user_mode(regs) #endif - static inline void arch_unw_init_frame_info(struct unwind_frame_info *info, /*const*/ struct pt_regs *regs, int sanitize) { if (!regs) { - asm("lea (%%eip), %1 \n\t" - "mov %%ebx, 0%0 \n\t" - "mov %%ecx, 8%0 \n\t" - "mov %%edx, 16%0 \n\t" - "mov %%esi, 24%0 \n\t" - "mov %%edi, 32%0 \n\t" - "mov %%ebp, 40%0 \n\t" - "mov %%eax, 48%0 \n\t" - "mov %%xds, 56%0 \n\t" - "mov %%xes, 60%0 \n\t" - "mov %%xfs, 64%0 \n\t" - "mov %%xgs, 68%0 \n\t" - "mov %%orig_eax, 72%0 \n\t" - "mov %%xcs, 88%0 \n\t" - "mov %%eflags, 92%0 \n\t" - "mov %%esp, 100%0 \n\t" - "mov %%xss, 108%0 \n\t" + /* NB: This uses an "=m" output constraint to indicate we're + * writing all of info->regs, but then uses an "r" input + * pointer for the actual writes. This is to be sure we have + * something we can offset properly. + * NB2: kernel pt_regs haven't always included fs and gs, which + * means the offsets of the fields after have changed over + * time. We'll reconvene at orig_eax to fill the end. */ + asm("movl $1f, %1; 1: \n\t" + "mov %%ebx, 0(%2) \n\t" + "mov %%ecx, 4(%2) \n\t" + "mov %%edx, 8(%2) \n\t" + "mov %%esi, 12(%2) \n\t" + "mov %%edi, 16(%2) \n\t" + "mov %%ebp, 20(%2) \n\t" + "mov %%eax, 24(%2) \n\t" + "mov %%ds, 28(%2) \n\t" + "mov %%es, 32(%2) \n\t" +#if defined(STAPCONF_X86_XFS) || defined (STAPCONF_X86_FS) + "mov %%fs, 36(%2) \n\t" +#endif +#ifdef STAPCONF_X86_GS + "mov %%gs, 40(%2) \n\t" +#endif + /* "mov %%orig_eax, 0(%3) \n\t" */ + /* "mov %%eip, 4(%3) \n\t" */ + "mov %%cs, 8(%3) \n\t" + /* "mov %%eflags, 12(%3) \n\t" */ + "mov %%esp, 16(%3) \n\t" + "mov %%ss, 20(%3) \n\t" + : "=m" (info->regs), #ifdef STAPCONF_X86_UNIREGS - : "=m"(info->regs), "=r" (info->regs.ip)); + "=m" (info->regs.ip) #else - : "=m"(info->regs), "=r" (info->regs.eip)); + "=m" (info->regs.eip) #endif /* STAPCONF_X86_UNIREGS */ + : "r"(&info->regs), +#ifdef STAPCONF_X86_UNIREGS + "r" (&info->regs.orig_ax) +#else + "r" (&info->regs.orig_eax) +#endif /* STAPCONF_X86_UNIREGS */ + ); + return; } diff --git a/runtime/unwind/x86_64.h b/runtime/unwind/x86_64.h index cad18e0f6..c5a561880 100644 --- a/runtime/unwind/x86_64.h +++ b/runtime/unwind/x86_64.h @@ -106,29 +106,40 @@ static inline void arch_unw_init_frame_info(struct unwind_frame_info *info, int sanitize) { if(regs == NULL){ - asm("lea (%%rip), %1 \n\t" - "mov %%r15, 0%0 \n\t" - "mov %%r14, 8%0 \n\t" - "mov %%r13, 16%0 \n\t" - "mov %%r12, 24%0 \n\t" - "mov %%rbp, 32%0 \n\t" - "mov %%rbx, 40%0 \n\t" - "mov %%r11, 48%0 \n\t" - "mov %%r10, 56%0 \n\t" - "mov %%r9, 64%0 \n\t" - "mov %%r8, 72%0 \n\t" - "mov %%rax, 80%0 \n\t" - "mov %%rcx, 88%0 \n\t" - "mov %%rdx, 96%0 \n\t" - "mov %%rsi, 104%0 \n\t" - "mov %%rdi, 112%0 \n\t" - "mov %%cs, 136%0 \n\t" - "mov %%rsp, 152%0 \n\t" + /* NB: This uses an "=m" output constraint to indicate we're + * writing all of info->regs, but then uses an "r" input + * pointer for the actual writes. This is to be sure we have + * something we can offset properly. */ + asm("lea (%%rip), %1 \n\t" + "mov %%r15, 0(%2) \n\t" + "mov %%r14, 8(%2) \n\t" + "mov %%r13, 16(%2) \n\t" + "mov %%r12, 24(%2) \n\t" + "mov %%rbp, 32(%2) \n\t" + "mov %%rbx, 40(%2) \n\t" + "mov %%r11, 48(%2) \n\t" + "mov %%r10, 56(%2) \n\t" + "mov %%r9, 64(%2) \n\t" + "mov %%r8, 72(%2) \n\t" + "mov %%rax, 80(%2) \n\t" + "mov %%rcx, 88(%2) \n\t" + "mov %%rdx, 96(%2) \n\t" + "mov %%rsi, 104(%2) \n\t" + "mov %%rdi, 112(%2) \n\t" + /* "mov %%orig_rax, 120(%2) \n\t" */ + /* "mov %%rip, 128(%2) \n\t" */ + "mov %%cs, 136(%2) \n\t" + /* "mov %%eflags, 144(%2) \n\t" */ + "mov %%rsp, 152(%2) \n\t" + "mov %%ss, 160(%2) \n\t" + : "=m" (info->regs), #ifdef STAPCONF_X86_UNIREGS - : "=m"(info->regs), "=r" (info->regs.ip)); + "=r" (info->regs.ip) #else - : "=m"(info->regs), "=r" (info->regs.rip)); + "=r" (info->regs.rip) #endif /* STAPCONF_X86_UNIREGS */ + : "r" (&info->regs) + ); return; }