1
v1: https://lore.kernel.org/qemu-devel/20241024200031.80327-1-iii@linux.ibm.com/
1
v2: https://lore.kernel.org/qemu-devel/20241106223629.2608-1-iii@linux.ibm.com/
2
v1 -> v2: Rebase, fix conflicts with the QEMU_RTSIG_MAP patch.
2
v2 -> v3: Rebase.
3
Use qemu_get_thread_id() for %d (Helge, Richard, Warner).
4
Add R-bs, except for the Richard's one on 4/8, since
5
conflict resolution caused a noticeable change.
6
Patches that need review:
3
Patches that need review:
7
- [PATCH 2/8] gdbstub: Try unlinking the unix socket before binding
4
- [PATCH 2/8] gdbstub: Try unlinking the unix socket before binding
8
- [PATCH 4/8] user: Introduce host_interrupt_signal # linux part
5
- [PATCH 4/8] user: Introduce host_interrupt_signal # linux part
9
- [PATCH 6/8] gdbstub: Allow late attachment
6
- [PATCH 6/8] gdbstub: Allow late attachment
10
- [PATCH 7/8] docs/user: Document the %d placeholder and suspend=n QEMU_GDB features
7
- [PATCH 7/8] docs/user: Document the %d placeholder and suspend=n QEMU_GDB features
11
- [PATCH 8/8] tests/tcg: Add late gdbstub attach test
8
- [PATCH 8/8] tests/tcg: Add late gdbstub attach test
9
10
v1: https://lore.kernel.org/qemu-devel/20241024200031.80327-1-iii@linux.ibm.com/
11
v1 -> v2: Rebase, fix conflicts with the QEMU_RTSIG_MAP patch.
12
Use qemu_get_thread_id() for %d (Helge, Richard, Warner).
13
Add R-bs, except for the Richard's one on 4/8, since
14
conflict resolution caused a noticeable change.
12
15
13
Hi,
16
Hi,
14
17
15
This series adds the ability to attach GDB to a running qemu-user
18
This series adds the ability to attach GDB to a running qemu-user
16
instance. This is useful for debugging multi-process apps.
19
instance. This is useful for debugging multi-process apps.
...
...
32
patch 8 is a test. I tested this series on Linux and only
35
patch 8 is a test. I tested this series on Linux and only
33
compile-tested on the BSDs.
36
compile-tested on the BSDs.
34
37
35
Best regards,
38
Best regards,
36
Ilya
39
Ilya
37
38
[1] https://lore.kernel.org/qemu-devel/94ebebf2-e775-4fd2-8fcf-921610261a7e@linaro.org/
39
40
40
Ilya Leoshkevich (8):
41
Ilya Leoshkevich (8):
41
gdbstub: Allow the %d placeholder in the socket path
42
gdbstub: Allow the %d placeholder in the socket path
42
gdbstub: Try unlinking the unix socket before binding
43
gdbstub: Try unlinking the unix socket before binding
43
user: Introduce user/signal.h
44
user: Introduce user/signal.h
...
...
diff view generated by jsdifflib
1
Just like for QEMU_LOG_FILENAME, replace %d with PID in the GDB socket
1
Just like for QEMU_LOG_FILENAME, replace %d with PID in the GDB socket
2
path. This allows running multi-process applications with, e.g.,
2
path. This allows running multi-process applications with, e.g.,
3
export QEMU_GDB=/tmp/qemu-%d.sock. Currently this is not possible,
3
export QEMU_GDB=/tmp/qemu-%d.sock. Currently this is not possible,
4
since the first process will cause the subsequent ones to fail due to
4
since the first process will cause the subsequent ones to fail due to
5
not being able to bind() the GDB socket.
5
not being able to bind() the GDB socket.
6
6
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
8
Reviewed-by: Warner Losh <imp@bsdimp.com>
8
Reviewed-by: Warner Losh <imp@bsdimp.com>
9
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
9
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
10
---
10
---
11
gdbstub/user.c | 10 ++++++++++
11
gdbstub/user.c | 10 ++++++++++
12
1 file changed, 10 insertions(+)
12
1 file changed, 10 insertions(+)
13
13
14
diff --git a/gdbstub/user.c b/gdbstub/user.c
14
diff --git a/gdbstub/user.c b/gdbstub/user.c
15
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
16
--- a/gdbstub/user.c
16
--- a/gdbstub/user.c
17
+++ b/gdbstub/user.c
17
+++ b/gdbstub/user.c
18
@@ -XXX,XX +XXX,XX @@ static bool gdb_accept_socket(int gdb_fd)
18
@@ -XXX,XX +XXX,XX @@ static bool gdb_accept_socket(int gdb_fd)
19
19
20
static int gdbserver_open_socket(const char *path)
20
static int gdbserver_open_socket(const char *path)
21
{
21
{
22
+ g_autoptr(GString) buf = g_string_new("");
22
+ g_autoptr(GString) buf = g_string_new("");
23
struct sockaddr_un sockaddr = {};
23
struct sockaddr_un sockaddr = {};
24
+ char *pid_placeholder;
24
+ char *pid_placeholder;
25
int fd, ret;
25
int fd, ret;
26
26
27
+ pid_placeholder = strstr(path, "%d");
27
+ pid_placeholder = strstr(path, "%d");
28
+ if (pid_placeholder != NULL) {
28
+ if (pid_placeholder != NULL) {
29
+ g_string_append_len(buf, path, pid_placeholder - path);
29
+ g_string_append_len(buf, path, pid_placeholder - path);
30
+ g_string_append_printf(buf, "%d", qemu_get_thread_id());
30
+ g_string_append_printf(buf, "%d", qemu_get_thread_id());
31
+ g_string_append(buf, pid_placeholder + 2);
31
+ g_string_append(buf, pid_placeholder + 2);
32
+ path = buf->str;
32
+ path = buf->str;
33
+ }
33
+ }
34
+
34
+
35
fd = socket(AF_UNIX, SOCK_STREAM, 0);
35
fd = socket(AF_UNIX, SOCK_STREAM, 0);
36
if (fd < 0) {
36
if (fd < 0) {
37
perror("create socket");
37
perror("create socket");
38
--
38
--
39
2.47.0
39
2.47.0
diff view generated by jsdifflib
1
In case an emulated process execve()s another emulated process, bind()
1
In case an emulated process execve()s another emulated process, bind()
2
will fail, because the socket already exists. So try deleting it.
2
will fail, because the socket already exists. So try deleting it.
3
3
4
Note that it is not possible to handle this in do_execv(): deleting
4
Note that it is not possible to handle this in do_execv(): deleting
5
gdbserver_user_state.socket_path before safe_execve() is not correct,
5
gdbserver_user_state.socket_path before safe_execve() is not correct,
6
because the latter may fail, and afterwards we may lose control.
6
because the latter may fail, and afterwards we may lose control.
7
7
8
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
8
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
9
---
9
---
10
gdbstub/user.c | 1 +
10
gdbstub/user.c | 1 +
11
1 file changed, 1 insertion(+)
11
1 file changed, 1 insertion(+)
12
12
13
diff --git a/gdbstub/user.c b/gdbstub/user.c
13
diff --git a/gdbstub/user.c b/gdbstub/user.c
14
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
15
--- a/gdbstub/user.c
15
--- a/gdbstub/user.c
16
+++ b/gdbstub/user.c
16
+++ b/gdbstub/user.c
17
@@ -XXX,XX +XXX,XX @@ static int gdbserver_open_socket(const char *path)
17
@@ -XXX,XX +XXX,XX @@ static int gdbserver_open_socket(const char *path)
18
18
19
sockaddr.sun_family = AF_UNIX;
19
sockaddr.sun_family = AF_UNIX;
20
pstrcpy(sockaddr.sun_path, sizeof(sockaddr.sun_path) - 1, path);
20
pstrcpy(sockaddr.sun_path, sizeof(sockaddr.sun_path) - 1, path);
21
+ unlink(sockaddr.sun_path);
21
+ unlink(sockaddr.sun_path);
22
ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
22
ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
23
if (ret < 0) {
23
if (ret < 0) {
24
perror("bind socket");
24
perror("bind socket");
25
--
25
--
26
2.47.0
26
2.47.0
diff view generated by jsdifflib
1
gdbstub needs target_to_host_signal(), so move its declaration to a
1
gdbstub needs target_to_host_signal(), so move its declaration to a
2
public header.
2
public header.
3
3
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
Reviewed-by: Warner Losh <imp@bsdimp.com>
5
Reviewed-by: Warner Losh <imp@bsdimp.com>
6
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
6
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
7
---
7
---
8
bsd-user/signal-common.h | 1 -
8
bsd-user/signal-common.h | 1 -
9
bsd-user/signal.c | 1 +
9
bsd-user/signal.c | 1 +
10
include/user/signal.h | 23 +++++++++++++++++++++++
10
include/user/signal.h | 23 +++++++++++++++++++++++
11
linux-user/signal-common.h | 1 -
11
linux-user/signal-common.h | 1 -
12
linux-user/signal.c | 1 +
12
linux-user/signal.c | 1 +
13
linux-user/syscall.c | 1 +
13
linux-user/syscall.c | 1 +
14
6 files changed, 26 insertions(+), 2 deletions(-)
14
6 files changed, 26 insertions(+), 2 deletions(-)
15
create mode 100644 include/user/signal.h
15
create mode 100644 include/user/signal.h
16
16
17
diff --git a/bsd-user/signal-common.h b/bsd-user/signal-common.h
17
diff --git a/bsd-user/signal-common.h b/bsd-user/signal-common.h
18
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
19
--- a/bsd-user/signal-common.h
19
--- a/bsd-user/signal-common.h
20
+++ b/bsd-user/signal-common.h
20
+++ b/bsd-user/signal-common.h
21
@@ -XXX,XX +XXX,XX @@ void process_pending_signals(CPUArchState *env);
21
@@ -XXX,XX +XXX,XX @@ void process_pending_signals(CPUArchState *env);
22
void queue_signal(CPUArchState *env, int sig, int si_type,
22
void queue_signal(CPUArchState *env, int sig, int si_type,
23
target_siginfo_t *info);
23
target_siginfo_t *info);
24
void signal_init(void);
24
void signal_init(void);
25
-int target_to_host_signal(int sig);
25
-int target_to_host_signal(int sig);
26
void target_to_host_sigset(sigset_t *d, const target_sigset_t *s);
26
void target_to_host_sigset(sigset_t *d, const target_sigset_t *s);
27
27
28
/*
28
/*
29
diff --git a/bsd-user/signal.c b/bsd-user/signal.c
29
diff --git a/bsd-user/signal.c b/bsd-user/signal.c
30
index XXXXXXX..XXXXXXX 100644
30
index XXXXXXX..XXXXXXX 100644
31
--- a/bsd-user/signal.c
31
--- a/bsd-user/signal.c
32
+++ b/bsd-user/signal.c
32
+++ b/bsd-user/signal.c
33
@@ -XXX,XX +XXX,XX @@
33
@@ -XXX,XX +XXX,XX @@
34
#include "qemu/log.h"
34
#include "qemu/log.h"
35
#include "qemu.h"
35
#include "qemu.h"
36
#include "exec/page-protection.h"
36
#include "exec/page-protection.h"
37
+#include "user/signal.h"
37
+#include "user/signal.h"
38
#include "user/tswap-target.h"
38
#include "user/tswap-target.h"
39
#include "gdbstub/user.h"
39
#include "gdbstub/user.h"
40
#include "signal-common.h"
40
#include "signal-common.h"
41
diff --git a/include/user/signal.h b/include/user/signal.h
41
diff --git a/include/user/signal.h b/include/user/signal.h
42
new file mode 100644
42
new file mode 100644
43
index XXXXXXX..XXXXXXX
43
index XXXXXXX..XXXXXXX
44
--- /dev/null
44
--- /dev/null
45
+++ b/include/user/signal.h
45
+++ b/include/user/signal.h
46
@@ -XXX,XX +XXX,XX @@
46
@@ -XXX,XX +XXX,XX @@
47
+/*
47
+/*
48
+ * Signal-related declarations.
48
+ * Signal-related declarations.
49
+ *
49
+ *
50
+ * SPDX-License-Identifier: GPL-2.0-or-later
50
+ * SPDX-License-Identifier: GPL-2.0-or-later
51
+ */
51
+ */
52
+#ifndef USER_SIGNAL_H
52
+#ifndef USER_SIGNAL_H
53
+#define USER_SIGNAL_H
53
+#define USER_SIGNAL_H
54
+
54
+
55
+#ifndef CONFIG_USER_ONLY
55
+#ifndef CONFIG_USER_ONLY
56
+#error Cannot include this header from system emulation
56
+#error Cannot include this header from system emulation
57
+#endif
57
+#endif
58
+
58
+
59
+/**
59
+/**
60
+ * target_to_host_signal:
60
+ * target_to_host_signal:
61
+ * @sig: target signal.
61
+ * @sig: target signal.
62
+ *
62
+ *
63
+ * On success, return the host signal between 0 (inclusive) and NSIG
63
+ * On success, return the host signal between 0 (inclusive) and NSIG
64
+ * (exclusive) corresponding to the target signal @sig. Return any other value
64
+ * (exclusive) corresponding to the target signal @sig. Return any other value
65
+ * on failure.
65
+ * on failure.
66
+ */
66
+ */
67
+int target_to_host_signal(int sig);
67
+int target_to_host_signal(int sig);
68
+
68
+
69
+#endif
69
+#endif
70
diff --git a/linux-user/signal-common.h b/linux-user/signal-common.h
70
diff --git a/linux-user/signal-common.h b/linux-user/signal-common.h
71
index XXXXXXX..XXXXXXX 100644
71
index XXXXXXX..XXXXXXX 100644
72
--- a/linux-user/signal-common.h
72
--- a/linux-user/signal-common.h
73
+++ b/linux-user/signal-common.h
73
+++ b/linux-user/signal-common.h
74
@@ -XXX,XX +XXX,XX @@ void queue_signal(CPUArchState *env, int sig, int si_type,
74
@@ -XXX,XX +XXX,XX @@ void queue_signal(CPUArchState *env, int sig, int si_type,
75
target_siginfo_t *info);
75
target_siginfo_t *info);
76
void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info);
76
void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info);
77
void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo);
77
void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo);
78
-int target_to_host_signal(int sig);
78
-int target_to_host_signal(int sig);
79
int host_to_target_signal(int sig);
79
int host_to_target_signal(int sig);
80
long do_sigreturn(CPUArchState *env);
80
long do_sigreturn(CPUArchState *env);
81
long do_rt_sigreturn(CPUArchState *env);
81
long do_rt_sigreturn(CPUArchState *env);
82
diff --git a/linux-user/signal.c b/linux-user/signal.c
82
diff --git a/linux-user/signal.c b/linux-user/signal.c
83
index XXXXXXX..XXXXXXX 100644
83
index XXXXXXX..XXXXXXX 100644
84
--- a/linux-user/signal.c
84
--- a/linux-user/signal.c
85
+++ b/linux-user/signal.c
85
+++ b/linux-user/signal.c
86
@@ -XXX,XX +XXX,XX @@
86
@@ -XXX,XX +XXX,XX @@
87
#include "signal-common.h"
87
#include "signal-common.h"
88
#include "host-signal.h"
88
#include "host-signal.h"
89
#include "user/safe-syscall.h"
89
#include "user/safe-syscall.h"
90
+#include "user/signal.h"
90
+#include "user/signal.h"
91
#include "tcg/tcg.h"
91
#include "tcg/tcg.h"
92
92
93
/* target_siginfo_t must fit in gdbstub's siginfo save area. */
93
/* target_siginfo_t must fit in gdbstub's siginfo save area. */
94
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
94
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
95
index XXXXXXX..XXXXXXX 100644
95
index XXXXXXX..XXXXXXX 100644
96
--- a/linux-user/syscall.c
96
--- a/linux-user/syscall.c
97
+++ b/linux-user/syscall.c
97
+++ b/linux-user/syscall.c
98
@@ -XXX,XX +XXX,XX @@
98
@@ -XXX,XX +XXX,XX @@
99
#include "loader.h"
99
#include "loader.h"
100
#include "user-mmap.h"
100
#include "user-mmap.h"
101
#include "user/safe-syscall.h"
101
#include "user/safe-syscall.h"
102
+#include "user/signal.h"
102
+#include "user/signal.h"
103
#include "qemu/guest-random.h"
103
#include "qemu/guest-random.h"
104
#include "qemu/selfmap.h"
104
#include "qemu/selfmap.h"
105
#include "user/syscall-trace.h"
105
#include "user/syscall-trace.h"
106
--
106
--
107
2.47.0
107
2.47.0
diff view generated by jsdifflib
1
Attaching to the gdbstub of a running process requires stopping its
1
Attaching to the gdbstub of a running process requires stopping its
2
threads. For threads that run on a CPU, cpu_exit() is enough, but the
2
threads. For threads that run on a CPU, cpu_exit() is enough, but the
3
only way to grab attention of a thread that is stuck in a long-running
3
only way to grab attention of a thread that is stuck in a long-running
4
syscall is to interrupt it with a signal.
4
syscall is to interrupt it with a signal.
5
5
6
Reserve a host realtime signal for this, just like it's already done
6
Reserve a host realtime signal for this, just like it's already done
7
for TARGET_SIGABRT on Linux. This may reduce the number of available
7
for TARGET_SIGABRT on Linux. This may reduce the number of available
8
guest realtime signals by one, but this is acceptable, since there are
8
guest realtime signals by one, but this is acceptable, since there are
9
quite a lot of them, and it's unlikely that there are apps that need
9
quite a lot of them, and it's unlikely that there are apps that need
10
them all.
10
them all.
11
11
12
Set signal_pending for the safe_sycall machinery to prevent invoking
12
Set signal_pending for the safe_sycall machinery to prevent invoking
13
the syscall. This is a lie, since we don't queue a guest signal, but
13
the syscall. This is a lie, since we don't queue a guest signal, but
14
process_pending_signals() can handle the absence of pending signals.
14
process_pending_signals() can handle the absence of pending signals.
15
The syscall returns with QEMU_ERESTARTSYS errno, which arranges for
15
The syscall returns with QEMU_ERESTARTSYS errno, which arranges for
16
the automatic restart. This is important, because it helps avoiding
16
the automatic restart. This is important, because it helps avoiding
17
disturbing poorly written guests.
17
disturbing poorly written guests.
18
18
19
Reviewed-by: Warner Losh <imp@bsdimp.com>
19
Reviewed-by: Warner Losh <imp@bsdimp.com>
20
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
20
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
21
---
21
---
22
bsd-user/signal.c | 12 ++++++++++++
22
bsd-user/signal.c | 12 ++++++++++++
23
include/user/signal.h | 2 ++
23
include/user/signal.h | 2 ++
24
linux-user/signal.c | 25 ++++++++++++++++++++-----
24
linux-user/signal.c | 25 ++++++++++++++++++++-----
25
3 files changed, 34 insertions(+), 5 deletions(-)
25
3 files changed, 34 insertions(+), 5 deletions(-)
26
26
27
diff --git a/bsd-user/signal.c b/bsd-user/signal.c
27
diff --git a/bsd-user/signal.c b/bsd-user/signal.c
28
index XXXXXXX..XXXXXXX 100644
28
index XXXXXXX..XXXXXXX 100644
29
--- a/bsd-user/signal.c
29
--- a/bsd-user/signal.c
30
+++ b/bsd-user/signal.c
30
+++ b/bsd-user/signal.c
31
@@ -XXX,XX +XXX,XX @@ static inline int sas_ss_flags(TaskState *ts, unsigned long sp)
31
@@ -XXX,XX +XXX,XX @@ static inline int sas_ss_flags(TaskState *ts, unsigned long sp)
32
on_sig_stack(ts, sp) ? SS_ONSTACK : 0;
32
on_sig_stack(ts, sp) ? SS_ONSTACK : 0;
33
}
33
}
34
34
35
+int host_interrupt_signal = SIGRTMAX;
35
+int host_interrupt_signal = SIGRTMAX;
36
+
36
+
37
/*
37
/*
38
* The BSD ABIs use the same signal numbers across all the CPU architectures, so
38
* The BSD ABIs use the same signal numbers across all the CPU architectures, so
39
* (unlike Linux) these functions are just the identity mapping. This might not
39
* (unlike Linux) these functions are just the identity mapping. This might not
40
@@ -XXX,XX +XXX,XX @@ static void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
40
@@ -XXX,XX +XXX,XX @@ static void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
41
uintptr_t pc = 0;
41
uintptr_t pc = 0;
42
bool sync_sig = false;
42
bool sync_sig = false;
43
43
44
+ if (host_sig == host_interrupt_signal) {
44
+ if (host_sig == host_interrupt_signal) {
45
+ ts->signal_pending = 1;
45
+ ts->signal_pending = 1;
46
+ cpu_exit(thread_cpu);
46
+ cpu_exit(thread_cpu);
47
+ return;
47
+ return;
48
+ }
48
+ }
49
+
49
+
50
/*
50
/*
51
* Non-spoofed SIGSEGV and SIGBUS are synchronous, and need special
51
* Non-spoofed SIGSEGV and SIGBUS are synchronous, and need special
52
* handling wrt signal blocking and unwinding.
52
* handling wrt signal blocking and unwinding.
53
@@ -XXX,XX +XXX,XX @@ void signal_init(void)
53
@@ -XXX,XX +XXX,XX @@ void signal_init(void)
54
54
55
for (i = 1; i <= TARGET_NSIG; i++) {
55
for (i = 1; i <= TARGET_NSIG; i++) {
56
host_sig = target_to_host_signal(i);
56
host_sig = target_to_host_signal(i);
57
+ if (host_sig == host_interrupt_signal) {
57
+ if (host_sig == host_interrupt_signal) {
58
+ continue;
58
+ continue;
59
+ }
59
+ }
60
sigaction(host_sig, NULL, &oact);
60
sigaction(host_sig, NULL, &oact);
61
if (oact.sa_sigaction == (void *)SIG_IGN) {
61
if (oact.sa_sigaction == (void *)SIG_IGN) {
62
sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN;
62
sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN;
63
@@ -XXX,XX +XXX,XX @@ void signal_init(void)
63
@@ -XXX,XX +XXX,XX @@ void signal_init(void)
64
sigaction(host_sig, &act, NULL);
64
sigaction(host_sig, &act, NULL);
65
}
65
}
66
}
66
}
67
+ sigaction(host_interrupt_signal, &act, NULL);
67
+ sigaction(host_interrupt_signal, &act, NULL);
68
}
68
}
69
69
70
static void handle_pending_signal(CPUArchState *env, int sig,
70
static void handle_pending_signal(CPUArchState *env, int sig,
71
diff --git a/include/user/signal.h b/include/user/signal.h
71
diff --git a/include/user/signal.h b/include/user/signal.h
72
index XXXXXXX..XXXXXXX 100644
72
index XXXXXXX..XXXXXXX 100644
73
--- a/include/user/signal.h
73
--- a/include/user/signal.h
74
+++ b/include/user/signal.h
74
+++ b/include/user/signal.h
75
@@ -XXX,XX +XXX,XX @@
75
@@ -XXX,XX +XXX,XX @@
76
*/
76
*/
77
int target_to_host_signal(int sig);
77
int target_to_host_signal(int sig);
78
78
79
+extern int host_interrupt_signal;
79
+extern int host_interrupt_signal;
80
+
80
+
81
#endif
81
#endif
82
diff --git a/linux-user/signal.c b/linux-user/signal.c
82
diff --git a/linux-user/signal.c b/linux-user/signal.c
83
index XXXXXXX..XXXXXXX 100644
83
index XXXXXXX..XXXXXXX 100644
84
--- a/linux-user/signal.c
84
--- a/linux-user/signal.c
85
+++ b/linux-user/signal.c
85
+++ b/linux-user/signal.c
86
@@ -XXX,XX +XXX,XX @@ static int core_dump_signal(int sig)
86
@@ -XXX,XX +XXX,XX @@ static int core_dump_signal(int sig)
87
}
87
}
88
}
88
}
89
89
90
+int host_interrupt_signal;
90
+int host_interrupt_signal;
91
+
91
+
92
static void signal_table_init(const char *rtsig_map)
92
static void signal_table_init(const char *rtsig_map)
93
{
93
{
94
int hsig, tsig, count;
94
int hsig, tsig, count;
95
@@ -XXX,XX +XXX,XX @@ static void signal_table_init(const char *rtsig_map)
95
@@ -XXX,XX +XXX,XX @@ static void signal_table_init(const char *rtsig_map)
96
* Attempts for configure "missing" signals via sigaction will be
96
* Attempts for configure "missing" signals via sigaction will be
97
* silently ignored.
97
* silently ignored.
98
*
98
*
99
- * Reserve one signal for internal usage (see below).
99
- * Reserve one signal for internal usage (see below).
100
+ * Reserve two signals for internal usage (see below).
100
+ * Reserve two signals for internal usage (see below).
101
*/
101
*/
102
102
103
- hsig = SIGRTMIN + 1;
103
- hsig = SIGRTMIN + 1;
104
+ hsig = SIGRTMIN + 2;
104
+ hsig = SIGRTMIN + 2;
105
for (tsig = TARGET_SIGRTMIN;
105
for (tsig = TARGET_SIGRTMIN;
106
hsig <= SIGRTMAX && tsig <= TARGET_NSIG;
106
hsig <= SIGRTMAX && tsig <= TARGET_NSIG;
107
hsig++, tsig++) {
107
hsig++, tsig++) {
108
@@ -XXX,XX +XXX,XX @@ static void signal_table_init(const char *rtsig_map)
108
@@ -XXX,XX +XXX,XX @@ static void signal_table_init(const char *rtsig_map)
109
host_to_target_signal_table[SIGABRT] = 0;
109
host_to_target_signal_table[SIGABRT] = 0;
110
for (hsig = SIGRTMIN; hsig <= SIGRTMAX; hsig++) {
110
for (hsig = SIGRTMIN; hsig <= SIGRTMAX; hsig++) {
111
if (!host_to_target_signal_table[hsig]) {
111
if (!host_to_target_signal_table[hsig]) {
112
- host_to_target_signal_table[hsig] = TARGET_SIGABRT;
112
- host_to_target_signal_table[hsig] = TARGET_SIGABRT;
113
- break;
113
- break;
114
+ if (host_interrupt_signal) {
114
+ if (host_interrupt_signal) {
115
+ host_to_target_signal_table[hsig] = TARGET_SIGABRT;
115
+ host_to_target_signal_table[hsig] = TARGET_SIGABRT;
116
+ break;
116
+ break;
117
+ } else {
117
+ } else {
118
+ host_interrupt_signal = hsig;
118
+ host_interrupt_signal = hsig;
119
+ }
119
+ }
120
}
120
}
121
}
121
}
122
if (hsig > SIGRTMAX) {
122
if (hsig > SIGRTMAX) {
123
- fprintf(stderr, "No rt signals left for SIGABRT mapping\n");
123
- fprintf(stderr, "No rt signals left for SIGABRT mapping\n");
124
+ fprintf(stderr,
124
+ fprintf(stderr,
125
+ "No rt signals left for interrupt and SIGABRT mapping\n");
125
+ "No rt signals left for interrupt and SIGABRT mapping\n");
126
exit(EXIT_FAILURE);
126
exit(EXIT_FAILURE);
127
}
127
}
128
128
129
@@ -XXX,XX +XXX,XX @@ void signal_init(const char *rtsig_map)
129
@@ -XXX,XX +XXX,XX @@ void signal_init(const char *rtsig_map)
130
}
130
}
131
sigact_table[tsig - 1]._sa_handler = thand;
131
sigact_table[tsig - 1]._sa_handler = thand;
132
}
132
}
133
+
133
+
134
+ sigaction(host_interrupt_signal, &act, NULL);
134
+ sigaction(host_interrupt_signal, &act, NULL);
135
}
135
}
136
136
137
/* Force a synchronously taken signal. The kernel force_sig() function
137
/* Force a synchronously taken signal. The kernel force_sig() function
138
@@ -XXX,XX +XXX,XX @@ static void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
138
@@ -XXX,XX +XXX,XX @@ static void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
139
bool sync_sig = false;
139
bool sync_sig = false;
140
void *sigmask;
140
void *sigmask;
141
141
142
+ if (host_sig == host_interrupt_signal) {
142
+ if (host_sig == host_interrupt_signal) {
143
+ ts->signal_pending = 1;
143
+ ts->signal_pending = 1;
144
+ cpu_exit(thread_cpu);
144
+ cpu_exit(thread_cpu);
145
+ return;
145
+ return;
146
+ }
146
+ }
147
+
147
+
148
/*
148
/*
149
* Non-spoofed SIGSEGV and SIGBUS are synchronous, and need special
149
* Non-spoofed SIGSEGV and SIGBUS are synchronous, and need special
150
* handling wrt signal blocking and unwinding. Non-spoofed SIGILL,
150
* handling wrt signal blocking and unwinding. Non-spoofed SIGILL,
151
--
151
--
152
2.47.0
152
2.47.0
diff view generated by jsdifflib
1
Add a function for sending signals to individual threads. It does not make
1
Add a function for sending signals to individual threads. It does not make
2
sense on Windows, so do not provide an implementation, so that if someone
2
sense on Windows, so do not provide an implementation, so that if someone
3
uses it by accident, they will get a linker error.
3
uses it by accident, they will get a linker error.
4
4
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Reviewed-by: Warner Losh <imp@bsidmp.com>
6
Reviewed-by: Warner Losh <imp@bsidmp.com>
7
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
7
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
8
---
8
---
9
include/qemu/osdep.h | 9 +++++++++
9
include/qemu/osdep.h | 9 +++++++++
10
util/oslib-posix.c | 15 +++++++++++++++
10
util/oslib-posix.c | 15 +++++++++++++++
11
2 files changed, 24 insertions(+)
11
2 files changed, 24 insertions(+)
12
12
13
diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h
13
diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h
14
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
15
--- a/include/qemu/osdep.h
15
--- a/include/qemu/osdep.h
16
+++ b/include/qemu/osdep.h
16
+++ b/include/qemu/osdep.h
17
@@ -XXX,XX +XXX,XX @@ bool qemu_write_pidfile(const char *pidfile, Error **errp);
17
@@ -XXX,XX +XXX,XX @@ bool qemu_write_pidfile(const char *pidfile, Error **errp);
18
18
19
int qemu_get_thread_id(void);
19
int qemu_get_thread_id(void);
20
20
21
+/**
21
+/**
22
+ * qemu_kill_thread:
22
+ * qemu_kill_thread:
23
+ * @tid: thread id.
23
+ * @tid: thread id.
24
+ * @sig: host signal.
24
+ * @sig: host signal.
25
+ *
25
+ *
26
+ * Send @sig to one of QEMU's own threads with identifier @tid.
26
+ * Send @sig to one of QEMU's own threads with identifier @tid.
27
+ */
27
+ */
28
+int qemu_kill_thread(int tid, int sig);
28
+int qemu_kill_thread(int tid, int sig);
29
+
29
+
30
#ifndef CONFIG_IOVEC
30
#ifndef CONFIG_IOVEC
31
struct iovec {
31
struct iovec {
32
void *iov_base;
32
void *iov_base;
33
diff --git a/util/oslib-posix.c b/util/oslib-posix.c
33
diff --git a/util/oslib-posix.c b/util/oslib-posix.c
34
index XXXXXXX..XXXXXXX 100644
34
index XXXXXXX..XXXXXXX 100644
35
--- a/util/oslib-posix.c
35
--- a/util/oslib-posix.c
36
+++ b/util/oslib-posix.c
36
+++ b/util/oslib-posix.c
37
@@ -XXX,XX +XXX,XX @@ int qemu_get_thread_id(void)
37
@@ -XXX,XX +XXX,XX @@ int qemu_get_thread_id(void)
38
#endif
38
#endif
39
}
39
}
40
40
41
+int qemu_kill_thread(int tid, int sig)
41
+int qemu_kill_thread(int tid, int sig)
42
+{
42
+{
43
+#if defined(__linux__)
43
+#if defined(__linux__)
44
+ return syscall(__NR_tgkill, getpid(), tid, sig);
44
+ return syscall(__NR_tgkill, getpid(), tid, sig);
45
+#elif defined(__FreeBSD__)
45
+#elif defined(__FreeBSD__)
46
+ return thr_kill2(getpid(), tid, sig);
46
+ return thr_kill2(getpid(), tid, sig);
47
+#elif defined(__NetBSD__)
47
+#elif defined(__NetBSD__)
48
+ return _lwp_kill(tid, sig);
48
+ return _lwp_kill(tid, sig);
49
+#elif defined(__OpenBSD__)
49
+#elif defined(__OpenBSD__)
50
+ return thrkill(tid, sig, NULL);
50
+ return thrkill(tid, sig, NULL);
51
+#else
51
+#else
52
+ return kill(tid, sig);
52
+ return kill(tid, sig);
53
+#endif
53
+#endif
54
+}
54
+}
55
+
55
+
56
int qemu_daemon(int nochdir, int noclose)
56
int qemu_daemon(int nochdir, int noclose)
57
{
57
{
58
return daemon(nochdir, noclose);
58
return daemon(nochdir, noclose);
59
--
59
--
60
2.47.0
60
2.47.0
diff view generated by jsdifflib
1
Allow debugging individual processes in multi-process applications by
1
Allow debugging individual processes in multi-process applications by
2
starting them with export QEMU_GDB=/tmp/qemu-%d.sock,suspend=n.
2
starting them with export QEMU_GDB=/tmp/qemu-%d.sock,suspend=n.
3
Currently one would have to attach to every process to ensure the app
3
Currently one would have to attach to every process to ensure the app
4
makes progress.
4
makes progress.
5
5
6
In case suspend=n is not specified, the flow remains unchanged. If it
6
In case suspend=n is not specified, the flow remains unchanged. If it
7
is specified, then accepting the client connection is delegated to a
7
is specified, then accepting the client connection is delegated to a
8
thread. In the future this machinery may be reused for handling
8
thread. In the future this machinery may be reused for handling
9
reconnections and interruptions.
9
reconnections and interruptions.
10
10
11
On accepting a connection, the thread schedules gdb_handlesig() on the
11
On accepting a connection, the thread schedules gdb_handlesig() on the
12
first CPU and wakes it up with host_interrupt_signal. Note that the
12
first CPU and wakes it up with host_interrupt_signal. Note that the
13
result of this gdb_handlesig() invocation is handled, as opposed to
13
result of this gdb_handlesig() invocation is handled, as opposed to
14
many other existing call sites. These other call sites probably need to
14
many other existing call sites. These other call sites probably need to
15
be fixed separately.
15
be fixed separately.
16
16
17
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
17
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
18
---
18
---
19
bsd-user/main.c | 1 -
19
bsd-user/main.c | 1 -
20
gdbstub/user.c | 120 ++++++++++++++++++++++++++++++++++++++++++----
20
gdbstub/user.c | 120 ++++++++++++++++++++++++++++++++++++++++++----
21
linux-user/main.c | 1 -
21
linux-user/main.c | 1 -
22
3 files changed, 110 insertions(+), 12 deletions(-)
22
3 files changed, 110 insertions(+), 12 deletions(-)
23
23
24
diff --git a/bsd-user/main.c b/bsd-user/main.c
24
diff --git a/bsd-user/main.c b/bsd-user/main.c
25
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX 100644
26
--- a/bsd-user/main.c
26
--- a/bsd-user/main.c
27
+++ b/bsd-user/main.c
27
+++ b/bsd-user/main.c
28
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
28
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
29
29
30
if (gdbstub) {
30
if (gdbstub) {
31
gdbserver_start(gdbstub);
31
gdbserver_start(gdbstub);
32
- gdb_handlesig(cpu, 0, NULL, NULL, 0);
32
- gdb_handlesig(cpu, 0, NULL, NULL, 0);
33
}
33
}
34
cpu_loop(env);
34
cpu_loop(env);
35
/* never exits */
35
/* never exits */
36
diff --git a/gdbstub/user.c b/gdbstub/user.c
36
diff --git a/gdbstub/user.c b/gdbstub/user.c
37
index XXXXXXX..XXXXXXX 100644
37
index XXXXXXX..XXXXXXX 100644
38
--- a/gdbstub/user.c
38
--- a/gdbstub/user.c
39
+++ b/gdbstub/user.c
39
+++ b/gdbstub/user.c
40
@@ -XXX,XX +XXX,XX @@
40
@@ -XXX,XX +XXX,XX @@
41
*/
41
*/
42
42
43
#include "qemu/osdep.h"
43
#include "qemu/osdep.h"
44
+#include <sys/syscall.h>
44
+#include <sys/syscall.h>
45
#include "qemu/bitops.h"
45
#include "qemu/bitops.h"
46
#include "qemu/cutils.h"
46
#include "qemu/cutils.h"
47
#include "qemu/sockets.h"
47
#include "qemu/sockets.h"
48
@@ -XXX,XX +XXX,XX @@
48
@@ -XXX,XX +XXX,XX @@
49
#include "gdbstub/user.h"
49
#include "gdbstub/user.h"
50
#include "gdbstub/enums.h"
50
#include "gdbstub/enums.h"
51
#include "hw/core/cpu.h"
51
#include "hw/core/cpu.h"
52
+#include "user/signal.h"
52
+#include "user/signal.h"
53
#include "trace.h"
53
#include "trace.h"
54
#include "internals.h"
54
#include "internals.h"
55
55
56
@@ -XXX,XX +XXX,XX @@ static int gdbserver_open_port(int port)
56
@@ -XXX,XX +XXX,XX @@ static int gdbserver_open_port(int port)
57
return fd;
57
return fd;
58
}
58
}
59
59
60
-int gdbserver_start(const char *port_or_path)
60
-int gdbserver_start(const char *port_or_path)
61
+static bool gdbserver_accept(int port, int gdb_fd, const char *port_or_path)
61
+static bool gdbserver_accept(int port, int gdb_fd, const char *port_or_path)
62
{
62
{
63
- int port = g_ascii_strtoull(port_or_path, NULL, 10);
63
- int port = g_ascii_strtoull(port_or_path, NULL, 10);
64
+ bool ret;
64
+ bool ret;
65
+
65
+
66
+ if (port > 0) {
66
+ if (port > 0) {
67
+ ret = gdb_accept_tcp(gdb_fd);
67
+ ret = gdb_accept_tcp(gdb_fd);
68
+ } else {
68
+ } else {
69
+ ret = gdb_accept_socket(gdb_fd);
69
+ ret = gdb_accept_socket(gdb_fd);
70
+ if (ret) {
70
+ if (ret) {
71
+ gdbserver_user_state.socket_path = g_strdup(port_or_path);
71
+ gdbserver_user_state.socket_path = g_strdup(port_or_path);
72
+ }
72
+ }
73
+ }
73
+ }
74
+
74
+
75
+ if (!ret) {
75
+ if (!ret) {
76
+ close(gdb_fd);
76
+ close(gdb_fd);
77
+ }
77
+ }
78
+
78
+
79
+ return ret;
79
+ return ret;
80
+}
80
+}
81
+
81
+
82
+struct {
82
+struct {
83
+ int port;
83
+ int port;
84
int gdb_fd;
84
int gdb_fd;
85
+ char *port_or_path;
85
+ char *port_or_path;
86
+} gdbserver_args;
86
+} gdbserver_args;
87
+
87
+
88
+static void do_gdb_handlesig(CPUState *cs, run_on_cpu_data arg)
88
+static void do_gdb_handlesig(CPUState *cs, run_on_cpu_data arg)
89
+{
89
+{
90
+ int sig;
90
+ int sig;
91
+
91
+
92
+ sig = target_to_host_signal(gdb_handlesig(cs, 0, NULL, NULL, 0));
92
+ sig = target_to_host_signal(gdb_handlesig(cs, 0, NULL, NULL, 0));
93
+ if (sig >= 1 && sig < NSIG) {
93
+ if (sig >= 1 && sig < NSIG) {
94
+ qemu_kill_thread(gdb_get_cpu_index(cs), sig);
94
+ qemu_kill_thread(gdb_get_cpu_index(cs), sig);
95
+ }
95
+ }
96
+}
96
+}
97
+
97
+
98
+static void *gdbserver_accept_thread(void *arg)
98
+static void *gdbserver_accept_thread(void *arg)
99
+{
99
+{
100
+ if (gdbserver_accept(gdbserver_args.port, gdbserver_args.gdb_fd,
100
+ if (gdbserver_accept(gdbserver_args.port, gdbserver_args.gdb_fd,
101
+ gdbserver_args.port_or_path)) {
101
+ gdbserver_args.port_or_path)) {
102
+ CPUState *cs = first_cpu;
102
+ CPUState *cs = first_cpu;
103
+
103
+
104
+ async_safe_run_on_cpu(cs, do_gdb_handlesig, RUN_ON_CPU_NULL);
104
+ async_safe_run_on_cpu(cs, do_gdb_handlesig, RUN_ON_CPU_NULL);
105
+ qemu_kill_thread(gdb_get_cpu_index(cs), host_interrupt_signal);
105
+ qemu_kill_thread(gdb_get_cpu_index(cs), host_interrupt_signal);
106
+ }
106
+ }
107
+
107
+
108
+ g_free(gdbserver_args.port_or_path);
108
+ g_free(gdbserver_args.port_or_path);
109
+
109
+
110
+ return NULL;
110
+ return NULL;
111
+}
111
+}
112
+
112
+
113
+__attribute__((__format__(__printf__, 1, 2)))
113
+__attribute__((__format__(__printf__, 1, 2)))
114
+static void print_usage(const char *format, ...)
114
+static void print_usage(const char *format, ...)
115
+{
115
+{
116
+ va_list ap;
116
+ va_list ap;
117
+
117
+
118
+ va_start(ap, format);
118
+ va_start(ap, format);
119
+ vfprintf(stderr, format, ap);
119
+ vfprintf(stderr, format, ap);
120
+ va_end(ap);
120
+ va_end(ap);
121
+ fprintf(stderr, "Usage: -g {port|path}[,suspend={y|n}]\n");
121
+ fprintf(stderr, "Usage: -g {port|path}[,suspend={y|n}]\n");
122
+}
122
+}
123
+
123
+
124
+#define SUSPEND "suspend="
124
+#define SUSPEND "suspend="
125
+
125
+
126
+int gdbserver_start(const char *args)
126
+int gdbserver_start(const char *args)
127
+{
127
+{
128
+ g_auto(GStrv) argv = g_strsplit(args, ",", 0);
128
+ g_auto(GStrv) argv = g_strsplit(args, ",", 0);
129
+ const char *port_or_path = NULL;
129
+ const char *port_or_path = NULL;
130
+ bool suspend = true;
130
+ bool suspend = true;
131
+ int gdb_fd, port;
131
+ int gdb_fd, port;
132
+ GStrv arg;
132
+ GStrv arg;
133
133
134
+ for (arg = argv; *arg; arg++) {
134
+ for (arg = argv; *arg; arg++) {
135
+ if (g_str_has_prefix(*arg, SUSPEND)) {
135
+ if (g_str_has_prefix(*arg, SUSPEND)) {
136
+ const char *val = *arg + strlen(SUSPEND);
136
+ const char *val = *arg + strlen(SUSPEND);
137
+
137
+
138
+ suspend = (strcmp(val, "y") == 0);
138
+ suspend = (strcmp(val, "y") == 0);
139
+ if (!suspend && (strcmp(val, "n") != 0)) {
139
+ if (!suspend && (strcmp(val, "n") != 0)) {
140
+ print_usage("Bad option value: %s", *arg);
140
+ print_usage("Bad option value: %s", *arg);
141
+ return -1;
141
+ return -1;
142
+ }
142
+ }
143
+ } else {
143
+ } else {
144
+ if (port_or_path) {
144
+ if (port_or_path) {
145
+ print_usage("Unknown option: %s", *arg);
145
+ print_usage("Unknown option: %s", *arg);
146
+ return -1;
146
+ return -1;
147
+ }
147
+ }
148
+ port_or_path = *arg;
148
+ port_or_path = *arg;
149
+ }
149
+ }
150
+ }
150
+ }
151
+ if (!port_or_path) {
151
+ if (!port_or_path) {
152
+ print_usage("Port or path not specified");
152
+ print_usage("Port or path not specified");
153
+ return -1;
153
+ return -1;
154
+ }
154
+ }
155
+
155
+
156
+ port = g_ascii_strtoull(port_or_path, NULL, 10);
156
+ port = g_ascii_strtoull(port_or_path, NULL, 10);
157
if (port > 0) {
157
if (port > 0) {
158
gdb_fd = gdbserver_open_port(port);
158
gdb_fd = gdbserver_open_port(port);
159
} else {
159
} else {
160
@@ -XXX,XX +XXX,XX @@ int gdbserver_start(const char *port_or_path)
160
@@ -XXX,XX +XXX,XX @@ int gdbserver_start(const char *port_or_path)
161
return -1;
161
return -1;
162
}
162
}
163
163
164
- if (port > 0 && gdb_accept_tcp(gdb_fd)) {
164
- if (port > 0 && gdb_accept_tcp(gdb_fd)) {
165
- return 0;
165
- return 0;
166
- } else if (gdb_accept_socket(gdb_fd)) {
166
- } else if (gdb_accept_socket(gdb_fd)) {
167
- gdbserver_user_state.socket_path = g_strdup(port_or_path);
167
- gdbserver_user_state.socket_path = g_strdup(port_or_path);
168
+ if (suspend) {
168
+ if (suspend) {
169
+ if (gdbserver_accept(port, gdb_fd, port_or_path)) {
169
+ if (gdbserver_accept(port, gdb_fd, port_or_path)) {
170
+ gdb_handlesig(first_cpu, 0, NULL, NULL, 0);
170
+ gdb_handlesig(first_cpu, 0, NULL, NULL, 0);
171
+ return 0;
171
+ return 0;
172
+ } else {
172
+ } else {
173
+ return -1;
173
+ return -1;
174
+ }
174
+ }
175
+ } else {
175
+ } else {
176
+ QemuThread thread;
176
+ QemuThread thread;
177
+
177
+
178
+ gdbserver_args.port = port;
178
+ gdbserver_args.port = port;
179
+ gdbserver_args.gdb_fd = gdb_fd;
179
+ gdbserver_args.gdb_fd = gdb_fd;
180
+ gdbserver_args.port_or_path = g_strdup(port_or_path);
180
+ gdbserver_args.port_or_path = g_strdup(port_or_path);
181
+ qemu_thread_create(&thread, "gdb-accept",
181
+ qemu_thread_create(&thread, "gdb-accept",
182
+ &gdbserver_accept_thread, NULL,
182
+ &gdbserver_accept_thread, NULL,
183
+ QEMU_THREAD_DETACHED);
183
+ QEMU_THREAD_DETACHED);
184
return 0;
184
return 0;
185
}
185
}
186
-
186
-
187
- /* gone wrong */
187
- /* gone wrong */
188
- close(gdb_fd);
188
- close(gdb_fd);
189
- return -1;
189
- return -1;
190
}
190
}
191
191
192
void gdbserver_fork_start(void)
192
void gdbserver_fork_start(void)
193
diff --git a/linux-user/main.c b/linux-user/main.c
193
diff --git a/linux-user/main.c b/linux-user/main.c
194
index XXXXXXX..XXXXXXX 100644
194
index XXXXXXX..XXXXXXX 100644
195
--- a/linux-user/main.c
195
--- a/linux-user/main.c
196
+++ b/linux-user/main.c
196
+++ b/linux-user/main.c
197
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv, char **envp)
197
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv, char **envp)
198
gdbstub);
198
gdbstub);
199
exit(EXIT_FAILURE);
199
exit(EXIT_FAILURE);
200
}
200
}
201
- gdb_handlesig(cpu, 0, NULL, NULL, 0);
201
- gdb_handlesig(cpu, 0, NULL, NULL, 0);
202
}
202
}
203
203
204
#ifdef CONFIG_SEMIHOSTING
204
#ifdef CONFIG_SEMIHOSTING
205
--
205
--
206
2.47.0
206
2.47.0
diff view generated by jsdifflib
1
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
1
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
2
---
2
---
3
docs/user/main.rst | 16 +++++++++++++---
3
docs/user/main.rst | 16 +++++++++++++---
4
1 file changed, 13 insertions(+), 3 deletions(-)
4
1 file changed, 13 insertions(+), 3 deletions(-)
5
5
6
diff --git a/docs/user/main.rst b/docs/user/main.rst
6
diff --git a/docs/user/main.rst b/docs/user/main.rst
7
index XXXXXXX..XXXXXXX 100644
7
index XXXXXXX..XXXXXXX 100644
8
--- a/docs/user/main.rst
8
--- a/docs/user/main.rst
9
+++ b/docs/user/main.rst
9
+++ b/docs/user/main.rst
10
@@ -XXX,XX +XXX,XX @@ Command line options
10
@@ -XXX,XX +XXX,XX @@ Command line options
11
11
12
::
12
::
13
13
14
- qemu-i386 [-h] [-d] [-L path] [-s size] [-cpu model] [-g port] [-B offset] [-R size] program [arguments...]
14
- qemu-i386 [-h] [-d] [-L path] [-s size] [-cpu model] [-g port] [-B offset] [-R size] program [arguments...]
15
+ qemu-i386 [-h] [-d] [-L path] [-s size] [-cpu model] [-g endpoint] [-B offset] [-R size] program [arguments...]
15
+ qemu-i386 [-h] [-d] [-L path] [-s size] [-cpu model] [-g endpoint] [-B offset] [-R size] program [arguments...]
16
16
17
``-h``
17
``-h``
18
Print the help
18
Print the help
19
@@ -XXX,XX +XXX,XX @@ Debug options:
19
@@ -XXX,XX +XXX,XX @@ Debug options:
20
Activate logging of the specified items (use '-d help' for a list of
20
Activate logging of the specified items (use '-d help' for a list of
21
log items)
21
log items)
22
22
23
-``-g port``
23
-``-g port``
24
- Wait gdb connection to port
24
- Wait gdb connection to port
25
+``-g endpoint``
25
+``-g endpoint``
26
+ Wait gdb connection to a port (e.g., ``1234``) or a unix socket (e.g.,
26
+ Wait gdb connection to a port (e.g., ``1234``) or a unix socket (e.g.,
27
+ ``/tmp/qemu.sock``).
27
+ ``/tmp/qemu.sock``).
28
+
28
+
29
+ If a unix socket path contains single ``%d`` placeholder (e.g.,
29
+ If a unix socket path contains single ``%d`` placeholder (e.g.,
30
+ ``/tmp/qemu-%d.sock``), it is replaced by the emulator PID, which is useful
30
+ ``/tmp/qemu-%d.sock``), it is replaced by the emulator PID, which is useful
31
+ when passing this option via the ``QEMU_GDB`` environment variable to a
31
+ when passing this option via the ``QEMU_GDB`` environment variable to a
32
+ multi-process application.
32
+ multi-process application.
33
+
33
+
34
+ If the endpoint address is followed by ``,suspend=n`` (e.g.,
34
+ If the endpoint address is followed by ``,suspend=n`` (e.g.,
35
+ ``1234,suspend=n``), then the emulated program starts without waiting for a
35
+ ``1234,suspend=n``), then the emulated program starts without waiting for a
36
+ connection, which can be established at any later point in time.
36
+ connection, which can be established at any later point in time.
37
37
38
``-one-insn-per-tb``
38
``-one-insn-per-tb``
39
Run the emulation with one guest instruction per translation block.
39
Run the emulation with one guest instruction per translation block.
40
--
40
--
41
2.47.0
41
2.47.0
diff view generated by jsdifflib
1
Add a small test to prevent regressions.
1
Add a small test to prevent regressions.
2
Make sure that host_interrupt_signal is not visible to the guest.
2
Make sure that host_interrupt_signal is not visible to the guest.
3
3
4
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
4
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
5
---
5
---
6
tests/guest-debug/run-test.py | 15 ++++++--
6
tests/guest-debug/run-test.py | 15 ++++++--
7
tests/tcg/multiarch/Makefile.target | 9 ++++-
7
tests/tcg/multiarch/Makefile.target | 9 ++++-
8
tests/tcg/multiarch/gdbstub/late-attach.py | 28 +++++++++++++++
8
tests/tcg/multiarch/gdbstub/late-attach.py | 28 +++++++++++++++
9
tests/tcg/multiarch/late-attach.c | 41 ++++++++++++++++++++++
9
tests/tcg/multiarch/late-attach.c | 41 ++++++++++++++++++++++
10
4 files changed, 90 insertions(+), 3 deletions(-)
10
4 files changed, 90 insertions(+), 3 deletions(-)
11
create mode 100644 tests/tcg/multiarch/gdbstub/late-attach.py
11
create mode 100644 tests/tcg/multiarch/gdbstub/late-attach.py
12
create mode 100644 tests/tcg/multiarch/late-attach.c
12
create mode 100644 tests/tcg/multiarch/late-attach.c
13
13
14
diff --git a/tests/guest-debug/run-test.py b/tests/guest-debug/run-test.py
14
diff --git a/tests/guest-debug/run-test.py b/tests/guest-debug/run-test.py
15
index XXXXXXX..XXXXXXX 100755
15
index XXXXXXX..XXXXXXX 100755
16
--- a/tests/guest-debug/run-test.py
16
--- a/tests/guest-debug/run-test.py
17
+++ b/tests/guest-debug/run-test.py
17
+++ b/tests/guest-debug/run-test.py
18
@@ -XXX,XX +XXX,XX @@ def get_args():
18
@@ -XXX,XX +XXX,XX @@ def get_args():
19
parser.add_argument("--gdb-args", help="Additional gdb arguments")
19
parser.add_argument("--gdb-args", help="Additional gdb arguments")
20
parser.add_argument("--output", help="A file to redirect output to")
20
parser.add_argument("--output", help="A file to redirect output to")
21
parser.add_argument("--stderr", help="A file to redirect stderr to")
21
parser.add_argument("--stderr", help="A file to redirect stderr to")
22
+ parser.add_argument("--no-suspend", action="store_true",
22
+ parser.add_argument("--no-suspend", action="store_true",
23
+ help="Ask the binary to not wait for GDB connection")
23
+ help="Ask the binary to not wait for GDB connection")
24
24
25
return parser.parse_args()
25
return parser.parse_args()
26
26
27
@@ -XXX,XX +XXX,XX @@ def log(output, msg):
27
@@ -XXX,XX +XXX,XX @@ def log(output, msg):
28
28
29
# Launch QEMU with binary
29
# Launch QEMU with binary
30
if "system" in args.qemu:
30
if "system" in args.qemu:
31
+ if args.no_suspend:
31
+ if args.no_suspend:
32
+ suspend = ''
32
+ suspend = ''
33
+ else:
33
+ else:
34
+ suspend = ' -S'
34
+ suspend = ' -S'
35
cmd = f'{args.qemu} {args.qargs} {args.binary}' \
35
cmd = f'{args.qemu} {args.qargs} {args.binary}' \
36
- f' -S -gdb unix:path={socket_name},server=on'
36
- f' -S -gdb unix:path={socket_name},server=on'
37
+ f'{suspend} -gdb unix:path={socket_name},server=on'
37
+ f'{suspend} -gdb unix:path={socket_name},server=on'
38
else:
38
else:
39
- cmd = f'{args.qemu} {args.qargs} -g {socket_name} {args.binary}'
39
- cmd = f'{args.qemu} {args.qargs} -g {socket_name} {args.binary}'
40
+ if args.no_suspend:
40
+ if args.no_suspend:
41
+ suspend = ',suspend=n'
41
+ suspend = ',suspend=n'
42
+ else:
42
+ else:
43
+ suspend = ''
43
+ suspend = ''
44
+ cmd = f'{args.qemu} {args.qargs} -g {socket_name}{suspend}' \
44
+ cmd = f'{args.qemu} {args.qargs} -g {socket_name}{suspend}' \
45
+ f' {args.binary}'
45
+ f' {args.binary}'
46
46
47
log(output, "QEMU CMD: %s" % (cmd))
47
log(output, "QEMU CMD: %s" % (cmd))
48
inferior = subprocess.Popen(shlex.split(cmd))
48
inferior = subprocess.Popen(shlex.split(cmd))
49
diff --git a/tests/tcg/multiarch/Makefile.target b/tests/tcg/multiarch/Makefile.target
49
diff --git a/tests/tcg/multiarch/Makefile.target b/tests/tcg/multiarch/Makefile.target
50
index XXXXXXX..XXXXXXX 100644
50
index XXXXXXX..XXXXXXX 100644
51
--- a/tests/tcg/multiarch/Makefile.target
51
--- a/tests/tcg/multiarch/Makefile.target
52
+++ b/tests/tcg/multiarch/Makefile.target
52
+++ b/tests/tcg/multiarch/Makefile.target
53
@@ -XXX,XX +XXX,XX @@ run-gdbstub-follow-fork-mode-parent: follow-fork-mode
53
@@ -XXX,XX +XXX,XX @@ run-gdbstub-follow-fork-mode-parent: follow-fork-mode
54
        --bin $< --test $(MULTIARCH_SRC)/gdbstub/follow-fork-mode-parent.py, \
