1
0
Fork 0
mirror of https://github.com/tobast/libunwind-eh_elf.git synced 2024-12-22 19:43:42 +01:00

Add port to Linux on IBM Z (s390x)

This adds a port to Linux on the IBM Z platform (a.k.a s390x). It only
supports the 64-bit ABI. Most functionality is working and all the tests
pass with the exception of the coredump tests*.

Unwinding is only supported if DWARF unwind information is present.
libunwind can't currently make use of the backchain (if present).

The getcontext/setcontext functions only preserve/restore a subset of
registers. Currently this only consists of callee-saved registers and
some parameter registers.

Vector registers and access registers are not saved (and aren't callee-
saved) by getcontext and cannot currently be modified. They will however
be restored unmodified after resuming a context from a signal handler.

There is no special libunwind support for setjmp, the functionality is
emulated using glibc (I think all the ports do this for modern Linux
kernels).

* Unwinding on s390x requires floating point register access which the
coredump library doesn't currently support.
This commit is contained in:
Michael Munday 2017-12-05 10:05:41 -05:00 committed by Dave Watson
parent 4c07b17037
commit 441adc46ff
45 changed files with 2400 additions and 1 deletions

View file

@ -41,6 +41,9 @@ endif
if ARCH_SH if ARCH_SH
include_HEADERS += include/libunwind-sh.h include_HEADERS += include/libunwind-sh.h
endif endif
if ARCH_S390X
include_HEADERS += include/libunwind-s390x.h
endif
if !REMOTE_ONLY if !REMOTE_ONLY
include_HEADERS += include/libunwind.h include/unwind.h include_HEADERS += include/libunwind.h include/unwind.h
@ -84,6 +87,8 @@ noinst_HEADERS = include/dwarf.h include/dwarf_i.h include/dwarf-eh.h \
include/tdep-ppc64/jmpbuf.h include/tdep-ppc64/libunwind_i.h \ include/tdep-ppc64/jmpbuf.h include/tdep-ppc64/libunwind_i.h \
include/tdep-sh/dwarf-config.h \ include/tdep-sh/dwarf-config.h \
include/tdep-sh/jmpbuf.h include/tdep-sh/libunwind_i.h \ include/tdep-sh/jmpbuf.h include/tdep-sh/libunwind_i.h \
include/tdep-s390x/dwarf-config.h \
include/tdep-s390x/jmpbuf.h include/tdep-s390x/libunwind_i.h \
include/tdep/libunwind_i.h \ include/tdep/libunwind_i.h \
include/tdep/jmpbuf.h include/tdep/dwarf-config.h include/tdep/jmpbuf.h include/tdep/dwarf-config.h

View file

@ -175,6 +175,7 @@ AM_CONDITIONAL(ARCH_PPC32, test x$target_arch = xppc32)
AM_CONDITIONAL(ARCH_PPC64, test x$target_arch = xppc64) AM_CONDITIONAL(ARCH_PPC64, test x$target_arch = xppc64)
AM_CONDITIONAL(ARCH_SH, test x$target_arch = xsh) AM_CONDITIONAL(ARCH_SH, test x$target_arch = xsh)
AM_CONDITIONAL(ARCH_TILEGX, test x$target_arch = xtilegx) AM_CONDITIONAL(ARCH_TILEGX, test x$target_arch = xtilegx)
AM_CONDITIONAL(ARCH_S390X, test x$target_arch = xs390x)
AM_CONDITIONAL(OS_LINUX, expr x$target_os : xlinux >/dev/null) AM_CONDITIONAL(OS_LINUX, expr x$target_os : xlinux >/dev/null)
AM_CONDITIONAL(OS_HPUX, expr x$target_os : xhpux >/dev/null) AM_CONDITIONAL(OS_HPUX, expr x$target_os : xhpux >/dev/null)
AM_CONDITIONAL(OS_FREEBSD, expr x$target_os : xfreebsd >/dev/null) AM_CONDITIONAL(OS_FREEBSD, expr x$target_os : xfreebsd >/dev/null)
@ -183,7 +184,7 @@ AM_CONDITIONAL(OS_QNX, expr x$target_os : xnto-qnx >/dev/null)
AC_MSG_CHECKING([for ELF helper width]) AC_MSG_CHECKING([for ELF helper width])
case "${target_arch}" in case "${target_arch}" in
(arm|hppa|ppc32|x86|sh) use_elf32=yes; AC_MSG_RESULT([32]);; (arm|hppa|ppc32|x86|sh) use_elf32=yes; AC_MSG_RESULT([32]);;
(aarch64|ia64|ppc64|x86_64|tilegx) use_elf64=yes; AC_MSG_RESULT([64]);; (aarch64|ia64|ppc64|x86_64|s390x|tilegx) use_elf64=yes; AC_MSG_RESULT([64]);;
(mips) use_elfxx=yes; AC_MSG_RESULT([xx]);; (mips) use_elfxx=yes; AC_MSG_RESULT([xx]);;
*) AC_MSG_ERROR([Unknown ELF target: ${target_arch}]) *) AC_MSG_ERROR([Unknown ELF target: ${target_arch}])
esac esac

144
include/libunwind-s390x.h Normal file
View file

@ -0,0 +1,144 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2002-2004 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
Modified for s390x by Michael Munday <mike.munday@ibm.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#ifndef LIBUNWIND_H
#define LIBUNWIND_H
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
#include <sys/types.h>
#include <inttypes.h>
#include <ucontext.h>
#define UNW_TARGET s390x
#define UNW_TARGET_S390X 1
#define _U_TDEP_QP_TRUE 0 /* see libunwind-dynamic.h */
/* This needs to be big enough to accommodate "struct cursor", while
leaving some slack for future expansion. Changing this value will
require recompiling all users of this library. Stack allocation is
relatively cheap and unwind-state copying is relatively rare, so we
want to err on making it rather too big than too small. */
#define UNW_TDEP_CURSOR_LEN 384
typedef uint64_t unw_word_t;
typedef int64_t unw_sword_t;
typedef long double unw_tdep_fpreg_t;
typedef enum
{
/* general purpose registers */
UNW_S390X_R0,
UNW_S390X_R1,
UNW_S390X_R2,
UNW_S390X_R3,
UNW_S390X_R4,
UNW_S390X_R5,
UNW_S390X_R6,
UNW_S390X_R7,
UNW_S390X_R8,
UNW_S390X_R9,
UNW_S390X_R10,
UNW_S390X_R11,
UNW_S390X_R12,
UNW_S390X_R13,
UNW_S390X_R14,
UNW_S390X_R15,
/* floating point registers */
UNW_S390X_F0,
UNW_S390X_F1,
UNW_S390X_F2,
UNW_S390X_F3,
UNW_S390X_F4,
UNW_S390X_F5,
UNW_S390X_F6,
UNW_S390X_F7,
UNW_S390X_F8,
UNW_S390X_F9,
UNW_S390X_F10,
UNW_S390X_F11,
UNW_S390X_F12,
UNW_S390X_F13,
UNW_S390X_F14,
UNW_S390X_F15,
/* PSW */
UNW_S390X_IP,
UNW_TDEP_LAST_REG = UNW_S390X_IP,
/* TODO: access, vector registers */
/* frame info (read-only) */
UNW_S390X_CFA,
UNW_TDEP_IP = UNW_S390X_IP,
UNW_TDEP_SP = UNW_S390X_R15,
/* TODO: placeholders */
UNW_TDEP_EH = UNW_S390X_R0,
}
s390x_regnum_t;
#define UNW_TDEP_NUM_EH_REGS 2 /* XXX Not sure what this means */
typedef struct unw_tdep_save_loc
{
/* Additional target-dependent info on a save location. */
char unused;
}
unw_tdep_save_loc_t;
/* On s390x, we can directly use ucontext_t as the unwind context. */
typedef ucontext_t unw_tdep_context_t;
typedef struct
{
/* no s390x-specific auxiliary proc-info */
char unused;
}
unw_tdep_proc_info_t;
#include "libunwind-dynamic.h"
#include "libunwind-common.h"
#define unw_tdep_getcontext UNW_ARCH_OBJ(getcontext)
#define unw_tdep_is_fpreg UNW_ARCH_OBJ(is_fpreg)
extern int unw_tdep_getcontext (unw_tdep_context_t *);
extern int unw_tdep_is_fpreg (int);
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
#endif /* LIBUNWIND_H */

View file

@ -25,6 +25,8 @@
# include "libunwind-x86_64.h" # include "libunwind-x86_64.h"
#elif defined __tilegx__ #elif defined __tilegx__
# include "libunwind-tilegx.h" # include "libunwind-tilegx.h"
#elif defined __s390x__
# include "libunwind-s390x.h"
#else #else
# error "Unsupported arch" # error "Unsupported arch"
#endif #endif

