diff options
Diffstat (limited to 'gdb/gdbserver/linux-arm-low.c')
-rw-r--r-- | gdb/gdbserver/linux-arm-low.c | 66 |
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 ®s_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, |