All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 00/12] gdbstub: Implement follow-fork-mode child
@ 2024-02-19 14:15 Ilya Leoshkevich
  2024-02-19 14:15 ` [PATCH v4 01/12] gdbstub: Support disablement in a multi-threaded process Ilya Leoshkevich
                   ` (12 more replies)
  0 siblings, 13 replies; 17+ messages in thread
From: Ilya Leoshkevich @ 2024-02-19 14:15 UTC (permalink / raw)
  To: Warner Losh, Alex Bennée, Richard Henderson, Riku Voipio,
	Laurent Vivier
  Cc: Kyle Evans, Philippe Mathieu-Daudé,
	Alexandre Iooss, Mahmoud Mandour, Pierrick Bouvier, qemu-devel,
	Ilya Leoshkevich

v3: https://lists.gnu.org/archive/html/qemu-devel/2024-02/msg03142.html
v3 -> v4: Address the review comments, add R-bs.
          Add the get_task_state() refactoring.
          Keep passing CPUState to gdbserver_fork_end() for tb_flush().
          Patches that need review: 02/12, 09/12-12/12.

v2: https://lists.gnu.org/archive/html/qemu-devel/2024-02/msg00810.html
v2 -> v3: Rebase on top of master.
          Fix a typo in the 01/11 commit message.

v1: https://lists.gnu.org/archive/html/qemu-devel/2024-01/msg06646.html
v1 -> v2: Factor out a number of prep patches;
          Add a state transition diagram comment (Alex).
          Improve a few comments;
          Extend the ts_tid fix to bsd.

Hi,

I needed to debug a linux-user crash between fork() and exec() [1] and
realized that gdbstub does not allow this. This series lifts this
restriction (one still cannot debug past exec() though). Patches 1-10
are preliminary refactorings, patch 11 is the implementation, and patch
12 is the test.

[1] https://lists.gnu.org/archive/html/qemu-devel/2024-01/msg06424.html

Best regards,
Ilya

Ilya Leoshkevich (12):
  gdbstub: Support disablement in a multi-threaded process
  {linux,bsd}-user: Introduce get_task_state()
  {linux,bsd}-user: Update ts_tid after fork()
  gdbstub: Introduce gdbserver_fork_start()
  {linux,bsd}-user: Pass pid to fork_end()
  {linux,bsd}-user: Pass pid to gdbserver_fork()
  gdbstub: Call gdbserver_fork() both in parent and in child
  gdbstub: Introduce gdb_handle_query_supported_user()
  gdbstub: Introduce gdb_handle_set_thread_user()
  gdbstub: Introduce gdb_handle_detach_user()
  gdbstub: Implement follow-fork-mode child
  tests/tcg: Add two follow-fork-mode tests

 bsd-user/bsd-file.h                           |   2 +-
 bsd-user/freebsd/os-proc.h                    |   6 +-
 bsd-user/main.c                               |   9 +-
 bsd-user/qemu.h                               |   7 +-
 bsd-user/signal.c                             |  20 +-
 gdbstub/gdbstub.c                             |  29 ++-
 gdbstub/internals.h                           |   3 +
 gdbstub/user-target.c                         |   4 +-
 gdbstub/user.c                                | 244 +++++++++++++++++-
 include/gdbstub/user.h                        |  10 +-
 include/user/safe-syscall.h                   |   2 +-
 linux-user/aarch64/cpu_loop.c                 |   2 +-
 linux-user/arm/cpu_loop.c                     |   4 +-
 linux-user/arm/signal.c                       |   2 +-
 linux-user/cris/cpu_loop.c                    |   2 +-
 linux-user/elfload.c                          |   6 +-
 linux-user/hppa/signal.c                      |   2 +-
 linux-user/linuxload.c                        |   2 +-
 linux-user/m68k/cpu_loop.c                    |   2 +-
 linux-user/m68k/target_cpu.h                  |   2 +-
 linux-user/main.c                             |   8 +-
 linux-user/mips/cpu_loop.c                    |   2 +-
 linux-user/ppc/signal.c                       |   4 +-
 linux-user/qemu.h                             |   5 +
 linux-user/riscv/cpu_loop.c                   |   2 +-
 linux-user/signal-common.h                    |   2 +-
 linux-user/signal.c                           |  30 +--
 linux-user/syscall.c                          |  32 +--
 linux-user/user-internals.h                   |   2 +-
 linux-user/vm86.c                             |  18 +-
 linux-user/xtensa/signal.c                    |   2 +-
 plugins/api.c                                 |   8 +-
 semihosting/arm-compat-semi.c                 |   8 +-
 tests/tcg/multiarch/Makefile.target           |  17 +-
 tests/tcg/multiarch/follow-fork-mode.c        |  56 ++++
 .../gdbstub/follow-fork-mode-child.py         |  40 +++
 .../gdbstub/follow-fork-mode-parent.py        |  16 ++
 37 files changed, 511 insertions(+), 101 deletions(-)
 create mode 100644 tests/tcg/multiarch/follow-fork-mode.c
 create mode 100644 tests/tcg/multiarch/gdbstub/follow-fork-mode-child.py
 create mode 100644 tests/tcg/multiarch/gdbstub/follow-fork-mode-parent.py

-- 
2.43.2



^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v4 01/12] gdbstub: Support disablement in a multi-threaded process
  2024-02-19 14:15 [PATCH v4 00/12] gdbstub: Implement follow-fork-mode child Ilya Leoshkevich
@ 2024-02-19 14:15 ` Ilya Leoshkevich
  2024-02-19 14:15 ` [PATCH v4 02/12] {linux,bsd}-user: Introduce get_task_state() Ilya Leoshkevich
                   ` (11 subsequent siblings)
  12 siblings, 0 replies; 17+ messages in thread
From: Ilya Leoshkevich @ 2024-02-19 14:15 UTC (permalink / raw)
  To: Warner Losh, Alex Bennée, Richard Henderson, Riku Voipio,
	Laurent Vivier
  Cc: Kyle Evans, Philippe Mathieu-Daudé,
	Alexandre Iooss, Mahmoud Mandour, Pierrick Bouvier, qemu-devel,
	Ilya Leoshkevich

The upcoming follow-fork-mode child support will require disabling
gdbstub in the parent process, which may have multiple threads (which
are represented as CPUs).

Loop over all CPUs in order to remove breakpoints and disable
single-step. Move the respective code into a separate function.

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
---
 gdbstub/user.c | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)

diff --git a/gdbstub/user.c b/gdbstub/user.c
index 14918d1a217..3ce20b7bbfc 100644
--- a/gdbstub/user.c
+++ b/gdbstub/user.c
@@ -356,16 +356,27 @@ int gdbserver_start(const char *port_or_path)
     return -1;
 }
 
+static void disable_gdbstub(CPUState *thread_cpu)
+{
+    CPUState *cpu;
+
+    close(gdbserver_user_state.fd);
+    gdbserver_user_state.fd = -1;
+    CPU_FOREACH(cpu) {
+        cpu_breakpoint_remove_all(cpu, BP_GDB);
+        /* no cpu_watchpoint_remove_all for user-mode */
+        cpu_single_step(cpu, 0);
+    }
+    tb_flush(thread_cpu);
+}
+
 /* Disable gdb stub for child processes.  */
 void gdbserver_fork(CPUState *cpu)
 {
     if (!gdbserver_state.init || gdbserver_user_state.fd < 0) {
         return;
     }
-    close(gdbserver_user_state.fd);
-    gdbserver_user_state.fd = -1;
-    cpu_breakpoint_remove_all(cpu, BP_GDB);
-    /* no cpu_watchpoint_remove_all for user-mode */
+    disable_gdbstub(cpu);
 }
 
 /*
-- 
2.43.2



^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v4 02/12] {linux,bsd}-user: Introduce get_task_state()
  2024-02-19 14:15 [PATCH v4 00/12] gdbstub: Implement follow-fork-mode child Ilya Leoshkevich
  2024-02-19 14:15 ` [PATCH v4 01/12] gdbstub: Support disablement in a multi-threaded process Ilya Leoshkevich