View file

@ -0,0 +1,52 @@
/* libunwind - a platform-independent unwind library
Copyright (c) 2003, 2005 Hewlett-Packard Development Company, L.P.
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/* copy of include/tdep-x86/dwarf-config.h, modified slightly for x86-64
some consolidation is possible here */
#ifndef dwarf_config_h
#define dwarf_config_h
/* derived from DWARF register mappings in Z ELF ABI */
#define DWARF_NUM_PRESERVED_REGS 66
#define DWARF_REGNUM_MAP_LENGTH DWARF_NUM_PRESERVED_REGS
/* Return TRUE if the ADDR_SPACE uses big-endian byte-order. */
#define dwarf_is_big_endian(addr_space) 1
/* Convert a pointer to a dwarf_cursor structure to a pointer to
unw_cursor_t. */
#define dwarf_to_cursor(c) ((unw_cursor_t *) (c))
typedef struct dwarf_loc
{
unw_word_t val;
unw_word_t type; /* see S390X_LOC_TYPE_* macros. */
}
dwarf_loc_t;
#endif /* dwarf_config_h */

View file

@ -0,0 +1,35 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2004 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#if defined __linux__
/* Use glibc's jump-buffer indices; NPTL peeks at SP: */
#define JB_SP 9 // __gregs[9]
#define JB_RP 8 // __gregs[8]
#define JB_MASK_SAVED 18 // __mask_was_saved
#define JB_MASK 19 // __saved_mask
#endif

View file

@ -0,0 +1,262 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2002-2005 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#ifndef S390X_LIBUNWIND_I_H
#define S390X_LIBUNWIND_I_H
/* Target-dependent definitions that are internal to libunwind but need
to be shared with target-independent code. */
#include <stdlib.h>
#include <libunwind.h>
#include "elf64.h"
#include "mempool.h"
#include "dwarf.h"
struct unw_addr_space
{
struct unw_accessors acc;
unw_caching_policy_t caching_policy;
#ifdef HAVE_ATOMIC_OPS_H
AO_t cache_generation;
#else
uint32_t cache_generation;
#endif
unw_word_t dyn_generation; /* see dyn-common.h */
unw_word_t dyn_info_list_addr; /* (cached) dyn_info_list_addr */
struct dwarf_rs_cache global_cache;
struct unw_debug_frame_list *debug_frames;
};
struct cursor
{
struct dwarf_cursor dwarf; /* must be first */
/* Format of sigcontext structure and address at which it is
stored: */
enum
{
S390X_SCF_NONE = 0, /* no signal frame encountered */
S390X_SCF_LINUX_SIGFRAME = 1, /* Linux struct sigcontext */
S390X_SCF_LINUX_RT_SIGFRAME = 2, /* Linux ucontext_t */
}
sigcontext_format;
unw_word_t sigcontext_addr;
unw_word_t sigcontext_sp;
unw_word_t sigcontext_pc;
int validate;
ucontext_t *uc;
};
static inline ucontext_t *
dwarf_get_uc(const struct dwarf_cursor *cursor)
{
const struct cursor *c = (struct cursor *) cursor->as_arg;
return c->uc;
}
#define DWARF_GET_LOC(l) ((l).val)
# define DWARF_LOC_TYPE_MEM (0 << 0)
# define DWARF_LOC_TYPE_FP (1 << 0)
# define DWARF_LOC_TYPE_REG (1 << 1)
# define DWARF_LOC_TYPE_VAL (1 << 2)
# define DWARF_IS_REG_LOC(l) (((l).type & DWARF_LOC_TYPE_REG) != 0)
# define DWARF_IS_FP_LOC(l) (((l).type & DWARF_LOC_TYPE_FP) != 0)
# define DWARF_IS_MEM_LOC(l) ((l).type == DWARF_LOC_TYPE_MEM)
# define DWARF_IS_VAL_LOC(l) (((l).type & DWARF_LOC_TYPE_VAL) != 0)
# define DWARF_LOC(r, t) ((dwarf_loc_t) { .val = (r), .type = (t) })
# define DWARF_VAL_LOC(c,v) DWARF_LOC ((v), DWARF_LOC_TYPE_VAL)
# define DWARF_MEM_LOC(c,m) DWARF_LOC ((m), DWARF_LOC_TYPE_MEM)
#ifdef UNW_LOCAL_ONLY
# define DWARF_NULL_LOC DWARF_LOC (0, 0)
# define DWARF_IS_NULL_LOC(l) (DWARF_GET_LOC (l) == 0)
# define DWARF_REG_LOC(c,r) (DWARF_LOC((unw_word_t) \
tdep_uc_addr(dwarf_get_uc(c), (r)), 0))
# define DWARF_FPREG_LOC(c,r) (DWARF_LOC((unw_word_t) \
tdep_uc_addr(dwarf_get_uc(c), (r)), 0))
#else /* !UNW_LOCAL_ONLY */
# define DWARF_NULL_LOC DWARF_LOC (0, 0)
# define DWARF_IS_NULL_LOC(l) \
({ dwarf_loc_t _l = (l); _l.val == 0 && _l.type == 0; })
# define DWARF_REG_LOC(c,r) DWARF_LOC((r), DWARF_LOC_TYPE_REG)
# define DWARF_FPREG_LOC(c,r) DWARF_LOC((r), (DWARF_LOC_TYPE_REG \
| DWARF_LOC_TYPE_FP))
#endif /* !UNW_LOCAL_ONLY */
static inline int
dwarf_getfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t *val)
{
assert(sizeof unw_fpreg_t == sizeof unw_word_t);
if (DWARF_IS_NULL_LOC (loc))
return -UNW_EBADREG;
if (DWARF_IS_FP_LOC (loc))
return (*c->as->acc.access_fpreg) (c->as, DWARF_GET_LOC (loc), val,
0, c->as_arg);
/* FPRs may be saved in GPRs */
if (DWARF_IS_REG_LOC (loc))
return (*c->as->acc.access_reg) (c->as, DWARF_GET_LOC (loc), (unw_word_t*)val,
0, c->as_arg);
if (DWARF_IS_MEM_LOC (loc))
return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), (unw_word_t*)val,
0, c->as_arg);
assert(DWARF_IS_VAL_LOC (loc));
*val = *(unw_fpreg_t*) DWARF_GET_LOC (loc);
return 0;
}
static inline int
dwarf_putfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val)
{
assert(sizeof unw_fpreg_t == sizeof unw_word_t);
assert(!DWARF_IS_VAL_LOC (loc));
if (DWARF_IS_NULL_LOC (loc))
return -UNW_EBADREG;
if (DWARF_IS_FP_LOC (loc))
return (*c->as->acc.access_fpreg) (c->as, DWARF_GET_LOC (loc), &val,
1, c->as_arg);
/* FPRs may be saved in GPRs */
if (DWARF_IS_REG_LOC (loc))
return (*c->as->acc.access_reg) (c->as, DWARF_GET_LOC (loc), (unw_word_t*) &val,
1, c->as_arg);
assert(DWARF_IS_MEM_LOC (loc));
return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), (unw_word_t*) &val,
1, c->as_arg);
}
static inline int
dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t *val)
{
assert(sizeof unw_fpreg_t == sizeof unw_word_t);
if (DWARF_IS_NULL_LOC (loc))
return -UNW_EBADREG;
if (DWARF_IS_REG_LOC (loc))
return (*c->as->acc.access_reg) (c->as, DWARF_GET_LOC (loc), val,
0, c->as_arg);
if (DWARF_IS_MEM_LOC (loc))
return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), val,
0, c->as_arg);
/* GPRs may be saved in FPRs */
if (DWARF_IS_FP_LOC (loc))
return (*c->as->acc.access_fpreg) (c->as, DWARF_GET_LOC (loc), (unw_fpreg_t*)val,
0, c->as_arg);
assert(DWARF_IS_VAL_LOC (loc));
*val = DWARF_GET_LOC (loc);
return 0;
}
static inline int
dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val)
{
assert(sizeof unw_fpreg_t == sizeof unw_word_t);
assert(!DWARF_IS_VAL_LOC (loc));
if (DWARF_IS_NULL_LOC (loc))
return -UNW_EBADREG;
if (DWARF_IS_REG_LOC (loc))
return (*c->as->acc.access_reg) (c->as, DWARF_GET_LOC (loc), &val,
1, c->as_arg);
/* GPRs may be saved in FPRs */
if (DWARF_IS_FP_LOC (loc))
return (*c->as->acc.access_fpreg) (c->as, DWARF_GET_LOC (loc), (unw_fpreg_t*) &val,
1, c->as_arg);
assert(DWARF_IS_MEM_LOC (loc));
return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), &val,
1, c->as_arg);
}
#define tdep_getcontext_trace unw_getcontext
#define tdep_init_done UNW_OBJ(init_done)
#define tdep_init_mem_validate UNW_OBJ(init_mem_validate)
#define tdep_init UNW_OBJ(init)
/* Platforms that support UNW_INFO_FORMAT_TABLE need to define
tdep_search_unwind_table. */
#define tdep_search_unwind_table dwarf_search_unwind_table
#define tdep_find_unwind_table dwarf_find_unwind_table
#define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image)
#define tdep_get_exe_image_path UNW_ARCH_OBJ(get_exe_image_path)
#define tdep_access_reg UNW_OBJ(access_reg)
#define tdep_access_fpreg UNW_OBJ(access_fpreg)
#define tdep_fetch_frame(c,ip,n) do {} while(0)
#define tdep_cache_frame(c) 0
#define tdep_reuse_frame(c,rs) do {} while(0)
#define tdep_stash_frame(cs,rs) do {} while(0)
#define tdep_trace(cur,addr,n) (-UNW_ENOINFO)
#define tdep_uc_addr UNW_OBJ(uc_addr)
#ifdef UNW_LOCAL_ONLY
# define tdep_find_proc_info(c,ip,n) \
dwarf_find_proc_info((c)->as, (ip), &(c)->pi, (n), \
(c)->as_arg)
# define tdep_put_unwind_info(as,pi,arg) \
dwarf_put_unwind_info((as), (pi), (arg))
#else
# define tdep_find_proc_info(c,ip,n) \
(*(c)->as->acc.find_proc_info)((c)->as, (ip), &(c)->pi, (n), \
(c)->as_arg)
# define tdep_put_unwind_info(as,pi,arg) \
(*(as)->acc.put_unwind_info)((as), (pi), (arg))
#endif
#define tdep_get_as(c) ((c)->dwarf.as)
#define tdep_get_as_arg(c) ((c)->dwarf.as_arg)
#define tdep_get_ip(c) ((c)->dwarf.ip)
#define tdep_big_endian(as) 1
extern int tdep_init_done;
extern void tdep_init (void);
extern void tdep_init_mem_validate (void);
extern int tdep_search_unwind_table (unw_addr_space_t as, unw_word_t ip,
unw_dyn_info_t *di, unw_proc_info_t *pi,
int need_unwind_info, void *arg);
extern void *tdep_uc_addr (unw_tdep_context_t *uc, int reg);
extern int tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip,
unsigned long *segbase, unsigned long *mapoff,
char *path, size_t pathlen);
extern void tdep_get_exe_image_path (char *path);
extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg,
unw_word_t *valp, int write);
extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg,
unw_fpreg_t *valp, int write);
#endif /* S390X_LIBUNWIND_I_H */