54
        --bin $< --test $(MULTIARCH_SRC)/gdbstub/follow-fork-mode-parent.py, \
55
    following parents on fork)
55
    following parents on fork)
56
56
57
+run-gdbstub-late-attach: late-attach
57
+run-gdbstub-late-attach: late-attach
58
+    $(call run-test, $@, env LATE_ATTACH_PY=1 $(GDB_SCRIPT) \
58
+    $(call run-test, $@, env LATE_ATTACH_PY=1 $(GDB_SCRIPT) \
59
+        --gdb $(GDB) \
59
+        --gdb $(GDB) \
60
+        --qemu $(QEMU) --qargs "$(QEMU_OPTS)" --no-suspend \
60
+        --qemu $(QEMU) --qargs "$(QEMU_OPTS)" --no-suspend \
61
+        --bin $< --test $(MULTIARCH_SRC)/gdbstub/late-attach.py, \
61
+        --bin $< --test $(MULTIARCH_SRC)/gdbstub/late-attach.py, \
62
+    attaching to a running process)
62
+    attaching to a running process)
63
+
63
+
64
else
64
else
65
run-gdbstub-%:
65
run-gdbstub-%:
66
    $(call skip-test, "gdbstub test $*", "need working gdb with $(patsubst -%,,$(TARGET_NAME)) support")
