gdb-7.4.1 thread.c:613 internal-error: is_thread_state: Assertion 'tp' failed

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
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;
        }
Here is the sequence that results in the "Invalid selected thread" message.

  1. The delete_thread() in the above code sets the state of the thread associated with the inferior_ptid as exited (THREAD_EXITED).
  2. 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.
  3. 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)
  4. 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,
  1. prune_threads() gets called and deletes all the threads that exited
  2. 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;
            }
        }
  3. 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
 
Back
Top