View file

@ -25,6 +25,8 @@
# include "tdep-x86_64/libunwind_i.h" # include "tdep-x86_64/libunwind_i.h"
#elif defined __tilegx__ #elif defined __tilegx__
# include "tdep-tilegx/libunwind_i.h" # include "tdep-tilegx/libunwind_i.h"
#elif defined __s390x__
# include "tdep-s390x/libunwind_i.h"
#else #else
# error "Unsupported arch" # error "Unsupported arch"
#endif #endif

View file

@ -463,6 +463,30 @@ libunwind_sh_la_SOURCES_sh = $(libunwind_la_SOURCES_sh_common) \
sh/Gglobal.c sh/Ginit.c sh/Ginit_local.c sh/Ginit_remote.c \ sh/Gglobal.c sh/Ginit.c sh/Ginit_local.c sh/Ginit_remote.c \
sh/Gis_signal_frame.c sh/Gregs.c sh/Gresume.c sh/Gstep.c sh/Gis_signal_frame.c sh/Gregs.c sh/Gresume.c sh/Gstep.c
# The list of files that go both into libunwind and libunwind-s390x:
noinst_HEADERS += s390x/init.h s390x/unwind_i.h
libunwind_la_SOURCES_s390x_common = $(libunwind_la_SOURCES_common) \
s390x/is_fpreg.c s390x/regname.c
# The list of files that go into libunwind:
libunwind_la_SOURCES_s390x = $(libunwind_la_SOURCES_s390x_common) \
$(libunwind_la_SOURCES_local) \
s390x/Lapply_reg_state.c s390x/Lreg_states_iterate.c \
s390x/Lcreate_addr_space.c s390x/Lget_save_loc.c s390x/Lglobal.c \
s390x/Linit.c s390x/Linit_local.c s390x/Linit_remote.c \
s390x/Lget_proc_info.c s390x/Lregs.c s390x/Lresume.c \
s390x/Lis_signal_frame.c s390x/Lstep.c \
s390x/getcontext.S s390x/setcontext.S
# The list of files that go into libunwind-s390x:
libunwind_s390x_la_SOURCES_s390x = $(libunwind_la_SOURCES_s390x_common) \
$(libunwind_la_SOURCES_generic) \
s390x/Gapply_reg_state.c s390x/Greg_states_iterate.c \
s390x/Gcreate_addr_space.c s390x/Gget_save_loc.c s390x/Gglobal.c \
s390x/Ginit.c s390x/Ginit_local.c s390x/Ginit_remote.c \
s390x/Gget_proc_info.c s390x/Gregs.c s390x/Gresume.c \
s390x/Gis_signal_frame.c s390x/Gstep.c
if REMOTE_ONLY if REMOTE_ONLY
install-exec-hook: install-exec-hook:
# Nothing to do here.... # Nothing to do here....
@ -662,7 +686,19 @@ if !REMOTE_ONLY
libunwind_sh_la_LIBADD += libunwind.la -lc libunwind_sh_la_LIBADD += libunwind.la -lc
endif endif
libunwind_setjmp_la_SOURCES += sh/siglongjmp.S libunwind_setjmp_la_SOURCES += sh/siglongjmp.S
else
if ARCH_S390X
lib_LTLIBRARIES += libunwind-s390x.la
libunwind_la_SOURCES = $(libunwind_la_SOURCES_s390x)
libunwind_s390x_la_SOURCES = $(libunwind_s390x_la_SOURCES_s390x)
libunwind_s390x_la_LDFLAGS = $(COMMON_SO_LDFLAGS) -version-info $(SOVERSION)
libunwind_s390x_la_LIBADD = libunwind-dwarf-generic.la
libunwind_s390x_la_LIBADD += libunwind-elf64.la
if !REMOTE_ONLY
libunwind_s390x_la_LIBADD += libunwind.la -lc
endif
endif # ARCH_S390X
endif # ARCH_SH endif # ARCH_SH
endif # ARCH_PPC64 endif # ARCH_PPC64
endif # ARCH_PPC32 endif # ARCH_PPC32

View file