66
    $(call skip-test, "gdbstub test $*", "need working gdb with $(patsubst -%,,$(TARGET_NAME)) support")
67
@@ -XXX,XX +XXX,XX @@ EXTRA_RUNS += run-gdbstub-sha1 run-gdbstub-qxfer-auxv-read \
67
@@ -XXX,XX +XXX,XX @@ EXTRA_RUNS += run-gdbstub-sha1 run-gdbstub-qxfer-auxv-read \
68
     run-gdbstub-registers run-gdbstub-prot-none \
68
     run-gdbstub-registers run-gdbstub-prot-none \
69
     run-gdbstub-catch-syscalls run-gdbstub-follow-fork-mode-child \
69
     run-gdbstub-catch-syscalls run-gdbstub-follow-fork-mode-child \
70
     run-gdbstub-follow-fork-mode-parent \
70
     run-gdbstub-follow-fork-mode-parent \
71
-     run-gdbstub-qxfer-siginfo-read
71
-     run-gdbstub-qxfer-siginfo-read
72
+     run-gdbstub-qxfer-siginfo-read run-gdbstub-late-attach
72
+     run-gdbstub-qxfer-siginfo-read run-gdbstub-late-attach
73
73
74
# ARM Compatible Semi Hosting Tests
74
# ARM Compatible Semi Hosting Tests
75
#
75
#
76
diff --git a/tests/tcg/multiarch/gdbstub/late-attach.py b/tests/tcg/multiarch/gdbstub/late-attach.py
76
diff --git a/tests/tcg/multiarch/gdbstub/late-attach.py b/tests/tcg/multiarch/gdbstub/late-attach.py
77
new file mode 100644
77
new file mode 100644
78
index XXXXXXX..XXXXXXX
78
index XXXXXXX..XXXXXXX
79
--- /dev/null
79
--- /dev/null
80
+++ b/tests/tcg/multiarch/gdbstub/late-attach.py
80
+++ b/tests/tcg/multiarch/gdbstub/late-attach.py
81
@@ -XXX,XX +XXX,XX @@
81
@@ -XXX,XX +XXX,XX @@
82
+"""Test attaching GDB to a running process.
82
+"""Test attaching GDB to a running process.
83
+
83
+
84
+SPDX-License-Identifier: GPL-2.0-or-later
84
+SPDX-License-Identifier: GPL-2.0-or-later
85
+"""
85
+"""
86
+from test_gdbstub import main, report
86
+from test_gdbstub import main, report
87
+
87
+
88
+
88
+
89
+def run_test():
89
+def run_test():
90
+ """Run through the tests one by one"""
90
+ """Run through the tests one by one"""
91
+ try:
91
+ try:
92
+ phase = gdb.parse_and_eval("phase").string()
92
+ phase = gdb.parse_and_eval("phase").string()
93
+ except gdb.error:
93
+ except gdb.error:
94
+ # Assume the guest did not reach main().
94
+ # Assume the guest did not reach main().
95
+ phase = "start"
95
+ phase = "start"
96
+
96
+
97
+ if phase == "start":
97
+ if phase == "start":
98
+ gdb.execute("break sigwait")
98
+ gdb.execute("break sigwait")
99
+ gdb.execute("continue")
99
+ gdb.execute("continue")
100
+ phase = gdb.parse_and_eval("phase").string()
100
+ phase = gdb.parse_and_eval("phase").string()
101
+ report(phase == "sigwait", "{} == \"sigwait\"".format(phase))
101
+ report(phase == "sigwait", "{} == \"sigwait\"".format(phase))
102
+
102
+
103
+ gdb.execute("signal SIGUSR1")
103
+ gdb.execute("signal SIGUSR1")
104
+
104
+
105
+ exitcode = int(gdb.parse_and_eval("$_exitcode"))
105
+ exitcode = int(gdb.parse_and_eval("$_exitcode"))
106
+ report(exitcode == 0, "{} == 0".format(exitcode))
106
+ report(exitcode == 0, "{} == 0".format(exitcode))
107
+
107
+
108
+
108
+
109
+main(run_test)
109
+main(run_test)
110
diff --git a/tests/tcg/multiarch/late-attach.c b/tests/tcg/multiarch/late-attach.c
110
diff --git a/tests/tcg/multiarch/late-attach.c b/tests/tcg/multiarch/late-attach.c
111
new file mode 100644
111
new file mode 100644
112
index XXXXXXX..XXXXXXX
112
index XXXXXXX..XXXXXXX
113
--- /dev/null
113
--- /dev/null
114
+++ b/tests/tcg/multiarch/late-attach.c
114
+++ b/tests/tcg/multiarch/late-attach.c
115
@@ -XXX,XX +XXX,XX @@
115
@@ -XXX,XX +XXX,XX @@
116
+/*
116
+/*
117
+ * Test attaching GDB to a running process.
117
+ * Test attaching GDB to a running process.
118
+ *
118
+ *
119
+ * SPDX-License-Identifier: GPL-2.0-or-later
119
+ * SPDX-License-Identifier: GPL-2.0-or-later
120
+ */
120
+ */
121
+#include <assert.h>
121
+#include <assert.h>
122
+#include <signal.h>
122
+#include <signal.h>
123
+#include <stdio.h>
123
+#include <stdio.h>
124
+#include <stdlib.h>
124
+#include <stdlib.h>
125
+
125
+
126
+static const char *phase = "start";
126
+static const char *phase = "start";
127
+
127
+
128
+int main(void)
128
+int main(void)
129
+{
129
+{
130
+ sigset_t set;
130
+ sigset_t set;
131
+ int sig;
131
+ int sig;
132
+
132
+
133
+ assert(sigfillset(&set) == 0);
133
+ assert(sigfillset(&set) == 0);
134
+ assert(sigprocmask(SIG_BLOCK, &set, NULL) == 0);
134
+ assert(sigprocmask(SIG_BLOCK, &set, NULL) == 0);
135
+
135
+
136
+ /* Let GDB know it can send SIGUSR1. */
136
+ /* Let GDB know it can send SIGUSR1. */
137
+ phase = "sigwait";
137
+ phase = "sigwait";
138
+ if (getenv("LATE_ATTACH_PY")) {
138
+ if (getenv("LATE_ATTACH_PY")) {
139
+ assert(sigwait(&set, &sig) == 0);
139
+ assert(sigwait(&set, &sig) == 0);
140
+ if (sig != SIGUSR1) {
140
+ if (sig != SIGUSR1) {
141
+ fprintf(stderr, "Unexpected signal %d\n", sig);
141
+ fprintf(stderr, "Unexpected signal %d\n", sig);
142
+ return EXIT_FAILURE;
142
+ return EXIT_FAILURE;
143
+ }
143
+ }
144
+ }
144
+ }
145
+
145
+
146
+ /* Check that the guest does not see host_interrupt_signal. */
146
+ /* Check that the guest does not see host_interrupt_signal. */
147
+ assert(sigpending(&set) == 0);
147
+ assert(sigpending(&set) == 0);
148
+ for (sig = 1; sig < NSIG; sig++) {
148
+ for (sig = 1; sig < NSIG; sig++) {
149
+ if (sigismember(&set, sig)) {
149
+ if (sigismember(&set, sig)) {
150
+ fprintf(stderr, "Unexpected signal %d\n", sig);
150
+ fprintf(stderr, "Unexpected signal %d\n", sig);
151
+ return EXIT_FAILURE;
151
+ return EXIT_FAILURE;
152
+ }
152
+ }
153
+ }
153
+ }
154
+
154
+
155
+ return EXIT_SUCCESS;
155
+ return EXIT_SUCCESS;
156
+}
156
+}
157
--
157
--
158
2.47.0
158
2.47.0
diff view generated by jsdifflib