blob: 6687127d0aa4ec87947a4b745ae6a2d02fd2db82 [file] [log] [blame]
/* Target-dependent code for s390.
Copyright (C) 2001-2024 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "arch-utils.h"
#include "ax-gdb.h"
#include "dwarf2/frame.h"
#include "elf/s390.h"
#include "elf-bfd.h"
#include "extract-store-integer.h"
#include "frame-base.h"
#include "frame-unwind.h"
#include "gdbarch.h"
#include "gdbcore.h"
#include "infrun.h"
#include "linux-tdep.h"
#include "objfiles.h"
#include "osabi.h"
#include "record-full.h"
#include "regcache.h"
#include "reggroups.h"
#include "s390-tdep.h"
#include "target-descriptions.h"
#include "trad-frame.h"
#include "value.h"
#include "inferior.h"
#include "features/s390-linux32.c"
#include "features/s390x-linux64.c"
/* Holds the current set of options to be passed to the disassembler. */
static std::string s390_disassembler_options;
/* Breakpoints. */
constexpr gdb_byte s390_break_insn[] = { 0x0, 0x1 };
typedef BP_MANIPULATION (s390_break_insn) s390_breakpoint;
/* Types. */
/* Implement the gdbarch type alignment method. */
static ULONGEST
s390_type_align (gdbarch *gdbarch, struct type *t)
{
t = check_typedef (t);
if (t->length () > 8)
{
switch (t->code ())
{
case TYPE_CODE_INT:
case TYPE_CODE_RANGE:
case TYPE_CODE_FLT:
case TYPE_CODE_ENUM:
case TYPE_CODE_CHAR:
case TYPE_CODE_BOOL:
case TYPE_CODE_DECFLOAT:
return 8;
case TYPE_CODE_ARRAY:
if (t->is_vector ())
return 8;
break;
}
}
return 0;
}
/* Decoding S/390 instructions. */
/* Read a single instruction from address AT. */
static int
s390_readinstruction (bfd_byte instr[], CORE_ADDR at)
{
static int s390_instrlen[] = { 2, 4, 4, 6 };
int instrlen;
if (target_read_memory (at, &instr[0], 2))
return -1;
instrlen = s390_instrlen[instr[0] >> 6];
if (instrlen > 2)
{
if (target_read_memory (at + 2, &instr[2], instrlen - 2))
return -1;
}
return instrlen;
}
/* The functions below are for recognizing and decoding S/390
instructions of various formats. Each of them checks whether INSN
is an instruction of the given format, with the specified opcodes.
If it is, it sets the remaining arguments to the values of the
instruction's fields, and returns a non-zero value; otherwise, it
returns zero.
These functions' arguments appear in the order they appear in the
instruction, not in the machine-language form. So, opcodes always
come first, even though they're sometimes scattered around the
instructions. And displacements appear before base and extension
registers, as they do in the assembly syntax, not at the end, as
they do in the machine language.
Test for RI instruction format. */
static int
is_ri (bfd_byte *insn, int op1, int op2, unsigned int *r1, int *i2)
{
if (insn[0] == op1 && (insn[1] & 0xf) == op2)
{
*r1 = (insn[1] >> 4) & 0xf;
/* i2 is a 16-bit signed quantity. */
*i2 = (((insn[2] << 8) | insn[3]) ^ 0x8000) - 0x8000;
return 1;
}
else
return 0;
}
/* Test for RIL instruction format. See comment on is_ri for details. */
static int
is_ril (bfd_byte *insn, int op1, int op2,
unsigned int *r1, int *i2)
{
if (insn[0] == op1 && (insn[1] & 0xf) == op2)
{
*r1 = (insn[1] >> 4) & 0xf;
/* i2 is a signed quantity. If the host 'int' is 32 bits long,
no sign extension is necessary, but we don't want to assume
that. */
*i2 = (((insn[2] << 24)
| (insn[3] << 16)
| (insn[4] << 8)
| (insn[5])) ^ 0x80000000) - 0x80000000;
return 1;
}
else
return 0;
}
/* Test for RR instruction format. See comment on is_ri for details. */
static int
is_rr (bfd_byte *insn, int op, unsigned int *r1, unsigned int *r2)
{
if (insn[0] == op)
{
*r1 = (insn[1] >> 4) & 0xf;
*r2 = insn[1] & 0xf;
return 1;
}
else
return 0;
}
/* Test for RRE instruction format. See comment on is_ri for details. */
static int
is_rre (bfd_byte *insn, int op, unsigned int *r1, unsigned int *r2)
{
if (((insn[0] << 8) | insn[1]) == op)
{
/* Yes, insn[3]. insn[2] is unused in RRE format. */
*r1 = (insn[3] >> 4) & 0xf;
*r2 = insn[3] & 0xf;
return 1;
}
else
return 0;
}
/* Test for RS instruction format. See comment on is_ri for details. */
static int
is_rs (bfd_byte *insn, int op,
unsigned int *r1, unsigned int *r3, int *d2, unsigned int *b2)
{
if (insn[0] == op)
{
*r1 = (insn[1] >> 4) & 0xf;
*r3 = insn[1] & 0xf;
*b2 = (insn[2] >> 4) & 0xf;
*d2 = ((insn[2] & 0xf) << 8) | insn[3];
return 1;
}
else
return 0;
}
/* Test for RSY instruction format. See comment on is_ri for details. */
static int
is_rsy (bfd_byte *insn, int op1, int op2,
unsigned int *r1, unsigned int *r3, int *d2, unsigned int *b2)
{
if (insn[0] == op1
&& insn[5] == op2)
{
*r1 = (insn[1] >> 4) & 0xf;
*r3 = insn[1] & 0xf;
*b2 = (insn[2] >> 4) & 0xf;
/* The 'long displacement' is a 20-bit signed integer. */
*d2 = ((((insn[2] & 0xf) << 8) | insn[3] | (insn[4] << 12))
^ 0x80000) - 0x80000;
return 1;
}
else
return 0;
}
/* Test for RX instruction format. See comment on is_ri for details. */
static int
is_rx (bfd_byte *insn, int op,
unsigned int *r1, int *d2, unsigned int *x2, unsigned int *b2)
{
if (insn[0] == op)
{
*r1 = (insn[1] >> 4) & 0xf;
*x2 = insn[1] & 0xf;
*b2 = (insn[2] >> 4) & 0xf;
*d2 = ((insn[2] & 0xf) << 8) | insn[3];
return 1;
}
else
return 0;
}
/* Test for RXY instruction format. See comment on is_ri for details. */
static int
is_rxy (bfd_byte *insn, int op1, int op2,
unsigned int *r1, int *d2, unsigned int *x2, unsigned int *b2)
{
if (insn[0] == op1
&& insn[5] == op2)
{
*r1 = (insn[1] >> 4) & 0xf;
*x2 = insn[1] & 0xf;
*b2 = (insn[2] >> 4) & 0xf;
/* The 'long displacement' is a 20-bit signed integer. */
*d2 = ((((insn[2] & 0xf) << 8) | insn[3] | (insn[4] << 12))
^ 0x80000) - 0x80000;
return 1;
}
else
return 0;
}
/* A helper for s390_software_single_step, decides if an instruction
is a partial-execution instruction that needs to be executed until
completion when in record mode. If it is, returns 1 and writes
instruction length to a pointer. */
static int
s390_is_partial_instruction (struct gdbarch *gdbarch, CORE_ADDR loc, int *len)
{
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
uint16_t insn;
insn = read_memory_integer (loc, 2, byte_order);
switch (insn >> 8)
{
case 0xa8: /* MVCLE */
*len = 4;
return 1;
case 0xeb:
{
insn = read_memory_integer (loc + 4, 2, byte_order);
if ((insn & 0xff) == 0x8e)
{
/* MVCLU */
*len = 6;
return 1;
}
}
break;
}
switch (insn)
{
case 0xb255: /* MVST */
case 0xb263: /* CMPSC */
case 0xb2a5: /* TRE */
case 0xb2a6: /* CU21 */
case 0xb2a7: /* CU12 */
case 0xb9b0: /* CU14 */
case 0xb9b1: /* CU24 */
case 0xb9b2: /* CU41 */
case 0xb9b3: /* CU42 */
case 0xb92a: /* KMF */
case 0xb92b: /* KMO */
case 0xb92f: /* KMC */
case 0xb92d: /* KMCTR */
case 0xb92e: /* KM */
case 0xb93c: /* PPNO */
case 0xb990: /* TRTT */
case 0xb991: /* TRTO */
case 0xb992: /* TROT */
case 0xb993: /* TROO */
*len = 4;
return 1;
}
return 0;
}
/* Implement the "software_single_step" gdbarch method, needed to single step
through instructions like MVCLE in record mode, to make sure they are
executed to completion. Without that, record will save the full length
of destination buffer on every iteration, even though the CPU will only
process about 4kiB of it each time, leading to O(n**2) memory and time
complexity. */
static std::vector<CORE_ADDR>
s390_software_single_step (struct regcache *regcache)
{
struct gdbarch *gdbarch = regcache->arch ();
CORE_ADDR loc = regcache_read_pc (regcache);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
int len;
uint16_t insn;
/* Special handling only if recording. */
if (!record_full_is_used ())
return {};
/* First, match a partial instruction. */
if (!s390_is_partial_instruction (gdbarch, loc, &len))
return {};
loc += len;
/* Second, look for a branch back to it. */
insn = read_memory_integer (loc, 2, byte_order);
if (insn != 0xa714) /* BRC with mask 1 */
return {};
insn = read_memory_integer (loc + 2, 2, byte_order);
if (insn != (uint16_t) -(len / 2))
return {};
loc += 4;
/* Found it, step past the whole thing. */
return {loc};
}
/* Displaced stepping. */
/* Return true if INSN is a non-branch RIL-b or RIL-c format
instruction. */
static int
is_non_branch_ril (gdb_byte *insn)
{
gdb_byte op1 = insn[0];
if (op1 == 0xc4)
{
gdb_byte op2 = insn[1] & 0x0f;
switch (op2)
{
case 0x02: /* llhrl */
case 0x04: /* lghrl */
case 0x05: /* lhrl */
case 0x06: /* llghrl */
case 0x07: /* sthrl */
case 0x08: /* lgrl */
case 0x0b: /* stgrl */
case 0x0c: /* lgfrl */
case 0x0d: /* lrl */
case 0x0e: /* llgfrl */
case 0x0f: /* strl */
return 1;
}
}
else if (op1 == 0xc6)
{
gdb_byte op2 = insn[1] & 0x0f;
switch (op2)
{
case 0x00: /* exrl */
case 0x02: /* pfdrl */
case 0x04: /* cghrl */
case 0x05: /* chrl */
case 0x06: /* clghrl */
case 0x07: /* clhrl */
case 0x08: /* cgrl */
case 0x0a: /* clgrl */
case 0x0c: /* cgfrl */
case 0x0d: /* crl */
case 0x0e: /* clgfrl */
case 0x0f: /* clrl */
return 1;
}
}
return 0;
}
typedef buf_displaced_step_copy_insn_closure
s390_displaced_step_copy_insn_closure;
/* Implementation of gdbarch_displaced_step_copy_insn. */
static displaced_step_copy_insn_closure_up
s390_displaced_step_copy_insn (struct gdbarch *gdbarch,
CORE_ADDR from, CORE_ADDR to,
struct regcache *regs)
{
size_t len = gdbarch_max_insn_length (gdbarch);
std::unique_ptr<s390_displaced_step_copy_insn_closure> closure
(new s390_displaced_step_copy_insn_closure (len));
gdb_byte *buf = closure->buf.data ();
read_memory (from, buf, len);
/* Adjust the displacement field of PC-relative RIL instructions,
except branches. The latter are handled in the fixup hook. */
if (is_non_branch_ril (buf))
{
LONGEST offset;
offset = extract_signed_integer (buf + 2, 4, BFD_ENDIAN_BIG);
offset = (from - to + offset * 2) / 2;
/* If the instruction is too far from the jump pad, punt. This
will usually happen with instructions in shared libraries.
We could probably support these by rewriting them to be
absolute or fully emulating them. */
if (offset < INT32_MIN || offset > INT32_MAX)
{
/* Let the core fall back to stepping over the breakpoint
in-line. */
displaced_debug_printf ("can't displaced step RIL instruction: offset "
"%s out of range", plongest (offset));
return NULL;
}
store_signed_integer (buf + 2, 4, BFD_ENDIAN_BIG, offset);
}
write_memory (to, buf, len);
displaced_debug_printf ("copy %s->%s: %s",
paddress (gdbarch, from), paddress (gdbarch, to),
bytes_to_string (buf, len).c_str ());
/* This is a work around for a problem with g++ 4.8. */
return displaced_step_copy_insn_closure_up (closure.release ());
}
/* Fix up the state of registers and memory after having single-stepped
a displaced instruction. */
static void
s390_displaced_step_fixup (struct gdbarch *gdbarch,
displaced_step_copy_insn_closure *closure_,
CORE_ADDR from, CORE_ADDR to,
struct regcache *regs, bool completed_p)
{
CORE_ADDR pc = regcache_read_pc (regs);
/* If the displaced instruction didn't complete successfully then all we
need to do is restore the program counter. */
if (!completed_p)
{
pc = from + (pc - to);
regcache_write_pc (regs, pc);
return;
}
/* Our closure is a copy of the instruction. */
s390_displaced_step_copy_insn_closure *closure
= (s390_displaced_step_copy_insn_closure *) closure_;
gdb_byte *insn = closure->buf.data ();
static int s390_instrlen[] = { 2, 4, 4, 6 };
int insnlen = s390_instrlen[insn[0] >> 6];
/* Fields for various kinds of instructions. */
unsigned int b2, r1, r2, x2, r3;
int i2, d2;
/* Get addressing mode bit. */
ULONGEST amode = 0;
if (register_size (gdbarch, S390_PSWA_REGNUM) == 4)
{
regcache_cooked_read_unsigned (regs, S390_PSWA_REGNUM, &amode);
amode &= 0x80000000;
}
displaced_debug_printf ("(s390) fixup (%s, %s) pc %s len %d amode 0x%x",
paddress (gdbarch, from), paddress (gdbarch, to),
paddress (gdbarch, pc), insnlen, (int) amode);
/* Handle absolute branch and save instructions. */
int op_basr_p = is_rr (insn, op_basr, &r1, &r2);
if (op_basr_p
|| is_rx (insn, op_bas, &r1, &d2, &x2, &b2))
{
/* Recompute saved return address in R1. */
regcache_cooked_write_unsigned (regs, S390_R0_REGNUM + r1,
amode | (from + insnlen));
/* Update PC iff the instruction doesn't actually branch. */
if (op_basr_p && r2 == 0)
regcache_write_pc (regs, from + insnlen);
}
/* Handle absolute branch instructions. */
else if (is_rr (insn, op_bcr, &r1, &r2)
|| is_rx (insn, op_bc, &r1, &d2, &x2, &b2)
|| is_rr (insn, op_bctr, &r1, &r2)
|| is_rre (insn, op_bctgr, &r1, &r2)
|| is_rx (insn, op_bct, &r1, &d2, &x2, &b2)
|| is_rxy (insn, op1_bctg, op2_brctg, &r1, &d2, &x2, &b2)
|| is_rs (insn, op_bxh, &r1, &r3, &d2, &b2)
|| is_rsy (insn, op1_bxhg, op2_bxhg, &r1, &r3, &d2, &b2)
|| is_rs (insn, op_bxle, &r1, &r3, &d2, &b2)
|| is_rsy (insn, op1_bxleg, op2_bxleg, &r1, &r3, &d2, &b2))
{
/* Update PC iff branch was *not* taken. */
if (pc == to + insnlen)
regcache_write_pc (regs, from + insnlen);
}
/* Handle PC-relative branch and save instructions. */
else if (is_ri (insn, op1_bras, op2_bras, &r1, &i2)
|| is_ril (insn, op1_brasl, op2_brasl, &r1, &i2))
{
/* Update PC. */
regcache_write_pc (regs, pc - to + from);
/* Recompute saved return address in R1. */
regcache_cooked_write_unsigned (regs, S390_R0_REGNUM + r1,
amode | (from + insnlen));
}
/* Handle LOAD ADDRESS RELATIVE LONG. */
else if (is_ril (insn, op1_larl, op2_larl, &r1, &i2))
{
/* Update PC. */
regcache_write_pc (regs, from + insnlen);
/* Recompute output address in R1. */
regcache_cooked_write_unsigned (regs, S390_R0_REGNUM + r1,
from + i2 * 2);
}
/* If we executed a breakpoint instruction, point PC right back at it. */
else if (insn[0] == 0x0 && insn[1] == 0x1)
regcache_write_pc (regs, from);
/* For any other insn, adjust PC by negated displacement. PC then
points right after the original instruction, except for PC-relative
branches, where it points to the adjusted branch target. */
else
regcache_write_pc (regs, pc - to + from);
displaced_debug_printf ("(s390) pc is now %s",
paddress (gdbarch, regcache_read_pc (regs)));
}
/* Implement displaced_step_hw_singlestep gdbarch method. */
static bool
s390_displaced_step_hw_singlestep (struct gdbarch *gdbarch)
{
return true;
}
/* Prologue analysis. */
struct s390_prologue_data {
/* The stack. */
struct pv_area *stack;
/* The size and byte-order of a GPR or FPR. */
int gpr_size;
int fpr_size;
enum bfd_endian byte_order;
/* The general-purpose registers. */
pv_t gpr[S390_NUM_GPRS];
/* The floating-point registers. */
pv_t fpr[S390_NUM_FPRS];
/* The offset relative to the CFA where the incoming GPR N was saved
by the function prologue. 0 if not saved or unknown. */
int gpr_slot[S390_NUM_GPRS];
/* Likewise for FPRs. */
int fpr_slot[S390_NUM_FPRS];
/* Nonzero if the backchain was saved. This is assumed to be the
case when the incoming SP is saved at the current SP location. */
int back_chain_saved_p;
};
/* Return the effective address for an X-style instruction, like:
L R1, D2(X2, B2)
Here, X2 and B2 are registers, and D2 is a signed 20-bit
constant; the effective address is the sum of all three. If either
X2 or B2 are zero, then it doesn't contribute to the sum --- this
means that r0 can't be used as either X2 or B2. */
static pv_t
s390_addr (struct s390_prologue_data *data,
int d2, unsigned int x2, unsigned int b2)
{
pv_t result;
result = pv_constant (d2);
if (x2)
result = pv_add (result, data->gpr[x2]);
if (b2)
result = pv_add (result, data->gpr[b2]);
return result;
}
/* Do a SIZE-byte store of VALUE to D2(X2,B2). */
static void
s390_store (struct s390_prologue_data *data,
int d2, unsigned int x2, unsigned int b2, CORE_ADDR size,
pv_t value)
{
pv_t addr = s390_addr (data, d2, x2, b2);
pv_t offset;
/* Check whether we are storing the backchain. */
offset = pv_subtract (data->gpr[S390_SP_REGNUM - S390_R0_REGNUM], addr);
if (pv_is_constant (offset) && offset.k == 0)
if (size == data->gpr_size
&& pv_is_register_k (value, S390_SP_REGNUM, 0))
{
data->back_chain_saved_p = 1;
return;
}
/* Check whether we are storing a register into the stack. */
if (!data->stack->store_would_trash (addr))
data->stack->store (addr, size, value);
/* Note: If this is some store we cannot identify, you might think we
should forget our cached values, as any of those might have been hit.
However, we make the assumption that the register save areas are only
ever stored to once in any given function, and we do recognize these
stores. Thus every store we cannot recognize does not hit our data. */
}
/* Do a SIZE-byte load from D2(X2,B2). */
static pv_t
s390_load (struct s390_prologue_data *data,
int d2, unsigned int x2, unsigned int b2, CORE_ADDR size)
{
pv_t addr = s390_addr (data, d2, x2, b2);
/* If it's a load from an in-line constant pool, then we can
simulate that, under the assumption that the code isn't
going to change between the time the processor actually
executed it creating the current frame, and the time when
we're analyzing the code to unwind past that frame. */
if (pv_is_constant (addr))
{
const struct target_section *secp
= target_section_by_addr (current_inferior ()->top_target (), addr.k);
if (secp != NULL
&& (bfd_section_flags (secp->the_bfd_section) & SEC_READONLY))
return pv_constant (read_memory_integer (addr.k, size,
data->byte_order));
}
/* Check whether we are accessing one of our save slots. */
return data->stack->fetch (addr, size);
}
/* Function for finding saved registers in a 'struct pv_area'; we pass
this to pv_area::scan.
If VALUE is a saved register, ADDR says it was saved at a constant
offset from the frame base, and SIZE indicates that the whole
register was saved, record its offset in the reg_offset table in
PROLOGUE_UNTYPED. */
static void
s390_check_for_saved (void *data_untyped, pv_t addr,
CORE_ADDR size, pv_t value)
{
struct s390_prologue_data *data = (struct s390_prologue_data *) data_untyped;
int i, offset;
if (!pv_is_register (addr, S390_SP_REGNUM))
return;
offset = 16 * data->gpr_size + 32 - addr.k;
/* If we are storing the original value of a register, we want to
record the CFA offset. If the same register is stored multiple
times, the stack slot with the highest address counts. */
for (i = 0; i < S390_NUM_GPRS; i++)
if (size == data->gpr_size
&& pv_is_register_k (value, S390_R0_REGNUM + i, 0))
if (data->gpr_slot[i] == 0
|| data->gpr_slot[i] > offset)
{
data->gpr_slot[i] = offset;
return;
}
for (i = 0; i < S390_NUM_FPRS; i++)
if (size == data->fpr_size
&& pv_is_register_k (value, S390_F0_REGNUM + i, 0))
if (data->fpr_slot[i] == 0
|| data->fpr_slot[i] > offset)
{
data->fpr_slot[i] = offset;
return;
}
}
/* Analyze the prologue of the function starting at START_PC, continuing at
most until CURRENT_PC. Initialize DATA to hold all information we find
out about the state of the registers and stack slots. Return the address
of the instruction after the last one that changed the SP, FP, or back
chain; or zero on error. */
static CORE_ADDR
s390_analyze_prologue (struct gdbarch *gdbarch,
CORE_ADDR start_pc,
CORE_ADDR current_pc,
struct s390_prologue_data *data)
{
int word_size = gdbarch_ptr_bit (gdbarch) / 8;
/* Our return value:
The address of the instruction after the last one that changed
the SP, FP, or back chain; zero if we got an error trying to
read memory. */
CORE_ADDR result = start_pc;
/* The current PC for our abstract interpretation. */
CORE_ADDR pc;
/* The address of the next instruction after that. */
CORE_ADDR next_pc;
pv_area stack (S390_SP_REGNUM, gdbarch_addr_bit (gdbarch));
scoped_restore restore_stack = make_scoped_restore (&data->stack, &stack);
/* Set up everything's initial value. */
{
int i;
/* For the purpose of prologue tracking, we consider the GPR size to
be equal to the ABI word size, even if it is actually larger
(i.e. when running a 32-bit binary under a 64-bit kernel). */
data->gpr_size = word_size;
data->fpr_size = 8;
data->byte_order = gdbarch_byte_order (gdbarch);
for (i = 0; i < S390_NUM_GPRS; i++)
data->gpr[i] = pv_register (S390_R0_REGNUM + i, 0);
for (i = 0; i < S390_NUM_FPRS; i++)
data->fpr[i] = pv_register (S390_F0_REGNUM + i, 0);
for (i = 0; i < S390_NUM_GPRS; i++)
data->gpr_slot[i] = 0;
for (i = 0; i < S390_NUM_FPRS; i++)
data->fpr_slot[i] = 0;
data->back_chain_saved_p = 0;
}
/* Start interpreting instructions, until we hit the frame's
current PC or the first branch instruction. */
for (pc = start_pc; pc > 0 && pc < current_pc; pc = next_pc)
{
bfd_byte insn[S390_MAX_INSTR_SIZE];
int insn_len = s390_readinstruction (insn, pc);
bfd_byte dummy[S390_MAX_INSTR_SIZE] = { 0 };
bfd_byte *insn32 = word_size == 4 ? insn : dummy;
bfd_byte *insn64 = word_size == 8 ? insn : dummy;
/* Fields for various kinds of instructions. */
unsigned int b2, r1, r2, x2, r3;
int i2, d2;
/* The values of SP and FP before this instruction,
for detecting instructions that change them. */
pv_t pre_insn_sp, pre_insn_fp;
/* Likewise for the flag whether the back chain was saved. */
int pre_insn_back_chain_saved_p;
/* If we got an error trying to read the instruction, report it. */
if (insn_len < 0)
{
result = 0;
break;
}
next_pc = pc + insn_len;
pre_insn_sp = data->gpr[S390_SP_REGNUM - S390_R0_REGNUM];
pre_insn_fp = data->gpr[S390_FRAME_REGNUM - S390_R0_REGNUM];
pre_insn_back_chain_saved_p = data->back_chain_saved_p;
/* LHI r1, i2 --- load halfword immediate. */
/* LGHI r1, i2 --- load halfword immediate (64-bit version). */
/* LGFI r1, i2 --- load fullword immediate. */
if (is_ri (insn32, op1_lhi, op2_lhi, &r1, &i2)
|| is_ri (insn64, op1_lghi, op2_lghi, &r1, &i2)
|| is_ril (insn, op1_lgfi, op2_lgfi, &r1, &i2))
data->gpr[r1] = pv_constant (i2);
/* LR r1, r2 --- load from register. */
/* LGR r1, r2 --- load from register (64-bit version). */
else if (is_rr (insn32, op_lr, &r1, &r2)
|| is_rre (insn64, op_lgr, &r1, &r2))
data->gpr[r1] = data->gpr[r2];
/* L r1, d2(x2, b2) --- load. */
/* LY r1, d2(x2, b2) --- load (long-displacement version). */
/* LG r1, d2(x2, b2) --- load (64-bit version). */
else if (is_rx (insn32, op_l, &r1, &d2, &x2, &b2)
|| is_rxy (insn32, op1_ly, op2_ly, &r1, &d2, &x2, &b2)
|| is_rxy (insn64, op1_lg, op2_lg, &r1, &d2, &x2, &b2))
data->gpr[r1] = s390_load (data, d2, x2, b2, data->gpr_size);
/* ST r1, d2(x2, b2) --- store. */
/* STY r1, d2(x2, b2) --- store (long-displacement version). */
/* STG r1, d2(x2, b2) --- store (64-bit version). */
else if (is_rx (insn32, op_st, &r1, &d2, &x2, &b2)
|| is_rxy (insn32, op1_sty, op2_sty, &r1, &d2, &x2, &b2)
|| is_rxy (insn64, op1_stg, op2_stg, &r1, &d2, &x2, &b2))
s390_store (data, d2, x2, b2, data->gpr_size, data->gpr[r1]);
/* STD r1, d2(x2,b2) --- store floating-point register. */
else if (is_rx (insn, op_std, &r1, &d2, &x2, &b2))
s390_store (data, d2, x2, b2, data->fpr_size, data->fpr[r1]);
/* STM r1, r3, d2(b2) --- store multiple. */
/* STMY r1, r3, d2(b2) --- store multiple (long-displacement
version). */
/* STMG r1, r3, d2(b2) --- store multiple (64-bit version). */
else if (is_rs (insn32, op_stm, &r1, &r3, &d2, &b2)
|| is_rsy (insn32, op1_stmy, op2_stmy, &r1, &r3, &d2, &b2)
|| is_rsy (insn64, op1_stmg, op2_stmg, &r1, &r3, &d2, &b2))
{
for (; r1 <= r3; r1++, d2 += data->gpr_size)
s390_store (data, d2, 0, b2, data->gpr_size, data->gpr[r1]);
}
/* AHI r1, i2 --- add halfword immediate. */
/* AGHI r1, i2 --- add halfword immediate (64-bit version). */
/* AFI r1, i2 --- add fullword immediate. */
/* AGFI r1, i2 --- add fullword immediate (64-bit version). */
else if (is_ri (insn32, op1_ahi, op2_ahi, &r1, &i2)
|| is_ri (insn64, op1_aghi, op2_aghi, &r1, &i2)
|| is_ril (insn32, op1_afi, op2_afi, &r1, &i2)
|| is_ril (insn64, op1_agfi, op2_agfi, &r1, &i2))
data->gpr[r1] = pv_add_constant (data->gpr[r1], i2);
/* ALFI r1, i2 --- add logical immediate. */
/* ALGFI r1, i2 --- add logical immediate (64-bit version). */
else if (is_ril (insn32, op1_alfi, op2_alfi, &r1, &i2)
|| is_ril (insn64, op1_algfi, op2_algfi, &r1, &i2))
data->gpr[r1] = pv_add_constant (data->gpr[r1],
(CORE_ADDR)i2 & 0xffffffff);
/* AR r1, r2 -- add register. */
/* AGR r1, r2 -- add register (64-bit version). */
else if (is_rr (insn32, op_ar, &r1, &r2)
|| is_rre (insn64, op_agr, &r1, &r2))
data->gpr[r1] = pv_add (data->gpr[r1], data->gpr[r2]);
/* A r1, d2(x2, b2) -- add. */
/* AY r1, d2(x2, b2) -- add (long-displacement version). */
/* AG r1, d2(x2, b2) -- add (64-bit version). */
else if (is_rx (insn32, op_a, &r1, &d2, &x2, &b2)
|| is_rxy (insn32, op1_ay, op2_ay, &r1, &d2, &x2, &b2)
|| is_rxy (insn64, op1_ag, op2_ag, &r1, &d2, &x2, &b2))
data->gpr[r1] = pv_add (data->gpr[r1],
s390_load (data, d2, x2, b2, data->gpr_size));
/* SLFI r1, i2 --- subtract logical immediate. */
/* SLGFI r1, i2 --- subtract logical immediate (64-bit version). */
else if (is_ril (insn32, op1_slfi, op2_slfi, &r1, &i2)
|| is_ril (insn64, op1_slgfi, op2_slgfi, &r1, &i2))
data->gpr[r1] = pv_add_constant (data->gpr[r1],
-((CORE_ADDR)i2 & 0xffffffff));
/* SR r1, r2 -- subtract register. */
/* SGR r1, r2 -- subtract register (64-bit version). */
else if (is_rr (insn32, op_sr, &r1, &r2)
|| is_rre (insn64, op_sgr, &r1, &r2))
data->gpr[r1] = pv_subtract (data->gpr[r1], data->gpr[r2]);
/* S r1, d2(x2, b2) -- subtract. */
/* SY r1, d2(x2, b2) -- subtract (long-displacement version). */
/* SG r1, d2(x2, b2) -- subtract (64-bit version). */
else if (is_rx (insn32, op_s, &r1, &d2, &x2, &b2)
|| is_rxy (insn32, op1_sy, op2_sy, &r1, &d2, &x2, &b2)
|| is_rxy (insn64, op1_sg, op2_sg, &r1, &d2, &x2, &b2))
data->gpr[r1] = pv_subtract (data->gpr[r1],
s390_load (data, d2, x2, b2, data->gpr_size));
/* LA r1, d2(x2, b2) --- load address. */
/* LAY r1, d2(x2, b2) --- load address (long-displacement version). */
else if (is_rx (insn, op_la, &r1, &d2, &x2, &b2)
|| is_rxy (insn, op1_lay, op2_lay, &r1, &d2, &x2, &b2))
data->gpr[r1] = s390_addr (data, d2, x2, b2);
/* LARL r1, i2 --- load address relative long. */
else if (is_ril (insn, op1_larl, op2_larl, &r1, &i2))
data->gpr[r1] = pv_constant (pc + i2 * 2);
/* BASR r1, 0 --- branch and save.
Since r2 is zero, this saves the PC in r1, but doesn't branch. */
else if (is_rr (insn, op_basr, &r1, &r2)
&& r2 == 0)
data->gpr[r1] = pv_constant (next_pc);
/* BRAS r1, i2 --- branch relative and save. */
else if (is_ri (insn, op1_bras, op2_bras, &r1, &i2))
{
data->gpr[r1] = pv_constant (next_pc);
next_pc = pc + i2 * 2;
/* We'd better not interpret any backward branches. We'll
never terminate. */
if (next_pc <= pc)
break;
}
/* BRC/BRCL -- branch relative on condition. Ignore "branch
never", branch to following instruction, and "conditional
trap" (BRC +2). Otherwise terminate search. */
else if (is_ri (insn, op1_brc, op2_brc, &r1, &i2))
{
if (r1 != 0 && i2 != 1 && i2 != 2)
break;
}
else if (is_ril (insn, op1_brcl, op2_brcl, &r1, &i2))
{
if (r1 != 0 && i2 != 3)
break;
}
/* Terminate search when hitting any other branch instruction. */
else if (is_rr (insn, op_basr, &r1, &r2)
|| is_rx (insn, op_bas, &r1, &d2, &x2, &b2)
|| is_rr (insn, op_bcr, &r1, &r2)
|| is_rx (insn, op_bc, &r1, &d2, &x2, &b2)
|| is_ril (insn, op1_brasl, op2_brasl, &r2, &i2))
break;
else
{
/* An instruction we don't know how to simulate. The only
safe thing to do would be to set every value we're tracking
to 'unknown'. Instead, we'll be optimistic: we assume that
we *can* interpret every instruction that the compiler uses
to manipulate any of the data we're interested in here --
then we can just ignore anything else. */
}
/* Record the address after the last instruction that changed
the FP, SP, or backlink. Ignore instructions that changed
them back to their original values --- those are probably
restore instructions. (The back chain is never restored,
just popped.) */
{
pv_t sp = data->gpr[S390_SP_REGNUM - S390_R0_REGNUM];
pv_t fp = data->gpr[S390_FRAME_REGNUM - S390_R0_REGNUM];
if ((! pv_is_identical (pre_insn_sp, sp)
&& ! pv_is_register_k (sp, S390_SP_REGNUM, 0)
&& sp.kind != pvk_unknown)
|| (! pv_is_identical (pre_insn_fp, fp)
&& ! pv_is_register_k (fp, S390_FRAME_REGNUM, 0)
&& fp.kind != pvk_unknown)
|| pre_insn_back_chain_saved_p != data->back_chain_saved_p)
result = next_pc;
}
}
/* Record where all the registers were saved. */
data->stack->scan (s390_check_for_saved, data);
return result;
}
/* Advance PC across any function entry prologue instructions to reach
some "real" code. */
static CORE_ADDR
s390_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
{
struct s390_prologue_data data;
CORE_ADDR skip_pc, func_addr;
if (find_pc_partial_function (pc, NULL, &func_addr, NULL))
{
CORE_ADDR post_prologue_pc
= skip_prologue_using_sal (gdbarch, func_addr);
if (post_prologue_pc != 0)
return std::max (pc, post_prologue_pc);
}
skip_pc = s390_analyze_prologue (gdbarch, pc, (CORE_ADDR)-1, &data);
return skip_pc ? skip_pc : pc;
}
/* Register handling. */
/* ABI call-saved register information. */
static int
s390_register_call_saved (struct gdbarch *gdbarch, int regnum)
{
s390_gdbarch_tdep *tdep = gdbarch_tdep<s390_gdbarch_tdep> (gdbarch);
switch (tdep->abi)
{
case ABI_LINUX_S390:
if ((regnum >= S390_R6_REGNUM && regnum <= S390_R15_REGNUM)
|| regnum == S390_F4_REGNUM || regnum == S390_F6_REGNUM
|| regnum == S390_A0_REGNUM)
return 1;
break;
case ABI_LINUX_ZSERIES:
if ((regnum >= S390_R6_REGNUM && regnum <= S390_R15_REGNUM)
|| (regnum >= S390_F8_REGNUM && regnum <= S390_F15_REGNUM)
|| (regnum >= S390_A0_REGNUM && regnum <= S390_A1_REGNUM))
return 1;
break;
}
return 0;
}
/* The "guess_tracepoint_registers" gdbarch method. */
static void
s390_guess_tracepoint_registers (struct gdbarch *gdbarch,
struct regcache *regcache,
CORE_ADDR addr)
{
s390_gdbarch_tdep *tdep = gdbarch_tdep<s390_gdbarch_tdep> (gdbarch);
int sz = register_size (gdbarch, S390_PSWA_REGNUM);
gdb_byte *reg = (gdb_byte *) alloca (sz);
ULONGEST pswm, pswa;
/* Set PSWA from the location and a default PSWM (the only part we're
unlikely to get right is the CC). */
if (tdep->abi == ABI_LINUX_S390)
{
/* 31-bit PSWA needs high bit set (it's very unlikely the target
was in 24-bit mode). */
pswa = addr | 0x80000000UL;
pswm = 0x070d0000UL;
}
else
{
pswa = addr;
pswm = 0x0705000180000000ULL;
}
store_unsigned_integer (reg, sz, gdbarch_byte_order (gdbarch), pswa);
regcache->raw_supply (S390_PSWA_REGNUM, reg);
store_unsigned_integer (reg, sz, gdbarch_byte_order (gdbarch), pswm);
regcache->raw_supply (S390_PSWM_REGNUM, reg);
}
/* Return the name of register REGNO. Return the empty string for
registers that shouldn't be visible. */
static const char *
s390_register_name (struct gdbarch *gdbarch, int regnum)
{
if (regnum >= S390_V0_LOWER_REGNUM
&& regnum <= S390_V15_LOWER_REGNUM)
return "";
return tdesc_register_name (gdbarch, regnum);
}
/* DWARF Register Mapping. */
static const short s390_dwarf_regmap[] =
{
/* 0-15: General Purpose Registers. */
S390_R0_REGNUM, S390_R1_REGNUM, S390_R2_REGNUM, S390_R3_REGNUM,
S390_R4_REGNUM, S390_R5_REGNUM, S390_R6_REGNUM, S390_R7_REGNUM,
S390_R8_REGNUM, S390_R9_REGNUM, S390_R10_REGNUM, S390_R11_REGNUM,
S390_R12_REGNUM, S390_R13_REGNUM, S390_R14_REGNUM, S390_R15_REGNUM,
/* 16-31: Floating Point Registers / Vector Registers 0-15. */
S390_F0_REGNUM, S390_F2_REGNUM, S390_F4_REGNUM, S390_F6_REGNUM,
S390_F1_REGNUM, S390_F3_REGNUM, S390_F5_REGNUM, S390_F7_REGNUM,
S390_F8_REGNUM, S390_F10_REGNUM, S390_F12_REGNUM, S390_F14_REGNUM,
S390_F9_REGNUM, S390_F11_REGNUM, S390_F13_REGNUM, S390_F15_REGNUM,
/* 32-47: Control Registers (not mapped). */
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
/* 48-63: Access Registers. */
S390_A0_REGNUM, S390_A1_REGNUM, S390_A2_REGNUM, S390_A3_REGNUM,
S390_A4_REGNUM, S390_A5_REGNUM, S390_A6_REGNUM, S390_A7_REGNUM,
S390_A8_REGNUM, S390_A9_REGNUM, S390_A10_REGNUM, S390_A11_REGNUM,
S390_A12_REGNUM, S390_A13_REGNUM, S390_A14_REGNUM, S390_A15_REGNUM,
/* 64-65: Program Status Word. */
S390_PSWM_REGNUM,
S390_PSWA_REGNUM,
/* 66-67: Reserved. */
-1, -1,
/* 68-83: Vector Registers 16-31. */
S390_V16_REGNUM, S390_V18_REGNUM, S390_V20_REGNUM, S390_V22_REGNUM,
S390_V17_REGNUM, S390_V19_REGNUM, S390_V21_REGNUM, S390_V23_REGNUM,
S390_V24_REGNUM, S390_V26_REGNUM, S390_V28_REGNUM, S390_V30_REGNUM,
S390_V25_REGNUM, S390_V27_REGNUM, S390_V29_REGNUM, S390_V31_REGNUM,
/* End of "official" DWARF registers. The remainder of the map is
for GDB internal use only. */
/* GPR Lower Half Access. */
S390_R0_REGNUM, S390_R1_REGNUM, S390_R2_REGNUM, S390_R3_REGNUM,
S390_R4_REGNUM, S390_R5_REGNUM, S390_R6_REGNUM, S390_R7_REGNUM,
S390_R8_REGNUM, S390_R9_REGNUM, S390_R10_REGNUM, S390_R11_REGNUM,
S390_R12_REGNUM, S390_R13_REGNUM, S390_R14_REGNUM, S390_R15_REGNUM,
};
enum { s390_dwarf_reg_r0l = ARRAY_SIZE (s390_dwarf_regmap) - 16 };
/* Convert DWARF register number REG to the appropriate register
number used by GDB. */
static int
s390_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int reg)
{
s390_gdbarch_tdep *tdep = gdbarch_tdep<s390_gdbarch_tdep> (gdbarch);
int gdb_reg = -1;
/* In a 32-on-64 debug scenario, debug info refers to the full
64-bit GPRs. Note that call frame information still refers to
the 32-bit lower halves, because s390_adjust_frame_regnum uses
special register numbers to access GPRs. */
if (tdep->gpr_full_regnum != -1 && reg >= 0 && reg < 16)
return tdep->gpr_full_regnum + reg;
if (reg >= 0 && reg < ARRAY_SIZE (s390_dwarf_regmap))
gdb_reg = s390_dwarf_regmap[reg];
if (tdep->v0_full_regnum == -1)
{
if (gdb_reg >= S390_V16_REGNUM && gdb_reg <= S390_V31_REGNUM)
gdb_reg = -1;
}
else
{
if (gdb_reg >= S390_F0_REGNUM && gdb_reg <= S390_F15_REGNUM)
gdb_reg = gdb_reg - S390_F0_REGNUM + tdep->v0_full_regnum;
}
return gdb_reg;
}
/* Pseudo registers. */
/* Check whether REGNUM indicates a coupled general purpose register.
These pseudo-registers are composed of two adjacent gprs. */
static int
regnum_is_gpr_full (s390_gdbarch_tdep *tdep, int regnum)
{
return (tdep->gpr_full_regnum != -1
&& regnum >= tdep->gpr_full_regnum
&& regnum <= tdep->gpr_full_regnum + 15);
}
/* Check whether REGNUM indicates a full vector register (v0-v15).
These pseudo-registers are composed of f0-f15 and v0l-v15l. */
static int
regnum_is_vxr_full (s390_gdbarch_tdep *tdep, int regnum)
{
return (tdep->v0_full_regnum != -1
&& regnum >= tdep->v0_full_regnum
&& regnum <= tdep->v0_full_regnum + 15);
}
/* 'float' values are stored in the upper half of floating-point
registers, even though we are otherwise a big-endian platform. The
same applies to a 'float' value within a vector. */
static value *
s390_value_from_register (gdbarch *gdbarch, type *type, int regnum,
const frame_info_ptr &this_frame)
{
s390_gdbarch_tdep *tdep = gdbarch_tdep<s390_gdbarch_tdep> (gdbarch);
value *value
= default_value_from_register (gdbarch, type, regnum, this_frame);
check_typedef (type);
if ((regnum >= S390_F0_REGNUM && regnum <= S390_F15_REGNUM
&& type->length () < 8)
|| regnum_is_vxr_full (tdep, regnum)
|| (regnum >= S390_V16_REGNUM && regnum <= S390_V31_REGNUM))
value->set_offset (0);
return value;
}
/* Implement pseudo_register_name tdesc method. */
static const char *
s390_pseudo_register_name (struct gdbarch *gdbarch, int regnum)
{
s390_gdbarch_tdep *tdep = gdbarch_tdep<s390_gdbarch_tdep> (gdbarch);
if (regnum == tdep->pc_regnum)
return "pc";
if (regnum == tdep->cc_regnum)
return "cc";
if (regnum_is_gpr_full (tdep, regnum))
{
static const char *full_name[] = {
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
};
return full_name[regnum - tdep->gpr_full_regnum];
}
if (regnum_is_vxr_full (tdep, regnum))
{
static const char *full_name[] = {
"v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",
"v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15"
};
return full_name[regnum - tdep->v0_full_regnum];
}
internal_error (_("invalid regnum"));
}
/* Implement pseudo_register_type tdesc method. */
static struct type *
s390_pseudo_register_type (struct gdbarch *gdbarch, int regnum)
{
s390_gdbarch_tdep *tdep = gdbarch_tdep<s390_gdbarch_tdep> (gdbarch);
if (regnum == tdep->pc_regnum)
return builtin_type (gdbarch)->builtin_func_ptr;
if (regnum == tdep->cc_regnum)
return builtin_type (gdbarch)->builtin_int;
if (regnum_is_gpr_full (tdep, regnum))
return builtin_type (gdbarch)->builtin_uint64;
/* For the "concatenated" vector registers use the same type as v16. */
if (regnum_is_vxr_full (tdep, regnum))
return tdesc_register_type (gdbarch, S390_V16_REGNUM);
internal_error (_("invalid regnum"));
}
/* Implement pseudo_register_read gdbarch method. */
static enum register_status
s390_pseudo_register_read (struct gdbarch *gdbarch, readable_regcache *regcache,
int regnum, gdb_byte *buf)
{
s390_gdbarch_tdep *tdep = gdbarch_tdep<s390_gdbarch_tdep> (gdbarch);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
int regsize = register_size (gdbarch, regnum);
ULONGEST val;
if (regnum == tdep->pc_regnum)
{
enum register_status status;
status = regcache->raw_read (S390_PSWA_REGNUM, &val);
if (status == REG_VALID)
{
if (register_size (gdbarch, S390_PSWA_REGNUM) == 4)
val &= 0x7fffffff;
store_unsigned_integer (buf, regsize, byte_order, val);
}
return status;
}
if (regnum == tdep->cc_regnum)
{
enum register_status status;
status = regcache->raw_read (S390_PSWM_REGNUM, &val);
if (status == REG_VALID)
{
if (register_size (gdbarch, S390_PSWA_REGNUM) == 4)
val = (val >> 12) & 3;
else
val = (val >> 44) & 3;
store_unsigned_integer (buf, regsize, byte_order, val);
}
return status;
}
if (regnum_is_gpr_full (tdep, regnum))
{
enum register_status status;
ULONGEST val_upper;
regnum -= tdep->gpr_full_regnum;
status = regcache->raw_read (S390_R0_REGNUM + regnum, &val);
if (status == REG_VALID)
status = regcache->raw_read (S390_R0_UPPER_REGNUM + regnum,
&val_upper);
if (status == REG_VALID)
{
val |= val_upper << 32;
store_unsigned_integer (buf, regsize, byte_order, val);
}
return status;
}
if (regnum_is_vxr_full (tdep, regnum))
{
enum register_status status;
regnum -= tdep->v0_full_regnum;
status = regcache->raw_read (S390_F0_REGNUM + regnum, buf);
if (status == REG_VALID)
status = regcache->raw_read (S390_V0_LOWER_REGNUM + regnum, buf + 8);
return status;
}
internal_error (_("invalid regnum"));
}
/* Implement pseudo_register_write gdbarch method. */
static void
s390_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
int regnum, const gdb_byte *buf)
{
s390_gdbarch_tdep *tdep = gdbarch_tdep<s390_gdbarch_tdep> (gdbarch);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
int regsize = register_size (gdbarch, regnum);
ULONGEST val, psw;
if (regnum == tdep->pc_regnum)
{
val = extract_unsigned_integer (buf, regsize, byte_order);
if (register_size (gdbarch, S390_PSWA_REGNUM) == 4)
{
regcache_raw_read_unsigned (regcache, S390_PSWA_REGNUM, &psw);
val = (psw & 0x80000000) | (val & 0x7fffffff);
}
regcache_raw_write_unsigned (regcache, S390_PSWA_REGNUM, val);
return;
}
if (regnum == tdep->cc_regnum)
{
val = extract_unsigned_integer (buf, regsize, byte_order);
regcache_raw_read_unsigned (regcache, S390_PSWM_REGNUM, &psw);
if (register_size (gdbarch, S390_PSWA_REGNUM) == 4)
val = (psw & ~((ULONGEST)3 << 12)) | ((val & 3) << 12);
else
val = (psw & ~((ULONGEST)3 << 44)) | ((val & 3) << 44);
regcache_raw_write_unsigned (regcache, S390_PSWM_REGNUM, val);
return;
}
if (regnum_is_gpr_full (tdep, regnum))
{
regnum -= tdep->gpr_full_regnum;
val = extract_unsigned_integer (buf, regsize, byte_order);
regcache_raw_write_unsigned (regcache, S390_R0_REGNUM + regnum,
val & 0xffffffff);
regcache_raw_write_unsigned (regcache, S390_R0_UPPER_REGNUM + regnum,
val >> 32);
return;
}
if (regnum_is_vxr_full (tdep, regnum))
{
regnum -= tdep->v0_full_regnum;
regcache->raw_write (S390_F0_REGNUM + regnum, buf);
regcache->raw_write (S390_V0_LOWER_REGNUM + regnum, buf + 8);
return;
}
internal_error (_("invalid regnum"));
}
/* Register groups. */
/* Implement pseudo_register_reggroup_p tdesc method. */
static int
s390_pseudo_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
const struct reggroup *group)
{
s390_gdbarch_tdep *tdep = gdbarch_tdep<s390_gdbarch_tdep> (gdbarch);
/* We usually save/restore the whole PSW, which includes PC and CC.
However, some older gdbservers may not support saving/restoring
the whole PSW yet, and will return an XML register description
excluding those from the save/restore register groups. In those
cases, we still need to explicitly save/restore PC and CC in order
to push or pop frames. Since this doesn't hurt anything if we
already save/restore the whole PSW (it's just redundant), we add
PC and CC at this point unconditionally. */
if (group == save_reggroup || group == restore_reggroup)
return regnum == tdep->pc_regnum || regnum == tdep->cc_regnum;
if (group == vector_reggroup)
return regnum_is_vxr_full (tdep, regnum);
if (group == general_reggroup && regnum_is_vxr_full (tdep, regnum))
return 0;
return default_register_reggroup_p (gdbarch, regnum, group);
}
/* The "ax_pseudo_register_collect" gdbarch method. */
static int
s390_ax_pseudo_register_collect (struct gdbarch *gdbarch,
struct agent_expr *ax, int regnum)
{
s390_gdbarch_tdep *tdep = gdbarch_tdep<s390_gdbarch_tdep> (gdbarch);
if (regnum == tdep->pc_regnum)
{
ax_reg_mask (ax, S390_PSWA_REGNUM);
}
else if (regnum == tdep->cc_regnum)
{
ax_reg_mask (ax, S390_PSWM_REGNUM);
}
else if (regnum_is_gpr_full (tdep, regnum))
{
regnum -= tdep->gpr_full_regnum;
ax_reg_mask (ax, S390_R0_REGNUM + regnum);
ax_reg_mask (ax, S390_R0_UPPER_REGNUM + regnum);
}
else if (regnum_is_vxr_full (tdep, regnum))
{
regnum -= tdep->v0_full_regnum;
ax_reg_mask (ax, S390_F0_REGNUM + regnum);
ax_reg_mask (ax, S390_V0_LOWER_REGNUM + regnum);
}
else
{
internal_error (_("invalid regnum"));
}
return 0;
}
/* The "ax_pseudo_register_push_stack" gdbarch method. */
static int
s390_ax_pseudo_register_push_stack (struct gdbarch *gdbarch,
struct agent_expr *ax, int regnum)
{
s390_gdbarch_tdep *tdep = gdbarch_tdep<s390_gdbarch_tdep> (gdbarch);
if (regnum == tdep->pc_regnum)
{
ax_reg (ax, S390_PSWA_REGNUM);
if (register_size (gdbarch, S390_PSWA_REGNUM) == 4)
{
ax_zero_ext (ax, 31);
}
}
else if (regnum == tdep->cc_regnum)
{
ax_reg (ax, S390_PSWM_REGNUM);
if (register_size (gdbarch, S390_PSWA_REGNUM) == 4)
ax_const_l (ax, 12);
else
ax_const_l (ax, 44);
ax_simple (ax, aop_rsh_unsigned);
ax_zero_ext (ax, 2);
}
else if (regnum_is_gpr_full (tdep, regnum))
{
regnum -= tdep->gpr_full_regnum;
ax_reg (ax, S390_R0_REGNUM + regnum);
ax_reg (ax, S390_R0_UPPER_REGNUM + regnum);
ax_const_l (ax, 32);
ax_simple (ax, aop_lsh);
ax_simple (ax, aop_bit_or);
}
else if (regnum_is_vxr_full (tdep, regnum))
{
/* Too large to stuff on the stack. */
return 1;
}
else
{
internal_error (_("invalid regnum"));
}
return 0;
}
/* The "gen_return_address" gdbarch method. Since this is supposed to be
just a best-effort method, and we don't really have the means to run
the full unwinder here, just collect the link register. */
static void
s390_gen_return_address (struct gdbarch *gdbarch,
struct agent_expr *ax, struct axs_value *value,
CORE_ADDR scope)
{
value->type = register_type (gdbarch, S390_R14_REGNUM);
value->kind = axs_lvalue_register;
value->u.reg = S390_R14_REGNUM;
}
/* Address handling. */
/* Implement addr_bits_remove gdbarch method.
Only used for ABI_LINUX_S390. */
static CORE_ADDR
s390_addr_bits_remove (struct gdbarch *gdbarch, CORE_ADDR addr)
{
return addr & 0x7fffffff;
}
/* Implement addr_class_type_flags gdbarch method.
Only used for ABI_LINUX_ZSERIES. */
static type_instance_flags
s390_address_class_type_flags (int byte_size, int dwarf2_addr_class)
{
if (byte_size == 4)
return TYPE_INSTANCE_FLAG_ADDRESS_CLASS_1;
else
return 0;
}
/* Implement addr_class_type_flags_to_name gdbarch method.
Only used for ABI_LINUX_ZSERIES. */
static const char *
s390_address_class_type_flags_to_name (struct gdbarch *gdbarch,
type_instance_flags type_flags)
{
if (type_flags & TYPE_INSTANCE_FLAG_ADDRESS_CLASS_1)
return "mode32";
else
return NULL;
}
/* Implement addr_class_name_to_type_flags gdbarch method.
Only used for ABI_LINUX_ZSERIES. */
static bool
s390_address_class_name_to_type_flags (struct gdbarch *gdbarch,
const char *name,
type_instance_flags *type_flags_ptr)
{
if (strcmp (name, "mode32") == 0)
{
*type_flags_ptr = TYPE_INSTANCE_FLAG_ADDRESS_CLASS_1;
return true;
}
else
return false;
}
/* Inferior function calls. */
/* Dummy function calls. */
/* Unwrap any single-field structs in TYPE and return the effective
"inner" type. E.g., yield "float" for all these cases:
float x;
struct { float x };
struct { struct { float x; } x; };
struct { struct { struct { float x; } x; } x; };
However, if an inner type is smaller than MIN_SIZE, abort the
unwrapping. */
static struct type *
s390_effective_inner_type (struct type *type, unsigned int min_size)
{
while (type->code () == TYPE_CODE_STRUCT)
{
struct type *inner = NULL;
/* Find a non-static field, if any. Unless there's exactly one,
abort the unwrapping. */
for (int i = 0; i < type->num_fields (); i++)
{
struct field f = type->field (i);
if (f.is_static ())
continue;
if (inner != NULL)
return type;
inner = f.type ();
}
if (inner == NULL)
break;
inner = check_typedef (inner);
if (inner->length () < min_size)
break;
type = inner;
}
return type;
}
/* Return non-zero if TYPE should be passed like "float" or
"double". */
static int
s390_function_arg_float (struct type *type)
{
/* Note that long double as well as complex types are intentionally
excluded. */
if (type->length () > 8)
return 0;
/* A struct containing just a float or double is passed like a float
or double. */
type = s390_effective_inner_type (type, 0);
return (type->code () == TYPE_CODE_FLT
|| type->code () == TYPE_CODE_DECFLOAT);
}
/* Return non-zero if TYPE should be passed like a vector. */
static int
s390_function_arg_vector (struct type *type)
{
if (type->length () > 16)
return 0;
/* Structs containing just a vector are passed like a vector. */
type = s390_effective_inner_type (type, type->length ());
return type->code () == TYPE_CODE_ARRAY && type->is_vector ();
}
/* Determine whether N is a power of two. */
static int
is_power_of_two (unsigned int n)
{
return n && ((n & (n - 1)) == 0);
}
/* For an argument whose type is TYPE and which is not passed like a
float or vector, return non-zero if it should be passed like "int"
or "long long". */
static int
s390_function_arg_integer (struct type *type)
{
enum type_code code = type->code ();
if (type->length () > 8)
return 0;
if (code == TYPE_CODE_INT
|| code == TYPE_CODE_ENUM
|| code == TYPE_CODE_RANGE
|| code == TYPE_CODE_CHAR
|| code == TYPE_CODE_BOOL
|| code == TYPE_CODE_PTR
|| TYPE_IS_REFERENCE (type))
return 1;
return ((code == TYPE_CODE_UNION || code == TYPE_CODE_STRUCT)
&& is_power_of_two (type->length ()));
}
/* Argument passing state: Internal data structure passed to helper
routines of s390_push_dummy_call. */
struct s390_arg_state
{
/* Register cache, or NULL, if we are in "preparation mode". */
struct regcache *regcache;
/* Next available general/floating-point/vector register for
argument passing. */
int gr, fr, vr;
/* Current pointer to copy area (grows downwards). */
CORE_ADDR copy;
/* Current pointer to parameter area (grows upwards). */
CORE_ADDR argp;
};
/* Prepare one argument ARG for a dummy call and update the argument
passing state AS accordingly. If the regcache field in AS is set,
operate in "write mode" and write ARG into the inferior. Otherwise
run "preparation mode" and skip all updates to the inferior. */
static void
s390_handle_arg (struct s390_arg_state *as, struct value *arg,
s390_gdbarch_tdep *tdep, int word_size,
enum bfd_endian byte_order, int is_unnamed)
{
struct type *type = check_typedef (arg->type ());
unsigned int length = type->length ();
int write_mode = as->regcache != NULL;
if (s390_function_arg_float (type))
{
/* The GNU/Linux for S/390 ABI uses FPRs 0 and 2 to pass
arguments. The GNU/Linux for zSeries ABI uses 0, 2, 4, and
6. */
if (as->fr <= (tdep->abi == ABI_LINUX_S390 ? 2 : 6))
{
/* When we store a single-precision value in an FP register,
it occupies the leftmost bits. */
if (write_mode)
as->regcache->cooked_write_part (S390_F0_REGNUM + as->fr, 0, length,
arg->contents ().data ());
as->fr += 2;
}
else
{
/* When we store a single-precision value in a stack slot,
it occupies the rightmost bits. */
as->argp = align_up (as->argp + length, word_size);
if (write_mode)
write_memory (as->argp - length, arg->contents ().data (),
length);
}
}
else if (tdep->vector_abi == S390_VECTOR_ABI_128
&& s390_function_arg_vector (type))
{
static const char use_vr[] = {24, 26, 28, 30, 25, 27, 29, 31};
if (!is_unnamed && as->vr < ARRAY_SIZE (use_vr))
{
int regnum = S390_V24_REGNUM + use_vr[as->vr] - 24;
if (write_mode)
as->regcache->cooked_write_part (regnum, 0, length,
arg->contents ().data ());
as->vr++;
}
else
{
if (write_mode)
write_memory (as->argp, arg->contents ().data (), length);
as->argp = align_up (as->argp + length, word_size);
}
}
else if (s390_function_arg_integer (type) && length <= word_size)
{
/* Initialize it just to avoid a GCC false warning. */
ULONGEST val = 0;
if (write_mode)
{
/* Place value in least significant bits of the register or
memory word and sign- or zero-extend to full word size.
This also applies to a struct or union. */
val = type->is_unsigned ()
? extract_unsigned_integer (arg->contents ().data (),
length, byte_order)
: extract_signed_integer (arg->contents ().data (),
length, byte_order);
}
if (as->gr <= 6)
{
if (write_mode)
regcache_cooked_write_unsigned (as->regcache,
S390_R0_REGNUM + as->gr,
val);
as->gr++;
}
else
{
if (write_mode)
write_memory_unsigned_integer (as->argp, word_size,
byte_order, val);
as->argp += word_size;
}
}
else if (s390_function_arg_integer (type) && length == 8)
{
if (as->gr <= 5)
{
if (write_mode)
{
as->regcache->cooked_write (S390_R0_REGNUM + as->gr,
arg->contents ().data ());
as->regcache->cooked_write
(S390_R0_REGNUM + as->gr + 1,
arg->contents ().data () + word_size);
}
as->gr += 2;
}
else
{
/* If we skipped r6 because we couldn't fit a DOUBLE_ARG
in it, then don't go back and use it again later. */
as->gr = 7;
if (write_mode)
write_memory (as->argp, arg->contents ().data (), length);
as->argp += length;
}
}
else
{
/* This argument type is never passed in registers. Place the
value in the copy area and pass a pointer to it. Use 8-byte
alignment as a conservative assumption. */
as->copy = align_down (as->copy - length, 8);
if (write_mode)
write_memory (as->copy, arg->contents ().data (), length);
if (as->gr <= 6)
{
if (write_mode)
regcache_cooked_write_unsigned (as->regcache,
S390_R0_REGNUM + as->gr,
as->copy);
as->gr++;
}
else
{
if (write_mode)
write_memory_unsigned_integer (as->argp, word_size,
byte_order, as->copy);
as->argp += word_size;
}
}
}
/* Put the actual parameter values pointed to by ARGS[0..NARGS-1] in
place to be passed to a function, as specified by the "GNU/Linux
for S/390 ELF Application Binary Interface Supplement".
SP is the current stack pointer. We must put arguments, links,
padding, etc. whereever they belong, and return the new stack
pointer value.
If STRUCT_RETURN is non-zero, then the function we're calling is
going to return a structure by value; STRUCT_ADDR is the address of
a block we've allocated for it on the stack.
Our caller has taken care of any type promotions needed to satisfy
prototypes or the old K&R argument-passing rules. */
static CORE_ADDR
s390_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
struct regcache *regcache, CORE_ADDR bp_addr,
int nargs, struct value **args, CORE_ADDR sp,
function_call_return_method return_method,
CORE_ADDR struct_addr)
{
s390_gdbarch_tdep *tdep = gdbarch_tdep<s390_gdbarch_tdep> (gdbarch);
int word_size = gdbarch_ptr_bit (gdbarch) / 8;
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
int i;
struct s390_arg_state arg_state, arg_prep;
CORE_ADDR param_area_start, new_sp;
struct type *ftype = check_typedef (function->type ());
if (ftype->code () == TYPE_CODE_PTR)
ftype = check_typedef (ftype->target_type ());
arg_prep.copy = sp;
arg_prep.gr = (return_method == return_method_struct) ? 3 : 2;
arg_prep.fr = 0;
arg_prep.vr = 0;
arg_prep.argp = 0;
arg_prep.regcache = NULL;
/* Initialize arg_state for "preparation mode". */
arg_state = arg_prep;
/* Update arg_state.copy with the start of the reference-to-copy area
and arg_state.argp with the size of the parameter area. */
for (i = 0; i < nargs; i++)
s390_handle_arg (&arg_state, args[i], tdep, word_size, byte_order,
ftype->has_varargs () && i >= ftype->num_fields ());
param_area_start = align_down (arg_state.copy - arg_state.argp, 8);
/* Allocate the standard frame areas: the register save area, the
word reserved for the compiler, and the back chain pointer. */
new_sp = param_area_start - (16 * word_size + 32);
/* Now we have the final stack pointer. Make sure we didn't
underflow; on 31-bit, this would result in addresses with the
high bit set, which causes confusion elsewhere. Note that if we
error out here, stack and registers remain untouched. */
if (gdbarch_addr_bits_remove (gdbarch, new_sp) != new_sp)
error (_("Stack overflow"));
/* Pass the structure return address in general register 2. */
if (return_method == return_method_struct)
regcache_cooked_write_unsigned (regcache, S390_R2_REGNUM, struct_addr);
/* Initialize arg_state for "write mode". */
arg_state = arg_prep;
arg_state.argp = param_area_start;
arg_state.regcache = regcache;
/* Write all parameters. */
for (i = 0; i < nargs; i++)
s390_handle_arg (&arg_state, args[i], tdep, word_size, byte_order,
ftype->has_varargs () && i >= ftype->num_fields ());
/* Store return PSWA. In 31-bit mode, keep addressing mode bit. */
if (word_size == 4)
{
ULONGEST pswa;
regcache_cooked_read_unsigned (regcache, S390_PSWA_REGNUM, &pswa);
bp_addr = (bp_addr & 0x7fffffff) | (pswa & 0x80000000);
}
regcache_cooked_write_unsigned (regcache, S390_RETADDR_REGNUM, bp_addr);
/* Store updated stack pointer. */
regcache_cooked_write_unsigned (regcache, S390_SP_REGNUM, new_sp);
/* We need to return the 'stack part' of the frame ID,
which is actually the top of the register save area. */
return param_area_start;
}
/* Assuming THIS_FRAME is a dummy, return the frame ID of that
dummy frame. The frame ID's base needs to match the TOS value
returned by push_dummy_call, and the PC match the dummy frame's
breakpoint. */
static struct frame_id
s390_dummy_id (struct gdbarch *gdbarch, const frame_info_ptr &this_frame)
{
int word_size = gdbarch_ptr_bit (gdbarch) / 8;
CORE_ADDR sp = get_frame_register_unsigned (this_frame, S390_SP_REGNUM);
sp = gdbarch_addr_bits_remove (gdbarch, sp);
return frame_id_build (sp + 16*word_size + 32,
get_frame_pc (this_frame));
}
/* Implement frame_align gdbarch method. */
static CORE_ADDR
s390_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr)
{
/* Both the 32- and 64-bit ABI's say that the stack pointer should
always be aligned on an eight-byte boundary. */
return (addr & -8);
}
/* Helper for s390_return_value: Set or retrieve a function return
value if it resides in a register. */
static void
s390_register_return_value (struct gdbarch *gdbarch, struct type *type,
struct regcache *regcache,
gdb_byte *out, const gdb_byte *in)
{
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
int word_size = gdbarch_ptr_bit (gdbarch) / 8;
int length = type->length ();
int code = type->code ();
if (code == TYPE_CODE_FLT || code == TYPE_CODE_DECFLOAT)
{
/* Float-like value: left-aligned in f0. */
if (in != NULL)
regcache->cooked_write_part (S390_F0_REGNUM, 0, length, in);
else
regcache->cooked_read_part (S390_F0_REGNUM, 0, length, out);
}
else if (code == TYPE_CODE_ARRAY)
{
/* Vector: left-aligned in v24. */
if (in != NULL)
regcache->cooked_write_part (S390_V24_REGNUM, 0, length, in);
else
regcache->cooked_read_part (S390_V24_REGNUM, 0, length, out);
}
else if (length <= word_size)
{
/* Integer: zero- or sign-extended in r2. */
if (out != NULL)
regcache->cooked_read_part (S390_R2_REGNUM, word_size - length, length,
out);
else if (type->is_unsigned ())
regcache_cooked_write_unsigned
(regcache, S390_R2_REGNUM,
extract_unsigned_integer (in, length, byte_order));
else
regcache_cooked_write_signed
(regcache, S390_R2_REGNUM,
extract_signed_integer (in, length, byte_order));
}
else if (length == 2 * word_size)
{
/* Double word: in r2 and r3. */
if (in != NULL)
{
regcache->cooked_write (S390_R2_REGNUM, in);
regcache->cooked_write (S390_R3_REGNUM, in + word_size);
}
else
{
regcache->cooked_read (S390_R2_REGNUM, out);
regcache->cooked_read (S390_R3_REGNUM, out + word_size);
}
}
else
internal_error (_("invalid return type"));
}
/* Implement the 'return_value' gdbarch method. */
static enum return_value_convention
s390_return_value (struct gdbarch *gdbarch, struct value *function,
struct type *type, struct regcache *regcache,
gdb_byte *out, const gdb_byte *in)
{
enum return_value_convention rvc;
type = check_typedef (type);
switch (type->code ())
{
case TYPE_CODE_STRUCT:
case TYPE_CODE_UNION:
case TYPE_CODE_COMPLEX:
rvc = RETURN_VALUE_STRUCT_CONVENTION;
break;
case TYPE_CODE_ARRAY:
{
s390_gdbarch_tdep *tdep = gdbarch_tdep<s390_gdbarch_tdep> (gdbarch);
rvc = (tdep->vector_abi == S390_VECTOR_ABI_128
&& type->length () <= 16 && type->is_vector ())
? RETURN_VALUE_REGISTER_CONVENTION
: RETURN_VALUE_STRUCT_CONVENTION;
break;
}
default:
rvc = type->length () <= 8
? RETURN_VALUE_REGISTER_CONVENTION
: RETURN_VALUE_STRUCT_CONVENTION;
}
if (in != NULL || out != NULL)
{
if (rvc == RETURN_VALUE_REGISTER_CONVENTION)
s390_register_return_value (gdbarch, type, regcache, out, in);
else if (in != NULL)
error (_("Cannot set function return value."));
else
error (_("Function return value unknown."));
}
return rvc;
}
/* Frame unwinding. */
/* Implement the stack_frame_destroyed_p gdbarch method. */
static int
s390_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR pc)
{
int word_size = gdbarch_ptr_bit (gdbarch) / 8;
/* In frameless functions, there's no frame to destroy and thus
we don't care about the epilogue.
In functions with frame, the epilogue sequence is a pair of
a LM-type instruction that restores (amongst others) the
return register %r14 and the stack pointer %r15, followed
by a branch 'br %r14' --or equivalent-- that effects the
actual return.
In that situation, this function needs to return 'true' in
exactly one case: when pc points to that branch instruction.
Thus we try to disassemble the one instructions immediately
preceding pc and check whether it is an LM-type instruction
modifying the stack pointer.
Note that disassembling backwards is not reliable, so there
is a slight chance of false positives here ... */
bfd_byte insn[6];
unsigned int r1, r3, b2;
int d2;
if (word_size == 4
&& !target_read_memory (pc - 4, insn, 4)
&& is_rs (insn, op_lm, &r1, &r3, &d2, &b2)
&& r3 == S390_SP_REGNUM - S390_R0_REGNUM)
return 1;
if (word_size == 4
&& !target_read_memory (pc - 6, insn, 6)
&& is_rsy (insn, op1_lmy, op2_lmy, &r1, &r3, &d2, &b2)
&& r3 == S390_SP_REGNUM - S390_R0_REGNUM)
return 1;
if (word_size == 8
&& !target_read_memory (pc - 6, insn, 6)
&& is_rsy (insn, op1_lmg, op2_lmg, &r1, &r3, &d2, &b2)
&& r3 == S390_SP_REGNUM - S390_R0_REGNUM)
return 1;
return 0;
}
/* Implement unwind_pc gdbarch method. */
static CORE_ADDR
s390_unwind_pc (struct gdbarch *gdbarch, const frame_info_ptr &next_frame)
{
s390_gdbarch_tdep *tdep = gdbarch_tdep<s390_gdbarch_tdep> (gdbarch);
ULONGEST pc;
pc = frame_unwind_register_unsigned (next_frame, tdep->pc_regnum);
return gdbarch_addr_bits_remove (gdbarch, pc);
}
/* Implement unwind_sp gdbarch method. */
static CORE_ADDR
s390_unwind_sp (struct gdbarch *gdbarch, const frame_info_ptr &next_frame)
{
ULONGEST sp;
sp = frame_unwind_register_unsigned (next_frame, S390_SP_REGNUM);
return gdbarch_addr_bits_remove (gdbarch, sp);
}
/* Helper routine to unwind pseudo registers. */
static struct value *
s390_unwind_pseudo_register (const frame_info_ptr &this_frame, int regnum)
{
struct gdbarch *gdbarch = get_frame_arch (this_frame);
s390_gdbarch_tdep *tdep = gdbarch_tdep<s390_gdbarch_tdep> (gdbarch);
struct type *type = register_type (gdbarch, regnum);
/* Unwind PC via PSW address. */
if (regnum == tdep->pc_regnum)
{
struct value *val;
val = frame_unwind_register_value (this_frame, S390_PSWA_REGNUM);
if (!val->optimized_out ())
{
LONGEST pswa = value_as_long (val);
if (type->length () == 4)
return value_from_pointer (type, pswa & 0x7fffffff);
else
return value_from_pointer (type, pswa);
}
}
/* Unwind CC via PSW mask. */
if (regnum == tdep->cc_regnum)
{
struct value *val;
val = frame_unwind_register_value (this_frame, S390_PSWM_REGNUM);
if (!val->optimized_out ())
{
LONGEST pswm = value_as_long (val);
if (type->length () == 4)
return value_from_longest (type, (pswm >> 12) & 3);
else
return value_from_longest (type, (pswm >> 44) & 3);
}
}
/* Unwind full GPRs to show at least the lower halves (as the
upper halves are undefined). */
if (regnum_is_gpr_full (tdep, regnum))
{
int reg = regnum - tdep->gpr_full_regnum;
struct value *val;
val = frame_unwind_register_value (this_frame, S390_R0_REGNUM + reg);
if (!val->optimized_out ())
return value_cast (type, val);
}
return value::allocate_optimized_out (type);
}
/* Translate a .eh_frame register to DWARF register, or adjust a
.debug_frame register. */
static int
s390_adjust_frame_regnum (struct gdbarch *gdbarch, int num, int eh_frame_p)
{
/* See s390_dwarf_reg_to_regnum for comments. */
return (num >= 0 && num < 16) ? num + s390_dwarf_reg_r0l : num;
}
/* DWARF-2 frame unwinding. */
/* Function to unwind a pseudo-register in dwarf2_frame unwinder. Used by
s390_dwarf2_frame_init_reg. */
static struct value *
s390_dwarf2_prev_register (const frame_info_ptr &this_frame, void **this_cache,
int regnum)
{
return s390_unwind_pseudo_register (this_frame, regnum);
}
/* Implement init_reg dwarf2_frame method. */
static void
s390_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
struct dwarf2_frame_state_reg *reg,
const frame_info_ptr &this_frame)
{
/* The condition code (and thus PSW mask) is call-clobbered. */
if (regnum == S390_PSWM_REGNUM)
reg->how = DWARF2_FRAME_REG_UNDEFINED;
/* The PSW address unwinds to the return address. */
else if (regnum == S390_PSWA_REGNUM)
reg->how = DWARF2_FRAME_REG_RA;
/* Fixed registers are call-saved or call-clobbered
depending on the ABI in use. */
else if (regnum < S390_NUM_REGS)
{
if (s390_register_call_saved (gdbarch, regnum))
reg->how = DWARF2_FRAME_REG_SAME_VALUE;
else
reg->how = DWARF2_FRAME_REG_UNDEFINED;
}
/* We install a special function to unwind pseudos. */
else
{
reg->how = DWARF2_FRAME_REG_FN;
reg->loc.fn = s390_dwarf2_prev_register;
}
}
/* Frame unwinding. */
/* Wrapper for trad_frame_get_prev_register to allow for s390 pseudo
register translation. */
struct value *
s390_trad_frame_prev_register (const frame_info_ptr &this_frame,
trad_frame_saved_reg saved_regs[],
int regnum)
{
if (regnum < S390_NUM_REGS)
return trad_frame_get_prev_register (this_frame, saved_regs, regnum);
else
return s390_unwind_pseudo_register (this_frame, regnum);
}
/* Normal stack frames. */
struct s390_unwind_cache {
CORE_ADDR func;
CORE_ADDR frame_base;
CORE_ADDR local_base;
trad_frame_saved_reg *saved_regs;
};
/* Unwind THIS_FRAME and write the information into unwind cache INFO using
prologue analysis. Helper for s390_frame_unwind_cache. */
static int
s390_prologue_frame_unwind_cache (const frame_info_ptr &this_frame,
struct s390_unwind_cache *info)
{
struct gdbarch *gdbarch = get_frame_arch (this_frame);
int word_size = gdbarch_ptr_bit (gdbarch) / 8;
struct s390_prologue_data data;
pv_t *fp = &data.gpr[S390_FRAME_REGNUM - S390_R0_REGNUM];
pv_t *sp = &data.gpr[S390_SP_REGNUM - S390_R0_REGNUM];
int i;
CORE_ADDR cfa;
CORE_ADDR func;
CORE_ADDR result;
ULONGEST reg;
CORE_ADDR prev_sp;
int frame_pointer;
int size;
frame_info_ptr next_frame;
/* Try to find the function start address. If we can't find it, we don't
bother searching for it -- with modern compilers this would be mostly
pointless anyway. Trust that we'll either have valid DWARF-2 CFI data
or else a valid backchain ... */
if (!get_frame_func_if_available (this_frame, &info->func))
{
info->func = -1;
return 0;
}
func = info->func;
/* Try to analyze the prologue. */
result = s390_analyze_prologue (gdbarch, func,
get_frame_pc (this_frame), &data);
if (!result)
return 0;
/* If this was successful, we should have found the instruction that
sets the stack pointer register to the previous value of the stack
pointer minus the frame size. */
if (!pv_is_register (*sp, S390_SP_REGNUM))
return 0;
/* A frame size of zero at this point can mean either a real
frameless function, or else a failure to find the prologue.
Perform some sanity checks to verify we really have a
frameless function. */
if (sp->k == 0)
{
/* If the next frame is a NORMAL_FRAME, this frame *cannot* have frame
size zero. This is only possible if the next frame is a sentinel
frame, a dummy frame, or a signal trampoline frame. */
/* FIXME: cagney/2004-05-01: This sanity check shouldn't be
needed, instead the code should simpliy rely on its
analysis. */
next_frame = get_next_frame (this_frame);
while (next_frame && get_frame_type (next_frame) == INLINE_FRAME)
next_frame = get_next_frame (next_frame);
if (next_frame
&& get_frame_type (get_next_frame (this_frame)) == NORMAL_FRAME)
return 0;
/* If we really have a frameless function, %r14 must be valid
-- in particular, it must point to a different function. */
reg = get_frame_register_unsigned (this_frame, S390_RETADDR_REGNUM);
reg = gdbarch_addr_bits_remove (gdbarch, reg) - 1;
if (get_pc_function_start (reg) == func)
{
/* However, there is one case where it *is* valid for %r14
to point to the same function -- if this is a recursive
call, and we have stopped in the prologue *before* the
stack frame was allocated.
Recognize this case by looking ahead a bit ... */
struct s390_prologue_data data2;
pv_t *sp2 = &data2.gpr[S390_SP_REGNUM - S390_R0_REGNUM];
if (!(s390_analyze_prologue (gdbarch, func, (CORE_ADDR)-1, &data2)
&& pv_is_register (*sp2, S390_SP_REGNUM)
&& sp2->k != 0))
return 0;
}
}
/* OK, we've found valid prologue data. */
size = -sp->k;
/* If the frame pointer originally also holds the same value
as the stack pointer, we're probably using it. If it holds
some other value -- even a constant offset -- it is most
likely used as temp register. */
if (pv_is_identical (*sp, *fp))
frame_pointer = S390_FRAME_REGNUM;
else
frame_pointer = S390_SP_REGNUM;
/* If we've detected a function with stack frame, we'll still have to
treat it as frameless if we're currently within the function epilog
code at a point where the frame pointer has already been restored.
This can only happen in an innermost frame. */
/* FIXME: cagney/2004-05-01: This sanity check shouldn't be needed,
instead the code should simpliy rely on its analysis. */
next_frame = get_next_frame (this_frame);
while (next_frame && get_frame_type (next_frame) == INLINE_FRAME)
next_frame = get_next_frame (next_frame);
if (size > 0
&& (next_frame == NULL
|| get_frame_type (get_next_frame (this_frame)) != NORMAL_FRAME))
{
/* See the comment in s390_stack_frame_destroyed_p on why this is
not completely reliable ... */
if (s390_stack_frame_destroyed_p (gdbarch, get_frame_pc (this_frame)))
{
memset (&data, 0, sizeof (data));
size = 0;
frame_pointer = S390_SP_REGNUM;
}
}
/* Once we know the frame register and the frame size, we can unwind
the current value of the frame register from the next frame, and
add back the frame size to arrive that the previous frame's
stack pointer value. */
prev_sp = get_frame_register_unsigned (this_frame, frame_pointer) + size;
cfa = prev_sp + 16*word_size + 32;
/* Set up ABI call-saved/call-clobbered registers. */
for (i = 0; i < S390_NUM_REGS; i++)
if (!s390_register_call_saved (gdbarch, i))
info->saved_regs[i].set_unknown ();
/* CC is always call-clobbered. */
info->saved_regs[S390_PSWM_REGNUM].set_unknown ();
/* Record the addresses of all register spill slots the prologue parser
has recognized. Consider only registers defined as call-saved by the
ABI; for call-clobbered registers the parser may have recognized
spurious stores. */
for (i = 0; i < 16; i++)
if (s390_register_call_saved (gdbarch, S390_R0_REGNUM + i)
&& data.gpr_slot[i] != 0)
info->saved_regs[S390_R0_REGNUM + i].set_addr (cfa - data.gpr_slot[i]);
for (i = 0; i < 16; i++)
if (s390_register_call_saved (gdbarch, S390_F0_REGNUM + i)
&& data.fpr_slot[i] != 0)
info->saved_regs[S390_F0_REGNUM + i].set_addr (cfa - data.fpr_slot[i]);
/* Function return will set PC to %r14. */
info->saved_regs[S390_PSWA_REGNUM] = info->saved_regs[S390_RETADDR_REGNUM];
/* In frameless functions, we unwind simply by moving the return
address to the PC. However, if we actually stored to the
save area, use that -- we might only think the function frameless
because we're in the middle of the prologue ... */
if (size == 0
&& !info->saved_regs[S390_PSWA_REGNUM].is_addr ())
{
info->saved_regs[S390_PSWA_REGNUM].set_realreg (S390_RETADDR_REGNUM);
}
/* Another sanity check: unless this is a frameless function,
we should have found spill slots for SP and PC.
If not, we cannot unwind further -- this happens e.g. in
libc's thread_start routine. */
if (size > 0)
{
if (!info->saved_regs[S390_SP_REGNUM].is_addr ()
|| !info->saved_regs[S390_PSWA_REGNUM].is_addr ())
prev_sp = -1;
}
/* We use the current value of the frame register as local_base,
and the top of the register save area as frame_base. */
if (prev_sp != -1)
{
info->frame_base = prev_sp + 16*word_size + 32;
info->local_base = prev_sp - size;
}
return 1;
}
/* Unwind THIS_FRAME and write the information into unwind cache INFO using
back chain unwinding. Helper for s390_frame_unwind_cache. */
static void
s390_backchain_frame_unwind_cache (const frame_info_ptr &this_frame,
struct s390_unwind_cache *info)
{
struct gdbarch *gdbarch = get_frame_arch (this_frame);
int word_size = gdbarch_ptr_bit (gdbarch) / 8;
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
CORE_ADDR backchain;
ULONGEST reg;
LONGEST sp, tmp;
int i;
/* Set up ABI call-saved/call-clobbered registers. */
for (i = 0; i < S390_NUM_REGS; i++)
if (!s390_register_call_saved (gdbarch, i))
info->saved_regs[i].set_unknown ();
/* CC is always call-clobbered. */
info->saved_regs[S390_PSWM_REGNUM].set_unknown ();
/* Get the backchain. */
reg = get_frame_register_unsigned (this_frame, S390_SP_REGNUM);
if (!safe_read_memory_integer (reg, word_size, byte_order, &tmp))
tmp = 0;
backchain = (CORE_ADDR) tmp;
/* A zero backchain terminates the frame chain. As additional
sanity check, let's verify that the spill slot for SP in the
save area pointed to by the backchain in fact links back to
the save area. */
if (backchain != 0
&& safe_read_memory_integer (backchain + 15*word_size,
word_size, byte_order, &sp)
&& (CORE_ADDR)sp == backchain)
{
/* We don't know which registers were saved, but it will have
to be at least %r14 and %r15. This will allow us to continue
unwinding, but other prev-frame registers may be incorrect ... */
info->saved_regs[S390_SP_REGNUM].set_addr (backchain + 15*word_size);
info->saved_regs[S390_RETADDR_REGNUM].set_addr (backchain + 14*word_size);
/* Function return will set PC to %r14. */
info->saved_regs[S390_PSWA_REGNUM]
= info->saved_regs[S390_RETADDR_REGNUM];
/* We use the current value of the frame register as local_base,
and the top of the register save area as frame_base. */
info->frame_base = backchain + 16*word_size + 32;
info->local_base = reg;
}
info->func = get_frame_pc (this_frame);
}
/* Unwind THIS_FRAME and return the corresponding unwind cache for
s390_frame_unwind and s390_frame_base. */
static struct s390_unwind_cache *
s390_frame_unwind_cache (const frame_info_ptr &this_frame,
void **this_prologue_cache)
{
struct s390_unwind_cache *info;
if (*this_prologue_cache)
return (struct s390_unwind_cache *) *this_prologue_cache;
info = FRAME_OBSTACK_ZALLOC (struct s390_unwind_cache);
*this_prologue_cache = info;
info->saved_regs = trad_frame_alloc_saved_regs (this_frame);
info->func = -1;
info->frame_base = -1;
info->local_base = -1;
try
{
/* Try to use prologue analysis to fill the unwind cache.
If this fails, fall back to reading the stack backchain. */
if (!s390_prologue_frame_unwind_cache (this_frame, info))
s390_backchain_frame_unwind_cache (this_frame, info);
}
catch (const gdb_exception_error &ex)
{
if (ex.error != NOT_AVAILABLE_ERROR)
throw;
}
return info;
}
/* Implement this_id frame_unwind method for s390_frame_unwind. */
static void
s390_frame_this_id (const frame_info_ptr &this_frame,
void **this_prologue_cache,
struct frame_id *this_id)
{
struct s390_unwind_cache *info
= s390_frame_unwind_cache (this_frame, this_prologue_cache);
if (info->frame_base == -1)
{
if (info->func != -1)
*this_id = frame_id_build_unavailable_stack (info->func);
return;
}
*this_id = frame_id_build (info->frame_base, info->func);
}
/* Implement prev_register frame_unwind method for s390_frame_unwind. */
static struct value *
s390_frame_prev_register (const frame_info_ptr &this_frame,
void **this_prologue_cache, int regnum)
{
struct s390_unwind_cache *info
= s390_frame_unwind_cache (this_frame, this_prologue_cache);
return s390_trad_frame_prev_register (this_frame, info->saved_regs, regnum);
}
/* Default S390 frame unwinder. */
static const struct frame_unwind s390_frame_unwind = {
"s390 prologue",
NORMAL_FRAME,
default_frame_unwind_stop_reason,
s390_frame_this_id,
s390_frame_prev_register,
NULL,
default_frame_sniffer
};
/* Code stubs and their stack frames. For things like PLTs and NULL
function calls (where there is no true frame and the return address
is in the RETADDR register). */
struct s390_stub_unwind_cache
{
CORE_ADDR frame_base;
trad_frame_saved_reg *saved_regs;
};
/* Unwind THIS_FRAME and return the corresponding unwind cache for
s390_stub_frame_unwind. */
static struct s390_stub_unwind_cache *
s390_stub_frame_unwind_cache (const frame_info_ptr &this_frame,
void **this_prologue_cache)
{
struct gdbarch *gdbarch = get_frame_arch (this_frame);
int word_size = gdbarch_ptr_bit (gdbarch) / 8;
struct s390_stub_unwind_cache *info;
ULONGEST reg;
if (*this_prologue_cache)
return (struct s390_stub_unwind_cache *) *this_prologue_cache;
info = FRAME_OBSTACK_ZALLOC (struct s390_stub_unwind_cache);
*this_prologue_cache = info;
info->saved_regs = trad_frame_alloc_saved_regs (this_frame);
/* The return address is in register %r14. */
info->saved_regs[S390_PSWA_REGNUM].set_realreg (S390_RETADDR_REGNUM);
/* Retrieve stack pointer and determine our frame base. */
reg = get_frame_register_unsigned (this_frame, S390_SP_REGNUM);
info->frame_base = reg + 16*word_size + 32;
return info;
}
/* Implement this_id frame_unwind method for s390_stub_frame_unwind. */
static void
s390_stub_frame_this_id (const frame_info_ptr &this_frame,
void **this_prologue_cache,
struct frame_id *this_id)
{
struct s390_stub_unwind_cache *info
= s390_stub_frame_unwind_cache (this_frame, this_prologue_cache);
*this_id = frame_id_build (info->frame_base, get_frame_pc (this_frame));
}
/* Implement prev_register frame_unwind method for s390_stub_frame_unwind. */
static struct value *
s390_stub_frame_prev_register (const frame_info_ptr &this_frame,
void **this_prologue_cache, int regnum)
{
struct s390_stub_unwind_cache *info
= s390_stub_frame_unwind_cache (this_frame, this_prologue_cache);
return s390_trad_frame_prev_register (this_frame, info->saved_regs, regnum);
}
/* Implement sniffer frame_unwind method for s390_stub_frame_unwind. */
static int
s390_stub_frame_sniffer (const struct frame_unwind *self,
const frame_info_ptr &this_frame,
void **this_prologue_cache)
{
CORE_ADDR addr_in_block;
bfd_byte insn[S390_MAX_INSTR_SIZE];
/* If the current PC points to non-readable memory, we assume we
have trapped due to an invalid function pointer call. We handle
the non-existing current function like a PLT stub. */
addr_in_block = get_frame_address_in_block (this_frame);
if (in_plt_section (addr_in_block)
|| s390_readinstruction (insn, get_frame_pc (this_frame)) < 0)
return 1;
return 0;
}
/* S390 stub frame unwinder. */
static const struct frame_unwind s390_stub_frame_unwind = {
"s390 stub",
NORMAL_FRAME,
default_frame_unwind_stop_reason,
s390_stub_frame_this_id,
s390_stub_frame_prev_register,
NULL,
s390_stub_frame_sniffer
};
/* Frame base handling. */
static CORE_ADDR
s390_frame_base_address (const frame_info_ptr &this_frame, void **this_cache)
{
struct s390_unwind_cache *info
= s390_frame_unwind_cache (this_frame, this_cache);
return info->frame_base;
}
static CORE_ADDR
s390_local_base_address (const frame_info_ptr &this_frame, void **this_cache)
{
struct s390_unwind_cache *info
= s390_frame_unwind_cache (this_frame, this_cache);
return info->local_base;
}
static const struct frame_base s390_frame_base = {
&s390_frame_unwind,
s390_frame_base_address,
s390_local_base_address,
s390_local_base_address
};
/* Process record-replay */
/* Takes the intermediate sum of address calculations and masks off upper
bits according to current addressing mode. */
static CORE_ADDR
s390_record_address_mask (struct gdbarch *gdbarch, struct regcache *regcache,
CORE_ADDR val)
{
s390_gdbarch_tdep *tdep = gdbarch_tdep<s390_gdbarch_tdep> (gdbarch);
ULONGEST pswm, pswa;
int am;
if (tdep->abi == ABI_LINUX_S390)
{
regcache_raw_read_unsigned (regcache, S390_PSWA_REGNUM, &pswa);
am = pswa >> 31 & 1;
}
else
{
regcache_raw_read_unsigned (regcache, S390_PSWM_REGNUM, &pswm);
am = pswm >> 31 & 3;
}
switch (am)
{
case 0:
return val & 0xffffff;
case 1:
return val & 0x7fffffff;
case 3:
return val;
default:
gdb_printf (gdb_stdlog, "Warning: Addressing mode %d used.", am);
return 0;
}
}
/* Calculates memory address using pre-calculated index, raw instruction word
with b and d/dl fields, and raw instruction byte with dh field. Index and
dh should be set to 0 if unused. */
static CORE_ADDR
s390_record_calc_disp_common (struct gdbarch *gdbarch, struct regcache *regcache,
ULONGEST x, uint16_t bd, int8_t dh)
{
uint8_t rb = bd >> 12 & 0xf;
int32_t d = (bd & 0xfff) | ((int32_t)dh << 12);
ULONGEST b;
CORE_ADDR res = d + x;
if (rb)
{
regcache_raw_read_unsigned (regcache, S390_R0_REGNUM + rb, &b);
res += b;
}
return s390_record_address_mask (gdbarch, regcache, res);
}
/* Calculates memory address using raw x, b + d/dl, dh fields from
instruction. rx and dh should be set to 0 if unused. */
static CORE_ADDR
s390_record_calc_disp (struct gdbarch *gdbarch, struct regcache *regcache,
uint8_t rx, uint16_t bd, int8_t dh)
{
ULONGEST x = 0;
if (rx)
regcache_raw_read_unsigned (regcache, S390_R0_REGNUM + rx, &x);
return s390_record_calc_disp_common (gdbarch, regcache, x, bd, dh);
}
/* Calculates memory address for VSCE[GF] instructions. */
static int
s390_record_calc_disp_vsce (struct gdbarch *gdbarch, struct regcache *regcache,
uint8_t vx, uint8_t el, uint8_t es, uint16_t bd,
int8_t dh, CORE_ADDR *res)
{
s390_gdbarch_tdep *tdep = gdbarch_tdep<s390_gdbarch_tdep> (gdbarch);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
ULONGEST x;
gdb_byte buf[16];
if (tdep->v0_full_regnum == -1 || el * es >= 16)
return -1;
if (vx < 16)
regcache->cooked_read (tdep->v0_full_regnum + vx, buf);
else
regcache->raw_read (S390_V16_REGNUM + vx - 16, buf);
x = extract_unsigned_integer (buf + el * es, es, byte_order);
*res = s390_record_calc_disp_common (gdbarch, regcache, x, bd, dh);
return 0;
}
/* Calculates memory address for instructions with relative long addressing. */
static CORE_ADDR
s390_record_calc_rl (struct gdbarch *gdbarch, struct regcache *regcache,
CORE_ADDR addr, uint16_t i1, uint16_t i2)
{
int32_t ri = i1 << 16 | i2;
return s390_record_address_mask (gdbarch, regcache, addr + (LONGEST)ri * 2);
}
/* Population count helper. */
static int s390_popcnt (unsigned int x) {
int res = 0;
while (x)
{
if (x & 1)
res++;
x >>= 1;
}
return res;
}
/* Record 64-bit register. */
static int
s390_record_gpr_g (struct gdbarch *gdbarch, struct regcache *regcache, int i)
{
s390_gdbarch_tdep *tdep = gdbarch_tdep<s390_gdbarch_tdep> (gdbarch);
if (record_full_arch_list_add_reg (regcache, S390_R0_REGNUM + i))
return -1;
if (tdep->abi == ABI_LINUX_S390)
if (record_full_arch_list_add_reg (regcache, S390_R0_UPPER_REGNUM + i))
return -1;
return 0;
}
/* Record high 32 bits of a register. */
static int
s390_record_gpr_h (struct gdbarch *gdbarch, struct regcache *regcache, int i)
{
s390_gdbarch_tdep *tdep = gdbarch_tdep<s390_gdbarch_tdep> (gdbarch);
if (tdep->abi == ABI_LINUX_S390)
{
if (record_full_arch_list_add_reg (regcache, S390_R0_UPPER_REGNUM + i))
return -1;
}
else
{
if (record_full_arch_list_add_reg (regcache, S390_R0_REGNUM + i))
return -1;
}
return 0;
}
/* Record vector register. */
static int
s390_record_vr (struct gdbarch *gdbarch, struct regcache *regcache, int i)
{
if (i < 16)
{
if (record_full_arch_list_add_reg (regcache, S390_F0_REGNUM + i))
return -1;
if (record_full_arch_list_add_reg (regcache, S390_V0_LOWER_REGNUM + i))
return -1;
}
else
{
if (record_full_arch_list_add_reg (regcache, S390_V16_REGNUM + i - 16))
return -1;
}
return 0;
}
/* Implement process_record gdbarch method. */
static int
s390_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
CORE_ADDR addr)
{
s390_gdbarch_tdep *tdep = gdbarch_tdep<s390_gdbarch_tdep> (gdbarch);
uint16_t insn[3] = {0};
/* Instruction as bytes. */
uint8_t ibyte[6];
/* Instruction as nibbles. */
uint8_t inib[12];
/* Instruction vector registers. */
uint8_t ivec[4];
CORE_ADDR oaddr, oaddr2, oaddr3;
ULONGEST tmp;
int i, n;
/* if EX/EXRL instruction used, here's the reg parameter */
int ex = -1;
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
/* Attempting to use EX or EXRL jumps back here */
ex:
/* Read instruction. */
insn[0] = read_memory_unsigned_integer (addr, 2, byte_order);
/* If execute was involved, do the adjustment. */
if (ex != -1)
insn[0] |= ex & 0xff;
/* Two highest bits determine instruction size. */
if (insn[0] >= 0x4000)
insn[1] = read_memory_unsigned_integer (addr+2, 2, byte_order);
else
/* Not necessary, but avoids uninitialized variable warnings. */
insn[1] = 0;
if (insn[0] >= 0xc000)
insn[2] = read_memory_unsigned_integer (addr+4, 2, byte_order);
else
insn[2] = 0;
/* Split instruction into bytes and nibbles. */
for (i = 0; i < 3; i++)
{
ibyte[i*2] = insn[i] >> 8 & 0xff;
ibyte[i*2+1] = insn[i] & 0xff;
}
for (i = 0; i < 6; i++)
{
inib[i*2] = ibyte[i] >> 4 & 0xf;
inib[i*2+1] = ibyte[i] & 0xf;
}
/* Compute vector registers, if applicable. */
ivec[0] = (inib[9] >> 3 & 1) << 4 | inib[2];
ivec[1] = (inib[9] >> 2 & 1) << 4 | inib[3];
ivec[2] = (inib[9] >> 1 & 1) << 4 | inib[4];
ivec[3] = (inib[9] >> 0 & 1) << 4 | inib[8];
switch (ibyte[0])
{
/* 0x00 undefined */
case 0x01:
/* E-format instruction */
switch (ibyte[1])
{
/* 0x00 undefined */
/* 0x01 unsupported: PR - program return */
/* 0x02 unsupported: UPT */
/* 0x03 undefined */