* s390-tdep.c (enum pv_boolean): Remove.
(pv_is_array_ref): Remove. (s390_on_stack): Remove. (S390_NUM_SPILL_SLOTS): Remove. (struct s390_prologue_data): Remove members 'spill' and 'back_chain', add members 'gpr_slot', 'fpr_slot', and 'back_chain_saved_p'. (s390_store): Track all stores of orginal incoming registers to the stack constant offsets relative to the CFA, instead of only tracking stores into specific spill slots. (s390_load): Likewise. (s390_analyze_prologue): Adapt to struct s390_prologue_data changes. (s390_prologue_frame_unwind_cache): Likewise. Only track registers defined as call-saved by the ABI. (s390_push_dummy_call): Use bottom of dummy call argument save area as return value, not the top. Do not store to the called function's register save area. (s390_unwind_dummy_id): Adapt accordingly.
This commit is contained in:
parent
0a6ddd0822
commit
121d8485df
2 changed files with 140 additions and 199 deletions
|
@ -1,3 +1,23 @@
|
|||
2004-10-23 Ulrich Weigand <uweigand@de.ibm.com>
|
||||
|
||||
* s390-tdep.c (enum pv_boolean): Remove.
|
||||
(pv_is_array_ref): Remove.
|
||||
(s390_on_stack): Remove.
|
||||
(S390_NUM_SPILL_SLOTS): Remove.
|
||||
(struct s390_prologue_data): Remove members 'spill' and 'back_chain',
|
||||
add members 'gpr_slot', 'fpr_slot', and 'back_chain_saved_p'.
|
||||
(s390_store): Track all stores of orginal incoming registers to the
|
||||
stack constant offsets relative to the CFA, instead of only tracking
|
||||
stores into specific spill slots.
|
||||
(s390_load): Likewise.
|
||||
(s390_analyze_prologue): Adapt to struct s390_prologue_data changes.
|
||||
(s390_prologue_frame_unwind_cache): Likewise. Only track registers
|
||||
defined as call-saved by the ABI.
|
||||
(s390_push_dummy_call): Use bottom of dummy call argument save area
|
||||
as return value, not the top. Do not store to the called function's
|
||||
register save area.
|
||||
(s390_unwind_dummy_id): Adapt accordingly.
|
||||
|
||||
2004-10-23 Andrew Cagney <cagney@gnu.org>
|
||||
|
||||
* objfiles.h (struct objfile): Rename obj_private to
|
||||
|
|
315
gdb/s390-tdep.c
315
gdb/s390-tdep.c
|
@ -801,66 +801,6 @@ pv_is_register (struct prologue_value *a, int r, CORE_ADDR k)
|
|||
}
|
||||
|
||||
|
||||
/* A prologue-value-esque boolean type, including "maybe", when we
|
||||
can't figure out whether something is true or not. */
|
||||
enum pv_boolean {
|
||||
pv_maybe,
|
||||
pv_definite_yes,
|
||||
pv_definite_no,
|
||||
};
|
||||
|
||||
|
||||
/* Decide whether a reference to SIZE bytes at ADDR refers exactly to
|
||||
an element of an array. The array starts at ARRAY_ADDR, and has
|
||||
ARRAY_LEN values of ELT_SIZE bytes each. If ADDR definitely does
|
||||
refer to an array element, set *I to the index of the referenced
|
||||
element in the array, and return pv_definite_yes. If it definitely
|
||||
doesn't, return pv_definite_no. If we can't tell, return pv_maybe.
|
||||
|
||||
If the reference does touch the array, but doesn't fall exactly on
|
||||
an element boundary, or doesn't refer to the whole element, return
|
||||
pv_maybe. */
|
||||
static enum pv_boolean
|
||||
pv_is_array_ref (struct prologue_value *addr,
|
||||
CORE_ADDR size,
|
||||
struct prologue_value *array_addr,
|
||||
CORE_ADDR array_len,
|
||||
CORE_ADDR elt_size,
|
||||
int *i)
|
||||
{
|
||||
struct prologue_value offset;
|
||||
|
||||
/* Note that, since ->k is a CORE_ADDR, and CORE_ADDR is unsigned,
|
||||
if addr is *before* the start of the array, then this isn't going
|
||||
to be negative... */
|
||||
pv_subtract (&offset, addr, array_addr);
|
||||
|
||||
if (offset.kind == pv_constant)
|
||||
{
|
||||
/* This is a rather odd test. We want to know if the SIZE bytes
|
||||
at ADDR don't overlap the array at all, so you'd expect it to
|
||||
be an || expression: "if we're completely before || we're
|
||||
completely after". But with unsigned arithmetic, things are
|
||||
different: since it's a number circle, not a number line, the
|
||||
right values for offset.k are actually one contiguous range. */
|
||||
if (offset.k <= -size
|
||||
&& offset.k >= array_len * elt_size)
|
||||
return pv_definite_no;
|
||||
else if (offset.k % elt_size != 0
|
||||
|| size != elt_size)
|
||||
return pv_maybe;
|
||||
else
|
||||
{
|
||||
*i = offset.k / elt_size;
|
||||
return pv_definite_yes;
|
||||
}
|
||||
}
|
||||
else
|
||||
return pv_maybe;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Decoding S/390 instructions. */
|
||||
|
||||
/* Named opcode values for the S/390 instructions we recognize. Some
|
||||
|
@ -1116,10 +1056,6 @@ compute_x_addr (struct prologue_value *addr,
|
|||
}
|
||||
|
||||
|
||||
/* The number of GPR and FPR spill slots in an S/390 stack frame. We
|
||||
track general-purpose registers r2 -- r15, and floating-point
|
||||
registers f0, f2, f4, and f6. */
|
||||
#define S390_NUM_SPILL_SLOTS (14 + 4)
|
||||
#define S390_NUM_GPRS 16
|
||||
#define S390_NUM_FPRS 16
|
||||
|
||||
|
@ -1135,84 +1071,18 @@ struct s390_prologue_data {
|
|||
/* The floating-point registers. */
|
||||
struct prologue_value fpr[S390_NUM_FPRS];
|
||||
|
||||
/* The register spill stack slots in the caller's frame ---
|
||||
general-purpose registers r2 through r15, and floating-point
|
||||
registers. spill[i] is where gpr i+2 gets spilled;
|
||||
spill[(14, 15, 16, 17)] is where (f0, f2, f4, f6) get spilled. */
|
||||
struct prologue_value spill[S390_NUM_SPILL_SLOTS];
|
||||
/* 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];
|
||||
|
||||
/* The value of the back chain slot. This is only valid if the stack
|
||||
pointer is known to be less than its original value --- that is,
|
||||
if we have indeed allocated space on the stack. */
|
||||
struct prologue_value back_chain;
|
||||
/* 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;
|
||||
};
|
||||
|
||||
|
||||
/* If the SIZE bytes at ADDR are a stack slot we're actually tracking,
|
||||
return pv_definite_yes and set *STACK to point to the slot. If
|
||||
we're sure that they are not any of our stack slots, then return
|
||||
pv_definite_no. Otherwise, return pv_maybe.
|
||||
|
||||
DATA describes our current state (registers and stack slots). */
|
||||
static enum pv_boolean
|
||||
s390_on_stack (struct prologue_value *addr,
|
||||
CORE_ADDR size,
|
||||
struct s390_prologue_data *data,
|
||||
struct prologue_value **stack)
|
||||
{
|
||||
struct prologue_value gpr_spill_addr;
|
||||
struct prologue_value fpr_spill_addr;
|
||||
struct prologue_value back_chain_addr;
|
||||
int i;
|
||||
enum pv_boolean b;
|
||||
|
||||
/* Construct the addresses of the spill arrays and the back chain. */
|
||||
pv_set_to_register (&gpr_spill_addr, S390_SP_REGNUM, 2 * data->gpr_size);
|
||||
pv_set_to_register (&fpr_spill_addr, S390_SP_REGNUM, 16 * data->gpr_size);
|
||||
back_chain_addr = data->gpr[S390_SP_REGNUM - S390_R0_REGNUM];
|
||||
|
||||
/* We have to check for GPR and FPR references using two separate
|
||||
calls to pv_is_array_ref, since the GPR and FPR spill slots are
|
||||
different sizes. (SPILL is an array, but the thing it tracks
|
||||
isn't really an array.) */
|
||||
|
||||
/* Was it a reference to the GPR spill array? */
|
||||
b = pv_is_array_ref (addr, size, &gpr_spill_addr, 14, data->gpr_size, &i);
|
||||
if (b == pv_definite_yes)
|
||||
{
|
||||
*stack = &data->spill[i];
|
||||
return pv_definite_yes;
|
||||
}
|
||||
if (b == pv_maybe)
|
||||
return pv_maybe;
|
||||
|
||||
/* Was it a reference to the FPR spill array? */
|
||||
b = pv_is_array_ref (addr, size, &fpr_spill_addr, 4, data->fpr_size, &i);
|
||||
if (b == pv_definite_yes)
|
||||
{
|
||||
*stack = &data->spill[14 + i];
|
||||
return pv_definite_yes;
|
||||
}
|
||||
if (b == pv_maybe)
|
||||
return pv_maybe;
|
||||
|
||||
/* Was it a reference to the back chain?
|
||||
This isn't quite right. We ought to check whether we have
|
||||
actually allocated any new frame at all. */
|
||||
b = pv_is_array_ref (addr, size, &back_chain_addr, 1, data->gpr_size, &i);
|
||||
if (b == pv_definite_yes)
|
||||
{
|
||||
*stack = &data->back_chain;
|
||||
return pv_definite_yes;
|
||||
}
|
||||
if (b == pv_maybe)
|
||||
return pv_maybe;
|
||||
|
||||
/* All the above queries returned definite 'no's. */
|
||||
return pv_definite_no;
|
||||
}
|
||||
|
||||
|
||||
/* Do a SIZE-byte store of VALUE to ADDR. */
|
||||
static void
|
||||
s390_store (struct prologue_value *addr,
|
||||
|
@ -1220,22 +1090,61 @@ s390_store (struct prologue_value *addr,
|
|||
struct prologue_value *value,
|
||||
struct s390_prologue_data *data)
|
||||
{
|
||||
struct prologue_value *stack;
|
||||
struct prologue_value cfa, offset;
|
||||
int i;
|
||||
|
||||
/* We can do it if it's definitely a reference to something on the stack. */
|
||||
if (s390_on_stack (addr, size, data, &stack) == pv_definite_yes)
|
||||
/* Check whether we are storing the backchain. */
|
||||
pv_subtract (&offset, &data->gpr[S390_SP_REGNUM - S390_R0_REGNUM], addr);
|
||||
|
||||
if (offset.kind == pv_constant && offset.k == 0)
|
||||
if (size == data->gpr_size
|
||||
&& pv_is_register (value, S390_SP_REGNUM, 0))
|
||||
{
|
||||
*stack = *value;
|
||||
data->back_chain_saved_p = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Note: If s390_on_stack returns pv_maybe, you might think we should
|
||||
forget our cached values, as any of those might have been hit.
|
||||
|
||||
However, we make the assumption that --since the fields we track
|
||||
are save areas private to compiler, and never directly exposed to
|
||||
the user-- every access to our data is explicit. Hence, every
|
||||
memory access we cannot follow can't hit our data. */
|
||||
/* Check whether we are storing a register into the stack. */
|
||||
pv_set_to_register (&cfa, S390_SP_REGNUM, 16 * data->gpr_size + 32);
|
||||
pv_subtract (&offset, &cfa, addr);
|
||||
|
||||
if (offset.kind == pv_constant
|
||||
&& offset.k < INT_MAX && offset.k > 0
|
||||
&& offset.k % data->gpr_size == 0)
|
||||
{
|
||||
/* 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 (value, S390_R0_REGNUM + i, 0))
|
||||
if (data->gpr_slot[i] == 0
|
||||
|| data->gpr_slot[i] > offset.k)
|
||||
{
|
||||
data->gpr_slot[i] = offset.k;
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < S390_NUM_FPRS; i++)
|
||||
if (size == data->fpr_size
|
||||
&& pv_is_register (value, S390_F0_REGNUM + i, 0))
|
||||
if (data->fpr_slot[i] == 0
|
||||
|| data->fpr_slot[i] > offset.k)
|
||||
{
|
||||
data->fpr_slot[i] = offset.k;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* 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 ADDR into VALUE. */
|
||||
|
@ -1245,7 +1154,8 @@ s390_load (struct prologue_value *addr,
|
|||
struct prologue_value *value,
|
||||
struct s390_prologue_data *data)
|
||||
{
|
||||
struct prologue_value *stack;
|
||||
struct prologue_value cfa, offset;
|
||||
int i;
|
||||
|
||||
/* If it's a load from an in-line constant pool, then we can
|
||||
simulate that, under the assumption that the code isn't
|
||||
|
@ -1265,14 +1175,28 @@ s390_load (struct prologue_value *addr,
|
|||
}
|
||||
}
|
||||
|
||||
/* If it's definitely a reference to something on the stack,
|
||||
we can do that. */
|
||||
if (s390_on_stack (addr, size, data, &stack) == pv_definite_yes)
|
||||
/* Check whether we are accessing one of our save slots. */
|
||||
pv_set_to_register (&cfa, S390_SP_REGNUM, 16 * data->gpr_size + 32);
|
||||
pv_subtract (&offset, &cfa, addr);
|
||||
|
||||
if (offset.kind == pv_constant
|
||||
&& offset.k < INT_MAX && offset.k > 0)
|
||||
{
|
||||
*value = *stack;
|
||||
for (i = 0; i < S390_NUM_GPRS; i++)
|
||||
if (offset.k == data->gpr_slot[i])
|
||||
{
|
||||
pv_set_to_register (value, S390_R0_REGNUM + i, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < S390_NUM_FPRS; i++)
|
||||
if (offset.k == data->fpr_slot[i])
|
||||
{
|
||||
pv_set_to_register (value, S390_F0_REGNUM + i, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise, we don't know the value. */
|
||||
pv_set_to_unknown (value);
|
||||
}
|
||||
|
@ -1320,10 +1244,13 @@ s390_analyze_prologue (struct gdbarch *gdbarch,
|
|||
for (i = 0; i < S390_NUM_FPRS; i++)
|
||||
pv_set_to_register (&data->fpr[i], S390_F0_REGNUM + i, 0);
|
||||
|
||||
for (i = 0; i < S390_NUM_SPILL_SLOTS; i++)
|
||||
pv_set_to_unknown (&data->spill[i]);
|
||||
for (i = 0; i < S390_NUM_GPRS; i++)
|
||||
data->gpr_slot[i] = 0;
|
||||
|
||||
pv_set_to_unknown (&data->back_chain);
|
||||
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
|
||||
|
@ -1337,9 +1264,11 @@ s390_analyze_prologue (struct gdbarch *gdbarch,
|
|||
unsigned int b2, r1, r2, x2, r3;
|
||||
int i2, d2;
|
||||
|
||||
/* The values of SP, FP, and back chain before this instruction,
|
||||
/* The values of SP and FP before this instruction,
|
||||
for detecting instructions that change them. */
|
||||
struct prologue_value pre_insn_sp, pre_insn_fp, pre_insn_back_chain;
|
||||
struct prologue_value 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)
|
||||
|
@ -1352,7 +1281,7 @@ s390_analyze_prologue (struct gdbarch *gdbarch,
|
|||
|
||||
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 = data->back_chain;
|
||||
pre_insn_back_chain_saved_p = data->back_chain_saved_p;
|
||||
|
||||
/* LHI r1, i2 --- load halfword immediate */
|
||||
if (word_size == 4
|
||||
|
@ -1674,7 +1603,7 @@ s390_analyze_prologue (struct gdbarch *gdbarch,
|
|||
&& ! 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, &data->back_chain))
|
||||
|| pre_insn_back_chain_saved_p != data->back_chain_saved_p)
|
||||
result = next_pc;
|
||||
}
|
||||
}
|
||||
|
@ -1761,12 +1690,13 @@ s390_prologue_frame_unwind_cache (struct frame_info *next_frame,
|
|||
struct s390_unwind_cache *info)
|
||||
{
|
||||
struct gdbarch *gdbarch = get_frame_arch (next_frame);
|
||||
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
|
||||
int word_size = gdbarch_ptr_bit (gdbarch) / 8;
|
||||
struct s390_prologue_data data;
|
||||
struct prologue_value *fp = &data.gpr[S390_FRAME_REGNUM - S390_R0_REGNUM];
|
||||
struct prologue_value *sp = &data.gpr[S390_SP_REGNUM - S390_R0_REGNUM];
|
||||
int slot_num;
|
||||
CORE_ADDR slot_addr;
|
||||
int i;
|
||||
CORE_ADDR cfa;
|
||||
CORE_ADDR func;
|
||||
CORE_ADDR result;
|
||||
ULONGEST reg;
|
||||
|
@ -1869,33 +1799,31 @@ s390_prologue_frame_unwind_cache (struct frame_info *next_frame,
|
|||
add back the frame size to arrive that the previous frame's
|
||||
stack pointer value. */
|
||||
prev_sp = frame_unwind_register_unsigned (next_frame, frame_pointer) + size;
|
||||
cfa = prev_sp + 16*word_size + 32;
|
||||
|
||||
/* Scan the spill array; if a spill slot says it holds the
|
||||
original value of some register, then record that slot's
|
||||
address as the place that register was saved. */
|
||||
/* 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. */
|
||||
|
||||
/* Slots for %r2 .. %r15. */
|
||||
for (slot_num = 0, slot_addr = prev_sp + 2 * data.gpr_size;
|
||||
slot_num < 14;
|
||||
slot_num++, slot_addr += data.gpr_size)
|
||||
for (i = 6; i <= 15; i++)
|
||||
if (data.gpr_slot[i] != 0)
|
||||
info->saved_regs[S390_R0_REGNUM + i].addr = cfa - data.gpr_slot[i];
|
||||
|
||||
switch (tdep->abi)
|
||||
{
|
||||
struct prologue_value *slot = &data.spill[slot_num];
|
||||
case ABI_LINUX_S390:
|
||||
if (data.fpr_slot[4] != 0)
|
||||
info->saved_regs[S390_F4_REGNUM].addr = cfa - data.fpr_slot[4];
|
||||
if (data.fpr_slot[6] != 0)
|
||||
info->saved_regs[S390_F6_REGNUM].addr = cfa - data.fpr_slot[6];
|
||||
break;
|
||||
|
||||
if (slot->kind == pv_register
|
||||
&& slot->k == 0)
|
||||
info->saved_regs[slot->reg].addr = slot_addr;
|
||||
}
|
||||
|
||||
/* Slots for %f0 .. %f6. */
|
||||
for (slot_num = 14, slot_addr = prev_sp + 16 * data.gpr_size;
|
||||
slot_num < S390_NUM_SPILL_SLOTS;
|
||||
slot_num++, slot_addr += data.fpr_size)
|
||||
{
|
||||
struct prologue_value *slot = &data.spill[slot_num];
|
||||
|
||||
if (slot->kind == pv_register
|
||||
&& slot->k == 0)
|
||||
info->saved_regs[slot->reg].addr = slot_addr;
|
||||
case ABI_LINUX_ZSERIES:
|
||||
for (i = 8; i <= 15; i++)
|
||||
if (data.fpr_slot[i] != 0)
|
||||
info->saved_regs[S390_F0_REGNUM + i].addr = cfa - data.fpr_slot[i];
|
||||
break;
|
||||
}
|
||||
|
||||
/* Function return will set PC to %r14. */
|
||||
|
@ -2708,11 +2636,6 @@ s390_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
|
|||
and the back chain pointer. */
|
||||
sp -= 16*word_size + 32;
|
||||
|
||||
/* Write the back chain pointer into the first word of the stack
|
||||
frame. This is needed to unwind across a dummy frame. */
|
||||
regcache_cooked_read_unsigned (regcache, S390_SP_REGNUM, &orig_sp);
|
||||
write_memory_unsigned_integer (sp, word_size, orig_sp);
|
||||
|
||||
/* Store return address. */
|
||||
regcache_cooked_write_unsigned (regcache, S390_RETADDR_REGNUM, bp_addr);
|
||||
|
||||
|
@ -2720,9 +2643,8 @@ s390_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
|
|||
regcache_cooked_write_unsigned (regcache, S390_SP_REGNUM, sp);
|
||||
|
||||
/* We need to return the 'stack part' of the frame ID,
|
||||
which is actually the top of the register save area
|
||||
allocated on the original stack. */
|
||||
return orig_sp + 16*word_size + 32;
|
||||
which is actually the top of the register save area. */
|
||||
return sp + 16*word_size + 32;
|
||||
}
|
||||
|
||||
/* Assuming NEXT_FRAME->prev is a dummy, return the frame ID of that
|
||||
|
@ -2733,10 +2655,9 @@ static struct frame_id
|
|||
s390_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
|
||||
{
|
||||
int word_size = gdbarch_ptr_bit (gdbarch) / 8;
|
||||
CORE_ADDR this_sp = s390_unwind_sp (gdbarch, next_frame);
|
||||
CORE_ADDR prev_sp = read_memory_unsigned_integer (this_sp, word_size);
|
||||
CORE_ADDR sp = s390_unwind_sp (gdbarch, next_frame);
|
||||
|
||||
return frame_id_build (prev_sp + 16*word_size + 32,
|
||||
return frame_id_build (sp + 16*word_size + 32,
|
||||
frame_pc_unwind (next_frame));
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue