aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Jacobowitz <drow@false.org>2007-09-27 18:48:33 +0000
committerDaniel Jacobowitz <drow@false.org>2007-09-27 18:48:33 +0000
commitdaddc3c15f2b1e2d39bddea8e055a0e329b4035e (patch)
tree92ca8568bd6a3281c3ad02d2efec37a9bc1eef21
parent7c52e0e8658a0ea03067c301a15e793cf9f1c208 (diff)
downloadgdb-daddc3c15f2b1e2d39bddea8e055a0e329b4035e.zip
gdb-daddc3c15f2b1e2d39bddea8e055a0e329b4035e.tar.gz
gdb-daddc3c15f2b1e2d39bddea8e055a0e329b4035e.tar.bz2
* arm-linux-tdep.c (arm_linux_software_single_step): New.
(arm_linux_init_abi): Use it. * arm-tdep.c (arm_get_next_pc): Make global. Handle all-ones condition correctly. * arm-tdep.h (arm_get_next_pc): Declare. * Makefile.in (arm-linux-tdep.o): Update.
-rw-r--r--gdb/ChangeLog9
-rw-r--r--gdb/Makefile.in2
-rw-r--r--gdb/arm-linux-tdep.c23
-rw-r--r--gdb/arm-tdep.c31
-rw-r--r--gdb/arm-tdep.h1
5 files changed, 58 insertions, 8 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index f6cc0e6..e0ae426 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,12 @@
+2007-09-27 Daniel Jacobowitz <dan@codesourcery.com>
+
+ * arm-linux-tdep.c (arm_linux_software_single_step): New.
+ (arm_linux_init_abi): Use it.
+ * arm-tdep.c (arm_get_next_pc): Make global. Handle all-ones
+ condition correctly.
+ * arm-tdep.h (arm_get_next_pc): Declare.
+ * Makefile.in (arm-linux-tdep.o): Update.
+
2007-09-26 Vladimir Prus <vladimir@codesourcery.com>
* varobj.c (install_new_value): Don't
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index cebfbc9..6469244 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1805,7 +1805,7 @@ arm-linux-nat.o: arm-linux-nat.c $(defs_h) $(inferior_h) $(gdbcore_h) \
arm-linux-tdep.o: arm-linux-tdep.c $(defs_h) $(target_h) $(value_h) \
$(gdbtypes_h) $(floatformat_h) $(gdbcore_h) $(frame_h) $(regcache_h) \
$(doublest_h) $(solib_svr4_h) $(osabi_h) $(arm_tdep_h) \
- $(regset_h) $(arm_linux_tdep_h) \
+ $(regset_h) $(arm_linux_tdep_h) $(breakpoint_h) \
$(glibc_tdep_h) $(trad_frame_h) $(tramp_frame_h) $(gdb_string_h)
armnbsd-nat.o: armnbsd-nat.c $(defs_h) $(gdbcore_h) $(inferior_h) \
$(regcache_h) $(target_h) $(gdb_string_h) $(arm_tdep_h) $(inf_ptrace_h)
diff --git a/gdb/arm-linux-tdep.c b/gdb/arm-linux-tdep.c
index e33a93e..fd6b2e5 100644
--- a/gdb/arm-linux-tdep.c
+++ b/gdb/arm-linux-tdep.c
@@ -32,6 +32,7 @@
#include "regset.h"
#include "trad-frame.h"
#include "tramp-frame.h"
+#include "breakpoint.h"
#include "arm-tdep.h"
#include "arm-linux-tdep.h"
@@ -568,6 +569,26 @@ arm_linux_regset_from_core_section (struct gdbarch *gdbarch,
return NULL;
}
+/* Insert a single step breakpoint at the next executed instruction. */
+
+int
+arm_linux_software_single_step (struct frame_info *frame)
+{
+ CORE_ADDR next_pc = arm_get_next_pc (frame, get_frame_pc (frame));
+
+ /* The Linux kernel offers some user-mode helpers in a high page. We can
+ not read this page (as of 2.6.23), and even if we could then we couldn't
+ set breakpoints in it, and even if we could then the atomic operations
+ would fail when interrupted. They are all called as functions and return
+ to the address in LR, so step to there instead. */
+ if (next_pc > 0xffff0000)
+ next_pc = get_frame_register_unsigned (frame, ARM_LR_REGNUM);
+
+ insert_single_step_breakpoint (next_pc);
+
+ return 1;
+}
+
static void
arm_linux_init_abi (struct gdbarch_info info,
struct gdbarch *gdbarch)
@@ -604,7 +625,7 @@ arm_linux_init_abi (struct gdbarch_info info,
(gdbarch, svr4_ilp32_fetch_link_map_offsets);
/* Single stepping. */
- set_gdbarch_software_single_step (gdbarch, arm_software_single_step);
+ set_gdbarch_software_single_step (gdbarch, arm_linux_software_single_step);
/* Shared library handling. */
set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index b4d2211..325bd80 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -1664,7 +1664,7 @@ thumb_get_next_pc (struct frame_info *frame, CORE_ADDR pc)
return nextpc;
}
-static CORE_ADDR
+CORE_ADDR
arm_get_next_pc (struct frame_info *frame, CORE_ADDR pc)
{
unsigned long pc_val;
@@ -1680,7 +1680,30 @@ arm_get_next_pc (struct frame_info *frame, CORE_ADDR pc)
status = get_frame_register_unsigned (frame, ARM_PS_REGNUM);
nextpc = (CORE_ADDR) (pc_val + 4); /* Default case */
- if (condition_true (bits (this_instr, 28, 31), status))
+ if (bits (this_instr, 28, 31) == INST_NV)
+ switch (bits (this_instr, 24, 27))
+ {
+ case 0xa:
+ case 0xb:
+ {
+ /* Branch with Link and change to Thumb. */
+ nextpc = BranchDest (pc, this_instr);
+ nextpc |= bit (this_instr, 24) << 1;
+
+ nextpc = gdbarch_addr_bits_remove (current_gdbarch, nextpc);
+ if (nextpc == pc)
+ error (_("Infinite loop detected"));
+ break;
+ }
+ case 0xc:
+ case 0xd:
+ case 0xe:
+ /* Coprocessor register transfer. */
+ if (bits (this_instr, 12, 15) == 15)
+ error (_("Invalid update to pc in instruction"));
+ break;
+ }
+ else if (condition_true (bits (this_instr, 28, 31), status))
{
switch (bits (this_instr, 24, 27))
{
@@ -1886,10 +1909,6 @@ arm_get_next_pc (struct frame_info *frame, CORE_ADDR pc)
{
nextpc = BranchDest (pc, this_instr);
- /* BLX */
- if (bits (this_instr, 28, 31) == INST_NV)
- nextpc |= bit (this_instr, 24) << 1;
-
nextpc = gdbarch_addr_bits_remove (current_gdbarch, nextpc);
if (nextpc == pc)
error (_("Infinite loop detected"));
diff --git a/gdb/arm-tdep.h b/gdb/arm-tdep.h
index 5fa8b62..5ab110e 100644
--- a/gdb/arm-tdep.h
+++ b/gdb/arm-tdep.h
@@ -181,6 +181,7 @@ struct gdbarch_tdep
#endif
CORE_ADDR arm_skip_stub (struct frame_info *, CORE_ADDR);
+CORE_ADDR arm_get_next_pc (struct frame_info *, CORE_ADDR);
int arm_software_single_step (struct frame_info *);
/* Functions exported from armbsd-tdep.h. */