aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog21
-rw-r--r--gdb/mips-linux-tdep.c113
-rw-r--r--gdb/tramp-frame.c4
-rw-r--r--gdb/tramp-frame.h7
4 files changed, 139 insertions, 6 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index ebb36b7..80eb8c9 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,24 @@
+2014-12-03 Maciej W. Rozycki <macro@codesourcery.com>
+
+ * tramp-frame.h (tramp_frame): Add `validate' member.
+ * tramp-frame.c (tramp_frame_start): Validate trampoline before
+ scanning.
+ * mips-linux-tdep.c (MICROMIPS_INST_LI_V0): New macro.
+ (MICROMIPS_INST_POOL32A, MICROMIPS_INST_SYSCALL): Likewise.
+ (mips_linux_o32_sigframe): Initialize `validate' member.
+ (mips_linux_o32_rt_sigframe): Likewise.
+ (mips_linux_n32_rt_sigframe): Likewise.
+ (mips_linux_n64_rt_sigframe): Likewise.
+ (micromips_linux_o32_sigframe): New variable.
+ (micromips_linux_o32_rt_sigframe): Likewise.
+ (micromips_linux_n32_rt_sigframe): Likewise.
+ (micromips_linux_n64_rt_sigframe): Likewise.
+ (mips_linux_o32_sigframe_init): Handle microMIPS trampolines.
+ (mips_linux_n32n64_sigframe_init): Likewise.
+ (mips_linux_sigframe_validate): New function.
+ (micromips_linux_sigframe_validate): Likewise.
+ (mips_linux_init_abi): Install microMIPS trampoline unwinders.
+
2014-12-03 Ulrich Weigand  <uweigand@de.ibm.com>
* config/sparc/sol2.mh (NATDEPFILES): Remove core-regset.o.
diff --git a/gdb/mips-linux-tdep.c b/gdb/mips-linux-tdep.c
index bc42921..41602ba 100644
--- a/gdb/mips-linux-tdep.c
+++ b/gdb/mips-linux-tdep.c
@@ -827,6 +827,14 @@ static void mips_linux_n32n64_sigframe_init (const struct tramp_frame *self,
struct trad_frame_cache *this_cache,
CORE_ADDR func);
+static int mips_linux_sigframe_validate (const struct tramp_frame *self,
+ struct frame_info *this_frame,
+ CORE_ADDR *pc);
+
+static int micromips_linux_sigframe_validate (const struct tramp_frame *self,
+ struct frame_info *this_frame,
+ CORE_ADDR *pc);
+
#define MIPS_NR_LINUX 4000
#define MIPS_NR_N64_LINUX 5000
#define MIPS_NR_N32_LINUX 6000
@@ -842,6 +850,10 @@ static void mips_linux_n32n64_sigframe_init (const struct tramp_frame *self,
#define MIPS_INST_LI_V0_N32_RT_SIGRETURN 0x24020000 + MIPS_NR_N32_rt_sigreturn
#define MIPS_INST_SYSCALL 0x0000000c
+#define MICROMIPS_INST_LI_V0 0x3040
+#define MICROMIPS_INST_POOL32A 0x0000
+#define MICROMIPS_INST_SYSCALL 0x8b7c
+
static const struct tramp_frame mips_linux_o32_sigframe = {
SIGTRAMP_FRAME,
4,
@@ -850,7 +862,8 @@ static const struct tramp_frame mips_linux_o32_sigframe = {
{ MIPS_INST_SYSCALL, -1 },
{ TRAMP_SENTINEL_INSN, -1 }
},
- mips_linux_o32_sigframe_init
+ mips_linux_o32_sigframe_init,
+ mips_linux_sigframe_validate
};
static const struct tramp_frame mips_linux_o32_rt_sigframe = {
@@ -860,7 +873,8 @@ static const struct tramp_frame mips_linux_o32_rt_sigframe = {
{ MIPS_INST_LI_V0_RT_SIGRETURN, -1 },
{ MIPS_INST_SYSCALL, -1 },
{ TRAMP_SENTINEL_INSN, -1 } },
- mips_linux_o32_sigframe_init
+ mips_linux_o32_sigframe_init,
+ mips_linux_sigframe_validate
};
static const struct tramp_frame mips_linux_n32_rt_sigframe = {
@@ -871,7 +885,8 @@ static const struct tramp_frame mips_linux_n32_rt_sigframe = {
{ MIPS_INST_SYSCALL, -1 },
{ TRAMP_SENTINEL_INSN, -1 }
},
- mips_linux_n32n64_sigframe_init
+ mips_linux_n32n64_sigframe_init,
+ mips_linux_sigframe_validate
};
static const struct tramp_frame mips_linux_n64_rt_sigframe = {
@@ -882,7 +897,64 @@ static const struct tramp_frame mips_linux_n64_rt_sigframe = {
{ MIPS_INST_SYSCALL, -1 },
{ TRAMP_SENTINEL_INSN, -1 }
},
- mips_linux_n32n64_sigframe_init
+ mips_linux_n32n64_sigframe_init,
+ mips_linux_sigframe_validate
+};
+
+static const struct tramp_frame micromips_linux_o32_sigframe = {
+ SIGTRAMP_FRAME,
+ 2,
+ {
+ { MICROMIPS_INST_LI_V0, -1 },
+ { MIPS_NR_sigreturn, -1 },
+ { MICROMIPS_INST_POOL32A, -1 },
+ { MICROMIPS_INST_SYSCALL, -1 },
+ { TRAMP_SENTINEL_INSN, -1 }
+ },
+ mips_linux_o32_sigframe_init,
+ micromips_linux_sigframe_validate
+};
+
+static const struct tramp_frame micromips_linux_o32_rt_sigframe = {
+ SIGTRAMP_FRAME,
+ 2,
+ {
+ { MICROMIPS_INST_LI_V0, -1 },
+ { MIPS_NR_rt_sigreturn, -1 },
+ { MICROMIPS_INST_POOL32A, -1 },
+ { MICROMIPS_INST_SYSCALL, -1 },
+ { TRAMP_SENTINEL_INSN, -1 }
+ },
+ mips_linux_o32_sigframe_init,
+ micromips_linux_sigframe_validate
+};
+
+static const struct tramp_frame micromips_linux_n32_rt_sigframe = {
+ SIGTRAMP_FRAME,
+ 2,
+ {
+ { MICROMIPS_INST_LI_V0, -1 },
+ { MIPS_NR_N32_rt_sigreturn, -1 },
+ { MICROMIPS_INST_POOL32A, -1 },
+ { MICROMIPS_INST_SYSCALL, -1 },
+ { TRAMP_SENTINEL_INSN, -1 }
+ },
+ mips_linux_n32n64_sigframe_init,
+ micromips_linux_sigframe_validate
+};
+
+static const struct tramp_frame micromips_linux_n64_rt_sigframe = {
+ SIGTRAMP_FRAME,
+ 2,
+ {
+ { MICROMIPS_INST_LI_V0, -1 },
+ { MIPS_NR_N64_rt_sigreturn, -1 },
+ { MICROMIPS_INST_POOL32A, -1 },
+ { MICROMIPS_INST_SYSCALL, -1 },
+ { TRAMP_SENTINEL_INSN, -1 }
+ },
+ mips_linux_n32n64_sigframe_init,
+ micromips_linux_sigframe_validate
};
/* *INDENT-OFF* */
@@ -1002,7 +1074,8 @@ mips_linux_o32_sigframe_init (const struct tramp_frame *self,
const struct mips_regnum *regs = mips_regnum (gdbarch);
CORE_ADDR regs_base;
- if (self == &mips_linux_o32_sigframe)
+ if (self == &mips_linux_o32_sigframe
+ || self == &micromips_linux_o32_sigframe)
sigcontext_base = frame_sp + SIGFRAME_SIGCONTEXT_OFFSET;
else
sigcontext_base = frame_sp + RTSIGFRAME_SIGCONTEXT_OFFSET;
@@ -1203,7 +1276,8 @@ mips_linux_n32n64_sigframe_init (const struct tramp_frame *self,
CORE_ADDR sigcontext_base;
const struct mips_regnum *regs = mips_regnum (gdbarch);
- if (self == &mips_linux_n32_rt_sigframe)
+ if (self == &mips_linux_n32_rt_sigframe
+ || self == &micromips_linux_n32_rt_sigframe)
sigcontext_base = frame_sp + N32_SIGFRAME_SIGCONTEXT_OFFSET;
else
sigcontext_base = frame_sp + N64_SIGFRAME_SIGCONTEXT_OFFSET;
@@ -1273,6 +1347,26 @@ mips_linux_n32n64_sigframe_init (const struct tramp_frame *self,
trad_frame_set_id (this_cache, frame_id_build (frame_sp, func));
}
+/* Implement struct tramp_frame's "validate" method for standard MIPS code. */
+
+static int
+mips_linux_sigframe_validate (const struct tramp_frame *self,
+ struct frame_info *this_frame,
+ CORE_ADDR *pc)
+{
+ return mips_pc_is_mips (*pc);
+}
+
+/* Implement struct tramp_frame's "validate" method for microMIPS code. */
+
+static int
+micromips_linux_sigframe_validate (const struct tramp_frame *self,
+ struct frame_info *this_frame,
+ CORE_ADDR *pc)
+{
+ return mips_pc_is_micromips (get_frame_arch (this_frame), *pc);
+}
+
/* Implement the "write_pc" gdbarch method. */
static void
@@ -1556,6 +1650,9 @@ mips_linux_init_abi (struct gdbarch_info info,
mips_linux_get_longjmp_target);
set_solib_svr4_fetch_link_map_offsets
(gdbarch, svr4_ilp32_fetch_link_map_offsets);
+ tramp_frame_prepend_unwinder (gdbarch, &micromips_linux_o32_sigframe);
+ tramp_frame_prepend_unwinder (gdbarch,
+ &micromips_linux_o32_rt_sigframe);
tramp_frame_prepend_unwinder (gdbarch, &mips_linux_o32_sigframe);
tramp_frame_prepend_unwinder (gdbarch, &mips_linux_o32_rt_sigframe);
set_xml_syscall_file_name (gdbarch, "syscalls/mips-o32-linux.xml");
@@ -1571,6 +1668,8 @@ mips_linux_init_abi (struct gdbarch_info info,
except that the quiet/signalling NaN bit is reversed (GDB
does not distinguish between quiet and signalling NaNs). */
set_gdbarch_long_double_format (gdbarch, floatformats_ia64_quad);
+ tramp_frame_prepend_unwinder (gdbarch,
+ &micromips_linux_n32_rt_sigframe);
tramp_frame_prepend_unwinder (gdbarch, &mips_linux_n32_rt_sigframe);
set_xml_syscall_file_name (gdbarch, "syscalls/mips-n32-linux.xml");
break;
@@ -1585,6 +1684,8 @@ mips_linux_init_abi (struct gdbarch_info info,
except that the quiet/signalling NaN bit is reversed (GDB
does not distinguish between quiet and signalling NaNs). */
set_gdbarch_long_double_format (gdbarch, floatformats_ia64_quad);
+ tramp_frame_prepend_unwinder (gdbarch,
+ &micromips_linux_n64_rt_sigframe);
tramp_frame_prepend_unwinder (gdbarch, &mips_linux_n64_rt_sigframe);
set_xml_syscall_file_name (gdbarch, "syscalls/mips-n64-linux.xml");
break;
diff --git a/gdb/tramp-frame.c b/gdb/tramp-frame.c
index 0fd6ddc..a0e3eb5 100644
--- a/gdb/tramp-frame.c
+++ b/gdb/tramp-frame.c
@@ -86,6 +86,10 @@ tramp_frame_start (const struct tramp_frame *tramp,
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
int ti;
+ /* Check if we can use this trampoline. */
+ if (tramp->validate && !tramp->validate (tramp, this_frame, &pc))
+ return 0;
+
/* Search through the trampoline for one that matches the
instruction sequence around PC. */
for (ti = 0; tramp->insn[ti].bytes != TRAMP_SENTINEL_INSN; ti++)
diff --git a/gdb/tramp-frame.h b/gdb/tramp-frame.h
index eeaf7b5..d659c0b 100644
--- a/gdb/tramp-frame.h
+++ b/gdb/tramp-frame.h
@@ -69,6 +69,13 @@ struct tramp_frame
struct frame_info *this_frame,
struct trad_frame_cache *this_cache,
CORE_ADDR func);
+ /* Return non-zero if the tramp-frame is valid for the PC requested.
+ Adjust the PC to point to the address to check the instruction
+ sequence against if required. If this is NULL, then the tramp-frame
+ is valid for any PC. */
+ int (*validate) (const struct tramp_frame *self,
+ struct frame_info *this_frame,
+ CORE_ADDR *pc);
};
void tramp_frame_prepend_unwinder (struct gdbarch *gdbarch,