diff options
author | Ulrich Weigand <uweigand@de.ibm.com> | 2004-10-23 16:31:23 +0000 |
---|---|---|
committer | Ulrich Weigand <uweigand@de.ibm.com> | 2004-10-23 16:31:23 +0000 |
commit | 121d8485df3bd59f8a74752e6ef3b7123b482b9e (patch) | |
tree | e9d76f256ba4b2dbd0954e3ce959a7e1da8bb432 /gdb/s390-tdep.c | |
parent | 0a6ddd08223c066a91c9e70e863cb2a59ebc1dff (diff) | |
download | gdb-121d8485df3bd59f8a74752e6ef3b7123b482b9e.zip gdb-121d8485df3bd59f8a74752e6ef3b7123b482b9e.tar.gz gdb-121d8485df3bd59f8a74752e6ef3b7123b482b9e.tar.bz2 |
* 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.
Diffstat (limited to 'gdb/s390-tdep.c')
-rw-r--r-- | gdb/s390-tdep.c | 317 |
1 files changed, 119 insertions, 198 deletions
diff --git a/gdb/s390-tdep.c b/gdb/s390-tdep.c index 055ba6c..8245fa4 100644 --- a/gdb/s390-tdep.c +++ b/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,83 +1071,17 @@ 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 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; -}; + /* 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]; -/* 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; -} - + /* 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; +}; /* Do a SIZE-byte store of VALUE to ADDR. */ static void @@ -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; + + for (i = 0; i < S390_NUM_FPRS; i++) + data->fpr_slot[i] = 0; - pv_set_to_unknown (&data->back_chain); + 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. */ - - /* 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) - { - struct prologue_value *slot = &data.spill[slot_num]; + /* 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. */ - if (slot->kind == pv_register - && slot->k == 0) - info->saved_regs[slot->reg].addr = slot_addr; - } + 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]; - /* 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) + 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; + 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)); } |