* mips-tdep.c (MIPS16_INSTLEN): Define.
(mips_find_saved_regs): Replace hardcoded 2's with MIPS16_INSTLEN. (heuristic_proc_start): Recognize 'entry' pseudo-op as a start of function on MIPS16. (mips32_skip_prologue, mips16_skip_prologue): New helper functions for mips_skip_prologue. (mips_skip_prologue): Recognize both 16- and 32-bit prologues.
This commit is contained in:
parent
736a306cb2
commit
20fa0902e7
|
@ -1,3 +1,13 @@
|
||||||
|
Fri Jan 31 08:26:39 1997 Mark Alexander <marka@cygnus.com>
|
||||||
|
|
||||||
|
* mips-tdep.c (MIPS16_INSTLEN): Define.
|
||||||
|
(mips_find_saved_regs): Replace hardcoded 2's with MIPS16_INSTLEN.
|
||||||
|
(heuristic_proc_start): Recognize 'entry' pseudo-op as a start
|
||||||
|
of function on MIPS16.
|
||||||
|
(mips32_skip_prologue, mips16_skip_prologue): New helper functions
|
||||||
|
for mips_skip_prologue.
|
||||||
|
(mips_skip_prologue): Recognize both 16- and 32-bit prologues.
|
||||||
|
|
||||||
Wed Jan 29 12:45:54 1997 Michael Meissner <meissner@tiktok.cygnus.com>
|
Wed Jan 29 12:45:54 1997 Michael Meissner <meissner@tiktok.cygnus.com>
|
||||||
|
|
||||||
* config/powerpc/ppc{,le}-sim.mt (SIM): Remove the library
|
* config/powerpc/ppc{,le}-sim.mt (SIM): Remove the library
|
||||||
|
|
193
gdb/mips-tdep.c
193
gdb/mips-tdep.c
|
@ -43,6 +43,7 @@ extern struct obstack frame_cache_obstack;
|
||||||
|
|
||||||
/* FIXME! this code assumes 4-byte instructions. */
|
/* FIXME! this code assumes 4-byte instructions. */
|
||||||
#define MIPS_INSTLEN 4 /* Length of an instruction */
|
#define MIPS_INSTLEN 4 /* Length of an instruction */
|
||||||
|
#define MIPS16_INSTLEN 2 /* Length of an instruction on MIPS16*/
|
||||||
#define MIPS_NUMREGS 32 /* Number of integer or float registers */
|
#define MIPS_NUMREGS 32 /* Number of integer or float registers */
|
||||||
typedef unsigned long t_inst; /* Integer big enough to hold an instruction */
|
typedef unsigned long t_inst; /* Integer big enough to hold an instruction */
|
||||||
|
|
||||||
|
@ -406,19 +407,21 @@ mips_find_saved_regs (fci)
|
||||||
|
|
||||||
if ((addr = PROC_LOW_ADDR (proc_desc)) & 1)
|
if ((addr = PROC_LOW_ADDR (proc_desc)) & 1)
|
||||||
{
|
{
|
||||||
instlen = 2; /* MIPS16 */
|
instlen = MIPS16_INSTLEN; /* MIPS16 */
|
||||||
addr &= ~1;
|
addr &= ~1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
instlen = MIPS_INSTLEN; /* MIPS32 */
|
instlen = MIPS_INSTLEN; /* MIPS32 */
|
||||||
|
|
||||||
|
/* Scan through this function's instructions preceding the current
|
||||||
|
PC, and look for those that save registers. */
|
||||||
while (addr < fci->pc)
|
while (addr < fci->pc)
|
||||||
{
|
{
|
||||||
status = read_memory_nobpt (addr, buf, instlen);
|
status = read_memory_nobpt (addr, buf, instlen);
|
||||||
if (status)
|
if (status)
|
||||||
memory_error (status, addr);
|
memory_error (status, addr);
|
||||||
inst = extract_unsigned_integer (buf, instlen);
|
inst = extract_unsigned_integer (buf, instlen);
|
||||||
if (instlen == 2)
|
if (instlen == MIPS16_INSTLEN)
|
||||||
mips16_decode_reg_save (inst, &gen_save_found);
|
mips16_decode_reg_save (inst, &gen_save_found);
|
||||||
else
|
else
|
||||||
mips32_decode_reg_save (inst, &gen_save_found, &float_save_found);
|
mips32_decode_reg_save (inst, &gen_save_found, &float_save_found);
|
||||||
|
@ -446,10 +449,8 @@ mips_find_saved_regs (fci)
|
||||||
if (! GDB_TARGET_IS_MIPS64)
|
if (! GDB_TARGET_IS_MIPS64)
|
||||||
reg_position += 4;
|
reg_position += 4;
|
||||||
|
|
||||||
/* FIXME! this code looks scary...
|
/* Fill in the offsets for the float registers which float_mask says
|
||||||
* Looks like it's trying to do stuff with a register,
|
were saved. */
|
||||||
* but .... ???
|
|
||||||
*/
|
|
||||||
for (ireg = MIPS_NUMREGS-1; float_mask; --ireg, float_mask <<= 1)
|
for (ireg = MIPS_NUMREGS-1; float_mask; --ireg, float_mask <<= 1)
|
||||||
if (float_mask & 0x80000000)
|
if (float_mask & 0x80000000)
|
||||||
{
|
{
|
||||||
|
@ -551,6 +552,7 @@ heuristic_proc_start(pc)
|
||||||
{
|
{
|
||||||
CORE_ADDR start_pc = pc;
|
CORE_ADDR start_pc = pc;
|
||||||
CORE_ADDR fence = start_pc - heuristic_fence_post;
|
CORE_ADDR fence = start_pc - heuristic_fence_post;
|
||||||
|
int instlen;
|
||||||
|
|
||||||
if (start_pc == 0) return 0;
|
if (start_pc == 0) return 0;
|
||||||
|
|
||||||
|
@ -558,8 +560,10 @@ heuristic_proc_start(pc)
|
||||||
|| fence < VM_MIN_ADDRESS)
|
|| fence < VM_MIN_ADDRESS)
|
||||||
fence = VM_MIN_ADDRESS;
|
fence = VM_MIN_ADDRESS;
|
||||||
|
|
||||||
|
instlen = pc & 1 ? MIPS16_INSTLEN : MIPS_INSTLEN;
|
||||||
|
|
||||||
/* search back for previous return */
|
/* search back for previous return */
|
||||||
for (start_pc -= MIPS_INSTLEN; ; start_pc -= MIPS_INSTLEN) /* FIXME!! */
|
for (start_pc -= instlen; ; start_pc -= instlen)
|
||||||
if (start_pc < fence)
|
if (start_pc < fence)
|
||||||
{
|
{
|
||||||
/* It's not clear to me why we reach this point when
|
/* It's not clear to me why we reach this point when
|
||||||
|
@ -591,10 +595,21 @@ Otherwise, you told GDB there was a function where there isn't one, or\n\
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
else if (start_pc & 1)
|
||||||
|
{
|
||||||
|
/* On MIPS16, look for the 'entry' pseudo-op at the start
|
||||||
|
of a function. This is only going to work if the program
|
||||||
|
was compiled with -mentry. Otherwise, there's no reliable
|
||||||
|
way of finding the start of a function. */
|
||||||
|
if ((read_memory_integer (start_pc & ~1, 2) & 0xf81f)== 0xe809)
|
||||||
|
return start_pc;
|
||||||
|
}
|
||||||
else if (ABOUT_TO_RETURN(start_pc))
|
else if (ABOUT_TO_RETURN(start_pc))
|
||||||
|
{
|
||||||
|
start_pc += 2 * MIPS_INSTLEN; /* skip return, and its delay slot */
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
start_pc += 2 * MIPS_INSTLEN; /* skip return, and its delay slot */
|
|
||||||
#if 0
|
#if 0
|
||||||
/* skip nops (usually 1) 0 - is this */
|
/* skip nops (usually 1) 0 - is this */
|
||||||
while (start_pc < pc && read_memory_integer (start_pc, MIPS_INSTLEN) == 0)
|
while (start_pc < pc && read_memory_integer (start_pc, MIPS_INSTLEN) == 0)
|
||||||
|
@ -1362,49 +1377,31 @@ mips_step_skips_delay (pc)
|
||||||
return is_delayed ((unsigned long)extract_unsigned_integer (buf, MIPS_INSTLEN));
|
return is_delayed ((unsigned long)extract_unsigned_integer (buf, MIPS_INSTLEN));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* To skip prologues, I use this predicate. Returns either PC itself
|
|
||||||
if the code at PC does not look like a function prologue; otherwise
|
|
||||||
returns an address that (if we're lucky) follows the prologue. If
|
|
||||||
LENIENT, then we must skip everything which is involved in setting
|
|
||||||
up the frame (it's OK to skip more, just so long as we don't skip
|
|
||||||
anything which might clobber the registers which are being saved.
|
|
||||||
We must skip more in the case where part of the prologue is in the
|
|
||||||
delay slot of a non-prologue instruction). */
|
|
||||||
|
|
||||||
CORE_ADDR
|
/* Skip the PC past function prologue instructions (32-bit version).
|
||||||
mips_skip_prologue (pc, lenient)
|
This is a helper function for mips_skip_prologue. */
|
||||||
CORE_ADDR pc;
|
|
||||||
|
static CORE_ADDR
|
||||||
|
mips32_skip_prologue (pc, lenient)
|
||||||
|
CORE_ADDR pc; /* starting PC to search from */
|
||||||
int lenient;
|
int lenient;
|
||||||
{
|
{
|
||||||
t_inst inst;
|
t_inst inst;
|
||||||
unsigned offset;
|
CORE_ADDR end_pc;
|
||||||
int seen_sp_adjust = 0;
|
int seen_sp_adjust = 0;
|
||||||
int load_immediate_bytes = 0;
|
int load_immediate_bytes = 0;
|
||||||
CORE_ADDR post_prologue_pc;
|
|
||||||
|
|
||||||
/* See if we can determine the end of the prologue via the symbol table.
|
|
||||||
If so, then return either PC, or the PC after the prologue, whichever
|
|
||||||
is greater. */
|
|
||||||
|
|
||||||
post_prologue_pc = after_prologue (pc, NULL);
|
|
||||||
|
|
||||||
if (post_prologue_pc != 0)
|
|
||||||
return max (pc, post_prologue_pc);
|
|
||||||
|
|
||||||
/* Can't determine prologue from the symbol table, need to examine
|
|
||||||
instructions. */
|
|
||||||
|
|
||||||
/* Skip the typical prologue instructions. These are the stack adjustment
|
/* Skip the typical prologue instructions. These are the stack adjustment
|
||||||
instruction and the instructions that save registers on the stack
|
instruction and the instructions that save registers on the stack
|
||||||
or in the gcc frame. */
|
or in the gcc frame. */
|
||||||
for (offset = 0; offset < 100; offset += MIPS_INSTLEN)
|
for (end_pc = pc + 100; pc < end_pc; pc += MIPS_INSTLEN)
|
||||||
{
|
{
|
||||||
char buf[MIPS_INSTLEN];
|
char buf[MIPS_INSTLEN];
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
status = read_memory_nobpt (pc + offset, buf, MIPS_INSTLEN);
|
status = read_memory_nobpt (pc, buf, MIPS_INSTLEN);
|
||||||
if (status)
|
if (status)
|
||||||
memory_error (status, pc + offset);
|
memory_error (status, pc);
|
||||||
inst = (unsigned long)extract_unsigned_integer (buf, MIPS_INSTLEN);
|
inst = (unsigned long)extract_unsigned_integer (buf, MIPS_INSTLEN);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -1430,8 +1427,9 @@ mips_skip_prologue (pc, lenient)
|
||||||
continue; /* reg != $zero */
|
continue; /* reg != $zero */
|
||||||
|
|
||||||
/* move $s8,$sp. With different versions of gas this will be either
|
/* move $s8,$sp. With different versions of gas this will be either
|
||||||
`addu $s8,$sp,$zero' or `or $s8,$sp,$zero'. Accept either. */
|
`addu $s8,$sp,$zero' or `or $s8,$sp,$zero' or `daddu s8,sp,$0'.
|
||||||
else if (inst == 0x03A0F021 || inst == 0x03a0f025)
|
Accept any one of these. */
|
||||||
|
else if (inst == 0x03A0F021 || inst == 0x03a0f025 || inst == 0x03a0f02d)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
else if ((inst & 0xFF9F07FF) == 0x00800021) /* move reg,$a0-$a3 */
|
else if ((inst & 0xFF9F07FF) == 0x00800021) /* move reg,$a0-$a3 */
|
||||||
|
@ -1475,12 +1473,123 @@ mips_skip_prologue (pc, lenient)
|
||||||
skipped some load immediate instructions. Undo the skipping
|
skipped some load immediate instructions. Undo the skipping
|
||||||
if the load immediate was not followed by a stack adjustment. */
|
if the load immediate was not followed by a stack adjustment. */
|
||||||
if (load_immediate_bytes && !seen_sp_adjust)
|
if (load_immediate_bytes && !seen_sp_adjust)
|
||||||
offset -= load_immediate_bytes;
|
pc -= load_immediate_bytes;
|
||||||
return pc + offset;
|
return pc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Skip the PC past function prologue instructions (16-bit version).
|
||||||
|
This is a helper function for mips_skip_prologue. */
|
||||||
|
|
||||||
|
static CORE_ADDR
|
||||||
|
mips16_skip_prologue (pc, lenient)
|
||||||
|
CORE_ADDR pc; /* starting PC to search from */
|
||||||
|
int lenient;
|
||||||
|
{
|
||||||
|
CORE_ADDR end_pc;
|
||||||
|
|
||||||
|
/* Table of instructions likely to be found in a function prologue. */
|
||||||
|
static struct
|
||||||
|
{
|
||||||
|
unsigned short inst;
|
||||||
|
unsigned short mask;
|
||||||
|
} table[] =
|
||||||
|
{
|
||||||
|
{ 0x6300, 0xff00 }, /* addiu $sp,offset */
|
||||||
|
{ 0xfb00, 0xff00 }, /* daddiu $sp,offset */
|
||||||
|
{ 0xd000, 0xf800 }, /* sw reg,n($sp) */
|
||||||
|
{ 0xf900, 0xff00 }, /* sd reg,n($sp) */
|
||||||
|
{ 0x6200, 0xff00 }, /* sw $ra,n($sp) */
|
||||||
|
{ 0xfa00, 0xff00 }, /* sd $ra,n($sp) */
|
||||||
|
{ 0x673d, 0xffff }, /* move $s1,sp */
|
||||||
|
{ 0xd980, 0xff80 }, /* sw $a0-$a3,n($s1) */
|
||||||
|
{ 0x6704, 0xff1c }, /* move reg,$a0-$a3 */
|
||||||
|
{ 0xe809, 0xf81f }, /* entry pseudo-op */
|
||||||
|
{ 0, 0 } /* end of table marker */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Skip the typical prologue instructions. These are the stack adjustment
|
||||||
|
instruction and the instructions that save registers on the stack
|
||||||
|
or in the gcc frame. */
|
||||||
|
for (end_pc = pc + 100; pc < end_pc; pc += MIPS16_INSTLEN)
|
||||||
|
{
|
||||||
|
char buf[MIPS16_INSTLEN];
|
||||||
|
int status;
|
||||||
|
unsigned short inst;
|
||||||
|
int extend_bytes;
|
||||||
|
int prev_extend_bytes;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
status = read_memory_nobpt (pc & ~1, buf, MIPS16_INSTLEN);
|
||||||
|
if (status)
|
||||||
|
memory_error (status, pc);
|
||||||
|
inst = (unsigned long)extract_unsigned_integer (buf, MIPS16_INSTLEN);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
if (lenient && is_delayed (inst))
|
||||||
|
continue;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Normally we ignore an extend instruction. However, if it is
|
||||||
|
not followed by a valid prologue instruction, we must adjust
|
||||||
|
the pc back over the extend so that it won't be considered
|
||||||
|
part of the prologue. */
|
||||||
|
if ((inst & 0xf800) == 0xf000) /* extend */
|
||||||
|
{
|
||||||
|
extend_bytes = MIPS16_INSTLEN;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
prev_extend_bytes = extend_bytes;
|
||||||
|
extend_bytes = 0;
|
||||||
|
|
||||||
|
/* Check for other valid prologue instructions besides extend. */
|
||||||
|
for (i = 0; table[i].mask != 0; i++)
|
||||||
|
if ((inst & table[i].mask) == table[i].inst) /* found, get out */
|
||||||
|
break;
|
||||||
|
if (table[i].mask != 0) /* it was in table? */
|
||||||
|
continue; /* ignore it
|
||||||
|
else /* non-prologue */
|
||||||
|
{
|
||||||
|
/* Return the current pc, adjusted backwards by 2 if
|
||||||
|
the previous instruction was an extend. */
|
||||||
|
return pc - prev_extend_bytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* To skip prologues, I use this predicate. Returns either PC itself
|
||||||
|
if the code at PC does not look like a function prologue; otherwise
|
||||||
|
returns an address that (if we're lucky) follows the prologue. If
|
||||||
|
LENIENT, then we must skip everything which is involved in setting
|
||||||
|
up the frame (it's OK to skip more, just so long as we don't skip
|
||||||
|
anything which might clobber the registers which are being saved.
|
||||||
|
We must skip more in the case where part of the prologue is in the
|
||||||
|
delay slot of a non-prologue instruction). */
|
||||||
|
|
||||||
|
CORE_ADDR
|
||||||
|
mips_skip_prologue (pc, lenient)
|
||||||
|
CORE_ADDR pc;
|
||||||
|
int lenient;
|
||||||
|
{
|
||||||
|
/* See if we can determine the end of the prologue via the symbol table.
|
||||||
|
If so, then return either PC, or the PC after the prologue, whichever
|
||||||
|
is greater. */
|
||||||
|
|
||||||
|
CORE_ADDR post_prologue_pc = after_prologue (pc, NULL);
|
||||||
|
|
||||||
|
if (post_prologue_pc != 0)
|
||||||
|
return max (pc, post_prologue_pc);
|
||||||
|
|
||||||
|
/* Can't determine prologue from the symbol table, need to examine
|
||||||
|
instructions. */
|
||||||
|
|
||||||
|
if (pc & 1)
|
||||||
|
return mips16_skip_prologue (pc, lenient);
|
||||||
|
else
|
||||||
|
return mips32_skip_prologue (pc, lenient);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
/* The lenient prologue stuff should be superceded by the code in
|
/* The lenient prologue stuff should be superseded by the code in
|
||||||
init_extra_frame_info which looks to see whether the stores mentioned
|
init_extra_frame_info which looks to see whether the stores mentioned
|
||||||
in the proc_desc have actually taken place. */
|
in the proc_desc have actually taken place. */
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue