X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Faarch64-linux-nat.c;h=256725b517864a7f723455c2b4e0513285368944;hb=dfd4cc6311a8cf56cd6f4e0249fc243cface5a7f;hp=268f98d31fd08580e20af400c5479210af9fe79c;hpb=6eb044730a8991d0b43e89c7aa0f671bb577dfd0;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c index 268f98d31f..256725b517 100644 --- a/gdb/aarch64-linux-nat.c +++ b/gdb/aarch64-linux-nat.c @@ -54,10 +54,10 @@ static int get_thread_id (ptid_t ptid) { - int tid = TIDGET (ptid); + int tid = ptid_get_lwp (ptid); if (0 == tid) - tid = PIDGET (ptid); + tid = ptid_get_pid (ptid); return tid; } @@ -189,75 +189,103 @@ struct aarch64_debug_reg_state unsigned int dr_ref_count_wp[AARCH64_HWP_MAX_NUM]; }; -/* Clear the reference counts and forget everything we knew about the - debug registers. */ +/* Per-process data. We don't bind this to a per-inferior registry + because of targets like x86 GNU/Linux that need to keep track of + processes that aren't bound to any inferior (e.g., fork children, + checkpoints). */ -static void -aarch64_init_debug_reg_state (struct aarch64_debug_reg_state *state) +struct aarch64_process_info { - int i; + /* Linked list. */ + struct aarch64_process_info *next; - for (i = 0; i < AARCH64_HBP_MAX_NUM; ++i) - { - state->dr_addr_bp[i] = 0; - state->dr_ctrl_bp[i] = 0; - state->dr_ref_count_bp[i] = 0; - } + /* The process identifier. */ + pid_t pid; - for (i = 0; i < AARCH64_HWP_MAX_NUM; ++i) - { - state->dr_addr_wp[i] = 0; - state->dr_ctrl_wp[i] = 0; - state->dr_ref_count_wp[i] = 0; - } + /* Copy of aarch64 hardware debug registers. */ + struct aarch64_debug_reg_state state; +}; + +static struct aarch64_process_info *aarch64_process_list = NULL; + +/* Find process data for process PID. */ + +static struct aarch64_process_info * +aarch64_find_process_pid (pid_t pid) +{ + struct aarch64_process_info *proc; + + for (proc = aarch64_process_list; proc; proc = proc->next) + if (proc->pid == pid) + return proc; + + return NULL; } -/* Per-inferior data key. */ -static const struct inferior_data *aarch64_inferior_data; +/* Add process data for process PID. Returns newly allocated info + object. */ -/* Per-inferior data. */ -struct aarch64_inferior_data +static struct aarch64_process_info * +aarch64_add_process (pid_t pid) { - /* Copy of AArch64 hardware debug registers for performance reasons. */ - struct aarch64_debug_reg_state state; -}; + struct aarch64_process_info *proc; -/* Per-inferior hook for register_inferior_data_with_cleanup. */ + proc = xcalloc (1, sizeof (*proc)); + proc->pid = pid; -static void -aarch64_inferior_data_cleanup (struct inferior *inf, void *arg) + proc->next = aarch64_process_list; + aarch64_process_list = proc; + + return proc; +} + +/* Get data specific info for process PID, creating it if necessary. + Never returns NULL. */ + +static struct aarch64_process_info * +aarch64_process_info_get (pid_t pid) { - struct aarch64_inferior_data *inf_data = arg; + struct aarch64_process_info *proc; + + proc = aarch64_find_process_pid (pid); + if (proc == NULL) + proc = aarch64_add_process (pid); - xfree (inf_data); + return proc; } -/* Get data specific for INFERIOR_PTID LWP. Return special data area - for processes being detached. */ +/* Called whenever GDB is no longer debugging process PID. It deletes + data structures that keep track of debug register state. */ -static struct aarch64_inferior_data * -aarch64_inferior_data_get (void) +static void +aarch64_forget_process (pid_t pid) { - struct inferior *inf = current_inferior (); - struct aarch64_inferior_data *inf_data; + struct aarch64_process_info *proc, **proc_link; - inf_data = inferior_data (inf, aarch64_inferior_data); - if (inf_data == NULL) + proc = aarch64_process_list; + proc_link = &aarch64_process_list; + + while (proc != NULL) { - inf_data = xzalloc (sizeof (*inf_data)); - set_inferior_data (inf, aarch64_inferior_data, inf_data); - } + if (proc->pid == pid) + { + *proc_link = proc->next; - return inf_data; + xfree (proc); + return; + } + + proc_link = &proc->next; + proc = *proc_link; + } } -/* Get debug registers state for INFERIOR_PTID, see - aarch64_inferior_data_get. */ +/* Get debug registers state for process PID. */ static struct aarch64_debug_reg_state * -aarch64_get_debug_reg_state (void) +aarch64_get_debug_reg_state (pid_t pid) { - return &aarch64_inferior_data_get ()->state; + return &aarch64_process_info_get (pid)->state; } /* Per-thread arch-specific data we want to keep. */ @@ -284,6 +312,7 @@ aarch64_linux_set_debug_regs (const struct aarch64_debug_reg_state *state, const CORE_ADDR *addr; const unsigned int *ctrl; + memset (®s, 0, sizeof (regs)); iov.iov_base = ®s; iov.iov_len = sizeof (regs); count = watchpoint ? aarch64_num_wp_regs : aarch64_num_bp_regs; @@ -308,7 +337,7 @@ struct aarch64_dr_update_callback_param unsigned int idx; }; -/* Callback for linux_nat_iterate_watchpoint_lwps. Records the +/* Callback for iterate_over_lwps. Records the information about the change of one hardware breakpoint/watchpoint setting for the thread LWP. The information is passed in via PTR. @@ -335,9 +364,10 @@ debug_reg_change_callback (struct lwp_info *lwp, void *ptr) fprintf_unfiltered (gdb_stdlog, "debug_reg_change_callback: \n\tOn entry:\n"); fprintf_unfiltered (gdb_stdlog, - "\tpid%d, dr_changed_bp=0x%llx, " - "dr_changed_wp=0x%llx\n", - pid, info->dr_changed_bp, info->dr_changed_wp); + "\tpid%d, dr_changed_bp=0x%s, " + "dr_changed_wp=0x%s\n", + pid, phex (info->dr_changed_bp, 8), + phex (info->dr_changed_wp, 8)); } dr_changed_ptr = is_watchpoint ? &info->dr_changed_wp @@ -361,9 +391,10 @@ debug_reg_change_callback (struct lwp_info *lwp, void *ptr) if (debug_hw_points) { fprintf_unfiltered (gdb_stdlog, - "\tOn exit:\n\tpid%d, dr_changed_bp=0x%llx, " - "dr_changed_wp=0x%llx\n", - pid, info->dr_changed_bp, info->dr_changed_wp); + "\tOn exit:\n\tpid%d, dr_changed_bp=0x%s, " + "dr_changed_wp=0x%s\n", + pid, phex (info->dr_changed_bp, 8), + phex (info->dr_changed_wp, 8)); } /* Continue the iteration. */ @@ -380,12 +411,12 @@ aarch64_notify_debug_reg_change (const struct aarch64_debug_reg_state *state, int is_watchpoint, unsigned int idx) { struct aarch64_dr_update_callback_param param; + ptid_t pid_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid)); param.is_watchpoint = is_watchpoint; param.idx = idx; - linux_nat_iterate_watchpoint_lwps (debug_reg_change_callback, - (void *) ¶m); + iterate_over_lwps (pid_ptid, debug_reg_change_callback, (void *) ¶m); } /* Print the values of the cached breakpoint/watchpoint registers. */ @@ -652,8 +683,9 @@ aarch64_linux_prepare_to_resume (struct lwp_info *lwp) if (DR_HAS_CHANGED (info->dr_changed_bp) || DR_HAS_CHANGED (info->dr_changed_wp)) { - int tid = GET_LWP (lwp->ptid); - struct aarch64_debug_reg_state *state = aarch64_get_debug_reg_state (); + int tid = ptid_get_lwp (lwp->ptid); + struct aarch64_debug_reg_state *state + = aarch64_get_debug_reg_state (ptid_get_pid (lwp->ptid)); if (debug_hw_points) fprintf_unfiltered (gdb_stdlog, "prepare_to_resume thread %d\n", tid); @@ -686,6 +718,32 @@ aarch64_linux_new_thread (struct lwp_info *lp) lp->arch_private = info; } + +/* linux_nat_new_fork hook. */ + +static void +aarch64_linux_new_fork (struct lwp_info *parent, pid_t child_pid) +{ + pid_t parent_pid; + struct aarch64_debug_reg_state *parent_state; + struct aarch64_debug_reg_state *child_state; + + /* NULL means no watchpoint has ever been set in the parent. In + that case, there's nothing to do. */ + if (parent->arch_private == NULL) + return; + + /* GDB core assumes the child inherits the watchpoints/hw + breakpoints of the parent, and will remove them all from the + forked off process. Copy the debug registers mirrors into the + new process so that all breakpoints and watchpoints can be + removed together. */ + + parent_pid = ptid_get_pid (parent->ptid); + parent_state = aarch64_get_debug_reg_state (parent_pid); + child_state = aarch64_get_debug_reg_state (child_pid); + *child_state = *parent_state; +} /* Called by libthread_db. Returns a pointer to the thread local @@ -733,16 +791,16 @@ aarch64_linux_get_debug_reg_capacity (void) aarch64_num_wp_regs = AARCH64_DEBUG_NUM_SLOTS (dreg_state.dbg_info); if (aarch64_num_wp_regs > AARCH64_HWP_MAX_NUM) { - warning ("Unexpected number of hardware watchpoint registers reported" - " by ptrace, got %d, expected %d.", + warning (_("Unexpected number of hardware watchpoint registers" + " reported by ptrace, got %d, expected %d."), aarch64_num_wp_regs, AARCH64_HWP_MAX_NUM); aarch64_num_wp_regs = AARCH64_HWP_MAX_NUM; } } else { - warning ("Unable to determine the number of hardware watchpoints" - " available."); + warning (_("Unable to determine the number of hardware watchpoints" + " available.")); aarch64_num_wp_regs = 0; } @@ -753,16 +811,16 @@ aarch64_linux_get_debug_reg_capacity (void) aarch64_num_bp_regs = AARCH64_DEBUG_NUM_SLOTS (dreg_state.dbg_info); if (aarch64_num_bp_regs > AARCH64_HBP_MAX_NUM) { - warning ("Unexpected number of hardware breakpoint registers reported" - " by ptrace, got %d, expected %d.", + warning (_("Unexpected number of hardware breakpoint registers" + " reported by ptrace, got %d, expected %d."), aarch64_num_bp_regs, AARCH64_HBP_MAX_NUM); aarch64_num_bp_regs = AARCH64_HBP_MAX_NUM; } } else { - warning ("Unable to determine the number of hardware breakpoints" - " available."); + warning (_("Unable to determine the number of hardware breakpoints" + " available.")); aarch64_num_bp_regs = 0; } } @@ -774,9 +832,7 @@ static void (*super_post_startup_inferior) (ptid_t ptid); static void aarch64_linux_child_post_startup_inferior (ptid_t ptid) { - struct aarch64_debug_reg_state *state = aarch64_get_debug_reg_state (); - - aarch64_init_debug_reg_state (state); + aarch64_forget_process (ptid_get_pid (ptid)); aarch64_linux_get_debug_reg_capacity (); super_post_startup_inferior (ptid); } @@ -1130,7 +1186,7 @@ aarch64_handle_breakpoint (int type, CORE_ADDR addr, int len, int is_insert) if (!aarch64_point_is_aligned (0 /* is_watchpoint */ , addr, len)) return -1; - state = aarch64_get_debug_reg_state (); + state = aarch64_get_debug_reg_state (ptid_get_pid (inferior_ptid)); if (is_insert) return aarch64_dr_state_insert_one_point (state, type, addr, len); @@ -1159,8 +1215,13 @@ aarch64_linux_insert_hw_breakpoint (struct gdbarch *gdbarch, ret = aarch64_handle_breakpoint (type, addr, len, 1 /* is_insert */); if (debug_hw_points > 1) - aarch64_show_debug_reg_state (aarch64_get_debug_reg_state (), - "insert_hw_watchpoint", addr, len, type); + { + struct aarch64_debug_reg_state *state + = aarch64_get_debug_reg_state (ptid_get_pid (inferior_ptid)); + + aarch64_show_debug_reg_state (state, + "insert_hw_watchpoint", addr, len, type); + } return ret; } @@ -1185,8 +1246,13 @@ aarch64_linux_remove_hw_breakpoint (struct gdbarch *gdbarch, ret = aarch64_handle_breakpoint (type, addr, len, 0 /* is_insert */); if (debug_hw_points > 1) - aarch64_show_debug_reg_state (aarch64_get_debug_reg_state (), - "remove_hw_watchpoint", addr, len, type); + { + struct aarch64_debug_reg_state *state + = aarch64_get_debug_reg_state (ptid_get_pid (inferior_ptid)); + + aarch64_show_debug_reg_state (state, + "remove_hw_watchpoint", addr, len, type); + } return ret; } @@ -1198,7 +1264,8 @@ static int aarch64_handle_aligned_watchpoint (int type, CORE_ADDR addr, int len, int is_insert) { - struct aarch64_debug_reg_state *state = aarch64_get_debug_reg_state (); + struct aarch64_debug_reg_state *state + = aarch64_get_debug_reg_state (ptid_get_pid (inferior_ptid)); if (is_insert) return aarch64_dr_state_insert_one_point (state, type, addr, len); @@ -1217,7 +1284,8 @@ static int aarch64_handle_unaligned_watchpoint (int type, CORE_ADDR addr, int len, int is_insert) { - struct aarch64_debug_reg_state *state = aarch64_get_debug_reg_state (); + struct aarch64_debug_reg_state *state + = aarch64_get_debug_reg_state (ptid_get_pid (inferior_ptid)); while (len > 0) { @@ -1281,8 +1349,13 @@ aarch64_linux_insert_watchpoint (CORE_ADDR addr, int len, int type, ret = aarch64_handle_watchpoint (type, addr, len, 1 /* is_insert */); if (debug_hw_points > 1) - aarch64_show_debug_reg_state (aarch64_get_debug_reg_state (), - "insert_watchpoint", addr, len, type); + { + struct aarch64_debug_reg_state *state + = aarch64_get_debug_reg_state (ptid_get_pid (inferior_ptid)); + + aarch64_show_debug_reg_state (state, + "insert_watchpoint", addr, len, type); + } return ret; } @@ -1308,8 +1381,13 @@ aarch64_linux_remove_watchpoint (CORE_ADDR addr, int len, int type, ret = aarch64_handle_watchpoint (type, addr, len, 0 /* is_insert */); if (debug_hw_points > 1) - aarch64_show_debug_reg_state (aarch64_get_debug_reg_state (), - "remove_watchpoint", addr, len, type); + { + struct aarch64_debug_reg_state *state + = aarch64_get_debug_reg_state (ptid_get_pid (inferior_ptid)); + + aarch64_show_debug_reg_state (state, + "remove_watchpoint", addr, len, type); + } return ret; } @@ -1372,7 +1450,7 @@ aarch64_linux_stopped_data_address (struct target_ops *target, return 0; /* Check if the address matches any watched address. */ - state = aarch64_get_debug_reg_state (); + state = aarch64_get_debug_reg_state (ptid_get_pid (inferior_ptid)); for (i = aarch64_num_wp_regs - 1; i >= 0; --i) { const unsigned int len = aarch64_watchpoint_length (state->dr_ctrl_wp[i]); @@ -1463,10 +1541,6 @@ _initialize_aarch64_linux_nat (void) t->to_stopped_data_address = aarch64_linux_stopped_data_address; t->to_watchpoint_addr_within_range = aarch64_linux_watchpoint_addr_within_range; - if (aarch64_inferior_data == NULL) - aarch64_inferior_data - = register_inferior_data_with_cleanup (NULL, - aarch64_inferior_data_cleanup); /* Override the GNU/Linux inferior startup hook. */ super_post_startup_inferior = t->to_post_startup_inferior; @@ -1475,5 +1549,7 @@ _initialize_aarch64_linux_nat (void) /* Register the target. */ linux_nat_add_target (t); linux_nat_set_new_thread (t, aarch64_linux_new_thread); + linux_nat_set_new_fork (t, aarch64_linux_new_fork); + linux_nat_set_forget_process (t, aarch64_forget_process); linux_nat_set_prepare_to_resume (t, aarch64_linux_prepare_to_resume); }