+ /* AHI r1, i2 --- add halfword immediate */
+ else if (is_ri (insn, op1_ahi, op2_ahi, &r1, &i2))
+ pv_add_constant (&gpr[r1], i2);
+
+
+ /* AGHI r1, i2 --- add halfword immediate (64-bit version) */
+ else if (GDB_TARGET_IS_ESAME
+ && is_ri (insn, op1_aghi, op2_aghi, &r1, &i2))
+ pv_add_constant (&gpr[r1], i2);
+
+ /* AR r1, r2 -- add register */
+ else if (is_rr (insn, op_ar, &r1, &r2))
+ pv_add (&gpr[r1], &gpr[r1], &gpr[r2]);
+
+ /* 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)
+ pv_set_to_constant (&gpr[r1], next_pc);
+
+ /* BRAS r1, i2 --- branch relative and save */
+ else if (is_ri (insn, op1_bras, op2_bras, &r1, &i2))
+ {
+ pv_set_to_constant (&gpr[r1], next_pc);
+ next_pc = pc + i2 * 2;
+
+ /* We'd better not interpret any backward branches. We'll
+ never terminate. */
+ if (next_pc <= pc)
+ break;
+ }
+
+ /* L r1, d2(x2, b2) --- load */
+ else if (is_rx (insn, op_l, &r1, &d2, &x2, &b2))
+ {
+ struct prologue_value addr;
+ struct prologue_value *stack;
+
+ compute_x_addr (&addr, gpr, 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 (addr.kind == pv_constant
+ && start_pc <= addr.k
+ && addr.k < next_pc)
+ pv_set_to_constant (&gpr[r1],
+ read_memory_integer (addr.k, 4));
+
+ /* If it's definitely a reference to something on the stack,
+ we can do that. */
+ else if (s390_on_stack (&addr, 4, gpr, spill, &back_chain, &stack)
+ == pv_definite_yes)
+ gpr[r1] = *stack;
+
+ /* Otherwise, we don't know the value. */
+ else
+ pv_set_to_unknown (&gpr[r1]);
+ }
+
+ /* LA r1, d2(x2, b2) --- load address */
+ else if (is_rx (insn, op_la, &r1, &d2, &x2, &b2))
+ compute_x_addr (&gpr[r1], gpr, d2, x2, b2);
+
+ /* LARL r1, i2 --- load address relative long */
+ else if (GDB_TARGET_IS_ESAME
+ && is_ril (insn, op1_larl, op2_larl, &r1, &i2))
+ pv_set_to_constant (&gpr[r1], pc + i2 * 2);
+
+ /* LGR r1, r2 --- load from register */
+ else if (GDB_TARGET_IS_ESAME
+ && is_rre (insn, op_lgr, &r1, &r2))
+ gpr[r1] = gpr[r2];
+
+ /* LHI r1, i2 --- load halfword immediate */
+ else if (is_ri (insn, op1_lhi, op2_lhi, &r1, &i2))
+ pv_set_to_constant (&gpr[r1], i2);
+
+ /* LGHI r1, i2 --- load halfword immediate --- 64-bit version */
+ else if (is_ri (insn, op1_lghi, op2_lghi, &r1, &i2))
+ pv_set_to_constant (&gpr[r1], i2);
+
+ /* LR r1, r2 --- load from register */
+ else if (is_rr (insn, op_lr, &r1, &r2))
+ gpr[r1] = gpr[r2];
+
+ /* NGR r1, r2 --- logical and --- 64-bit version */
+ else if (GDB_TARGET_IS_ESAME
+ && is_rre (insn, op_ngr, &r1, &r2))
+ pv_logical_and (&gpr[r1], &gpr[r1], &gpr[r2]);
+
+ /* NR r1, r2 --- logical and */
+ else if (is_rr (insn, op_nr, &r1, &r2))
+ pv_logical_and (&gpr[r1], &gpr[r1], &gpr[r2]);
+
+ /* NGR r1, r2 --- logical and --- 64-bit version */
+ else if (GDB_TARGET_IS_ESAME
+ && is_rre (insn, op_ngr, &r1, &r2))
+ pv_logical_and (&gpr[r1], &gpr[r1], &gpr[r2]);
+
+ /* NR r1, r2 --- logical and */
+ else if (is_rr (insn, op_nr, &r1, &r2))
+ pv_logical_and (&gpr[r1], &gpr[r1], &gpr[r2]);
+
+ /* S r1, d2(x2, b2) --- subtract from memory */
+ else if (is_rx (insn, op_s, &r1, &d2, &x2, &b2))
+ {
+ struct prologue_value addr;
+ struct prologue_value value;
+ struct prologue_value *stack;
+
+ compute_x_addr (&addr, gpr, 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 and the time when we're analyzing it. */
+ if (addr.kind == pv_constant
+ && start_pc <= addr.k
+ && addr.k < pc)
+ pv_set_to_constant (&value, read_memory_integer (addr.k, 4));
+
+ /* If it's definitely a reference to something on the stack,
+ we could do that. */
+ else if (s390_on_stack (&addr, 4, gpr, spill, &back_chain, &stack)
+ == pv_definite_yes)
+ value = *stack;
+
+ /* Otherwise, we don't know the value. */
+ else
+ pv_set_to_unknown (&value);
+
+ pv_subtract (&gpr[r1], &gpr[r1], &value);
+ }
+
+ /* ST r1, d2(x2, b2) --- store */
+ else if (is_rx (insn, op_st, &r1, &d2, &x2, &b2))
+ {
+ struct prologue_value addr;
+
+ compute_x_addr (&addr, gpr, d2, x2, b2);
+
+ /* The below really should be '4', not 'S390_GPR_SIZE'; this
+ instruction always stores 32 bits, regardless of the full
+ size of the GPR. */
+ if (s390_store (&addr, 4, &gpr[r1], gpr, spill, &back_chain)
+ == pv_maybe)
+ /* If we can't be sure that it's *not* a store to
+ something we're tracing, then we would have to mark all
+ our memory as unknown --- after all, it *could* be a
+ store to any of them --- so we might as well just stop
+ interpreting. */
+ break;
+ }
+
+ /* STD r1, d2(x2,b2) --- store floating-point register */
+ else if (is_rx (insn, op_std, &r1, &d2, &x2, &b2))
+ {
+ struct prologue_value addr;
+
+ compute_x_addr (&addr, gpr, d2, x2, b2);
+
+ if (s390_store (&addr, 8, &fpr[r1], gpr, spill, &back_chain)
+ == pv_maybe)
+ /* If we can't be sure that it's *not* a store to
+ something we're tracing, then we would have to mark all
+ our memory as unknown --- after all, it *could* be a
+ store to any of them --- so we might as well just stop
+ interpreting. */
+ break;
+ }
+
+ /* STG r1, d2(x2, b2) --- 64-bit store */
+ else if (GDB_TARGET_IS_ESAME
+ && is_rxe (insn, op1_stg, op2_stg, &r1, &d2, &x2, &b2))
+ {
+ struct prologue_value addr;
+
+ compute_x_addr (&addr, gpr, d2, x2, b2);
+
+ /* The below really should be '8', not 'S390_GPR_SIZE'; this
+ instruction always stores 64 bits, regardless of the full
+ size of the GPR. */
+ if (s390_store (&addr, 8, &gpr[r1], gpr, spill, &back_chain)
+ == pv_maybe)
+ /* If we can't be sure that it's *not* a store to
+ something we're tracing, then we would have to mark all
+ our memory as unknown --- after all, it *could* be a
+ store to any of them --- so we might as well just stop
+ interpreting. */
+ break;
+ }
+
+ /* STM r1, r3, d2(b2) --- store multiple */
+ else if (is_rs (insn, op_stm, &r1, &r3, &d2, &b2))
+ {
+ int regnum;
+ int offset;
+ struct prologue_value addr;
+
+ for (regnum = r1, offset = 0;
+ regnum <= r3;
+ regnum++, offset += 4)
+ {
+ compute_x_addr (&addr, gpr, d2 + offset, 0, b2);
+
+ if (s390_store (&addr, 4, &gpr[regnum], gpr, spill, &back_chain)
+ == pv_maybe)
+ /* If we can't be sure that it's *not* a store to
+ something we're tracing, then we would have to mark all
+ our memory as unknown --- after all, it *could* be a
+ store to any of them --- so we might as well just stop
+ interpreting. */
+ break;
+ }
+
+ /* If we left the loop early, we should stop interpreting
+ altogether. */
+ if (regnum <= r3)
+ break;
+ }
+
+ /* STMG r1, r3, d2(b2) --- store multiple, 64-bit */
+ else if (GDB_TARGET_IS_ESAME
+ && is_rse (insn, op1_stmg, op2_stmg, &r1, &r3, &d2, &b2))
+ {
+ int regnum;
+ int offset;
+ struct prologue_value addr;
+
+ for (regnum = r1, offset = 0;
+ regnum <= r3;
+ regnum++, offset += 8)
+ {
+ compute_x_addr (&addr, gpr, d2 + offset, 0, b2);
+
+ if (s390_store (&addr, 8, &gpr[regnum], gpr, spill, &back_chain)
+ == pv_maybe)
+ /* If we can't be sure that it's *not* a store to
+ something we're tracing, then we would have to mark all
+ our memory as unknown --- after all, it *could* be a
+ store to any of them --- so we might as well just stop
+ interpreting. */
+ break;
+ }
+
+ /* If we left the loop early, we should stop interpreting
+ altogether. */
+ if (regnum <= r3)
+ 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 just stop
+ interpreting, and assume that the machine state we've got
+ now is good enough for unwinding the stack. */
+ break;
+
+ /* 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.) */
+ {
+ struct prologue_value *sp = &gpr[S390_SP_REGNUM - S390_GP0_REGNUM];
+ struct prologue_value *fp = &gpr[S390_FRAME_REGNUM - S390_GP0_REGNUM];
+
+ if ((! pv_is_identical (&pre_insn_sp, sp)
+ && ! pv_is_register (sp, S390_SP_REGNUM, 0))
+ || (! pv_is_identical (&pre_insn_fp, fp)
+ && ! pv_is_register (fp, S390_FRAME_REGNUM, 0))
+ || ! pv_is_identical (&pre_insn_back_chain, &back_chain))
+ after_last_frame_setup_insn = next_pc;
+ }
+ }
+
+ /* Okay, now gpr[], fpr[], spill[], and back_chain reflect the state
+ of the machine as of the first instruction we couldn't interpret
+ (hopefully the first non-prologue instruction). */
+ {
+ /* The size of the frame, or (CORE_ADDR) -1 if we couldn't figure
+ that out. */
+ CORE_ADDR frame_size = -1;
+
+ /* The value the SP had upon entry to the function, or
+ (CORE_ADDR) -1 if we can't figure that out. */
+ CORE_ADDR original_sp = -1;
+
+ /* Are we using S390_FRAME_REGNUM as a frame pointer register? */
+ int using_frame_pointer = 0;
+
+ /* If S390_FRAME_REGNUM is some constant offset from the SP, then
+ that strongly suggests that we're going to use that as our
+ frame pointer register, not the SP. */
+ {
+ struct prologue_value *fp = &gpr[S390_FRAME_REGNUM - S390_GP0_REGNUM];
+
+ if (fp->kind == pv_register
+ && fp->reg == S390_SP_REGNUM)
+ using_frame_pointer = 1;