@ 2024-02-19 14:15 ` Ilya Leoshkevich
  2024-02-19 14:32   ` Warner Losh
  2024-02-19 20:46   ` Richard Henderson
  2024-02-19 14:15 ` [PATCH v4 03/12] {linux,bsd}-user: Update ts_tid after fork() Ilya Leoshkevich
                   ` (10 subsequent siblings)
  12 siblings, 2 replies; 17+ messages in thread
From: Ilya Leoshkevich @ 2024-02-19 14:15 UTC (permalink / raw)
  To: Warner Losh, Alex Bennée, Richard Henderson, Riku Voipio,
	Laurent Vivier
  Cc: Kyle Evans, Philippe Mathieu-Daudé,
	Alexandre Iooss, Mahmoud Mandour, Pierrick Bouvier, qemu-devel,
	Ilya Leoshkevich

A CPU's TaskState is stored in the CPUState's void *opaque field,
accessing which is somewhat awkward due to having to use a cast.
Introduce a wrapper and use it everywhere.

Suggested-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
---
 bsd-user/bsd-file.h           |  2 +-
 bsd-user/qemu.h               |  5 +++++
 bsd-user/signal.c             | 20 ++++++++++----------
 gdbstub/user-target.c         |  4 ++--
 include/user/safe-syscall.h   |  2 +-
 linux-user/aarch64/cpu_loop.c |  2 +-
 linux-user/arm/cpu_loop.c     |  4 ++--
 linux-user/arm/signal.c       |  2 +-
 linux-user/cris/cpu_loop.c    |  2 +-
 linux-user/elfload.c          |  6 +++---
 linux-user/hppa/signal.c      |  2 +-
 linux-user/linuxload.c        |  2 +-
 linux-user/m68k/cpu_loop.c    |  2 +-
 linux-user/m68k/target_cpu.h  |  2 +-
 linux-user/mips/cpu_loop.c    |  2 +-
 linux-user/ppc/signal.c       |  4 ++--
 linux-user/qemu.h             |  5 +++++
 linux-user/riscv/cpu_loop.c   |  2 +-
 linux-user/signal-common.h    |  2 +-
 linux-user/signal.c           | 30 +++++++++++++++---------------
 linux-user/syscall.c          | 26 +++++++++++++-------------
 linux-user/vm86.c             | 18 +++++++++---------
 linux-user/xtensa/signal.c    |  2 +-
 plugins/api.c                 |  8 ++++----
 semihosting/arm-compat-semi.c |  8 ++++----
 25 files changed, 87 insertions(+), 77 deletions(-)

diff --git a/bsd-user/bsd-file.h b/bsd-user/bsd-file.h
index 3c00dc00567..6fa2c30b4de 100644
--- a/bsd-user/bsd-file.h
+++ b/bsd-user/bsd-file.h
@@ -641,7 +641,7 @@ static abi_long do_bsd_readlink(CPUArchState *env, abi_long arg1,
     }
     if (strcmp(p1, "/proc/curproc/file") == 0) {
         CPUState *cpu = env_cpu(env);
-        TaskState *ts = (TaskState *)cpu->opaque;
+        TaskState *ts = get_task_state(cpu);
         strncpy(p2, ts->bprm->fullpath, arg3);
         ret = MIN((abi_long)strlen(ts->bprm->fullpath), arg3);
     } else {
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index dc842fffa7d..a2417b25156 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -110,6 +110,11 @@ typedef struct TaskState {
     struct target_sigaltstack sigaltstack_used;
 } __attribute__((aligned(16))) TaskState;
 
+static inline TaskState *get_task_state(CPUState *cs)
+{
+    return cs->opaque;
+}
+
 void stop_all_tasks(void);
 extern const char *interp_prefix;
 extern const char *qemu_uname_release;
diff --git a/bsd-user/signal.c b/bsd-user/signal.c
index f4352e4530f..e9f80a06d32 100644
--- a/bsd-user/signal.c
+++ b/bsd-user/signal.c
@@ -319,7 +319,7 @@ void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
 
 int block_signals(void)
 {
-    TaskState *ts = (TaskState *)thread_cpu->opaque;
+    TaskState *ts = get_task_state(thread_cpu);
     sigset_t set;
 
     /*
@@ -359,7 +359,7 @@ void dump_core_and_abort(int target_sig)
 {
     CPUState *cpu = thread_cpu;
     CPUArchState *env = cpu_env(cpu);
-    TaskState *ts = cpu->opaque;
+    TaskState *ts = get_task_state(cpu);
     int core_dumped = 0;
     int host_sig;
     struct sigaction act;
@@ -421,7 +421,7 @@ void queue_signal(CPUArchState *env, int sig, int si_type,
                   target_siginfo_t *info)
 {
     CPUState *cpu = env_cpu(env);
-    TaskState *ts = cpu->opaque;
+    TaskState *ts = get_task_state(cpu);
 
     trace_user_queue_signal(env, sig);
 
@@ -476,7 +476,7 @@ void force_sig_fault(int sig, int code, abi_ulong addr)
 static void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
 {
     CPUState *cpu = thread_cpu;
-    TaskState *ts = cpu->opaque;
+    TaskState *ts = get_task_state(cpu);
     target_siginfo_t tinfo;
     ucontext_t *uc = puc;
     struct emulated_sigtable *k;
@@ -585,7 +585,7 @@ static void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
 /* compare to kern/kern_sig.c sys_sigaltstack() and kern_sigaltstack() */
 abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
 {
-    TaskState *ts = (TaskState *)thread_cpu->opaque;
+    TaskState *ts = get_task_state(thread_cpu);
     int ret;
     target_stack_t oss;
 
@@ -714,7 +714,7 @@ int do_sigaction(int sig, const struct target_sigaction *act,
 static inline abi_ulong get_sigframe(struct target_sigaction *ka,
         CPUArchState *env, size_t frame_size)
 {
-    TaskState *ts = (TaskState *)thread_cpu->opaque;
+    TaskState *ts = get_task_state(thread_cpu);
     abi_ulong sp;
 
     /* Use default user stack */
@@ -789,7 +789,7 @@ static int reset_signal_mask(target_ucontext_t *ucontext)
     int i;
     sigset_t blocked;
     target_sigset_t target_set;
-    TaskState *ts = (TaskState *)thread_cpu->opaque;
+    TaskState *ts = get_task_state(thread_cpu);
 
     for (i = 0; i < TARGET_NSIG_WORDS; i++) {
         __get_user(target_set.__bits[i], &ucontext->uc_sigmask.__bits[i]);
@@ -839,7 +839,7 @@ badframe:
 
 void signal_init(void)
 {
-    TaskState *ts = (TaskState *)thread_cpu->opaque;
+    TaskState *ts = get_task_state(thread_cpu);
     struct sigaction act;
     struct sigaction oact;
     int i;
@@ -878,7 +878,7 @@ static void handle_pending_signal(CPUArchState *env, int sig,
                                   struct emulated_sigtable *k)
 {
     CPUState *cpu = env_cpu(env);
-    TaskState *ts = cpu->opaque;
+    TaskState *ts = get_task_state(cpu);
     struct target_sigaction *sa;
     int code;
     sigset_t set;
@@ -967,7 +967,7 @@ void process_pending_signals(CPUArchState *env)
     int sig;
     sigset_t *blocked_set, set;
     struct emulated_sigtable *k;
-    TaskState *ts = cpu->opaque;
+    TaskState *ts = get_task_state(cpu);
 
     while (qatomic_read(&ts->signal_pending)) {
         sigfillset(&set);
diff --git a/gdbstub/user-target.c b/gdbstub/user-target.c
index b7d4c37cd81..6646684a4c6 100644
--- a/gdbstub/user-target.c
+++ b/gdbstub/user-target.c
@@ -204,7 +204,7 @@ int gdb_target_signal_to_gdb(int sig)
 
 int gdb_get_cpu_index(CPUState *cpu)
 {
-    TaskState *ts = (TaskState *) cpu->opaque;
+    TaskState *ts = get_task_state(cpu);
     return ts ? ts->ts_tid : -1;
 }
 
@@ -399,7 +399,7 @@ void gdb_handle_query_xfer_exec_file(GArray *params, void *user_ctx)
         return;
     }
 
-    TaskState *ts = cpu->opaque;
+    TaskState *ts = get_task_state(cpu);
     if (!ts || !ts->bprm || !ts->bprm->filename) {
         gdb_put_packet("E00");
         return;
diff --git a/include/user/safe-syscall.h b/include/user/safe-syscall.h
index 27b71cdbd8e..aa075f4d5cd 100644
--- a/include/user/safe-syscall.h
+++ b/include/user/safe-syscall.h
@@ -134,7 +134,7 @@ extern char safe_syscall_start[];
 extern char safe_syscall_end[];
 
 #define safe_syscall(...)                                                 \
-    safe_syscall_base(&((TaskState *)thread_cpu->opaque)->signal_pending, \
+    safe_syscall_base(&get_task_state(thread_cpu)->signal_pending,        \
                       __VA_ARGS__)
 
 #endif
diff --git a/linux-user/aarch64/cpu_loop.c b/linux-user/aarch64/cpu_loop.c
index 8c20dc8a39a..71cdc8be50c 100644
--- a/linux-user/aarch64/cpu_loop.c
+++ b/linux-user/aarch64/cpu_loop.c
@@ -189,7 +189,7 @@ void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
 {
     ARMCPU *cpu = env_archcpu(env);
     CPUState *cs = env_cpu(env);
-    TaskState *ts = cs->opaque;
+    TaskState *ts = get_task_state(cs);
     struct image_info *info = ts->info;
     int i;
 
diff --git a/linux-user/arm/cpu_loop.c b/linux-user/arm/cpu_loop.c
index b404117ff30..db1a41e27f4 100644
--- a/linux-user/arm/cpu_loop.c
+++ b/linux-user/arm/cpu_loop.c
@@ -263,7 +263,7 @@ static bool insn_is_linux_bkpt(uint32_t opcode, bool is_thumb)
 
 static bool emulate_arm_fpa11(CPUARMState *env, uint32_t opcode)
 {
-    TaskState *ts = env_cpu(env)->opaque;
+    TaskState *ts = get_task_state(env_cpu(env));
     int rc = EmulateAll(opcode, &ts->fpa, env);
     int raise, enabled;
 
@@ -514,7 +514,7 @@ void cpu_loop(CPUARMState *env)
 void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
 {
     CPUState *cpu = env_cpu(env);
-    TaskState *ts = cpu->opaque;
+    TaskState *ts = get_task_state(cpu);
     struct image_info *info = ts->info;
     int i;
 
diff --git a/linux-user/arm/signal.c b/linux-user/arm/signal.c
index f77f692c63f..59806335f5b 100644
--- a/linux-user/arm/signal.c
+++ b/linux-user/arm/signal.c
@@ -177,7 +177,7 @@ setup_return(CPUARMState *env, struct target_sigaction *ka, int usig,
     abi_ulong handler = 0;
     abi_ulong handler_fdpic_GOT = 0;
     abi_ulong retcode;
-    bool is_fdpic = info_is_fdpic(((TaskState *)thread_cpu->opaque)->info);
+    bool is_fdpic = info_is_fdpic(get_task_state(thread_cpu)->info);
     bool is_rt = ka->sa_flags & TARGET_SA_SIGINFO;
     bool thumb;
 
diff --git a/linux-user/cris/cpu_loop.c b/linux-user/cris/cpu_loop.c
index 01e6ff16fc9..04c9086b6dc 100644
--- a/linux-user/cris/cpu_loop.c
+++ b/linux-user/cris/cpu_loop.c
@@ -72,7 +72,7 @@ void cpu_loop(CPUCRISState *env)
 void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
 {
     CPUState *cpu = env_cpu(env);
-    TaskState *ts = cpu->opaque;
+    TaskState *ts = get_task_state(cpu);
     struct image_info *info = ts->info;
 
     env->regs[0] = regs->r0;
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index b8eef893d0c..6de72da585d 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -4499,7 +4499,7 @@ static int write_note(struct memelfnote *men, int fd)
 static void fill_thread_info(struct elf_note_info *info, const CPUArchState *env)
 {
     CPUState *cpu = env_cpu((CPUArchState *)env);
-    TaskState *ts = (TaskState *)cpu->opaque;
+    TaskState *ts = get_task_state(cpu);
     struct elf_thread_status *ets;
 
     ets = g_malloc0(sizeof (*ets));
@@ -4529,7 +4529,7 @@ static int fill_note_info(struct elf_note_info *info,
 {
 #define NUMNOTES 3
     CPUState *cpu = env_cpu((CPUArchState *)env);
-    TaskState *ts = (TaskState *)cpu->opaque;
+    TaskState *ts = get_task_state(cpu);
     int i;
 
     info->notes = g_new0(struct memelfnote, NUMNOTES);
@@ -4653,7 +4653,7 @@ static int write_note_info(struct elf_note_info *info, int fd)
 static int elf_core_dump(int signr, const CPUArchState *env)
 {
     const CPUState *cpu = env_cpu((CPUArchState *)env);
-    const TaskState *ts = (const TaskState *)cpu->opaque;
+    const TaskState *ts = (const TaskState *)get_task_state((CPUState *)cpu);
     struct vm_area_struct *vma = NULL;
     g_autofree char *corefile = NULL;
     struct elf_note_info info;
diff --git a/linux-user/hppa/signal.c b/linux-user/hppa/signal.c
index d08a97dae61..c84557e906a 100644
--- a/linux-user/hppa/signal.c
+++ b/linux-user/hppa/signal.c
@@ -112,7 +112,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
     abi_ulong frame_addr, sp, haddr;
     struct target_rt_sigframe *frame;
     int i;
-    TaskState *ts = (TaskState *)thread_cpu->opaque;
+    TaskState *ts = get_task_state(thread_cpu);
 
     sp = get_sp_from_cpustate(env);
     if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp)) {
diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c
index 4a794f8cea1..37f132be4af 100644
--- a/linux-user/linuxload.c
+++ b/linux-user/linuxload.c
@@ -89,7 +89,7 @@ static int prepare_binprm(struct linux_binprm *bprm)
 abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp,
                               abi_ulong stringp, int push_ptr)
 {
-    TaskState *ts = (TaskState *)thread_cpu->opaque;
+    TaskState *ts = get_task_state(thread_cpu);
     int n = sizeof(abi_ulong);
     abi_ulong envp;
     abi_ulong argv;
diff --git a/linux-user/m68k/cpu_loop.c b/linux-user/m68k/cpu_loop.c
index caead1cb741..f79b8e4ab05 100644
--- a/linux-user/m68k/cpu_loop.c
+++ b/linux-user/m68k/cpu_loop.c
@@ -95,7 +95,7 @@ void cpu_loop(CPUM68KState *env)
 void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
 {
     CPUState *cpu = env_cpu(env);
-    TaskState *ts = cpu->opaque;
+    TaskState *ts = get_task_state(cpu);
     struct image_info *info = ts->info;
 
     env->pc = regs->pc;
diff --git a/linux-user/m68k/target_cpu.h b/linux-user/m68k/target_cpu.h
index c3f288dfe83..4b40c09a8d6 100644
--- a/linux-user/m68k/target_cpu.h
+++ b/linux-user/m68k/target_cpu.h
@@ -37,7 +37,7 @@ static inline void cpu_clone_regs_parent(CPUM68KState *env, unsigned flags)
 static inline void cpu_set_tls(CPUM68KState *env, target_ulong newtls)
 {
     CPUState *cs = env_cpu(env);
-    TaskState *ts = cs->opaque;
+    TaskState *ts = get_task_state(cs);
 
     ts->tp_value = newtls;
 }
diff --git a/linux-user/mips/cpu_loop.c b/linux-user/mips/cpu_loop.c
index 990b03e727b..462387a0737 100644
--- a/linux-user/mips/cpu_loop.c
+++ b/linux-user/mips/cpu_loop.c
@@ -214,7 +214,7 @@ done_syscall:
 void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
 {
     CPUState *cpu = env_cpu(env);
-    TaskState *ts = cpu->opaque;
+    TaskState *ts = get_task_state(cpu);
     struct image_info *info = ts->info;
     int i;
 
diff --git a/linux-user/ppc/signal.c b/linux-user/ppc/signal.c
index 7e7302823b0..c232424c1e8 100644
--- a/linux-user/ppc/signal.c
+++ b/linux-user/ppc/signal.c
@@ -486,7 +486,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
     int i, err = 0;
 #if defined(TARGET_PPC64)
     struct target_sigcontext *sc = 0;
-    struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
+    struct image_info *image = get_task_state(thread_cpu)->info;
 #endif
 
     rt_sf_addr = get_sigframe(ka, env, sizeof(*rt_sf));
@@ -673,7 +673,7 @@ abi_long do_swapcontext(CPUArchState *env, abi_ulong uold_ctx,
     }
 
     if (uold_ctx) {
-        TaskState *ts = (TaskState *)thread_cpu->opaque;
+        TaskState *ts = get_task_state(thread_cpu);
 
         if (!lock_user_struct(VERIFY_WRITE, uctx, uold_ctx, 1)) {
             return -TARGET_EFAULT;
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 4de9ec783f6..32cd43d9eff 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -162,6 +162,11 @@ typedef struct TaskState {
     uint64_t start_boottime;
 } TaskState;
 
+static inline TaskState *get_task_state(CPUState *cs)
+{
+    return cs->opaque;
+}
+
 abi_long do_brk(abi_ulong new_brk);
 int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *pathname,
                     int flags, mode_t mode, bool safe);
diff --git a/linux-user/riscv/cpu_loop.c b/linux-user/riscv/cpu_loop.c
index bffca7db127..52c49c2e426 100644
--- a/linux-user/riscv/cpu_loop.c
+++ b/linux-user/riscv/cpu_loop.c
@@ -97,7 +97,7 @@ void cpu_loop(CPURISCVState *env)
 void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
 {
     CPUState *cpu = env_cpu(env);
-    TaskState *ts = cpu->opaque;
+    TaskState *ts = get_task_state(cpu);
     struct image_info *info = ts->info;
 
     env->pc = regs->sepc;
diff --git a/linux-user/signal-common.h b/linux-user/signal-common.h
index 3e2dc604c2f..a7df12fc445 100644
--- a/linux-user/signal-common.h
+++ b/linux-user/signal-common.h
@@ -113,7 +113,7 @@ int process_sigsuspend_mask(sigset_t **pset, target_ulong sigset,
 static inline void finish_sigsuspend_mask(int ret)
 {
     if (ret != -QEMU_ERESTARTSYS) {
-        TaskState *ts = (TaskState *)thread_cpu->opaque;
+        TaskState *ts = get_task_state(thread_cpu);
         ts->in_sigsuspend = 1;
     }
 }
diff --git a/linux-user/signal.c b/linux-user/signal.c
index d3e62ab030f..cc7dd78e41f 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -172,7 +172,7 @@ void target_to_host_old_sigset(sigset_t *sigset,
 
 int block_signals(void)
 {
-    TaskState *ts = (TaskState *)thread_cpu->opaque;
+    TaskState *ts = get_task_state(thread_cpu);
     sigset_t set;
 
     /* It's OK to block everything including SIGSEGV, because we won't
@@ -194,7 +194,7 @@ int block_signals(void)
  */
 int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
 {
-    TaskState *ts = (TaskState *)thread_cpu->opaque;
+    TaskState *ts = get_task_state(thread_cpu);
 
     if (oldset) {
         *oldset = ts->signal_mask;
@@ -237,7 +237,7 @@ int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
  */
 void set_sigmask(const sigset_t *set)
 {
-    TaskState *ts = (TaskState *)thread_cpu->opaque;
+    TaskState *ts = get_task_state(thread_cpu);
 
     ts->signal_mask = *set;
 }
@@ -246,7 +246,7 @@ void set_sigmask(const sigset_t *set)
 
 int on_sig_stack(unsigned long sp)
 {
-    TaskState *ts = (TaskState *)thread_cpu->opaque;
+    TaskState *ts = get_task_state(thread_cpu);
 
     return (sp - ts->sigaltstack_used.ss_sp
             < ts->sigaltstack_used.ss_size);
@@ -254,7 +254,7 @@ int on_sig_stack(unsigned long sp)
 
 int sas_ss_flags(unsigned long sp)
 {
-    TaskState *ts = (TaskState *)thread_cpu->opaque;
+    TaskState *ts = get_task_state(thread_cpu);
 
     return (ts->sigaltstack_used.ss_size == 0 ? SS_DISABLE
             : on_sig_stack(sp) ? SS_ONSTACK : 0);
@@ -265,7 +265,7 @@ abi_ulong target_sigsp(abi_ulong sp, struct target_sigaction *ka)
     /*
      * This is the X/Open sanctioned signal stack switching.
      */
-    TaskState *ts = (TaskState *)thread_cpu->opaque;
+    TaskState *ts = get_task_state(thread_cpu);
 
     if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp)) {
         return ts->sigaltstack_used.ss_sp + ts->sigaltstack_used.ss_size;
@@ -275,7 +275,7 @@ abi_ulong target_sigsp(abi_ulong sp, struct target_sigaction *ka)
 
 void target_save_altstack(target_stack_t *uss, CPUArchState *env)
 {
-    TaskState *ts = (TaskState *)thread_cpu->opaque;
+    TaskState *ts = get_task_state(thread_cpu);
 
     __put_user(ts->sigaltstack_used.ss_sp, &uss->ss_sp);
     __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &uss->ss_flags);
@@ -284,7 +284,7 @@ void target_save_altstack(target_stack_t *uss, CPUArchState *env)
 
 abi_long target_restore_altstack(target_stack_t *uss, CPUArchState *env)
 {
-    TaskState *ts = (TaskState *)thread_cpu->opaque;
+    TaskState *ts = get_task_state(thread_cpu);
     size_t minstacksize = TARGET_MINSIGSTKSZ;
     target_stack_t ss;
 
@@ -571,7 +571,7 @@ static void signal_table_init(void)
 
 void signal_init(void)
 {
-    TaskState *ts = (TaskState *)thread_cpu->opaque;
+    TaskState *ts = get_task_state(thread_cpu);
     struct sigaction act, oact;
 
     /* initialize signal conversion tables */
@@ -730,7 +730,7 @@ static G_NORETURN
 void dump_core_and_abort(CPUArchState *env, int target_sig)
 {
     CPUState *cpu = env_cpu(env);
-    TaskState *ts = (TaskState *)cpu->opaque;
+    TaskState *ts = get_task_state(cpu);
     int host_sig, core_dumped = 0;
 
     /* On exit, undo the remapping of SIGABRT. */
@@ -769,7 +769,7 @@ void queue_signal(CPUArchState *env, int sig, int si_type,
                   target_siginfo_t *info)
 {
     CPUState *cpu = env_cpu(env);
-    TaskState *ts = cpu->opaque;
+    TaskState *ts = get_task_state(cpu);
 
     trace_user_queue_signal(env, sig);
 
@@ -954,7 +954,7 @@ static void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
 {
     CPUState *cpu = thread_cpu;
     CPUArchState *env = cpu_env(cpu);
-    TaskState *ts = cpu->opaque;
+    TaskState *ts = get_task_state(cpu);
     target_siginfo_t tinfo;
     host_sigcontext *uc = puc;
     struct emulated_sigtable *k;
@@ -1174,7 +1174,7 @@ static void handle_pending_signal(CPUArchState *cpu_env, int sig,
     sigset_t set;
     target_sigset_t target_old_set;
     struct target_sigaction *sa;
-    TaskState *ts = cpu->opaque;
+    TaskState *ts = get_task_state(cpu);
 
     trace_user_handle_signal(cpu_env, sig);
     /* dequeue signal */
@@ -1256,7 +1256,7 @@ void process_pending_signals(CPUArchState *cpu_env)
 {
     CPUState *cpu = env_cpu(cpu_env);
     int sig;
-    TaskState *ts = cpu->opaque;
+    TaskState *ts = get_task_state(cpu);
     sigset_t set;
     sigset_t *blocked_set;
 
@@ -1316,7 +1316,7 @@ void process_pending_signals(CPUArchState *cpu_env)
 int process_sigsuspend_mask(sigset_t **pset, target_ulong sigset,
                             target_ulong sigsize)
 {
-    TaskState *ts = (TaskState *)thread_cpu->opaque;
+    TaskState *ts = get_task_state(thread_cpu);
     sigset_t *host_set = &ts->sigsuspend_mask;
     target_sigset_t *target_sigset;
 
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index e384e142489..3e105488ee2 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -6515,7 +6515,7 @@ static void *clone_func(void *arg)
     env = info->env;
     cpu = env_cpu(env);
     thread_cpu = cpu;
-    ts = (TaskState *)cpu->opaque;
+    ts = get_task_state(cpu);
     info->tid = sys_gettid();
     task_settid(ts);
     if (info->child_tidptr)
@@ -6557,7 +6557,7 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
         flags &= ~(CLONE_VFORK | CLONE_VM);
 
     if (flags & CLONE_VM) {
-        TaskState *parent_ts = (TaskState *)cpu->opaque;
+        TaskState *parent_ts = get_task_state(cpu);
         new_thread_info info;
         pthread_attr_t attr;
 
@@ -6680,7 +6680,7 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
                 put_user_u32(sys_gettid(), child_tidptr);
             if (flags & CLONE_PARENT_SETTID)
                 put_user_u32(sys_gettid(), parent_tidptr);
-            ts = (TaskState *)cpu->opaque;
+            ts = get_task_state(cpu);
             if (flags & CLONE_SETTLS)
                 cpu_set_tls (env, newtls);
             if (flags & CLONE_CHILD_CLEARTID)
@@ -7946,7 +7946,7 @@ int host_to_target_waitstatus(int status)
 static int open_self_cmdline(CPUArchState *cpu_env, int fd)
 {
     CPUState *cpu = env_cpu(cpu_env);
-    struct linux_binprm *bprm = ((TaskState *)cpu->opaque)->bprm;
+    struct linux_binprm *bprm = get_task_state(cpu)->bprm;
     int i;
 
     for (i = 0; i < bprm->argc; i++) {
@@ -8130,7 +8130,7 @@ static int open_self_smaps(CPUArchState *cpu_env, int fd)
 static int open_self_stat(CPUArchState *cpu_env, int fd)
 {
     CPUState *cpu = env_cpu(cpu_env);
-    TaskState *ts = cpu->opaque;
+    TaskState *ts = get_task_state(cpu);
     g_autoptr(GString) buf = g_string_new(NULL);
     int i;
 
@@ -8171,7 +8171,7 @@ static int open_self_stat(CPUArchState *cpu_env, int fd)
 static int open_self_auxv(CPUArchState *cpu_env, int fd)
 {
     CPUState *cpu = env_cpu(cpu_env);
-    TaskState *ts = cpu->opaque;
+    TaskState *ts = get_task_state(cpu);
     abi_ulong auxv = ts->info->saved_auxv;
     abi_ulong len = ts->info->auxv_len;
     char *ptr;
@@ -8996,7 +8996,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
         pthread_mutex_lock(&clone_lock);
 
         if (CPU_NEXT(first_cpu)) {
-            TaskState *ts = cpu->opaque;
+            TaskState *ts = get_task_state(cpu);
 
             if (ts->child_tidptr) {
                 put_user_u32(0, ts->child_tidptr);
@@ -9423,7 +9423,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
 #ifdef TARGET_NR_pause /* not on alpha */
     case TARGET_NR_pause:
         if (!block_signals()) {
-            sigsuspend(&((TaskState *)cpu->opaque)->signal_mask);
+            sigsuspend(&get_task_state(cpu)->signal_mask);
         }
         return -TARGET_EINTR;
 #endif
@@ -9989,7 +9989,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
             sigset_t *set;
 
 #if defined(TARGET_ALPHA)
-            TaskState *ts = cpu->opaque;
+            TaskState *ts = get_task_state(cpu);
             /* target_to_host_old_sigset will bswap back */
             abi_ulong mask = tswapal(arg1);
             set = &ts->sigsuspend_mask;
@@ -10390,7 +10390,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
     case TARGET_NR_mprotect:
         arg1 = cpu_untagged_addr(cpu, arg1);
         {
-            TaskState *ts = cpu->opaque;
+            TaskState *ts = get_task_state(cpu);
             /* Special hack to detect libc making the stack executable.  */
             if ((arg3 & PROT_GROWSDOWN)
                 && arg1 >= ts->info->stack_limit
@@ -12521,7 +12521,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
       return do_set_thread_area(cpu_env, arg1);
 #elif defined(TARGET_M68K)
       {
-          TaskState *ts = cpu->opaque;
+          TaskState *ts = get_task_state(cpu);
           ts->tp_value = arg1;
           return 0;
       }
@@ -12535,7 +12535,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
         return do_get_thread_area(cpu_env, arg1);
 #elif defined(TARGET_M68K)
         {
-            TaskState *ts = cpu->opaque;
+            TaskState *ts = get_task_state(cpu);
             return ts->tp_value;
         }
 #else
@@ -12660,7 +12660,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
 #if defined(TARGET_NR_set_tid_address)
     case TARGET_NR_set_tid_address:
     {
-        TaskState *ts = cpu->opaque;
+        TaskState *ts = get_task_state(cpu);
         ts->child_tidptr = arg1;
         /* do not call host set_tid_address() syscall, instead return tid() */
         return get_errno(sys_gettid());
diff --git a/linux-user/vm86.c b/linux-user/vm86.c
index c2facf3fc2d..9f512a2242b 100644
--- a/linux-user/vm86.c
+++ b/linux-user/vm86.c
@@ -74,7 +74,7 @@ static inline unsigned int vm_getl(CPUX86State *env,
 void save_v86_state(CPUX86State *env)
 {
     CPUState *cs = env_cpu(env);
-    TaskState *ts = cs->opaque;
+    TaskState *ts = get_task_state(cs);
     struct target_vm86plus_struct * target_v86;
 
     if (!lock_user_struct(VERIFY_WRITE, target_v86, ts->target_v86, 0))
@@ -134,7 +134,7 @@ static inline void return_to_32bit(CPUX86State *env, int retval)
 static inline int set_IF(CPUX86State *env)
 {
     CPUState *cs = env_cpu(env);
-    TaskState *ts = cs->opaque;
+    TaskState *ts = get_task_state(cs);
 
     ts->v86flags |= VIF_MASK;
     if (ts->v86flags & VIP_MASK) {
@@ -147,7 +147,7 @@ static inline int set_IF(CPUX86State *env)
 static inline void clear_IF(CPUX86State *env)
 {
     CPUState *cs = env_cpu(env);
-    TaskState *ts = cs->opaque;
+    TaskState *ts = get_task_state(cs);
 
     ts->v86flags &= ~VIF_MASK;
 }
@@ -165,7 +165,7 @@ static inline void clear_AC(CPUX86State *env)
 static inline int set_vflags_long(unsigned long eflags, CPUX86State *env)
 {
     CPUState *cs = env_cpu(env);
-    TaskState *ts = cs->opaque;
+    TaskState *ts = get_task_state(cs);
 
     set_flags(ts->v86flags, eflags, ts->v86mask);
     set_flags(env->eflags, eflags, SAFE_MASK);
@@ -179,7 +179,7 @@ static inline int set_vflags_long(unsigned long eflags, CPUX86State *env)
 static inline int set_vflags_short(unsigned short flags, CPUX86State *env)
 {
     CPUState *cs = env_cpu(env);
-    TaskState *ts = cs->opaque;
+    TaskState *ts = get_task_state(cs);
 
     set_flags(ts->v86flags, flags, ts->v86mask & 0xffff);
     set_flags(env->eflags, flags, SAFE_MASK);
@@ -193,7 +193,7 @@ static inline int set_vflags_short(unsigned short flags, CPUX86State *env)
 static inline unsigned int get_vflags(CPUX86State *env)
 {
     CPUState *cs = env_cpu(env);
-    TaskState *ts = cs->opaque;
+    TaskState *ts = get_task_state(cs);
     unsigned int flags;
 
     flags = env->eflags & RETURN_MASK;
@@ -210,7 +210,7 @@ static inline unsigned int get_vflags(CPUX86State *env)
 static void do_int(CPUX86State *env, int intno)
 {
     CPUState *cs = env_cpu(env);
-    TaskState *ts = cs->opaque;
+    TaskState *ts = get_task_state(cs);
     uint32_t int_addr, segoffs, ssp;
     unsigned int sp;
 
@@ -269,7 +269,7 @@ void handle_vm86_trap(CPUX86State *env, int trapno)
 void handle_vm86_fault(CPUX86State *env)
 {
     CPUState *cs = env_cpu(env);
-    TaskState *ts = cs->opaque;
+    TaskState *ts = get_task_state(cs);
     uint32_t csp, ssp;
     unsigned int ip, sp, newflags, newip, newcs, opcode, intno;
     int data32, pref_done;
@@ -394,7 +394,7 @@ void handle_vm86_fault(CPUX86State *env)
 int do_vm86(CPUX86State *env, long subfunction, abi_ulong vm86_addr)
 {
     CPUState *cs = env_cpu(env);
-    TaskState *ts = cs->opaque;
+    TaskState *ts = get_task_state(cs);
     struct target_vm86plus_struct * target_v86;
     int ret;
 
diff --git a/linux-user/xtensa/signal.c b/linux-user/xtensa/signal.c
index 32dcfa52291..003208a9161 100644
--- a/linux-user/xtensa/signal.c
+++ b/linux-user/xtensa/signal.c
@@ -157,7 +157,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
 {
     abi_ulong frame_addr;
     struct target_rt_sigframe *frame;
-    int is_fdpic = info_is_fdpic(((TaskState *)thread_cpu->opaque)->info);
+    int is_fdpic = info_is_fdpic(get_task_state(thread_cpu)->info);
     abi_ulong handler = 0;
     abi_ulong handler_fdpic_GOT = 0;
     uint32_t ra;
diff --git a/plugins/api.c b/plugins/api.c
index 5521b0ad36c..1d7b72c0f67 100644
--- a/plugins/api.c
+++ b/plugins/api.c
@@ -392,7 +392,7 @@ const char *qemu_plugin_path_to_binary(void)
 {
     char *path = NULL;
 #ifdef CONFIG_USER_ONLY
-    TaskState *ts = (TaskState *) current_cpu->opaque;
+    TaskState *ts = get_task_state(current_cpu);
     path = g_strdup(ts->bprm->filename);
 #endif
     return path;
@@ -402,7 +402,7 @@ uint64_t qemu_plugin_start_code(void)
 {
     uint64_t start = 0;
 #ifdef CONFIG_USER_ONLY
-    TaskState *ts = (TaskState *) current_cpu->opaque;
+    TaskState *ts = get_task_state(current_cpu);
     start = ts->info->start_code;
 #endif
     return start;
@@ -412,7 +412,7 @@ uint64_t qemu_plugin_end_code(void)
 {
     uint64_t end = 0;
 #ifdef CONFIG_USER_ONLY
-    TaskState *ts = (TaskState *) current_cpu->opaque;
+    TaskState *ts = get_task_state(current_cpu);
     end = ts->info->end_code;
 #endif
     return end;
@@ -422,7 +422,7 @@ uint64_t qemu_plugin_entry_code(void)
 {
     uint64_t entry = 0;
 #ifdef CONFIG_USER_ONLY
-    TaskState *ts = (TaskState *) current_cpu->opaque;
+    TaskState *ts = get_task_state(current_cpu);
     entry = ts->info->entry;
 #endif
     return entry;
diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
index 329ea112607..d78c6428b90 100644
--- a/semihosting/arm-compat-semi.c
+++ b/semihosting/arm-compat-semi.c
@@ -214,7 +214,7 @@ static target_ulong syscall_err;
 static inline uint32_t get_swi_errno(CPUState *cs)
 {
 #ifdef CONFIG_USER_ONLY
-    TaskState *ts = cs->opaque;
+    TaskState *ts = get_task_state(cs);
 
     return ts->swi_errno;
 #else
@@ -226,7 +226,7 @@ static void common_semi_cb(CPUState *cs, uint64_t ret, int err)
 {
     if (err) {
 #ifdef CONFIG_USER_ONLY
-        TaskState *ts = cs->opaque;
+        TaskState *ts = get_task_state(cs);
         ts->swi_errno = err;
 #else
         syscall_err = err;
@@ -586,7 +586,7 @@ void do_common_semihosting(CPUState *cs)
 #if !defined(CONFIG_USER_ONLY)
             const char *cmdline;
 #else
-            TaskState *ts = cs->opaque;
+            TaskState *ts = get_task_state(cs);
 #endif
             GET_ARG(0);
             GET_ARG(1);
@@ -664,7 +664,7 @@ void do_common_semihosting(CPUState *cs)
             target_ulong retvals[4];
             int i;
 #ifdef CONFIG_USER_ONLY
-            TaskState *ts = cs->opaque;
+            TaskState *ts = get_task_state(cs);
             target_ulong limit;
 #else
             LayoutInfo info = common_semi_find_bases(cs);
-- 
2.43.2



^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v4 03/12] {linux,bsd}-user: Update ts_tid after fork()
  2024-02-19 14:15 [PATCH v4 00/12] gdbstub: Implement follow-fork-mode child Ilya Leoshkevich
  2024-02-19 14:15 ` [PATCH v4 01/12] gdbstub: Support disablement in a multi-threaded process Ilya Leoshkevich
  2024-02-19 14:15 ` [PATCH v4 02/12] {linux,bsd}-user: Introduce get_task_state() Ilya Leoshkevich
@ 2024-02-19 14:15 ` Ilya Leoshkevich
  2024-02-19 14:33   ` Warner Losh
  2024-02-19 14:15 ` [PATCH v4 04/12] gdbstub: Introduce gdbserver_fork_start() Ilya Leoshkevich
                   ` (9 subsequent siblings)
  12 siblings, 1 reply; 17+ messages in thread
From: Ilya Leoshkevich @ 2024-02-19 14:15 UTC (permalink / raw)
  To: Warner Losh, Alex Bennée, Richard Henderson, Riku Voipio,
	Laurent Vivier
  Cc: Kyle Evans, Philippe Mathieu-Daudé,
	Alexandre Iooss, Mahmoud Mandour, Pierrick Bouvier, qemu-devel,
	Ilya Leoshkevich

Currently ts_tid contains the parent tid after fork(), which is not
correct. So far it has not affected anything, but the upcoming
follow-fork-mode child support relies on the correct value, so fix it.

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
---
 bsd-user/main.c   | 1 +
 linux-user/main.c | 1 +
 2 files changed, 2 insertions(+)

diff --git a/bsd-user/main.c b/bsd-user/main.c
index e5efb7b8458..72289673a94 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -127,6 +127,7 @@ void fork_end(int child)
          * state, so we don't need to end_exclusive() here.
          */
         qemu_init_cpu_list();
+        get_task_state(thread_cpu)->ts_tid = qemu_get_thread_id();
         gdbserver_fork(thread_cpu);
     } else {
         mmap_fork_end(child);
diff --git a/linux-user/main.c b/linux-user/main.c
index 74b2fbb3938..1d53f708354 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -160,6 +160,7 @@ void fork_end(int child)
             }
         }
         qemu_init_cpu_list();
+        get_task_state(thread_cpu)->ts_tid = qemu_get_thread_id();
         gdbserver_fork(thread_cpu);
     } else {
         cpu_list_unlock();
-- 
2.43.2



^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v4 04/12] gdbstub: Introduce gdbserver_fork_start()
  2024-02-19 14:15 [PATCH v4 00/12] gdbstub: Implement follow-fork-mode child Ilya Leoshkevich
                   ` (2 preceding siblings ...)
  2024-02-19 14:15 ` [PATCH v4 03/12] {linux,bsd}-user: Update ts_tid after fork() Ilya Leoshkevich
@ 2024-02-19 14:15 ` Ilya Leoshkevich
  2024-02-19 14:15 ` [PATCH v4 05/12] {linux,bsd}-user: Pass pid to fork_end() Ilya Leoshkevich
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 17+ messages in thread
From: Ilya Leoshkevich @ 2024-02-19 14:15 UTC (permalink / raw)
  To: Warner Losh, Alex Bennée, Richard Henderson, Riku Voipio,
	Laurent Vivier
  Cc: Kyle Evans, Philippe Mathieu-Daudé,
	Alexandre Iooss, Mahmoud Mandour, Pierrick Bouvier, qemu-devel,
	Ilya Leoshkevich

The upcoming follow-fork-mode child support requires knowing when
fork() is about to happen in order to initialize its state. Add a hook
for that.

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
---
 bsd-user/main.c        | 1 +
 gdbstub/user.c         | 4 ++++
 include/gdbstub/user.h | 5 +++++
 linux-user/main.c      | 1 +
 4 files changed, 11 insertions(+)

diff --git a/bsd-user/main.c b/bsd-user/main.c
index 72289673a94..35a27a07c8d 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -106,6 +106,7 @@ void fork_start(void)
     start_exclusive();
     cpu_list_lock();
     mmap_fork_start();
+    gdbserver_fork_start();
 }
 
 void fork_end(int child)
diff --git a/gdbstub/user.c b/gdbstub/user.c
index 3ce20b7bbfc..536fb43b03e 100644
--- a/gdbstub/user.c
+++ b/gdbstub/user.c
@@ -356,6 +356,10 @@ int gdbserver_start(const char *port_or_path)
     return -1;
 }
 
+void gdbserver_fork_start(void)
+{
+}
+
 static void disable_gdbstub(CPUState *thread_cpu)
 {
     CPUState *cpu;
diff --git a/include/gdbstub/user.h b/include/gdbstub/user.h
index 68b6534130c..e33f8d9a9a6 100644
--- a/include/gdbstub/user.h
+++ b/include/gdbstub/user.h
@@ -45,6 +45,11 @@ static inline int gdb_handlesig(CPUState *cpu, int sig)
  */
 void gdb_signalled(CPUArchState *as, int sig);
 
+/**
+ * gdbserver_fork_start() - inform gdb of the upcoming fork()
+ */
+void gdbserver_fork_start(void);
+
 /**
  * gdbserver_fork() - disable gdb stub for child processes.
  * @cs: CPU
diff --git a/linux-user/main.c b/linux-user/main.c
index 1d53f708354..dce6233ee49 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -144,6 +144,7 @@ void fork_start(void)
     mmap_fork_start();
     cpu_list_lock();
     qemu_plugin_user_prefork_lock();
+    gdbserver_fork_start();
 }
 
 void fork_end(int child)
-- 
2.43.2



^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v4 05/12] {linux,bsd}-user: Pass pid to fork_end()
  2024-02-19 14:15 [PATCH v4 00/12] gdbstub: Implement follow-fork-mode child Ilya Leoshkevich
                   ` (3 preceding siblings ...)
  2024-02-19 14:15 ` [PATCH v4 04/12] gdbstub: Introduce gdbserver_fork_start() Ilya Leoshkevich
@ 2024-02-19 14:15 ` Ilya Leoshkevich
  2024-02-19 14:15 ` [PATCH v4 06/12] {linux,bsd}-user: Pass pid to gdbserver_fork() Ilya Leoshkevich
                   ` (7 subsequent siblings)
  12 siblings, 0 replies; 17+ messages in thread
