* [PATCH] [native x86 GNU/Linux] Access debug register mirror from the corresponding inferior.
@ 2013-02-07 16:33 Pedro Alves
2013-02-07 16:59 ` Jan Kratochvil
0 siblings, 1 reply; 14+ messages in thread
From: Pedro Alves @ 2013-02-07 16:33 UTC (permalink / raw)
To: gdb-patches
While reviewing the native AArch64 patch, I noticed a problem:
On 02/06/2013 08:46 PM, Pedro Alves wrote:
>
>> > +static void
>> > +aarch64_linux_prepare_to_resume (struct lwp_info *lwp)
>> > +{
>> > + struct arch_lwp_info *info = lwp->arch_private;
>> > +
>> > + /* NULL means this is the main thread still going through the shell,
>> > + or, no watchpoint has been set yet. In that case, there's
>> > + nothing to do. */
>> > + if (info == NULL)
>> > + return;
>> > +
>> > + 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 ();
> Hmm. This is always fetching the debug_reg_state of
> the current inferior, but may not be the inferior of lwp.
> I see the same bug on x86. Sorry about that. I'll fix it.
The fix is to make i386_debug_reg_state take an inferior pointer and
work with it instead of always using the current inferior, and then
update all callers to pass in the right inferior.
There's one wrinkle though, and one which we already handle somewhat.
When detaching the fork child that we're not interested in debugging
(set detach-on-fork off / follow-fork parent), we don't even create an
inferior for that fork child, so there's no place to get the struct
i386_debug_reg_state from, as that's stored in the inferior.
I thought of more than one way to fix this, and this seemed the
simplest - special case the null inferior case.
Other options involved creating a about_to_detach/about_to_fork_detach
hook;
Create a target side "struct process_info", thus decoupling from
struct inferior (mildly complicated, lots of mechanical changes across
all native targets that do x86 watchpoints, or
Always creating an inferior (that has lots of complications).
I don't think now's the right time to do lots of changes in this area.
Tested on Fedora 17 x86_64 -m64/-m32.
I plan to check this in a bit later to today, unless of course there
are objections.
GDBserver already fetches the i386_debug_reg_state from the right
process, and, it doesn't handle forks at all, so no fix is needed over
there.
gdb/
2013-02-07 Pedro Alves <palves@redhat.com>
* amd64-linux-nat.c (amd64_linux_prepare_to_resume): Handle the
case of there being no matching inferior for the resumed lwp.
* i386-linux-nat.c (i386_linux_prepare_to_resume): Ditto.
* i386-nat.c (i386_inferior_data_cleanup, i386_debug_reg_state):
New parameter 'inf'. Use it instead of the current inferior.
(i386_cleanup_dregs, 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 inferior explicitly.
* i386-nat.h (struct inferior): Forward declare.
(i386_debug_reg_state): New parameter 'inf'.
---
gdb/amd64-linux-nat.c | 15 ++++++++++++++-
gdb/i386-linux-nat.c | 15 ++++++++++++++-
gdb/i386-nat.c | 31 +++++++++++++++++++------------
gdb/i386-nat.h | 8 +++++---
4 files changed, 52 insertions(+), 17 deletions(-)
diff --git a/gdb/amd64-linux-nat.c b/gdb/amd64-linux-nat.c
index e3e7f05..17cd2fd 100644
--- a/gdb/amd64-linux-nat.c
+++ b/gdb/amd64-linux-nat.c
@@ -394,9 +394,22 @@ 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 ();
+ int pid = ptid_get_pid (lwp->ptid);
+ struct inferior *inf = find_inferior_pid (pid);
+ struct i386_debug_reg_state *state;
int i;
+ if (inf == NULL)
+ {
+ /* NULL means this is a fork child we're not interested in
+ debugging being detached. We want to leave it with its
+ debug registers cleared. */
+ amd64_linux_dr_set (lwp->ptid, DR_CONTROL, 0);
+ return;
+ }
+
+ state = i386_debug_reg_state (inf);
+
/* On Linux kernel before 2.6.33 commit
72f674d203cd230426437cdcf7dd6f681dad8b0d
if you enable a breakpoint by the DR_CONTROL bits you need to have
diff --git a/gdb/i386-linux-nat.c b/gdb/i386-linux-nat.c
index 20cc032..1bfd73d 100644
--- a/gdb/i386-linux-nat.c
+++ b/gdb/i386-linux-nat.c
@@ -767,9 +767,22 @@ 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 ();
+ int pid = ptid_get_pid (lwp->ptid);
+ struct inferior *inf = find_inferior_pid (pid);
+ struct i386_debug_reg_state *state;
int i;
+ if (inf == NULL)
+ {
+ /* NULL means this is a fork child we're not interested in
+ debugging being detached. We want to leave it with its
+ debug registers cleared. */
+ i386_linux_dr_set (lwp->ptid, DR_CONTROL, 0);
+ return;
+ }
+
+ state = i386_debug_reg_state (inf);
+
/* See amd64_linux_prepare_to_resume for Linux kernel note on
i386_linux_dr_set calls ordering. */
diff --git a/gdb/i386-nat.c b/gdb/i386-nat.c
index c87e753..2f0a5f4 100644
--- a/gdb/i386-nat.c
+++ b/gdb/i386-nat.c
@@ -194,9 +194,8 @@ i386_inferior_data_cleanup (struct inferior *inf, void *arg)
for processes being detached. */
static struct i386_inferior_data *
-i386_inferior_data_get (void)
+i386_inferior_data_get (struct inferior *inf)
{
- struct inferior *inf = current_inferior ();
struct i386_inferior_data *inf_data;
inf_data = inferior_data (inf, i386_inferior_data);
@@ -248,9 +247,9 @@ i386_inferior_data_get (void)
i386_inferior_data_get. */
struct i386_debug_reg_state *
-i386_debug_reg_state (void)
+i386_debug_reg_state (struct inferior *inf)
{
- return &i386_inferior_data_get ()->state;
+ return &i386_inferior_data_get (inf)->state;
}
/* Whether or not to print the mirrored debug registers. */
@@ -303,7 +302,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 ();
+ struct i386_debug_reg_state *state
+ = i386_debug_reg_state (current_inferior ());
i386_init_dregs (state);
}
@@ -569,7 +569,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 (current_inferior ());
int i;
ALL_DEBUG_REGISTERS (i)
@@ -594,7 +595,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 (current_inferior ());
int retval;
/* Work on a local copy of the debug registers, and on success,
commit the change back to the inferior. */
@@ -631,7 +633,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 (current_inferior ());
int retval;
/* Work on a local copy of the debug registers, and on success,
commit the change back to the inferior. */
@@ -664,7 +667,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 (current_inferior ());
int nregs;
/* Compute how many aligned watchpoints we would need to cover this
@@ -681,7 +685,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 (current_inferior ());
CORE_ADDR addr = 0;
int i;
int rc = 0;
@@ -766,7 +771,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 (current_inferior ());
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 +797,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 (current_inferior ());
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,
diff --git a/gdb/i386-nat.h b/gdb/i386-nat.h
index 87e313d..322d7cf 100644
--- a/gdb/i386-nat.h
+++ b/gdb/i386-nat.h
@@ -25,10 +25,12 @@
/* Hardware-assisted breakpoints and watchpoints. */
+struct inferior;
+struct target_ops;
+
/* Add watchpoint methods to the provided target_ops.
Targets using i386 family debug registers for watchpoints should call
this. */
-struct target_ops;
extern void i386_use_watchpoints (struct target_ops *);
/* Support for hardware watchpoints and breakpoints using the i386
@@ -110,9 +112,9 @@ 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
+/* Return a pointer to the the local mirror of inferior INF's debug
registers. */
-extern struct i386_debug_reg_state *i386_debug_reg_state (void);
+extern struct i386_debug_reg_state *i386_debug_reg_state (struct inferior *inf);
#endif /* I386_NAT_H */
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] [native x86 GNU/Linux] Access debug register mirror from the corresponding inferior.
2013-02-07 16:33 [PATCH] [native x86 GNU/Linux] Access debug register mirror from the corresponding inferior Pedro Alves
@ 2013-02-07 16:59 ` Jan Kratochvil
2013-02-11 21:10 ` Pedro Alves
0 siblings, 1 reply; 14+ messages in thread
From: Jan Kratochvil @ 2013-02-07 16:59 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches
On Thu, 07 Feb 2013 17:33:39 +0100, Pedro Alves wrote:
> There's one wrinkle though, and one which we already handle somewhat.
> When detaching the fork child that we're not interested in debugging
> (set detach-on-fork off / follow-fork parent), we don't even create an
set detach-on-fork on
> inferior for that fork child, so there's no place to get the struct
> i386_debug_reg_state from, as that's stored in the inferior.
>
> I thought of more than one way to fix this, and this seemed the
> simplest - special case the null inferior case.
>
> Other options involved creating a about_to_detach/about_to_fork_detach
> hook;
>
> Create a target side "struct process_info", thus decoupling from
> struct inferior (mildly complicated, lots of mechanical changes across
> all native targets that do x86 watchpoints, or
>
> Always creating an inferior (that has lots of complications).
I tried that in the past and I agree it was not worth it.
> --- a/gdb/amd64-linux-nat.c
> +++ b/gdb/amd64-linux-nat.c
> @@ -394,9 +394,22 @@ 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 ();
> + int pid = ptid_get_pid (lwp->ptid);
> + struct inferior *inf = find_inferior_pid (pid);
> + struct i386_debug_reg_state *state;
> int i;
>
> + if (inf == NULL)
> + {
> + /* NULL means this is a fork child we're not interested in
> + debugging being detached. We want to leave it with its
> + debug registers cleared. */
> + amd64_linux_dr_set (lwp->ptid, DR_CONTROL, 0);
> + return;
> + }
It is already handled by this code which seems to be skipped by this patch.
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;
}
Also it seems incorrect to me to use 'ptid_get_pid (inferior_ptid)' there when
the detached LWP may not come from the current inferior, it is expected to be
the PID of the process remaining under control of GDB.
I did not try it but what about temporarily switching current inferior?
Thanks,
Jan
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] [native x86 GNU/Linux] Access debug register mirror from the corresponding inferior.
2013-02-07 16:59 ` Jan Kratochvil
@ 2013-02-11 21:10 ` Pedro Alves
2013-02-12 12:36 ` Pedro Alves
0 siblings, 1 reply; 14+ messages in thread
From: Pedro Alves @ 2013-02-11 21:10 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
On 02/07/2013 04:59 PM, Jan Kratochvil wrote:
> On Thu, 07 Feb 2013 17:33:39 +0100, Pedro Alves wrote:
>> There's one wrinkle though, and one which we already handle somewhat.
>> When detaching the fork child that we're not interested in debugging
>> (set detach-on-fork off / follow-fork parent), we don't even create an
> set detach-on-fork on
>> inferior for that fork child, so there's no place to get the struct
>> i386_debug_reg_state from, as that's stored in the inferior.
>>
>> I thought of more than one way to fix this, and this seemed the
>> simplest - special case the null inferior case.
>>
>> Other options involved creating a about_to_detach/about_to_fork_detach
>> hook;
>>
>> Create a target side "struct process_info", thus decoupling from
>> struct inferior (mildly complicated, lots of mechanical changes across
>> all native targets that do x86 watchpoints, or
>>
>> Always creating an inferior (that has lots of complications).
>
> I tried that in the past and I agree it was not worth it.
I've now gone the 'target side "struct process_info", thus decoupling from
struct inferior' way.
>
>
>> --- a/gdb/amd64-linux-nat.c
>> +++ b/gdb/amd64-linux-nat.c
>> @@ -394,9 +394,22 @@ 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 ();
>> + int pid = ptid_get_pid (lwp->ptid);
>> + struct inferior *inf = find_inferior_pid (pid);
>> + struct i386_debug_reg_state *state;
>> int i;
>>
>> + if (inf == NULL)
>> + {
>> + /* NULL means this is a fork child we're not interested in
>> + debugging being detached. We want to leave it with its
>> + debug registers cleared. */
>> + amd64_linux_dr_set (lwp->ptid, DR_CONTROL, 0);
>> + return;
>> + }
>
> It is already handled by this code which seems to be skipped by this patch.
Whoops, completely forgot this is here.
>
> 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;
> }
>
> Also it seems incorrect to me to use 'ptid_get_pid (inferior_ptid)' there when
> the detached LWP may not come from the current inferior, it is expected to be
> the PID of the process remaining under control of GDB.
Right. But prepare_to_resume is called in a lot more cases where we're
not detaching, and we don't switch the current inferior in those either.
I think that way is becoming too fragile.
> I did not try it but what about temporarily switching current inferior?
I think I'd rather try a different approach.
In a nutshell, we decouple the watchpoints code from inferiors, making
it track target processes instead. This way, we can freely keep track
of the watchpoint mirrors for these processes behind the core's
back. Checkpoints also play dirty tricks with swapping the process behind
the inferior, so they get special treatment too in the patch (which just
amounts to calling a new hook). Instead of the old
hack in i386_inferior_data_get, where we returned a copy of the current
inferior's debug registers mirror, as soon as we detect a fork in the target,
we copy the debug register mirror from the parent to the child process.
I don't have an old kernel handy to test, but I stepped through gdb doing
the watchpoint removal in the fork child in the watchpoint-fork test
seeing that the debug registers end up cleared in the child.
I didn't find the need for linux_nat_iterate_watchpoint_lwps. If
we use plain iterate_over_lwps instead, what happens is that
when removing watchpoints, that iterate_over_lwps doesn't actually
iterate over anything, since the fork child is not added to the
lwp list until later, at detach time, in linux_child_follow_fork.
And if we don't iterate over that lwp, we don't mark its debug
registers as needing update. But linux_child_follow_fork takes
care of doing that explicitly:
child_lp = add_lwp (inferior_ptid);
child_lp->stopped = 1;
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);
so unless I'm missing something (quite possible) it ends up all
the same. But, the !detach-on-fork, and the "follow-fork child" paths
should also call linux_nat_new_thread, and they don't presently. It
seems to me in those cases we're not clearing debug regs correctly
when that's needed? Instead of copying that bit that works around
add_lwp bypassing the linux_nat_new_thread call, I thought it'd
be better to add an add_initial_lwp call to be used in the case we
really need to bypass linux_nat_new_thread, and make
add_lwp always call linux_nat_new_thread.
WDYT?
Re-tested on Fedora 17.
gdb/
2013-02-11 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.
(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 i386_linux_new_fork as
linux_nat_new_fork hook, and i386_forget_process as
linux_nat_forget_process hook.
* i386-nat.c (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, 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_set_new_fork, linux_nat_set_forget_process)
(linux_nat_forget_process): New declaration.
---
gdb/amd64-linux-nat.c | 52 ++++++++++++++--
gdb/i386-linux-nat.c | 50 ++++++++++++++-
gdb/i386-nat.c | 159 +++++++++++++++++++++++++++----------------------
gdb/i386-nat.h | 11 ++-
gdb/linux-fork.c | 2 +
gdb/linux-nat.c | 149 +++++++++++++++++++++++++++-------------------
gdb/linux-nat.h | 18 ++++--
7 files changed, 290 insertions(+), 151 deletions(-)
diff --git a/gdb/amd64-linux-nat.c b/gdb/amd64-linux-nat.c
index e3e7f05..4d6e4ab 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, int child_pid)
+{
+ int 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;
+}
+
\f
/* 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/i386-linux-nat.c b/gdb/i386-linux-nat.c
index 20cc032..3c7494a 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, int child_pid)
+{
+ int 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;
+}
+
\f
/* 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..2e75ca3 100644
--- a/gdb/i386-nat.c
+++ b/gdb/i386-nat.c
@@ -170,87 +170,102 @@ i386_init_dregs (struct i386_debug_reg_state *state)
state->dr_status_mirror = 0;
}
-/* Per-inferior data key. */
-static const struct inferior_data *i386_inferior_data;
+/* 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). */
-/* Per-inferior data. */
-struct i386_inferior_data
+struct i386_process_info
{
- /* Copy of i386 hardware debug registers for performance reasons. */
+ /* Linked list. */
+ struct i386_process_info *next;
+
+ /* The process identifier. */
+ int pid;
+
+ /* Copy of i386 hardware debug registers. */
struct i386_debug_reg_state state;
};
-/* Per-inferior hook for register_inferior_data_with_cleanup. */
+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 (int pid)
{
- struct i386_inferior_data *inf_data = arg;
+ struct i386_process_info *inf;
- xfree (inf_data);
+ for (inf = i386_process_list; inf; inf = inf->next)
+ if (inf->pid == pid)
+ return inf;
+
+ 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 (int 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 (int 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 (int pid)
{
- return &i386_inferior_data_get ()->state;
+ return &i386_process_info_get (pid)->state;
+}
+
+/* See declaration in i386-nat.h. */
+
+void
+i386_forget_process (int 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,7 +318,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 ();
+ struct i386_debug_reg_state *state
+ = i386_debug_reg_state (ptid_get_pid (inferior_ptid));
i386_init_dregs (state);
}
@@ -569,7 +585,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 +611,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 +649,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 +683,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 +701,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 +787,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 +813,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 +892,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..ead1fb0 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 (int 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 (int 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..2438fa3 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 void (*linux_nat_new_fork) (struct lwp_info *, int);
+
+/* The method to call, if any, when a process is no longer
+ attached. */
+static void (*linux_nat_forget_process_hook) (int);
+
/* 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 all_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,34 @@ 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,
+ void (*new_fork) (struct lwp_info *, int))
+{
+ /* 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, void (*fn) (int))
+{
+ /* Save the pointer. */
+ linux_nat_forget_process_hook = fn;
+}
+
+/* See declaration in linux-nat.h. */
+
+void
+linux_nat_forget_process (int 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..3e6f871 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,18 @@ 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. */
+void linux_nat_set_new_fork (struct target_ops *,
+ void (*) (struct lwp_info *, int));
+
+/* Register a method to call whenever a process is killed or
+ detached. */
+void linux_nat_set_forget_process (struct target_ops *, void (*) (int));
+
+/* Call the method registered with the function above. PID is the
+ process to forget about. */
+void linux_nat_forget_process (int pid);
+
/* Register a method that converts a siginfo object between the layout
that ptrace returns, and the layout in the architecture of the
inferior. */
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] [native x86 GNU/Linux] Access debug register mirror from the corresponding inferior.
2013-02-11 21:10 ` Pedro Alves
@ 2013-02-12 12:36 ` Pedro Alves
2013-02-12 16:50 ` Jan Kratochvil
2013-02-13 14:20 ` Yufeng Zhang
0 siblings, 2 replies; 14+ messages in thread
From: Pedro Alves @ 2013-02-12 12:36 UTC (permalink / raw)
Cc: Jan Kratochvil, gdb-patches
[-- Attachment #1: Type: text/plain, Size: 6891 bytes --]
On 02/11/2013 09:09 PM, Pedro Alves wrote:
> On 02/07/2013 04:59 PM, Jan Kratochvil wrote:
>> On Thu, 07 Feb 2013 17:33:39 +0100, Pedro Alves wrote:
>>> There's one wrinkle though, and one which we already handle somewhat.
>>> When detaching the fork child that we're not interested in debugging
>>> (set detach-on-fork off / follow-fork parent), we don't even create an
>> set detach-on-fork on
>>> inferior for that fork child, so there's no place to get the struct
>>> i386_debug_reg_state from, as that's stored in the inferior.
>>>
>>> I thought of more than one way to fix this, and this seemed the
>>> simplest - special case the null inferior case.
>>>
>>> Other options involved creating a about_to_detach/about_to_fork_detach
>>> hook;
>>>
>>> Create a target side "struct process_info", thus decoupling from
>>> struct inferior (mildly complicated, lots of mechanical changes across
>>> all native targets that do x86 watchpoints, or
>>>
>>> Always creating an inferior (that has lots of complications).
>>
>> I tried that in the past and I agree it was not worth it.
>
> I've now gone the 'target side "struct process_info", thus decoupling from
> struct inferior' way.
>
>>
>>
>>> --- a/gdb/amd64-linux-nat.c
>>> +++ b/gdb/amd64-linux-nat.c
>>> @@ -394,9 +394,22 @@ 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 ();
>>> + int pid = ptid_get_pid (lwp->ptid);
>>> + struct inferior *inf = find_inferior_pid (pid);
>>> + struct i386_debug_reg_state *state;
>>> int i;
>>>
>>> + if (inf == NULL)
>>> + {
>>> + /* NULL means this is a fork child we're not interested in
>>> + debugging being detached. We want to leave it with its
>>> + debug registers cleared. */
>>> + amd64_linux_dr_set (lwp->ptid, DR_CONTROL, 0);
>>> + return;
>>> + }
>>
>> It is already handled by this code which seems to be skipped by this patch.
>
> Whoops, completely forgot this is here.
>
>>
>> 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;
>> }
>>
>> Also it seems incorrect to me to use 'ptid_get_pid (inferior_ptid)' there when
>> the detached LWP may not come from the current inferior, it is expected to be
>> the PID of the process remaining under control of GDB.
>
> Right. But prepare_to_resume is called in a lot more cases where we're
> not detaching, and we don't switch the current inferior in those either.
> I think that way is becoming too fragile.
>
>> I did not try it but what about temporarily switching current inferior?
>
> I think I'd rather try a different approach.
>
> In a nutshell, we decouple the watchpoints code from inferiors, making
> it track target processes instead. This way, we can freely keep track
> of the watchpoint mirrors for these processes behind the core's
> back. Checkpoints also play dirty tricks with swapping the process behind
> the inferior, so they get special treatment too in the patch (which just
> amounts to calling a new hook). Instead of the old
> hack in i386_inferior_data_get, where we returned a copy of the current
> inferior's debug registers mirror, as soon as we detect a fork in the target,
> we copy the debug register mirror from the parent to the child process.
>
> I don't have an old kernel handy to test, but I stepped through gdb doing
> the watchpoint removal in the fork child in the watchpoint-fork test
> seeing that the debug registers end up cleared in the child.
>
> I didn't find the need for linux_nat_iterate_watchpoint_lwps. If
> we use plain iterate_over_lwps instead, what happens is that
> when removing watchpoints, that iterate_over_lwps doesn't actually
> iterate over anything, since the fork child is not added to the
> lwp list until later, at detach time, in linux_child_follow_fork.
> And if we don't iterate over that lwp, we don't mark its debug
> registers as needing update. But linux_child_follow_fork takes
> care of doing that explicitly:
>
> child_lp = add_lwp (inferior_ptid);
> child_lp->stopped = 1;
> 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);
>
> so unless I'm missing something (quite possible) it ends up all
> the same. But, the !detach-on-fork, and the "follow-fork child" paths
> should also call linux_nat_new_thread, and they don't presently. It
> seems to me in those cases we're not clearing debug regs correctly
> when that's needed? Instead of copying that bit that works around
> add_lwp bypassing the linux_nat_new_thread call, I thought it'd
> be better to add an add_initial_lwp call to be used in the case we
> really need to bypass linux_nat_new_thread, and make
> add_lwp always call linux_nat_new_thread.
>
> WDYT?
>
> Re-tested on Fedora 17.
Here's a slithly updated patch that leverages i386_cleanup_dregs to
hopefully take care of the other i386 ports that support watchpoints.
I've also pushed this to
https://github.com/palves/gdb/commits/debug_regs_state
(git://github.com/palves/gdb.git debug_regs_state)
for convenience.
--
Pedro Alves
[-- Attachment #2: debug_regs_state.diff --]
[-- Type: text/x-patch, Size: 36955 bytes --]
commit 89775fcf9d970233cc664425cf793322db9e8f0b
Author: Pedro Alves <palves@redhat.com>
Date: Tue Feb 12 12:27:55 2013 +0000
[native x86 GNU/Linux] Access debug register mirror from the corresponding inferior.
While reviewing the native AArch64 patch, I noticed a problem:
On 02/06/2013 08:46 PM, Pedro Alves wrote:
>
>> > +static void
>> > +aarch64_linux_prepare_to_resume (struct lwp_info *lwp)
>> > +{
>> > + struct arch_lwp_info *info = lwp->arch_private;
>> > +
>> > + /* NULL means this is the main thread still going through the shell,
>> > + or, no watchpoint has been set yet. In that case, there's
>> > + nothing to do. */
>> > + if (info == NULL)
>> > + return;
>> > +
>> > + 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 ();
> Hmm. This is always fetching the debug_reg_state of
> the current inferior, but may not be the inferior of lwp.
> I see the same bug on x86. Sorry about that. I'll fix it.
A natural fix would be to make xxx_get_debug_reg_state take an
inferior argument, but that doesn't work because of the case where we
detach breakpoints/watchpoints from the child fork, at a time there's
no inferior for the child fork at all. We do a nasty hack in
i386_inferior_data_get, but that relies on all callers pointing the
current inferior to the correct inferior, which isn't actually being
done by all callers, and I don't think we want to enforce that -- deep
in the bowls of linux-nat.c, there are many cases we resume lwps
behind the scenes, and it's be better to not have that code rely on
global state (as it doesn't today).
The fix is to decouple the watchpoints code from inferiors, making it
track target processes instead. This way, we can freely keep track of
the watchpoint mirrors for these processes behind the core's back.
Checkpoints also play dirty tricks with swapping the process behind
the inferior, so they get special treatment too in the patch (which
just amounts to calling a new hook). Instead of the old hack in
i386_inferior_data_get, where we returned a copy of the current
inferior's debug registers mirror, as soon as we detect a fork in the
target, we copy the debug register mirror from the parent to the child
process.
I don't have an old kernel handy to test, but I stepped through gdb doing
the watchpoint removal in the fork child in the watchpoint-fork test
seeing that the debug registers end up cleared in the child.
I didn't find the need for linux_nat_iterate_watchpoint_lwps. If
we use plain iterate_over_lwps instead, what happens is that
when removing watchpoints, that iterate_over_lwps doesn't actually
iterate over anything, since the fork child is not added to the
lwp list until later, at detach time, in linux_child_follow_fork.
And if we don't iterate over that lwp, we don't mark its debug
registers as needing update. But linux_child_follow_fork takes
care of doing that explicitly:
child_lp = add_lwp (inferior_ptid);
child_lp->stopped = 1;
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);
so unless I'm missing something (quite possible) it ends up all
the same. But, the !detach-on-fork, and the "follow-fork child" paths
should also call linux_nat_new_thread, and they don't presently. It
seems to me in those cases we're not clearing debug regs correctly
when that's needed? Instead of copying that bit that works around
add_lwp bypassing the linux_nat_new_thread call, I thought it'd
be better to add an add_initial_lwp call to be used in the case we
really need to bypass linux_nat_new_thread, and make
add_lwp always call linux_nat_new_thread.
i386_cleanup_dregs is rewritten to forget about the current process
debug mirrors, which takes cares of other i386 ports. Only a couple
of extra tweaks here and there were needed, as some targets wheren't
actually calling i386_cleanup_dregs.
Tested on Fedora 17 x86_64 -m64/-m32.
GDBserver already fetches the i386_debug_reg_state from the right
process, and, it doesn't handle forks at all, so no fix is needed over
there.
gdb/
2013-02-12 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.
(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 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_cleanup_dregs, 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_set_new_fork, linux_nat_set_forget_process)
(linux_nat_forget_process): New declaration.
* 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.
diff --git a/gdb/amd64-linux-nat.c b/gdb/amd64-linux-nat.c
index e3e7f05..4d6e4ab 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, int child_pid)
+{
+ int 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;
+}
+
\f
/* 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)
}
\f
+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..3c7494a 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, int child_pid)
+{
+ int 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;
+}
+
\f
/* 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..4941477 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. */
+ int 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. */
+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 (int pid)
{
- struct i386_inferior_data *inf_data = arg;
+ struct i386_process_info *inf;
+
+ for (inf = i386_process_list; inf; inf = inf->next)
+ if (inf->pid == pid)
+ return inf;
- 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 (int 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 (int 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 (int pid)
{
- return &i386_inferior_data_get ()->state;
+ return &i386_process_info_get (pid)->state;
+}
+
+/* See declaration in i386-nat.h. */
+
+void
+i386_forget_process (int 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..ead1fb0 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 (int 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 (int 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..2438fa3 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 void (*linux_nat_new_fork) (struct lwp_info *, int);
+
+/* The method to call, if any, when a process is no longer
+ attached. */
+static void (*linux_nat_forget_process_hook) (int);
+
/* 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 all_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,34 @@ 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,
+ void (*new_fork) (struct lwp_info *, int))
+{
+ /* 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, void (*fn) (int))
+{
+ /* Save the pointer. */
+ linux_nat_forget_process_hook = fn;
+}
+
+/* See declaration in linux-nat.h. */
+
+void
+linux_nat_forget_process (int 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..3e6f871 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,18 @@ 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. */
+void linux_nat_set_new_fork (struct target_ops *,
+ void (*) (struct lwp_info *, int));
+
+/* Register a method to call whenever a process is killed or
+ detached. */
+void linux_nat_set_forget_process (struct target_ops *, void (*) (int));
+
+/* Call the method registered with the function above. PID is the
+ process to forget about. */
+void linux_nat_forget_process (int 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);
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] [native x86 GNU/Linux] Access debug register mirror from the corresponding inferior.
2013-02-12 12:36 ` Pedro Alves
@ 2013-02-12 16:50 ` Jan Kratochvil
2013-02-13 15:04 ` Pedro Alves
2013-02-13 14:20 ` Yufeng Zhang
1 sibling, 1 reply; 14+ messages in thread
From: Jan Kratochvil @ 2013-02-12 16:50 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches
On Tue, 12 Feb 2013 13:35:59 +0100, Pedro Alves wrote:
> On 02/11/2013 09:09 PM, Pedro Alves wrote:
> > In a nutshell, we decouple the watchpoints code from inferiors, making
> > it track target processes instead.
It looks really cleaner than waht it was.
I haven't found there any real bug.
[...]
> --- 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. */
> + int pid;
style: Here and on many other places should be pid_t.
>
> -/* 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. */
> +struct i386_process_info *i386_process_list = NULL;
Missing static.
>
> -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 (int pid)
> {
> - struct i386_inferior_data *inf_data = arg;
> + struct i386_process_info *inf;
style: The 'inf' name is confusing when it is not inferior.
> +
> + for (inf = i386_process_list; inf; inf = inf->next)
> + if (inf->pid == pid)
> + return inf;
>
> - xfree (inf_data);
> + return NULL;
> }
>
[...]
> --- 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 void (*linux_nat_new_fork) (struct lwp_info *, int);
style: The parameters could be named.
> +
> +/* The method to call, if any, when a process is no longer
> + attached. */
> +static void (*linux_nat_forget_process_hook) (int);
style: The parameter could be named.
> +
> /* Hook to call prior to resuming a thread. */
> static void (*linux_nat_prepare_to_resume) (struct lwp_info *);
>
[...]
> --- a/gdb/linux-nat.h
> +++ b/gdb/linux-nat.h
[...]
> @@ -176,6 +170,18 @@ 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. */
> +void linux_nat_set_new_fork (struct target_ops *,
> + void (*) (struct lwp_info *, int));
> +
> +/* Register a method to call whenever a process is killed or
> + detached. */
> +void linux_nat_set_forget_process (struct target_ops *, void (*) (int));
style: Parameters could be named, I do not understand why to omit their names.
> +
> +/* Call the method registered with the function above. PID is the
> + process to forget about. */
> +void linux_nat_forget_process (int pid);
> +
> /* Register a method that converts a siginfo object between the layout
> that ptrace returns, and the layout in the architecture of the
> inferior. */
[...]
Thanks,
Jan
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] [native x86 GNU/Linux] Access debug register mirror from the corresponding inferior.
2013-02-12 12:36 ` Pedro Alves
2013-02-12 16:50 ` Jan Kratochvil
@ 2013-02-13 14:20 ` Yufeng Zhang
2013-02-13 14:51 ` Pedro Alves
2013-02-13 15:14 ` Pedro Alves
1 sibling, 2 replies; 14+ messages in thread
From: Yufeng Zhang @ 2013-02-13 14:20 UTC (permalink / raw)
To: gdb-patches
On 02/12/13 12:35, Pedro Alves wrote:
> * i386-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 i386_linux_new_fork as
> linux_nat_new_fork hook, and i386_forget_process as
> linux_nat_forget_process hook.
typo in the changelog: s/amd64/i386
Yufeng
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] [native x86 GNU/Linux] Access debug register mirror from the corresponding inferior.
2013-02-13 14:20 ` Yufeng Zhang
@ 2013-02-13 14:51 ` Pedro Alves
2013-02-13 15:14 ` Pedro Alves
1 sibling, 0 replies; 14+ messages in thread
From: Pedro Alves @ 2013-02-13 14:51 UTC (permalink / raw)
To: Yufeng Zhang; +Cc: gdb-patches
On 02/13/2013 02:19 PM, Yufeng Zhang wrote:
> On 02/12/13 12:35, Pedro Alves wrote:
>> * i386-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 i386_linux_new_fork as
>> linux_nat_new_fork hook, and i386_forget_process as
>> linux_nat_forget_process hook.
>
> typo in the changelog: s/amd64/i386
Thanks.
--
Pedro Alves
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] [native x86 GNU/Linux] Access debug register mirror from the corresponding inferior.
2013-02-12 16:50 ` Jan Kratochvil
@ 2013-02-13 15:04 ` Pedro Alves
0 siblings, 0 replies; 14+ messages in thread
From: Pedro Alves @ 2013-02-13 15:04 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 1397 bytes --]
On 02/12/2013 04:50 PM, Jan Kratochvil wrote:
> On Tue, 12 Feb 2013 13:35:59 +0100, Pedro Alves wrote:
>> On 02/11/2013 09:09 PM, Pedro Alves wrote:
>>> In a nutshell, we decouple the watchpoints code from inferiors, making
>>> it track target processes instead.
>
> It looks really cleaner than waht it was.
>
> I haven't found there any real bug.
Great.
> style: Here and on many other places should be pid_t.
Fixed.
>> -/* Per-inferior hook for register_inferior_data_with_cleanup. */
>> +struct i386_process_info *i386_process_list = NULL;
>
> Missing static.
Fixed.
>> +static struct i386_process_info *
>> +i386_find_process_pid (int pid)
>> {
>> - struct i386_inferior_data *inf_data = arg;
>> + struct i386_process_info *inf;
>
> style: The 'inf' name is confusing when it is not inferior.
>
Fixed.
>> +/* The method to call, if any, when a new fork is attached. */
>> +static void (*linux_nat_new_fork) (struct lwp_info *, int);
>
> style: The parameters could be named.
Fixed.
>> +/* Register a method to call whenever a process is killed or
>> + detached. */
>> +void linux_nat_set_forget_process (struct target_ops *, void (*) (int));
>
> style: Parameters could be named, I do not understand why to omit their names.
When in Rome... I've now added a typedef for the hook type, so the
param names are written only once.
Here's what I applied now.
Thanks.
[-- Attachment #2: debug_regs_state.diff --]
[-- Type: text/x-patch, Size: 37268 bytes --]
commit c49cac77254d8a84e2ecfaab4bbe547778f84045
Author: Pedro Alves <palves@redhat.com>
Date: Wed Feb 13 14:50:58 2013 +0000
[native x86 GNU/Linux] Access debug register mirror from the corresponding process.
While reviewing the native AArch64 patch, I noticed a problem:
On 02/06/2013 08:46 PM, Pedro Alves wrote:
>
>> > +static void
>> > +aarch64_linux_prepare_to_resume (struct lwp_info *lwp)
>> > +{
>> > + struct arch_lwp_info *info = lwp->arch_private;
>> > +
>> > + /* NULL means this is the main thread still going through the shell,
>> > + or, no watchpoint has been set yet. In that case, there's
>> > + nothing to do. */
>> > + if (info == NULL)
>> > + return;
>> > +
>> > + 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 ();
> Hmm. This is always fetching the debug_reg_state of
> the current inferior, but may not be the inferior of lwp.
> I see the same bug on x86. Sorry about that. I'll fix it.
A natural fix would be to make xxx_get_debug_reg_state take an
inferior argument, but that doesn't work because of the case where we
detach breakpoints/watchpoints from the child fork, at a time there's
no inferior for the child fork at all. We do a nasty hack in
i386_inferior_data_get, but that relies on all callers pointing the
current inferior to the correct inferior, which isn't actually being
done by all callers, and I don't think we want to enforce that -- deep
in the bowls of linux-nat.c, there are many cases we resume lwps
behind the scenes, and it's be better to not have that code rely on
global state (as it doesn't today).
The fix is to decouple the watchpoints code from inferiors, making it
track target processes instead. This way, we can freely keep track of
the watchpoint mirrors for these processes behind the core's back.
Checkpoints also play dirty tricks with swapping the process behind
the inferior, so they get special treatment too in the patch (which
just amounts to calling a new hook). Instead of the old hack in
i386_inferior_data_get, where we returned a copy of the current
inferior's debug registers mirror, as soon as we detect a fork in the
target, we copy the debug register mirror from the parent to the child
process.
I don't have an old kernel handy to test, but I stepped through gdb doing
the watchpoint removal in the fork child in the watchpoint-fork test
seeing that the debug registers end up cleared in the child.
I didn't find the need for linux_nat_iterate_watchpoint_lwps. If
we use plain iterate_over_lwps instead, what happens is that
when removing watchpoints, that iterate_over_lwps doesn't actually
iterate over anything, since the fork child is not added to the
lwp list until later, at detach time, in linux_child_follow_fork.
And if we don't iterate over that lwp, we don't mark its debug
registers as needing update. But linux_child_follow_fork takes
care of doing that explicitly:
child_lp = add_lwp (inferior_ptid);
child_lp->stopped = 1;
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);
so unless I'm missing something (quite possible) it ends up all
the same. But, the !detach-on-fork, and the "follow-fork child" paths
should also call linux_nat_new_thread, and they don't presently. It
seems to me in those cases we're not clearing debug regs correctly
when that's needed. Instead of copying that bit that works around
add_lwp bypassing the linux_nat_new_thread call, I thought it'd
be better to add an add_initial_lwp call to be used in the case we
really need to bypass linux_nat_new_thread, and make
add_lwp always call linux_nat_new_thread.
i386_cleanup_dregs is rewritten to forget about the current process
debug mirrors, which takes cares of other i386 ports. Only a couple
of extra tweaks here and there were needed, as some targets wheren't
actually calling i386_cleanup_dregs.
Tested on Fedora 17 x86_64 -m64/-m32.
GDBserver already fetches the i386_debug_reg_state from the right
process, and, it doesn't handle forks at all, so no fix is needed over
there.
gdb/
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.
(i386_linux_dr_set_control, i386_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.
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;
+}
+
\f
/* 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)
}
\f
+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;
+}
+
\f
/* 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);
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] [native x86 GNU/Linux] Access debug register mirror from the corresponding inferior.
2013-02-13 14:20 ` Yufeng Zhang
2013-02-13 14:51 ` Pedro Alves
@ 2013-02-13 15:14 ` Pedro Alves
2013-02-13 15:21 ` Marcus Shawcroft
1 sibling, 1 reply; 14+ messages in thread
From: Pedro Alves @ 2013-02-13 15:14 UTC (permalink / raw)
To: Yufeng Zhang; +Cc: Marcus Shawcroft, GDB Patches
Aarch64 people,
I'll send you an aarch64 version of this patch, unless you've
already started porting the necessary bits over.
I think the only difference on AArch64 will be this comment:
/* 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. */
Where I assume all AArch64 kernels zero the debug registers, so
that part of the comment gets dropped.
--
Pedro Alves
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] [native x86 GNU/Linux] Access debug register mirror from the corresponding inferior.
2013-02-13 15:14 ` Pedro Alves
@ 2013-02-13 15:21 ` Marcus Shawcroft
2013-02-13 16:02 ` [native AAarch64 GNU/Linux] Access debug register mirror from the corresponding process Pedro Alves
0 siblings, 1 reply; 14+ messages in thread
From: Marcus Shawcroft @ 2013-02-13 15:21 UTC (permalink / raw)
To: Pedro Alves; +Cc: Yufeng Zhang, Marcus Shawcroft, GDB Patches
> I'll send you an aarch64 version of this patch, unless you've
> already started porting the necessary bits over.
We were just about to get started... but if you have a patch in hand
that would be great!
> I think the only difference on AArch64 will be this comment:
> Where I assume all AArch64 kernels zero the debug registers, so
> that part of the comment gets dropped.
Yes.
Cheers
/Marcus
^ permalink raw reply [flat|nested] 14+ messages in thread
* [native AAarch64 GNU/Linux] Access debug register mirror from the corresponding process.
2013-02-13 15:21 ` Marcus Shawcroft
@ 2013-02-13 16:02 ` Pedro Alves
2013-02-13 18:57 ` Yufeng Zhang
0 siblings, 1 reply; 14+ messages in thread
From: Pedro Alves @ 2013-02-13 16:02 UTC (permalink / raw)
To: Marcus Shawcroft; +Cc: Yufeng Zhang, GDB Patches
[-- Attachment #1: Type: text/plain, Size: 534 bytes --]
On 02/13/2013 03:21 PM, Marcus Shawcroft wrote:
>> I'll send you an aarch64 version of this patch, unless you've
>> already started porting the necessary bits over.
>
> We were just about to get started... but if you have a patch in hand
> that would be great!
Here it is. Completely untested, of course. But hopefully not
too far off.
>> I think the only difference on AArch64 will be this comment:
>
>> Where I assume all AArch64 kernels zero the debug registers, so
>> that part of the comment gets dropped.
>
> Yes.
Ack.
[-- Attachment #2: aarch64.diff --]
[-- Type: text/x-patch, Size: 11953 bytes --]
commit e5fb92a75ff420be4f27b85b702c5732e9f18d59
Author: Pedro Alves <palves@redhat.com>
Date: Wed Feb 13 15:07:18 2013 +0000
[native AAarch64 GNU/Linux] Access debug register mirror from the corresponding process.
Port over the x86 changes to AArch64.
Completely untested.
2013-02-13 Pedro Alves <palves@redhat.com>
* aarch-linux-nat.c (aarch64_init_debug_reg_state): Delete.
(aarch64_inferior_data, struct aarch64_inferior_data):
Delete.
(struct aarch64_process_info): New.
(aarch64_process_list): New global.
(aarch64_find_process_pid, aarch64_add_process, aarch64_process_info_get):
New functions.
(aarch64_inferior_data_get): Delete.
(aarch64_process_info_get): New function.
(aarch64_forget_process): New function.
(aarch64_get_debug_reg_state): New parameter 'pid'. Reimplement.
(aarch64_linux_prepare_to_resume): Pass the lwp's pid to
aarch64_get_debug_reg_state.
(aarch64_linux_new_fork): New function.
(aarch64_linux_child_post_startup_inferior): Use
aarch64_forget_process instead of aarch64_init_debug_reg_state.
(aarch64_handle_breakpoint, aarch64_linux_insert_hw_breakpoint)
(aarch64_linux_remove_hw_breakpoint)
(aarch64_handle_aligned_watchpoint)
(aarch64_handle_unaligned_watchpoint)
(aarch64_linux_insert_watchpoint)
(aarch64_linux_remove_watchpoint)
(aarch64_linux_stopped_data_address): Adjust to pass the current
process id to aarch64_debug_reg_state.
(_initialize_aarch64_linux_nat): Install aarch64_linux_new_fork as
linux_nat_new_fork hook, and aarch64_forget_process as
linux_nat_forget_process hook.
diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c
index 507ba81..89055f4 100644
--- a/gdb/aarch64-linux-nat.c
+++ b/gdb/aarch64-linux-nat.c
@@ -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. */
@@ -655,7 +683,8 @@ aarch64_linux_prepare_to_resume (struct lwp_info *lwp)
|| DR_HAS_CHANGED (info->dr_changed_wp))
{
int tid = GET_LWP (lwp->ptid);
- 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 (lwp->ptid));
if (debug_hw_points)
fprintf_unfiltered (gdb_stdlog, "prepare_to_resume thread %d\n", tid);
@@ -688,6 +717,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 = i386_debug_reg_state (parent_pid);
+ child_state = i386_debug_reg_state (child_pid);
+ *child_state = *parent_state;
+}
\f
/* Called by libthread_db. Returns a pointer to the thread local
@@ -776,9 +831,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);
}
@@ -1132,7 +1185,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);
@@ -1161,8 +1214,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;
}
@@ -1187,8 +1245,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;
}
@@ -1200,7 +1263,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);
@@ -1219,7 +1283,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)
{
@@ -1283,8 +1348,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;
}
@@ -1310,8 +1380,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;
}
@@ -1374,7 +1449,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]);
@@ -1477,5 +1552,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);
}
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [native AAarch64 GNU/Linux] Access debug register mirror from the corresponding process.
2013-02-13 16:02 ` [native AAarch64 GNU/Linux] Access debug register mirror from the corresponding process Pedro Alves
@ 2013-02-13 18:57 ` Yufeng Zhang
2013-02-13 19:04 ` Pedro Alves
0 siblings, 1 reply; 14+ messages in thread
From: Yufeng Zhang @ 2013-02-13 18:57 UTC (permalink / raw)
To: Pedro Alves; +Cc: Marcus Shawcroft, GDB Patches
[-- Attachment #1: Type: text/plain, Size: 588 bytes --]
On 02/13/13 16:01, Pedro Alves wrote:
> On 02/13/2013 03:21 PM, Marcus Shawcroft wrote:
>>> I'll send you an aarch64 version of this patch, unless you've
>>> already started porting the necessary bits over.
>>
>> We were just about to get started... but if you have a patch in hand
>> that would be great!
>
> Here it is. Completely untested, of course. But hopefully not
> too far off.
Not far off at all; thanks! I have tested your patch and made some
further changes; please find the attached patch. The two patches
together seem to be working.
Thanks,
Yufeng
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: aarch64-fix.diff --]
[-- Type: text/x-patch; name=aarch64-fix.diff, Size: 2038 bytes --]
diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c
index 89055f4..846f156 100644
--- a/gdb/aarch64-linux-nat.c
+++ b/gdb/aarch64-linux-nat.c
@@ -336,7 +336,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.
@@ -410,12 +410,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. */
@@ -739,8 +739,8 @@ aarch64_linux_new_fork (struct lwp_info *parent, pid_t child_pid)
removed together. */
parent_pid = ptid_get_pid (parent->ptid);
- parent_state = i386_debug_reg_state (parent_pid);
- child_state = i386_debug_reg_state (child_pid);
+ parent_state = aarch64_get_debug_reg_state (parent_pid);
+ child_state = aarch64_get_debug_reg_state (child_pid);
*child_state = *parent_state;
}
\f
@@ -1540,10 +1540,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;
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [native AAarch64 GNU/Linux] Access debug register mirror from the corresponding process.
2013-02-13 18:57 ` Yufeng Zhang
@ 2013-02-13 19:04 ` Pedro Alves
2013-02-14 10:13 ` Yufeng Zhang
0 siblings, 1 reply; 14+ messages in thread
From: Pedro Alves @ 2013-02-13 19:04 UTC (permalink / raw)
To: Yufeng Zhang; +Cc: Marcus Shawcroft, GDB Patches
On 02/13/2013 06:56 PM, Yufeng Zhang wrote:
> On 02/13/13 16:01, Pedro Alves wrote:
>> On 02/13/2013 03:21 PM, Marcus Shawcroft wrote:
>>>> I'll send you an aarch64 version of this patch, unless you've
>>>> already started porting the necessary bits over.
>>>
>>> We were just about to get started... but if you have a patch in hand
>>> that would be great!
>>
>> Here it is. Completely untested, of course. But hopefully not
>> too far off.
>
> Not far off at all; thanks! I have tested your patch and made some further changes; please find the attached patch. The two patches together seem to be working.
Those changes look fine. Please merge them, and go ahead
post/commit the resulting patch.
--
Pedro Alves
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [native AAarch64 GNU/Linux] Access debug register mirror from the corresponding process.
2013-02-13 19:04 ` Pedro Alves
@ 2013-02-14 10:13 ` Yufeng Zhang
0 siblings, 0 replies; 14+ messages in thread
From: Yufeng Zhang @ 2013-02-14 10:13 UTC (permalink / raw)
To: Pedro Alves; +Cc: Marcus Shawcroft, GDB Patches
[-- Attachment #1: Type: text/plain, Size: 2440 bytes --]
On 02/13/13 19:03, Pedro Alves wrote:
> On 02/13/2013 06:56 PM, Yufeng Zhang wrote:
>> On 02/13/13 16:01, Pedro Alves wrote:
>>> On 02/13/2013 03:21 PM, Marcus Shawcroft wrote:
>>>>> I'll send you an aarch64 version of this patch, unless you've
>>>>> already started porting the necessary bits over.
>>>>
>>>> We were just about to get started... but if you have a patch in hand
>>>> that would be great!
>>>
>>> Here it is. Completely untested, of course. But hopefully not
>>> too far off.
>>
>> Not far off at all; thanks! I have tested your patch and made some further changes; please find the attached patch. The two patches together seem to be working.
>
> Those changes look fine. Please merge them, and go ahead
> post/commit the resulting patch.
>
Thanks. The attached is the merged patch. I'll commit it in a couple
of hours if no more comment is received.
Thanks,
Yufeng
2013-02-14 Pedro Alves <palves@redhat.com>
Yufeng Zhang <yufeng.zhang@arm.com>
* aarch64-linux-nat.c (aarch64_init_debug_reg_state): Delete.
(aarch64_inferior_data, struct aarch64_inferior_data):
Delete.
(struct aarch64_process_info): New.
(aarch64_process_list): New global.
(aarch64_find_process_pid, aarch64_add_process)
(aarch64_process_info_get): New functions.
(aarch64_inferior_data_get): Delete.
(aarch64_process_info_get): New function.
(aarch64_forget_process): New function.
(aarch64_get_debug_reg_state): New parameter 'pid'. Reimplement.
(aarch64_linux_prepare_to_resume): Pass the lwp's pid to
aarch64_get_debug_reg_state.
(aarch64_notify_debug_reg_change): Use iterate_over_lwps
instead of linux_nat_iterate_watchpoint_lwps.
(aarch64_linux_new_fork): New function.
(aarch64_linux_child_post_startup_inferior): Use
aarch64_forget_process instead of aarch64_init_debug_reg_state.
(aarch64_handle_breakpoint, aarch64_linux_insert_hw_breakpoint)
(aarch64_linux_remove_hw_breakpoint)
(aarch64_handle_aligned_watchpoint)
(aarch64_handle_unaligned_watchpoint)
(aarch64_linux_insert_watchpoint)
(aarch64_linux_remove_watchpoint)
(aarch64_linux_stopped_data_address): Adjust to pass the current
process id to aarch64_debug_reg_state.
(_initialize_aarch64_linux_nat): Install aarch64_linux_new_fork as
linux_nat_new_fork hook, and aarch64_forget_process as
linux_nat_forget_process hook; remove the call to
register_inferior_data_with_cleanup.
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: aarch64-dregs.patch --]
[-- Type: text/x-patch; name=aarch64-dregs.patch, Size: 12030 bytes --]
diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c
index 507ba81..846f156 100644
--- a/gdb/aarch64-linux-nat.c
+++ b/gdb/aarch64-linux-nat.c
@@ -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. */
@@ -308,7 +336,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.
@@ -382,12 +410,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. */
@@ -655,7 +683,8 @@ aarch64_linux_prepare_to_resume (struct lwp_info *lwp)
|| DR_HAS_CHANGED (info->dr_changed_wp))
{
int tid = GET_LWP (lwp->ptid);
- 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 (lwp->ptid));
if (debug_hw_points)
fprintf_unfiltered (gdb_stdlog, "prepare_to_resume thread %d\n", tid);
@@ -688,6 +717,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;
+}
\f
/* Called by libthread_db. Returns a pointer to the thread local
@@ -776,9 +831,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);
}
@@ -1132,7 +1185,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);
@@ -1161,8 +1214,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;
}
@@ -1187,8 +1245,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;
}
@@ -1200,7 +1263,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);
@@ -1219,7 +1283,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)
{
@@ -1283,8 +1348,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;
}
@@ -1310,8 +1380,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;
}
@@ -1374,7 +1449,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]);
@@ -1465,10 +1540,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;
@@ -1477,5 +1548,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);
}
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2013-02-14 10:13 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-02-07 16:33 [PATCH] [native x86 GNU/Linux] Access debug register mirror from the corresponding inferior Pedro Alves
2013-02-07 16:59 ` Jan Kratochvil
2013-02-11 21:10 ` Pedro Alves
2013-02-12 12:36 ` Pedro Alves
2013-02-12 16:50 ` Jan Kratochvil
2013-02-13 15:04 ` Pedro Alves
2013-02-13 14:20 ` Yufeng Zhang
2013-02-13 14:51 ` Pedro Alves
2013-02-13 15:14 ` Pedro Alves
2013-02-13 15:21 ` Marcus Shawcroft
2013-02-13 16:02 ` [native AAarch64 GNU/Linux] Access debug register mirror from the corresponding process Pedro Alves
2013-02-13 18:57 ` Yufeng Zhang
2013-02-13 19:04 ` Pedro Alves
2013-02-14 10:13 ` Yufeng Zhang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox