From 1e9fa730163c2a445014ff8324b169cd82a50df1 Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Wed, 3 Jun 2009 11:33:08 -0700 Subject: fix gdbstub support for multiple threads in usermode, v3 When debugging multi-threaded programs, QEMU's gdb stub would report the correct number of threads (the qfThreadInfo and qsThreadInfo packets). However, the stub was unable to actually switch between threads (the T packet), since it would report every thread except the first as being dead. Furthermore, the stub relied upon cpu_index as a reliable means of assigning IDs to the threads. This was a bad idea; if you have this sequence of events: initial thread created new thread #1 new thread #2 thread #1 exits new thread #3 thread #3 will have the same cpu_index as thread #1, which would confuse GDB. (This problem is partly due to the remote protocol not having a good way to send thread creation/destruction events.) We fix this by using the host thread ID for the identifier passed to GDB when debugging a multi-threaded userspace program. The thread ID might wrap, but the same sort of problems with wrapping thread IDs would come up with debugging programs natively, so this doesn't represent a problem. Signed-off-by: Nathan Froyd --- linux-user/syscall.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'linux-user') diff --git a/linux-user/syscall.c b/linux-user/syscall.c index a0915a455..59c91f8da 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -3202,6 +3202,7 @@ static void *clone_func(void *arg) env = info->env; thread_env = env; info->tid = gettid(); + env->host_tid = info->tid; if (info->child_tidptr) put_user_u32(info->tid, info->child_tidptr); if (info->parent_tidptr) @@ -3792,6 +3793,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, /* FIXME: This probably breaks if a signal arrives. We should probably be disabling signals. */ if (first_cpu->next_cpu) { + TaskState *ts; CPUState **lastp; CPUState *p; @@ -3809,7 +3811,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, /* Remove the CPU from the list. */ *lastp = p->next_cpu; cpu_list_unlock(); - TaskState *ts = ((CPUState *)cpu_env)->opaque; + ts = ((CPUState *)cpu_env)->opaque; if (ts->child_tidptr) { put_user_u32(0, ts->child_tidptr); sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX, -- cgit v1.2.3