#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;
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;
}
/* Correct in either endianness. */
-static const unsigned long arm_breakpoint = 0xef9f0001;
-#define arm_breakpoint_len 4
-static const unsigned short thumb_breakpoint = 0xde01;
-static const unsigned short thumb2_breakpoint[] = { 0xf7f0, 0xa000 };
+#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. */
-static const unsigned long arm_eabi_breakpoint = 0xe7f001f0;
+#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
static int
arm_breakpoint_at (CORE_ADDR where)
unsigned long insn;
(*the_target->read_memory) (where, (unsigned char *) &insn, 4);
- if (insn == arm_breakpoint)
+ if (insn == arm_abi_breakpoint)
return 1;
if (insn == arm_eabi_breakpoint)
/* Convert a raw breakpoint type to an enum arm_hwbp_type. */
-static int
+static arm_hwbp_type
raw_bkpt_type_to_arm_hwbp_type (enum raw_bkpt_type raw_type)
{
switch (raw_type)
{
switch (z_type)
{
+ case Z_PACKET_SW_BP:
case Z_PACKET_HW_BP:
case Z_PACKET_WRITE_WP:
case Z_PACKET_READ_WP:
static void
arm_new_fork (struct process_info *parent, struct process_info *child)
{
- struct arch_process_info *parent_proc_info = parent->priv->arch_private;
- struct arch_process_info *child_proc_info = child->priv->arch_private;
+ struct arch_process_info *parent_proc_info;
+ struct arch_process_info *child_proc_info;
struct lwp_info *child_lwp;
struct arch_lwp_info *child_lwp_info;
int i;
gdb_assert (child->priv != NULL
&& child->priv->arch_private != NULL);
+ parent_proc_info = parent->priv->arch_private;
+ child_proc_info = child->priv->arch_private;
+
/* Linux kernel before 2.6.33 commit
72f674d203cd230426437cdcf7dd6f681dad8b0d
will inherit hardware debug registers from parent
static int
arm_get_hwcap (unsigned long *valp)
{
- unsigned char *data = alloca (8);
+ unsigned char *data = (unsigned char *) alloca (8);
int offset = 0;
while ((*the_target->read_auxv) (offset, data, 8) == 8)
/* Now make sure that the kernel supports reading these
registers. Support was added in 2.6.30. */
errno = 0;
- buf = xmalloc (32 * 8 + 4);
+ buf = (char *) xmalloc (32 * 8 + 4);
if (ptrace (PTRACE_GETVFPREGS, pid, 0, buf) < 0
&& errno == EIO)
result = tdesc_arm;
{ PTRACE_GETVFPREGS, PTRACE_SETVFPREGS, 0, 32 * 8 + 4,
EXTENDED_REGS,
arm_fill_vfpregset, arm_store_vfpregset },
- { 0, 0, 0, -1, -1, NULL, NULL }
+ NULL_REGSET
};
static struct regsets_info arm_regsets_info =
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)
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. */
-#ifndef __ARM_EABI__
- return (const gdb_byte *) &arm_breakpoint;
-#else
- return (const gdb_byte *) &arm_eabi_breakpoint;
-#endif
+ 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;
+ return (const gdb_byte *) &arm_breakpoint;
+ default:
+ return NULL;
+ }
+ return NULL;
}
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,