diff options
author | Antoine Tremblay <antoine.tremblay@ericsson.com> | 2015-12-18 11:33:59 -0500 |
---|---|---|
committer | Antoine Tremblay <antoine.tremblay@ericsson.com> | 2015-12-18 11:39:48 -0500 |
commit | d9311bfaf572cf14af577a66e79c51c491553552 (patch) | |
tree | 79f246efab51cde1d20b37d32e17e24bdf66c82d /gdb/gdbserver | |
parent | 68ce205943e0821eacd8028881ced3607cc83c0d (diff) | |
download | gdb-d9311bfaf572cf14af577a66e79c51c491553552.zip gdb-d9311bfaf572cf14af577a66e79c51c491553552.tar.gz gdb-d9311bfaf572cf14af577a66e79c51c491553552.tar.bz2 |
Support software single step on ARM in GDBServer
This patch teaches GDBServer how to software single step on ARM
linux by sharing code with GDB.
The arm_get_next_pcs function in GDB is now shared with GDBServer. So
that GDBServer can use the function to return the possible addresses of
the next PC.
A proper shared context was also needed so that we could share the code,
this context is described in the arm_get_next_pcs structure.
Testing :
No regressions, tested on ubuntu 14.04 ARMv7 and x86.
With gdbserver-{native,extended} / { -marm -mthumb }
gdb/ChangeLog:
* Makefile.in (ALL_TARGET_OBS): Append arm-get-next-pcs.o,
arm-linux.o.
(ALLDEPFILES): Append arm-get-next-pcs.c, arm-linux.c
(arm-linux.o): New rule.
(arm-get-next-pcs.o): New rule.
* arch/arm-get-next-pcs.c: New file.
* arch/arm-get-next-pcs.h: New file.
* arch/arm-linux.h: New file.
* arch/arm-linux.c: New file.
* arm.c: Include common-regcache.c.
(thumb_advance_itstate): Moved from arm-tdep.c.
(arm_instruction_changes_pc): Likewise.
(thumb_instruction_changes_pc): Likewise.
(thumb2_instruction_changes_pc): Likewise.
(shifted_reg_val): Likewise.
* arm.h (submask): Move macro from arm-tdep.h
(bit): Likewise.
(bits): Likewise.
(sbits): Likewise.
(BranchDest): Likewise.
(thumb_advance_itstate): Moved declaration from arm-tdep.h
(arm_instruction_changes_pc): Likewise.
(thumb_instruction_changes_pc): Likewise.
(thumb2_instruction_changes_pc): Likewise.
(shifted_reg_val): Likewise.
* arm-linux-tdep.c: Include arch/arm.h, arch/arm-get-next-pcs.h
arch/arm-linux.h.
(arm_linux_get_next_pcs_ops): New struct.
(ARM_SIGCONTEXT_R0, ARM_UCONTEXT_SIGCONTEXT,
ARM_OLD_RT_SIGFRAME_SIGINFO, ARM_OLD_RT_SIGFRAME_UCONTEXT,
ARM_NEW_RT_SIGFRAME_UCONTEXT, ARM_NEW_SIGFRAME_MAGIC): Move stack
layout defines to arch/arm-linux.h.
(arm_linux_sigreturn_next_pc_offset): Move to arch/arm-linux.c.
(arm_linux_software_single_step): Adjust for arm_get_next_pcs
implementation.
* arm-tdep.c: Include arch/arm-get-next-pcs.h.
(arm_get_next_pcs_ops): New struct.
(submask): Move macro to arm.h.
(bit): Likewise.
(bits): Likewise.
(sbits): Likewise.
(BranchDest): Likewise.
(thumb_instruction_changes_pc): Move to arm.c
(thumb2_instruction_changes_pc): Likewise.
(arm_instruction_changes_pc): Likewise.
(shifted_reg_val): Likewise.
(thumb_advance_itstate): Likewise.
(thumb_get_next_pc_raw): Move to arm-get-next-pcs.c.
(arm_get_next_pc_raw): Likewise.
(arm_get_next_pc): Likewise.
(thumb_deal_with_atomic_sequence_raw): Likewise.
(arm_deal_with_atomic_sequence_raw): Likewise.
(arm_deal_with_atomic_sequence): Likewise.
(arm_get_next_pcs_read_memory_unsigned_integer): New function.
(arm_get_next_pcs_addr_bits_remove): Likewise.
(arm_get_next_pcs_syscall_next_pc): Likewise.
(arm_get_next_pcs_is_thumb): Likewise.
(arm_software_single_step): Adjust for arm_get_next_pcs
implementation.
* arm-tdep.h: (arm_get_next_pc): Remove declaration.
(arm_get_next_pcs_read_memory_unsigned_integer):
New declaration.
(arm_get_next_pcs_addr_bits_remove): Likewise.
(arm_get_next_pcs_syscall_next_pc): Likewise.
(arm_get_next_pcs_is_thumb): Likewise.
(arm_deal_with_atomic_sequence: Remove declaration.
* common/gdb_vecs.h: Add CORE_ADDR vector definition.
* configure.tgt (aarch64*-*-linux): Add arm-get-next-pcs.o,
arm-linux.o.
(arm*-wince-pe): Add arm-get-next-pcs.o.
(arm*-*-linux*): Add arm-get-next-pcs.o, arm-linux.o,
arm-get-next-pcs.o
(arm*-*-netbsd*,arm*-*-knetbsd*-gnu): Add arm-get-next-pcs.o.
(arm*-*-openbsd*): Likewise.
(arm*-*-symbianelf*): Likewise.
(arm*-*-*): Likewise.
* symtab.h: Move CORE_ADDR vector definition to gdb_vecs.h.
gdb/gdbserver/ChangeLog:
* Makefile.in (SFILES): Append arch/arm-linux.c,
arch/arm-get-next-pcs.c.
(arm-linux.o): New rule.
(arm-get-next-pcs.o): New rule.
* configure.srv (arm*-*-linux*): Add arm-get-next-pcs.o,
arm-linux.o.
* linux-aarch32-low.c (arm_abi_breakpoint): Remove macro. Moved
to linux-aarch32-low.c.
(arm_eabi_breakpoint, arm_breakpoint): Likewise.
(arm_breakpoint_len, thumb_breakpoint): Likewise.
(thumb_breakpoint_len, thumb2_breakpoint): Likewise.
(thumb2_breakpoint_len): Likewise.
(arm_is_thumb_mode): Make non-static.
* linux-aarch32-low.h (arm_abi_breakpoint): New macro. Moved
from linux-aarch32-low.c.
(arm_eabi_breakpoint, arm_breakpoint): Likewise.
(arm_breakpoint_len, thumb_breakpoint): Likewise.
(thumb_breakpoint_len, thumb2_breakpoint): Likewise.
(thumb2_breakpoint_len): Likewise.
(arm_is_thumb_mode): New declaration.
* linux-arm-low.c: Include arch/arm-linux.h
aarch/arm-get-next-pcs.h, sys/syscall.h.
(get_next_pcs_ops): New struct.
(get_next_pcs_addr_bits_remove): New function.
(get_next_pcs_is_thumb): New function.
(get_next_pcs_read_memory_unsigned_integer): Likewise.
(arm_sigreturn_next_pc): Likewise.
(get_next_pcs_syscall_next_pc): Likewise.
(arm_gdbserver_get_next_pcs): Likewise.
(struct linux_target_ops) <arm_gdbserver_get_next_pcs>:
Initialize.
* linux-low.h: Move CORE_ADDR vector definition to gdb_vecs.h.
* server.h: Include gdb_vecs.h.
Diffstat (limited to 'gdb/gdbserver')
-rw-r--r-- | gdb/gdbserver/ChangeLog | 36 | ||||
-rw-r--r-- | gdb/gdbserver/Makefile.in | 9 | ||||
-rw-r--r-- | gdb/gdbserver/configure.srv | 2 | ||||
-rw-r--r-- | gdb/gdbserver/linux-aarch32-low.c | 23 | ||||
-rw-r--r-- | gdb/gdbserver/linux-aarch32-low.h | 23 | ||||
-rw-r--r-- | gdb/gdbserver/linux-arm-low.c | 146 | ||||
-rw-r--r-- | gdb/gdbserver/linux-low.h | 2 | ||||
-rw-r--r-- | gdb/gdbserver/server.h | 1 |
8 files changed, 216 insertions, 26 deletions
diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index eab6930..93a8fbe 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,5 +1,41 @@ 2015-12-18 Antoine Tremblay <antoine.tremblay@ericsson.com> + * Makefile.in (SFILES): Append arch/arm-linux.c, + arch/arm-get-next-pcs.c. + (arm-linux.o): New rule. + (arm-get-next-pcs.o): New rule. + * configure.srv (arm*-*-linux*): Add arm-get-next-pcs.o, + arm-linux.o. + * linux-aarch32-low.c (arm_abi_breakpoint): Remove macro. Moved + to linux-aarch32-low.c. + (arm_eabi_breakpoint, arm_breakpoint): Likewise. + (arm_breakpoint_len, thumb_breakpoint): Likewise. + (thumb_breakpoint_len, thumb2_breakpoint): Likewise. + (thumb2_breakpoint_len): Likewise. + (arm_is_thumb_mode): Make non-static. + * linux-aarch32-low.h (arm_abi_breakpoint): New macro. Moved + from linux-aarch32-low.c. + (arm_eabi_breakpoint, arm_breakpoint): Likewise. + (arm_breakpoint_len, thumb_breakpoint): Likewise. + (thumb_breakpoint_len, thumb2_breakpoint): Likewise. + (thumb2_breakpoint_len): Likewise. + (arm_is_thumb_mode): New declaration. + * linux-arm-low.c: Include arch/arm-linux.h + aarch/arm-get-next-pcs.h, sys/syscall.h. + (get_next_pcs_ops): New struct. + (get_next_pcs_addr_bits_remove): New function. + (get_next_pcs_is_thumb): New function. + (get_next_pcs_read_memory_unsigned_integer): Likewise. + (arm_sigreturn_next_pc): Likewise. + (get_next_pcs_syscall_next_pc): Likewise. + (arm_gdbserver_get_next_pcs): Likewise. + (struct linux_target_ops) <arm_gdbserver_get_next_pcs>: + Initialize. + * linux-low.h: Move CORE_ADDR vector definition to gdb_vecs.h. + * server.h: Include gdb_vecs.h. + +2015-12-18 Antoine Tremblay <antoine.tremblay@ericsson.com> + * Makefile.in (SFILES): Append common/common-regcache.c. (OBS): Append common-regcache.o. (common-regcache.o): New rule. diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in index 82af44c..c72db67 100644 --- a/gdb/gdbserver/Makefile.in +++ b/gdb/gdbserver/Makefile.in @@ -181,7 +181,8 @@ SFILES= $(srcdir)/gdbreplay.c $(srcdir)/inferiors.c $(srcdir)/dll.c \ $(srcdir)/common/common-exceptions.c $(srcdir)/symbol.c \ $(srcdir)/common/btrace-common.c \ $(srcdir)/common/fileio.c $(srcdir)/nat/linux-namespaces.c \ - $(srcdir)/arch/arm.c $(srcdir)/common/common-regcache.c + $(srcdir)/arch/arm.c $(srcdir)/common/common-regcache.c \ + $(srcdir)/arch/arm-linux.c $(srcdir)/arch/arm-get-next-pcs.c DEPFILES = @GDBSERVER_DEPFILES@ @@ -592,6 +593,12 @@ common-regcache.o: ../common/common-regcache.c arm.o: ../arch/arm.c $(COMPILE) $< $(POSTCOMPILE) +arm-linux.o: ../arch/arm-linux.c + $(COMPILE) $< + $(POSTCOMPILE) +arm-get-next-pcs.o: ../arch/arm-get-next-pcs.c + $(COMPILE) $< + $(POSTCOMPILE) # Native object files rules from ../nat diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv index 6dfd6e0..5f5112e 100644 --- a/gdb/gdbserver/configure.srv +++ b/gdb/gdbserver/configure.srv @@ -72,6 +72,8 @@ case "${target}" in srv_tgtobj="$srv_linux_obj linux-arm-low.o" srv_tgtobj="$srv_tgtobj linux-aarch32-low.o" srv_tgtobj="${srv_tgtobj} arm.o" + srv_tgtobj="${srv_tgtobj} arm-linux.o" + srv_tgtobj="${srv_tgtobj} arm-get-next-pcs.o" srv_xmlfiles="arm-with-iwmmxt.xml" srv_xmlfiles="${srv_xmlfiles} arm-with-vfpv2.xml" srv_xmlfiles="${srv_xmlfiles} arm-with-vfpv3.xml" diff --git a/gdb/gdbserver/linux-aarch32-low.c b/gdb/gdbserver/linux-aarch32-low.c index 930e73a..bbef721 100644 --- a/gdb/gdbserver/linux-aarch32-low.c +++ b/gdb/gdbserver/linux-aarch32-low.c @@ -137,30 +137,9 @@ struct regs_info regs_info_aarch32 = &aarch32_regsets_info }; -/* Correct in either endianness. */ -#define arm_abi_breakpoint 0xef9f0001UL - -/* For new EABI binaries. We recognize it regardless of which ABI - is used for gdbserver, so single threaded debugging should work - OK, but for multi-threaded debugging we only insert the current - ABI's breakpoint instruction. For now at least. */ -#define arm_eabi_breakpoint 0xe7f001f0UL - -#if (defined __ARM_EABI__ || defined __aarch64__) -static const unsigned long arm_breakpoint = arm_eabi_breakpoint; -#else -static const unsigned long arm_breakpoint = arm_abi_breakpoint; -#endif - -#define arm_breakpoint_len 4 -static const unsigned short thumb_breakpoint = 0xde01; -#define thumb_breakpoint_len 2 -static const unsigned short thumb2_breakpoint[] = { 0xf7f0, 0xa000 }; -#define thumb2_breakpoint_len 4 - /* Returns 1 if the current instruction set is thumb, 0 otherwise. */ -static int +int arm_is_thumb_mode (void) { struct regcache *regcache = get_thread_regcache (current_thread, 1); diff --git a/gdb/gdbserver/linux-aarch32-low.h b/gdb/gdbserver/linux-aarch32-low.h index 0afddc8..d452894 100644 --- a/gdb/gdbserver/linux-aarch32-low.h +++ b/gdb/gdbserver/linux-aarch32-low.h @@ -15,6 +15,27 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ +/* Correct in either endianness. */ +#define arm_abi_breakpoint 0xef9f0001UL + +/* For new EABI binaries. We recognize it regardless of which ABI + is used for gdbserver, so single threaded debugging should work + OK, but for multi-threaded debugging we only insert the current + ABI's breakpoint instruction. For now at least. */ +#define arm_eabi_breakpoint 0xe7f001f0UL + +#ifndef __ARM_EABI__ +static const unsigned long arm_breakpoint = arm_abi_breakpoint; +#else +static const unsigned long arm_breakpoint = arm_eabi_breakpoint; +#endif + +#define arm_breakpoint_len 4 +static const unsigned short thumb_breakpoint = 0xde01; +#define thumb_breakpoint_len 2 +static const unsigned short thumb2_breakpoint[] = { 0xf7f0, 0xa000 }; +#define thumb2_breakpoint_len 4 + extern struct regs_info regs_info_aarch32; void arm_fill_gregset (struct regcache *regcache, void *buf); @@ -31,4 +52,6 @@ int arm_breakpoint_at (CORE_ADDR where); void initialize_low_arch_aarch32 (void); void init_registers_arm_with_neon (void); +int arm_is_thumb_mode (void); + extern const struct target_desc *tdesc_arm_with_neon; diff --git a/gdb/gdbserver/linux-arm-low.c b/gdb/gdbserver/linux-arm-low.c index 2e8cd6d..af6df7f 100644 --- a/gdb/gdbserver/linux-arm-low.c +++ b/gdb/gdbserver/linux-arm-low.c @@ -19,6 +19,8 @@ #include "server.h" #include "linux-low.h" #include "arch/arm.h" +#include "arch/arm-linux.h" +#include "arch/arm-get-next-pcs.h" #include "linux-aarch32-low.h" #include <sys/uio.h> @@ -29,6 +31,7 @@ #endif #include "nat/gdb_ptrace.h" #include <signal.h> +#include <sys/syscall.h> /* Defined in auto-generated files. */ void init_registers_arm (void); @@ -136,6 +139,27 @@ static int arm_regmap[] = { 64 }; +/* Forward declarations needed for get_next_pcs ops. */ +static ULONGEST get_next_pcs_read_memory_unsigned_integer (CORE_ADDR memaddr, + int len, + int byte_order); + +static CORE_ADDR get_next_pcs_addr_bits_remove (struct arm_get_next_pcs *self, + CORE_ADDR val); + +static CORE_ADDR get_next_pcs_syscall_next_pc (struct arm_get_next_pcs *self, + CORE_ADDR pc); + +static int get_next_pcs_is_thumb (struct arm_get_next_pcs *self); + +/* get_next_pcs operations. */ +static struct arm_get_next_pcs_ops get_next_pcs_ops = { + get_next_pcs_read_memory_unsigned_integer, + get_next_pcs_syscall_next_pc, + get_next_pcs_addr_bits_remove, + get_next_pcs_is_thumb +}; + static int arm_cannot_store_register (int regno) { @@ -198,6 +222,13 @@ arm_fill_vfpregset (struct regcache *regcache, void *buf) arm_fill_vfpregset_num (regcache, buf, num); } +/* Wrapper of UNMAKE_THUMB_ADDR for get_next_pcs. */ +static CORE_ADDR +get_next_pcs_addr_bits_remove (struct arm_get_next_pcs *self, CORE_ADDR val) +{ + return UNMAKE_THUMB_ADDR (val); +} + static void arm_store_vfpregset (struct regcache *regcache, const void *buf) { @@ -233,6 +264,27 @@ arm_set_pc (struct regcache *regcache, CORE_ADDR pc) supply_register_by_name (regcache, "pc", &newpc); } +/* Wrapper of arm_is_thumb_mode for get_next_pcs. */ +static int +get_next_pcs_is_thumb (struct arm_get_next_pcs *self) +{ + return arm_is_thumb_mode (); +} + +/* Read memory from the inferiror. + BYTE_ORDER is ignored and there to keep compatiblity with GDB's + read_memory_unsigned_integer. */ +static ULONGEST +get_next_pcs_read_memory_unsigned_integer (CORE_ADDR memaddr, + int len, + int byte_order) +{ + ULONGEST res; + + (*the_target->read_memory) (memaddr, (unsigned char *) &res, len); + return res; +} + /* Fetch the thread-local storage pointer for libthread_db. */ ps_err_e @@ -717,6 +769,77 @@ arm_prepare_to_resume (struct lwp_info *lwp) } } +/* Find the next pc for a sigreturn or rt_sigreturn syscall. + See arm-linux.h for stack layout details. */ +static CORE_ADDR +arm_sigreturn_next_pc (struct regcache *regcache, int svc_number) +{ + unsigned long sp; + unsigned long sp_data; + /* Offset of PC register. */ + int pc_offset = 0; + CORE_ADDR next_pc = 0; + + gdb_assert (svc_number == __NR_sigreturn || svc_number == __NR_rt_sigreturn); + + collect_register_by_name (regcache, "sp", &sp); + (*the_target->read_memory) (sp, (unsigned char *) &sp_data, 4); + + pc_offset = arm_linux_sigreturn_next_pc_offset + (sp, sp_data, svc_number, __NR_sigreturn == svc_number ? 1 : 0); + + (*the_target->read_memory) (sp + pc_offset, (unsigned char *) &next_pc, 4); + + return next_pc; +} + +/* When PC is at a syscall instruction, return the PC of the next + instruction to be executed. */ +static CORE_ADDR +get_next_pcs_syscall_next_pc (struct arm_get_next_pcs *self, CORE_ADDR pc) +{ + CORE_ADDR next_pc = 0; + int is_thumb = arm_is_thumb_mode (); + ULONGEST svc_number = 0; + struct regcache *regcache = self->regcache; + + if (is_thumb) + { + collect_register (regcache, 7, &svc_number); + next_pc = pc + 2; + } + else + { + unsigned long this_instr; + unsigned long svc_operand; + + (*the_target->read_memory) (pc, (unsigned char *) &this_instr, 4); + svc_operand = (0x00ffffff & this_instr); + + if (svc_operand) /* OABI. */ + { + svc_number = svc_operand - 0x900000; + } + else /* EABI. */ + { + collect_register (regcache, 7, &svc_number); + } + + next_pc = pc + 4; + } + + /* This is a sigreturn or sigreturn_rt syscall. */ + if (svc_number == __NR_sigreturn || svc_number == __NR_rt_sigreturn) + { + next_pc = arm_sigreturn_next_pc (regcache, svc_number); + } + + /* Addresses for calling Thumb functions have the bit 0 set. */ + if (is_thumb) + next_pc = MAKE_THUMB_ADDR (next_pc); + + return next_pc; +} static int arm_get_hwcap (unsigned long *valp) @@ -806,6 +929,27 @@ arm_arch_setup (void) have_ptrace_getregset = 0; } +/* Fetch the next possible PCs after the current instruction executes. */ + +static VEC (CORE_ADDR) * +arm_gdbserver_get_next_pcs (CORE_ADDR pc, struct regcache *regcache) +{ + struct arm_get_next_pcs next_pcs_ctx; + VEC (CORE_ADDR) *next_pcs = NULL; + + arm_get_next_pcs_ctor (&next_pcs_ctx, + &get_next_pcs_ops, + /* Byte order is ignored assumed as host. */ + 0, + 0, + (const gdb_byte *) &thumb2_breakpoint, + regcache); + + next_pcs = arm_get_next_pcs (&next_pcs_ctx, pc); + + return next_pcs; +} + /* Support for hardware single step. */ static int @@ -871,7 +1015,7 @@ struct linux_target_ops the_low_target = { arm_set_pc, arm_breakpoint_kind_from_pc, arm_sw_breakpoint_from_kind, - NULL, /* get_next_pcs */ + arm_gdbserver_get_next_pcs, 0, arm_breakpoint_at, arm_supports_z_point_type, diff --git a/gdb/gdbserver/linux-low.h b/gdb/gdbserver/linux-low.h index cd455a8..8eaad3e 100644 --- a/gdb/gdbserver/linux-low.h +++ b/gdb/gdbserver/linux-low.h @@ -124,8 +124,6 @@ struct process_info_private struct lwp_info; -DEF_VEC_I (CORE_ADDR); - struct linux_target_ops { /* Architecture-specific setup. */ diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h index 18095f2..498367c 100644 --- a/gdb/gdbserver/server.h +++ b/gdb/gdbserver/server.h @@ -123,6 +123,7 @@ extern void discard_queued_stop_replies (ptid_t ptid); #include "utils.h" #include "debug.h" +#include "gdb_vecs.h" /* Maximum number of bytes to read/write at once. The value here is chosen to fill up a packet (the headers account for the 32). */ |