X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fgdbserver%2Flinux-arm-low.c;h=2cd16682574c6338291e1238727ea821b287bfb0;hb=fe978cb071b460b2d4aed2f9a71d895f84efce0e;hp=547292ecd6436bb405589fdbdafdd5ba87df141e;hpb=71487fd776633dfd3489089e1fb2342044cd813f;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/gdbserver/linux-arm-low.c b/gdb/gdbserver/linux-arm-low.c index 547292ecd6..2cd1668257 100644 --- a/gdb/gdbserver/linux-arm-low.c +++ b/gdb/gdbserver/linux-arm-low.c @@ -1,6 +1,5 @@ /* GNU/Linux/ARM specific low level interface, for the remote server for GDB. - Copyright (C) 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, - 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. + Copyright (C) 1995-2015 Free Software Foundation, Inc. This file is part of GDB. @@ -30,10 +29,19 @@ /* Defined in auto-generated files. */ void init_registers_arm (void); +extern const struct target_desc *tdesc_arm; + void init_registers_arm_with_iwmmxt (void); +extern const struct target_desc *tdesc_arm_with_iwmmxt; + void init_registers_arm_with_vfpv2 (void); +extern const struct target_desc *tdesc_arm_with_vfpv2; + void init_registers_arm_with_vfpv3 (void); +extern const struct target_desc *tdesc_arm_with_vfpv3; + void init_registers_arm_with_neon (void); +extern const struct target_desc *tdesc_arm_with_neon; #ifndef PTRACE_GET_THREAD_AREA #define PTRACE_GET_THREAD_AREA 22 @@ -213,7 +221,7 @@ arm_fill_vfpregset (struct regcache *regcache, void *buf) else num = 16; - base = find_regno ("d0"); + base = find_regno (regcache->tdesc, "d0"); for (i = 0; i < num; i++) collect_register (regcache, base + i, (char *) buf + i * 8); @@ -233,7 +241,7 @@ arm_store_vfpregset (struct regcache *regcache, const void *buf) else num = 16; - base = find_regno ("d0"); + base = find_regno (regcache->tdesc, "d0"); for (i = 0; i < num; i++) supply_register (regcache, base + i, (char *) buf + i * 8); @@ -248,7 +256,7 @@ arm_get_pc (struct regcache *regcache) unsigned long pc; collect_register_by_name (regcache, "pc", &pc); if (debug_threads) - fprintf (stderr, "stop pc is %08lx\n", pc); + debug_printf ("stop pc is %08lx\n", pc); return pc; } @@ -274,7 +282,7 @@ static const unsigned long arm_eabi_breakpoint = 0xe7f001f0; static int arm_breakpoint_at (CORE_ADDR where) { - struct regcache *regcache = get_thread_regcache (current_inferior, 1); + struct regcache *regcache = get_thread_regcache (current_thread, 1); unsigned long cpsr; collect_register_by_name (regcache, "cpsr", &cpsr); @@ -317,7 +325,7 @@ arm_breakpoint_at (CORE_ADDR where) static CORE_ADDR arm_reinsert_addr (void) { - struct regcache *regcache = get_thread_regcache (current_inferior, 1); + struct regcache *regcache = get_thread_regcache (current_thread, 1); unsigned long pc; collect_register_by_name (regcache, "lr", &pc); return pc; @@ -431,42 +439,39 @@ arm_linux_hw_breakpoint_equal (const struct arm_linux_hw_breakpoint *p1, return p1->address == p2->address && p1->control == p2->control; } +/* Convert a raw breakpoint type to an enum arm_hwbp_type. */ + +static int +raw_bkpt_type_to_arm_hwbp_type (enum raw_bkpt_type raw_type) +{ + switch (raw_type) + { + case raw_bkpt_type_hw: + return arm_hwbp_break; + case raw_bkpt_type_write_wp: + return arm_hwbp_store; + case raw_bkpt_type_read_wp: + return arm_hwbp_load; + case raw_bkpt_type_access_wp: + return arm_hwbp_access; + default: + gdb_assert_not_reached ("unhandled raw type"); + } +} + /* Initialize the hardware breakpoint structure P for a breakpoint or watchpoint at ADDR to LEN. The type of watchpoint is given in TYPE. - Returns -1 if TYPE is unsupported, 0 if TYPE represents a breakpoint, - and 1 if type represents a watchpoint. */ + Returns -1 if TYPE is unsupported, or -2 if the particular combination + of ADDR and LEN cannot be implemented. Otherwise, returns 0 if TYPE + represents a breakpoint and 1 if type represents a watchpoint. */ static int -arm_linux_hw_point_initialize (char type, CORE_ADDR addr, int len, - struct arm_linux_hw_breakpoint *p) +arm_linux_hw_point_initialize (enum raw_bkpt_type raw_type, CORE_ADDR addr, + int len, struct arm_linux_hw_breakpoint *p) { arm_hwbp_type hwbp_type; unsigned mask; - /* Breakpoint/watchpoint types (GDB terminology): - 0 = memory breakpoint for instructions - (not supported; done via memory write instead) - 1 = hardware breakpoint for instructions (supported) - 2 = write watchpoint (supported) - 3 = read watchpoint (supported) - 4 = access watchpoint (supported). */ - switch (type) - { - case '1': - hwbp_type = arm_hwbp_break; - break; - case '2': - hwbp_type = arm_hwbp_store; - break; - case '3': - hwbp_type = arm_hwbp_load; - break; - case '4': - hwbp_type = arm_hwbp_access; - break; - default: - /* Unsupported. */ - return -1; - } + hwbp_type = raw_bkpt_type_to_arm_hwbp_type (raw_type); if (hwbp_type == arm_hwbp_break) { @@ -475,17 +480,17 @@ arm_linux_hw_point_initialize (char type, CORE_ADDR addr, int len, { case 2: /* 16-bit Thumb mode breakpoint */ case 3: /* 32-bit Thumb mode breakpoint */ - mask = 0x3 << (addr & 2); + mask = 0x3; + addr &= ~1; break; case 4: /* 32-bit ARM mode breakpoint */ mask = 0xf; + addr &= ~3; break; default: /* Unsupported. */ - return -1; + return -2; } - - addr &= ~3; } else { @@ -494,17 +499,17 @@ arm_linux_hw_point_initialize (char type, CORE_ADDR addr, int len, /* Can not set watchpoints for zero or negative lengths. */ if (len <= 0) - return -1; + return -2; /* The current ptrace interface can only handle watchpoints that are a power of 2. */ if ((len & (len - 1)) != 0) - return -1; + return -2; /* Test that the range [ADDR, ADDR + LEN) fits into the largest address range covered by a watchpoint. */ aligned_addr = addr & ~(max_wp_length - 1); if (aligned_addr + max_wp_length < addr + len) - return -1; + return -2; mask = (1 << len) - 1; } @@ -527,11 +532,12 @@ struct update_registers_data static int update_registers_callback (struct inferior_list_entry *entry, void *arg) { - struct lwp_info *lwp = (struct lwp_info *) entry; + struct thread_info *thread = (struct thread_info *) entry; + struct lwp_info *lwp = get_thread_lwp (thread); struct update_registers_data *data = (struct update_registers_data *) arg; /* Only update the threads of the current process. */ - if (pid_of (lwp) == pid_of (get_thread_lwp (current_inferior))) + if (pid_of (thread) == pid_of (current_thread)) { /* The actual update is done later just before resuming the lwp, we just mark that the registers need updating. */ @@ -549,9 +555,26 @@ update_registers_callback (struct inferior_list_entry *entry, void *arg) return 0; } +static int +arm_supports_z_point_type (char z_type) +{ + switch (z_type) + { + case Z_PACKET_HW_BP: + case Z_PACKET_WRITE_WP: + case Z_PACKET_READ_WP: + case Z_PACKET_ACCESS_WP: + return 1; + default: + /* Leave the handling of sw breakpoints with the gdb client. */ + return 0; + } +} + /* Insert hardware break-/watchpoint. */ static int -arm_insert_point (char type, CORE_ADDR addr, int len) +arm_insert_point (enum raw_bkpt_type type, CORE_ADDR addr, + int len, struct raw_breakpoint *bp) { struct process_info *proc = current_process (); struct arm_linux_hw_breakpoint p, *pts; @@ -561,18 +584,18 @@ arm_insert_point (char type, CORE_ADDR addr, int len) if (watch < 0) { /* Unsupported. */ - return 1; + return watch == -1 ? 1 : -1; } if (watch) { count = arm_linux_get_hw_watchpoint_count (); - pts = proc->private->arch_private->wpts; + pts = proc->priv->arch_private->wpts; } else { count = arm_linux_get_hw_breakpoint_count (); - pts = proc->private->arch_private->bpts; + pts = proc->priv->arch_private->bpts; } for (i = 0; i < count; i++) @@ -580,7 +603,7 @@ arm_insert_point (char type, CORE_ADDR addr, int len) { struct update_registers_data data = { watch, i }; pts[i] = p; - find_inferior (&all_lwps, update_registers_callback, &data); + find_inferior (&all_threads, update_registers_callback, &data); return 0; } @@ -590,7 +613,8 @@ arm_insert_point (char type, CORE_ADDR addr, int len) /* Remove hardware break-/watchpoint. */ static int -arm_remove_point (char type, CORE_ADDR addr, int len) +arm_remove_point (enum raw_bkpt_type type, CORE_ADDR addr, + int len, struct raw_breakpoint *bp) { struct process_info *proc = current_process (); struct arm_linux_hw_breakpoint p, *pts; @@ -606,12 +630,12 @@ arm_remove_point (char type, CORE_ADDR addr, int len) if (watch) { count = arm_linux_get_hw_watchpoint_count (); - pts = proc->private->arch_private->wpts; + pts = proc->priv->arch_private->wpts; } else { count = arm_linux_get_hw_breakpoint_count (); - pts = proc->private->arch_private->bpts; + pts = proc->priv->arch_private->bpts; } for (i = 0; i < count; i++) @@ -619,7 +643,7 @@ arm_remove_point (char type, CORE_ADDR addr, int len) { struct update_registers_data data = { watch, i }; pts[i].control = arm_hwbp_control_disable (pts[i].control); - find_inferior (&all_lwps, update_registers_callback, &data); + find_inferior (&all_threads, update_registers_callback, &data); return 0; } @@ -631,8 +655,8 @@ arm_remove_point (char type, CORE_ADDR addr, int len) static int arm_stopped_by_watchpoint (void) { - struct lwp_info *lwp = get_thread_lwp (current_inferior); - struct siginfo siginfo; + struct lwp_info *lwp = get_thread_lwp (current_thread); + siginfo_t siginfo; /* We must be able to set hardware watchpoints. */ if (arm_linux_get_hw_watchpoint_count () == 0) @@ -640,7 +664,7 @@ arm_stopped_by_watchpoint (void) /* Retrieve siginfo. */ errno = 0; - ptrace (PTRACE_GETSIGINFO, lwpid_of (lwp), 0, &siginfo); + ptrace (PTRACE_GETSIGINFO, lwpid_of (current_thread), 0, &siginfo); if (errno != 0) return 0; @@ -666,7 +690,7 @@ arm_stopped_by_watchpoint (void) static CORE_ADDR arm_stopped_data_address (void) { - struct lwp_info *lwp = get_thread_lwp (current_inferior); + struct lwp_info *lwp = get_thread_lwp (current_thread); return lwp->arch_private->stopped_data_address; } @@ -698,9 +722,10 @@ arm_new_thread (void) static void arm_prepare_to_resume (struct lwp_info *lwp) { - int pid = lwpid_of (lwp); - struct process_info *proc = find_process_pid (pid_of (lwp)); - struct arch_process_info *proc_info = proc->private->arch_private; + struct thread_info *thread = get_lwp_thread (lwp); + int pid = lwpid_of (thread); + struct process_info *proc = find_process_pid (pid_of (thread)); + struct arch_process_info *proc_info = proc->priv->arch_private; struct arch_lwp_info *lwp_info = lwp->arch_private; int i; @@ -710,13 +735,15 @@ arm_prepare_to_resume (struct lwp_info *lwp) errno = 0; if (arm_hwbp_control_is_enabled (proc_info->bpts[i].control)) - if (ptrace (PTRACE_SETHBPREGS, pid, ((i << 1) + 1), - &proc_info->bpts[i].address) < 0) + if (ptrace (PTRACE_SETHBPREGS, pid, + (PTRACE_TYPE_ARG3) ((i << 1) + 1), + &proc_info->bpts[i].address) < 0) perror_with_name ("Unexpected error setting breakpoint address"); if (arm_hwbp_control_is_initialized (proc_info->bpts[i].control)) - if (ptrace (PTRACE_SETHBPREGS, pid, ((i << 1) + 2), - &proc_info->bpts[i].control) < 0) + if (ptrace (PTRACE_SETHBPREGS, pid, + (PTRACE_TYPE_ARG3) ((i << 1) + 2), + &proc_info->bpts[i].control) < 0) perror_with_name ("Unexpected error setting breakpoint"); lwp_info->bpts_changed[i] = 0; @@ -728,13 +755,15 @@ arm_prepare_to_resume (struct lwp_info *lwp) errno = 0; if (arm_hwbp_control_is_enabled (proc_info->wpts[i].control)) - if (ptrace (PTRACE_SETHBPREGS, pid, -((i << 1) + 1), - &proc_info->wpts[i].address) < 0) + if (ptrace (PTRACE_SETHBPREGS, pid, + (PTRACE_TYPE_ARG3) -((i << 1) + 1), + &proc_info->wpts[i].address) < 0) perror_with_name ("Unexpected error setting watchpoint address"); if (arm_hwbp_control_is_initialized (proc_info->wpts[i].control)) - if (ptrace (PTRACE_SETHBPREGS, pid, -((i << 1) + 2), - &proc_info->wpts[i].control) < 0) + if (ptrace (PTRACE_SETHBPREGS, pid, + (PTRACE_TYPE_ARG3) -((i << 1) + 2), + &proc_info->wpts[i].control) < 0) perror_with_name ("Unexpected error setting watchpoint"); lwp_info->wpts_changed[i] = 0; @@ -764,39 +793,34 @@ arm_get_hwcap (unsigned long *valp) return 0; } -static void -arm_arch_setup (void) +static const struct target_desc * +arm_read_description (void) { - int pid = lwpid_of (get_thread_lwp (current_inferior)); + int pid = lwpid_of (current_thread); /* Query hardware watchpoint/breakpoint capabilities. */ arm_linux_init_hwbp_cap (pid); arm_hwcap = 0; if (arm_get_hwcap (&arm_hwcap) == 0) - { - init_registers_arm (); - return; - } + return tdesc_arm; if (arm_hwcap & HWCAP_IWMMXT) - { - init_registers_arm_with_iwmmxt (); - return; - } + return tdesc_arm_with_iwmmxt; if (arm_hwcap & HWCAP_VFP) { + const struct target_desc *result; char *buf; /* NEON implies either no VFP, or VFPv3-D32. We only support it with VFP. */ if (arm_hwcap & HWCAP_NEON) - init_registers_arm_with_neon (); + result = tdesc_arm_with_neon; else if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPv3D16)) == HWCAP_VFPv3) - init_registers_arm_with_vfpv3 (); + result = tdesc_arm_with_vfpv3; else - init_registers_arm_with_vfpv2 (); + result = tdesc_arm_with_vfpv2; /* Now make sure that the kernel supports reading these registers. Support was added in 2.6.30. */ @@ -806,19 +830,25 @@ arm_arch_setup (void) && errno == EIO) { arm_hwcap = 0; - init_registers_arm (); + result = tdesc_arm; } free (buf); - return; + return result; } /* The default configuration uses legacy FPA registers, probably simulated. */ - init_registers_arm (); + return tdesc_arm; } -struct regset_info target_regsets[] = { +static void +arm_arch_setup (void) +{ + current_process ()->tdesc = arm_read_description (); +} + +static struct regset_info arm_regsets[] = { { PTRACE_GETREGS, PTRACE_SETREGS, 0, 18 * 4, GENERAL_REGS, arm_fill_gregset, arm_store_gregset }, @@ -831,12 +861,38 @@ struct regset_info target_regsets[] = { { 0, 0, 0, -1, -1, NULL, NULL } }; +static struct regsets_info arm_regsets_info = + { + arm_regsets, /* regsets */ + 0, /* num_regsets */ + NULL, /* disabled_regsets */ + }; + +static struct usrregs_info arm_usrregs_info = + { + arm_num_regs, + arm_regmap, + }; + +static struct regs_info regs_info = + { + NULL, /* regset_bitmap */ + &arm_usrregs_info, + &arm_regsets_info + }; + +static const struct regs_info * +arm_regs_info (void) +{ + return ®s_info; +} + struct linux_target_ops the_low_target = { arm_arch_setup, - arm_num_regs, - arm_regmap, + arm_regs_info, arm_cannot_fetch_register, arm_cannot_store_register, + NULL, /* fetch_register */ arm_get_pc, arm_set_pc, @@ -854,6 +910,7 @@ struct linux_target_ops the_low_target = { arm_reinsert_addr, 0, arm_breakpoint_at, + arm_supports_z_point_type, arm_insert_point, arm_remove_point, arm_stopped_by_watchpoint, @@ -865,3 +922,16 @@ struct linux_target_ops the_low_target = { arm_new_thread, arm_prepare_to_resume, }; + +void +initialize_low_arch (void) +{ + /* Initialize the Linux target descriptions. */ + init_registers_arm (); + init_registers_arm_with_iwmmxt (); + init_registers_arm_with_vfpv2 (); + init_registers_arm_with_vfpv3 (); + init_registers_arm_with_neon (); + + initialize_regsets_info (&arm_regsets_info); +}