Skip to content

Commit

Permalink
detach and breakpoint removal
Browse files Browse the repository at this point in the history
A following patch will add a testcase that has a number of threads
constantly stepping over a breakpoint, and then has GDB detach the
process.  That testcase sometimes fails with the inferior crashing
with SIGTRAP after the detach because of the bug fixed by this patch,
when tested with the native target.

The problem is that target_detach removes breakpoints from the target
immediately, and that does not work with the native GNU/Linux target
(and probably no other native target) currently.  The test wouldn't
fail with this issue when testing against gdbserver, because gdbserver
does allow accessing memory while the current thread is running, by
transparently pausing all threads temporarily, without GDB noticing.
Implementing that in gdbserver was a lot of work, so I'm not looking
forward right now to do the same in the native target.  Instead, I
came up with a simpler solution -- push the breakpoints removal down
to the targets.  The Linux target conveniently already pauses all
threads before detaching them, since PTRACE_DETACH only works with
stopped threads, so we move removing breakpoints to after that.  Only
the remote and GNU/Linux targets support support async execution, so
no other target should really need this.

gdb/ChangeLog:

	* linux-nat.c (linux_nat_target::detach): Remove breakpoints
	here...
	* remote.c (remote_target::remote_detach_1): ... and here ...
	* target.c (target_detach): ... instead of here.
	* target.h (target_ops::detach): Add comment.
  • Loading branch information
palves committed Feb 3, 2021
1 parent 8ff5313 commit e87f0fe
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 9 deletions.
8 changes: 8 additions & 0 deletions gdb/ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
2021-02-03 Pedro Alves <pedro@palves.net>

* linux-nat.c (linux_nat_target::detach): Remove breakpoints
here...
* remote.c (remote_target::remote_detach_1): ... and here ...
* target.c (target_detach): ... instead of here.
* target.h (target_ops::detach): Add comment.

2021-02-03 Pedro Alves <pedro@palves.net>

* infrun.c (struct wait_one_event): Move higher up.
Expand Down
5 changes: 5 additions & 0 deletions gdb/linux-nat.c
Original file line number Diff line number Diff line change
Expand Up @@ -1456,6 +1456,11 @@ linux_nat_target::detach (inferior *inf, int from_tty)
they're no longer running. */
iterate_over_lwps (ptid_t (pid), stop_wait_callback);

/* We can now safely remove breakpoints. We don't this in earlier
in common code because this target doesn't currently support
writing memory while the inferior is running. */
remove_breakpoints_inf (current_inferior ());

iterate_over_lwps (ptid_t (pid), detach_callback);

/* Only the initial process should be left right now. */
Expand Down
10 changes: 10 additions & 0 deletions gdb/remote.c
Original file line number Diff line number Diff line change
Expand Up @@ -5800,6 +5800,16 @@ remote_target::remote_detach_1 (inferior *inf, int from_tty)

target_announce_detach (from_tty);

if (!gdbarch_has_global_breakpoints (target_gdbarch ()))
{
/* If we're in breakpoints-always-inserted mode, or the inferior
is running, we have to remove breakpoints before detaching.
We don't do this in common code instead because not all
targets support removing breakpoints while the target is
running. The remote target / gdbserver does, though. */
remove_breakpoints_inf (current_inferior ());
}

/* Tell the remote target to detach. */
remote_detach_pid (pid);

Expand Down
9 changes: 0 additions & 9 deletions gdb/target.c
Original file line number Diff line number Diff line change
Expand Up @@ -1949,15 +1949,6 @@ target_detach (inferior *inf, int from_tty)
assertion. */
gdb_assert (inf == current_inferior ());

if (gdbarch_has_global_breakpoints (target_gdbarch ()))
/* Don't remove global breakpoints here. They're removed on
disconnection from the target. */
;
else
/* If we're in breakpoints-always-inserted mode, have to remove
breakpoints before detaching. */
remove_breakpoints_inf (current_inferior ());

prepare_for_detach ();

/* Hold a strong reference because detaching may unpush the
Expand Down
7 changes: 7 additions & 0 deletions gdb/target.h
Original file line number Diff line number Diff line change
Expand Up @@ -470,8 +470,15 @@ struct target_ops
virtual void attach (const char *, int);
virtual void post_attach (int)
TARGET_DEFAULT_IGNORE ();

/* Detaches from the inferior. Note that on targets that support
async execution (i.e., targets where it is possible to detach
from programs with threads running), the target is responsible
for removing breakpoints from the program before the actual
detach, otherwise the program dies when it hits one. */
virtual void detach (inferior *, int)
TARGET_DEFAULT_IGNORE ();

virtual void disconnect (const char *, int)
TARGET_DEFAULT_NORETURN (tcomplain ());
virtual void resume (ptid_t,
Expand Down

0 comments on commit e87f0fe

Please sign in to comment.