@ -54,6 +54,9 @@ _UCD_access_reg (unw_addr_space_t as,
#elif defined(UNW_TARGET_TILEGX) #elif defined(UNW_TARGET_TILEGX)
if (regnum > UNW_TILEGX_CFA) if (regnum > UNW_TILEGX_CFA)
goto badreg; goto badreg;
#elif defined(UNW_TARGET_S390X)
if (regnum > UNW_S390X_R15)
goto badreg;
#else #else
#if defined(UNW_TARGET_MIPS) #if defined(UNW_TARGET_MIPS)
static const uint8_t remap_regs[] = static const uint8_t remap_regs[] =

View file

@ -831,6 +831,14 @@ apply_reg_state (struct dwarf_cursor *c, struct dwarf_reg_state *rs)
break; break;
case DWARF_WHERE_REG: case DWARF_WHERE_REG:
#ifdef __s390x__
/* GPRs can be saved in FPRs on s390x */
if (unw_is_fpreg (dwarf_to_unw_regnum (rs->reg.val[i])))
{
new_loc[i] = DWARF_FPREG_LOC (c, dwarf_to_unw_regnum (rs->reg.val[i]));
break;
}
#endif
new_loc[i] = DWARF_REG_LOC (c, dwarf_to_unw_regnum (rs->reg.val[i])); new_loc[i] = DWARF_REG_LOC (c, dwarf_to_unw_regnum (rs->reg.val[i]));
break; break;

View file

@ -632,6 +632,40 @@ const int _UPT_reg_offset[UNW_REG_LAST + 1] =
[UNW_TILEGX_R54] = 0x1b0, [UNW_TILEGX_R54] = 0x1b0,
[UNW_TILEGX_R55] = 0x1b8, [UNW_TILEGX_R55] = 0x1b8,
[UNW_TILEGX_PC] = 0x1a0 [UNW_TILEGX_PC] = 0x1a0
#elif defined(UNW_TARGET_S390X)
[UNW_S390X_R0] = 0x10,
[UNW_S390X_R1] = 0x18,
[UNW_S390X_R2] = 0x20,
[UNW_S390X_R3] = 0x28,
[UNW_S390X_R4] = 0x30,
[UNW_S390X_R5] = 0x38,
[UNW_S390X_R6] = 0x40,
[UNW_S390X_R7] = 0x48,
[UNW_S390X_R8] = 0x50,
[UNW_S390X_R9] = 0x58,
[UNW_S390X_R10] = 0x60,
[UNW_S390X_R11] = 0x68,
[UNW_S390X_R12] = 0x70,
[UNW_S390X_R13] = 0x78,
[UNW_S390X_R14] = 0x80,
[UNW_S390X_R15] = 0x88,
[UNW_S390X_F0] = 0xe0,
[UNW_S390X_F1] = 0xe8,
[UNW_S390X_F2] = 0xf0,
[UNW_S390X_F3] = 0xf8,
[UNW_S390X_F4] = 0x100,
[UNW_S390X_F5] = 0x108,
[UNW_S390X_F6] = 0x110,
[UNW_S390X_F7] = 0x118,
[UNW_S390X_F8] = 0x120,
[UNW_S390X_F9] = 0x128,
[UNW_S390X_F10] = 0x130,
[UNW_S390X_F11] = 0x138,
[UNW_S390X_F12] = 0x140,
[UNW_S390X_F13] = 0x148,
[UNW_S390X_F14] = 0x150,
[UNW_S390X_F15] = 0x150,
[UNW_S390X_IP] = 0x08
#else #else
# error Fix me. # error Fix me.
#endif #endif

View file

@ -0,0 +1,37 @@
/* libunwind - a platform-independent unwind library
Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P.
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "unwind_i.h"
PROTECTED int
unw_apply_reg_state (unw_cursor_t *cursor,
void *reg_states_data)
{
struct cursor *c = (struct cursor *) cursor;
return dwarf_apply_reg_state (&c->dwarf, (dwarf_reg_state_t *)reg_states_data);
}

View file

@ -0,0 +1,62 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2003 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
Copyright (C) 2012 Tommi Rantala <tt.rantala@gmail.com>
Modified for s390x by Michael Munday <mike.munday@ibm.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include <stdlib.h>
#include "unwind_i.h"
#if defined(_BIG_ENDIAN) && !defined(__BIG_ENDIAN)
#define __BIG_ENDIAN _BIG_ENDIAN
#endif
PROTECTED unw_addr_space_t
unw_create_addr_space (unw_accessors_t *a, int byte_order)
{
#ifdef UNW_LOCAL_ONLY
return NULL;
#else
unw_addr_space_t as;
/*
* s390x supports only big-endian.
*/
if (byte_order != 0 && byte_order != __BIG_ENDIAN)
return NULL;
as = malloc (sizeof (*as));
if (!as)
return NULL;
memset (as, 0, sizeof (*as));
as->acc = *a;
return as;
#endif
}

View file

@ -0,0 +1,48 @@
/* libunwind - a platform-independent unwind library
Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P.
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "unwind_i.h"
PROTECTED int
unw_get_proc_info (unw_cursor_t *cursor, unw_proc_info_t *pi)
{
struct cursor *c = (struct cursor *) cursor;
if (dwarf_make_proc_info (&c->dwarf) < 0)
{
/* On x86-64, some key routines such as _start() and _dl_start()
are missing DWARF unwind info. We don't want to fail in that
case, because those frames are uninteresting and just mark
the end of the frame-chain anyhow. */
memset (pi, 0, sizeof (*pi));
pi->start_ip = c->dwarf.ip;
pi->end_ip = c->dwarf.ip + 1;
return 0;
}
*pi = c->dwarf.pi;
return 0;
}

86
src/s390x/Gget_save_loc.c Normal file
View file

@ -0,0 +1,86 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2004 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
Modified for s390x by Michael Munday <mike.munday@ibm.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "unwind_i.h"
PROTECTED int
unw_get_save_loc (unw_cursor_t *cursor, int reg, unw_save_loc_t *sloc)
{
struct cursor *c = (struct cursor *) cursor;
dwarf_loc_t loc;
loc = DWARF_NULL_LOC; /* default to "not saved" */
switch (reg)
{
case UNW_S390X_R6:
case UNW_S390X_R7:
case UNW_S390X_R8:
case UNW_S390X_R9:
case UNW_S390X_R10:
case UNW_S390X_R11:
case UNW_S390X_R12:
case UNW_S390X_R13:
case UNW_S390X_R15:
case UNW_S390X_F8:
case UNW_S390X_F9:
case UNW_S390X_F10:
case UNW_S390X_F11:
case UNW_S390X_F12:
case UNW_S390X_F13:
case UNW_S390X_F14:
case UNW_S390X_F15:
loc = c->dwarf.loc[reg];
break;
default:
break;
}
memset (sloc, 0, sizeof (*sloc));
if (DWARF_IS_NULL_LOC (loc))
{
sloc->type = UNW_SLT_NONE;
return 0;
}
#if !defined(UNW_LOCAL_ONLY)
if (DWARF_IS_REG_LOC (loc))
{
sloc->type = UNW_SLT_REG;
sloc->u.regnum = DWARF_GET_LOC (loc);
}
else
#endif
{
sloc->type = UNW_SLT_MEMORY;
sloc->u.addr = DWARF_GET_LOC (loc);
}
return 0;
}

101
src/s390x/Gglobal.c Normal file
View file

@ -0,0 +1,101 @@
/* libunwind - a platform-independent unwind library
Copyright (c) 2003, 2005 Hewlett-Packard Development Company, L.P.
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
Modified for s390x by Michael Munday <mike.munday@ibm.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "config.h"
#include "unwind_i.h"
#include "dwarf_i.h"
HIDDEN define_lock (s390x_lock);
HIDDEN int tdep_init_done;
/* The API register numbers are exactly the same as the .eh_frame
registers, for now at least. */
HIDDEN const uint8_t dwarf_to_unw_regnum_map[DWARF_NUM_PRESERVED_REGS] =
{
UNW_S390X_R0,
UNW_S390X_R1,
UNW_S390X_R2,
UNW_S390X_R3,
UNW_S390X_R4,
UNW_S390X_R5,
UNW_S390X_R6,
UNW_S390X_R7,
UNW_S390X_R8,
UNW_S390X_R9,
UNW_S390X_R10,
UNW_S390X_R11,
UNW_S390X_R12,
UNW_S390X_R13,
UNW_S390X_R14,
UNW_S390X_R15,
UNW_S390X_F0,
UNW_S390X_F2,
UNW_S390X_F4,
UNW_S390X_F6,
UNW_S390X_F1,
UNW_S390X_F3,
UNW_S390X_F5,
UNW_S390X_F7,
UNW_S390X_F8,
UNW_S390X_F10,
UNW_S390X_F12,
UNW_S390X_F14,
UNW_S390X_F9,
UNW_S390X_F11,
UNW_S390X_F13,
UNW_S390X_F15,
};
HIDDEN void
tdep_init (void)
{
intrmask_t saved_mask;
sigfillset (&unwi_full_mask);
lock_acquire (&s390x_lock, saved_mask);
{
if (tdep_init_done)
/* another thread else beat us to it... */
goto out;
mi_init ();
dwarf_init ();
tdep_init_mem_validate ();
#ifndef UNW_REMOTE_ONLY
s390x_local_addr_space_init ();
#endif
tdep_init_done = 1; /* signal that we're initialized... */
}
out:
lock_release (&s390x_lock, saved_mask);
}

364
src/s390x/Ginit.c Normal file
View file

