if ((*this_cache) != NULL)
return (*this_cache);
+
cache = FRAME_OBSTACK_ZALLOC (struct mips_frame_cache);
(*this_cache) = cache;
cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
if (start_addr == 0)
start_addr = heuristic_proc_start (pc);
-#ifdef NOT_YET
proc_desc = heuristic_proc_desc (start_addr, pc, next_frame, *this_cache);
-#else
- proc_desc = heuristic_proc_desc (start_addr, pc, next_frame, NULL);
-#endif
}
if (proc_desc == NULL)
heuristic_proc_desc and set the saved_regs right away. */
return cache;
- /* Extract the frame's base. */
- cache->base = (frame_unwind_register_signed (next_frame, NUM_REGS + PROC_FRAME_REG (proc_desc))
- + PROC_FRAME_OFFSET (proc_desc) - PROC_FRAME_ADJUST (proc_desc));
-
- kernel_trap = PROC_REG_MASK (proc_desc) & 1;
- gen_mask = kernel_trap ? 0xFFFFFFFF : PROC_REG_MASK (proc_desc);
- float_mask = kernel_trap ? 0xFFFFFFFF : PROC_FREG_MASK (proc_desc);
-
- /* In any frame other than the innermost or a frame interrupted by a
- signal, we assume that all registers have been saved. This
- assumes that all register saves in a function happen before the
- first function call. */
- if (in_prologue (frame_pc_unwind (next_frame), PROC_LOW_ADDR (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)
- {
- /* We need to figure out whether the registers that the
- proc_desc claims are saved have been saved yet. */
-
- CORE_ADDR addr;
-
- /* Bitmasks; set if we have found a save for the register. */
- unsigned long gen_save_found = 0;
- unsigned long float_save_found = 0;
-
- addr = PROC_LOW_ADDR (proc_desc);
-
- /* Scan through this function's instructions preceding the
- current PC, and look for those that save registers. */
- while (addr < frame_pc_unwind (next_frame))
- {
- mips32_decode_reg_save (mips32_fetch_instruction (addr),
- &gen_save_found, &float_save_found);
- addr += MIPS_INSTLEN;
- }
- gen_mask = gen_save_found;
- float_mask = float_save_found;
- }
-
- /* Fill in the offsets for the registers which gen_mask says were
- saved. */
- {
- CORE_ADDR reg_position = (cache->base
- + PROC_REG_OFFSET (proc_desc));
- int ireg;
- for (ireg = MIPS_NUMREGS - 1; gen_mask; --ireg, gen_mask <<= 1)
- if (gen_mask & 0x80000000)
- {
- cache->saved_regs[NUM_REGS + ireg].addr = reg_position;
- reg_position -= mips_abi_regsize (gdbarch);
- }
- }
-
- /* Fill in the offsets for the registers which float_mask says were
- saved. */
- {
- CORE_ADDR reg_position = (cache->base + PROC_FREG_OFFSET (proc_desc));
- int ireg;
-
- /* Fill in the offsets for the float registers which float_mask
- says were saved. */
- for (ireg = MIPS_NUMREGS - 1; float_mask; --ireg, float_mask <<= 1)
- if (float_mask & 0x80000000)
- {
- const int regno =
- NUM_REGS + mips_regnum (current_gdbarch)->fp0 + ireg;
-
- if (mips_abi_regsize (gdbarch) == 4
- && TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
- {
- /* On a big endian 32 bit ABI, floating point registers
- are paired to form doubles such that the most
- significant part is in $f[N+1] and the least
- significant in $f[N] vis: $f[N+1] ||| $f[N]. The
- registers are also spilled as a pair and stored as a
- double.
-
- When little-endian the least significant part is
- stored first leading to the memory order $f[N] and
- then $f[N+1].
-
- Unfortunately, when big-endian the most significant
- part of the double is stored first, and the least
- significant is stored second. This leads to the
- registers being ordered in memory as firt $f[N+1] and
- then $f[N].
-
- For the big-endian case make certain that the
- addresses point at the correct (swapped) locations
- $f[N] and $f[N+1] pair (keep in mind that
- reg_position is decremented each time through the
- loop). */
- if ((ireg & 1))
- cache->saved_regs[regno].addr =
- reg_position - mips_abi_regsize (gdbarch);
- else
- cache->saved_regs[regno].addr =
- reg_position + mips_abi_regsize (gdbarch);
- }
- else
- cache->saved_regs[regno].addr = reg_position;
- reg_position -= mips_abi_regsize (gdbarch);
- }
-
- cache->saved_regs[NUM_REGS + mips_regnum (current_gdbarch)->pc]
- = cache->saved_regs[NUM_REGS + RA_REGNUM];
- }
-
/* SP_REGNUM, contains the value and not the address. */
trad_frame_set_value (cache->saved_regs, NUM_REGS + MIPS_SP_REGNUM, cache->base);
regcache_cooked_read_signed (current_regcache, regno, &val);
return val;
}
- else if ((regno % NUM_REGS) == MIPS_SP_REGNUM)
- /* MIPS_SP_REGNUM is special, its value is stored in saved_regs.
- In fact, it is so special that it can even only be fetched
- using a raw register number! Once this code as been converted
- to frame-unwind the problem goes away. */
- return frame_unwind_register_signed (fi, regno % NUM_REGS);
else
return frame_unwind_register_signed (fi, regno);
CORE_ADDR offset)
{
if (this_cache != NULL
- && this_cache->saved_regs[regnum].addr == 0)
+ && this_cache->saved_regs[regnum].addr == -1)
{
this_cache->saved_regs[regnum + 0 * NUM_REGS].addr = offset;
this_cache->saved_regs[regnum + 1 * NUM_REGS].addr = offset;
}
}
+/* Mark all the registers as unset in the saved_regs array
+ of THIS_CACHE. Do nothing if THIS_CACHE is null. */
+
+void
+reset_saved_regs (struct mips_frame_cache *this_cache)
+{
+ if (this_cache == NULL || this_cache->saved_regs == NULL)
+ return;
+
+ {
+ const int num_regs = NUM_REGS;
+ int i;
+
+ for (i = 0; i < num_regs; i++)
+ {
+ this_cache->saved_regs[i].addr = -1;
+ }
+ }
+}
+
static void
mips32_heuristic_proc_desc (CORE_ADDR start_pc, CORE_ADDR limit_pc,
CORE_ADDR sp, struct frame_info *next_frame,
{
CORE_ADDR cur_pc;
CORE_ADDR frame_addr = 0; /* Value of $r30. Used by gcc for frame-pointer */
+ long frame_offset;
+ int frame_reg = MIPS_SP_REGNUM;
+
restart:
- PROC_FRAME_OFFSET (&temp_proc_desc) = 0;
- PROC_FRAME_ADJUST (&temp_proc_desc) = 0; /* offset of FP from SP */
+
+ frame_offset = 0;
for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += MIPS_INSTLEN)
{
unsigned long inst, high_word, low_word;
|| high_word == 0x67bd) /* daddiu $sp,$sp,-i */
{
if (low_word & 0x8000) /* negative stack adjustment? */
- PROC_FRAME_OFFSET (&temp_proc_desc) += 0x10000 - low_word;
+ frame_offset += 0x10000 - low_word;
else
/* Exit loop if a positive stack adjustment is found, which
usually means that the stack cleanup code in the function
}
else if ((high_word & 0xFFE0) == 0xafa0) /* sw reg,offset($sp) */
{
- PROC_REG_MASK (&temp_proc_desc) |= 1 << reg;
set_reg_offset (this_cache, reg, sp + low_word);
}
else if ((high_word & 0xFFE0) == 0xffa0) /* sd reg,offset($sp) */
{
/* Irix 6.2 N32 ABI uses sd instructions for saving $gp and
$ra. */
- PROC_REG_MASK (&temp_proc_desc) |= 1 << reg;
set_reg_offset (this_cache, reg, sp + low_word);
}
else if (high_word == 0x27be) /* addiu $30,$sp,size */
{
/* Old gcc frame, r30 is virtual frame pointer. */
- if ((long) low_word != PROC_FRAME_OFFSET (&temp_proc_desc))
+ if ((long) low_word != frame_offset)
frame_addr = sp + low_word;
- else if (PROC_FRAME_REG (&temp_proc_desc) == MIPS_SP_REGNUM)
+ else if (frame_reg == MIPS_SP_REGNUM)
{
unsigned alloca_adjust;
- PROC_FRAME_REG (&temp_proc_desc) = 30;
+
+ frame_reg = 30;
frame_addr = read_next_frame_reg (next_frame, NUM_REGS + 30);
alloca_adjust = (unsigned) (frame_addr - (sp + low_word));
if (alloca_adjust > 0)
{
- /* FP > SP + frame_size. This may be because
- * of an alloca or somethings similar.
- * Fix sp to "pre-alloca" value, and try again.
- */
+ /* FP > SP + frame_size. This may be because of
+ an alloca or somethings similar. Fix sp to
+ "pre-alloca" value, and try again. */
sp += alloca_adjust;
+ /* Need to reset the status of all registers. Otherwise,
+ we will hit a guard that prevents the new address
+ for each register to be recomputed during the second
+ pass. */
+ reset_saved_regs (this_cache);
goto restart;
}
}
else if (inst == 0x03A0F021 || inst == 0x03a0f025 || inst == 0x03a0f02d)
{
/* New gcc frame, virtual frame pointer is at r30 + frame_size. */
- if (PROC_FRAME_REG (&temp_proc_desc) == MIPS_SP_REGNUM)
+ if (frame_reg == MIPS_SP_REGNUM)
{
unsigned alloca_adjust;
- PROC_FRAME_REG (&temp_proc_desc) = 30;
+
+ frame_reg = 30;
frame_addr = read_next_frame_reg (next_frame, NUM_REGS + 30);
alloca_adjust = (unsigned) (frame_addr - sp);
if (alloca_adjust > 0)
- {
- /* FP > SP + frame_size. This may be because
- * of an alloca or somethings similar.
- * Fix sp to "pre-alloca" value, and try again.
- */
- sp += alloca_adjust;
- goto restart;
- }
+ {
+ /* FP > SP + frame_size. This may be because of
+ an alloca or somethings similar. Fix sp to
+ "pre-alloca" value, and try again. */
+ sp = frame_addr;
+ /* Need to reset the status of all registers. Otherwise,
+ we will hit a guard that prevents the new address
+ for each register to be recomputed during the second
+ pass. */
+ reset_saved_regs (this_cache);
+ goto restart;
+ }
}
}
else if ((high_word & 0xFFE0) == 0xafc0) /* sw reg,offset($30) */
{
- PROC_REG_MASK (&temp_proc_desc) |= 1 << reg;
set_reg_offset (this_cache, reg, frame_addr + low_word);
}
}
+
+ if (this_cache != NULL)
+ {
+ this_cache->base =
+ (frame_unwind_register_signed (next_frame, NUM_REGS + frame_reg)
+ + frame_offset);
+ /* FIXME: brobecker/2004-09-15: We should be able to get rid of
+ this assignment below, eventually. But it's still needed
+ for now. */
+ this_cache->saved_regs[NUM_REGS + mips_regnum (current_gdbarch)->pc]
+ = this_cache->saved_regs[NUM_REGS + RA_REGNUM];
+ }
}
static mips_extra_func_info_t