From daddc3c15f2b1e2d39bddea8e055a0e329b4035e Mon Sep 17 00:00:00 2001 From: Daniel Jacobowitz Date: Thu, 27 Sep 2007 18:48:33 +0000 Subject: [PATCH] * 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. --- gdb/ChangeLog | 9 +++++++++ gdb/Makefile.in | 2 +- gdb/arm-linux-tdep.c | 23 ++++++++++++++++++++++- gdb/arm-tdep.c | 31 +++++++++++++++++++++++++------ gdb/arm-tdep.h | 1 + 5 files changed, 58 insertions(+), 8 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index f6cc0e6f23..e0ae42681e 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,12 @@ +2007-09-27 Daniel Jacobowitz + + * 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 * varobj.c (install_new_value): Don't diff --git a/gdb/Makefile.in b/gdb/Makefile.in index cebfbc9bb1..6469244230 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 e33a93e625..fd6b2e5a6a 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 b4d221184a..325bd80df7 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 5fa8b62d38..5ab110e824 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. */