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 |