@ -0,0 +1,364 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2002 Hewlett-Packard Co
Copyright (C) 2007 David Mosberger-Tang
Contributed by David Mosberger-Tang <dmosberger@gmail.com>
Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
Modified for s390x by Michael Munday <mike.munday@ibm.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include "unwind_i.h"
#ifdef UNW_REMOTE_ONLY
/* unw_local_addr_space is a NULL pointer in this case. */
PROTECTED unw_addr_space_t unw_local_addr_space;
#else /* !UNW_REMOTE_ONLY */
static struct unw_addr_space local_addr_space;
PROTECTED unw_addr_space_t unw_local_addr_space = &local_addr_space;
HIDDEN unw_dyn_info_list_t _U_dyn_info_list;
static inline void *
uc_addr (ucontext_t *uc, int reg)
{
if (reg >= UNW_S390X_R0 && reg <= UNW_S390X_R15)
return &uc->uc_mcontext.gregs[reg - UNW_S390X_R0];
if (reg >= UNW_S390X_F0 && reg <= UNW_S390X_F15)
return &uc->uc_mcontext.fpregs.fprs[reg - UNW_S390X_F0];
if (reg == UNW_S390X_IP)
return &uc->uc_mcontext.psw.addr;
return NULL;
}
# ifdef UNW_LOCAL_ONLY
HIDDEN void *
tdep_uc_addr (ucontext_t *uc, int reg)
{
return uc_addr (uc, reg);
}
# endif /* UNW_LOCAL_ONLY */
/* XXX fix me: there is currently no way to locate the dyn-info list
by a remote unwinder. On ia64, this is done via a special
unwind-table entry. Perhaps something similar can be done with
DWARF2 unwind info. */
static void
put_unwind_info (unw_addr_space_t as, unw_proc_info_t *proc_info, void *arg)
{
/* it's a no-op */
}
static int
get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr,
void *arg)
{
*dyn_info_list_addr = (unw_word_t) &_U_dyn_info_list;
return 0;
}
#define PAGE_SIZE 4096
#define PAGE_START(a) ((a) & ~(PAGE_SIZE-1))
static int mem_validate_pipe[2] = {-1, -1};
static inline void
open_pipe (void)
{
/* ignore errors for closing invalid fd's */
close (mem_validate_pipe[0]);
close (mem_validate_pipe[1]);
pipe2 (mem_validate_pipe, O_CLOEXEC | O_NONBLOCK);
}
ALWAYS_INLINE
static int
write_validate (void *addr)
{
int ret = -1;
ssize_t bytes = 0;
do
{
char buf;
bytes = read (mem_validate_pipe[0], &buf, 1);
}
while ( errno == EINTR );
int valid_read = (bytes > 0 || errno == EAGAIN || errno == EWOULDBLOCK);
if (!valid_read)
{
// re-open closed pipe
open_pipe ();
}
do
{
ret = write (mem_validate_pipe[1], addr, 1);
}
while ( errno == EINTR );
return ret;
}
static int (*mem_validate_func) (void *addr, size_t len);
static int msync_validate (void *addr, size_t len)
{
if (msync (addr, len, MS_ASYNC) != 0)
{
return -1;
}
return write_validate (addr);
}
#ifdef HAVE_MINCORE
static int mincore_validate (void *addr, size_t len)
{
unsigned char mvec[2]; /* Unaligned access may cross page boundary */
size_t i;
/* mincore could fail with EAGAIN but we conservatively return -1
instead of looping. */
if (mincore (addr, len, mvec) != 0)
{
return -1;
}
for (i = 0; i < (len + PAGE_SIZE - 1) / PAGE_SIZE; i++)
{
if (!(mvec[i] & 1)) return -1;
}
return write_validate (addr);
}
#endif
/* Initialise memory validation method. On linux kernels <2.6.21,
mincore() returns incorrect value for MAP_PRIVATE mappings,
such as stacks. If mincore() was available at compile time,
check if we can actually use it. If not, use msync() instead. */
HIDDEN void
tdep_init_mem_validate (void)
{
open_pipe ();
#ifdef HAVE_MINCORE
unsigned char present = 1;
unw_word_t addr = PAGE_START((unw_word_t)&present);
unsigned char mvec[1];
int ret;
while ((ret = mincore ((void*)addr, PAGE_SIZE, mvec)) == -1 &&
errno == EAGAIN) {}
if (ret == 0 && (mvec[0] & 1))
{
Debug(1, "using mincore to validate memory\n");
mem_validate_func = mincore_validate;
}
else
#endif
{
Debug(1, "using msync to validate memory\n");
mem_validate_func = msync_validate;
}
}
/* Cache of already validated addresses */
#define NLGA 4
static unw_word_t last_good_addr[NLGA];
static int lga_victim;
static int
validate_mem (unw_word_t addr)
{
int i, victim;
size_t len;
if (PAGE_START(addr + sizeof (unw_word_t) - 1) == PAGE_START(addr))
len = PAGE_SIZE;
else
len = PAGE_SIZE * 2;
addr = PAGE_START(addr);
if (addr == 0)
return -1;
for (i = 0; i < NLGA; i++)
{
if (last_good_addr[i] && (addr == last_good_addr[i]))
return 0;
}
if (mem_validate_func ((void *) addr, len) == -1)
return -1;
victim = lga_victim;
for (i = 0; i < NLGA; i++) {
if (!last_good_addr[victim]) {
last_good_addr[victim++] = addr;
return 0;
}
victim = (victim + 1) % NLGA;
}
/* All slots full. Evict the victim. */
last_good_addr[victim] = addr;
victim = (victim + 1) % NLGA;
lga_victim = victim;
return 0;
}
static int
access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write,
void *arg)
{
if (unlikely (write))
{
Debug (16, "mem[%016lx] <- %lx\n", addr, *val);
*(unw_word_t *) addr = *val;
}
else
{
/* validate address */
const struct cursor *c = (const struct cursor *)arg;
if (likely (c != NULL) && unlikely (c->validate)
&& unlikely (validate_mem (addr))) {
Debug (16, "mem[%016lx] -> invalid\n", addr);
return -1;
}
*val = *(unw_word_t *) addr;
Debug (16, "mem[%016lx] -> %lx\n", addr, *val);
}
return 0;
}
static int
access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, int write,
void *arg)
{
unw_word_t *addr;
ucontext_t *uc = ((struct cursor *)arg)->uc;
if (unw_is_fpreg (reg))
goto badreg;
if (!(addr = uc_addr (uc, reg)))
goto badreg;
if (write)
{
*(unw_word_t *) addr = *val;
Debug (12, "%s <- 0x%016lx\n", unw_regname (reg), *val);
}
else
{
*val = *(unw_word_t *) addr;
Debug (12, "%s -> 0x%016lx\n", unw_regname (reg), *val);
}
return 0;
badreg:
Debug (1, "bad register number %u\n", reg);
return -UNW_EBADREG;
}
static int
access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
int write, void *arg)
{
ucontext_t *uc = ((struct cursor *)arg)->uc;
unw_fpreg_t *addr;
if (!unw_is_fpreg (reg))
goto badreg;
if (!(addr = uc_addr (uc, reg)))
goto badreg;
if (write)
{
Debug (12, "%s <- %08lx.%08lx.%08lx\n", unw_regname (reg),
((long *)val)[0], ((long *)val)[1], ((long *)val)[2]);
*(unw_fpreg_t *) addr = *val;
}
else
{
*val = *(unw_fpreg_t *) addr;
Debug (12, "%s -> %08lx.%08lx.%08lx\n", unw_regname (reg),
((long *)val)[0], ((long *)val)[1], ((long *)val)[2]);
}
return 0;
badreg:
Debug (1, "bad register number %u\n", reg);
/* attempt to access a non-preserved register */
return -UNW_EBADREG;
}
static int
get_static_proc_name (unw_addr_space_t as, unw_word_t ip,
char *buf, size_t buf_len, unw_word_t *offp,
void *arg)
{
return _Uelf64_get_proc_name (as, getpid (), ip, buf, buf_len, offp);
}
HIDDEN void
s390x_local_addr_space_init (void)
{
memset (&local_addr_space, 0, sizeof (local_addr_space));
local_addr_space.caching_policy = UNW_CACHE_GLOBAL;
local_addr_space.acc.find_proc_info = dwarf_find_proc_info;
local_addr_space.acc.put_unwind_info = put_unwind_info;
local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
local_addr_space.acc.access_mem = access_mem;
local_addr_space.acc.access_reg = access_reg;
local_addr_space.acc.access_fpreg = access_fpreg;
local_addr_space.acc.resume = s390x_local_resume;
local_addr_space.acc.get_proc_name = get_static_proc_name;
unw_flush_cache (&local_addr_space, 0, 0);
memset (last_good_addr, 0, sizeof (unw_word_t) * NLGA);
lga_victim = 0;
}
#endif /* !UNW_REMOTE_ONLY */

81
src/s390x/Ginit_local.c Normal file
View file

@ -0,0 +1,81 @@
/* libunwind - a platform-independent unwind library
Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P.
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "unwind_i.h"
#include "init.h"
#ifdef UNW_REMOTE_ONLY
PROTECTED int
unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
{
return -UNW_EINVAL;
}
#else /* !UNW_REMOTE_ONLY */
static int
unw_init_local_common (unw_cursor_t *cursor, ucontext_t *uc, unsigned use_prev_instr)
{
struct cursor *c = (struct cursor *) cursor;
if (unlikely (!tdep_init_done))
tdep_init ();
Debug (1, "(cursor=%p)\n", c);
c->dwarf.as = unw_local_addr_space;
c->dwarf.as_arg = c;
c->uc = uc;
c->validate = 0;
return common_init (c, use_prev_instr);
}
PROTECTED int
unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
{
return unw_init_local_common(cursor, uc, 1);
}
PROTECTED int
unw_init_local2 (unw_cursor_t *cursor, ucontext_t *uc, int flag)
{
if (!flag)
{
return unw_init_local_common(cursor, uc, 1);
}
else if (flag == UNW_INIT_SIGNAL_FRAME)
{
return unw_init_local_common(cursor, uc, 0);
}
else
{
return -UNW_EINVAL;
}
}
#endif /* !UNW_REMOTE_ONLY */

