* infrun.c (wait_for_inferior): Mark registers as invalid when
stepping over an instruction that triggered a watchpoint. * remote-mips.c: Numerous changes to support hardware breakpoints and watchpoints on LSI MiniRISC and TinyRISC boards. * mips-tdep.c: Move MIPS16-related macros to config/mips/tm-mips.h. (mips_breakpoint_from_pc): Account for different breakpoint instructions used by PMON and IDT monitor. * config/mips/tm-embed.h: Enable hardware breakpoints on embedded MIPS targets. * config/mips/tm-mips.h: Define breakpoint instructions for PMON and IDT monitor. Move MIPS16-related macros here from mips-tdep.c.
This commit is contained in:
parent
77f3ac77b5
commit
f781fe93a6
|
@ -1,3 +1,18 @@
|
||||||
|
Mon Jun 16 18:38:28 1997 Mark Alexander <marka@cygnus.com>
|
||||||
|
|
||||||
|
* infrun.c (wait_for_inferior): Mark registers as invalid when
|
||||||
|
stepping over an instruction that triggered a watchpoint.
|
||||||
|
* remote-mips.c: Numerous changes to support hardware breakpoints
|
||||||
|
and watchpoints on LSI MiniRISC and TinyRISC boards.
|
||||||
|
* mips-tdep.c: Move MIPS16-related macros to config/mips/tm-mips.h.
|
||||||
|
(mips_breakpoint_from_pc): Account for different breakpoint
|
||||||
|
instructions used by PMON and IDT monitor.
|
||||||
|
* config/mips/tm-embed.h: Enable hardware breakpoints on embedded
|
||||||
|
MIPS targets.
|
||||||
|
* config/mips/tm-mips.h: Define breakpoint instructions for
|
||||||
|
PMON and IDT monitor. Move MIPS16-related macros here from
|
||||||
|
mips-tdep.c.
|
||||||
|
|
||||||
Fri Jun 13 13:44:47 1997 Michael Snyder (msnyder@cleaver.cygnus.com)
|
Fri Jun 13 13:44:47 1997 Michael Snyder (msnyder@cleaver.cygnus.com)
|
||||||
|
|
||||||
* config/mips/tm-tx39[l].h, tx39[l].mt: change r3900 target to tx39.
|
* config/mips/tm-tx39[l].h, tx39[l].mt: change r3900 target to tx39.
|
||||||
|
|
|
@ -23,6 +23,27 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||||
#undef DEFAULT_MIPS_TYPE
|
#undef DEFAULT_MIPS_TYPE
|
||||||
#define DEFAULT_MIPS_TYPE "r3051"
|
#define DEFAULT_MIPS_TYPE "r3051"
|
||||||
|
|
||||||
|
/* Watchpoint support */
|
||||||
|
|
||||||
|
#define TARGET_HAS_HARDWARE_WATCHPOINTS
|
||||||
|
|
||||||
|
/* Use these macros for watchpoint insertion/deletion. */
|
||||||
|
/* type can be 0: write watch, 1: read watch, 2: access watch (read/write) */
|
||||||
|
|
||||||
|
#define target_insert_watchpoint(addr, len, type) \
|
||||||
|
remote_mips_set_watchpoint (addr, len, type)
|
||||||
|
int remote_mips_set_watchpoint PARAMS ((CORE_ADDR addr, int len, int type));
|
||||||
|
|
||||||
|
#define target_remove_watchpoint(addr, len, type) \
|
||||||
|
remote_mips_remove_watchpoint (addr, len, type)
|
||||||
|
int remote_mips_remove_watchpoint PARAMS ((CORE_ADDR addr, int len, int type));
|
||||||
|
|
||||||
|
/* We need to remove watchpoints when stepping, else we hit them again! */
|
||||||
|
|
||||||
|
#define HAVE_NONSTEPPABLE_WATCHPOINT
|
||||||
|
|
||||||
|
#define STOPPED_BY_WATCHPOINT(w) remote_mips_stopped_by_watchpoint ()
|
||||||
|
|
||||||
/* start-sanitize-gm */
|
/* start-sanitize-gm */
|
||||||
#ifdef GENERAL_MAGIC
|
#ifdef GENERAL_MAGIC
|
||||||
|
|
||||||
|
@ -32,29 +53,18 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||||
|
|
||||||
#undef GET_LONGJMP_TARGET
|
#undef GET_LONGJMP_TARGET
|
||||||
|
|
||||||
/* Watchpoint support */
|
|
||||||
|
|
||||||
#define TARGET_HAS_HARDWARE_WATCHPOINTS
|
|
||||||
|
|
||||||
#define TARGET_CAN_USE_HARDWARE_WATCHPOINT(type, cnt, ot) \
|
#define TARGET_CAN_USE_HARDWARE_WATCHPOINT(type, cnt, ot) \
|
||||||
(1 == 1) /* We allow all types of hardware watchpoints */
|
(1 == 1) /* We allow all types of hardware watchpoints */
|
||||||
|
|
||||||
/* Use these macros for watchpoint insertion/deletion. */
|
|
||||||
/* type can be 0: write watch, 1: read watch, 2: access watch (read/write) */
|
|
||||||
|
|
||||||
#define target_insert_watchpoint(addr, len, type) \
|
|
||||||
remote_mips_set_watchpoint (addr, len, type)
|
|
||||||
|
|
||||||
#define target_remove_watchpoint(addr, len, type) \
|
|
||||||
remote_mips_remove_watchpoint (addr, len, type)
|
|
||||||
|
|
||||||
/* We need to remove watchpoints when stepping, else we hit them again! */
|
|
||||||
|
|
||||||
#define HAVE_NONSTEPPABLE_WATCHPOINT
|
|
||||||
|
|
||||||
#define STOPPED_BY_WATCHPOINT(w) remote_mips_stopped_by_watchpoint ()
|
|
||||||
|
|
||||||
#define FLUSH_CACHED_MEMORY() flush_cached_memory()
|
#define FLUSH_CACHED_MEMORY() flush_cached_memory()
|
||||||
|
|
||||||
|
#else
|
||||||
|
/* end-sanitize-gm */
|
||||||
|
|
||||||
|
#define TARGET_CAN_USE_HARDWARE_WATCHPOINT(type, cnt, ot) \
|
||||||
|
remote_mips_can_use_hardware_watchpoint(cnt)
|
||||||
|
int remote_mips_can_use_hardware_watchpoint PARAMS ((int cnt));
|
||||||
|
|
||||||
|
/* start-sanitize-gm */
|
||||||
#endif /* GENERAL_MAGIC */
|
#endif /* GENERAL_MAGIC */
|
||||||
/* end-sanitize-gm */
|
/* end-sanitize-gm */
|
||||||
|
|
|
@ -115,10 +115,16 @@ extern int in_sigtramp PARAMS ((CORE_ADDR, char *));
|
||||||
|
|
||||||
#define BIG_ENDIAN 4321
|
#define BIG_ENDIAN 4321
|
||||||
|
|
||||||
/* Old-style breakpoint macros. */
|
/* Old-style breakpoint macros.
|
||||||
|
The IDT board uses an unusual breakpoint value, and sometimes gets
|
||||||
|
confused when it sees the usual MIPS breakpoint instruction. */
|
||||||
|
|
||||||
#define BIG_BREAKPOINT {0, 0x5, 0, 0xd}
|
#define BIG_BREAKPOINT {0, 0x5, 0, 0xd}
|
||||||
#define LITTLE_BREAKPOINT {0xd, 0, 0x5, 0}
|
#define LITTLE_BREAKPOINT {0xd, 0, 0x5, 0}
|
||||||
|
#define PMON_BIG_BREAKPOINT {0, 0, 0, 0xd}
|
||||||
|
#define PMON_LITTLE_BREAKPOINT {0xd, 0, 0, 0}
|
||||||
|
#define IDT_BIG_BREAKPOINT {0, 0, 0x0a, 0xd}
|
||||||
|
#define IDT_LITTLE_BREAKPOINT {0xd, 0x0a, 0, 0}
|
||||||
#define MIPS16_BIG_BREAKPOINT {0xe8, 0xa5}
|
#define MIPS16_BIG_BREAKPOINT {0xe8, 0xa5}
|
||||||
#define MIPS16_LITTLE_BREAKPOINT {0xa5, 0xe8}
|
#define MIPS16_LITTLE_BREAKPOINT {0xa5, 0xe8}
|
||||||
|
|
||||||
|
@ -519,4 +525,16 @@ extern int mips_ignore_helper PARAMS ((CORE_ADDR pc));
|
||||||
#define TARGET_MIPS
|
#define TARGET_MIPS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Definitions and declarations used by mips-tdep.c and remote-mips.c */
|
||||||
|
#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 */
|
||||||
|
|
||||||
|
/* MIPS16 function addresses are odd (bit 0 is set). Here are some
|
||||||
|
macros to test, set, or clear bit 0 of addresses. */
|
||||||
|
#define IS_MIPS16_ADDR(addr) ((addr) & 1)
|
||||||
|
#define MAKE_MIPS16_ADDR(addr) ((addr) | 1)
|
||||||
|
#define UNMAKE_MIPS16_ADDR(addr) ((addr) & ~1)
|
||||||
|
|
||||||
#endif /* TM_MIPS_H */
|
#endif /* TM_MIPS_H */
|
||||||
|
|
312
gdb/mips-tdep.c
312
gdb/mips-tdep.c
|
@ -41,18 +41,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||||
/* FIXME: Put this declaration in frame.h. */
|
/* FIXME: Put this declaration in frame.h. */
|
||||||
extern struct obstack frame_cache_obstack;
|
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 */
|
|
||||||
|
|
||||||
/* MIPS16 function addresses are odd (bit 0 is set). Here are some
|
|
||||||
macros to test, set, or clear bit 0 of addresses. */
|
|
||||||
#define IS_MIPS16_ADDR(addr) ((addr) & 1)
|
|
||||||
#define MAKE_MIPS16_ADDR(addr) ((addr) | 1)
|
|
||||||
#define UNMAKE_MIPS16_ADDR(addr) ((addr) & ~1)
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
static int mips_in_lenient_prologue PARAMS ((CORE_ADDR, CORE_ADDR));
|
static int mips_in_lenient_prologue PARAMS ((CORE_ADDR, CORE_ADDR));
|
||||||
#endif
|
#endif
|
||||||
|
@ -545,9 +533,9 @@ mips_addr_bits_remove (addr)
|
||||||
{
|
{
|
||||||
#if GDB_TARGET_IS_MIPS64
|
#if GDB_TARGET_IS_MIPS64
|
||||||
if ((addr >> 32 == (CORE_ADDR)0xffffffff)
|
if ((addr >> 32 == (CORE_ADDR)0xffffffff)
|
||||||
&& (strcmp(target_shortname,"pmon")==0
|
&& (strcmp (target_shortname,"pmon")==0
|
||||||
|| strcmp(target_shortname,"ddb")==0
|
|| strcmp (target_shortname,"ddb")==0
|
||||||
|| strcmp(target_shortname,"sim")==0))
|
|| strcmp (target_shortname,"sim")==0))
|
||||||
{
|
{
|
||||||
/* This hack is a work-around for existing boards using PMON,
|
/* This hack is a work-around for existing boards using PMON,
|
||||||
the simulator, and any other 64-bit targets that doesn't have
|
the simulator, and any other 64-bit targets that doesn't have
|
||||||
|
@ -574,6 +562,20 @@ mips_addr_bits_remove (addr)
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mips_init_frame_pc_first (fromleaf, prev)
|
||||||
|
int fromleaf;
|
||||||
|
struct frame_info *prev;
|
||||||
|
{
|
||||||
|
CORE_ADDR pc, tmp;
|
||||||
|
|
||||||
|
pc = ((fromleaf) ? SAVED_PC_AFTER_CALL (prev->next) :
|
||||||
|
prev->next ? FRAME_SAVED_PC (prev->next) : read_pc ());
|
||||||
|
tmp = mips_skip_stub (pc);
|
||||||
|
prev->pc = tmp ? tmp : pc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
CORE_ADDR
|
CORE_ADDR
|
||||||
mips_frame_saved_pc(frame)
|
mips_frame_saved_pc(frame)
|
||||||
struct frame_info *frame;
|
struct frame_info *frame;
|
||||||
|
@ -637,7 +639,7 @@ heuristic_proc_start(pc)
|
||||||
else
|
else
|
||||||
warning("Hit heuristic-fence-post without finding");
|
warning("Hit heuristic-fence-post without finding");
|
||||||
|
|
||||||
warning("enclosing function for address 0x%s", paddr (pc));
|
warning("enclosing function for address 0x%s", paddr_nz (pc));
|
||||||
if (!blurb_printed)
|
if (!blurb_printed)
|
||||||
{
|
{
|
||||||
printf_filtered ("\
|
printf_filtered ("\
|
||||||
|
@ -1096,29 +1098,36 @@ CORE_ADDR
|
||||||
mips_frame_chain(frame)
|
mips_frame_chain(frame)
|
||||||
struct frame_info *frame;
|
struct frame_info *frame;
|
||||||
{
|
{
|
||||||
mips_extra_func_info_t proc_desc;
|
mips_extra_func_info_t proc_desc;
|
||||||
CORE_ADDR saved_pc = FRAME_SAVED_PC(frame);
|
CORE_ADDR tmp;
|
||||||
|
CORE_ADDR saved_pc = FRAME_SAVED_PC(frame);
|
||||||
|
|
||||||
if (saved_pc == 0 || inside_entry_file (saved_pc))
|
if (saved_pc == 0 || inside_entry_file (saved_pc))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
proc_desc = find_proc_desc(saved_pc, frame);
|
/* Check if the PC is inside a call stub. If it is, fetch the
|
||||||
if (!proc_desc)
|
PC of the caller of that stub. */
|
||||||
return 0;
|
if ((tmp = mips_skip_stub (saved_pc)) != 0)
|
||||||
|
saved_pc = tmp;
|
||||||
|
|
||||||
cached_proc_desc = proc_desc;
|
/* Look up the procedure descriptor for this PC. */
|
||||||
|
proc_desc = find_proc_desc(saved_pc, frame);
|
||||||
|
if (!proc_desc)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* If no frame pointer and frame size is zero, we must be at end
|
cached_proc_desc = proc_desc;
|
||||||
of stack (or otherwise hosed). If we don't check frame size,
|
|
||||||
we loop forever if we see a zero size frame. */
|
/* If no frame pointer and frame size is zero, we must be at end
|
||||||
if (PROC_FRAME_REG (proc_desc) == SP_REGNUM
|
of stack (or otherwise hosed). If we don't check frame size,
|
||||||
&& PROC_FRAME_OFFSET (proc_desc) == 0
|
we loop forever if we see a zero size frame. */
|
||||||
/* The previous frame from a sigtramp frame might be frameless
|
if (PROC_FRAME_REG (proc_desc) == SP_REGNUM
|
||||||
and have frame size zero. */
|
&& PROC_FRAME_OFFSET (proc_desc) == 0
|
||||||
&& !frame->signal_handler_caller)
|
/* The previous frame from a sigtramp frame might be frameless
|
||||||
return 0;
|
and have frame size zero. */
|
||||||
else
|
&& !frame->signal_handler_caller)
|
||||||
return get_frame_pointer (frame, proc_desc);
|
return 0;
|
||||||
|
else
|
||||||
|
return get_frame_pointer (frame, proc_desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -1540,12 +1549,11 @@ mips_print_register (regnum, all)
|
||||||
if (regnum >= FP0_REGNUM && regnum < FP0_REGNUM+MIPS_NUMREGS
|
if (regnum >= FP0_REGNUM && regnum < FP0_REGNUM+MIPS_NUMREGS
|
||||||
&& !((regnum-FP0_REGNUM) & 1))
|
&& !((regnum-FP0_REGNUM) & 1))
|
||||||
{
|
{
|
||||||
char dbuffer[MAX_REGISTER_RAW_SIZE];
|
char dbuffer[2 * MAX_REGISTER_RAW_SIZE];
|
||||||
|
|
||||||
/* MIPS doubles are stored in a register pair with the least
|
read_relative_register_raw_bytes (regnum, dbuffer);
|
||||||
signficant register in the lower-numbered register. */
|
read_relative_register_raw_bytes (regnum+1, dbuffer+MIPS_REGSIZE);
|
||||||
read_relative_register_raw_bytes (regnum+1, dbuffer);
|
REGISTER_CONVERT_TO_TYPE (regnum, builtin_type_double, dbuffer);
|
||||||
read_relative_register_raw_bytes (regnum, dbuffer+MIPS_REGSIZE);
|
|
||||||
|
|
||||||
printf_filtered ("(d%d: ", regnum-FP0_REGNUM);
|
printf_filtered ("(d%d: ", regnum-FP0_REGNUM);
|
||||||
val_print (builtin_type_double, dbuffer, 0,
|
val_print (builtin_type_double, dbuffer, 0,
|
||||||
|
@ -1901,19 +1909,7 @@ mips_extract_return_value (valtype, regbuf, valbuf)
|
||||||
if (TYPE_CODE (valtype) == TYPE_CODE_FLT
|
if (TYPE_CODE (valtype) == TYPE_CODE_FLT
|
||||||
&& (mips_fpu == MIPS_FPU_DOUBLE
|
&& (mips_fpu == MIPS_FPU_DOUBLE
|
||||||
|| (mips_fpu == MIPS_FPU_SINGLE && len <= MIPS_REGSIZE)))
|
|| (mips_fpu == MIPS_FPU_SINGLE && len <= MIPS_REGSIZE)))
|
||||||
{
|
regnum = FP0_REGNUM;
|
||||||
regnum = FP0_REGNUM;
|
|
||||||
|
|
||||||
/* If this is a double, the odd-numbered register (FP1) contains the
|
|
||||||
high word of the result. Copy that to the buffer before
|
|
||||||
copying the low word in FP0. */
|
|
||||||
if (len > MIPS_REGSIZE)
|
|
||||||
{
|
|
||||||
memcpy (valbuf, regbuf + REGISTER_BYTE (regnum+1), MIPS_REGSIZE);
|
|
||||||
len -= MIPS_REGSIZE;
|
|
||||||
valbuf += MIPS_REGSIZE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TARGET_BYTE_ORDER == BIG_ENDIAN
|
if (TARGET_BYTE_ORDER == BIG_ENDIAN
|
||||||
&& TYPE_CODE (valtype) != TYPE_CODE_FLT
|
&& TYPE_CODE (valtype) != TYPE_CODE_FLT
|
||||||
|
@ -1921,6 +1917,7 @@ mips_extract_return_value (valtype, regbuf, valbuf)
|
||||||
offset = REGISTER_RAW_SIZE (regnum) - len;
|
offset = REGISTER_RAW_SIZE (regnum) - len;
|
||||||
|
|
||||||
memcpy (valbuf, regbuf + REGISTER_BYTE (regnum) + offset, len);
|
memcpy (valbuf, regbuf + REGISTER_BYTE (regnum) + offset, len);
|
||||||
|
REGISTER_CONVERT_TO_TYPE (regnum, valtype, valbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Given a return value in `regbuf' with a type `valtype',
|
/* Given a return value in `regbuf' with a type `valtype',
|
||||||
|
@ -1940,10 +1937,7 @@ mips_store_return_value (valtype, valbuf)
|
||||||
regnum = FP0_REGNUM;
|
regnum = FP0_REGNUM;
|
||||||
|
|
||||||
memcpy(raw_buffer, valbuf, TYPE_LENGTH (valtype));
|
memcpy(raw_buffer, valbuf, TYPE_LENGTH (valtype));
|
||||||
|
|
||||||
#ifdef REGISTER_CONVERT_FROM_TYPE
|
|
||||||
REGISTER_CONVERT_FROM_TYPE(regnum, valtype, raw_buffer);
|
REGISTER_CONVERT_FROM_TYPE(regnum, valtype, raw_buffer);
|
||||||
#endif
|
|
||||||
|
|
||||||
write_register_bytes(REGISTER_BYTE (regnum), raw_buffer, TYPE_LENGTH (valtype));
|
write_register_bytes(REGISTER_BYTE (regnum), raw_buffer, TYPE_LENGTH (valtype));
|
||||||
}
|
}
|
||||||
|
@ -2173,8 +2167,19 @@ unsigned char *mips_breakpoint_from_pc (pcptr, lenptr)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
static char big_breakpoint[] = BIG_BREAKPOINT;
|
static char big_breakpoint[] = BIG_BREAKPOINT;
|
||||||
|
static char pmon_big_breakpoint[] = PMON_BIG_BREAKPOINT;
|
||||||
|
static char idt_big_breakpoint[] = IDT_BIG_BREAKPOINT;
|
||||||
|
|
||||||
*lenptr = sizeof(big_breakpoint);
|
*lenptr = sizeof(big_breakpoint);
|
||||||
return big_breakpoint;
|
|
||||||
|
if (strcmp (target_shortname, "mips") == 0)
|
||||||
|
return idt_big_breakpoint;
|
||||||
|
else if (strcmp (target_shortname, "ddb") == 0
|
||||||
|
|| strcmp (target_shortname, "pmon") == 0
|
||||||
|
|| strcmp (target_shortname, "lsi") == 0)
|
||||||
|
return pmon_big_breakpoint;
|
||||||
|
else
|
||||||
|
return big_breakpoint;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -2189,8 +2194,19 @@ unsigned char *mips_breakpoint_from_pc (pcptr, lenptr)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
static char little_breakpoint[] = LITTLE_BREAKPOINT;
|
static char little_breakpoint[] = LITTLE_BREAKPOINT;
|
||||||
|
static char pmon_little_breakpoint[] = PMON_LITTLE_BREAKPOINT;
|
||||||
|
static char idt_little_breakpoint[] = IDT_LITTLE_BREAKPOINT;
|
||||||
|
|
||||||
*lenptr = sizeof(little_breakpoint);
|
*lenptr = sizeof(little_breakpoint);
|
||||||
return little_breakpoint;
|
|
||||||
|
if (strcmp (target_shortname, "mips") == 0)
|
||||||
|
return idt_little_breakpoint;
|
||||||
|
else if (strcmp (target_shortname, "ddb") == 0
|
||||||
|
|| strcmp (target_shortname, "pmon") == 0
|
||||||
|
|| strcmp (target_shortname, "lsi") == 0)
|
||||||
|
return pmon_little_breakpoint;
|
||||||
|
else
|
||||||
|
return little_breakpoint;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2215,6 +2231,186 @@ mips_about_to_return (pc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* If PC is in a mips16 call or return stub, return the address of the target
|
||||||
|
PC, which is either the callee or the caller. There are several
|
||||||
|
cases which must be handled:
|
||||||
|
|
||||||
|
* If the PC is in __mips16_ret_{d,s}f, this is a return stub and the
|
||||||
|
target PC is in $31 ($ra).
|
||||||
|
* If the PC is in __mips16_call_stub_{1..10}, this is a call stub
|
||||||
|
and the target PC is in $2.
|
||||||
|
* If the PC at the start of __mips16_call_stub_{s,d}f_{0..10}, i.e.
|
||||||
|
before the jal instruction, this is effectively a call stub
|
||||||
|
and the the target PC is in $2. Otherwise this is effectively
|
||||||
|
a return stub and the target PC is in $18.
|
||||||
|
|
||||||
|
See the source code for the stubs in gcc/config/mips/mips16.S for
|
||||||
|
gory details.
|
||||||
|
|
||||||
|
This function implements the SKIP_TRAMPOLINE_CODE macro.
|
||||||
|
*/
|
||||||
|
|
||||||
|
CORE_ADDR
|
||||||
|
mips_skip_stub (pc)
|
||||||
|
CORE_ADDR pc;
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
CORE_ADDR start_addr;
|
||||||
|
|
||||||
|
/* Find the starting address and name of the function containing the PC. */
|
||||||
|
if (find_pc_partial_function (pc, &name, &start_addr, NULL) == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* If the PC is in __mips16_ret_{d,s}f, this is a return stub and the
|
||||||
|
target PC is in $31 ($ra). */
|
||||||
|
if (strcmp (name, "__mips16_ret_sf") == 0
|
||||||
|
|| strcmp (name, "__mips16_ret_df") == 0)
|
||||||
|
return read_register (RA_REGNUM);
|
||||||
|
|
||||||
|
if (strncmp (name, "__mips16_call_stub_", 19) == 0)
|
||||||
|
{
|
||||||
|
/* If the PC is in __mips16_call_stub_{1..10}, this is a call stub
|
||||||
|
and the target PC is in $2. */
|
||||||
|
if (name[19] >= '0' && name[19] <= '9')
|
||||||
|
return read_register (2);
|
||||||
|
|
||||||
|
/* If the PC at the start of __mips16_call_stub_{s,d}f_{0..10}, i.e.
|
||||||
|
before the jal instruction, this is effectively a call stub
|
||||||
|
and the the target PC is in $2. Otherwise this is effectively
|
||||||
|
a return stub and the target PC is in $18. */
|
||||||
|
else if (name[19] == 's' || name[19] == 'd')
|
||||||
|
{
|
||||||
|
if (pc == start_addr)
|
||||||
|
{
|
||||||
|
/* Check if the target of the stub is a compiler-generated
|
||||||
|
stub. Such a stub for a function bar might have a name
|
||||||
|
like __fn_stub_bar, and might look like this:
|
||||||
|
mfc1 $4,$f13
|
||||||
|
mfc1 $5,$f12
|
||||||
|
mfc1 $6,$f15
|
||||||
|
mfc1 $7,$f14
|
||||||
|
la $1,bar (becomes a lui/addiu pair)
|
||||||
|
jr $1
|
||||||
|
So scan down to the lui/addi and extract the target
|
||||||
|
address from those two instructions. */
|
||||||
|
|
||||||
|
CORE_ADDR target_pc = read_register (2);
|
||||||
|
t_inst inst;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* See if the name of the target function is __fn_stub_*. */
|
||||||
|
if (find_pc_partial_function (target_pc, &name, NULL, NULL) == 0)
|
||||||
|
return target_pc;
|
||||||
|
if (strncmp (name, "__fn_stub_", 10) != 0
|
||||||
|
&& strcmp (name, "etext") != 0
|
||||||
|
&& strcmp (name, "_etext") != 0)
|
||||||
|
return target_pc;
|
||||||
|
|
||||||
|
/* Scan through this _fn_stub_ code for the lui/addiu pair.
|
||||||
|
The limit on the search is arbitrarily set to 20
|
||||||
|
instructions. FIXME. */
|
||||||
|
for (i = 0, pc = 0; i < 20; i++, target_pc += MIPS_INSTLEN)
|
||||||
|
{
|
||||||
|
inst = mips_fetch_instruction (target_pc);
|
||||||
|
if ((inst & 0xffff0000) == 0x3c010000) /* lui $at */
|
||||||
|
pc = (inst << 16) & 0xffff0000; /* high word */
|
||||||
|
else if ((inst & 0xffff0000) == 0x24210000) /* addiu $at */
|
||||||
|
return pc | (inst & 0xffff); /* low word */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Couldn't find the lui/addui pair, so return stub address. */
|
||||||
|
return target_pc;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
/* This is the 'return' part of a call stub. The return
|
||||||
|
address is in $r18. */
|
||||||
|
return read_register (18);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0; /* not a stub */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return non-zero if the PC is inside a call thunk (aka stub or trampoline).
|
||||||
|
This implements the IN_SOLIB_CALL_TRAMPOLINE macro. */
|
||||||
|
|
||||||
|
int
|
||||||
|
mips_in_call_stub (pc, name)
|
||||||
|
CORE_ADDR pc;
|
||||||
|
char *name;
|
||||||
|
{
|
||||||
|
CORE_ADDR start_addr;
|
||||||
|
|
||||||
|
/* Find the starting address of the function containing the PC. If the
|
||||||
|
caller didn't give us a name, look it up at the same time. */
|
||||||
|
if (find_pc_partial_function (pc, name ? NULL : &name, &start_addr, NULL) == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (strncmp (name, "__mips16_call_stub_", 19) == 0)
|
||||||
|
{
|
||||||
|
/* If the PC is in __mips16_call_stub_{1..10}, this is a call stub. */
|
||||||
|
if (name[19] >= '0' && name[19] <= '9')
|
||||||
|
return 1;
|
||||||
|
/* If the PC at the start of __mips16_call_stub_{s,d}f_{0..10}, i.e.
|
||||||
|
before the jal instruction, this is effectively a call stub. */
|
||||||
|
else if (name[19] == 's' || name[19] == 'd')
|
||||||
|
return pc == start_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0; /* not a stub */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return non-zero if the PC is inside a return thunk (aka stub or trampoline).
|
||||||
|
This implements the IN_SOLIB_RETURN_TRAMPOLINE macro. */
|
||||||
|
|
||||||
|
int
|
||||||
|
mips_in_return_stub (pc, name)
|
||||||
|
CORE_ADDR pc;
|
||||||
|
char *name;
|
||||||
|
{
|
||||||
|
CORE_ADDR start_addr;
|
||||||
|
|
||||||
|
/* Find the starting address of the function containing the PC. */
|
||||||
|
if (find_pc_partial_function (pc, NULL, &start_addr, NULL) == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* If the PC is in __mips16_ret_{d,s}f, this is a return stub. */
|
||||||
|
if (strcmp (name, "__mips16_ret_sf") == 0
|
||||||
|
|| strcmp (name, "__mips16_ret_df") == 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* If the PC is in __mips16_call_stub_{s,d}f_{0..10} but not at the start,
|
||||||
|
i.e. after the jal instruction, this is effectively a return stub. */
|
||||||
|
if (strncmp (name, "__mips16_call_stub_", 19) == 0
|
||||||
|
&& (name[19] == 's' || name[19] == 'd')
|
||||||
|
&& pc != start_addr)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0; /* not a stub */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return non-zero if the PC is in a library helper function that should
|
||||||
|
be ignored. This implements the IGNORE_HELPER_CALL macro. */
|
||||||
|
|
||||||
|
int
|
||||||
|
mips_ignore_helper (pc)
|
||||||
|
CORE_ADDR pc;
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
|
||||||
|
/* Find the starting address and name of the function containing the PC. */
|
||||||
|
if (find_pc_partial_function (pc, &name, NULL, NULL) == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* If the PC is in __mips16_ret_{d,s}f, this is a library helper function
|
||||||
|
that we want to ignore. */
|
||||||
|
return (strcmp (name, "__mips16_ret_sf") == 0
|
||||||
|
|| strcmp (name, "__mips16_ret_df") == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
_initialize_mips_tdep ()
|
_initialize_mips_tdep ()
|
||||||
{
|
{
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue