* 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:
Ulrich Weigand 2004-10-23 16:31:23 +00:00
parent 0a6ddd0822
commit 121d8485df
2 changed files with 140 additions and 199 deletions

View File

@ -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

View File

@ -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))
{
data->back_chain_saved_p = 1;
return;
}
/* 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)
{
*stack = *value;
return;
/* 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 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. */
/* 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,12 +1175,26 @@ 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;
return;
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. */
@ -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));
}