aboutsummaryrefslogtreecommitdiff
path: root/gdb/mips-tdep.c
diff options
context:
space:
mode:
authorJim Kingdon <jkingdon@engr.sgi.com>1993-11-12 16:35:59 +0000
committerJim Kingdon <jkingdon@engr.sgi.com>1993-11-12 16:35:59 +0000
commit002a422b22cb90692c90afccf2f217fd2c9532c2 (patch)
tree125f319600eb0c2dace8daa206af617486041727 /gdb/mips-tdep.c
parent6fd1e9eeb19eabb35491b9647c8c71ee790472e0 (diff)
downloadgdb-002a422b22cb90692c90afccf2f217fd2c9532c2.zip
gdb-002a422b22cb90692c90afccf2f217fd2c9532c2.tar.gz
gdb-002a422b22cb90692c90afccf2f217fd2c9532c2.tar.bz2
* mips-tdep.c (init_extra_frame_info): Check to see whether the
registers mentioned in the proc_desc have been saved. This generalizes mips_in_lenient_prologue in the sense that we keep searching until we've found saves for all the registers, not just look for a "lenient prologue" pattern. * mips-tdep.c: #if 0 lenient prologue code. * mips-tdep.c (heuristic_proc_desc): Don't assume a host short is 16 bits.
Diffstat (limited to 'gdb/mips-tdep.c')
-rw-r--r--gdb/mips-tdep.c120
1 files changed, 86 insertions, 34 deletions
diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c
index f7b4f28..c5f870f 100644
--- a/gdb/mips-tdep.c
+++ b/gdb/mips-tdep.c
@@ -34,7 +34,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#define VM_MIN_ADDRESS (unsigned)0x400000
+#if 0
static int mips_in_lenient_prologue PARAMS ((CORE_ADDR, CORE_ADDR));
+#endif
/* Some MIPS boards don't support floating point, so we permit the
user to turn it off. */
@@ -210,16 +212,16 @@ heuristic_proc_desc(start_pc, limit_pc, next_frame)
else if ((word & 0xFFE00000) == 0xafa00000) { /* sw reg,offset($sp) */
int reg = (word & 0x001F0000) >> 16;
reg_mask |= 1 << reg;
- temp_saved_regs.regs[reg] = sp + (short)word;
+ temp_saved_regs.regs[reg] = sp + (word & 0xffff);
}
else if ((word & 0xFFFF0000) == 0x27be0000) { /* addiu $30,$sp,size */
- if ((unsigned short)word != frame_size)
- reg30 = sp + (unsigned short)word;
+ if ((word & 0xffff) != frame_size)
+ reg30 = sp + (word & 0xffff);
else if (!has_frame_reg) {
int alloca_adjust;
has_frame_reg = 1;
reg30 = read_next_frame_reg(next_frame, 30);
- alloca_adjust = reg30 - (sp + (unsigned short)word);
+ alloca_adjust = reg30 - (sp + (word & 0xffff));
if (alloca_adjust > 0) {
/* FP > SP + frame_size. This may be because
/* of an alloca or somethings similar.
@@ -233,7 +235,7 @@ heuristic_proc_desc(start_pc, limit_pc, next_frame)
else if ((word & 0xFFE00000) == 0xafc00000) { /* sw reg,offset($30) */
int reg = (word & 0x001F0000) >> 16;
reg_mask |= 1 << reg;
- temp_saved_regs.regs[reg] = reg30 + (short)word;
+ temp_saved_regs.regs[reg] = reg30 + (word & 0xffff);
}
}
if (has_frame_reg) {
@@ -386,38 +388,26 @@ init_extra_frame_info(fci)
fci->frame = READ_FRAME_REG(fci, PROC_FRAME_REG(proc_desc))
+ PROC_FRAME_OFFSET(proc_desc);
- /* If this is the innermost frame, and we are still in the
- prologue (loosely defined), then the registers may not have
- been saved yet. */
- if (fci->next == NULL
- && !PROC_DESC_IS_DUMMY(proc_desc)
- && mips_in_lenient_prologue (PROC_LOW_ADDR (proc_desc), fci->pc))
- {
- /* Can't just say that the registers are not saved, because they
- might get clobbered halfway through the prologue.
- heuristic_proc_desc already has the right code to figure out
- exactly what has been saved, so use it. As far as I know we
- could be doing this (as we do on the 68k, for example)
- regardless of whether we are in the prologue; I'm leaving in
- the check for being in the prologue only out of conservatism
- (I'm not sure whether heuristic_proc_desc handles all cases,
- for example).
-
- This stuff is ugly (and getting uglier by the minute). Probably
- the best way to clean it up is to ignore the proc_desc's from
- the symbols altogher, and get all the information we need by
- examining the prologue (provided we can make the prologue
- examining code good enough to get all the cases...). */
- proc_desc =
- heuristic_proc_desc (PROC_LOW_ADDR (proc_desc),
- fci->pc,
- fci->next);
- }
-
if (proc_desc == &temp_proc_desc)
*fci->saved_regs = temp_saved_regs;
- else
+ else if (/* In any frame other than the innermost, we assume that all
+ registers have been saved. This assumes that all register
+ saves in a function happen before the first function
+ call. */
+ fci->next != NULL
+
+ /* In a dummy frame we know exactly where things are saved. */
+ || PROC_DESC_IS_DUMMY (proc_desc)
+
+ /* Not sure exactly what kernel_trap means, but if it means
+ the kernel saves the registers without a prologue doing it,
+ we better not examine the prologue to see whether registers
+ have been saved yet. */
+ || kernel_trap)
{
+ /* All the registers which will be saved have been saved, so we
+ can believe the proc_desc. */
+
/* find which general-purpose registers were saved */
reg_position = fci->frame + PROC_REG_OFFSET(proc_desc);
mask = kernel_trap ? 0xFFFFFFFF : PROC_REG_MASK(proc_desc);
@@ -441,6 +431,58 @@ init_extra_frame_info(fci)
reg_position -= 4;
}
}
+ else
+ {
+ /* We need to figure out whether the registers that the proc_desc
+ claims are saved have been saved yet. */
+
+ CORE_ADDR addr;
+ int status;
+ char buf[4];
+ unsigned long inst;
+ /* Bitmasks; set if the proc_desc claims the register is saved and we
+ haven't found a save instruction for it yet. */
+ unsigned long gen_mask, float_mask;
+
+ gen_mask = PROC_REG_MASK (proc_desc);
+ float_mask = PROC_FREG_MASK (proc_desc);
+
+ for (addr = PROC_LOW_ADDR (proc_desc);
+ addr < fci->pc && (gen_mask | float_mask);
+ addr += 4)
+ {
+ status = read_memory_nobpt (addr, buf, 4);
+ if (status)
+ memory_error (status, addr);
+ inst = extract_unsigned_integer (buf, 4);
+ if (/* sw reg,n($sp) */
+ (inst & 0xffe00000) == 0xafa00000
+
+ /* sw reg,n($r30) */
+ || (inst & 0xffe00000) == 0xafc00000)
+ {
+ /* We assume that all saves are relative to the
+ PROC_FRAME_REG, which is what we used to set up
+ ->frame. */
+ int reg = (inst & 0x001f0000) >> 16;
+ if (gen_mask & (1 << reg))
+ fci->saved_regs.regs[reg] = fci->frame + (inst & 0xffff);
+ gen_mask &= ~(1 << reg);
+ }
+ else if (/* swc1 freg,n($sp) */
+ (inst & 0xffe00000) == 0xe7a00000
+
+ /* swc1 freg,n($r30) */
+ (inst & 0xffe00000) == 0xe7c00000)
+ {
+ int reg = ((inst & 0x001f0000) >> 16);
+ if (float_mask & (1 << reg))
+ fci->saved_regs.regs[FP0_REGNUM + reg]
+ = fci->frame + (inst & 0xffff);
+ float_mask &= ~(1 << reg);
+ }
+ }
+ }
/* hack: if argument regs are saved, guess these contain args */
if ((PROC_REG_MASK(proc_desc) & 0xF0) == 0) fci->num_args = -1;
@@ -773,6 +815,7 @@ mips_frame_num_args(fip)
return -1;
}
+#if 0
/* Is this a branch with a delay slot? */
static int
is_delayed (insn)
@@ -788,6 +831,7 @@ is_delayed (insn)
| INSN_COND_BRANCH_DELAY
| INSN_COND_BRANCH_LIKELY)));
}
+#endif
/* To skip prologues, I use this predicate. Returns either PC itself
if the code at PC does not look like a function prologue; otherwise
@@ -822,8 +866,10 @@ mips_skip_prologue (pc, lenient)
memory_error (status, pc + offset);
inst = extract_unsigned_integer (buf, 4);
+#if 0
if (lenient && is_delayed (inst))
continue;
+#endif
if ((inst & 0xffff0000) == 0x27bd0000) /* addiu $sp,$sp,offset */
seen_sp_adjust = 1;
@@ -874,6 +920,11 @@ mips_skip_prologue (pc, lenient)
#endif
}
+#if 0
+/* The lenient prologue stuff should be superceded by the code in
+ init_extra_frame_info which looks to see whether the stores mentioned
+ in the proc_desc have actually taken place. */
+
/* Is address PC in the prologue (loosely defined) for function at
STARTADDR? */
@@ -885,6 +936,7 @@ mips_in_lenient_prologue (startaddr, pc)
CORE_ADDR end_prologue = mips_skip_prologue (startaddr, 1);
return pc >= startaddr && pc < end_prologue;
}
+#endif
/* Given a return value in `regbuf' with a type `valtype',
extract and copy its value into `valbuf'. */