aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog73
-rw-r--r--gdb/amd64-linux-nat.c52
-rw-r--r--gdb/amd64fbsd-nat.c14
-rw-r--r--gdb/i386-linux-nat.c50
-rw-r--r--gdb/i386-nat.c174
-rw-r--r--gdb/i386-nat.h11
-rw-r--r--gdb/linux-fork.c2
-rw-r--r--gdb/linux-nat.c150
-rw-r--r--gdb/linux-nat.h23
-rw-r--r--gdb/windows-nat.c1
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);