57
src/s390x/Ginit_remote.c Normal file
View file

@ -0,0 +1,57 @@
/* libunwind - a platform-independent unwind library
Copyright (c) 2003 Hewlett-Packard Development Company, L.P.
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "init.h"
#include "unwind_i.h"
PROTECTED int
unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg)
{
#ifdef UNW_LOCAL_ONLY
return -UNW_EINVAL;
#else /* !UNW_LOCAL_ONLY */
struct cursor *c = (struct cursor *) cursor;
if (!tdep_init_done)
tdep_init ();
Debug (1, "(cursor=%p)\n", c);
c->dwarf.as = as;
if (as == unw_local_addr_space)
{
c->dwarf.as_arg = c;
c->uc = as_arg;
}
else
{
c->dwarf.as_arg = as_arg;
c->uc = NULL;
}
return common_init (c, 0);
#endif /* !UNW_LOCAL_ONLY */
}

View file

@ -0,0 +1,77 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2012 Tommi Rantala <tt.rantala@gmail.com>
Copyright (C) 2013 Linaro Limited
Copyright (C) 2017 IBM
Modified for s390x by Michael Munday <mike.munday@ibm.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "unwind_i.h"
/* The restorer stub will be a system call:
- rt_sigreturn: svc 173 (0x0aad)
- sigreturn: svc 119 (0x0a77)
*/
PROTECTED int
unw_is_signal_frame (unw_cursor_t *cursor)
{
#ifdef __linux__
struct cursor *c = (struct cursor *) cursor;
unw_word_t w0, ip;
unw_addr_space_t as;
unw_accessors_t *a;
void *arg;
int ret, shift = 48;
as = c->dwarf.as;
a = unw_get_accessors (as);
arg = c->dwarf.as_arg;
/* Align the instruction pointer to 8 bytes so that we guarantee
an 8 byte read from it won't cross a page boundary.
Instructions on s390x are 2 byte aligned. */
ip = c->dwarf.ip & ~7;
shift -= (c->dwarf.ip - ip) * 8;
ret = (*a->access_mem) (as, ip, &w0, 0, arg);
if (ret < 0)
return ret;
/* extract first 2 bytes of the next instruction */
w0 = (w0 >> shift) & 0xffff;
/* sigreturn */
if (w0 == 0x0a77)
return 1;
/* rt_sigreturn */
if (w0 == 0x0aad)
return 2;
return 0;
#else
return -UNW_ENOINFO;
#endif
}

View file

@ -0,0 +1,37 @@
/* libunwind - a platform-independent unwind library
Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P.
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "unwind_i.h"
PROTECTED int
unw_reg_states_iterate (unw_cursor_t *cursor,
unw_reg_states_callback cb, void *token)
{
struct cursor *c = (struct cursor *) cursor;
return dwarf_reg_states_iterate (&c->dwarf, cb, token);
}

116
src/s390x/Gregs.c Normal file
View file

@ -0,0 +1,116 @@
/* libunwind - a platform-independent unwind library
Copyright (c) 2002-2004 Hewlett-Packard Development Company, L.P.
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
Modified for s390x by Michael Munday <mike.munday@ibm.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "unwind_i.h"
HIDDEN int
tdep_access_reg (struct cursor *c, unw_regnum_t reg, unw_word_t *valp,
int write)
{
dwarf_loc_t loc = DWARF_NULL_LOC;
switch (reg)
{
case UNW_S390X_CFA:
if (write)
return -UNW_EREADONLYREG;
*valp = c->dwarf.cfa;
return 0;
case UNW_S390X_R0:
case UNW_S390X_R1:
case UNW_S390X_R2:
case UNW_S390X_R3:
case UNW_S390X_R4:
case UNW_S390X_R5:
case UNW_S390X_R6:
case UNW_S390X_R7:
case UNW_S390X_R8:
case UNW_S390X_R9:
case UNW_S390X_R10:
case UNW_S390X_R11:
case UNW_S390X_R12:
case UNW_S390X_R13:
case UNW_S390X_R14:
case UNW_S390X_IP:
loc = c->dwarf.loc[reg];
break;
case UNW_S390X_R15:
if (write)
return -UNW_EREADONLYREG;
loc = c->dwarf.loc[reg];
break;
default:
Debug (1, "bad register number %u\n", reg);
return -UNW_EBADREG;
}
if (write)
return dwarf_put (&c->dwarf, loc, *valp);
else
return dwarf_get (&c->dwarf, loc, valp);
}
HIDDEN int
tdep_access_fpreg (struct cursor *c, unw_regnum_t reg, unw_fpreg_t *valp,
int write)
{
dwarf_loc_t loc = DWARF_NULL_LOC;
switch (reg)
{
case UNW_S390X_F0:
case UNW_S390X_F1:
case UNW_S390X_F2:
case UNW_S390X_F3:
case UNW_S390X_F4:
case UNW_S390X_F5:
case UNW_S390X_F6:
case UNW_S390X_F7:
case UNW_S390X_F8:
case UNW_S390X_F9:
case UNW_S390X_F10:
case UNW_S390X_F11:
case UNW_S390X_F12:
case UNW_S390X_F13:
case UNW_S390X_F14:
case UNW_S390X_F15:
loc = c->dwarf.loc[reg];
break;
default:
Debug (1, "bad register number %u\n", reg);
return -UNW_EBADREG;
}
if (write)
return dwarf_putfp (&c->dwarf, loc, *valp);
else
return dwarf_getfp (&c->dwarf, loc, valp);
}

160
src/s390x/Gresume.c Normal file
View file

@ -0,0 +1,160 @@
/* libunwind - a platform-independent unwind library
Copyright (c) 2002-2004 Hewlett-Packard Development Company, L.P.
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include <stdlib.h>
#include "unwind_i.h"
#ifndef UNW_REMOTE_ONLY
HIDDEN inline int
s390x_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg)
{
struct cursor *c = (struct cursor *) cursor;
ucontext_t uc = *c->uc;
ucontext_t *rt = NULL;
struct sigcontext *sc = NULL;
int i;
unw_word_t sp, ip;
uc.uc_mcontext.psw.addr = c->dwarf.ip;
/* Ensure c->pi is up-to-date. On x86-64, it's relatively common to
be missing DWARF unwind info. We don't want to fail in that
case, because the frame-chain still would let us do a backtrace
at least. */
dwarf_make_proc_info (&c->dwarf);
switch (c->sigcontext_format)
{
case S390X_SCF_NONE:
Debug (8, "resuming at ip=%llx via setcontext()\n",
(unsigned long long) c->dwarf.ip);
setcontext (&uc);
abort(); /* unreachable */
case S390X_SCF_LINUX_SIGFRAME:
Debug (8, "resuming at ip=%llx via signal trampoline\n",
(unsigned long long) c->dwarf.ip);
sc = (struct sigcontext*)c->sigcontext_addr;
for (i = UNW_S390X_R0; i <= UNW_S390X_R15; ++i)
sc->sregs->regs.gprs[i-UNW_S390X_R0] = uc.uc_mcontext.gregs[i-UNW_S390X_R0];
for (i = UNW_S390X_F0; i <= UNW_S390X_F15; ++i)
sc->sregs->fpregs.fprs[i-UNW_S390X_F0] = uc.uc_mcontext.fpregs.fprs[i-UNW_S390X_F0].d;
sc->sregs->regs.psw.addr = uc.uc_mcontext.psw.addr;
sp = c->sigcontext_sp;
ip = c->sigcontext_pc;
__asm__ __volatile__ (
"lgr 15, %[sp]\n"
"br %[ip]\n"
: : [sp] "r" (sp), [ip] "r" (ip)
);
abort(); /* unreachable */
case S390X_SCF_LINUX_RT_SIGFRAME:
Debug (8, "resuming at ip=%llx via signal trampoline\n",
(unsigned long long) c->dwarf.ip);
rt = (ucontext_t*)c->sigcontext_addr;
for (i = UNW_S390X_R0; i <= UNW_S390X_R15; ++i)
rt->uc_mcontext.gregs[i-UNW_S390X_R0] = uc.uc_mcontext.gregs[i-UNW_S390X_R0];
for (i = UNW_S390X_F0; i <= UNW_S390X_F15; ++i)
rt->uc_mcontext.fpregs.fprs[i-UNW_S390X_F0] = uc.uc_mcontext.fpregs.fprs[i-UNW_S390X_F0];
rt->uc_mcontext.psw.addr = uc.uc_mcontext.psw.addr;
sp = c->sigcontext_sp;
ip = c->sigcontext_pc;
__asm__ __volatile__ (
"lgr 15, %[sp]\n"
"br %[ip]\n"
: : [sp] "r" (sp), [ip] "r" (ip)
);
abort(); /* unreachable */
}
return -UNW_EINVAL;
}
#endif /* !UNW_REMOTE_ONLY */
/* This routine is responsible for copying the register values in
cursor C and establishing them as the current machine state. */
static inline int
establish_machine_state (struct cursor *c)
{
int (*access_reg) (unw_addr_space_t, unw_regnum_t, unw_word_t *,
int write, void *);
int (*access_fpreg) (unw_addr_space_t, unw_regnum_t, unw_fpreg_t *,
int write, void *);
unw_addr_space_t as = c->dwarf.as;
void *arg = c->dwarf.as_arg;
unw_fpreg_t fpval;
unw_word_t val;
int reg;
access_reg = as->acc.access_reg;
access_fpreg = as->acc.access_fpreg;
Debug (8, "copying out cursor state\n");
for (reg = 0; reg <= UNW_REG_LAST; ++reg)
{
Debug (16, "copying %s %d\n", unw_regname (reg), reg);
if (unw_is_fpreg (reg))
{
if (tdep_access_fpreg (c, reg, &fpval, 0) >= 0)
(*access_fpreg) (as, reg, &fpval, 1, arg);
}
else
{
if (tdep_access_reg (c, reg, &val, 0) >= 0)
(*access_reg) (as, reg, &val, 1, arg);
}
}
if (c->dwarf.args_size)
{
if (tdep_access_reg (c, UNW_S390X_R15, &val, 0) >= 0)
{
val += c->dwarf.args_size;
(*access_reg) (as, UNW_S390X_R15, &val, 1, arg);
}
}
return 0;
}
PROTECTED int
unw_resume (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
int ret;
Debug (1, "(cursor=%p)\n", c);
if ((ret = establish_machine_state (c)) < 0)
return ret;
return (*c->dwarf.as->acc.resume) (c->dwarf.as, (unw_cursor_t *) c,
c->dwarf.as_arg);
}

