Re: Multithreaded debugging: strange thread switches

Daniel Jacobowitz
2006-01-23T15:52:46Z

On Mon, Jan 23, 2006 at 06:20:32PM +0300, Vladimir Prus wrote:
>
> Hello,
> I'm observing strange behaviour when debugging with gdb using a custom stub.
> I have two threads. After connecting, I say "next" several times and that
> steps in thread 1. Then I say "thread 2" and "next". Gdb then stops again in
> thread 1, not in thread 2 as I'd expected.
>
> In the remote protocol I see "Hc1" packet after last "next" though I'd expect

This, generally, is part of the problem. If you want this to work, you
need to implement the vCont packet in the stub. The Hc1 packet is
supposed to mean "step only thread 1, leaving thread 2 stopped", and
that's not what the gdb "next" command is supposed to map to - that's
"step this thread but leave other threads free-running".

> "Hc2", and in infrun.c, function prepare_to_proceed, I see this:
>
>
> if (!ptid_equal (wait_ptid, minus_one_ptid)
> && !ptid_equal (inferior_ptid, wait_ptid))
> {
> /* Switched over from WAIT_PID. */
> CORE_ADDR wait_pc = read_pc_pid (wait_ptid);
>
> if (wait_pc != read_pc ())
> {
> /* Switch back to WAIT_PID thread. */
> inferior_ptid = wait_ptid;
>
> /* FIXME: This stuff came from switch_to_thread() in
> thread.c (which should probably be a public function). */
> flush_cached_frames ();
> registers_changed ();
> stop_pc = wait_pc;
> select_frame (get_current_frame ());
> }
>
> Can somebody explain the reason for this explicit switch back to "wait_ptid"?

I have no idea, but if you remove it you're going to bust the bit below
that steps over breakpoints, and then GDB will really get unhappy.
Maybe we can adjust that block of code, though. See the comment in
proceed():

/* In a multi-threaded task we may select another thread
and then continue or step.

But if the old thread was stopped at a breakpoint, it
will immediately cause another breakpoint stop without
any execution (i.e. it will report a breakpoint hit
incorrectly). So we must step over it first.

prepare_to_proceed checks the current thread against the thread
that reported the most recent event. If a step-over is required
it returns TRUE and sets the current thread to the old thread. */

The current code was modified to always select the previous thread
in arch-utils.c revision 1.28 in order to support resuming after
hitting Control-C:
http://sourceware.org/ml/gdb-patches/2001-05/msg00419.html

I can't tell from Jonathan's post what problem he's trying to fix.
Previously the thread would only be switched if (SIGTRAP && breakpoint
here). Now it's switched if (SIGTRAP || SIGINT) and then we
single-step if (breakpoint here). Which doesn't make much sense.

--
Daniel Jacobowitz
CodeSourcery