From: Ilya Leoshkevich @ 2024-02-19 14:15 UTC (permalink / raw)
  To: Warner Losh, Alex Bennée, Richard Henderson, Riku Voipio,
	Laurent Vivier
  Cc: Kyle Evans, Philippe Mathieu-Daudé,
	Alexandre Iooss, Mahmoud Mandour, Pierrick Bouvier, qemu-devel,
	Ilya Leoshkevich

The upcoming follow-fork-mode child support requires knowing the child
pid. Pass it down.

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
---
 bsd-user/freebsd/os-proc.h  | 6 +++---
 bsd-user/main.c             | 4 +++-
 bsd-user/qemu.h             | 2 +-
 linux-user/main.c           | 4 +++-
 linux-user/syscall.c        | 6 +++---
 linux-user/user-internals.h | 2 +-
 6 files changed, 14 insertions(+), 10 deletions(-)

diff --git a/bsd-user/freebsd/os-proc.h b/bsd-user/freebsd/os-proc.h
index d6418780344..3003c8cb637 100644
--- a/bsd-user/freebsd/os-proc.h
+++ b/bsd-user/freebsd/os-proc.h
@@ -208,7 +208,7 @@ static inline abi_long do_freebsd_fork(void *cpu_env)
      */
     set_second_rval(cpu_env, child_flag);
 
-    fork_end(child_flag);
+    fork_end(ret);
 
     return ret;
 }
@@ -252,7 +252,7 @@ static inline abi_long do_freebsd_rfork(void *cpu_env, abi_long flags)
      * value: 0 for parent process, 1 for child process.
      */
     set_second_rval(cpu_env, child_flag);
-    fork_end(child_flag);
+    fork_end(ret);
 
     return ret;
 
@@ -285,7 +285,7 @@ static inline abi_long do_freebsd_pdfork(void *cpu_env, abi_ulong target_fdp,
      * value: 0 for parent process, 1 for child process.
      */
     set_second_rval(cpu_env, child_flag);
-    fork_end(child_flag);
+    fork_end(ret);
 
     return ret;
 }
diff --git a/bsd-user/main.c b/bsd-user/main.c
index 35a27a07c8d..94e1edf8247 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -109,8 +109,10 @@ void fork_start(void)
     gdbserver_fork_start();
 }
 
-void fork_end(int child)
+void fork_end(pid_t pid)
 {
+    bool child = pid == 0;
+
     if (child) {
         CPUState *cpu, *next_cpu;
         /*
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index a2417b25156..c1ee90a296d 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -185,7 +185,7 @@ void cpu_loop(CPUArchState *env);
 char *target_strerror(int err);
 int get_osversion(void);
 void fork_start(void);
-void fork_end(int child);
+void fork_end(pid_t pid);
 
 #include "qemu/log.h"
 
diff --git a/linux-user/main.c b/linux-user/main.c
index dce6233ee49..a490d798898 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -147,8 +147,10 @@ void fork_start(void)
     gdbserver_fork_start();
 }
 
-void fork_end(int child)
+void fork_end(pid_t pid)
 {
+    bool child = pid == 0;
+
     qemu_plugin_user_postfork(child);
     mmap_fork_end(child);
     if (child) {
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 3e105488ee2..a0b61bcb2a2 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -6669,7 +6669,7 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
         if (ret == 0) {
             /* Child Process.  */
             cpu_clone_regs_child(env, newsp, flags);
-            fork_end(1);
+            fork_end(ret);
             /* There is a race condition here.  The parent process could
                theoretically read the TID in the child process before the child
                tid is set.  This would require using either ptrace
@@ -6700,8 +6700,8 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
                 }
 #endif
                 put_user_u32(pid_fd, parent_tidptr);
-                }
-            fork_end(0);
+            }
+            fork_end(ret);
         }
         g_assert(!cpu_in_exclusive_context(cpu));
     }
diff --git a/linux-user/user-internals.h b/linux-user/user-internals.h
index c63ef45fc78..ce11d9e21c1 100644
--- a/linux-user/user-internals.h
+++ b/linux-user/user-internals.h
@@ -71,7 +71,7 @@ const char *target_strerror(int err);
 int get_osversion(void);
 void init_qemu_uname_release(void);
 void fork_start(void);
-void fork_end(int child);
+void fork_end(pid_t pid);
 
 /**
  * probe_guest_base:
-- 
2.43.2



^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v4 06/12] {linux,bsd}-user: Pass pid to gdbserver_fork()
  2024-02-19 14:15 [PATCH v4 00/12] gdbstub: Implement follow-fork-mode child Ilya Leoshkevich
                   ` (4 preceding siblings ...)
  2024-02-19 14:15 ` [PATCH v4 05/12] {linux,bsd}-user: Pass pid to fork_end() Ilya Leoshkevich
@ 2024-02-19 14:15 ` Ilya Leoshkevich
  2024-02-19 14:15 ` [PATCH v4 07/12] gdbstub: Call gdbserver_fork() both in parent and in child Ilya Leoshkevich
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 17+ messages in thread
From: Ilya Leoshkevich @ 2024-02-19 14:15 UTC (permalink / raw)
  To: Warner Losh, Alex Bennée, Richard Henderson, Riku Voipio,
	Laurent Vivier
  Cc: Kyle Evans, Philippe Mathieu-Daudé,
	Alexandre Iooss, Mahmoud Mandour, Pierrick Bouvier, qemu-devel,
	Ilya Leoshkevich

The upcoming follow-fork-mode child support requires knowing the child
pid. Pass it down.

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
---
 bsd-user/main.c        | 2 +-
 gdbstub/user.c         | 2 +-
 include/gdbstub/user.h | 2 +-
 linux-user/main.c      | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/bsd-user/main.c b/bsd-user/main.c
index 94e1edf8247..9c5b5c7e1dc 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -131,7 +131,7 @@ void fork_end(pid_t pid)
          */
         qemu_init_cpu_list();
         get_task_state(thread_cpu)->ts_tid = qemu_get_thread_id();
-        gdbserver_fork(thread_cpu);
+        gdbserver_fork(thread_cpu, pid);
     } else {
         mmap_fork_end(child);
         cpu_list_unlock();
diff --git a/gdbstub/user.c b/gdbstub/user.c
index 536fb43b03e..c61e1a0d1f6 100644
--- a/gdbstub/user.c
+++ b/gdbstub/user.c
@@ -375,7 +375,7 @@ static void disable_gdbstub(CPUState *thread_cpu)
 }
 
 /* Disable gdb stub for child processes.  */
-void gdbserver_fork(CPUState *cpu)
+void gdbserver_fork(CPUState *cpu, pid_t pid)
 {
     if (!gdbserver_state.init || gdbserver_user_state.fd < 0) {
         return;
diff --git a/include/gdbstub/user.h b/include/gdbstub/user.h
index e33f8d9a9a6..3f9f45946e0 100644
--- a/include/gdbstub/user.h
+++ b/include/gdbstub/user.h
@@ -54,7 +54,7 @@ void gdbserver_fork_start(void);
  * gdbserver_fork() - disable gdb stub for child processes.
  * @cs: CPU
  */
-void gdbserver_fork(CPUState *cs);
+void gdbserver_fork(CPUState *cs, pid_t pid);
 
 /**
  * gdb_syscall_entry() - inform gdb of syscall entry and yield control to it
diff --git a/linux-user/main.c b/linux-user/main.c
index a490d798898..bc78c1a4b03 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -164,7 +164,7 @@ void fork_end(pid_t pid)
         }
         qemu_init_cpu_list();
         get_task_state(thread_cpu)->ts_tid = qemu_get_thread_id();
-        gdbserver_fork(thread_cpu);
+        gdbserver_fork(thread_cpu, pid);
     } else {
         cpu_list_unlock();
     }
-- 
2.43.2



^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v4 07/12] gdbstub: Call gdbserver_fork() both in parent and in child
  2024-02-19 14:15 [PATCH v4 00/12] gdbstub: Implement follow-fork-mode child Ilya Leoshkevich
                   ` (5 preceding siblings ...)
  2024-02-19 14:15 ` [PATCH v4 06/12] {linux,bsd}-user: Pass pid to gdbserver_fork() Ilya Leoshkevich
@ 2024-02-19 14:15 ` Ilya Leoshkevich
  2024-02-19 14:15 ` [PATCH v4 08/12] gdbstub: Introduce gdb_handle_query_supported_user() Ilya Leoshkevich
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 17+ messages in thread
From: Ilya Leoshkevich @ 2024-02-19 14:15 UTC (permalink / raw)
  To: Warner Losh, Alex Bennée, Richard Henderson, Riku Voipio,
	Laurent Vivier
  Cc: Kyle Evans, Philippe Mathieu-Daudé,
	Alexandre Iooss, Mahmoud Mandour, Pierrick Bouvier, qemu-devel,
	Ilya Leoshkevich

The upcoming follow-fork-mode child support requires post-fork message
exchange between the parent and the child. Prepare gdbserver_fork() for
this purpose. Rename it to gdbserver_fork_end() to better reflect its
purpose.

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
---
 bsd-user/main.c        | 3 ++-
 gdbstub/user.c         | 5 ++---
 include/gdbstub/user.h | 5 +++--
 linux-user/main.c      | 2 +-
 4 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/bsd-user/main.c b/bsd-user/main.c
index 9c5b5c7e1dc..9e23578c4e7 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -131,10 +131,11 @@ void fork_end(pid_t pid)
          */
         qemu_init_cpu_list();
         get_task_state(thread_cpu)->ts_tid = qemu_get_thread_id();
-        gdbserver_fork(thread_cpu, pid);
+        gdbserver_fork_end(thread_cpu, pid);
     } else {
         mmap_fork_end(child);
         cpu_list_unlock();
+        gdbserver_fork_end(thread_cpu, pid);
         end_exclusive();
     }
 }
diff --git a/gdbstub/user.c b/gdbstub/user.c
index c61e1a0d1f6..866a25f9c06 100644
--- a/gdbstub/user.c
+++ b/gdbstub/user.c
@@ -374,10 +374,9 @@ static void disable_gdbstub(CPUState *thread_cpu)
     tb_flush(thread_cpu);
 }
 
-/* Disable gdb stub for child processes.  */
-void gdbserver_fork(CPUState *cpu, pid_t pid)
+void gdbserver_fork_end(CPUState *cpu, pid_t pid)
 {
-    if (!gdbserver_state.init || gdbserver_user_state.fd < 0) {
+    if (pid != 0 || !gdbserver_state.init || gdbserver_user_state.fd < 0) {
         return;
     }
     disable_gdbstub(cpu);
diff --git a/include/gdbstub/user.h b/include/gdbstub/user.h
index 3f9f45946e0..4c4e5c4c582 100644
--- a/include/gdbstub/user.h
+++ b/include/gdbstub/user.h
@@ -51,10 +51,11 @@ void gdb_signalled(CPUArchState *as, int sig);
 void gdbserver_fork_start(void);
 
 /**
- * gdbserver_fork() - disable gdb stub for child processes.
+ * gdbserver_fork_end() - inform gdb of the completed fork()
  * @cs: CPU
+ * @pid: 0 if in child process, -1 if fork failed, child process pid otherwise
  */
-void gdbserver_fork(CPUState *cs, pid_t pid);
+void gdbserver_fork_end(CPUState *cs, pid_t pid);
 
 /**
  * gdb_syscall_entry() - inform gdb of syscall entry and yield control to it
diff --git a/linux-user/main.c b/linux-user/main.c
index bc78c1a4b03..b7294b9cee2 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -164,10 +164,10 @@ void fork_end(pid_t pid)
         }
         qemu_init_cpu_list();
         get_task_state(thread_cpu)->ts_tid = qemu_get_thread_id();
-        gdbserver_fork(thread_cpu, pid);
     } else {
         cpu_list_unlock();
     }
+    gdbserver_fork_end(thread_cpu, pid);
     /*
      * qemu_init_cpu_list() reinitialized the child exclusive state, but we
      * also need to keep current_cpu consistent, so call end_exclusive() for
-- 
2.43.2



^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v4 08/12] gdbstub: Introduce gdb_handle_query_supported_user()
  2024-02-19 14:15 [PATCH v4 00/12] gdbstub: Implement follow-fork-mode child Ilya Leoshkevich
                   ` (6 preceding siblings ...)
  2024-02-19 14:15 ` [PATCH v4 07/12] gdbstub: Call gdbserver_fork() both in parent and in child Ilya Leoshkevich
@ 2024-02-19 14:15 ` Ilya Leoshkevich
  2024-02-19 14:15 ` [PATCH v4 09/12] gdbstub: Introduce gdb_handle_set_thread_user() Ilya Leoshkevich
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 17+ messages in thread
From: Ilya Leoshkevich @ 2024-02-19 14:15 UTC (permalink / raw)
  To: Warner Losh, Alex Bennée, Richard Henderson, Riku Voipio,
	Laurent Vivier
  Cc: Kyle Evans, Philippe Mathieu-Daudé,
	Alexandre Iooss, Mahmoud Mandour, Pierrick Bouvier, qemu-devel,
	Ilya Leoshkevich

The upcoming follow-fork-mode child support requires advertising the
fork-events feature, which is user-specific. Introduce a user-specific
hook for this.

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
---
 gdbstub/gdbstub.c   | 12 +++++++++---
 gdbstub/internals.h |  1 +
 gdbstub/user.c      |  4 ++++
 3 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c
index 7e73e916bdc..898a108b7f1 100644
--- a/gdbstub/gdbstub.c
+++ b/gdbstub/gdbstub.c
@@ -1622,9 +1622,15 @@ static void handle_query_supported(GArray *params, void *user_ctx)
     g_string_append(gdbserver_state.str_buf, ";qXfer:exec-file:read+");
 #endif
 
-    if (params->len &&
-        strstr(get_param(params, 0)->data, "multiprocess+")) {
-        gdbserver_state.multiprocess = true;
+    if (params->len) {
+        const char *gdb_supported = get_param(params, 0)->data;
+
+        if (strstr(gdb_supported, "multiprocess+")) {
+            gdbserver_state.multiprocess = true;
+        }
+#if defined(CONFIG_USER_ONLY)
+        gdb_handle_query_supported_user(gdb_supported);
+#endif
     }
 
     g_string_append(gdbserver_state.str_buf, ";vContSupported+;multiprocess+");
diff --git a/gdbstub/internals.h b/gdbstub/internals.h
index 56b7c13b750..e6063835b1f 100644
--- a/gdbstub/internals.h
+++ b/gdbstub/internals.h
@@ -196,6 +196,7 @@ void gdb_handle_v_file_pread(GArray *params, void *user_ctx); /* user */
 void gdb_handle_v_file_readlink(GArray *params, void *user_ctx); /* user */
 void gdb_handle_query_xfer_exec_file(GArray *params, void *user_ctx); /* user */
 void gdb_handle_set_catch_syscalls(GArray *params, void *user_ctx); /* user */
+void gdb_handle_query_supported_user(const char *gdb_supported); /* user */
 
 void gdb_handle_query_attached(GArray *params, void *user_ctx); /* both */
 
diff --git a/gdbstub/user.c b/gdbstub/user.c
index 866a25f9c06..c9e8b83d720 100644
--- a/gdbstub/user.c
+++ b/gdbstub/user.c
@@ -382,6 +382,10 @@ void gdbserver_fork_end(CPUState *cpu, pid_t pid)
     disable_gdbstub(cpu);
 }
 
+void gdb_handle_query_supported_user(const char *gdb_supported)
+{
+}
+
 /*
  * Execution state helpers
  */
-- 
2.43.2



^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v4 09/12] gdbstub: Introduce gdb_handle_set_thread_user()
  2024-02-19 14:15 [PATCH v4 00/12] gdbstub: Implement follow-fork-mode child Ilya Leoshkevich
                   ` (7 preceding siblings ...)
  2024-02-19 14:15 ` [PATCH v4 08/12] gdbstub: Introduce gdb_handle_query_supported_user() Ilya Leoshkevich
@ 2024-02-19 14:15 ` Ilya Leoshkevich
  2024-02-19 14:15 ` [PATCH v4 10/12] gdbstub: Introduce gdb_handle_detach_user() Ilya Leoshkevich
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 17+ messages in thread
From: Ilya Leoshkevich @ 2024-02-19 14:15 UTC (permalink / raw)
  To: Warner Losh, Alex Bennée, Richard Henderson, Riku Voipio,
	Laurent Vivier
  Cc: Kyle Evans, Philippe Mathieu-Daudé,
	Alexandre Iooss, Mahmoud Mandour, Pierrick Bouvier, qemu-devel,
	Ilya Leoshkevich

The upcoming follow-fork-mode child support needs to perform certain
actions when GDB switches between the stopped parent and the stopped
child. Introduce a user-specific hook for this.

Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
---
 gdbstub/gdbstub.c   | 11 +++++++++--
 gdbstub/internals.h |  1 +
 gdbstub/user.c      |  5 +++++
 3 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c
index 898a108b7f1..05fcdd86527 100644
--- a/gdbstub/gdbstub.c
+++ b/gdbstub/gdbstub.c
@@ -1066,6 +1066,7 @@ static void handle_cont_with_sig(GArray *params, void *user_ctx)
 
 static void handle_set_thread(GArray *params, void *user_ctx)
 {
+    uint32_t pid, tid;
     CPUState *cpu;
 
     if (params->len != 2) {
@@ -1083,8 +1084,14 @@ static void handle_set_thread(GArray *params, void *user_ctx)
         return;
     }
 
-    cpu = gdb_get_cpu(get_param(params, 1)->thread_id.pid,
-                      get_param(params, 1)->thread_id.tid);
+    pid = get_param(params, 1)->thread_id.pid;
+    tid = get_param(params, 1)->thread_id.tid;
+#ifdef CONFIG_USER_ONLY
+    if (gdb_handle_set_thread_user(pid, tid)) {
+        return;
+    }
+#endif
+    cpu = gdb_get_cpu(pid, tid);
     if (!cpu) {
         gdb_put_packet("E22");
         return;
diff --git a/gdbstub/internals.h b/gdbstub/internals.h
index e6063835b1f..b4905c7181a 100644
--- a/gdbstub/internals.h
+++ b/gdbstub/internals.h
@@ -197,6 +197,7 @@ void gdb_handle_v_file_readlink(GArray *params, void *user_ctx); /* user */
 void gdb_handle_query_xfer_exec_file(GArray *params, void *user_ctx); /* user */
 void gdb_handle_set_catch_syscalls(GArray *params, void *user_ctx); /* user */
 void gdb_handle_query_supported_user(const char *gdb_supported); /* user */
+bool gdb_handle_set_thread_user(uint32_t pid, uint32_t tid); /* user */
 
 void gdb_handle_query_attached(GArray *params, void *user_ctx); /* both */
 
diff --git a/gdbstub/user.c b/gdbstub/user.c
index c9e8b83d720..b048754c4f8 100644
--- a/gdbstub/user.c
+++ b/gdbstub/user.c
@@ -386,6 +386,11 @@ void gdb_handle_query_supported_user(const char *gdb_supported)
 {
 }
 
+bool gdb_handle_set_thread_user(uint32_t pid, uint32_t tid)
+{
+    return false;
+}
+
 /*
  * Execution state helpers
  */
-- 
2.43.2



^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v4 10/12] gdbstub: Introduce gdb_handle_detach_user()
  2024-02-19 14:15 [PATCH v4 00/12] gdbstub: Implement follow-fork-mode child Ilya Leoshkevich
                   ` (8 preceding siblings ...)
  2024-02-19 14:15 ` [PATCH v4 09/12] gdbstub: Introduce gdb_handle_set_thread_user() Ilya Leoshkevich
@ 2024-02-19 14:15 ` Ilya Leoshkevich
  2024-02-19 14:15 ` [PATCH v4 11/12] gdbstub: Implement follow-fork-mode child Ilya Leoshkevich
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 17+ messages in thread
From: Ilya Leoshkevich @ 2024-02-19 14:15 UTC (permalink / raw)
  To: Warner Losh, Alex Bennée, Richard Henderson, Riku Voipio,
	Laurent Vivier
  Cc: Kyle Evans, Philippe Mathieu-Daudé,
	Alexandre Iooss, Mahmoud Mandour, Pierrick Bouvier, qemu-devel,
	Ilya Leoshkevich

The upcoming follow-fork-mode child support needs to perform certain
actions when GDB detaches from the stopped parent or the stopped child.
Introduce a user-specific hook for this.

Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
---
 gdbstub/gdbstub.c   | 6 ++++++
 gdbstub/internals.h | 1 +
 gdbstub/user.c      | 5 +++++
 3 files changed, 12 insertions(+)

diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c
index 05fcdd86527..219b0422f9a 100644
--- a/gdbstub/gdbstub.c
+++ b/gdbstub/gdbstub.c
@@ -991,6 +991,12 @@ static void handle_detach(GArray *params, void *user_ctx)
         pid = get_param(params, 0)->val_ul;
     }
 
+#ifdef CONFIG_USER_ONLY
+    if (gdb_handle_detach_user(pid)) {
+        return;
+    }
+#endif
+
     process = gdb_get_process(pid);
     gdb_process_breakpoint_remove_all(process);
     process->attached = false;
diff --git a/gdbstub/internals.h b/gdbstub/internals.h
index b4905c7181a..b4724598384 100644
--- a/gdbstub/internals.h
+++ b/gdbstub/internals.h
@@ -198,6 +198,7 @@ void gdb_handle_query_xfer_exec_file(GArray *params, void *user_ctx); /* user */
 void gdb_handle_set_catch_syscalls(GArray *params, void *user_ctx); /* user */
 void gdb_handle_query_supported_user(const char *gdb_supported); /* user */
 bool gdb_handle_set_thread_user(uint32_t pid, uint32_t tid); /* user */
+bool gdb_handle_detach_user(uint32_t pid); /* user */
 
 void gdb_handle_query_attached(GArray *params, void *user_ctx); /* both */
 
diff --git a/gdbstub/user.c b/gdbstub/user.c
index b048754c4f8..1a7b582a40d 100644
--- a/gdbstub/user.c
+++ b/gdbstub/user.c
@@ -391,6 +391,11 @@ bool gdb_handle_set_thread_user(uint32_t pid, uint32_t tid)
     return false;
 }
 
+bool gdb_handle_detach_user(uint32_t pid)
+{
+    return false;
+}
+
 /*
  * Execution state helpers
  */
-- 
2.43.2



^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v4 11/12] gdbstub: Implement follow-fork-mode child
  2024-02-19 14:15 [PATCH v4 00/12] gdbstub: Implement follow-fork-mode child Ilya Leoshkevich
                   ` (9 preceding siblings ...)
  2024-02-19 14:15 ` [PATCH v4 10/12] gdbstub: Introduce gdb_handle_detach_user() Ilya Leoshkevich
@ 2024-02-19 14:15 ` Ilya Leoshkevich
  2024-02-19 14:16 ` [PATCH v4 12/12] tests/tcg: Add two follow-fork-mode tests Ilya Leoshkevich
  2024-03-04 18:03 ` [PATCH v4 00/12] gdbstub: Implement follow-fork-mode child Alex Bennée
  12 siblings, 0 replies; 17+ messages in thread
From: Ilya Leoshkevich @ 2024-02-19 14:15 UTC (permalink / raw)
  To: Warner Losh, Alex Bennée, Richard Henderson, Riku Voipio,
	Laurent Vivier
  Cc: Kyle Evans, Philippe Mathieu-Daudé,
	Alexandre Iooss, Mahmoud Mandour, Pierrick Bouvier, qemu-devel,
	Ilya Leoshkevich

Currently it's not possible to use gdbstub for debugging linux-user
code that runs in a forked child, which is normally done using the `set
follow-fork-mode child` GDB command. Purely on the protocol level, the
missing piece is the fork-events feature.

However, a deeper problem is supporting $Hg switching between different
processes - right now it can do only threads. Implementing this for the
general case would be quite complicated, but, fortunately, for the
follow-fork-mode case there are a few factors that greatly simplify
things: fork() happens in the exclusive section, there are only two
processes involved, and before one of them is resumed, the second one
is detached.

This makes it possible to implement a simplified scheme: the parent and
the child share the gdbserver socket, it's used only by one of them at
any given time, which is coordinated through a separate socketpair. The
processes can read from the gdbserver socket only one byte at a time,
which is not great for performance, but, fortunately, the
follow-fork-mode handling involves only a few messages.

Advertise the fork-events support, and remember whether GDB has it
as well. Implement the state machine that is initialized on fork(),
decides the current owner of the gdbserver socket, and is terminated
when one of the two processes is detached. The logic for the parent and
the child is the same, only the initial state is different.

Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
---
 gdbstub/user.c | 212 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 210 insertions(+), 2 deletions(-)

diff --git a/gdbstub/user.c b/gdbstub/user.c
index 1a7b582a40d..7f9f19a1249 100644
--- a/gdbstub/user.c
+++ b/gdbstub/user.c
@@ -25,6 +25,61 @@
 #define GDB_NR_SYSCALLS 1024
 typedef unsigned long GDBSyscallsMask[BITS_TO_LONGS(GDB_NR_SYSCALLS)];
 
+/*
+ * Forked child talks to its parent in order to let GDB enforce the
+ * follow-fork-mode. This happens inside a start_exclusive() section, so that
+ * the other threads, which may be forking too, do not interfere. The
+ * implementation relies on GDB not sending $vCont until it has detached
+ * either from the parent (follow-fork-mode child) or from the child
+ * (follow-fork-mode parent).
+ *
+ * The parent and the child share the GDB socket; at any given time only one
+ * of them is allowed to use it, as is reflected in the respective fork_state.
+ * This is negotiated via the fork_sockets pair as a reaction to $Hg.
+ *
+ * Below is a short summary of the possible state transitions:
+ *
+ *     ENABLED                     : Terminal state.
+ *     DISABLED                    : Terminal state.
+ *     ACTIVE                      : Parent initial state.
+ *     INACTIVE                    : Child initial state.
+ *     ACTIVE       -> DEACTIVATING: On $Hg.
+ *     ACTIVE       -> ENABLING    : On $D.
+ *     ACTIVE       -> DISABLING   : On $D.
+ *     ACTIVE       -> DISABLED    : On communication error.
+ *     DEACTIVATING -> INACTIVE    : On gdb_read_byte() return.
+ *     DEACTIVATING -> DISABLED    : On communication error.
+ *     INACTIVE     -> ACTIVE      : On $Hg in the peer.
+ *     INACTIVE     -> ENABLE      : On $D in the peer.
+ *     INACTIVE     -> DISABLE     : On $D in the peer.
+ *     INACTIVE     -> DISABLED    : On communication error.
+ *     ENABLING     -> ENABLED     : On gdb_read_byte() return.
+ *     ENABLING     -> DISABLED    : On communication error.
+ *     DISABLING    -> DISABLED    : On gdb_read_byte() return.
+ */
+enum GDBForkState {
+    /* Fully owning the GDB socket. */
+    GDB_FORK_ENABLED,
+    /* Working with the GDB socket; the peer is inactive. */
+    GDB_FORK_ACTIVE,
+    /* Handing off the GDB socket to the peer. */
+    GDB_FORK_DEACTIVATING,
+    /* The peer is working with the GDB socket. */
+    GDB_FORK_INACTIVE,
+    /* Asking the peer to close its GDB socket fd. */
+    GDB_FORK_ENABLING,
+    /* Asking the peer to take over, closing our GDB socket fd. */
+    GDB_FORK_DISABLING,
+    /* The peer has taken over, our GDB socket fd is closed. */
+    GDB_FORK_DISABLED,
+};
+
+enum GDBForkMessage {
+    GDB_FORK_ACTIVATE = 'a',
+    GDB_FORK_ENABLE = 'e',
+    GDB_FORK_DISABLE = 'd',
+};
+
 /* User-mode specific state */
 typedef struct {
     int fd;
@@ -36,6 +91,10 @@ typedef struct {
      */
     bool catch_all_syscalls;
     GDBSyscallsMask catch_syscalls_mask;
+    bool fork_events;
+    enum GDBForkState fork_state;
+    int fork_sockets[2];
+    pid_t fork_peer_pid, fork_peer_tid;
 } GDBUserState;
 
 static GDBUserState gdbserver_user_state;
@@ -358,6 +417,18 @@ int gdbserver_start(const char *port_or_path)
 
 void gdbserver_fork_start(void)
 {
+    if (!gdbserver_state.init || gdbserver_user_state.fd < 0) {
+        return;
+    }
+    if (!gdbserver_user_state.fork_events ||
+            qemu_socketpair(AF_UNIX, SOCK_STREAM, 0,
+                            gdbserver_user_state.fork_sockets) < 0) {
+        gdbserver_user_state.fork_state = GDB_FORK_DISABLED;
+        return;
+    }
+    gdbserver_user_state.fork_state = GDB_FORK_INACTIVE;
+    gdbserver_user_state.fork_peer_pid = getpid();
+    gdbserver_user_state.fork_peer_tid = qemu_get_thread_id();
 }
 
 static void disable_gdbstub(CPUState *thread_cpu)
@@ -376,23 +447,160 @@ static void disable_gdbstub(CPUState *thread_cpu)
 
 void gdbserver_fork_end(CPUState *cpu, pid_t pid)
 {
-    if (pid != 0 || !gdbserver_state.init || gdbserver_user_state.fd < 0) {
+    char b;
+    int fd;
+
+    if (!gdbserver_state.init || gdbserver_user_state.fd < 0) {
         return;
     }
-    disable_gdbstub(cpu);
+
+    if (pid == -1) {
+        if (gdbserver_user_state.fork_state != GDB_FORK_DISABLED) {
+            g_assert(gdbserver_user_state.fork_state == GDB_FORK_INACTIVE);
+            close(gdbserver_user_state.fork_sockets[0]);
+            close(gdbserver_user_state.fork_sockets[1]);
+        }
+        return;
+    }
+
+    if (gdbserver_user_state.fork_state == GDB_FORK_DISABLED) {
+        if (pid == 0) {
+            disable_gdbstub(cpu);
+        }
+        return;
+    }
+
+    if (pid == 0) {
+        close(gdbserver_user_state.fork_sockets[0]);
+        fd = gdbserver_user_state.fork_sockets[1];
+        g_assert(gdbserver_state.process_num == 1);
+        g_assert(gdbserver_state.processes[0].pid ==
+                     gdbserver_user_state.fork_peer_pid);
+        g_assert(gdbserver_state.processes[0].attached);
+        gdbserver_state.processes[0].pid = getpid();
+    } else {
+        close(gdbserver_user_state.fork_sockets[1]);
+        fd = gdbserver_user_state.fork_sockets[0];
+        gdbserver_user_state.fork_state = GDB_FORK_ACTIVE;
+        gdbserver_user_state.fork_peer_pid = pid;
+        gdbserver_user_state.fork_peer_tid = pid;
+
+        if (!gdbserver_state.allow_stop_reply) {
+            goto fail;
+        }
+        g_string_printf(gdbserver_state.str_buf,
+                        "T%02xfork:p%02x.%02x;thread:p%02x.%02x;",
+                        gdb_target_signal_to_gdb(gdb_target_sigtrap()),
+                        pid, pid, (int)getpid(), qemu_get_thread_id());
+        gdb_put_strbuf();
+    }
+
+    gdbserver_state.state = RS_IDLE;
+    gdbserver_state.allow_stop_reply = false;
+    gdbserver_user_state.running_state = 0;
+    for (;;) {
+        switch (gdbserver_user_state.fork_state) {
+        case GDB_FORK_ENABLED:
+            if (gdbserver_user_state.running_state) {
+                return;
+            }
+            QEMU_FALLTHROUGH;
+        case GDB_FORK_ACTIVE:
+            if (read(gdbserver_user_state.fd, &b, 1) != 1) {
+                goto fail;
+            }
+            gdb_read_byte(b);
+            break;
+        case GDB_FORK_DEACTIVATING:
+            b = GDB_FORK_ACTIVATE;
+            if (write(fd, &b, 1) != 1) {
+                goto fail;
+            }
+            gdbserver_user_state.fork_state = GDB_FORK_INACTIVE;
+            break;
+        case GDB_FORK_INACTIVE:
+            if (read(fd, &b, 1) != 1) {
+                goto fail;
+            }
+            switch (b) {
+            case GDB_FORK_ACTIVATE:
+                gdbserver_user_state.fork_state = GDB_FORK_ACTIVE;
+                break;
+            case GDB_FORK_ENABLE:
+                close(fd);
+                gdbserver_user_state.fork_state = GDB_FORK_ENABLED;
+                break;
+            case GDB_FORK_DISABLE:
+                gdbserver_user_state.fork_state = GDB_FORK_DISABLED;
+                break;
+            default:
+                g_assert_not_reached();
+            }
+            break;
+        case GDB_FORK_ENABLING:
+            b = GDB_FORK_DISABLE;
+            if (write(fd, &b, 1) != 1) {
+                goto fail;
+            }
+            close(fd);
+            gdbserver_user_state.fork_state = GDB_FORK_ENABLED;
+            break;
+        case GDB_FORK_DISABLING:
+            b = GDB_FORK_ENABLE;
+            if (write(fd, &b, 1) != 1) {
+                goto fail;
+            }
+            gdbserver_user_state.fork_state = GDB_FORK_DISABLED;
+            break;
+        case GDB_FORK_DISABLED:
+            close(fd);
+            disable_gdbstub(cpu);
+            return;
+        default:
+            g_assert_not_reached();
+        }
+    }
+
+fail:
+    close(fd);
+    if (pid == 0) {
+        disable_gdbstub(cpu);
+    }
 }
 
 void gdb_handle_query_supported_user(const char *gdb_supported)
 {
+    if (strstr(gdb_supported, "fork-events+")) {
+        gdbserver_user_state.fork_events = true;
+    }
+    g_string_append(gdbserver_state.str_buf, ";fork-events+");
 }
 
 bool gdb_handle_set_thread_user(uint32_t pid, uint32_t tid)
 {
+    if (gdbserver_user_state.fork_state == GDB_FORK_ACTIVE &&
+            pid == gdbserver_user_state.fork_peer_pid &&
+            tid == gdbserver_user_state.fork_peer_tid) {
+        gdbserver_user_state.fork_state = GDB_FORK_DEACTIVATING;
+        gdb_put_packet("OK");
+        return true;
+    }
     return false;
 }
 
 bool gdb_handle_detach_user(uint32_t pid)
 {
+    bool enable;
+
+    if (gdbserver_user_state.fork_state == GDB_FORK_ACTIVE) {
+        enable = pid == gdbserver_user_state.fork_peer_pid;
+        if (enable || pid == getpid()) {
+            gdbserver_user_state.fork_state = enable ? GDB_FORK_ENABLING :
+                                                       GDB_FORK_DISABLING;
+            gdb_put_packet("OK");
+            return true;
+        }
+    }
     return false;
 }
 
-- 
2.43.2



^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v4 12/12] tests/tcg: Add two follow-fork-mode tests
  2024-02-19 14:15 [PATCH v4 00/12] gdbstub: Implement follow-fork-mode child Ilya Leoshkevich
                   ` (10 preceding siblings ...)
  2024-02-19 14:15 ` [PATCH v4 11/12] gdbstub: Implement follow-fork-mode child Ilya Leoshkevich
@ 2024-02-19 14:16 ` Ilya Leoshkevich
  2024-03-04 18:03 ` [PATCH v4 00/12] gdbstub: Implement follow-fork-mode child Alex Bennée
  12 siblings, 0 replies; 17+ messages in thread
From: Ilya Leoshkevich @ 2024-02-19 14:16 UTC (permalink / raw)
  To: Warner Losh, Alex Bennée, Richard Henderson, Riku Voipio,
	Laurent Vivier
  Cc: Kyle Evans, Philippe Mathieu-Daudé,
	Alexandre Iooss, Mahmoud Mandour, Pierrick Bouvier, qemu-devel,
	Ilya Leoshkevich

Add follow-fork-mode child and and follow-fork-mode parent tests.
Check for the obvious pitfalls, such as lingering breakpoints,
catchpoints, and single-step mode.

Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
---
 tests/tcg/multiarch/Makefile.target           | 17 +++++-
 tests/tcg/multiarch/follow-fork-mode.c        | 56 +++++++++++++++++++
 .../gdbstub/follow-fork-mode-child.py         | 40 +++++++++++++
 .../gdbstub/follow-fork-mode-parent.py        | 16 ++++++
 4 files changed, 128 insertions(+), 1 deletion(-)
 create mode 100644 tests/tcg/multiarch/follow-fork-mode.c
 create mode 100644 tests/tcg/multiarch/gdbstub/follow-fork-mode-child.py
 create mode 100644 tests/tcg/multiarch/gdbstub/follow-fork-mode-parent.py

diff --git a/tests/tcg/multiarch/Makefile.target b/tests/tcg/multiarch/Makefile.target
index e10951a8016..b8b70c81860 100644
--- a/tests/tcg/multiarch/Makefile.target
+++ b/tests/tcg/multiarch/Makefile.target
@@ -115,6 +115,20 @@ run-gdbstub-catch-syscalls: catch-syscalls
 		--bin $< --test $(MULTIARCH_SRC)/gdbstub/catch-syscalls.py, \
 	hitting a syscall catchpoint)
 
+run-gdbstub-follow-fork-mode-child: follow-fork-mode
+	$(call run-test, $@, $(GDB_SCRIPT) \
+		--gdb $(GDB) \
+		--qemu $(QEMU) --qargs "$(QEMU_OPTS)" \
+		--bin $< --test $(MULTIARCH_SRC)/gdbstub/follow-fork-mode-child.py, \
+	following children on fork)
+
+run-gdbstub-follow-fork-mode-parent: follow-fork-mode
+	$(call run-test, $@, $(GDB_SCRIPT) \
+		--gdb $(GDB) \
+		--qemu $(QEMU) --qargs "$(QEMU_OPTS)" \
+		--bin $< --test $(MULTIARCH_SRC)/gdbstub/follow-fork-mode-parent.py, \
+	following parents on fork)
+
 else
 run-gdbstub-%:
 	$(call skip-test, "gdbstub test $*", "need working gdb with $(patsubst -%,,$(TARGET_NAME)) support")
@@ -122,7 +136,8 @@ endif
 EXTRA_RUNS += run-gdbstub-sha1 run-gdbstub-qxfer-auxv-read \
 	      run-gdbstub-proc-mappings run-gdbstub-thread-breakpoint \
 	      run-gdbstub-registers run-gdbstub-prot-none \
-	      run-gdbstub-catch-syscalls
+	      run-gdbstub-catch-syscalls run-gdbstub-follow-fork-mode-child \
+	      run-gdbstub-follow-fork-mode-parent
 
 # ARM Compatible Semi Hosting Tests
 #
diff --git a/tests/tcg/multiarch/follow-fork-mode.c b/tests/tcg/multiarch/follow-fork-mode.c
new file mode 100644
index 00000000000..cb6b032b388
--- /dev/null
+++ b/tests/tcg/multiarch/follow-fork-mode.c
@@ -0,0 +1,56 @@
+/*
+ * Test GDB's follow-fork-mode.
+ *
+ * fork() a chain of processes.
+ * Parents sends one byte to their children, and children return their
+ * position in the chain, in order to prove that they survived GDB's fork()
+ * handling.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include <assert.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+void break_after_fork(void)
+{
+}
+
+int main(void)
+{
+    int depth = 42, err, i, fd[2], status;
+    pid_t child, pid;
+    ssize_t n;
+    char b;
+
+    for (i = 0; i < depth; i++) {
+        err = pipe(fd);
+        assert(err == 0);
+        child = fork();
+        break_after_fork();
+        assert(child != -1);
+        if (child == 0) {
+            close(fd[1]);
+
+            n = read(fd[0], &b, 1);
+            close(fd[0]);
+            assert(n == 1);
+            assert(b == (char)i);
+        } else {
+            close(fd[0]);
+
+            b = (char)i;
+            n = write(fd[1], &b, 1);
+            close(fd[1]);
+            assert(n == 1);
+
+            pid = waitpid(child, &status, 0);
+            assert(pid == child);
+            assert(WIFEXITED(status));
+            return WEXITSTATUS(status) - 1;
+        }
+    }
+
+    return depth;
+}
diff --git a/tests/tcg/multiarch/gdbstub/follow-fork-mode-child.py b/tests/tcg/multiarch/gdbstub/follow-fork-mode-child.py
new file mode 100644
index 00000000000..72a6e440c08
--- /dev/null
+++ b/tests/tcg/multiarch/gdbstub/follow-fork-mode-child.py
@@ -0,0 +1,40 @@
+"""Test GDB's follow-fork-mode child.
+
+SPDX-License-Identifier: GPL-2.0-or-later
+"""
+from test_gdbstub import main, report
+
+
+def run_test():
+    """Run through the tests one by one"""
+    gdb.execute("set follow-fork-mode child")
+    # Check that the parent breakpoints are unset.
+    gdb.execute("break break_after_fork")
+    # Check that the parent syscall catchpoints are unset.
+    # Skip this check on the architectures that don't have them.
+    have_fork_syscall = False
+    for fork_syscall in ("fork", "clone", "clone2", "clone3"):
+        try:
+            gdb.execute("catch syscall {}".format(fork_syscall))
+        except gdb.error:
+            pass
+        else:
+            have_fork_syscall = True
+    gdb.execute("continue")
+    for i in range(42):
+        if have_fork_syscall:
+            # syscall entry.
+            if i % 2 == 0:
+                # Check that the parent single-stepping is turned off.
+                gdb.execute("si")
+            else:
+                gdb.execute("continue")
+            # syscall exit.
+            gdb.execute("continue")
+        # break_after_fork()
+        gdb.execute("continue")
+    exitcode = int(gdb.parse_and_eval("$_exitcode"))
+    report(exitcode == 42, "{} == 42".format(exitcode))
+
+
+main(run_test)
diff --git a/tests/tcg/multiarch/gdbstub/follow-fork-mode-parent.py b/tests/tcg/multiarch/gdbstub/follow-fork-mode-parent.py
new file mode 100644
index 00000000000..5c2fe722088
--- /dev/null
+++ b/tests/tcg/multiarch/gdbstub/follow-fork-mode-parent.py
@@ -0,0 +1,16 @@
+"""Test GDB's follow-fork-mode parent.
+
+SPDX-License-Identifier: GPL-2.0-or-later
+"""
+from test_gdbstub import main, report
+
+
+def run_test():
+    """Run through the tests one by one"""
+    gdb.execute("set follow-fork-mode parent")
+    gdb.execute("continue")
+    exitcode = int(gdb.parse_and_eval("$_exitcode"))
+    report(exitcode == 0, "{} == 0".format(exitcode))
+
+
+main(run_test)
-- 
2.43.2



^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [PATCH v4 02/12] {linux,bsd}-user: Introduce get_task_state()
  2024-02-19 14:15 ` [PATCH v4 02/12] {linux,bsd}-user: Introduce get_task_state() Ilya Leoshkevich
