diff --git a/configure.ac b/configure.ac index c7221ca3..a688a25a 100644 --- a/configure.ac +++ b/configure.ac @@ -53,8 +53,8 @@ case "$host" in *-darwin*) default_enable_heap_checker=no;; esac -# Currently only backtrace works on s390x. -AC_COMPILE_IFELSE([AC_LANG_PROGRAM(, [return __s390x__])], +# Currently only backtrace works on s390. +AC_COMPILE_IFELSE([AC_LANG_PROGRAM(, [return __s390__])], [default_enable_libunwind=no default_enable_backtrace=yes], [default_enable_libunwind=yes diff --git a/m4/pc_from_ucontext.m4 b/m4/pc_from_ucontext.m4 index d743fa43..c9224bc6 100644 --- a/m4/pc_from_ucontext.m4 +++ b/m4/pc_from_ucontext.m4 @@ -27,7 +27,7 @@ AC_DEFUN([AC_PC_FROM_UCONTEXT], pc_fields="$pc_fields uc_mcontext.sc_ip" # Linux (ia64) pc_fields="$pc_fields uc_mcontext.pc" # Linux (mips) pc_fields="$pc_fields uc_mcontext.uc_regs->gregs[[PT_NIP]]" # Linux (ppc) - pc_fields="$pc_fields uc_mcontext.psw.addr" # Linux (s390x) + pc_fields="$pc_fields uc_mcontext.psw.addr" # Linux (s390) pc_fields="$pc_fields uc_mcontext.gregs[[R15]]" # Linux (arm old [untested]) pc_fields="$pc_fields uc_mcontext.arm_pc" # Linux (arm arch 5) pc_fields="$pc_fields uc_mcontext.gp_regs[[PT_NIP]]" # Suse SLES 11 (ppc64) diff --git a/src/base/basictypes.h b/src/base/basictypes.h index b6287091..72c27b49 100644 --- a/src/base/basictypes.h +++ b/src/base/basictypes.h @@ -363,7 +363,7 @@ class AssignAttributeStartEnd { # elif (defined(__aarch64__)) # define CACHELINE_ALIGNED __attribute__((aligned(64))) // implementation specific, Cortex-A53 and 57 should have 64 bytes -# elif (defined(__s390x__)) +# elif (defined(__s390__)) # define CACHELINE_ALIGNED __attribute__((aligned(256))) # else # error Could not determine cache line length - unknown architecture diff --git a/src/base/linux_syscall_support.h b/src/base/linux_syscall_support.h index 5d578cd7..235f2ad6 100644 --- a/src/base/linux_syscall_support.h +++ b/src/base/linux_syscall_support.h @@ -130,12 +130,13 @@ #ifndef SYS_LINUX_SYSCALL_SUPPORT_H #define SYS_LINUX_SYSCALL_SUPPORT_H -/* We currently only support x86-32, x86-64, ARM, MIPS, PPC/PPC64, Aarch64 and s390x on Linux. +/* We currently only support x86-32, x86-64, ARM, MIPS, PPC/PPC64, Aarch64, s390 and s390x + * on Linux. * Porting to other related platforms should not be difficult. */ #if (defined(__i386__) || defined(__x86_64__) || defined(__arm__) || \ defined(__mips__) || defined(__PPC__) || \ - defined(__aarch64__) || defined(__s390x__)) \ + defined(__aarch64__) || defined(__s390__)) \ && (defined(__linux)) #ifndef SYS_CPLUSPLUS @@ -247,7 +248,8 @@ struct kernel_rusage { long ru_nivcsw; }; -#if defined(__i386__) || defined(__arm__) || defined(__PPC__) +#if defined(__i386__) || defined(__arm__) \ + || defined(__PPC__) || (defined(__s390__) && !defined(__s390x__)) /* include/asm-{arm,i386,mips,ppc}/signal.h */ struct kernel_old_sigaction { @@ -261,8 +263,8 @@ struct kernel_old_sigaction { } __attribute__((packed,aligned(4))); #elif (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) #define kernel_old_sigaction kernel_sigaction -#elif defined(__aarch64__) || defined(__s390x__) - // No kernel_old_sigaction defined for arm64 or s390x. +#elif defined(__aarch64__) + // No kernel_old_sigaction defined for arm64. #endif /* Some kernel functions (e.g. sigaction() in 2.6.23) require that the @@ -306,7 +308,7 @@ struct kernel_sigaction { #endif }; -/* include/asm-{arm,i386,mips,ppc}/stat.h */ +/* include/asm-{arm,i386,mips,ppc,s390}/stat.h */ #ifdef __mips__ #if _MIPS_SIM == _MIPS_SIM_ABI64 struct kernel_stat { @@ -514,6 +516,29 @@ struct kernel_stat { long st_blocks; unsigned long __unused[3]; }; +#elif defined(__s390__) +struct kernel_stat { + unsigned short st_dev; + unsigned short __pad1; + unsigned long st_ino; + unsigned short st_mode; + unsigned short st_nlink; + unsigned short st_uid; + unsigned short st_gid; + unsigned short st_rdev; + unsigned short __pad2; + unsigned long st_size; + unsigned long st_blksize; + unsigned long st_blocks; + unsigned long st_atime_; + unsigned long st_atime_nsec_; + unsigned long st_mtime_; + unsigned long st_mtime_nsec_; + unsigned long st_ctime_; + unsigned long st_ctime_nsec_; + unsigned long __unused4; + unsigned long __unused5; +}; #endif @@ -728,7 +753,7 @@ struct kernel_stat { #define __NR_fstatat 79 #endif /* End of aarch64 defininitions */ -#elif defined(__s390x__) +#elif defined(__s390__) #ifndef __NR_quotactl #define __NR_quotactl 131 #endif @@ -753,27 +778,6 @@ struct kernel_stat { #ifndef __NR_pwrite64 #define __NR_pwrite64 181 #endif -#ifndef __NR_getrlimit -#define __NR_getrlimit 191 -#endif -#ifndef __NR_setresuid -#define __NR_setresuid 208 -#endif -#ifndef __NR_getresuid -#define __NR_getresuid 209 -#endif -#ifndef __NR_setresgid -#define __NR_setresgid 210 -#endif -#ifndef __NR_getresgid -#define __NR_getresgid 211 -#endif -#ifndef __NR_setfsuid -#define __NR_setfsuid 215 -#endif -#ifndef __NR_setfsgid -#define __NR_setfsgid 216 -#endif #ifndef __NR_getdents64 #define __NR_getdents64 220 #endif @@ -816,9 +820,6 @@ struct kernel_stat { #ifndef __NR_set_tid_address #define __NR_set_tid_address 252 #endif -#ifndef __NR_fadvise64 -#define __NR_fadvise64 253 -#endif #ifndef __NR_clock_gettime #define __NR_clock_gettime 260 #endif @@ -840,9 +841,6 @@ struct kernel_stat { #ifndef __NR_openat #define __NR_openat 288 #endif -#ifndef __NR_newfstatat -#define __NR_newfstatat 293 -#endif #ifndef __NR_unlinkat #define __NR_unlinkat 294 #endif @@ -855,7 +853,89 @@ struct kernel_stat { #ifndef __NR_fallocate #define __NR_fallocate 314 #endif -/* End of s390x definitions */ +/* Some syscalls are named/numbered differently between s390 and s390x. */ +#ifdef __s390x__ +# ifndef __NR_getrlimit +# define __NR_getrlimit 191 +# endif +# ifndef __NR_setresuid +# define __NR_setresuid 208 +# endif +# ifndef __NR_getresuid +# define __NR_getresuid 209 +# endif +# ifndef __NR_setresgid +# define __NR_setresgid 210 +# endif +# ifndef __NR_getresgid +# define __NR_getresgid 211 +# endif +# ifndef __NR_setfsuid +# define __NR_setfsuid 215 +# endif +# ifndef __NR_setfsgid +# define __NR_setfsgid 216 +# endif +# ifndef __NR_fadvise64 +# define __NR_fadvise64 253 +# endif +# ifndef __NR_newfstatat +# define __NR_newfstatat 293 +# endif +#else /* __s390x__ */ +# ifndef __NR_getrlimit +# define __NR_getrlimit 76 +# endif +# ifndef __NR_setfsuid +# define __NR_setfsuid 138 +# endif +# ifndef __NR_setfsgid +# define __NR_setfsgid 139 +# endif +# ifndef __NR_setresuid +# define __NR_setresuid 164 +# endif +# ifndef __NR_getresuid +# define __NR_getresuid 165 +# endif +# ifndef __NR_setresgid +# define __NR_setresgid 170 +# endif +# ifndef __NR_getresgid +# define __NR_getresgid 171 +# endif +# ifndef __NR_ugetrlimit +# define __NR_ugetrlimit 191 +# endif +# ifndef __NR_mmap2 +# define __NR_mmap2 192 +# endif +# ifndef __NR_setresuid32 +# define __NR_setresuid32 208 +# endif +# ifndef __NR_getresuid32 +# define __NR_getresuid32 209 +# endif +# ifndef __NR_setresgid32 +# define __NR_setresgid32 210 +# endif +# ifndef __NR_getresgid32 +# define __NR_getresgid32 211 +# endif +# ifndef __NR_setfsuid32 +# define __NR_setfsuid32 215 +# endif +# ifndef __NR_setfsgid32 +# define __NR_setfsgid32 216 +# endif +# ifndef __NR_fadvise64_64 +# define __NR_fadvise64_64 264 +# endif +# ifndef __NR_fstatat64 +# define __NR_fstatat64 293 +# endif +#endif /* __s390__ */ +/* End of s390/s390x definitions */ #endif @@ -919,7 +999,7 @@ struct kernel_stat { #undef LSS_RETURN #if (defined(__i386__) || defined(__x86_64__) || defined(__arm__) || \ - defined(__aarch64__) || defined(__s390x__)) + defined(__aarch64__) || defined(__s390__)) /* Failing system calls return a negative result in the range of * -1..-4095. These are "errno" values with the sign inverted. */ @@ -2236,19 +2316,20 @@ struct kernel_stat { } LSS_RETURN(int, __res); } - #elif defined(__s390x__) + #elif defined(__s390__) #undef LSS_REG #define LSS_REG(r, a) register unsigned long __r##r __asm__("r"#r) = (unsigned long) a #undef LSS_BODY #define LSS_BODY(type, name, args...) \ + register unsigned long __nr __asm__("r1") \ + = (unsigned long)(__NR_##name); \ register long __res_r2 __asm__("r2"); \ long __res; \ __asm__ __volatile__ \ - ("lgfi %%r1, %1\n\t" \ - "svc 0\n\t" \ - : "=&r"(__res_r2) \ - : "i"(__NR_##name), ## args \ - : "r1", "memory"); \ + ("svc 0\n\t" \ + : "=d"(__res_r2) \ + : "d"(__nr), ## args \ + : "memory"); \ __res = __res_r2; \ LSS_RETURN(type, __res) #undef _syscall0 @@ -2266,13 +2347,13 @@ struct kernel_stat { #define _syscall2(type, name, type1, arg1, type2, arg2) \ type LSS_NAME(name)(type1 arg1, type2 arg2) { \ LSS_REG(2, arg1); LSS_REG(3, arg2); \ - LSS_BODY(type, name, "0"(__r2), "r"(__r3)); \ + LSS_BODY(type, name, "0"(__r2), "d"(__r3)); \ } #undef _syscall3 #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \ LSS_REG(2, arg1); LSS_REG(3, arg2); LSS_REG(4, arg3); \ - LSS_BODY(type, name, "0"(__r2), "r"(__r3), "r"(__r4)); \ + LSS_BODY(type, name, "0"(__r2), "d"(__r3), "d"(__r4)); \ } #undef _syscall4 #define _syscall4(type, name, type1, arg1, type2, arg2, type3, arg3, \ @@ -2281,8 +2362,8 @@ struct kernel_stat { type4 arg4) { \ LSS_REG(2, arg1); LSS_REG(3, arg2); LSS_REG(4, arg3); \ LSS_REG(5, arg4); \ - LSS_BODY(type, name, "0"(__r2), "r"(__r3), "r"(__r4), \ - "r"(__r5)); \ + LSS_BODY(type, name, "0"(__r2), "d"(__r3), "d"(__r4), \ + "d"(__r5)); \ } #undef _syscall5 #define _syscall5(type, name, type1, arg1, type2, arg2, type3, arg3, \ @@ -2291,8 +2372,8 @@ struct kernel_stat { type4 arg4, type5 arg5) { \ LSS_REG(2, arg1); LSS_REG(3, arg2); LSS_REG(4, arg3); \ LSS_REG(5, arg4); LSS_REG(6, arg5); \ - LSS_BODY(type, name, "0"(__r2), "r"(__r3), "r"(__r4), \ - "r"(__r5), "r"(__r6)); \ + LSS_BODY(type, name, "0"(__r2), "d"(__r3), "d"(__r4), \ + "d"(__r5), "d"(__r6)); \ } #undef _syscall6 #define _syscall6(type, name, type1, arg1, type2, arg2, type3, arg3, \ @@ -2301,8 +2382,8 @@ struct kernel_stat { type4 arg4, type5 arg5, type6 arg6) { \ LSS_REG(2, arg1); LSS_REG(3, arg2); LSS_REG(4, arg3); \ LSS_REG(5, arg4); LSS_REG(6, arg5); LSS_REG(7, arg6); \ - LSS_BODY(type, name, "0"(__r2), "r"(__r3), "r"(__r4), \ - "r"(__r5), "r"(__r6), "r"(__r7)); \ + LSS_BODY(type, name, "0"(__r2), "d"(__r3), "d"(__r4), \ + "d"(__r5), "d"(__r6), "d"(__r7)); \ } LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, int flags, void *arg, int *parent_tidptr, @@ -2317,6 +2398,27 @@ struct kernel_stat { register void *__newtls __asm__ ("r6") = newtls; register int *__ctidptr __asm__ ("r5") = child_tidptr; __asm__ __volatile__ ( + #ifndef __s390x__ + /* arg already in r0 */ + "ltr %4, %4\n\t" /* check fn, which is already in r1 */ + "jz 1f\n\t" /* NULL function pointer, return -EINVAL */ + "ltr %5, %5\n\t" /* check child_stack, which is already in r2 */ + "jz 1f\n\t" /* NULL stack pointer, return -EINVAL */ + /* flags already in r3 */ + /* parent_tidptr already in r4 */ + /* child_tidptr already in r5 */ + /* newtls already in r6 */ + "svc %2\n\t" /* invoke clone syscall */ + "ltr %0,%%r2\n\t" /* load return code into __ret and test */ + "jnz 1f\n\t" /* return to parent if non-zero */ + /* start child thread */ + "lr %%r2, %7\n\t" /* set first parameter to void *arg */ + "ahi %%r15, -96\n\t" /* make room on the stack for the save area */ + "xc 0(4,%%r15), 0(%%r15)\n\t" + "basr %%r14, %4\n\t" /* jump to fn */ + "svc %3\n" /* invoke exit syscall */ + "1:\n" + #else /* arg already in r0 */ "ltgr %4, %4\n\t" /* check fn, which is already in r1 */ "jz 1f\n\t" /* NULL function pointer, return -EINVAL */ @@ -2335,12 +2437,12 @@ struct kernel_stat { "xc 0(8,%%r15), 0(%%r15)\n\t" "basr %%r14, %4\n\t" /* jump to fn */ "svc %3\n" /* invoke exit syscall */ - "1:\n" + #endif : "=r" (__ret) : "0" (-EINVAL), "i" (__NR_clone), "i" (__NR_exit), - "r" (__fn), "r" (__cstack), "r" (__flags), "r" (__arg), - "r" (__ptidptr), "r" (__newtls), "r" (__ctidptr) + "d" (__fn), "d" (__cstack), "d" (__flags), "d" (__arg), + "d" (__ptidptr), "d" (__newtls), "d" (__ctidptr) : "cc", "r14", "memory" ); } @@ -2429,18 +2531,6 @@ struct kernel_stat { int, t, int, p) #endif #if defined(__x86_64__) || defined(__s390x__) - #if defined(__s390x__) - LSS_INLINE _syscall1(void*, mmap, void*, a) - #else - /* Need to make sure __off64_t isn't truncated to 32-bits under x32. */ - LSS_INLINE void* LSS_NAME(mmap)(void *s, size_t l, int p, int f, int d, - __off64_t o) { - LSS_BODY(6, void*, mmap, LSS_SYSCALL_ARG(s), LSS_SYSCALL_ARG(l), - LSS_SYSCALL_ARG(p), LSS_SYSCALL_ARG(f), - LSS_SYSCALL_ARG(d), (uint64_t)(o)); - } - #endif - LSS_INLINE int LSS_NAME(sigaction)(int signum, const struct kernel_sigaction *act, struct kernel_sigaction *oldact) { @@ -2458,10 +2548,8 @@ struct kernel_stat { (KERNEL_NSIG+7)/8); } else #endif - { return LSS_NAME(rt_sigaction)(signum, act, oldact, (KERNEL_NSIG+7)/8); - } } LSS_INLINE int LSS_NAME(sigprocmask)(int how, @@ -2542,26 +2630,30 @@ struct kernel_stat { } } - #if defined(__i386__) || \ - defined(__arm__) || \ - (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) || defined(__PPC__) + #if defined(__i386__) || \ + defined(__arm__) || \ + (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) || \ + defined(__PPC__) || \ + (defined(__s390__) && !defined(__s390x__)) #define __NR__sigaction __NR_sigaction #define __NR__sigprocmask __NR_sigprocmask LSS_INLINE _syscall2(int, fstat64, int, f, struct kernel_stat64 *, b) LSS_INLINE _syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo, loff_t *, res, uint, wh) -#ifdef __PPC64__ - LSS_INLINE _syscall6(void*, mmap, void*, s, - size_t, l, int, p, - int, f, int, d, - off_t, o) -#else - #ifndef __ARM_EABI__ - /* Not available on ARM EABI Linux. */ - LSS_INLINE _syscall1(void*, mmap, void*, a) - #endif - LSS_INLINE _syscall6(void*, mmap2, void*, s, +#if defined(__s390__) && !defined(__s390x__) + /* On s390, mmap2() arguments are passed in memory. */ + LSS_INLINE void* LSS_NAME(_mmap2)(void *s, size_t l, int p, int f, int d, + off_t o) { + unsigned long buf[6] = { (unsigned long) s, (unsigned long) l, + (unsigned long) p, (unsigned long) f, + (unsigned long) d, (unsigned long) o }; + LSS_REG(2, buf); + LSS_BODY(void*, mmap2, "0"(__r2)); + } +#elif !defined(__PPC64__) + #define __NR__mmap2 __NR_mmap2 + LSS_INLINE _syscall6(void*, _mmap2, void*, s, size_t, l, int, p, int, f, int, d, off_t, o) @@ -2654,11 +2746,48 @@ struct kernel_stat { return rc; } #endif + #if defined(__i386__) || \ + defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) || \ + (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) || \ + (defined(__PPC__) && !defined(__PPC64__)) || \ + (defined(__s390__) && !defined(__s390x__)) + /* On these architectures, implement mmap() with mmap2(). */ + LSS_INLINE void* LSS_NAME(mmap)(void *s, size_t l, int p, int f, int d, + int64_t o) { + if (o % 4096) { + LSS_ERRNO = EINVAL; + return (void *) -1; + } + return LSS_NAME(_mmap2)(s, l, p, f, d, (o / 4096)); + } + #elif defined(__s390x__) + /* On s390x, mmap() arguments are passed in memory. */ + LSS_INLINE void* LSS_NAME(mmap)(void *s, size_t l, int p, int f, int d, + int64_t o) { + unsigned long buf[6] = { (unsigned long) s, (unsigned long) l, + (unsigned long) p, (unsigned long) f, + (unsigned long) d, (unsigned long) o }; + LSS_REG(2, buf); + LSS_BODY(void*, mmap, "0"(__r2)); + } + #elif defined(__x86_64__) + /* Need to make sure __off64_t isn't truncated to 32-bits under x32. */ + LSS_INLINE void* LSS_NAME(mmap)(void *s, size_t l, int p, int f, int d, + int64_t o) { + LSS_BODY(6, void*, mmap, LSS_SYSCALL_ARG(s), LSS_SYSCALL_ARG(l), + LSS_SYSCALL_ARG(p), LSS_SYSCALL_ARG(f), + LSS_SYSCALL_ARG(d), (uint64_t)(o)); + } + #else + /* Remaining 64-bit architectures. */ + LSS_INLINE _syscall6(void*, mmap, void*, addr, size_t, length, int, prot, + int, flags, int, fd, int64_t, offset) + #endif #if defined(__i386__) || \ defined(__PPC__) || \ (defined(__arm__) && !defined(__ARM_EABI__)) || \ (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) || \ - defined(__s390x__) + defined(__s390__) /* See sys_socketcall in net/socket.c in kernel source. * It de-multiplexes on its first arg and unpacks the arglist diff --git a/src/base/linuxthreads.h b/src/base/linuxthreads.h index b7151901..09ce45fc 100644 --- a/src/base/linuxthreads.h +++ b/src/base/linuxthreads.h @@ -42,7 +42,7 @@ */ #if (defined(__i386__) || defined(__x86_64__) || defined(__arm__) || \ defined(__mips__) || defined(__PPC__) || defined(__aarch64__) || \ - defined(__s390x__)) && defined(__linux) + defined(__s390__)) && defined(__linux) /* Define the THREADS symbol to make sure that there is exactly one core dumper * built into the library. diff --git a/src/getpc.h b/src/getpc.h index 25fee393..163873ea 100644 --- a/src/getpc.h +++ b/src/getpc.h @@ -179,7 +179,12 @@ inline void* GetPC(const struct ucontext_t& signal_ucontext) { // configure.ac (or set it manually in your config.h). #else inline void* GetPC(const ucontext_t& signal_ucontext) { +#if defined(__s390__) && !defined(__s390x__) + // Mask out the AMODE31 bit from the PC recorded in the context. + return (void*)((unsigned long)signal_ucontext.PC_FROM_UCONTEXT & 0x7fffffffUL); +#else return (void*)signal_ucontext.PC_FROM_UCONTEXT; // defined in config.h +#endif } #endif diff --git a/src/malloc_hook_mmap_linux.h b/src/malloc_hook_mmap_linux.h index 1c4c7660..4b138618 100755 --- a/src/malloc_hook_mmap_linux.h +++ b/src/malloc_hook_mmap_linux.h @@ -52,7 +52,7 @@ // I test for 64-bit first so I don't have to do things like // '#if (defined(__mips__) && !defined(__MIPS64__))' as a mips32 check. -#if defined(__x86_64__) || defined(__PPC64__) || defined(__aarch64__) || (defined(_MIPS_SIM) && _MIPS_SIM == _ABI64) +#if defined(__x86_64__) || defined(__PPC64__) || defined(__aarch64__) || (defined(_MIPS_SIM) && _MIPS_SIM == _ABI64) || defined(__s390__) static inline void* do_mmap64(void *start, size_t length, int prot, int flags, @@ -119,20 +119,6 @@ static inline void* do_mmap64(void *start, size_t length, #define MALLOC_HOOK_HAVE_DO_MMAP64 1 -#elif defined(__s390x__) - -static inline void* do_mmap64(void *start, size_t length, - int prot, int flags, - int fd, __off64_t offset) __THROW { - // mmap on s390x uses the old syscall interface - unsigned long args[6] = { (unsigned long) start, (unsigned long) length, - (unsigned long) prot, (unsigned long) flags, - (unsigned long) fd, (unsigned long) offset }; - return sys_mmap(args); -} - -#define MALLOC_HOOK_HAVE_DO_MMAP64 1 - #endif // #if defined(__x86_64__)