146
src/s390x/Gstep.c Normal file
View file

@ -0,0 +1,146 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2002-2004 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
Modified for s390x by Michael Munday <mike.munday@ibm.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "unwind_i.h"
#include <signal.h>
PROTECTED int
unw_handle_signal_frame (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
int ret, i;
unw_word_t sc_addr, sp, *gprs, *fprs, *psw;
ret = dwarf_get (&c->dwarf, c->dwarf.loc[UNW_S390X_R15], &sp);
if (ret < 0)
return ret;
/* Save the SP and PC to be able to return execution at this point
later in time (unw_resume). */
c->sigcontext_sp = sp;
c->sigcontext_pc = c->dwarf.ip;
switch (c->sigcontext_format)
{
case S390X_SCF_LINUX_SIGFRAME: /* sigreturn */
sc_addr = sp + 160;
gprs = ((struct sigcontext*)sc_addr)->sregs->regs.gprs;
fprs = (unw_word_t*)((struct sigcontext*)sc_addr)->sregs->fpregs.fprs;
psw = &((struct sigcontext*)sc_addr)->sregs->regs.psw.addr;
break;
case S390X_SCF_LINUX_RT_SIGFRAME: /* rt_sigreturn */
sc_addr = sp + sizeof(siginfo_t) + 8 + 160;
gprs = ((ucontext_t*)sc_addr)->uc_mcontext.gregs;
fprs = (unw_word_t*)((ucontext_t*)sc_addr)->uc_mcontext.fpregs.fprs;
psw = &((ucontext_t*)sc_addr)->uc_mcontext.psw.addr;
break;
default:
return -UNW_EUNSPEC;
}
c->sigcontext_addr = sc_addr;
/* Update the dwarf cursor.
Set the location of the registers to the corresponding addresses of the
uc_mcontext / sigcontext structure contents. */
for (i = UNW_S390X_R0; i <= UNW_S390X_R15; ++i)
c->dwarf.loc[i] = DWARF_MEM_LOC (c, (unw_word_t) &gprs[i-UNW_S390X_R0]);
for (i = UNW_S390X_F0; i <= UNW_S390X_F15; ++i)
c->dwarf.loc[i] = DWARF_MEM_LOC (c, (unw_word_t) &fprs[i-UNW_S390X_F0]);
c->dwarf.loc[UNW_S390X_IP] = DWARF_MEM_LOC (c, (unw_word_t) psw);
/* Set SP/CFA and PC/IP.
Normally the default CFA on s390x is r15+160. We do not add that offset
here because dwarf_step will add the offset. */
dwarf_get (&c->dwarf, c->dwarf.loc[UNW_S390X_R15], &c->dwarf.cfa);
dwarf_get (&c->dwarf, c->dwarf.loc[UNW_S390X_IP], &c->dwarf.ip);
c->dwarf.pi_valid = 0;
c->dwarf.use_prev_instr = 0;
return 1;
}
PROTECTED int
unw_step (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
int ret = 0, val = c->validate, sig;
#if CONSERVATIVE_CHECKS
c->validate = 1;
#endif
Debug (1, "(cursor=%p, ip=0x%016lx, cfa=0x%016lx)\n",
c, c->dwarf.ip, c->dwarf.cfa);
/* Try DWARF-based unwinding... */
c->sigcontext_format = S390X_SCF_NONE;
ret = dwarf_step (&c->dwarf);
#if CONSERVATIVE_CHECKS
c->validate = val;
#endif
if (unlikely (ret == -UNW_ENOINFO))
{
/* GCC doesn't currently emit debug information for signal
trampolines on s390x so we check for them explicitly.
If there isn't debug information available we could also
try using the backchain (if available).
Other platforms also detect PLT entries here. That's
tricky to do reliably on s390x so I've left it out for
now. */
/* Memory accesses here are quite likely to be unsafe. */
c->validate = 1;
/* Check if this is a signal frame. */
sig = unw_is_signal_frame (cursor);
if (sig > 0)
{
c->sigcontext_format = sig;
ret = unw_handle_signal_frame (cursor);
}
else
{
c->dwarf.ip = 0;
ret = 0;
}
c->validate = val;
return ret;
}
if (unlikely (ret > 0 && c->dwarf.ip == 0))
return 0;
return ret;
}

View file

@ -0,0 +1,5 @@
#define UNW_LOCAL_ONLY
#include <libunwind.h>
#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
#include "Gapply_reg_state.c"
#endif

View file

@ -0,0 +1,5 @@
#define UNW_LOCAL_ONLY
#include <libunwind.h>
#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
#include "Gcreate_addr_space.c"
#endif

View file

@ -0,0 +1,5 @@
#define UNW_LOCAL_ONLY
#include <libunwind.h>
#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
#include "Gget_proc_info.c"
#endif

View file

@ -0,0 +1,5 @@
#define UNW_LOCAL_ONLY
#include <libunwind.h>
#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
#include "Gget_save_loc.c"
#endif

6
src/s390x/Lglobal.c Normal file
View file

@ -0,0 +1,6 @@
#define UNW_LOCAL_ONLY
#include "config.h"
#include <libunwind.h>
#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
#include "Gglobal.c"
#endif

5
src/s390x/Linit.c Normal file
View file

@ -0,0 +1,5 @@
#define UNW_LOCAL_ONLY
#include <libunwind.h>
#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
#include "Ginit.c"
#endif

5
src/s390x/Linit_local.c Normal file
View file

@ -0,0 +1,5 @@
#define UNW_LOCAL_ONLY
#include <libunwind.h>
#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
#include "Ginit_local.c"
#endif

5
src/s390x/Linit_remote.c Normal file
View file

@ -0,0 +1,5 @@
#define UNW_LOCAL_ONLY
#include <libunwind.h>
#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
#include "Ginit_remote.c"
#endif

View file

@ -0,0 +1,5 @@
#define UNW_LOCAL_ONLY
#include <libunwind.h>
#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
#include "Gis_signal_frame.c"
#endif

View file

@ -0,0 +1,5 @@
#define UNW_LOCAL_ONLY
#include <libunwind.h>
#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
#include "Greg_states_iterate.c"
#endif

5
src/s390x/Lregs.c Normal file
View file

@ -0,0 +1,5 @@
#define UNW_LOCAL_ONLY
#include <libunwind.h>
#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
#include "Gregs.c"
#endif

5
src/s390x/Lresume.c Normal file
View file

@ -0,0 +1,5 @@
#define UNW_LOCAL_ONLY
#include <libunwind.h>
#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
#include "Gresume.c"
#endif

5
src/s390x/Lstep.c Normal file
View file

@ -0,0 +1,5 @@
#define UNW_LOCAL_ONLY
#include <libunwind.h>
#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
#include "Gstep.c"
#endif

74
src/s390x/getcontext.S Normal file
View file

@ -0,0 +1,74 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 Google, Inc
Contributed by Paul Pluzhnikov <ppluzhnikov@google.com>
Copyright (C) 2010 Konstantin Belousov <kib@freebsd.org>
Copyright (C) 2017 IBM
Modified for s390x by Michael Munday <mike.munday@ibm.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
// int _Us390x_getcontext (unw_tdep_context_t *ucp)
.global _Us390x_getcontext
.type _Us390x_getcontext, @function
_Us390x_getcontext:
.cfi_startproc
// Save the minimal set of registers required to restore the
// context. Generally speaking this is just the preserved
// registers but we've also saved the parameter registers
// so that return values can be modified too.
// save PSW address
// (not strictly needed but makes other code simpler)
stg %r14,0x30(%r2)
// floating point parameters (not strictly needed)
std %f0,0x100(%r2)
std %f2,0x110(%r2)
std %f4,0x120(%r2)
std %f6,0x130(%r2)
// floating point preserved registers
stfpc 0xf8(%r2)
std %f8,0x140(%r2)
std %f9,0x148(%r2)
std %f10,0x150(%r2)
std %f11,0x158(%r2)
std %f12,0x160(%r2)
std %f13,0x168(%r2)
std %f14,0x170(%r2)
std %f15,0x178(%r2)
// preserved registers and parameters
lgr %r1,%r2
lghi %r2,0
stmg %r2,%r15,0x48(%r1)
br %r14
.cfi_endproc
.size _Us390x_getcontext, . - _Us390x_getcontext
// We do not need executable stack.
.section .note.GNU-stack,"",@progbits

71
src/s390x/init.h Normal file
View file

@ -0,0 +1,71 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2002 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
Modified for s390x by Michael Munday <mike.munday@ibm.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "unwind_i.h"
static inline int
common_init (struct cursor *c, unsigned use_prev_instr)
{
int ret;
int i;
for (i = UNW_S390X_R0; i <= UNW_S390X_R15; ++i) {
c->dwarf.loc[i] = DWARF_REG_LOC(&c->dwarf, i);
}
for (i = UNW_S390X_F0; i <= UNW_S390X_F15; ++i) {
c->dwarf.loc[i] = DWARF_FPREG_LOC(&c->dwarf, i);
}
/* IP isn't a real register, it is encoded in the PSW */
c->dwarf.loc[UNW_S390X_IP] = DWARF_REG_LOC(&c->dwarf, UNW_S390X_IP);
ret = dwarf_get (&c->dwarf, c->dwarf.loc[UNW_S390X_IP], &c->dwarf.ip);
if (ret < 0)
return ret;
/* Normally the CFA offset on s390x is biased, however this is taken
into account by the CFA offset in dwarf_step, so here we just mark
make it equal to the stack pointer. */
ret = dwarf_get (&c->dwarf, DWARF_REG_LOC (&c->dwarf, UNW_S390X_R15),
&c->dwarf.cfa);
if (ret < 0)
return ret;
c->sigcontext_format = S390X_SCF_NONE;
c->sigcontext_addr = 0;
c->dwarf.args_size = 0;
c->dwarf.stash_frames = 0;
c->dwarf.use_prev_instr = use_prev_instr;
c->dwarf.pi_valid = 0;
c->dwarf.pi_is_dynamic = 0;
c->dwarf.hint = 0;
c->dwarf.prev_rs = 0;
c->dwarf.eh_valid_mask = 0;
return 0;
}

36
src/s390x/is_fpreg.c Normal file
View file

@ -0,0 +1,36 @@
/* libunwind - a platform-independent unwind library
Copyright (c) 2004-2005 Hewlett-Packard Development Company, L.P.
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
Modified for s390x by Michael Munday <mike.munday@ibm.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "libunwind_i.h"
PROTECTED int
unw_is_fpreg (int regnum)
{
/* vector registers? */
return regnum >= UNW_S390X_F0 && regnum <= UNW_S390X_F15;
}

57
src/s390x/regname.c Normal file
View file

@ -0,0 +1,57 @@
/* libunwind - a platform-independent unwind library
Contributed by Max Asbock <masbock@us.ibm.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "unwind_i.h"
static const char *regname[] =
{
[UNW_S390X_R0]="R0",
[UNW_S390X_R1]="R1",
[UNW_S390X_R2]="R2",
[UNW_S390X_R3]="R3",
[UNW_S390X_R4]="R4",
[UNW_S390X_R5]="R5",
[UNW_S390X_R6]="R6",
[UNW_S390X_R7]="R7",
[UNW_S390X_R8]="R8",
[UNW_S390X_R9]="R9",
[UNW_S390X_R10]="R10",
[UNW_S390X_R11]="R11",
[UNW_S390X_R12]="R12",
[UNW_S390X_R13]="R13",
[UNW_S390X_R14]="R14",
[UNW_S390X_R15]="R15",
[UNW_S390X_IP]="IP"
};
PROTECTED const char *
unw_regname (unw_regnum_t reg)
{
if (reg < (unw_regnum_t) ARRAY_SIZE (regname))
return regname[reg];
else
return "???";
}

76
src/s390x/setcontext.S Normal file
View file

@ -0,0 +1,76 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 Google, Inc
Contributed by Paul Pluzhnikov <ppluzhnikov@google.com>
Copyright (C) 2010 Konstantin Belousov <kib@freebsd.org>
Copyright (C) 2017 IBM
Modified for s390x by Michael Munday <mike.munday@ibm.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
// int _Us390x_setcontext (const ucontext_t *ucp)
.global _Us390x_setcontext
.type _Us390x_setcontext, @function
_Us390x_setcontext:
.cfi_startproc
// Must only restore registers saved by getcontext, other fields
// in the ucontext_t might be uninitialised.
// Stop this function being unwound. We are clobbering callee-save
// registers in this function so unwinding it is unsafe.
// Ideally we'd save callee-save registers, update the CFI for them
// and then switch to the new CFI once the context switch is
// complete.
.cfi_undefined %r14
// floating point parameters
ld %f0,0x100(%r2)
ld %f2,0x110(%r2)
ld %f4,0x120(%r2)
ld %f6,0x130(%r2)
// floating point preserved registers
lfpc 0xf8(%r2)
ld %f8,0x140(%r2)
ld %f9,0x148(%r2)
ld %f10,0x150(%r2)
ld %f11,0x158(%r2)
ld %f12,0x160(%r2)
ld %f13,0x168(%r2)
ld %f14,0x170(%r2)
ld %f15,0x178(%r2)
// preserved registers and parameters
lgr %r1,%r2
lmg %r2,%r15,0x48(%r1)
// restore PSW address
lg %r1,0x30(%r1)
br %r1
.cfi_endproc
.size _Us390x_setcontext, . - _Us390x_setcontext
// We do not need executable stack.
.section .note.GNU-stack,"",@progbits

48
src/s390x/unwind_i.h Normal file
View file

@ -0,0 +1,48 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2002, 2005 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
Modified for s390x by Michael Munday <mike.munday@ibm.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#ifndef unwind_i_h
#define unwind_i_h
#include <stdint.h>
#include <libunwind-s390x.h>
#include "libunwind_i.h"
#include <sys/ucontext.h>
#define s390x_lock UNW_OBJ(lock)
#define s390x_local_resume UNW_OBJ(local_resume)
#define s390x_local_addr_space_init UNW_OBJ(local_addr_space_init)
#define setcontext UNW_ARCH_OBJ(setcontext)
extern void s390x_local_addr_space_init (void);
extern int s390x_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg);
extern int setcontext (const ucontext_t *ucp);
#endif /* unwind_i_h */

View file

@ -176,6 +176,14 @@ check_local_unw_abi () {
match _U${plat}_get_exe_image_path match _U${plat}_get_exe_image_path
match ${plat}_lock match ${plat}_lock
;; ;;
s390x)
match _U${plat}_get_elf_image
match _U${plat}_get_exe_image_path
match _U${plat}_is_fpreg
match _UL${plat}_dwarf_search_unwind_table
match _UL${plat}_dwarf_find_unwind_table
match _U${plat}_setcontext
;;
*) *)
match _U${plat}_is_fpreg match _U${plat}_is_fpreg
@ -276,6 +284,13 @@ check_generic_unw_abi () {
match _U${plat}_local_addr_space_init match _U${plat}_local_addr_space_init
match ${plat}_lock match ${plat}_lock
;; ;;
s390x)
match _U${plat}_is_fpreg
match _U${plat}_get_elf_image
match _U${plat}_get_exe_image_path
match _U${plat}_dwarf_search_unwind_table
match _U${plat}_dwarf_find_unwind_table
;;
*) *)
match _U${plat}_is_fpreg match _U${plat}_is_fpreg
match _U${plat}_dwarf_search_unwind_table match _U${plat}_dwarf_search_unwind_table