@ 2024-02-19 14:32   ` Warner Losh
  2024-02-19 20:46   ` Richard Henderson
  1 sibling, 0 replies; 17+ messages in thread
From: Warner Losh @ 2024-02-19 14:32 UTC (permalink / raw)
  To: Ilya Leoshkevich
  Cc: Alex Bennée, Richard Henderson, Riku Voipio, Laurent Vivier,
	Kyle Evans, Philippe Mathieu-Daudé,
	Alexandre Iooss, Mahmoud Mandour, Pierrick Bouvier, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 34201 bytes --]

On Mon, Feb 19, 2024 at 7:21 AM Ilya Leoshkevich <iii@linux.ibm.com> wrote:

> A CPU's TaskState is stored in the CPUState's void *opaque field,
> accessing which is somewhat awkward due to having to use a cast.
> Introduce a wrapper and use it everywhere.
>
> Suggested-by: Alex Bennée <alex.bennee@linaro.org>
> Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
>

Reviewed-by: Warner Losh <imp@bsdimp.com>

The bsd-user stuff is definitely good. The linux-user seems good, but I
didn't look
at it as closely.

Warner

>  bsd-user/bsd-file.h           |  2 +-
>  bsd-user/qemu.h               |  5 +++++
>  bsd-user/signal.c             | 20 ++++++++++----------
>  gdbstub/user-target.c         |  4 ++--
>  include/user/safe-syscall.h   |  2 +-
>  linux-user/aarch64/cpu_loop.c |  2 +-
>  linux-user/arm/cpu_loop.c     |  4 ++--
>  linux-user/arm/signal.c       |  2 +-
>  linux-user/cris/cpu_loop.c    |  2 +-
>  linux-user/elfload.c          |  6 +++---
>  linux-user/hppa/signal.c      |  2 +-
>  linux-user/linuxload.c        |  2 +-
>  linux-user/m68k/cpu_loop.c    |  2 +-
>  linux-user/m68k/target_cpu.h  |  2 +-
>  linux-user/mips/cpu_loop.c    |  2 +-
>  linux-user/ppc/signal.c       |  4 ++--
>  linux-user/qemu.h             |  5 +++++
>  linux-user/riscv/cpu_loop.c   |  2 +-
>  linux-user/signal-common.h    |  2 +-
>  linux-user/signal.c           | 30 +++++++++++++++---------------
>  linux-user/syscall.c          | 26 +++++++++++++-------------
>  linux-user/vm86.c             | 18 +++++++++---------
>  linux-user/xtensa/signal.c    |  2 +-
>  plugins/api.c                 |  8 ++++----
>  semihosting/arm-compat-semi.c |  8 ++++----
>  25 files changed, 87 insertions(+), 77 deletions(-)
>
> diff --git a/bsd-user/bsd-file.h b/bsd-user/bsd-file.h
> index 3c00dc00567..6fa2c30b4de 100644
> --- a/bsd-user/bsd-file.h
> +++ b/bsd-user/bsd-file.h
> @@ -641,7 +641,7 @@ static abi_long do_bsd_readlink(CPUArchState *env,
> abi_long arg1,
>      }
>      if (strcmp(p1, "/proc/curproc/file") == 0) {
>          CPUState *cpu = env_cpu(env);
> -        TaskState *ts = (TaskState *)cpu->opaque;
> +        TaskState *ts = get_task_state(cpu);
>          strncpy(p2, ts->bprm->fullpath, arg3);
>          ret = MIN((abi_long)strlen(ts->bprm->fullpath), arg3);
>      } else {
> diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
> index dc842fffa7d..a2417b25156 100644
> --- a/bsd-user/qemu.h
> +++ b/bsd-user/qemu.h
> @@ -110,6 +110,11 @@ typedef struct TaskState {
>      struct target_sigaltstack sigaltstack_used;
>  } __attribute__((aligned(16))) TaskState;
>
> +static inline TaskState *get_task_state(CPUState *cs)
> +{
> +    return cs->opaque;
> +}
> +
>  void stop_all_tasks(void);
>  extern const char *interp_prefix;
>  extern const char *qemu_uname_release;
> diff --git a/bsd-user/signal.c b/bsd-user/signal.c
> index f4352e4530f..e9f80a06d32 100644
> --- a/bsd-user/signal.c
> +++ b/bsd-user/signal.c
> @@ -319,7 +319,7 @@ void host_to_target_siginfo(target_siginfo_t *tinfo,
> const siginfo_t *info)
>
>  int block_signals(void)
>  {
> -    TaskState *ts = (TaskState *)thread_cpu->opaque;
> +    TaskState *ts = get_task_state(thread_cpu);
>      sigset_t set;
>
>      /*
> @@ -359,7 +359,7 @@ void dump_core_and_abort(int target_sig)
>  {
>      CPUState *cpu = thread_cpu;
>      CPUArchState *env = cpu_env(cpu);
> -    TaskState *ts = cpu->opaque;
> +    TaskState *ts = get_task_state(cpu);
>      int core_dumped = 0;
>      int host_sig;
>      struct sigaction act;
> @@ -421,7 +421,7 @@ void queue_signal(CPUArchState *env, int sig, int
> si_type,
>                    target_siginfo_t *info)
>  {
>      CPUState *cpu = env_cpu(env);
> -    TaskState *ts = cpu->opaque;
> +    TaskState *ts = get_task_state(cpu);
>
>      trace_user_queue_signal(env, sig);
>
> @@ -476,7 +476,7 @@ void force_sig_fault(int sig, int code, abi_ulong addr)
>  static void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
>  {
>      CPUState *cpu = thread_cpu;
> -    TaskState *ts = cpu->opaque;
> +    TaskState *ts = get_task_state(cpu);
>      target_siginfo_t tinfo;
>      ucontext_t *uc = puc;
>      struct emulated_sigtable *k;
> @@ -585,7 +585,7 @@ static void host_signal_handler(int host_sig,
> siginfo_t *info, void *puc)
>  /* compare to kern/kern_sig.c sys_sigaltstack() and kern_sigaltstack() */
>  abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr,
> abi_ulong sp)
>  {
> -    TaskState *ts = (TaskState *)thread_cpu->opaque;
> +    TaskState *ts = get_task_state(thread_cpu);
>      int ret;
>      target_stack_t oss;
>
> @@ -714,7 +714,7 @@ int do_sigaction(int sig, const struct
> target_sigaction *act,
>  static inline abi_ulong get_sigframe(struct target_sigaction *ka,
>          CPUArchState *env, size_t frame_size)
>  {
> -    TaskState *ts = (TaskState *)thread_cpu->opaque;
> +    TaskState *ts = get_task_state(thread_cpu);
>      abi_ulong sp;
>
>      /* Use default user stack */
> @@ -789,7 +789,7 @@ static int reset_signal_mask(target_ucontext_t
> *ucontext)
>      int i;
>      sigset_t blocked;
>      target_sigset_t target_set;
> -    TaskState *ts = (TaskState *)thread_cpu->opaque;
> +    TaskState *ts = get_task_state(thread_cpu);
>
>      for (i = 0; i < TARGET_NSIG_WORDS; i++) {
>          __get_user(target_set.__bits[i], &ucontext->uc_sigmask.__bits[i]);
> @@ -839,7 +839,7 @@ badframe:
>
>  void signal_init(void)
>  {
> -    TaskState *ts = (TaskState *)thread_cpu->opaque;
> +    TaskState *ts = get_task_state(thread_cpu);
>      struct sigaction act;
>      struct sigaction oact;
>      int i;
> @@ -878,7 +878,7 @@ static void handle_pending_signal(CPUArchState *env,
> int sig,
>                                    struct emulated_sigtable *k)
>  {
>      CPUState *cpu = env_cpu(env);
> -    TaskState *ts = cpu->opaque;
> +    TaskState *ts = get_task_state(cpu);
>      struct target_sigaction *sa;
>      int code;
>      sigset_t set;
> @@ -967,7 +967,7 @@ void process_pending_signals(CPUArchState *env)
>      int sig;
>      sigset_t *blocked_set, set;
>      struct emulated_sigtable *k;
> -    TaskState *ts = cpu->opaque;
> +    TaskState *ts = get_task_state(cpu);
>
>      while (qatomic_read(&ts->signal_pending)) {
>          sigfillset(&set);
> diff --git a/gdbstub/user-target.c b/gdbstub/user-target.c
> index b7d4c37cd81..6646684a4c6 100644
> --- a/gdbstub/user-target.c
> +++ b/gdbstub/user-target.c
> @@ -204,7 +204,7 @@ int gdb_target_signal_to_gdb(int sig)
>
>  int gdb_get_cpu_index(CPUState *cpu)
>  {
> -    TaskState *ts = (TaskState *) cpu->opaque;
> +    TaskState *ts = get_task_state(cpu);
>      return ts ? ts->ts_tid : -1;
>  }
>
> @@ -399,7 +399,7 @@ void gdb_handle_query_xfer_exec_file(GArray *params,
> void *user_ctx)
>          return;
>      }
>
> -    TaskState *ts = cpu->opaque;
> +    TaskState *ts = get_task_state(cpu);
>      if (!ts || !ts->bprm || !ts->bprm->filename) {
>          gdb_put_packet("E00");
>          return;
> diff --git a/include/user/safe-syscall.h b/include/user/safe-syscall.h
> index 27b71cdbd8e..aa075f4d5cd 100644
> --- a/include/user/safe-syscall.h
> +++ b/include/user/safe-syscall.h
> @@ -134,7 +134,7 @@ extern char safe_syscall_start[];
>  extern char safe_syscall_end[];
>
>  #define safe_syscall(...)
>  \
> -    safe_syscall_base(&((TaskState *)thread_cpu->opaque)->signal_pending,
> \
> +    safe_syscall_base(&get_task_state(thread_cpu)->signal_pending,
> \
>                        __VA_ARGS__)
>
>  #endif
> diff --git a/linux-user/aarch64/cpu_loop.c b/linux-user/aarch64/cpu_loop.c
> index 8c20dc8a39a..71cdc8be50c 100644
> --- a/linux-user/aarch64/cpu_loop.c
> +++ b/linux-user/aarch64/cpu_loop.c
> @@ -189,7 +189,7 @@ void target_cpu_copy_regs(CPUArchState *env, struct
> target_pt_regs *regs)
>  {
>      ARMCPU *cpu = env_archcpu(env);
>      CPUState *cs = env_cpu(env);
> -    TaskState *ts = cs->opaque;
> +    TaskState *ts = get_task_state(cs);
>      struct image_info *info = ts->info;
>      int i;
>
> diff --git a/linux-user/arm/cpu_loop.c b/linux-user/arm/cpu_loop.c
> index b404117ff30..db1a41e27f4 100644
> --- a/linux-user/arm/cpu_loop.c
> +++ b/linux-user/arm/cpu_loop.c
> @@ -263,7 +263,7 @@ static bool insn_is_linux_bkpt(uint32_t opcode, bool
> is_thumb)
>
>  static bool emulate_arm_fpa11(CPUARMState *env, uint32_t opcode)
>  {
> -    TaskState *ts = env_cpu(env)->opaque;
> +    TaskState *ts = get_task_state(env_cpu(env));
>      int rc = EmulateAll(opcode, &ts->fpa, env);
>      int raise, enabled;
>
> @@ -514,7 +514,7 @@ void cpu_loop(CPUARMState *env)
>  void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
>  {
>      CPUState *cpu = env_cpu(env);
> -    TaskState *ts = cpu->opaque;
> +    TaskState *ts = get_task_state(cpu);
>      struct image_info *info = ts->info;
>      int i;
>
> diff --git a/linux-user/arm/signal.c b/linux-user/arm/signal.c
> index f77f692c63f..59806335f5b 100644
> --- a/linux-user/arm/signal.c
> +++ b/linux-user/arm/signal.c
> @@ -177,7 +177,7 @@ setup_return(CPUARMState *env, struct target_sigaction
> *ka, int usig,
>      abi_ulong handler = 0;
>      abi_ulong handler_fdpic_GOT = 0;
>      abi_ulong retcode;
> -    bool is_fdpic = info_is_fdpic(((TaskState
> *)thread_cpu->opaque)->info);
> +    bool is_fdpic = info_is_fdpic(get_task_state(thread_cpu)->info);
>      bool is_rt = ka->sa_flags & TARGET_SA_SIGINFO;
>      bool thumb;
>
> diff --git a/linux-user/cris/cpu_loop.c b/linux-user/cris/cpu_loop.c
> index 01e6ff16fc9..04c9086b6dc 100644
> --- a/linux-user/cris/cpu_loop.c
> +++ b/linux-user/cris/cpu_loop.c
> @@ -72,7 +72,7 @@ void cpu_loop(CPUCRISState *env)
>  void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
>  {
>      CPUState *cpu = env_cpu(env);
> -    TaskState *ts = cpu->opaque;
> +    TaskState *ts = get_task_state(cpu);
>      struct image_info *info = ts->info;
>
>      env->regs[0] = regs->r0;
> diff --git a/linux-user/elfload.c b/linux-user/elfload.c
> index b8eef893d0c..6de72da585d 100644
> --- a/linux-user/elfload.c
> +++ b/linux-user/elfload.c
> @@ -4499,7 +4499,7 @@ static int write_note(struct memelfnote *men, int fd)
>  static void fill_thread_info(struct elf_note_info *info, const
> CPUArchState *env)
>  {
>      CPUState *cpu = env_cpu((CPUArchState *)env);
> -    TaskState *ts = (TaskState *)cpu->opaque;
> +    TaskState *ts = get_task_state(cpu);
>      struct elf_thread_status *ets;
>
>      ets = g_malloc0(sizeof (*ets));
> @@ -4529,7 +4529,7 @@ static int fill_note_info(struct elf_note_info *info,
>  {
>  #define NUMNOTES 3
>      CPUState *cpu = env_cpu((CPUArchState *)env);
> -    TaskState *ts = (TaskState *)cpu->opaque;
> +    TaskState *ts = get_task_state(cpu);
>      int i;
>
>      info->notes = g_new0(struct memelfnote, NUMNOTES);
> @@ -4653,7 +4653,7 @@ static int write_note_info(struct elf_note_info
> *info, int fd)
>  static int elf_core_dump(int signr, const CPUArchState *env)
>  {
>      const CPUState *cpu = env_cpu((CPUArchState *)env);
> -    const TaskState *ts = (const TaskState *)cpu->opaque;
> +    const TaskState *ts = (const TaskState *)get_task_state((CPUState
> *)cpu);
>      struct vm_area_struct *vma = NULL;
>      g_autofree char *corefile = NULL;
>      struct elf_note_info info;
> diff --git a/linux-user/hppa/signal.c b/linux-user/hppa/signal.c
> index d08a97dae61..c84557e906a 100644
> --- a/linux-user/hppa/signal.c
> +++ b/linux-user/hppa/signal.c
> @@ -112,7 +112,7 @@ void setup_rt_frame(int sig, struct target_sigaction
> *ka,
>      abi_ulong frame_addr, sp, haddr;
>      struct target_rt_sigframe *frame;
>      int i;
> -    TaskState *ts = (TaskState *)thread_cpu->opaque;
> +    TaskState *ts = get_task_state(thread_cpu);
>
>      sp = get_sp_from_cpustate(env);
>      if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp)) {
> diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c
> index 4a794f8cea1..37f132be4af 100644
> --- a/linux-user/linuxload.c
> +++ b/linux-user/linuxload.c
> @@ -89,7 +89,7 @@ static int prepare_binprm(struct linux_binprm *bprm)
>  abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp,
>                                abi_ulong stringp, int push_ptr)
>  {
> -    TaskState *ts = (TaskState *)thread_cpu->opaque;
> +    TaskState *ts = get_task_state(thread_cpu);
>      int n = sizeof(abi_ulong);
>      abi_ulong envp;
>      abi_ulong argv;
> diff --git a/linux-user/m68k/cpu_loop.c b/linux-user/m68k/cpu_loop.c
> index caead1cb741..f79b8e4ab05 100644
> --- a/linux-user/m68k/cpu_loop.c
> +++ b/linux-user/m68k/cpu_loop.c
> @@ -95,7 +95,7 @@ void cpu_loop(CPUM68KState *env)
>  void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
>  {
>      CPUState *cpu = env_cpu(env);
> -    TaskState *ts = cpu->opaque;
> +    TaskState *ts = get_task_state(cpu);
>      struct image_info *info = ts->info;
>
>      env->pc = regs->pc;
> diff --git a/linux-user/m68k/target_cpu.h b/linux-user/m68k/target_cpu.h
> index c3f288dfe83..4b40c09a8d6 100644
> --- a/linux-user/m68k/target_cpu.h
> +++ b/linux-user/m68k/target_cpu.h
> @@ -37,7 +37,7 @@ static inline void cpu_clone_regs_parent(CPUM68KState
> *env, unsigned flags)
>  static inline void cpu_set_tls(CPUM68KState *env, target_ulong newtls)
>  {
>      CPUState *cs = env_cpu(env);
> -    TaskState *ts = cs->opaque;
> +    TaskState *ts = get_task_state(cs);
>
>      ts->tp_value = newtls;
>  }
> diff --git a/linux-user/mips/cpu_loop.c b/linux-user/mips/cpu_loop.c
> index 990b03e727b..462387a0737 100644
> --- a/linux-user/mips/cpu_loop.c
> +++ b/linux-user/mips/cpu_loop.c
> @@ -214,7 +214,7 @@ done_syscall:
>  void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
>  {
>      CPUState *cpu = env_cpu(env);
> -    TaskState *ts = cpu->opaque;
> +    TaskState *ts = get_task_state(cpu);
>      struct image_info *info = ts->info;
>      int i;
>
> diff --git a/linux-user/ppc/signal.c b/linux-user/ppc/signal.c
> index 7e7302823b0..c232424c1e8 100644
> --- a/linux-user/ppc/signal.c
> +++ b/linux-user/ppc/signal.c
> @@ -486,7 +486,7 @@ void setup_rt_frame(int sig, struct target_sigaction
> *ka,
>      int i, err = 0;
>  #if defined(TARGET_PPC64)
>      struct target_sigcontext *sc = 0;
> -    struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
> +    struct image_info *image = get_task_state(thread_cpu)->info;
>  #endif
>
>      rt_sf_addr = get_sigframe(ka, env, sizeof(*rt_sf));
> @@ -673,7 +673,7 @@ abi_long do_swapcontext(CPUArchState *env, abi_ulong
> uold_ctx,
>      }
>
>      if (uold_ctx) {
> -        TaskState *ts = (TaskState *)thread_cpu->opaque;
> +        TaskState *ts = get_task_state(thread_cpu);
>
>          if (!lock_user_struct(VERIFY_WRITE, uctx, uold_ctx, 1)) {
>              return -TARGET_EFAULT;
> diff --git a/linux-user/qemu.h b/linux-user/qemu.h
> index 4de9ec783f6..32cd43d9eff 100644
> --- a/linux-user/qemu.h
> +++ b/linux-user/qemu.h
> @@ -162,6 +162,11 @@ typedef struct TaskState {
>      uint64_t start_boottime;
>  } TaskState;
>
> +static inline TaskState *get_task_state(CPUState *cs)
> +{
> +    return cs->opaque;
> +}
> +
>  abi_long do_brk(abi_ulong new_brk);
>  int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char
> *pathname,
>                      int flags, mode_t mode, bool safe);
> diff --git a/linux-user/riscv/cpu_loop.c b/linux-user/riscv/cpu_loop.c
> index bffca7db127..52c49c2e426 100644
> --- a/linux-user/riscv/cpu_loop.c
> +++ b/linux-user/riscv/cpu_loop.c
> @@ -97,7 +97,7 @@ void cpu_loop(CPURISCVState *env)
>  void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
>  {
>      CPUState *cpu = env_cpu(env);
> -    TaskState *ts = cpu->opaque;
> +    TaskState *ts = get_task_state(cpu);
>      struct image_info *info = ts->info;
>
>      env->pc = regs->sepc;
> diff --git a/linux-user/signal-common.h b/linux-user/signal-common.h
> index 3e2dc604c2f..a7df12fc445 100644
> --- a/linux-user/signal-common.h
> +++ b/linux-user/signal-common.h
> @@ -113,7 +113,7 @@ int process_sigsuspend_mask(sigset_t **pset,
> target_ulong sigset,
>  static inline void finish_sigsuspend_mask(int ret)
>  {
>      if (ret != -QEMU_ERESTARTSYS) {
> -        TaskState *ts = (TaskState *)thread_cpu->opaque;
> +        TaskState *ts = get_task_state(thread_cpu);
>          ts->in_sigsuspend = 1;
>      }
>  }
> diff --git a/linux-user/signal.c b/linux-user/signal.c
> index d3e62ab030f..cc7dd78e41f 100644
> --- a/linux-user/signal.c
> +++ b/linux-user/signal.c
> @@ -172,7 +172,7 @@ void target_to_host_old_sigset(sigset_t *sigset,
>
>  int block_signals(void)
>  {
> -    TaskState *ts = (TaskState *)thread_cpu->opaque;
> +    TaskState *ts = get_task_state(thread_cpu);
>      sigset_t set;
>
>      /* It's OK to block everything including SIGSEGV, because we won't
> @@ -194,7 +194,7 @@ int block_signals(void)
>   */
>  int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
>  {
> -    TaskState *ts = (TaskState *)thread_cpu->opaque;
> +    TaskState *ts = get_task_state(thread_cpu);
>
>      if (oldset) {
>          *oldset = ts->signal_mask;
> @@ -237,7 +237,7 @@ int do_sigprocmask(int how, const sigset_t *set,
> sigset_t *oldset)
>   */
>  void set_sigmask(const sigset_t *set)
>  {
> -    TaskState *ts = (TaskState *)thread_cpu->opaque;
> +    TaskState *ts = get_task_state(thread_cpu);
>
>      ts->signal_mask = *set;
>  }
> @@ -246,7 +246,7 @@ void set_sigmask(const sigset_t *set)
>
>  int on_sig_stack(unsigned long sp)
>  {
> -    TaskState *ts = (TaskState *)thread_cpu->opaque;
> +    TaskState *ts = get_task_state(thread_cpu);
>
>      return (sp - ts->sigaltstack_used.ss_sp
>              < ts->sigaltstack_used.ss_size);
> @@ -254,7 +254,7 @@ int on_sig_stack(unsigned long sp)
>
>  int sas_ss_flags(unsigned long sp)
>  {
> -    TaskState *ts = (TaskState *)thread_cpu->opaque;
> +    TaskState *ts = get_task_state(thread_cpu);
>
>      return (ts->sigaltstack_used.ss_size == 0 ? SS_DISABLE
>              : on_sig_stack(sp) ? SS_ONSTACK : 0);
> @@ -265,7 +265,7 @@ abi_ulong target_sigsp(abi_ulong sp, struct
> target_sigaction *ka)
>      /*
>       * This is the X/Open sanctioned signal stack switching.
>       */
> -    TaskState *ts = (TaskState *)thread_cpu->opaque;
> +    TaskState *ts = get_task_state(thread_cpu);
>
>      if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp)) {
>          return ts->sigaltstack_used.ss_sp + ts->sigaltstack_used.ss_size;
> @@ -275,7 +275,7 @@ abi_ulong target_sigsp(abi_ulong sp, struct
> target_sigaction *ka)
>
>  void target_save_altstack(target_stack_t *uss, CPUArchState *env)
>  {
> -    TaskState *ts = (TaskState *)thread_cpu->opaque;
> +    TaskState *ts = get_task_state(thread_cpu);
>
>      __put_user(ts->sigaltstack_used.ss_sp, &uss->ss_sp);
>      __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &uss->ss_flags);
> @@ -284,7 +284,7 @@ void target_save_altstack(target_stack_t *uss,
> CPUArchState *env)
>
>  abi_long target_restore_altstack(target_stack_t *uss, CPUArchState *env)
>  {
> -    TaskState *ts = (TaskState *)thread_cpu->opaque;
> +    TaskState *ts = get_task_state(thread_cpu);
>      size_t minstacksize = TARGET_MINSIGSTKSZ;
>      target_stack_t ss;
>
> @@ -571,7 +571,7 @@ static void signal_table_init(void)
>
>  void signal_init(void)
>  {
> -    TaskState *ts = (TaskState *)thread_cpu->opaque;
> +    TaskState *ts = get_task_state(thread_cpu);
>      struct sigaction act, oact;
>
>      /* initialize signal conversion tables */
> @@ -730,7 +730,7 @@ static G_NORETURN
>  void dump_core_and_abort(CPUArchState *env, int target_sig)
>  {
>      CPUState *cpu = env_cpu(env);
> -    TaskState *ts = (TaskState *)cpu->opaque;
> +    TaskState *ts = get_task_state(cpu);
>      int host_sig, core_dumped = 0;
>
>      /* On exit, undo the remapping of SIGABRT. */
> @@ -769,7 +769,7 @@ void queue_signal(CPUArchState *env, int sig, int
> si_type,
>                    target_siginfo_t *info)
>  {
>      CPUState *cpu = env_cpu(env);
> -    TaskState *ts = cpu->opaque;
> +    TaskState *ts = get_task_state(cpu);
>
>      trace_user_queue_signal(env, sig);
>
> @@ -954,7 +954,7 @@ static void host_signal_handler(int host_sig,
> siginfo_t *info, void *puc)
>  {
>      CPUState *cpu = thread_cpu;
>      CPUArchState *env = cpu_env(cpu);
> -    TaskState *ts = cpu->opaque;
> +    TaskState *ts = get_task_state(cpu);
>      target_siginfo_t tinfo;
>      host_sigcontext *uc = puc;
>      struct emulated_sigtable *k;
> @@ -1174,7 +1174,7 @@ static void handle_pending_signal(CPUArchState
> *cpu_env, int sig,
>      sigset_t set;
>      target_sigset_t target_old_set;
>      struct target_sigaction *sa;
> -    TaskState *ts = cpu->opaque;
> +    TaskState *ts = get_task_state(cpu);
>
>      trace_user_handle_signal(cpu_env, sig);
>      /* dequeue signal */
> @@ -1256,7 +1256,7 @@ void process_pending_signals(CPUArchState *cpu_env)
>  {
>      CPUState *cpu = env_cpu(cpu_env);
>      int sig;
> -    TaskState *ts = cpu->opaque;
> +    TaskState *ts = get_task_state(cpu);
>      sigset_t set;
>      sigset_t *blocked_set;
>
> @@ -1316,7 +1316,7 @@ void process_pending_signals(CPUArchState *cpu_env)
>  int process_sigsuspend_mask(sigset_t **pset, target_ulong sigset,
>                              target_ulong sigsize)
>  {
> -    TaskState *ts = (TaskState *)thread_cpu->opaque;
> +    TaskState *ts = get_task_state(thread_cpu);
>      sigset_t *host_set = &ts->sigsuspend_mask;
>      target_sigset_t *target_sigset;
>
> diff --git a/linux-user/syscall.c b/linux-user/syscall.c
> index e384e142489..3e105488ee2 100644
> --- a/linux-user/syscall.c
> +++ b/linux-user/syscall.c
> @@ -6515,7 +6515,7 @@ static void *clone_func(void *arg)
>      env = info->env;
>      cpu = env_cpu(env);
>      thread_cpu = cpu;
> -    ts = (TaskState *)cpu->opaque;
> +    ts = get_task_state(cpu);
>      info->tid = sys_gettid();
>      task_settid(ts);
>      if (info->child_tidptr)
> @@ -6557,7 +6557,7 @@ static int do_fork(CPUArchState *env, unsigned int
> flags, abi_ulong newsp,
>          flags &= ~(CLONE_VFORK | CLONE_VM);
>
>      if (flags & CLONE_VM) {
> -        TaskState *parent_ts = (TaskState *)cpu->opaque;
> +        TaskState *parent_ts = get_task_state(cpu);
>          new_thread_info info;
>          pthread_attr_t attr;
>
> @@ -6680,7 +6680,7 @@ static int do_fork(CPUArchState *env, unsigned int
> flags, abi_ulong newsp,
>                  put_user_u32(sys_gettid(), child_tidptr);
>              if (flags & CLONE_PARENT_SETTID)
>                  put_user_u32(sys_gettid(), parent_tidptr);
> -            ts = (TaskState *)cpu->opaque;
> +            ts = get_task_state(cpu);
>              if (flags & CLONE_SETTLS)
>                  cpu_set_tls (env, newtls);
>              if (flags & CLONE_CHILD_CLEARTID)
> @@ -7946,7 +7946,7 @@ int host_to_target_waitstatus(int status)
>  static int open_self_cmdline(CPUArchState *cpu_env, int fd)
>  {
>      CPUState *cpu = env_cpu(cpu_env);
> -    struct linux_binprm *bprm = ((TaskState *)cpu->opaque)->bprm;
> +    struct linux_binprm *bprm = get_task_state(cpu)->bprm;
>      int i;
>
>      for (i = 0; i < bprm->argc; i++) {
> @@ -8130,7 +8130,7 @@ static int open_self_smaps(CPUArchState *cpu_env,
> int fd)
>  static int open_self_stat(CPUArchState *cpu_env, int fd)
>  {
>      CPUState *cpu = env_cpu(cpu_env);
> -    TaskState *ts = cpu->opaque;
> +    TaskState *ts = get_task_state(cpu);
>      g_autoptr(GString) buf = g_string_new(NULL);
>      int i;
>
> @@ -8171,7 +8171,7 @@ static int open_self_stat(CPUArchState *cpu_env, int
> fd)
>  static int open_self_auxv(CPUArchState *cpu_env, int fd)
>  {
>      CPUState *cpu = env_cpu(cpu_env);
> -    TaskState *ts = cpu->opaque;
> +    TaskState *ts = get_task_state(cpu);
>      abi_ulong auxv = ts->info->saved_auxv;
>      abi_ulong len = ts->info->auxv_len;
>      char *ptr;
> @@ -8996,7 +8996,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env,
> int num, abi_long arg1,
>          pthread_mutex_lock(&clone_lock);
>
>          if (CPU_NEXT(first_cpu)) {
> -            TaskState *ts = cpu->opaque;
> +            TaskState *ts = get_task_state(cpu);
>
>              if (ts->child_tidptr) {
>                  put_user_u32(0, ts->child_tidptr);
> @@ -9423,7 +9423,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env,
> int num, abi_long arg1,
>  #ifdef TARGET_NR_pause /* not on alpha */
>      case TARGET_NR_pause:
>          if (!block_signals()) {
> -            sigsuspend(&((TaskState *)cpu->opaque)->signal_mask);
> +            sigsuspend(&get_task_state(cpu)->signal_mask);
>          }
>          return -TARGET_EINTR;
>  #endif
> @@ -9989,7 +9989,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env,
> int num, abi_long arg1,
>              sigset_t *set;
>
>  #if defined(TARGET_ALPHA)
> -            TaskState *ts = cpu->opaque;
> +            TaskState *ts = get_task_state(cpu);
>              /* target_to_host_old_sigset will bswap back */
>              abi_ulong mask = tswapal(arg1);
>              set = &ts->sigsuspend_mask;
> @@ -10390,7 +10390,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env,
> int num, abi_long arg1,
>      case TARGET_NR_mprotect:
>          arg1 = cpu_untagged_addr(cpu, arg1);
>          {
> -            TaskState *ts = cpu->opaque;
> +            TaskState *ts = get_task_state(cpu);
>              /* Special hack to detect libc making the stack executable.
> */
>              if ((arg3 & PROT_GROWSDOWN)
>                  && arg1 >= ts->info->stack_limit
> @@ -12521,7 +12521,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env,
> int num, abi_long arg1,
>        return do_set_thread_area(cpu_env, arg1);
>  #elif defined(TARGET_M68K)
>        {
> -          TaskState *ts = cpu->opaque;
> +          TaskState *ts = get_task_state(cpu);
>            ts->tp_value = arg1;
>            return 0;
>        }
> @@ -12535,7 +12535,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env,
> int num, abi_long arg1,
>          return do_get_thread_area(cpu_env, arg1);
>  #elif defined(TARGET_M68K)
>          {
> -            TaskState *ts = cpu->opaque;
> +            TaskState *ts = get_task_state(cpu);
>              return ts->tp_value;
>          }
>  #else
> @@ -12660,7 +12660,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env,
> int num, abi_long arg1,
>  #if defined(TARGET_NR_set_tid_address)
>      case TARGET_NR_set_tid_address:
>      {
> -        TaskState *ts = cpu->opaque;
> +        TaskState *ts = get_task_state(cpu);
>          ts->child_tidptr = arg1;
>          /* do not call host set_tid_address() syscall, instead return
> tid() */
>          return get_errno(sys_gettid());
> diff --git a/linux-user/vm86.c b/linux-user/vm86.c
> index c2facf3fc2d..9f512a2242b 100644
> --- a/linux-user/vm86.c
> +++ b/linux-user/vm86.c
> @@ -74,7 +74,7 @@ static inline unsigned int vm_getl(CPUX86State *env,
>  void save_v86_state(CPUX86State *env)
>  {
>      CPUState *cs = env_cpu(env);
> -    TaskState *ts = cs->opaque;
> +    TaskState *ts = get_task_state(cs);
>      struct target_vm86plus_struct * target_v86;
>
>      if (!lock_user_struct(VERIFY_WRITE, target_v86, ts->target_v86, 0))
> @@ -134,7 +134,7 @@ static inline void return_to_32bit(CPUX86State *env,
> int retval)
>  static inline int set_IF(CPUX86State *env)
>  {
>      CPUState *cs = env_cpu(env);
> -    TaskState *ts = cs->opaque;
> +    TaskState *ts = get_task_state(cs);
>
>      ts->v86flags |= VIF_MASK;
>      if (ts->v86flags & VIP_MASK) {
> @@ -147,7 +147,7 @@ static inline int set_IF(CPUX86State *env)
>  static inline void clear_IF(CPUX86State *env)
>  {
>      CPUState *cs = env_cpu(env);
> -    TaskState *ts = cs->opaque;
> +    TaskState *ts = get_task_state(cs);
>
>      ts->v86flags &= ~VIF_MASK;
>  }
> @@ -165,7 +165,7 @@ static inline void clear_AC(CPUX86State *env)
>  static inline int set_vflags_long(unsigned long eflags, CPUX86State *env)
>  {
>      CPUState *cs = env_cpu(env);
> -    TaskState *ts = cs->opaque;
> +    TaskState *ts = get_task_state(cs);
>
>      set_flags(ts->v86flags, eflags, ts->v86mask);
>      set_flags(env->eflags, eflags, SAFE_MASK);
> @@ -179,7 +179,7 @@ static inline int set_vflags_long(unsigned long
> eflags, CPUX86State *env)
>  static inline int set_vflags_short(unsigned short flags, CPUX86State *env)
>  {
>      CPUState *cs = env_cpu(env);
> -    TaskState *ts = cs->opaque;
> +    TaskState *ts = get_task_state(cs);
>
>      set_flags(ts->v86flags, flags, ts->v86mask & 0xffff);
>      set_flags(env->eflags, flags, SAFE_MASK);
> @@ -193,7 +193,7 @@ static inline int set_vflags_short(unsigned short
> flags, CPUX86State *env)
>  static inline unsigned int get_vflags(CPUX86State *env)
>  {
>      CPUState *cs = env_cpu(env);
> -    TaskState *ts = cs->opaque;
> +    TaskState *ts = get_task_state(cs);
>      unsigned int flags;
>
>      flags = env->eflags & RETURN_MASK;
> @@ -210,7 +210,7 @@ static inline unsigned int get_vflags(CPUX86State *env)
>  static void do_int(CPUX86State *env, int intno)
>  {
>      CPUState *cs = env_cpu(env);
> -    TaskState *ts = cs->opaque;
> +    TaskState *ts = get_task_state(cs);
>      uint32_t int_addr, segoffs, ssp;
>      unsigned int sp;
>
> @@ -269,7 +269,7 @@ void handle_vm86_trap(CPUX86State *env, int trapno)
>  void handle_vm86_fault(CPUX86State *env)
>  {
>      CPUState *cs = env_cpu(env);
> -    TaskState *ts = cs->opaque;
> +    TaskState *ts = get_task_state(cs);
>      uint32_t csp, ssp;
>      unsigned int ip, sp, newflags, newip, newcs, opcode, intno;
>      int data32, pref_done;
> @@ -394,7 +394,7 @@ void handle_vm86_fault(CPUX86State *env)
>  int do_vm86(CPUX86State *env, long subfunction, abi_ulong vm86_addr)
>  {
>      CPUState *cs = env_cpu(env);
> -    TaskState *ts = cs->opaque;
> +    TaskState *ts = get_task_state(cs);
>      struct target_vm86plus_struct * target_v86;
>      int ret;
>
> diff --git a/linux-user/xtensa/signal.c b/linux-user/xtensa/signal.c
> index 32dcfa52291..003208a9161 100644
> --- a/linux-user/xtensa/signal.c
> +++ b/linux-user/xtensa/signal.c
> @@ -157,7 +157,7 @@ void setup_rt_frame(int sig, struct target_sigaction
> *ka,
>  {
>      abi_ulong frame_addr;
>      struct target_rt_sigframe *frame;
> -    int is_fdpic = info_is_fdpic(((TaskState *)thread_cpu->opaque)->info);
> +    int is_fdpic = info_is_fdpic(get_task_state(thread_cpu)->info);
>      abi_ulong handler = 0;
>      abi_ulong handler_fdpic_GOT = 0;
>      uint32_t ra;
> diff --git a/plugins/api.c b/plugins/api.c
> index 5521b0ad36c..1d7b72c0f67 100644
> --- a/plugins/api.c
> +++ b/plugins/api.c
> @@ -392,7 +392,7 @@ const char *qemu_plugin_path_to_binary(void)
>  {
>      char *path = NULL;
>  #ifdef CONFIG_USER_ONLY
> -    TaskState *ts = (TaskState *) current_cpu->opaque;
> +    TaskState *ts = get_task_state(current_cpu);
>      path = g_strdup(ts->bprm->filename);
>  #endif
>      return path;
> @@ -402,7 +402,7 @@ uint64_t qemu_plugin_start_code(void)
>  {
>      uint64_t start = 0;
>  #ifdef CONFIG_USER_ONLY
> -    TaskState *ts = (TaskState *) current_cpu->opaque;
> +    TaskState *ts = get_task_state(current_cpu);
>      start = ts->info->start_code;
>  #endif
>      return start;
> @@ -412,7 +412,7 @@ uint64_t qemu_plugin_end_code(void)
>  {
>      uint64_t end = 0;
>  #ifdef CONFIG_USER_ONLY
> -    TaskState *ts = (TaskState *) current_cpu->opaque;
> +    TaskState *ts = get_task_state(current_cpu);
>      end = ts->info->end_code;
>  #endif
>      return end;
> @@ -422,7 +422,7 @@ uint64_t qemu_plugin_entry_code(void)
>  {
>      uint64_t entry = 0;
>  #ifdef CONFIG_USER_ONLY
> -    TaskState *ts = (TaskState *) current_cpu->opaque;
> +    TaskState *ts = get_task_state(current_cpu);
>      entry = ts->info->entry;
>  #endif
>      return entry;
> diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
> index 329ea112607..d78c6428b90 100644
> --- a/semihosting/arm-compat-semi.c
> +++ b/semihosting/arm-compat-semi.c
> @@ -214,7 +214,7 @@ static target_ulong syscall_err;
>  static inline uint32_t get_swi_errno(CPUState *cs)
>  {
>  #ifdef CONFIG_USER_ONLY
> -    TaskState *ts = cs->opaque;
> +    TaskState *ts = get_task_state(cs);
>
>      return ts->swi_errno;
>  #else
> @@ -226,7 +226,7 @@ static void common_semi_cb(CPUState *cs, uint64_t ret,
> int err)
>  {
>      if (err) {
>  #ifdef CONFIG_USER_ONLY
> -        TaskState *ts = cs->opaque;
> +        TaskState *ts = get_task_state(cs);
>          ts->swi_errno = err;
>  #else
>          syscall_err = err;
> @@ -586,7 +586,7 @@ void do_common_semihosting(CPUState *cs)
>  #if !defined(CONFIG_USER_ONLY)
>              const char *cmdline;
>  #else
> -            TaskState *ts = cs->opaque;
> +            TaskState *ts = get_task_state(cs);
>  #endif
>              GET_ARG(0);
>              GET_ARG(1);
> @@ -664,7 +664,7 @@ void do_common_semihosting(CPUState *cs)
>              target_ulong retvals[4];
>              int i;
>  #ifdef CONFIG_USER_ONLY
> -            TaskState *ts = cs->opaque;
> +            TaskState *ts = get_task_state(cs);
>              target_ulong limit;
>  #else
>              LayoutInfo info = common_semi_find_bases(cs);
> --
> 2.43.2
>
>

[-- Attachment #2: Type: text/html, Size: 39019 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v4 03/12] {linux,bsd}-user: Update ts_tid after fork()
  2024-02-19 14:15 ` [PATCH v4 03/12] {linux,bsd}-user: Update ts_tid after fork() Ilya Leoshkevich
@ 2024-02-19 14:33   ` Warner Losh
  0 siblings, 0 replies; 17+ messages in thread
From: Warner Losh @ 2024-02-19 14:33 UTC (permalink / raw)
  To: Ilya Leoshkevich
  Cc: Alex Bennée, Richard Henderson, Riku Voipio, Laurent Vivier,
	Kyle Evans, Philippe Mathieu-Daudé,
	Alexandre Iooss, Mahmoud Mandour, Pierrick Bouvier, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 1478 bytes --]

On Mon, Feb 19, 2024 at 7:22 AM Ilya Leoshkevich <iii@linux.ibm.com> wrote:

> Currently ts_tid contains the parent tid after fork(), which is not
> correct. So far it has not affected anything, but the upcoming
> follow-fork-mode child support relies on the correct value, so fix it.
>
> Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
> Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
>

Reviewed-by: Warner Losh <imp@bsdimp.com>

Warner


> ---
>  bsd-user/main.c   | 1 +
>  linux-user/main.c | 1 +
>  2 files changed, 2 insertions(+)
>
> diff --git a/bsd-user/main.c b/bsd-user/main.c
> index e5efb7b8458..72289673a94 100644
> --- a/bsd-user/main.c
> +++ b/bsd-user/main.c
> @@ -127,6 +127,7 @@ void fork_end(int child)
>           * state, so we don't need to end_exclusive() here.
>           */
>          qemu_init_cpu_list();
> +        get_task_state(thread_cpu)->ts_tid = qemu_get_thread_id();
>          gdbserver_fork(thread_cpu);
>      } else {
>          mmap_fork_end(child);
> diff --git a/linux-user/main.c b/linux-user/main.c
> index 74b2fbb3938..1d53f708354 100644
> --- a/linux-user/main.c
> +++ b/linux-user/main.c
> @@ -160,6 +160,7 @@ void fork_end(int child)
>              }
>          }
>          qemu_init_cpu_list();
> +        get_task_state(thread_cpu)->ts_tid = qemu_get_thread_id();
>          gdbserver_fork(thread_cpu);
>      } else {
>          cpu_list_unlock();
> --
> 2.43.2
>
>

[-- Attachment #2: Type: text/html, Size: 2295 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v4 02/12] {linux,bsd}-user: Introduce get_task_state()
  2024-02-19 14:15 ` [PATCH v4 02/12] {linux,bsd}-user: Introduce get_task_state() Ilya Leoshkevich
  2024-02-19 14:32   ` Warner Losh
@ 2024-02-19 20:46   ` Richard Henderson
  1 sibling, 0 replies; 17+ messages in thread
From: Richard Henderson @ 2024-02-19 20:46 UTC (permalink / raw)
  To: Ilya Leoshkevich, Warner Losh, Alex Bennée, Riku Voipio,
	Laurent Vivier
  Cc: qemu-devel

On 2/19/24 04:15, Ilya Leoshkevich wrote:
> A CPU's TaskState is stored in the CPUState's void *opaque field,
> accessing which is somewhat awkward due to having to use a cast.
> Introduce a wrapper and use it everywhere.
> 
> Suggested-by: Alex Bennée<alex.bennee@linaro.org>
> Signed-off-by: Ilya Leoshkevich<iii@linux.ibm.com>
> ---
>   bsd-user/bsd-file.h           |  2 +-
>   bsd-user/qemu.h               |  5 +++++
>   bsd-user/signal.c             | 20 ++++++++++----------
>   gdbstub/user-target.c         |  4 ++--
>   include/user/safe-syscall.h   |  2 +-
>   linux-user/aarch64/cpu_loop.c |  2 +-
>   linux-user/arm/cpu_loop.c     |  4 ++--
>   linux-user/arm/signal.c       |  2 +-
>   linux-user/cris/cpu_loop.c    |  2 +-
>   linux-user/elfload.c          |  6 +++---
>   linux-user/hppa/signal.c      |  2 +-
>   linux-user/linuxload.c        |  2 +-
>   linux-user/m68k/cpu_loop.c    |  2 +-
>   linux-user/m68k/target_cpu.h  |  2 +-
>   linux-user/mips/cpu_loop.c    |  2 +-
>   linux-user/ppc/signal.c       |  4 ++--
>   linux-user/qemu.h             |  5 +++++
>   linux-user/riscv/cpu_loop.c   |  2 +-
>   linux-user/signal-common.h    |  2 +-
>   linux-user/signal.c           | 30 +++++++++++++++---------------
>   linux-user/syscall.c          | 26 +++++++++++++-------------
>   linux-user/vm86.c             | 18 +++++++++---------
>   linux-user/xtensa/signal.c    |  2 +-
>   plugins/api.c                 |  8 ++++----
>   semihosting/arm-compat-semi.c |  8 ++++----
>   25 files changed, 87 insertions(+), 77 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v4 00/12] gdbstub: Implement follow-fork-mode child
  2024-02-19 14:15 [PATCH v4 00/12] gdbstub: Implement follow-fork-mode child Ilya Leoshkevich
                   ` (11 preceding siblings ...)
  2024-02-19 14:16 ` [PATCH v4 12/12] tests/tcg: Add two follow-fork-mode tests Ilya Leoshkevich
@ 2024-03-04 18:03 ` Alex Bennée
  12 siblings, 0 replies; 17+ messages in thread
From: Alex Bennée @ 2024-03-04 18:03 UTC (permalink / raw)
  To: Ilya Leoshkevich
  Cc: Warner Losh, Richard Henderson, Riku Voipio, Laurent Vivier,
	Kyle Evans, Philippe Mathieu-Daudé,
	Alexandre Iooss, Mahmoud Mandour, Pierrick Bouvier, qemu-devel

Ilya Leoshkevich <iii@linux.ibm.com> writes:

> v3: https://lists.gnu.org/archive/html/qemu-devel/2024-02/msg03142.html
> v3 -> v4: Address the review comments, add R-bs.
>           Add the get_task_state() refactoring.
>           Keep passing CPUState to gdbserver_fork_end() for tb_flush().
>           Patches that need review: 02/12, 09/12-12/12.
>
> v2: https://lists.gnu.org/archive/html/qemu-devel/2024-02/msg00810.html
> v2 -> v3: Rebase on top of master.
>           Fix a typo in the 01/11 commit message.
>
> v1: https://lists.gnu.org/archive/html/qemu-devel/2024-01/msg06646.html
> v1 -> v2: Factor out a number of prep patches;
>           Add a state transition diagram comment (Alex).
>           Improve a few comments;
>           Extend the ts_tid fix to bsd.
>
> Hi,
>
> I needed to debug a linux-user crash between fork() and exec() [1] and
> realized that gdbstub does not allow this. This series lifts this
> restriction (one still cannot debug past exec() though). Patches 1-10
> are preliminary refactorings, patch 11 is the implementation, and patch
> 12 is the test.

Queued to gdbstub/next, thanks.

-- 
Alex Bennée
Virtualisation Tech Lead @ Linaro


^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2024-03-04 18:04 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-02-19 14:15 [PATCH v4 00/12] gdbstub: Implement follow-fork-mode child Ilya Leoshkevich
2024-02-19 14:15 ` [PATCH v4 01/12] gdbstub: Support disablement in a multi-threaded process Ilya Leoshkevich
2024-02-19 14:15 ` [PATCH v4 02/12] {linux,bsd}-user: Introduce get_task_state() Ilya Leoshkevich
2024-02-19 14:32   ` Warner Losh
2024-02-19 20:46   ` Richard Henderson
2024-02-19 14:15 ` [PATCH v4 03/12] {linux,bsd}-user: Update ts_tid after fork() Ilya Leoshkevich
2024-02-19 14:33   ` Warner Losh
2024-02-19 14:15 ` [PATCH v4 04/12] gdbstub: Introduce gdbserver_fork_start() Ilya Leoshkevich
2024-02-19 14:15 ` [PATCH v4 05/12] {linux,bsd}-user: Pass pid to fork_end() Ilya Leoshkevich
2024-02-19 14:15 ` [PATCH v4 06/12] {linux,bsd}-user: Pass pid to gdbserver_fork() Ilya Leoshkevich
2024-02-19 14:15 ` [PATCH v4 07/12] gdbstub: Call gdbserver_fork() both in parent and in child Ilya Leoshkevich
2024-02-19 14:15 ` [PATCH v4 08/12] gdbstub: Introduce gdb_handle_query_supported_user() Ilya Leoshkevich
2024-02-19 14:15 ` [PATCH v4 09/12] gdbstub: Introduce gdb_handle_set_thread_user() Ilya Leoshkevich
2024-02-19 14:15 ` [PATCH v4 10/12] gdbstub: Introduce gdb_handle_detach_user() Ilya Leoshkevich
2024-02-19 14:15 ` [PATCH v4 11/12] gdbstub: Implement follow-fork-mode child Ilya Leoshkevich
2024-02-19 14:16 ` [PATCH v4 12/12] tests/tcg: Add two follow-fork-mode tests Ilya Leoshkevich
2024-03-04 18:03 ` [PATCH v4 00/12] gdbstub: Implement follow-fork-mode child Alex Bennée

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.