128 lines
3.5 KiB
Diff
128 lines
3.5 KiB
Diff
|
|
From 4c4c339585b523167e336d9b379fe4c00dc94dca Mon Sep 17 00:00:00 2001
|
||
|
|
From: "Dmitry V. Levin" <ldv@strace.io>
|
||
|
|
Date: Sun, 26 Nov 2023 08:00:00 +0000
|
||
|
|
Subject: [PATCH] Factor out interrupt_or_stop() from detach()
|
||
|
|
|
||
|
|
* src/strace.c (interrupt_or_stop): New function.
|
||
|
|
(detach): Use it.
|
||
|
|
|
||
|
|
Reference: https://github.com/strace/strace/commit/4c4c339585b523167e336d9b379fe4c00dc94dca
|
||
|
|
Conflict: NA
|
||
|
|
---
|
||
|
|
src/strace.c | 49 ++++++++++++++++++++++++++++---------------------
|
||
|
|
1 file changed, 28 insertions(+), 21 deletions(-)
|
||
|
|
|
||
|
|
diff --git a/src/strace.c b/src/strace.c
|
||
|
|
index 351842792..385cbaa72 100644
|
||
|
|
--- a/src/strace.c
|
||
|
|
+++ b/src/strace.c
|
||
|
|
@@ -1158,17 +1158,10 @@ droptcb_verbose(struct tcb *tcp)
|
||
|
|
droptcb(tcp);
|
||
|
|
}
|
||
|
|
|
||
|
|
-/* Detach traced process.
|
||
|
|
- * Never call DETACH twice on the same process as both unattached and
|
||
|
|
- * attached-unstopped processes give the same ESRCH. For unattached process we
|
||
|
|
- * would SIGSTOP it and wait for its SIGSTOP notification forever.
|
||
|
|
- */
|
||
|
|
-static void
|
||
|
|
-detach(struct tcb *tcp)
|
||
|
|
+/* Returns true when the tracee has to be waited for. */
|
||
|
|
+static bool
|
||
|
|
+interrupt_or_stop(struct tcb *tcp)
|
||
|
|
{
|
||
|
|
- int error;
|
||
|
|
- int status;
|
||
|
|
-
|
||
|
|
/*
|
||
|
|
* Linux wrongly insists the child be stopped
|
||
|
|
* before detaching. Arghh. We go through hoops
|
||
|
|
@@ -1176,24 +1169,24 @@ detach(struct tcb *tcp)
|
||
|
|
*/
|
||
|
|
|
||
|
|
if (!(tcp->flags & TCB_ATTACHED))
|
||
|
|
- goto drop;
|
||
|
|
+ return false;
|
||
|
|
|
||
|
|
/* We attached but possibly didn't see the expected SIGSTOP.
|
||
|
|
* We must catch exactly one as otherwise the detached process
|
||
|
|
* would be left stopped (process state T).
|
||
|
|
*/
|
||
|
|
if (tcp->flags & TCB_IGNORE_ONE_SIGSTOP)
|
||
|
|
- goto wait_loop;
|
||
|
|
+ return true;
|
||
|
|
|
||
|
|
- error = ptrace(PTRACE_DETACH, tcp->pid, 0, 0);
|
||
|
|
+ int error = ptrace(PTRACE_DETACH, tcp->pid, 0, 0);
|
||
|
|
if (!error) {
|
||
|
|
/* On a clear day, you can see forever. */
|
||
|
|
- goto drop;
|
||
|
|
+ return false;
|
||
|
|
}
|
||
|
|
if (errno != ESRCH) {
|
||
|
|
/* Shouldn't happen. */
|
||
|
|
perror_func_msg("ptrace(PTRACE_DETACH,%u)", tcp->pid);
|
||
|
|
- goto drop;
|
||
|
|
+ return false;
|
||
|
|
}
|
||
|
|
/* ESRCH: process is either not stopped or doesn't exist. */
|
||
|
|
if (my_tkill(tcp->pid, 0) < 0) {
|
||
|
|
@@ -1201,7 +1194,7 @@ detach(struct tcb *tcp)
|
||
|
|
/* Shouldn't happen. */
|
||
|
|
perror_func_msg("tkill(%u,0)", tcp->pid);
|
||
|
|
/* else: process doesn't exist. */
|
||
|
|
- goto drop;
|
||
|
|
+ return false;
|
||
|
|
}
|
||
|
|
/* Process is not stopped, need to stop it. */
|
||
|
|
if (use_seize) {
|
||
|
|
@@ -1213,26 +1206,40 @@ detach(struct tcb *tcp)
|
||
|
|
*/
|
||
|
|
error = ptrace(PTRACE_INTERRUPT, tcp->pid, 0, 0);
|
||
|
|
if (!error)
|
||
|
|
- goto wait_loop;
|
||
|
|
+ return true;
|
||
|
|
if (errno != ESRCH)
|
||
|
|
perror_func_msg("ptrace(PTRACE_INTERRUPT,%u)", tcp->pid);
|
||
|
|
} else {
|
||
|
|
error = my_tkill(tcp->pid, SIGSTOP);
|
||
|
|
if (!error)
|
||
|
|
- goto wait_loop;
|
||
|
|
+ return true;
|
||
|
|
if (errno != ESRCH)
|
||
|
|
perror_func_msg("tkill(%u,SIGSTOP)", tcp->pid);
|
||
|
|
}
|
||
|
|
+
|
||
|
|
/* Either process doesn't exist, or some weird error. */
|
||
|
|
- goto drop;
|
||
|
|
+ return false;
|
||
|
|
+}
|
||
|
|
|
||
|
|
- wait_loop:
|
||
|
|
- /* We end up here in three cases:
|
||
|
|
+/* Detach traced process.
|
||
|
|
+ * Never call DETACH twice on the same process as both unattached and
|
||
|
|
+ * attached-unstopped processes give the same ESRCH. For unattached process we
|
||
|
|
+ * would SIGSTOP it and wait for its SIGSTOP notification forever.
|
||
|
|
+ */
|
||
|
|
+static void
|
||
|
|
+detach(struct tcb *tcp)
|
||
|
|
+{
|
||
|
|
+ if (!interrupt_or_stop(tcp))
|
||
|
|
+ goto drop;
|
||
|
|
+
|
||
|
|
+ /*
|
||
|
|
+ * We end up here in three cases:
|
||
|
|
* 1. We sent PTRACE_INTERRUPT (use_seize case)
|
||
|
|
* 2. We sent SIGSTOP (!use_seize)
|
||
|
|
* 3. Attach SIGSTOP was already pending (TCB_IGNORE_ONE_SIGSTOP set)
|
||
|
|
*/
|
||
|
|
for (;;) {
|
||
|
|
+ int status;
|
||
|
|
unsigned int sig;
|
||
|
|
if (waitpid(tcp->pid, &status, __WALL) < 0) {
|
||
|
|
if (errno == EINTR)
|
||
|
|
--
|
||
|
|
2.33.0
|
||
|
|
|