diff options
-rw-r--r-- | gdb/ChangeLog | 73 | ||||
-rw-r--r-- | gdb/amd64-linux-nat.c | 52 | ||||
-rw-r--r-- | gdb/amd64fbsd-nat.c | 14 | ||||
-rw-r--r-- | gdb/i386-linux-nat.c | 50 | ||||
-rw-r--r-- | gdb/i386-nat.c | 174 | ||||
-rw-r--r-- | gdb/i386-nat.h | 11 | ||||
-rw-r--r-- | gdb/linux-fork.c | 2 | ||||
-rw-r--r-- | gdb/linux-nat.c | 150 | ||||
-rw-r--r-- | gdb/linux-nat.h | 23 | ||||
-rw-r--r-- | gdb/windows-nat.c | 1 |
10 files changed, 382 insertions, 168 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index b293389..24e38e9 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,76 @@ +2013-02-13 Pedro Alves <palves@redhat.com> + + * amd64-linux-nat.c (update_debug_registers_callback): + Update comment. + (amd64_linux_dr_set_control, amd64_linux_dr_set_addr): Use + iterate_over_lwps. + (amd64_linux_prepare_to_resume): Pass the lwp's pid to + i386_debug_reg_state. + (amd64_linux_new_fork): New function. + (_initialize_amd64_linux_nat): Install amd64_linux_new_fork as + linux_nat_new_fork hook, and i386_forget_process as + linux_nat_forget_process hook. + * i386-linux-nat.c (update_debug_registers_callback): + Update comment. + (amd64_linux_dr_set_control, amd64_linux_dr_set_addr): Use + iterate_over_lwps. + (i386_linux_prepare_to_resume): Pass the lwp's pid to + i386_debug_reg_state. + (i386_linux_new_fork): New function. + (_initialize_i386_linux_nat): Install i386_linux_new_fork as + linux_nat_new_fork hook, and i386_forget_process as + linux_nat_forget_process hook. + * i386-nat.c (i386_init_dregs): Delete. + (i386_inferior_data, struct i386_inferior_data): + Delete. + (struct i386_process_info): New. + (i386_process_list): New global. + (i386_find_process_pid, i386_add_process, i386_process_info_get): + New functions. + (i386_inferior_data_get): Delete. + (i386_process_info_get): New function. + (i386_debug_reg_state): New parameter 'pid'. Reimplement. + (i386_forget_process): New function. + (i386_cleanup_dregs): Rewrite. + (i386_update_inferior_debug_regs, i386_insert_watchpoint) + (i386_remove_watchpoint, i386_region_ok_for_watchpoint) + (i386_stopped_data_address, i386_insert_hw_breakpoint) + (i386_remove_hw_breakpoint): Adjust to pass the current process id + to i386_debug_reg_state. + (i386_use_watchpoints): Don't register inferior data. + * i386-nat.h (i386_debug_reg_state): Add new 'pid' parameter, and + adjust comment. + (i386_forget_process): Declare. + * linux-fork.c (delete_fork): Call linux_nat_forget_process. + * linux-nat.c (linux_nat_new_fork, linux_nat_forget_process_hook): + New static globals. + (linux_child_follow_fork): Don't call linux_nat_new_thread here. + (add_initial_lwp): New, factored out from ... + (add_lwp): ... this. Don't check the number of lwps before + calling linux_nat_new_thread. + (linux_nat_iterate_watchpoint_lwps): Delete. + (linux_nat_attach): Use add_initial_lwp instead of add_lwp. + (linux_handle_extended_wait): Call the linux_nat_new_fork hook on + forks and vforks. + (linux_nat_wait_1): Use add_initial_lwp instead of add_lwp for the + initial lwp. + (linux_nat_kill, linux_nat_mourn_inferior): Call + linux_nat_forget_process. + (linux_nat_set_new_fork, linux_nat_set_forget_process) + (linux_nat_forget_process): New functions. + * linux-nat.h (linux_nat_iterate_watchpoint_lwps_ftype): Delete + type. + (linux_nat_iterate_watchpoint_lwps): Delete declaration. + (linux_nat_new_fork_ftype, linux_nat_forget_process_ftype): New + types. + (linux_nat_set_new_fork, linux_nat_set_forget_process) + (linux_nat_forget_process): New declarations. + + * amd64fbsd-nat.c (super_mourn_inferior): New global. + (amd64fbsd_mourn_inferior): New function. + (_initialize_amd64fbsd_nat): Override to_mourn_inferior. + * windows-nat.c (windows_detach): Call i386_cleanup_dregs. + 2013-02-13 Marcus Shawcroft <marcus.shawcroft@arm.com> * aarch64-linux-nat.c (aarch64_linux_get_debug_reg_capacity) diff --git a/gdb/amd64-linux-nat.c b/gdb/amd64-linux-nat.c index e3e7f05..3d1983b 100644 --- a/gdb/amd64-linux-nat.c +++ b/gdb/amd64-linux-nat.c @@ -337,8 +337,8 @@ amd64_linux_dr_get_status (void) return amd64_linux_dr_get (inferior_ptid, DR_STATUS); } -/* Callback for linux_nat_iterate_watchpoint_lwps. Update the debug registers - of LWP. */ +/* Callback for iterate_over_lwps. Update the debug registers of + LWP. */ static int update_debug_registers_callback (struct lwp_info *lwp, void *arg) @@ -364,7 +364,9 @@ update_debug_registers_callback (struct lwp_info *lwp, void *arg) static void amd64_linux_dr_set_control (unsigned long control) { - linux_nat_iterate_watchpoint_lwps (update_debug_registers_callback, NULL); + ptid_t pid_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid)); + + iterate_over_lwps (pid_ptid, update_debug_registers_callback, NULL); } /* Set address REGNUM (zero based) to ADDR in all LWPs of the current @@ -373,9 +375,11 @@ amd64_linux_dr_set_control (unsigned long control) static void amd64_linux_dr_set_addr (int regnum, CORE_ADDR addr) { + ptid_t pid_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid)); + gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR); - linux_nat_iterate_watchpoint_lwps (update_debug_registers_callback, NULL); + iterate_over_lwps (pid_ptid, update_debug_registers_callback, NULL); } /* Called when resuming a thread. @@ -394,7 +398,8 @@ amd64_linux_prepare_to_resume (struct lwp_info *lwp) if (lwp->arch_private->debug_registers_changed) { - struct i386_debug_reg_state *state = i386_debug_reg_state (); + struct i386_debug_reg_state *state + = i386_debug_reg_state (ptid_get_pid (lwp->ptid)); int i; /* On Linux kernel before 2.6.33 commit @@ -434,6 +439,41 @@ amd64_linux_new_thread (struct lwp_info *lp) lp->arch_private = info; } + +/* linux_nat_new_fork hook. */ + +static void +amd64_linux_new_fork (struct lwp_info *parent, pid_t child_pid) +{ + pid_t parent_pid; + struct i386_debug_reg_state *parent_state; + struct i386_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; + + /* Linux kernel before 2.6.33 commit + 72f674d203cd230426437cdcf7dd6f681dad8b0d + will inherit hardware debug registers from parent + on fork/vfork/clone. Newer Linux kernels create such tasks with + zeroed debug registers. + + 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. The debug registers mirror will become zeroed + in the end before detaching the forked off process, thus making + this compatible with older Linux kernels too. */ + + parent_pid = ptid_get_pid (parent->ptid); + parent_state = i386_debug_reg_state (parent_pid); + child_state = i386_debug_reg_state (child_pid); + *child_state = *parent_state; +} + /* This function is called by libthread_db as part of its handling of @@ -1120,6 +1160,8 @@ _initialize_amd64_linux_nat (void) /* Register the target. */ linux_nat_add_target (t); linux_nat_set_new_thread (t, amd64_linux_new_thread); + linux_nat_set_new_fork (t, amd64_linux_new_fork); + linux_nat_set_forget_process (t, i386_forget_process); linux_nat_set_siginfo_fixup (t, amd64_linux_siginfo_fixup); linux_nat_set_prepare_to_resume (t, amd64_linux_prepare_to_resume); } diff --git a/gdb/amd64fbsd-nat.c b/gdb/amd64fbsd-nat.c index a500a66..eb30831 100644 --- a/gdb/amd64fbsd-nat.c +++ b/gdb/amd64fbsd-nat.c @@ -142,6 +142,17 @@ amd64fbsd_supply_pcb (struct regcache *regcache, struct pcb *pcb) } +static void (*super_mourn_inferior) (struct target_ops *ops); + +static void +amd64fbsd_mourn_inferior (struct target_ops *ops) +{ +#ifdef HAVE_PT_GETDBREGS + i386_cleanup_dregs (); +#endif + super_mourn_inferior (ops); +} + /* Provide a prototype to silence -Wmissing-prototypes. */ void _initialize_amd64fbsd_nat (void); @@ -170,6 +181,9 @@ _initialize_amd64fbsd_nat (void) #endif /* HAVE_PT_GETDBREGS */ + super_mourn_inferior = t->to_mourn_inferior; + t->to_mourn_inferior = amd64fbsd_mourn_inferior; + t->to_pid_to_exec_file = fbsd_pid_to_exec_file; t->to_find_memory_regions = fbsd_find_memory_regions; t->to_make_corefile_notes = fbsd_make_corefile_notes; diff --git a/gdb/i386-linux-nat.c b/gdb/i386-linux-nat.c index 20cc032..11b510d 100644 --- a/gdb/i386-linux-nat.c +++ b/gdb/i386-linux-nat.c @@ -708,8 +708,8 @@ i386_linux_dr_get_status (void) return i386_linux_dr_get (inferior_ptid, DR_STATUS); } -/* Callback for linux_nat_iterate_watchpoint_lwps. Update the debug registers - of LWP. */ +/* Callback for iterate_over_lwps. Update the debug registers of + LWP. */ static int update_debug_registers_callback (struct lwp_info *lwp, void *arg) @@ -735,7 +735,9 @@ update_debug_registers_callback (struct lwp_info *lwp, void *arg) static void i386_linux_dr_set_control (unsigned long control) { - linux_nat_iterate_watchpoint_lwps (update_debug_registers_callback, NULL); + ptid_t pid_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid)); + + iterate_over_lwps (pid_ptid, update_debug_registers_callback, NULL); } /* Set address REGNUM (zero based) to ADDR in all LWPs of the current @@ -748,7 +750,7 @@ i386_linux_dr_set_addr (int regnum, CORE_ADDR addr) gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR); - linux_nat_iterate_watchpoint_lwps (update_debug_registers_callback, NULL); + iterate_over_lwps (pid_ptid, update_debug_registers_callback, NULL); } /* Called when resuming a thread. @@ -767,7 +769,8 @@ i386_linux_prepare_to_resume (struct lwp_info *lwp) if (lwp->arch_private->debug_registers_changed) { - struct i386_debug_reg_state *state = i386_debug_reg_state (); + struct i386_debug_reg_state *state + = i386_debug_reg_state (ptid_get_pid (lwp->ptid)); int i; /* See amd64_linux_prepare_to_resume for Linux kernel note on @@ -803,6 +806,41 @@ i386_linux_new_thread (struct lwp_info *lp) lp->arch_private = info; } + +/* linux_nat_new_fork hook. */ + +static void +i386_linux_new_fork (struct lwp_info *parent, pid_t child_pid) +{ + pid_t parent_pid; + struct i386_debug_reg_state *parent_state; + struct i386_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; + + /* Linux kernel before 2.6.33 commit + 72f674d203cd230426437cdcf7dd6f681dad8b0d + will inherit hardware debug registers from parent + on fork/vfork/clone. Newer Linux kernels create such tasks with + zeroed debug registers. + + 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. The debug registers mirror will become zeroed + in the end before detaching the forked off process, thus making + this compatible with older Linux kernels too. */ + + parent_pid = ptid_get_pid (parent->ptid); + parent_state = i386_debug_reg_state (parent_pid); + child_state = i386_debug_reg_state (child_pid); + *child_state = *parent_state; +} + /* Called by libthread_db. Returns a pointer to the thread local @@ -1044,5 +1082,7 @@ _initialize_i386_linux_nat (void) /* Register the target. */ linux_nat_add_target (t); linux_nat_set_new_thread (t, i386_linux_new_thread); + linux_nat_set_new_fork (t, i386_linux_new_fork); + linux_nat_set_forget_process (t, i386_forget_process); linux_nat_set_prepare_to_resume (t, i386_linux_prepare_to_resume); } diff --git a/gdb/i386-nat.c b/gdb/i386-nat.c index c87e753..0a5deb0 100644 --- a/gdb/i386-nat.c +++ b/gdb/i386-nat.c @@ -153,104 +153,102 @@ struct i386_dr_low_type i386_dr_low; /* A macro to loop over all debug registers. */ #define ALL_DEBUG_REGISTERS(i) for (i = 0; i < DR_NADDR; i++) -/* 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 -i386_init_dregs (struct i386_debug_reg_state *state) +struct i386_process_info { - int i; - - ALL_DEBUG_REGISTERS (i) - { - state->dr_mirror[i] = 0; - state->dr_ref_count[i] = 0; - } - state->dr_control_mirror = 0; - state->dr_status_mirror = 0; -} + /* Linked list. */ + struct i386_process_info *next; -/* Per-inferior data key. */ -static const struct inferior_data *i386_inferior_data; + /* The process identifier. */ + pid_t pid; -/* Per-inferior data. */ -struct i386_inferior_data -{ - /* Copy of i386 hardware debug registers for performance reasons. */ + /* Copy of i386 hardware debug registers. */ struct i386_debug_reg_state state; }; -/* Per-inferior hook for register_inferior_data_with_cleanup. */ +static struct i386_process_info *i386_process_list = NULL; -static void -i386_inferior_data_cleanup (struct inferior *inf, void *arg) +/* Find process data for process PID. */ + +static struct i386_process_info * +i386_find_process_pid (pid_t pid) { - struct i386_inferior_data *inf_data = arg; + struct i386_process_info *proc; + + for (proc = i386_process_list; proc; proc = proc->next) + if (proc->pid == pid) + return proc; - xfree (inf_data); + return NULL; } -/* Get data specific for INFERIOR_PTID LWP. Return special data area - for processes being detached. */ +/* Add process data for process PID. Returns newly allocated info + object. */ -static struct i386_inferior_data * -i386_inferior_data_get (void) +static struct i386_process_info * +i386_add_process (pid_t pid) { - struct inferior *inf = current_inferior (); - struct i386_inferior_data *inf_data; + struct i386_process_info *proc; - inf_data = inferior_data (inf, i386_inferior_data); - if (inf_data == NULL) - { - inf_data = xzalloc (sizeof (*inf_data)); - set_inferior_data (current_inferior (), i386_inferior_data, inf_data); - } + proc = xcalloc (1, sizeof (*proc)); + proc->pid = pid; - if (inf->pid != ptid_get_pid (inferior_ptid)) - { - /* INFERIOR_PTID is being detached from the inferior INF. - Provide local cache specific for the detached LWP. */ + proc->next = i386_process_list; + i386_process_list = proc; - static struct i386_inferior_data detached_inf_data_local; - static int detached_inf_pid = -1; + return proc; +} - if (detached_inf_pid != ptid_get_pid (inferior_ptid)) - { - /* Reinitialize the local cache if INFERIOR_PTID is - different from the LWP last detached. - - Linux kernel before 2.6.33 commit - 72f674d203cd230426437cdcf7dd6f681dad8b0d - will inherit hardware debug registers from parent - on fork/vfork/clone. Newer Linux kernels create such tasks with - zeroed debug registers. - - GDB will remove all breakpoints (and watchpoints) from the forked - off process. We also need to reset the debug registers in that - process to be compatible with the older Linux kernels. - - Copy the debug registers mirrors into the new process so that all - breakpoints and watchpoints can be removed together. The debug - registers mirror will become zeroed in the end before detaching - the forked off process. */ - - detached_inf_pid = ptid_get_pid (inferior_ptid); - detached_inf_data_local = *inf_data; - } +/* Get data specific info for process PID, creating it if necessary. + Never returns NULL. */ - return &detached_inf_data_local; - } +static struct i386_process_info * +i386_process_info_get (pid_t pid) +{ + struct i386_process_info *proc; + + proc = i386_find_process_pid (pid); + if (proc == NULL) + proc = i386_add_process (pid); - return inf_data; + return proc; } -/* Get debug registers state for INFERIOR_PTID, see - i386_inferior_data_get. */ +/* Get debug registers state for process PID. */ struct i386_debug_reg_state * -i386_debug_reg_state (void) +i386_debug_reg_state (pid_t pid) { - return &i386_inferior_data_get ()->state; + return &i386_process_info_get (pid)->state; +} + +/* See declaration in i386-nat.h. */ + +void +i386_forget_process (pid_t pid) +{ + struct i386_process_info *proc, **proc_link; + + proc = i386_process_list; + proc_link = &i386_process_list; + + while (proc != NULL) + { + if (proc->pid == pid) + { + *proc_link = proc->next; + + xfree (proc); + return; + } + + proc_link = &proc->next; + proc = *proc_link; + } } /* Whether or not to print the mirrored debug registers. */ @@ -303,9 +301,8 @@ static int i386_handle_nonaligned_watchpoint (struct i386_debug_reg_state *state void i386_cleanup_dregs (void) { - struct i386_debug_reg_state *state = i386_debug_reg_state (); - - i386_init_dregs (state); + /* Starting from scratch has the same effect. */ + i386_forget_process (ptid_get_pid (inferior_ptid)); } /* Print the values of the mirrored debug registers. This is called @@ -569,7 +566,8 @@ Invalid value %d of operation in i386_handle_nonaligned_watchpoint.\n"), static void i386_update_inferior_debug_regs (struct i386_debug_reg_state *new_state) { - struct i386_debug_reg_state *state = i386_debug_reg_state (); + struct i386_debug_reg_state *state + = i386_debug_reg_state (ptid_get_pid (inferior_ptid)); int i; ALL_DEBUG_REGISTERS (i) @@ -594,7 +592,8 @@ static int i386_insert_watchpoint (CORE_ADDR addr, int len, int type, struct expression *cond) { - struct i386_debug_reg_state *state = i386_debug_reg_state (); + struct i386_debug_reg_state *state + = i386_debug_reg_state (ptid_get_pid (inferior_ptid)); int retval; /* Work on a local copy of the debug registers, and on success, commit the change back to the inferior. */ @@ -631,7 +630,8 @@ static int i386_remove_watchpoint (CORE_ADDR addr, int len, int type, struct expression *cond) { - struct i386_debug_reg_state *state = i386_debug_reg_state (); + struct i386_debug_reg_state *state + = i386_debug_reg_state (ptid_get_pid (inferior_ptid)); int retval; /* Work on a local copy of the debug registers, and on success, commit the change back to the inferior. */ @@ -664,7 +664,8 @@ i386_remove_watchpoint (CORE_ADDR addr, int len, int type, static int i386_region_ok_for_watchpoint (CORE_ADDR addr, int len) { - struct i386_debug_reg_state *state = i386_debug_reg_state (); + struct i386_debug_reg_state *state + = i386_debug_reg_state (ptid_get_pid (inferior_ptid)); int nregs; /* Compute how many aligned watchpoints we would need to cover this @@ -681,7 +682,8 @@ i386_region_ok_for_watchpoint (CORE_ADDR addr, int len) static int i386_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p) { - struct i386_debug_reg_state *state = i386_debug_reg_state (); + struct i386_debug_reg_state *state + = i386_debug_reg_state (ptid_get_pid (inferior_ptid)); CORE_ADDR addr = 0; int i; int rc = 0; @@ -766,7 +768,8 @@ static int i386_insert_hw_breakpoint (struct gdbarch *gdbarch, struct bp_target_info *bp_tgt) { - struct i386_debug_reg_state *state = i386_debug_reg_state (); + struct i386_debug_reg_state *state + = i386_debug_reg_state (ptid_get_pid (inferior_ptid)); unsigned len_rw = i386_length_and_rw_bits (1, hw_execute); CORE_ADDR addr = bp_tgt->placed_address; /* Work on a local copy of the debug registers, and on success, @@ -791,7 +794,8 @@ static int i386_remove_hw_breakpoint (struct gdbarch *gdbarch, struct bp_target_info *bp_tgt) { - struct i386_debug_reg_state *state = i386_debug_reg_state (); + struct i386_debug_reg_state *state + = i386_debug_reg_state (ptid_get_pid (inferior_ptid)); unsigned len_rw = i386_length_and_rw_bits (1, hw_execute); CORE_ADDR addr = bp_tgt->placed_address; /* Work on a local copy of the debug registers, and on success, @@ -869,10 +873,6 @@ i386_use_watchpoints (struct target_ops *t) t->to_remove_watchpoint = i386_remove_watchpoint; t->to_insert_hw_breakpoint = i386_insert_hw_breakpoint; t->to_remove_hw_breakpoint = i386_remove_hw_breakpoint; - - if (i386_inferior_data == NULL) - i386_inferior_data - = register_inferior_data_with_cleanup (NULL, i386_inferior_data_cleanup); } void diff --git a/gdb/i386-nat.h b/gdb/i386-nat.h index 87e313d..9ce52ab 100644 --- a/gdb/i386-nat.h +++ b/gdb/i386-nat.h @@ -110,9 +110,14 @@ extern void i386_set_debug_register_length (int len); extern void i386_cleanup_dregs (void); -/* Return a pointer to the the local mirror of the inferior's debug - registers. */ +/* Return a pointer to the local mirror of the debug registers of + process PID. */ -extern struct i386_debug_reg_state *i386_debug_reg_state (void); +extern struct i386_debug_reg_state *i386_debug_reg_state (pid_t pid); + +/* Called whenever GDB is no longer debugging process PID. It deletes + data structures that keep track of debug register state. */ + +extern void i386_forget_process (pid_t pid); #endif /* I386_NAT_H */ diff --git a/gdb/linux-fork.c b/gdb/linux-fork.c index 2151401..7ed1803 100644 --- a/gdb/linux-fork.c +++ b/gdb/linux-fork.c @@ -122,6 +122,8 @@ delete_fork (ptid_t ptid) fpprev = NULL; + linux_nat_forget_process (ptid_get_pid (ptid)); + for (fp = fork_list; fp; fpprev = fp, fp = fp->next) if (ptid_equal (fp->ptid, ptid)) break; diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c index 57bca11..0713edd 100644 --- a/gdb/linux-nat.c +++ b/gdb/linux-nat.c @@ -184,6 +184,13 @@ static struct target_ops linux_ops_saved; /* The method to call, if any, when a new thread is attached. */ static void (*linux_nat_new_thread) (struct lwp_info *); +/* The method to call, if any, when a new fork is attached. */ +static linux_nat_new_fork_ftype *linux_nat_new_fork; + +/* The method to call, if any, when a process is no longer + attached. */ +static linux_nat_forget_process_ftype *linux_nat_forget_process_hook; + /* Hook to call prior to resuming a thread. */ static void (*linux_nat_prepare_to_resume) (struct lwp_info *); @@ -698,15 +705,6 @@ holding the child stopped. Try \"set detach-on-fork\" or \ child_lp->last_resume_kind = resume_stop; make_cleanup (delete_lwp_cleanup, child_lp); - /* CHILD_LP has new PID, therefore linux_nat_new_thread is not called for it. - See i386_inferior_data_get for the Linux kernel specifics. - Ensure linux_nat_prepare_to_resume will reset the hardware debug - registers. It is done by the linux_nat_new_thread call, which is - being skipped in add_lwp above for the first lwp of a pid. */ - gdb_assert (num_lwps (GET_PID (child_lp->ptid)) == 1); - if (linux_nat_new_thread != NULL) - linux_nat_new_thread (child_lp); - if (linux_nat_prepare_to_resume != NULL) linux_nat_prepare_to_resume (child_lp); ptrace (PTRACE_DETACH, child_pid, 0, 0); @@ -1176,12 +1174,22 @@ purge_lwp_list (int pid) } } -/* Add the LWP specified by PID to the list. Return a pointer to the - structure describing the new LWP. The LWP should already be stopped - (with an exception for the very first LWP). */ +/* Add the LWP specified by PTID to the list. PTID is the first LWP + in the process. Return a pointer to the structure describing the + new LWP. + + This differs from add_lwp in that we don't let the arch specific + bits know about this new thread. Current clients of this callback + take the opportunity to install watchpoints in the new thread, and + we shouldn't do that for the first thread. If we're spawning a + child ("run"), the thread executes the shell wrapper first, and we + shouldn't touch it until it execs the program we want to debug. + For "attach", it'd be okay to call the callback, but it's not + necessary, because watchpoints can't yet have been inserted into + the inferior. */ static struct lwp_info * -add_lwp (ptid_t ptid) +add_initial_lwp (ptid_t ptid) { struct lwp_info *lp; @@ -1200,15 +1208,25 @@ add_lwp (ptid_t ptid) lp->next = lwp_list; lwp_list = lp; + return lp; +} + +/* Add the LWP specified by PID to the list. Return a pointer to the + structure describing the new LWP. The LWP should already be + stopped. */ + +static struct lwp_info * +add_lwp (ptid_t ptid) +{ + struct lwp_info *lp; + + lp = add_initial_lwp (ptid); + /* Let the arch specific bits know about this new thread. Current clients of this callback take the opportunity to install - watchpoints in the new thread. Don't do this for the first - thread though. If we're spawning a child ("run"), the thread - executes the shell wrapper first, and we shouldn't touch it until - it execs the program we want to debug. For "attach", it'd be - okay to call the callback, but it's not necessary, because - watchpoints can't yet have been inserted into the inferior. */ - if (num_lwps (GET_PID (ptid)) > 1 && linux_nat_new_thread != NULL) + watchpoints in the new thread. We don't do this for the first + thread though. See add_initial_lwp. */ + if (linux_nat_new_thread != NULL) linux_nat_new_thread (lp); return lp; @@ -1285,45 +1303,6 @@ iterate_over_lwps (ptid_t filter, return NULL; } -/* Iterate like iterate_over_lwps does except when forking-off a child call - CALLBACK with CALLBACK_DATA specifically only for that new child PID. */ - -void -linux_nat_iterate_watchpoint_lwps - (linux_nat_iterate_watchpoint_lwps_ftype callback, void *callback_data) -{ - int inferior_pid = ptid_get_pid (inferior_ptid); - struct inferior *inf = current_inferior (); - - if (inf->pid == inferior_pid) - { - /* Iterate all the threads of the current inferior. Without specifying - INFERIOR_PID it would iterate all threads of all inferiors, which is - inappropriate for watchpoints. */ - - iterate_over_lwps (pid_to_ptid (inferior_pid), callback, callback_data); - } - else - { - /* Detaching a new child PID temporarily present in INFERIOR_PID. */ - - struct lwp_info *child_lp; - struct cleanup *old_chain; - pid_t child_pid = GET_PID (inferior_ptid); - ptid_t child_ptid = ptid_build (child_pid, child_pid, 0); - - gdb_assert (find_lwp_pid (child_ptid) == NULL); - child_lp = add_lwp (child_ptid); - child_lp->stopped = 1; - child_lp->last_resume_kind = resume_stop; - old_chain = make_cleanup (delete_lwp_cleanup, child_lp); - - callback (child_lp, callback_data); - - do_cleanups (old_chain); - } -} - /* Update our internal state when changing from one checkpoint to another indicated by NEW_PTID. We can only switch single-threaded applications, so we only create one new LWP, and the previous list @@ -1656,7 +1635,7 @@ linux_nat_attach (struct target_ops *ops, char *args, int from_tty) thread_change_ptid (inferior_ptid, ptid); /* Add the initial process as the first LWP to the list. */ - lp = add_lwp (ptid); + lp = add_initial_lwp (ptid); status = linux_nat_post_attach_wait (lp->ptid, 1, &lp->cloned, &lp->signalled); @@ -2309,6 +2288,15 @@ linux_handle_extended_wait (struct lwp_info *lp, int status, ourstatus->value.related_pid = ptid_build (new_pid, new_pid, 0); + if (event == PTRACE_EVENT_FORK || event == PTRACE_EVENT_VFORK) + { + /* The arch-specific native code may need to know about new + forks even if those end up never mapped to an + inferior. */ + if (linux_nat_new_fork != NULL) + linux_nat_new_fork (lp, new_pid); + } + if (event == PTRACE_EVENT_FORK && linux_fork_checkpointing_p (GET_PID (lp->ptid))) { @@ -3489,7 +3477,7 @@ linux_nat_wait_1 (struct target_ops *ops, BUILD_LWP (GET_PID (inferior_ptid), GET_PID (inferior_ptid))); - lp = add_lwp (inferior_ptid); + lp = add_initial_lwp (inferior_ptid); lp->resumed = 1; } @@ -4075,6 +4063,10 @@ linux_nat_kill (struct target_ops *ops) { ptrace (PT_KILL, PIDGET (last.value.related_pid), 0, 0); wait (&status); + + /* Let the arch-specific native code know this process is + gone. */ + linux_nat_forget_process (PIDGET (last.value.related_pid)); } if (forks_exist_p ()) @@ -4103,7 +4095,9 @@ linux_nat_kill (struct target_ops *ops) static void linux_nat_mourn_inferior (struct target_ops *ops) { - purge_lwp_list (ptid_get_pid (inferior_ptid)); + int pid = ptid_get_pid (inferior_ptid); + + purge_lwp_list (pid); if (! forks_exist_p ()) /* Normal case, no other forks available. */ @@ -4113,6 +4107,9 @@ linux_nat_mourn_inferior (struct target_ops *ops) there are other viable forks to debug. Delete the exiting one and context-switch to the first available. */ linux_fork_mourn_inferior (); + + /* Let the arch-specific native code know this process is gone. */ + linux_nat_forget_process (pid); } /* Convert a native/host siginfo object, into/from the siginfo in the @@ -5146,6 +5143,35 @@ linux_nat_set_new_thread (struct target_ops *t, linux_nat_new_thread = new_thread; } +/* See declaration in linux-nat.h. */ + +void +linux_nat_set_new_fork (struct target_ops *t, + linux_nat_new_fork_ftype *new_fork) +{ + /* Save the pointer. */ + linux_nat_new_fork = new_fork; +} + +/* See declaration in linux-nat.h. */ + +void +linux_nat_set_forget_process (struct target_ops *t, + linux_nat_forget_process_ftype *fn) +{ + /* Save the pointer. */ + linux_nat_forget_process_hook = fn; +} + +/* See declaration in linux-nat.h. */ + +void +linux_nat_forget_process (pid_t pid) +{ + if (linux_nat_forget_process_hook != NULL) + linux_nat_forget_process_hook (pid); +} + /* Register a method that converts a siginfo object between the layout that ptrace returns, and the layout in the architecture of the inferior. */ diff --git a/gdb/linux-nat.h b/gdb/linux-nat.h index 928721b..3de866d 100644 --- a/gdb/linux-nat.h +++ b/gdb/linux-nat.h @@ -154,12 +154,6 @@ struct lwp_info *iterate_over_lwps (ptid_t filter, void *), void *data); -typedef int (*linux_nat_iterate_watchpoint_lwps_ftype) (struct lwp_info *lwp, - void *arg); - -extern void linux_nat_iterate_watchpoint_lwps - (linux_nat_iterate_watchpoint_lwps_ftype callback, void *callback_data); - /* Create a prototype generic GNU/Linux target. The client can override it with local methods. */ struct target_ops * linux_target (void); @@ -176,6 +170,23 @@ void linux_nat_add_target (struct target_ops *); /* Register a method to call whenever a new thread is attached. */ void linux_nat_set_new_thread (struct target_ops *, void (*) (struct lwp_info *)); + +/* Register a method to call whenever a new fork is attached. */ +typedef void (linux_nat_new_fork_ftype) (struct lwp_info *parent, + pid_t child_pid); +void linux_nat_set_new_fork (struct target_ops *ops, + linux_nat_new_fork_ftype *fn); + +/* Register a method to call whenever a process is killed or + detached. */ +typedef void (linux_nat_forget_process_ftype) (pid_t pid); +void linux_nat_set_forget_process (struct target_ops *ops, + linux_nat_forget_process_ftype *fn); + +/* Call the method registered with the function above. PID is the + process to forget about. */ +void linux_nat_forget_process (pid_t pid); + /* Register a method that converts a siginfo object between the layout that ptrace returns, and the layout in the architecture of the inferior. */ diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c index 7ef10f1..2fe50b1 100644 --- a/gdb/windows-nat.c +++ b/gdb/windows-nat.c @@ -1881,6 +1881,7 @@ windows_detach (struct target_ops *ops, char *args, int from_tty) gdb_flush (gdb_stdout); } + i386_cleanup_dregs (); inferior_ptid = null_ptid; detach_inferior (current_event.dwProcessId); |