OS: FreeBSD 7.4
GDB Version: 7.4.1 (compiled for FreeBSD 7.4)
Arch: amd64
[Note: a bit long email]
Problem:
While debugging a multi-threaded app that creates/deletes a bunch of threads, my GDB session, once every few runs, gets into a state where I cannot debug anymore.
First I get the error message
At that point, I can look at all the threads using info thread. Now, if I select an available thread and continue, I get the following error
I debugged it a bit further and here is what I found:
fbsd_thread_wait() in fbsd-threads.c function has the following code indicated as a hack
Here is the sequence that results in the "Invalid selected thread" message.
After getting into the "Invalid select thread" state, if I select an available thread and continue,
I'm not sure how exactly to fix this issue, as I've seen the "hack" in fbsd_thread_wait() getting called other times without any issue. It only seems to be an issue when the "hack" deletes a thread and a subsequent call to fbsd_thread_wait() returns the ptid of the thread that was deleted.
I can open a bug report if this is an issue, but also looking to see if there is an easy fix that I can use to correct the problem.
Thanks,
-Raghu
GDB Version: 7.4.1 (compiled for FreeBSD 7.4)
Arch: amd64
[Note: a bit long email]
Problem:
While debugging a multi-threaded app that creates/deletes a bunch of threads, my GDB session, once every few runs, gets into a state where I cannot debug anymore.
First I get the error message
Code:
Invalid selected thread
At that point, I can look at all the threads using info thread. Now, if I select an available thread and continue, I get the following error
Code:
thread.c:620: internal-error: is_thread_state: Assertion `tp' failed.
A problem internal to GDB has been detected,
further debugging may prove unreliable.
Quit this debugging session? (y or n)
I debugged it a bit further and here is what I found:
fbsd_thread_wait() in fbsd-threads.c function has the following code indicated as a hack
Code:
if (!fbsd_thread_alive (ops, inferior_ptid) && !ptid_equal(inferior_ptid, ret))
{
delete_thread (inferior_ptid);
inferior_ptid = ret;
}
- The delete_thread() in the above code sets the state of the thread associated with the inferior_ptid as exited (THREAD_EXITED).
- wait_for_inferior() function in infrun.c gets called and the call to target_wait() inside that function returns the 'ptid' of the thread that was deleted above.
- The handle_inferior_event() function called from wait_for_inferior does a switch_to_thread() to the thread deleted above. Here is the code fragment that does the switch:
Code:/* See if something interesting happened to the non-current thread. If so, then switch to that thread. */ if (!ptid_equal (ecs->ptid, inferior_ptid)) { if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: context switch\n"); context_switch (ecs->ptid); if (deprecated_context_hook) deprecated_context_hook (pid_to_thread_id (ecs->ptid)); } /* At this point, get hold of the now-current thread's frame. */ frame = get_current_frame (); gdbarch = get_frame_arch (frame)
- The call to get_frame_arch() after the switch displays the error "Invalid selected thread" as the thread had exited
After getting into the "Invalid select thread" state, if I select an available thread and continue,
- prune_threads() gets called and deletes all the threads that exited
- prepare_to_proceed() get called. This function retrieves the last_target_status and ptid, which points to the thread that got deleted by the "hack" in fbsd-threads.c, and tries to switch to that thread using the following code fragment
Code:/* Switched over from WAIT_PID. */ if (!ptid_equal (wait_ptid, minus_one_ptid) && !ptid_equal (inferior_ptid, wait_ptid)) { struct regcache *regcache = get_thread_regcache (wait_ptid); if (breakpoint_here_p (get_regcache_aspace (regcache), regcache_read_pc (regcache))) { /* If stepping, remember current thread to switch back to. */ if (step) deferred_step_ptid = inferior_ptid; /* Switch back to WAIT_PID thread. */ switch_to_thread (wait_ptid); if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: prepare_to_proceed (step=%d), " "switched to [%s]\n", step, target_pid_to_str (inferior_ptid)); /* We return 1 to indicate that there is a breakpoint here, so we need to step over it before continuing to avoid hitting it straight away. */ return 1; } }
- switch_to_thread() calls is_exited(), which asserts as it does not find the thread in the thread list
I'm not sure how exactly to fix this issue, as I've seen the "hack" in fbsd_thread_wait() getting called other times without any issue. It only seems to be an issue when the "hack" deletes a thread and a subsequent call to fbsd_thread_wait() returns the ptid of the thread that was deleted.
I can open a bug report if this is an issue, but also looking to see if there is an easy fix that I can use to correct the problem.
Thanks,
-Raghu