aboutsummaryrefslogtreecommitdiff
path: root/gdb/gdbserver/linux-arm-low.c
diff options
context:
space:
mode:
authorAntoine Tremblay <antoine.tremblay@ericsson.com>2015-10-21 11:13:41 -0400
committerAntoine Tremblay <antoine.tremblay@ericsson.com>2015-10-21 11:26:05 -0400
commit8689682cc375f6f30d65f1583b3aaa3e6a1e4d63 (patch)
tree88cd40b3931a44fb9e46e76431a80bbd432a0035 /gdb/gdbserver/linux-arm-low.c
parent2716529498941971b698f603e9aa0edc89905cb8 (diff)
downloadfsf-binutils-gdb-8689682cc375f6f30d65f1583b3aaa3e6a1e4d63.zip
fsf-binutils-gdb-8689682cc375f6f30d65f1583b3aaa3e6a1e4d63.tar.gz
fsf-binutils-gdb-8689682cc375f6f30d65f1583b3aaa3e6a1e4d63.tar.bz2
Implement breakpoint_kind_from_pc and sw_breakpoint_from_kind for ARM in GDBServer.
ARM can have multiple breakpoint types based on the instruction set it's currently in: arm, thumb or thumb2. GDBServer needs to know what breakpoint is to be inserted at location when inserting a breakpoint. This is handled by the breakpoint_kind_from_pc and sw_breakpoint_from_kind target ops introduced in a previous patch, this patch adds the arm_breakpoint_kind_from_pc and arm_sw_breakpoint_from_kind implementation so that the proper breakpoint type is returned based on the pc. Also in order to share some code with GDB a new file called arm.c have been introduced in arch/. While this file does not contain much yet future patches will add more to it thus the inclusion at this stage. No regressions on Ubuntu 14.04 on ARMv7 and x86. With gdbserver-{native,extended} / { -marm -mthumb } gdb/ChangeLog: * Makefile.in: Add arm.c/o. * arch/arm.c: New file. * arch/arm.h: (IS_THUMB_ADDR): Move macro from arm-tdep.c. (MAKE_THUMB_ADDR): Likewise. (UNMAKE_THUMB_ADDR): Likewise. * arm-tdep.c (int thumb_insn_size): Move to arm.c. (IS_THUMB_ADDR): Move to arm.h. (MAKE_THUMB_ADDR): Likewise. (UNMAKE_THUMB_ADDR): Likewise. * configure.tgt: Add arm.o to all ARM configs. gdb/gdbserver/ChangeLog: * Makefile.in: Add arm.c/o. * configure.srv: Likewise. * linux-arm-low.c (arm_breakpoint_kinds): New enum. (arm_breakpoint_kind_from_pc): New function. (arm_sw_breakpoint_from_kind): Return proper kind. (struct linux_target_ops) <breakpoint_kind_from_pc>: Initialize.
Diffstat (limited to 'gdb/gdbserver/linux-arm-low.c')
-rw-r--r--gdb/gdbserver/linux-arm-low.c66
1 files changed, 62 insertions, 4 deletions
diff --git a/gdb/gdbserver/linux-arm-low.c b/gdb/gdbserver/linux-arm-low.c
index 3a56620..d5af8c8 100644
--- a/gdb/gdbserver/linux-arm-low.c
+++ b/gdb/gdbserver/linux-arm-low.c
@@ -30,6 +30,8 @@
#include "nat/gdb_ptrace.h"
#include <signal.h>
+#include "arch/arm.h"
+
/* Defined in auto-generated files. */
void init_registers_arm (void);
extern const struct target_desc *tdesc_arm;
@@ -80,6 +82,14 @@ typedef enum
arm_hwbp_access = 3
} arm_hwbp_type;
+/* Enum describing the different kinds of breakpoints. */
+enum arm_breakpoint_kinds
+{
+ ARM_BP_KIND_THUMB = 2,
+ ARM_BP_KIND_THUMB2 = 3,
+ ARM_BP_KIND_ARM = 4,
+};
+
/* Type describing an ARM Hardware Breakpoint Control register value. */
typedef unsigned int arm_hwbp_control_t;
@@ -237,7 +247,9 @@ arm_set_pc (struct regcache *regcache, CORE_ADDR pc)
static const unsigned long arm_breakpoint = 0xef9f0001;
#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
/* For new EABI binaries. We recognize it regardless of which ABI
is used for gdbserver, so single threaded debugging should work
@@ -913,7 +925,39 @@ arm_regs_info (void)
return &regs_info_arm;
}
-/* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */
+/* Implementation of linux_target_ops method "breakpoint_kind_from_pc".
+
+ Determine the type and size of breakpoint to insert at PCPTR. Uses the
+ program counter value to determine whether a 16-bit or 32-bit breakpoint
+ should be used. It returns the breakpoint's kind, and adjusts the program
+ counter (if necessary) to point to the actual memory location where the
+ breakpoint should be inserted. */
+
+static int
+arm_breakpoint_kind_from_pc (CORE_ADDR *pcptr)
+{
+ if (IS_THUMB_ADDR (*pcptr))
+ {
+ gdb_byte buf[2];
+
+ *pcptr = UNMAKE_THUMB_ADDR (*pcptr);
+
+ /* Check whether we are replacing a thumb2 32-bit instruction. */
+ if ((*the_target->read_memory) (*pcptr, buf, 2) == 0)
+ {
+ unsigned short inst1 = 0;
+
+ (*the_target->read_memory) (*pcptr, (gdb_byte *) &inst1, 2);
+ if (thumb_insn_size (inst1) == 4)
+ return ARM_BP_KIND_THUMB2;
+ }
+ return ARM_BP_KIND_THUMB;
+ }
+ else
+ return ARM_BP_KIND_ARM;
+}
+
+/* Implementation of the linux_target_ops method "sw_breakpoint_from_kind". */
static const gdb_byte *
arm_sw_breakpoint_from_kind (int kind , int *size)
@@ -924,11 +968,25 @@ arm_sw_breakpoint_from_kind (int kind , int *size)
clone events, we will never insert a breakpoint, so even a Thumb
C library will work; so will mixing EABI/non-EABI gdbserver and
application. */
+ switch (kind)
+ {
+ case ARM_BP_KIND_THUMB:
+ *size = thumb_breakpoint_len;
+ return (gdb_byte *) &thumb_breakpoint;
+ case ARM_BP_KIND_THUMB2:
+ *size = thumb2_breakpoint_len;
+ return (gdb_byte *) &thumb2_breakpoint;
+ case ARM_BP_KIND_ARM:
+ *size = arm_breakpoint_len;
#ifndef __ARM_EABI__
- return (const gdb_byte *) &arm_breakpoint;
+ return (const gdb_byte *) &arm_breakpoint;
#else
- return (const gdb_byte *) &arm_eabi_breakpoint;
+ return (const gdb_byte *) &arm_eabi_breakpoint;
#endif
+ default:
+ return NULL;
+ }
+ return NULL;
}
struct linux_target_ops the_low_target = {
@@ -939,7 +997,7 @@ struct linux_target_ops the_low_target = {
NULL, /* fetch_register */
arm_get_pc,
arm_set_pc,
- NULL, /* breakpoint_kind_from_pc */
+ arm_breakpoint_kind_from_pc,
arm_sw_breakpoint_from_kind,
arm_reinsert_addr,
0,