mirror of
https://github.com/darlinghq/darling-gdb.git
synced 2025-02-15 06:58:16 +00:00
* 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>
|
||||
|
||||
* 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. */
|
||||
#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 */
|
||||
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)
|
||||
{
|
||||
instlen = 2; /* MIPS16 */
|
||||
instlen = MIPS16_INSTLEN; /* MIPS16 */
|
||||
addr &= ~1;
|
||||
}
|
||||
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)
|
||||
{
|
||||
status = read_memory_nobpt (addr, buf, instlen);
|
||||
if (status)
|
||||
memory_error (status, addr);
|
||||
inst = extract_unsigned_integer (buf, instlen);
|
||||
if (instlen == 2)
|
||||
if (instlen == MIPS16_INSTLEN)
|
||||
mips16_decode_reg_save (inst, &gen_save_found);
|
||||
else
|
||||
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)
|
||||
reg_position += 4;
|
||||
|
||||
/* FIXME! this code looks scary...
|
||||
* Looks like it's trying to do stuff with a register,
|
||||
* but .... ???
|
||||
*/
|
||||
/* 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)
|
||||
{
|
||||
@ -551,6 +552,7 @@ heuristic_proc_start(pc)
|
||||
{
|
||||
CORE_ADDR start_pc = pc;
|
||||
CORE_ADDR fence = start_pc - heuristic_fence_post;
|
||||
int instlen;
|
||||
|
||||
if (start_pc == 0) return 0;
|
||||
|
||||
@ -558,8 +560,10 @@ heuristic_proc_start(pc)
|
||||
|| fence < VM_MIN_ADDRESS)
|
||||
fence = VM_MIN_ADDRESS;
|
||||
|
||||
instlen = pc & 1 ? MIPS16_INSTLEN : MIPS_INSTLEN;
|
||||
|
||||
/* 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)
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
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))
|
||||
{
|
||||
start_pc += 2 * MIPS_INSTLEN; /* skip return, and its delay slot */
|
||||
break;
|
||||
}
|
||||
|
||||
start_pc += 2 * MIPS_INSTLEN; /* skip return, and its delay slot */
|
||||
#if 0
|
||||
/* skip nops (usually 1) 0 - is this */
|
||||
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));
|
||||
}
|
||||
|
||||
/* 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;
|
||||
/* Skip the PC past function prologue instructions (32-bit version).
|
||||
This is a helper function for mips_skip_prologue. */
|
||||
|
||||
static CORE_ADDR
|
||||
mips32_skip_prologue (pc, lenient)
|
||||
CORE_ADDR pc; /* starting PC to search from */
|
||||
int lenient;
|
||||
{
|
||||
t_inst inst;
|
||||
unsigned offset;
|
||||
CORE_ADDR end_pc;
|
||||
int seen_sp_adjust = 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
|
||||
instruction and the instructions that save registers on the stack
|
||||
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];
|
||||
int status;
|
||||
|
||||
status = read_memory_nobpt (pc + offset, buf, MIPS_INSTLEN);
|
||||
status = read_memory_nobpt (pc, buf, MIPS_INSTLEN);
|
||||
if (status)
|
||||
memory_error (status, pc + offset);
|
||||
memory_error (status, pc);
|
||||
inst = (unsigned long)extract_unsigned_integer (buf, MIPS_INSTLEN);
|
||||
|
||||
#if 0
|
||||
@ -1430,8 +1427,9 @@ mips_skip_prologue (pc, lenient)
|
||||
continue; /* reg != $zero */
|
||||
|
||||
/* move $s8,$sp. With different versions of gas this will be either
|
||||
`addu $s8,$sp,$zero' or `or $s8,$sp,$zero'. Accept either. */
|
||||
else if (inst == 0x03A0F021 || inst == 0x03a0f025)
|
||||
`addu $s8,$sp,$zero' or `or $s8,$sp,$zero' or `daddu s8,sp,$0'.
|
||||
Accept any one of these. */
|
||||
else if (inst == 0x03A0F021 || inst == 0x03a0f025 || inst == 0x03a0f02d)
|
||||
continue;
|
||||
|
||||
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
|
||||
if the load immediate was not followed by a stack adjustment. */
|
||||
if (load_immediate_bytes && !seen_sp_adjust)
|
||||
offset -= load_immediate_bytes;
|
||||
return pc + offset;
|
||||
pc -= load_immediate_bytes;
|
||||
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
|
||||
/* 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
|
||||
in the proc_desc have actually taken place. */
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user