/* GNU/Linux S/390 specific low level interface, for the remote server
for GDB.
- Copyright (C) 2001-2016 Free Software Foundation, Inc.
+ Copyright (C) 2001-2020 Free Software Foundation, Inc.
This file is part of GDB.
#include "server.h"
#include "linux-low.h"
#include "elf/common.h"
+#include "ax.h"
+#include "tracepoint.h"
#include <asm/ptrace.h>
#include "nat/gdb_ptrace.h"
#define HWCAP_S390_VX 2048
#endif
+#ifndef HWCAP_S390_GS
+#define HWCAP_S390_GS 16384
+#endif
+
#define s390_num_regs 52
static int s390_regmap[] = {
{
/* Convert 4-byte PSW mask to 8 bytes by clearing bit 12 and copying
the basic addressing mode bit from the PSW address. */
- char *addr = alloca (register_size (regcache->tdesc, regno ^ 1));
+ gdb_byte *addr = (gdb_byte *) alloca (register_size (regcache->tdesc, regno ^ 1));
collect_register (regcache, regno, buf);
collect_register (regcache, regno ^ 1, addr);
buf[1] &= ~0x8;
{
/* Convert 8-byte PSW mask to 4 bytes by setting bit 12 and copying
the basic addressing mode into the PSW address. */
- char *mask = alloca (size);
- char *addr = alloca (register_size (regcache->tdesc, regno ^ 1));
+ gdb_byte *mask = (gdb_byte *) alloca (size);
+ gdb_byte *addr = (gdb_byte *) alloca (register_size (regcache->tdesc, regno ^ 1));
memcpy (mask, buf, size);
mask[1] |= 0x8;
supply_register (regcache, regno, mask);
{
/* Convert 8-byte PSW address to 4 bytes by truncating, but
keeping the addressing mode bit (which was set from the mask). */
- char *addr = alloca (size);
+ gdb_byte *addr = (gdb_byte *) alloca (size);
char amode;
collect_register (regcache, regno, addr);
amode = addr[0] & 0x80;
supply_register (regcache, v16 + i, (const char *) buf + 16 * i);
}
+static void
+s390_store_gs (struct regcache *regcache, const void *buf)
+{
+ int gsd = find_regno (regcache->tdesc, "gsd");
+ int i;
+
+ for (i = 0; i < 3; i++)
+ supply_register (regcache, gsd + i, (const char *) buf + 8 * (i + 1));
+}
+
+static void
+s390_store_gsbc (struct regcache *regcache, const void *buf)
+{
+ int bc_gsd = find_regno (regcache->tdesc, "bc_gsd");
+ int i;
+
+ for (i = 0; i < 3; i++)
+ supply_register (regcache, bc_gsd + i, (const char *) buf + 8 * (i + 1));
+}
+
static struct regset_info s390_regsets[] = {
{ 0, 0, 0, 0, GENERAL_REGS, s390_fill_gregset, NULL },
#ifndef __s390x__
EXTENDED_REGS, s390_fill_vxrs_low, s390_store_vxrs_low },
{ PTRACE_GETREGSET, PTRACE_SETREGSET, NT_S390_VXRS_HIGH, 0,
EXTENDED_REGS, s390_fill_vxrs_high, s390_store_vxrs_high },
+ /* Guarded storage registers are read-only. */
+ { PTRACE_GETREGSET, -1, NT_S390_GS_CB, 0, EXTENDED_REGS,
+ NULL, s390_store_gs },
+ { PTRACE_GETREGSET, -1, NT_S390_GS_BC, 0, EXTENDED_REGS,
+ NULL, s390_store_gsbc },
NULL_REGSET
};
}
}
-static unsigned long
-s390_get_hwcap (const struct target_desc *tdesc)
-{
- int wordsize = register_size (tdesc, 0);
- unsigned char *data = alloca (2 * wordsize);
- int offset = 0;
+/* Determine the word size for the given PID, in bytes. */
- while ((*the_target->read_auxv) (offset, data, 2 * wordsize) == 2 * wordsize)
+#ifdef __s390x__
+static int
+s390_get_wordsize (int pid)
+{
+ errno = 0;
+ PTRACE_XFER_TYPE pswm = ptrace (PTRACE_PEEKUSER, pid,
+ (PTRACE_TYPE_ARG3) 0,
+ (PTRACE_TYPE_ARG4) 0);
+ if (errno != 0)
{
- if (wordsize == 4)
- {
- unsigned int *data_p = (unsigned int *)data;
- if (data_p[0] == AT_HWCAP)
- return data_p[1];
- }
- else
- {
- unsigned long *data_p = (unsigned long *)data;
- if (data_p[0] == AT_HWCAP)
- return data_p[1];
- }
-
- offset += 2 * wordsize;
+ warning (_("Couldn't determine word size, assuming 64-bit."));
+ return 8;
}
-
- return 0;
+ /* Derive word size from extended addressing mode (PSW bit 31). */
+ return pswm & (1L << 32) ? 8 : 4;
}
+#else
+#define s390_get_wordsize(pid) 4
+#endif
static int
s390_check_regset (int pid, int regset, int regsize)
{
- gdb_byte *buf = alloca (regsize);
+ void *buf = alloca (regsize);
struct iovec iov;
iov.iov_base = buf;
const struct target_desc *tdesc;
struct regset_info *regset;
- /* Check whether the kernel supports extra register sets. */
+ /* Determine word size and HWCAP. */
int pid = pid_of (current_thread);
+ int wordsize = s390_get_wordsize (pid);
+ unsigned long hwcap = linux_get_hwcap (wordsize);
+
+ /* Check whether the kernel supports extra register sets. */
int have_regset_last_break
= s390_check_regset (pid, NT_S390_LAST_BREAK, 8);
int have_regset_system_call
= s390_check_regset (pid, NT_S390_SYSTEM_CALL, 4);
- int have_regset_tdb = s390_check_regset (pid, NT_S390_TDB, 256);
- int have_regset_vxrs = s390_check_regset (pid, NT_S390_VXRS_LOW, 128)
- && s390_check_regset (pid, NT_S390_VXRS_HIGH, 256);
-
- /* Assume 31-bit inferior process. */
- if (have_regset_system_call)
- tdesc = tdesc_s390_linux32v2;
- else if (have_regset_last_break)
- tdesc = tdesc_s390_linux32v1;
- else
- tdesc = tdesc_s390_linux32;
+ int have_regset_tdb
+ = (s390_check_regset (pid, NT_S390_TDB, 256)
+ && (hwcap & HWCAP_S390_TE) != 0);
+ int have_regset_vxrs
+ = (s390_check_regset (pid, NT_S390_VXRS_LOW, 128)
+ && s390_check_regset (pid, NT_S390_VXRS_HIGH, 256)
+ && (hwcap & HWCAP_S390_VX) != 0);
+ int have_regset_gs
+ = (s390_check_regset (pid, NT_S390_GS_CB, 32)
+ && s390_check_regset (pid, NT_S390_GS_BC, 32)
+ && (hwcap & HWCAP_S390_GS) != 0);
- /* On a 64-bit host, check the low bit of the (31-bit) PSWM
- -- if this is one, we actually have a 64-bit inferior. */
{
#ifdef __s390x__
- unsigned int pswm;
- struct regcache *regcache = new_register_cache (tdesc);
-
- fetch_inferior_registers (regcache, find_regno (tdesc, "pswm"));
- collect_register_by_name (regcache, "pswm", &pswm);
- free_register_cache (regcache);
-
- if (pswm & 1)
+ if (wordsize == 8)
{
- if (have_regset_tdb)
- have_regset_tdb =
- (s390_get_hwcap (tdesc_s390x_linux64v2) & HWCAP_S390_TE) != 0;
- if (have_regset_vxrs)
- have_regset_vxrs =
- (s390_get_hwcap (tdesc_s390x_linux64v2) & HWCAP_S390_VX) != 0;
-
- if (have_regset_vxrs)
+ if (have_regset_gs)
+ tdesc = tdesc_s390x_gs_linux64;
+ else if (have_regset_vxrs)
tdesc = (have_regset_tdb ? tdesc_s390x_tevx_linux64 :
tdesc_s390x_vx_linux64);
else if (have_regset_tdb)
using the full 64-bit GPRs. */
else
#endif
- if (s390_get_hwcap (tdesc) & HWCAP_S390_HIGH_GPRS)
+ if (hwcap & HWCAP_S390_HIGH_GPRS)
{
have_hwcap_s390_high_gprs = 1;
- if (have_regset_tdb)
- have_regset_tdb = (s390_get_hwcap (tdesc) & HWCAP_S390_TE) != 0;
- if (have_regset_vxrs)
- have_regset_vxrs = (s390_get_hwcap (tdesc) & HWCAP_S390_VX) != 0;
-
- if (have_regset_vxrs)
+ if (have_regset_gs)
+ tdesc = tdesc_s390_gs_linux64;
+ else if (have_regset_vxrs)
tdesc = (have_regset_tdb ? tdesc_s390_tevx_linux64 :
tdesc_s390_vx_linux64);
else if (have_regset_tdb)
else
tdesc = tdesc_s390_linux64;
}
+ else
+ {
+ /* Assume 31-bit inferior process. */
+ if (have_regset_system_call)
+ tdesc = tdesc_s390_linux32v2;
+ else if (have_regset_last_break)
+ tdesc = tdesc_s390_linux32v1;
+ else
+ tdesc = tdesc_s390_linux32;
+ }
have_hwcap_s390_vx = have_regset_vxrs;
}
case NT_S390_VXRS_HIGH:
regset->size = have_regset_vxrs ? 256 : 0;
break;
+ case NT_S390_GS_CB:
+ case NT_S390_GS_BC:
+ regset->size = have_regset_gs ? 32 : 0;
default:
break;
}
static void
append_insns (CORE_ADDR *to, size_t len, const unsigned char *buf)
{
- write_inferior_memory (*to, buf, len);
+ target_write_memory (*to, buf, len);
*to += len;
}
return S390_TDESC_VX;
if (tdesc == tdesc_s390x_tevx_linux64)
return S390_TDESC_TEVX;
+ if (tdesc == tdesc_s390x_gs_linux64)
+ return S390_TDESC_GS;
#endif
if (tdesc == tdesc_s390_linux32)
return S390_TDESC_VX;
if (tdesc == tdesc_s390_tevx_linux64)
return S390_TDESC_TEVX;
+ if (tdesc == tdesc_s390_gs_linux64)
+ return S390_TDESC_GS;
return 0;
}
+/* Appends given buffer to current_insn_ptr in the target. */
+
+static void
+add_insns (const unsigned char *start, int len)
+{
+ CORE_ADDR buildaddr = current_insn_ptr;
+
+ if (debug_threads)
+ debug_printf ("Adding %d bytes of insn at %s\n",
+ len, paddress (buildaddr));
+
+ append_insns (&buildaddr, len, start);
+ current_insn_ptr = buildaddr;
+}
+
+/* Register usage in emit:
+
+ - %r0, %r1: temp
+ - %r2: top of stack (high word for 31-bit)
+ - %r3: low word of top of stack (for 31-bit)
+ - %r4, %r5: temp
+ - %r6, %r7, %r8: don't use
+ - %r9: saved arg1
+ - %r10: saved arg2
+ - %r11: frame pointer
+ - %r12: saved top of stack for void_call_2 (high word for 31-bit)
+ - %r13: low word of saved top of stack (for 31-bit)
+ - %r14: return address for calls
+ - %r15: stack pointer
+
+ */
+
+/* The "emit_prologue" emit_ops method for s390. */
+
+static void
+s390_emit_prologue (void)
+{
+ static const unsigned char buf[] = {
+ 0x90, 0x9f, 0xf0, 0x24, /* stm %r9, %r15, 0x24(%r15) */
+ 0x18, 0x92, /* lr %r9, %r2 */
+ 0x18, 0xa3, /* lr %r10, %r3 */
+ 0x18, 0xbf, /* lr %r11, %r15 */
+ };
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_epilogue" emit_ops method for s390. */
+
+static void
+s390_emit_epilogue (void)
+{
+ static const unsigned char buf[] = {
+ 0x90, 0x23, 0xa0, 0x00, /* stm %r2, %r3, 0(%r10) */
+ 0xa7, 0x28, 0x00, 0x00, /* lhi %r2, 0 */
+ 0x98, 0x9f, 0xb0, 0x24, /* lm %r9, %r15, 0x24(%r11) */
+ 0x07, 0xfe, /* br %r14 */
+ };
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_add" emit_ops method for s390. */
+
+static void
+s390_emit_add (void)
+{
+ static const unsigned char buf[] = {
+ 0x5e, 0x30, 0xf0, 0x04, /* al %r3, 4(%r15) */
+ 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x98, /* al %r2, 0(%r15) */
+ 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */
+ };
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_sub" emit_ops method for s390. */
+
+static void
+s390_emit_sub (void)
+{
+ static const unsigned char buf[] = {
+ 0x98, 0x45, 0xf0, 0x00, /* lm %r4, %r5, 0(%r15) */
+ 0x1f, 0x53, /* slr %r5, %r3 */
+ 0xb9, 0x99, 0x00, 0x42, /* slbr %r4, %r2 */
+ 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */
+ 0x18, 0x35, /* lr %r3, %r5 */
+ 0x18, 0x24, /* lr %r2, %r4 */
+ };
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_mul" emit_ops method for s390. */
+
+static void
+s390_emit_mul (void)
+{
+ emit_error = 1;
+}
+
+/* The "emit_lsh" emit_ops method for s390. */
+
+static void
+s390_emit_lsh (void)
+{
+ static const unsigned char buf[] = {
+ 0x18, 0x43, /* lr %r4, %r3 */
+ 0x98, 0x23, 0xf0, 0x00, /* lm %r2, %r3, 0(%r15) */
+ 0x8d, 0x20, 0x40, 0x00, /* sldl %r2, 0(%r4) */
+ 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */
+ };
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_rsh_signed" emit_ops method for s390. */
+
+static void
+s390_emit_rsh_signed (void)
+{
+ static const unsigned char buf[] = {
+ 0x18, 0x43, /* lr %r4, %r3 */
+ 0x98, 0x23, 0xf0, 0x00, /* lm %r2, %r3, 0(%r15) */
+ 0x8e, 0x20, 0x40, 0x00, /* srda %r2, 0(%r4) */
+ 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */
+ };
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_rsh_unsigned" emit_ops method for s390. */
+
+static void
+s390_emit_rsh_unsigned (void)
+{
+ static const unsigned char buf[] = {
+ 0x18, 0x43, /* lr %r4, %r3 */
+ 0x98, 0x23, 0xf0, 0x00, /* lm %r2, %r3, 0(%r15) */
+ 0x8c, 0x20, 0x40, 0x00, /* srdl %r2, 0(%r4) */
+ 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */
+ };
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_ext" emit_ops method for s390. */
+
+static void
+s390_emit_ext (int arg)
+{
+ unsigned char buf[] = {
+ 0x8d, 0x20, 0x00, (unsigned char) (64 - arg), /* sldl %r2, <64-arg> */
+ 0x8e, 0x20, 0x00, (unsigned char) (64 - arg), /* srda %r2, <64-arg> */
+ };
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_log_not" emit_ops method for s390. */
+
+static void
+s390_emit_log_not (void)
+{
+ static const unsigned char buf[] = {
+ 0x16, 0x23, /* or %r2, %r3 */
+ 0xa7, 0x28, 0x00, 0x00, /* lhi %r2, 0 */
+ 0xa7, 0x38, 0x00, 0x00, /* lhi %r3, 0 */
+ 0xa7, 0x74, 0x00, 0x04, /* jne .Lskip */
+ 0xa7, 0x38, 0x00, 0x01, /* lhi %r3, 1 */
+ /* .Lskip: */
+ };
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_bit_and" emit_ops method for s390. */
+
+static void
+s390_emit_bit_and (void)
+{
+ static const unsigned char buf[] = {
+ 0x54, 0x20, 0xf0, 0x00, /* n %r2, 0(%r15) */
+ 0x54, 0x30, 0xf0, 0x04, /* n %r3, 4(%r15) */
+ 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */
+ };
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_bit_or" emit_ops method for s390. */
+
+static void
+s390_emit_bit_or (void)
+{
+ static const unsigned char buf[] = {
+ 0x56, 0x20, 0xf0, 0x00, /* o %r2, 0(%r15) */
+ 0x56, 0x30, 0xf0, 0x04, /* o %r3, 4(%r15) */
+ 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */
+ };
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_bit_xor" emit_ops method for s390. */
+
+static void
+s390_emit_bit_xor (void)
+{
+ static const unsigned char buf[] = {
+ 0x57, 0x20, 0xf0, 0x00, /* x %r2, 0(%r15) */
+ 0x57, 0x30, 0xf0, 0x04, /* x %r3, 4(%r15) */
+ 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */
+ };
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_bit_not" emit_ops method for s390. */
+
+static void
+s390_emit_bit_not (void)
+{
+ static const unsigned char buf[] = {
+ 0xa7, 0x48, 0xff, 0xff, /* lhi %r4, -1 */
+ 0x17, 0x24, /* xr %r2, %r4 */
+ 0x17, 0x34, /* xr %r3, %r4 */
+ };
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_equal" emit_ops method for s390. */
+
+static void
+s390_emit_equal (void)
+{
+ s390_emit_bit_xor ();
+ s390_emit_log_not ();
+}
+
+/* The "emit_less_signed" emit_ops method for s390. */
+
+static void
+s390_emit_less_signed (void)
+{
+ static const unsigned char buf[] = {
+ 0x59, 0x20, 0xf0, 0x00, /* c %r2, 0(%r15) */
+ 0xa7, 0x24, 0x00, 0x0c, /* jh .Lless */
+ 0xa7, 0x44, 0x00, 0x06, /* jl .Lhigh */
+ 0x55, 0x30, 0xf0, 0x04, /* cl %r3, 4(%r15) */
+ 0xa7, 0x24, 0x00, 0x06, /* jh .Lless */
+ /* .Lhigh: */
+ 0xa7, 0x38, 0x00, 0x00, /* lhi %r3, 0 */
+ 0xa7, 0xf4, 0x00, 0x04, /* j .Lend */
+ /* .Lless: */
+ 0xa7, 0x38, 0x00, 0x01, /* lhi %r3, 1 */
+ /* .Lend: */
+ 0xa7, 0x28, 0x00, 0x00, /* lhi %r2, 0 */
+ 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */
+ };
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_less_unsigned" emit_ops method for s390. */
+
+static void
+s390_emit_less_unsigned (void)
+{
+ static const unsigned char buf[] = {
+ 0x55, 0x20, 0xf0, 0x00, /* cl %r2, 0(%r15) */
+ 0xa7, 0x24, 0x00, 0x0c, /* jh .Lless */
+ 0xa7, 0x44, 0x00, 0x06, /* jl .Lhigh */
+ 0x55, 0x30, 0xf0, 0x04, /* cl %r3, 4(%r15) */
+ 0xa7, 0x24, 0x00, 0x06, /* jh .Lless */
+ /* .Lhigh: */
+ 0xa7, 0x38, 0x00, 0x00, /* lhi %r3, 0 */
+ 0xa7, 0xf4, 0x00, 0x04, /* j .Lend */
+ /* .Lless: */
+ 0xa7, 0x38, 0x00, 0x01, /* lhi %r3, 1 */
+ /* .Lend: */
+ 0xa7, 0x28, 0x00, 0x00, /* lhi %r2, 0 */
+ 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */
+ };
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_ref" emit_ops method for s390. */
+
+static void
+s390_emit_ref (int size)
+{
+ static const unsigned char buf1[] = {
+ 0xa7, 0x28, 0x00, 0x00, /* lhi %r2, 0 */
+ 0x43, 0x30, 0x30, 0x00, /* ic %r3, 0(%r3) */
+ };
+ static const unsigned char buf2[] = {
+ 0xa7, 0x28, 0x00, 0x00, /* lhi %r2, 0 */
+ 0x48, 0x30, 0x30, 0x00, /* lh %r3, 0(%r3) */
+ };
+ static const unsigned char buf4[] = {
+ 0xa7, 0x28, 0x00, 0x00, /* lhi %r2, 0 */
+ 0x58, 0x30, 0x30, 0x00, /* l %r3, 0(%r3) */
+ };
+ static const unsigned char buf8[] = {
+ 0x98, 0x23, 0x30, 0x00, /* lm %r2, %r3, 0(%r3) */
+ };
+ switch (size)
+ {
+ case 1:
+ add_insns (buf1, sizeof buf1);
+ break;
+ case 2:
+ add_insns (buf2, sizeof buf2);
+ break;
+ case 4:
+ add_insns (buf4, sizeof buf4);
+ break;
+ case 8:
+ add_insns (buf8, sizeof buf8);
+ break;
+ default:
+ emit_error = 1;
+ }
+}
+
+/* The "emit_if_goto" emit_ops method for s390. */
+
+static void
+s390_emit_if_goto (int *offset_p, int *size_p)
+{
+ static const unsigned char buf[] = {
+ 0x16, 0x23, /* or %r2, %r3 */
+ 0x98, 0x23, 0xf0, 0x00, /* lm %r2, %r3, 0(%r15) */
+ 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */
+ 0xc0, 0x74, 0x00, 0x00, 0x00, 0x00 /* jgne <fillme> */
+ };
+ add_insns (buf, sizeof buf);
+ if (offset_p)
+ *offset_p = 12;
+ if (size_p)
+ *size_p = 4;
+}
+
+/* The "emit_goto" emit_ops method for s390 and s390x. */
+
+static void
+s390_emit_goto (int *offset_p, int *size_p)
+{
+ static const unsigned char buf[] = {
+ 0xc0, 0xf4, 0x00, 0x00, 0x00, 0x00, /* jg <fillme> */
+ };
+ add_insns (buf, sizeof buf);
+ if (offset_p)
+ *offset_p = 2;
+ if (size_p)
+ *size_p = 4;
+}
+
+/* The "write_goto_address" emit_ops method for s390 and s390x. */
+
+static void
+s390_write_goto_address (CORE_ADDR from, CORE_ADDR to, int size)
+{
+ long diff = ((long) (to - (from - 2))) / 2;
+ int sdiff = diff;
+ unsigned char buf[sizeof sdiff];
+
+ /* We're only doing 4-byte sizes at the moment. */
+ if (size != sizeof sdiff || sdiff != diff)
+ {
+ emit_error = 1;
+ return;
+ }
+
+ memcpy (buf, &sdiff, sizeof sdiff);
+ target_write_memory (from, buf, sizeof sdiff);
+}
+
+/* Preparation for emitting a literal pool of given size. Loads the address
+ of the pool into %r1, and jumps over it. Called should emit the pool data
+ immediately afterwards. Used for both s390 and s390x. */
+
+static void
+s390_emit_litpool (int size)
+{
+ static const unsigned char nop[] = {
+ 0x07, 0x07,
+ };
+ unsigned char buf[] = {
+ 0xa7, 0x15, 0x00,
+ (unsigned char) ((size + 4) / 2), /* bras %r1, .Lend+size */
+ /* .Lend: */
+ };
+ if (size == 4)
+ {
+ /* buf needs to start at even halfword for litpool to be aligned */
+ if (current_insn_ptr & 2)
+ add_insns (nop, sizeof nop);
+ }
+ else
+ {
+ while ((current_insn_ptr & 6) != 4)
+ add_insns (nop, sizeof nop);
+ }
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_const" emit_ops method for s390. */
+
+static void
+s390_emit_const (LONGEST num)
+{
+ unsigned long long n = num;
+ unsigned char buf_s[] = {
+ /* lhi %r3, <num> */
+ 0xa7, 0x38,
+ (unsigned char) (num >> 8), (unsigned char) num,
+ /* xr %r2, %r2 */
+ 0x17, 0x22,
+ };
+ static const unsigned char buf_l[] = {
+ 0x98, 0x23, 0x10, 0x00, /* lm %r2, %r3, 0(%r1) */
+ };
+ if (num < 0x8000 && num >= 0)
+ {
+ add_insns (buf_s, sizeof buf_s);
+ }
+ else
+ {
+ s390_emit_litpool (8);
+ add_insns ((unsigned char *) &n, sizeof n);
+ add_insns (buf_l, sizeof buf_l);
+ }
+}
+
+/* The "emit_call" emit_ops method for s390. */
+
+static void
+s390_emit_call (CORE_ADDR fn)
+{
+ unsigned int n = fn;
+ static const unsigned char buf[] = {
+ 0x58, 0x10, 0x10, 0x00, /* l %r1, 0(%r1) */
+ 0xa7, 0xfa, 0xff, 0xa0, /* ahi %r15, -0x60 */
+ 0x0d, 0xe1, /* basr %r14, %r1 */
+ 0xa7, 0xfa, 0x00, 0x60, /* ahi %r15, 0x60 */
+ };
+ s390_emit_litpool (4);
+ add_insns ((unsigned char *) &n, sizeof n);
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_reg" emit_ops method for s390. */
+
+static void
+s390_emit_reg (int reg)
+{
+ unsigned char bufpre[] = {
+ /* lr %r2, %r9 */
+ 0x18, 0x29,
+ /* lhi %r3, <reg> */
+ 0xa7, 0x38, (unsigned char) (reg >> 8), (unsigned char) reg,
+ };
+ add_insns (bufpre, sizeof bufpre);
+ s390_emit_call (get_raw_reg_func_addr ());
+}
+
+/* The "emit_pop" emit_ops method for s390. */
+
+static void
+s390_emit_pop (void)
+{
+ static const unsigned char buf[] = {
+ 0x98, 0x23, 0xf0, 0x00, /* lm %r2, %r3, 0(%r15) */
+ 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */
+ };
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_stack_flush" emit_ops method for s390. */
+
+static void
+s390_emit_stack_flush (void)
+{
+ static const unsigned char buf[] = {
+ 0xa7, 0xfa, 0xff, 0xf8, /* ahi %r15, -8 */
+ 0x90, 0x23, 0xf0, 0x00, /* stm %r2, %r3, 0(%r15) */
+ };
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_zero_ext" emit_ops method for s390. */
+
+static void
+s390_emit_zero_ext (int arg)
+{
+ unsigned char buf[] = {
+ 0x8d, 0x20, 0x00, (unsigned char) (64 - arg), /* sldl %r2, <64-arg> */
+ 0x8c, 0x20, 0x00, (unsigned char) (64 - arg), /* srdl %r2, <64-arg> */
+ };
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_swap" emit_ops method for s390. */
+
+static void
+s390_emit_swap (void)
+{
+ static const unsigned char buf[] = {
+ 0x98, 0x45, 0xf0, 0x00, /* lm %r4, %r5, 0(%r15) */
+ 0x90, 0x23, 0xf0, 0x00, /* stm %r2, %r3, 0(%r15) */
+ 0x18, 0x24, /* lr %r2, %r4 */
+ 0x18, 0x35, /* lr %r3, %r5 */
+ };
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_stack_adjust" emit_ops method for s390. */
+
+static void
+s390_emit_stack_adjust (int n)
+{
+ unsigned char buf[] = {
+ /* ahi %r15, 8*n */
+ 0xa7, 0xfa,
+ (unsigned char ) (n * 8 >> 8), (unsigned char) (n * 8),
+ };
+ add_insns (buf, sizeof buf);
+}
+
+/* Sets %r2 to a 32-bit constant. */
+
+static void
+s390_emit_set_r2 (int arg1)
+{
+ unsigned char buf_s[] = {
+ /* lhi %r2, <arg1> */
+ 0xa7, 0x28, (unsigned char) (arg1 >> 8), (unsigned char) arg1,
+ };
+ static const unsigned char buf_l[] = {
+ 0x58, 0x20, 0x10, 0x00, /* l %r2, 0(%r1) */
+ };
+ if (arg1 < 0x8000 && arg1 >= -0x8000)
+ {
+ add_insns (buf_s, sizeof buf_s);
+ }
+ else
+ {
+ s390_emit_litpool (4);
+ add_insns ((unsigned char *) &arg1, sizeof arg1);
+ add_insns (buf_l, sizeof buf_l);
+ }
+}
+
+/* The "emit_int_call_1" emit_ops method for s390. */
+
+static void
+s390_emit_int_call_1 (CORE_ADDR fn, int arg1)
+{
+ /* FN's prototype is `LONGEST(*fn)(int)'. */
+ s390_emit_set_r2 (arg1);
+ s390_emit_call (fn);
+}
+
+/* The "emit_void_call_2" emit_ops method for s390. */
+
+static void
+s390_emit_void_call_2 (CORE_ADDR fn, int arg1)
+{
+ /* FN's prototype is `void(*fn)(int,LONGEST)'. */
+ static const unsigned char buf[] = {
+ 0x18, 0xc2, /* lr %r12, %r2 */
+ 0x18, 0xd3, /* lr %r13, %r3 */
+ 0x18, 0x43, /* lr %r4, %r3 */
+ 0x18, 0x32, /* lr %r3, %r2 */
+ };
+ static const unsigned char buf2[] = {
+ 0x18, 0x2c, /* lr %r2, %r12 */
+ 0x18, 0x3d, /* lr %r3, %r13 */
+ };
+ add_insns (buf, sizeof buf);
+ s390_emit_set_r2 (arg1);
+ s390_emit_call (fn);
+ add_insns (buf2, sizeof buf2);
+}
+
+/* The "emit_eq_goto" emit_ops method for s390. */
+
+static void
+s390_emit_eq_goto (int *offset_p, int *size_p)
+{
+ static const unsigned char buf[] = {
+ 0x57, 0x20, 0xf0, 0x00, /* x %r2, 0(%r15) */
+ 0x57, 0x30, 0xf0, 0x04, /* x %r3, 4(%r15) */
+ 0x16, 0x23, /* or %r2, %r3 */
+ 0x98, 0x23, 0xf0, 0x08, /* lm %r2, %r3, 8(%r15) */
+ 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */
+ 0xc0, 0x84, 0x00, 0x00, 0x00, 0x00, /* jge <fillme> */
+ };
+ add_insns (buf, sizeof buf);
+ if (offset_p)
+ *offset_p = 20;
+ if (size_p)
+ *size_p = 4;
+}
+
+/* The "emit_ne_goto" emit_ops method for s390. */
+
+static void
+s390_emit_ne_goto (int *offset_p, int *size_p)
+{
+ static const unsigned char buf[] = {
+ 0x57, 0x20, 0xf0, 0x00, /* x %r2, 0(%r15) */
+ 0x57, 0x30, 0xf0, 0x04, /* x %r3, 4(%r15) */
+ 0x16, 0x23, /* or %r2, %r3 */
+ 0x98, 0x23, 0xf0, 0x08, /* lm %r2, %r3, 8(%r15) */
+ 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */
+ 0xc0, 0x74, 0x00, 0x00, 0x00, 0x00, /* jgne <fillme> */
+ };
+ add_insns (buf, sizeof buf);
+ if (offset_p)
+ *offset_p = 20;
+ if (size_p)
+ *size_p = 4;
+}
+
+/* The "emit_lt_goto" emit_ops method for s390. */
+
+static void
+s390_emit_lt_goto (int *offset_p, int *size_p)
+{
+ static const unsigned char buf[] = {
+ 0x59, 0x20, 0xf0, 0x00, /* c %r2, 0(%r15) */
+ 0xa7, 0x24, 0x00, 0x0e, /* jh .Ltrue */
+ 0xa7, 0x44, 0x00, 0x06, /* jl .Lfalse */
+ 0x55, 0x30, 0xf0, 0x04, /* cl %r3, 4(%r15) */
+ 0xa7, 0x24, 0x00, 0x08, /* jh .Ltrue */
+ /* .Lfalse: */
+ 0x98, 0x23, 0xf0, 0x08, /* lm %r2, %r3, 8(%r15) */
+ 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */
+ 0xa7, 0xf4, 0x00, 0x09, /* j .Lend */
+ /* .Ltrue: */
+ 0x98, 0x23, 0xf0, 0x08, /* lm %r2, %r3, 8(%r15) */
+ 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */
+ 0xc0, 0xf4, 0x00, 0x00, 0x00, 0x00, /* jg <fillme> */
+ /* .Lend: */
+ };
+ add_insns (buf, sizeof buf);
+ if (offset_p)
+ *offset_p = 42;
+ if (size_p)
+ *size_p = 4;
+}
+
+/* The "emit_le_goto" emit_ops method for s390. */
+
+static void
+s390_emit_le_goto (int *offset_p, int *size_p)
+{
+ static const unsigned char buf[] = {
+ 0x59, 0x20, 0xf0, 0x00, /* c %r2, 0(%r15) */
+ 0xa7, 0x24, 0x00, 0x0e, /* jh .Ltrue */
+ 0xa7, 0x44, 0x00, 0x06, /* jl .Lfalse */
+ 0x55, 0x30, 0xf0, 0x04, /* cl %r3, 4(%r15) */
+ 0xa7, 0xa4, 0x00, 0x08, /* jhe .Ltrue */
+ /* .Lfalse: */
+ 0x98, 0x23, 0xf0, 0x08, /* lm %r2, %r3, 8(%r15) */
+ 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */
+ 0xa7, 0xf4, 0x00, 0x09, /* j .Lend */
+ /* .Ltrue: */
+ 0x98, 0x23, 0xf0, 0x08, /* lm %r2, %r3, 8(%r15) */
+ 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */
+ 0xc0, 0xf4, 0x00, 0x00, 0x00, 0x00, /* jg <fillme> */
+ /* .Lend: */
+ };
+ add_insns (buf, sizeof buf);
+ if (offset_p)
+ *offset_p = 42;
+ if (size_p)
+ *size_p = 4;
+}
+
+/* The "emit_gt_goto" emit_ops method for s390. */
+
+static void
+s390_emit_gt_goto (int *offset_p, int *size_p)
+{
+ static const unsigned char buf[] = {
+ 0x59, 0x20, 0xf0, 0x00, /* c %r2, 0(%r15) */
+ 0xa7, 0x44, 0x00, 0x0e, /* jl .Ltrue */
+ 0xa7, 0x24, 0x00, 0x06, /* jh .Lfalse */
+ 0x55, 0x30, 0xf0, 0x04, /* cl %r3, 4(%r15) */
+ 0xa7, 0x44, 0x00, 0x08, /* jl .Ltrue */
+ /* .Lfalse: */
+ 0x98, 0x23, 0xf0, 0x08, /* lm %r2, %r3, 8(%r15) */
+ 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */
+ 0xa7, 0xf4, 0x00, 0x09, /* j .Lend */
+ /* .Ltrue: */
+ 0x98, 0x23, 0xf0, 0x08, /* lm %r2, %r3, 8(%r15) */
+ 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */
+ 0xc0, 0xf4, 0x00, 0x00, 0x00, 0x00, /* jg <fillme> */
+ /* .Lend: */
+ };
+ add_insns (buf, sizeof buf);
+ if (offset_p)
+ *offset_p = 42;
+ if (size_p)
+ *size_p = 4;
+}
+
+/* The "emit_ge_goto" emit_ops method for s390. */
+
+static void
+s390_emit_ge_goto (int *offset_p, int *size_p)
+{
+ static const unsigned char buf[] = {
+ 0x59, 0x20, 0xf0, 0x00, /* c %r2, 0(%r15) */
+ 0xa7, 0x44, 0x00, 0x0e, /* jl .Ltrue */
+ 0xa7, 0x24, 0x00, 0x06, /* jh .Lfalse */
+ 0x55, 0x30, 0xf0, 0x04, /* cl %r3, 4(%r15) */
+ 0xa7, 0xc4, 0x00, 0x08, /* jle .Ltrue */
+ /* .Lfalse: */
+ 0x98, 0x23, 0xf0, 0x08, /* lm %r2, %r3, 8(%r15) */
+ 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */
+ 0xa7, 0xf4, 0x00, 0x09, /* j .Lend */
+ /* .Ltrue: */
+ 0x98, 0x23, 0xf0, 0x08, /* lm %r2, %r3, 8(%r15) */
+ 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */
+ 0xc0, 0xf4, 0x00, 0x00, 0x00, 0x00, /* jg <fillme> */
+ /* .Lend: */
+ };
+ add_insns (buf, sizeof buf);
+ if (offset_p)
+ *offset_p = 42;
+ if (size_p)
+ *size_p = 4;
+}
+
+/* The "emit_ops" structure for s390. Named _impl to avoid name
+ collision with s390_emit_ops function. */
+
+static struct emit_ops s390_emit_ops_impl =
+ {
+ s390_emit_prologue,
+ s390_emit_epilogue,
+ s390_emit_add,
+ s390_emit_sub,
+ s390_emit_mul,
+ s390_emit_lsh,
+ s390_emit_rsh_signed,
+ s390_emit_rsh_unsigned,
+ s390_emit_ext,
+ s390_emit_log_not,
+ s390_emit_bit_and,
+ s390_emit_bit_or,
+ s390_emit_bit_xor,
+ s390_emit_bit_not,
+ s390_emit_equal,
+ s390_emit_less_signed,
+ s390_emit_less_unsigned,
+ s390_emit_ref,
+ s390_emit_if_goto,
+ s390_emit_goto,
+ s390_write_goto_address,
+ s390_emit_const,
+ s390_emit_call,
+ s390_emit_reg,
+ s390_emit_pop,
+ s390_emit_stack_flush,
+ s390_emit_zero_ext,
+ s390_emit_swap,
+ s390_emit_stack_adjust,
+ s390_emit_int_call_1,
+ s390_emit_void_call_2,
+ s390_emit_eq_goto,
+ s390_emit_ne_goto,
+ s390_emit_lt_goto,
+ s390_emit_le_goto,
+ s390_emit_gt_goto,
+ s390_emit_ge_goto
+ };
+
+#ifdef __s390x__
+
+/* The "emit_prologue" emit_ops method for s390x. */
+
+static void
+s390x_emit_prologue (void)
+{
+ static const unsigned char buf[] = {
+ 0xeb, 0x9f, 0xf0, 0x48, 0x00, 0x24, /* stmg %r9, %r15, 0x48(%r15) */
+ 0xb9, 0x04, 0x00, 0x92, /* lgr %r9, %r2 */
+ 0xb9, 0x04, 0x00, 0xa3, /* lgr %r10, %r3 */
+ 0xb9, 0x04, 0x00, 0xbf, /* lgr %r11, %r15 */
+ };
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_epilogue" emit_ops method for s390x. */
+
+static void
+s390x_emit_epilogue (void)
+{
+ static const unsigned char buf[] = {
+ 0xe3, 0x20, 0xa0, 0x00, 0x00, 0x24, /* stg %r2, 0(%r10) */
+ 0xa7, 0x29, 0x00, 0x00, /* lghi %r2, 0 */
+ 0xeb, 0x9f, 0xf0, 0x48, 0x00, 0x04, /* lmg %r9, %r15, 0x48(%r15) */
+ 0x07, 0xfe, /* br %r14 */
+ };
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_add" emit_ops method for s390x. */
+
+static void
+s390x_emit_add (void)
+{
+ static const unsigned char buf[] = {
+ 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x0a, /* alg %r2, 0(%r15) */
+ 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */
+ };
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_sub" emit_ops method for s390x. */
+
+static void
+s390x_emit_sub (void)
+{
+ static const unsigned char buf[] = {
+ 0xe3, 0x30, 0xf0, 0x00, 0x00, 0x04, /* lg %r3, 0(%r15) */
+ 0xb9, 0x0b, 0x00, 0x32, /* slgr %r3, %r2 */
+ 0xb9, 0x04, 0x00, 0x23, /* lgr %r2, %r3 */
+ 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */
+ };
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_mul" emit_ops method for s390x. */
+
+static void
+s390x_emit_mul (void)
+{
+ emit_error = 1;
+}
+
+/* The "emit_lsh" emit_ops method for s390x. */
+
+static void
+s390x_emit_lsh (void)
+{
+ static const unsigned char buf[] = {
+ 0xe3, 0x30, 0xf0, 0x00, 0x00, 0x04, /* lg %r3, 0(%r15) */
+ 0xeb, 0x23, 0x20, 0x00, 0x00, 0x0d, /* sllg %r2, %r3, 0(%r2) */
+ 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */
+ };
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_rsh_signed" emit_ops method for s390x. */
+
+static void
+s390x_emit_rsh_signed (void)
+{
+ static const unsigned char buf[] = {
+ 0xe3, 0x30, 0xf0, 0x00, 0x00, 0x04, /* lg %r3, 0(%r15) */
+ 0xeb, 0x23, 0x20, 0x00, 0x00, 0x0a, /* srag %r2, %r3, 0(%r2) */
+ 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */
+ };
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_rsh_unsigned" emit_ops method for s390x. */
+
+static void
+s390x_emit_rsh_unsigned (void)
+{
+ static const unsigned char buf[] = {
+ 0xe3, 0x30, 0xf0, 0x00, 0x00, 0x04, /* lg %r3, 0(%r15) */
+ 0xeb, 0x23, 0x20, 0x00, 0x00, 0x0c, /* srlg %r2, %r3, 0(%r2) */
+ 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */
+ };
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_ext" emit_ops method for s390x. */
+
+static void
+s390x_emit_ext (int arg)
+{
+ unsigned char buf[] = {
+ /* sllg %r2, %r2, <64-arg> */
+ 0xeb, 0x22, 0x00, (unsigned char) (64 - arg), 0x00, 0x0d,
+ /* srag %r2, %r2, <64-arg> */
+ 0xeb, 0x22, 0x00, (unsigned char) (64 - arg), 0x00, 0x0a,
+ };
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_log_not" emit_ops method for s390x. */
+
+static void
+s390x_emit_log_not (void)
+{
+ static const unsigned char buf[] = {
+ 0xb9, 0x00, 0x00, 0x22, /* lpgr %r2, %r2 */
+ 0xa7, 0x2b, 0xff, 0xff, /* aghi %r2, -1 */
+ 0xeb, 0x22, 0x00, 0x3f, 0x00, 0x0c, /* srlg %r2, %r2, 63 */
+ };
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_bit_and" emit_ops method for s390x. */
+
+static void
+s390x_emit_bit_and (void)
+{
+ static const unsigned char buf[] = {
+ 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x80, /* ng %r2, 0(%r15) */
+ 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */
+ };
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_bit_or" emit_ops method for s390x. */
+
+static void
+s390x_emit_bit_or (void)
+{
+ static const unsigned char buf[] = {
+ 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x81, /* og %r2, 0(%r15) */
+ 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */
+ };
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_bit_xor" emit_ops method for s390x. */
+
+static void
+s390x_emit_bit_xor (void)
+{
+ static const unsigned char buf[] = {
+ 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x82, /* xg %r2, 0(%r15) */
+ 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */
+ };
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_bit_not" emit_ops method for s390x. */
+
+static void
+s390x_emit_bit_not (void)
+{
+ static const unsigned char buf[] = {
+ 0xa7, 0x39, 0xff, 0xff, /* lghi %r3, -1 */
+ 0xb9, 0x82, 0x00, 0x23, /* xgr %r2, %r3 */
+ };
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_equal" emit_ops method for s390x. */
+
+static void
+s390x_emit_equal (void)
+{
+ s390x_emit_bit_xor ();
+ s390x_emit_log_not ();
+}
+
+/* The "emit_less_signed" emit_ops method for s390x. */
+
+static void
+s390x_emit_less_signed (void)
+{
+ static const unsigned char buf[] = {
+ 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x20, /* cg %r2, 0(%r15) */
+ 0xa7, 0x29, 0x00, 0x01, /* lghi %r2, 1 */
+ 0xa7, 0x24, 0x00, 0x04, /* jh .Lend */
+ 0xa7, 0x29, 0x00, 0x00, /* lghi %r2, 0 */
+ /* .Lend: */
+ 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */
+ };
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_less_unsigned" emit_ops method for s390x. */
+
+static void
+s390x_emit_less_unsigned (void)
+{
+ static const unsigned char buf[] = {
+ 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x21, /* clg %r2, 0(%r15) */
+ 0xa7, 0x29, 0x00, 0x01, /* lghi %r2, 1 */
+ 0xa7, 0x24, 0x00, 0x04, /* jh .Lend */
+ 0xa7, 0x29, 0x00, 0x00, /* lghi %r2, 0 */
+ /* .Lend: */
+ 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */
+ };
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_ref" emit_ops method for s390x. */
+
+static void
+s390x_emit_ref (int size)
+{
+ static const unsigned char buf1[] = {
+ 0xe3, 0x20, 0x20, 0x00, 0x00, 0x90, /* llgc %r2, 0(%r2) */
+ };
+ static const unsigned char buf2[] = {
+ 0xe3, 0x20, 0x20, 0x00, 0x00, 0x91 /* llgh %r2, 0(%r2) */
+ };
+ static const unsigned char buf4[] = {
+ 0xe3, 0x20, 0x20, 0x00, 0x00, 0x16, /* llgf %r2, 0(%r2) */
+ };
+ static const unsigned char buf8[] = {
+ 0xe3, 0x20, 0x20, 0x00, 0x00, 0x04, /* lg %r2, 0(%r2) */
+ };
+ switch (size)
+ {
+ case 1:
+ add_insns (buf1, sizeof buf1);
+ break;
+ case 2:
+ add_insns (buf2, sizeof buf2);
+ break;
+ case 4:
+ add_insns (buf4, sizeof buf4);
+ break;
+ case 8:
+ add_insns (buf8, sizeof buf8);
+ break;
+ default:
+ emit_error = 1;
+ }
+}
+
+/* The "emit_if_goto" emit_ops method for s390x. */
+
+static void
+s390x_emit_if_goto (int *offset_p, int *size_p)
+{
+ static const unsigned char buf[] = {
+ 0xb9, 0x02, 0x00, 0x22, /* ltgr %r2, %r2 */
+ 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x04, /* lg %r2, 0(%r15) */
+ 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */
+ 0xc0, 0x74, 0x00, 0x00, 0x00, 0x00, /* jgne <fillme> */
+ };
+ add_insns (buf, sizeof buf);
+ if (offset_p)
+ *offset_p = 16;
+ if (size_p)
+ *size_p = 4;
+}
+
+/* The "emit_const" emit_ops method for s390x. */
+
+static void
+s390x_emit_const (LONGEST num)
+{
+ unsigned long long n = num;
+ unsigned char buf_s[] = {
+ /* lghi %r2, <num> */
+ 0xa7, 0x29, (unsigned char) (num >> 8), (unsigned char) num,
+ };
+ static const unsigned char buf_l[] = {
+ 0xe3, 0x20, 0x10, 0x00, 0x00, 0x04, /* lg %r2, 0(%r1) */
+ };
+ if (num < 0x8000 && num >= -0x8000)
+ {
+ add_insns (buf_s, sizeof buf_s);
+ }
+ else
+ {
+ s390_emit_litpool (8);
+ add_insns ((unsigned char *) &n, sizeof n);
+ add_insns (buf_l, sizeof buf_l);
+ }
+}
+
+/* The "emit_call" emit_ops method for s390x. */
+
+static void
+s390x_emit_call (CORE_ADDR fn)
+{
+ unsigned long n = fn;
+ static const unsigned char buf[] = {
+ 0xe3, 0x10, 0x10, 0x00, 0x00, 0x04, /* lg %r1, 0(%r1) */
+ 0xa7, 0xfb, 0xff, 0x60, /* aghi %r15, -0xa0 */
+ 0x0d, 0xe1, /* basr %r14, %r1 */
+ 0xa7, 0xfb, 0x00, 0xa0, /* aghi %r15, 0xa0 */
+ };
+ s390_emit_litpool (8);
+ add_insns ((unsigned char *) &n, sizeof n);
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_reg" emit_ops method for s390x. */
+
+static void
+s390x_emit_reg (int reg)
+{
+ unsigned char buf[] = {
+ /* lgr %r2, %r9 */
+ 0xb9, 0x04, 0x00, 0x29,
+ /* lghi %r3, <reg> */
+ 0xa7, 0x39, (unsigned char) (reg >> 8), (unsigned char) reg,
+ };
+ add_insns (buf, sizeof buf);
+ s390x_emit_call (get_raw_reg_func_addr ());
+}
+
+/* The "emit_pop" emit_ops method for s390x. */
+
+static void
+s390x_emit_pop (void)
+{
+ static const unsigned char buf[] = {
+ 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x04, /* lg %r2, 0(%r15) */
+ 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */
+ };
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_stack_flush" emit_ops method for s390x. */
+
+static void
+s390x_emit_stack_flush (void)
+{
+ static const unsigned char buf[] = {
+ 0xa7, 0xfb, 0xff, 0xf8, /* aghi %r15, -8 */
+ 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x24, /* stg %r2, 0(%r15) */
+ };
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_zero_ext" emit_ops method for s390x. */
+
+static void
+s390x_emit_zero_ext (int arg)
+{
+ unsigned char buf[] = {
+ /* sllg %r2, %r2, <64-arg> */
+ 0xeb, 0x22, 0x00, (unsigned char) (64 - arg), 0x00, 0x0d,
+ /* srlg %r2, %r2, <64-arg> */
+ 0xeb, 0x22, 0x00, (unsigned char) (64 - arg), 0x00, 0x0c,
+ };
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_swap" emit_ops method for s390x. */
+
+static void
+s390x_emit_swap (void)
+{
+ static const unsigned char buf[] = {
+ 0xe3, 0x30, 0xf0, 0x00, 0x00, 0x04, /* lg %r3, 0(%r15) */
+ 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x24, /* stg %r2, 0(%r15) */
+ 0xb9, 0x04, 0x00, 0x23, /* lgr %r2, %r3 */
+ };
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_stack_adjust" emit_ops method for s390x. */
+
+static void
+s390x_emit_stack_adjust (int n)
+{
+ unsigned char buf[] = {
+ /* aghi %r15, 8*n */
+ 0xa7, 0xfb,
+ (unsigned char) (n * 8 >> 8), (unsigned char) (n * 8),
+ };
+ add_insns (buf, sizeof buf);
+}
+
+/* The "emit_int_call_1" emit_ops method for s390x. */
+
+static void
+s390x_emit_int_call_1 (CORE_ADDR fn, int arg1)
+{
+ /* FN's prototype is `LONGEST(*fn)(int)'. */
+ s390x_emit_const (arg1);
+ s390x_emit_call (fn);
+}
+
+/* The "emit_void_call_2" emit_ops method for s390x. */
+
+static void
+s390x_emit_void_call_2 (CORE_ADDR fn, int arg1)
+{
+ /* FN's prototype is `void(*fn)(int,LONGEST)'. */
+ static const unsigned char buf[] = {
+ 0xb9, 0x04, 0x00, 0x32, /* lgr %r3, %r2 */
+ 0xb9, 0x04, 0x00, 0xc2, /* lgr %r12, %r2 */
+ };
+ static const unsigned char buf2[] = {
+ 0xb9, 0x04, 0x00, 0x2c, /* lgr %r2, %r12 */
+ };
+ add_insns (buf, sizeof buf);
+ s390x_emit_const (arg1);
+ s390x_emit_call (fn);
+ add_insns (buf2, sizeof buf2);
+}
+
+/* The "emit_eq_goto" emit_ops method for s390x. */
+
+static void
+s390x_emit_eq_goto (int *offset_p, int *size_p)
+{
+ static const unsigned char buf[] = {
+ 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x20, /* cg %r2, 0(%r15) */
+ 0xe3, 0x20, 0xf0, 0x08, 0x00, 0x04, /* lg %r2, 8(%r15) */
+ 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */
+ 0xc0, 0x84, 0x00, 0x00, 0x00, 0x00, /* jge <fillme> */
+ };
+ add_insns (buf, sizeof buf);
+ if (offset_p)
+ *offset_p = 18;
+ if (size_p)
+ *size_p = 4;
+}
+
+/* The "emit_ne_goto" emit_ops method for s390x. */
+
+static void
+s390x_emit_ne_goto (int *offset_p, int *size_p)
+{
+ static const unsigned char buf[] = {
+ 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x20, /* cg %r2, 0(%r15) */
+ 0xe3, 0x20, 0xf0, 0x08, 0x00, 0x04, /* lg %r2, 8(%r15) */
+ 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */
+ 0xc0, 0x74, 0x00, 0x00, 0x00, 0x00, /* jgne <fillme> */
+ };
+ add_insns (buf, sizeof buf);
+ if (offset_p)
+ *offset_p = 18;
+ if (size_p)
+ *size_p = 4;
+}
+
+/* The "emit_lt_goto" emit_ops method for s390x. */
+
+static void
+s390x_emit_lt_goto (int *offset_p, int *size_p)
+{
+ static const unsigned char buf[] = {
+ 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x20, /* cg %r2, 0(%r15) */
+ 0xe3, 0x20, 0xf0, 0x08, 0x00, 0x04, /* lg %r2, 8(%r15) */
+ 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */
+ 0xc0, 0x24, 0x00, 0x00, 0x00, 0x00, /* jgh <fillme> */
+ };
+ add_insns (buf, sizeof buf);
+ if (offset_p)
+ *offset_p = 18;
+ if (size_p)
+ *size_p = 4;
+}
+
+/* The "emit_le_goto" emit_ops method for s390x. */
+
+static void
+s390x_emit_le_goto (int *offset_p, int *size_p)
+{
+ static const unsigned char buf[] = {
+ 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x20, /* cg %r2, 0(%r15) */
+ 0xe3, 0x20, 0xf0, 0x08, 0x00, 0x04, /* lg %r2, 8(%r15) */
+ 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */
+ 0xc0, 0xa4, 0x00, 0x00, 0x00, 0x00, /* jghe <fillme> */
+ };
+ add_insns (buf, sizeof buf);
+ if (offset_p)
+ *offset_p = 18;
+ if (size_p)
+ *size_p = 4;
+}
+
+/* The "emit_gt_goto" emit_ops method for s390x. */
+
+static void
+s390x_emit_gt_goto (int *offset_p, int *size_p)
+{
+ static const unsigned char buf[] = {
+ 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x20, /* cg %r2, 0(%r15) */
+ 0xe3, 0x20, 0xf0, 0x08, 0x00, 0x04, /* lg %r2, 8(%r15) */
+ 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */
+ 0xc0, 0x44, 0x00, 0x00, 0x00, 0x00, /* jgl <fillme> */
+ };
+ add_insns (buf, sizeof buf);
+ if (offset_p)
+ *offset_p = 18;
+ if (size_p)
+ *size_p = 4;
+}
+
+/* The "emit_ge_goto" emit_ops method for s390x. */
+
+static void
+s390x_emit_ge_goto (int *offset_p, int *size_p)
+{
+ static const unsigned char buf[] = {
+ 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x20, /* cg %r2, 0(%r15) */
+ 0xe3, 0x20, 0xf0, 0x08, 0x00, 0x04, /* lg %r2, 8(%r15) */
+ 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */
+ 0xc0, 0xc4, 0x00, 0x00, 0x00, 0x00, /* jgle <fillme> */
+ };
+ add_insns (buf, sizeof buf);
+ if (offset_p)
+ *offset_p = 18;
+ if (size_p)
+ *size_p = 4;
+}
+
+/* The "emit_ops" structure for s390x. */
+
+static struct emit_ops s390x_emit_ops =
+ {
+ s390x_emit_prologue,
+ s390x_emit_epilogue,
+ s390x_emit_add,
+ s390x_emit_sub,
+ s390x_emit_mul,
+ s390x_emit_lsh,
+ s390x_emit_rsh_signed,
+ s390x_emit_rsh_unsigned,
+ s390x_emit_ext,
+ s390x_emit_log_not,
+ s390x_emit_bit_and,
+ s390x_emit_bit_or,
+ s390x_emit_bit_xor,
+ s390x_emit_bit_not,
+ s390x_emit_equal,
+ s390x_emit_less_signed,
+ s390x_emit_less_unsigned,
+ s390x_emit_ref,
+ s390x_emit_if_goto,
+ s390_emit_goto,
+ s390_write_goto_address,
+ s390x_emit_const,
+ s390x_emit_call,
+ s390x_emit_reg,
+ s390x_emit_pop,
+ s390x_emit_stack_flush,
+ s390x_emit_zero_ext,
+ s390x_emit_swap,
+ s390x_emit_stack_adjust,
+ s390x_emit_int_call_1,
+ s390x_emit_void_call_2,
+ s390x_emit_eq_goto,
+ s390x_emit_ne_goto,
+ s390x_emit_lt_goto,
+ s390x_emit_le_goto,
+ s390x_emit_gt_goto,
+ s390x_emit_ge_goto
+ };
+#endif
+
+/* The "emit_ops" linux_target_ops method. */
+
+static struct emit_ops *
+s390_emit_ops (void)
+{
+#ifdef __s390x__
+ struct regcache *regcache = get_thread_regcache (current_thread, 0);
+
+ if (register_size (regcache->tdesc, 0) == 8)
+ return &s390x_emit_ops;
+ else
+#endif
+ return &s390_emit_ops_impl;
+}
+
struct linux_target_ops the_low_target = {
s390_arch_setup,
s390_regs_info,
s390_supply_ptrace_register,
NULL, /* siginfo_fixup */
NULL, /* new_process */
+ NULL, /* delete_process */
NULL, /* new_thread */
+ NULL, /* delete_thread */
NULL, /* new_fork */
NULL, /* prepare_to_resume */
NULL, /* process_qsupported */
s390_supports_tracepoints,
s390_get_thread_area,
s390_install_fast_tracepoint_jump_pad,
- NULL, /* emit_ops */
+ s390_emit_ops,
s390_get_min_fast_tracepoint_insn_len,
NULL, /* supports_range_stepping */
NULL, /* breakpoint_kind_from_current_state */
init_registers_s390_te_linux64 ();
init_registers_s390_vx_linux64 ();
init_registers_s390_tevx_linux64 ();
+ init_registers_s390_gs_linux64 ();
#ifdef __s390x__
init_registers_s390x_linux64 ();
init_registers_s390x_linux64v1 ();
init_registers_s390x_te_linux64 ();
init_registers_s390x_vx_linux64 ();
init_registers_s390x_tevx_linux64 ();
+ init_registers_s390x_gs_linux64 ();
#endif
initialize_regsets_info (&s390_regsets_info);