~ubuntu-support-team/binutils/+git/binutils-gdb:users/palves/windows-non-stop

Last commit made on 2023-05-31
Get this branch:
git clone -b users/palves/windows-non-stop https://git.launchpad.net/~ubuntu-support-team/binutils/+git/binutils-gdb

Branch merges

Branch information

Name:
users/palves/windows-non-stop
Repository:
lp:~ubuntu-support-team/binutils/+git/binutils-gdb

Recent commits

2726fee... by Pedro Alves <email address hidden>

Mention Windows non-stop support in NEWS

Add a note to gdb/NEWS mentioning Windows non-stop support.

Change-Id: Id0e28525c06e57120c47b07f978581d1627d70f3

625fb49... by Pedro Alves <email address hidden>

Windows gdb: Watchpoints and internal vs external stops

Teach the Windows target to temporarily pause all threads when we
change the debug registers for a watchpoint. Implements the same
logic as Linux uses:

    ~~~
      /* (...) if threads are running when the
         mirror changes, a temporary and transparent stop on all threads
         is forced so they can get their copy of the debug registers
         updated on re-resume. (...) */
    ~~~

On Linux, we send each thread a SIGSTOP to step them. On Windows,
SuspendThread itself doesn't cause any asynchronous debug event to be
reported. However, we've implemented windows_nat_target::stop such
that it uses SuspendThread, and then queues a pending GDB_SIGNAL_0
stop on the thread. That results in a user-visible stop, while here
we want a non-user-visible stop. So what we do is re-use that
windows_nat_target::stop stopping mechanism, but add an external vs
internal stopping kind distinction. An internal stop results in
windows_nat_target::wait immediately re-resuming the thread.

Note we don't make the debug registers poking code SuspendThread ->
write debug registers -> ContinueThread itself, because SuspendThread
is actually asynchronous and may take a bit to stop the thread (a
following GetThreadContext blocks until the thread is actually
suspended), and, there will be several debug register writes when a
watchpoint is set, because we have to set all of DR0, DR1, DR2, DR3,
and DR7. Defering the actualy writes to ::wait avoids a bunch of
SuspendThread/ResumeThread sequences, so in principle should be
faster.

Change-Id: I39c2492c7aac06d23ef8f287f4afe3747b7bc53f

cf81a31... by Pedro Alves <email address hidden>

Windows gdb: cygwin_set_dr => windows_set_dr, etc.

The Windows backend functions that manipulate the x86 debug registers
are called "cygwin_foo", which is outdated, because native MinGW gdb
also uses those functions, they are not Cygwin-specific. Rename them
to "windows_foo" to avoid confusion.

Change-Id: I46df3b44f5272adadf960da398342a3cbdb98533

25813fb... by Pedro Alves <email address hidden>

Windows gdb: Add non-stop support

This patch adds non-stop support to the native Windows target.

This is made possible by the ContinueDebugEvent DBG_REPLY_LATER flag:

https://learn.microsoft.com/en-us/windows/win32/api/debugapi/nf-debugapi-continuedebugevent

  Supported in Windows 10, version 1507 or above, this flag causes
  dwThreadId to replay the existing breaking event after the target
  continues. By calling the SuspendThread API against dwThreadId, a
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  debugger can resume other threads in the process and later return to
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  the breaking.
  ^^^^^^^^^^^^

The patch adds a new comment section in gdb/windows-nat.c providing an
overall picture of how all-stop / non-stop work.

Without DBG_REPLY_LATER, if we SuspendThread the thread, and then
immediately ContinueDebugThread(DBG_CONTINUE) before getting back to
the prompt, we could still have non-stop mode working, however, then
users wouldn't have a chance to decide whether to pass the signal to
the inferior the next time they resume the program, as that is done by
passing DBG_EXCEPTION_NOT_HANDLED to ContinueDebugEvent, and that has
already been called.

The patch adds that DBG_REPLY_LATER handling, and also adds support
for target_stop, so the core can pause threads at its discretion.
This pausing does not use the same mechanisms used in
windows_nat_target::interrupt, as those inject a new thread in the
inferior. Instead, for each thread the core wants paused, it uses
SuspendThread, and enqueues a pending GDB_SIGNAL_= stop on the thread.

Since DBG_REPLY_LATER only exists on Windows 10 and later, we only
enable non-stop mode on Windows 10 and later.

Since having the target backend work in non-stop mode adds features
compared to old all-stop mode (signal/exception passing/suppression is
truly per-thread), this patch also switches the backend to do
all-stop-on-top-of-non-stop, by having
windows_nat_target::always_non_stop_p return true if non-stop mode is
possible. To be clear, this just changes how the backend works in
coordination with infrun. The user-visible mode default mode is still
all-stop. The difference is that that infrun is responsible for
stopping all threads when needed, instead of the backend always doing
that.

No displaced stepping, but that's "just" a missed optimization to be
done later.

Change-Id: Id71aef461c43c244120635b5bedc638fe77c31fb

7eed1b7... by Pedro Alves <email address hidden>

Windows gdb: Change serial_event management

windows_nat_target::windows_continue, when it finds a resumed thread
that has a pending event, does:

   /* There's no need to really continue, because there's already
      another event pending. However, we do need to inform the
      event loop of this. */
   serial_event_set (m_wait_event);
   return TRUE;

If we have more than one pending event ready to be consumed, and,
windows_nat_target::wait returns without calling
windows_nat_target::windows_continue, which it will with the non-stop
support in the following patch, then we will miss waking up the event
loop.

This patch makes windows-nat.c manage the serial_event similarly to
how linux-nat.c does it. Clear it on entry to
windows_nat_target::wait, and set it if there may be more events to
process. With this, there's no need to set it from
windows_nat_target::wait_for_debug_event_main_thread, so the patch
also makes us not do it.

Change-Id: I44e1682721aa4866f1dbb052b3cfb4870fb13579

02260cf... by Pedro Alves <email address hidden>

Windows gdb/gdbserver: Eliminate struct pending_stop

After the previous patch, struct pending_stop only contains one field.
So move that field into the windows_thread_info structure directly,
and eliminate struct pending_stop.

Change-Id: I7955884b3f378d8b39b908f6252d215f6568b367

2d8f819... by Pedro Alves <email address hidden>

Windows gdb/gdbserver: Share $_siginfo reading code

Both GDB and GDBserver have similar code to read the $_siginfo data.
This patch moves the bulk of it to gdb/nat/windows-nat.c so it can be
shared.

Change-Id: I47fc0d3323be5b6f6fcfe912b768051a41910666

01169b1... by Pedro Alves <email address hidden>

Add backpointer from windows_thread_info to windows_process_info

The next patch will move some duplicated code in gdb and gdbserver to
gdb/nat/windows-nat.c, where it would be convenient to get at the
Windows process info of a given Windows thread info, from within a
windows_thread_info method.

I first thought of passing down the windows_process_info pointer as
argument to the windows_thread_info method, but that looked a bit odd.
I think it looks better to just add a back pointer, so that's what
this patch does. The following patch will then add a use of it.

I suspect this will help moving more duplicated code to
gdb/nat/windows-nat.c in the future, too.

Change-Id: I47fc0d3323be5b6f6fcfe912b768051a41910666

0112815... by Pedro Alves <email address hidden>

Windows gdb/gdbserver: Make siginfo_er per-thread state

With non-stop mode support, each thread has its own "last event", and
so printing $_siginfo should print the siginfo of the selected thread.
Likewise, with all-stop and scheduler-locking.

This patch reworks the siginfo functions in gdb/windows-nat.c and
gdbserver/win32-low.cc to reuse the exception record already saved
within each thread's 'last_event' field.

Here's an example of what you'll see after the whole non-stop series:

  (gdb) thread apply all p -pretty -- $_siginfo

  Thread 3 (Thread 2612.0x1470):
  $1 = {
    ExceptionCode = DBG_CONTROL_C,
    ExceptionFlags = 0,
    ExceptionRecord = 0x0,
    ExceptionAddress = 0x7ffd0583e929 <KERNELBASE!EncodeRemotePointer+8249>,
    NumberParameters = 0,
    {
      ExceptionInformation = {0 <repeats 15 times>},
      AccessViolationInformation = {
 Type = READ_ACCESS_VIOLATION,
 Address = 0x0
      }
    }
  }

  Thread 2 (Thread 2612.0x1704):
  $2 = {
    ExceptionCode = SINGLE_STEP,
    ExceptionFlags = 0,
    ExceptionRecord = 0x0,
    ExceptionAddress = 0x7ffd080ad6e4 <ntdll!ZwDelayExecution+20>,
    NumberParameters = 0,
    {
      ExceptionInformation = {0 <repeats 15 times>},
      AccessViolationInformation = {
 Type = READ_ACCESS_VIOLATION,
 Address = 0x0
      }
    }
  }

  Thread 1 (Thread 2612.0x434):
  $3 = {
    ExceptionCode = BREAKPOINT,
    ExceptionFlags = 0,
    ExceptionRecord = 0x0,
    ExceptionAddress = 0x7ff6f691174c <main+185>,
    NumberParameters = 1,
    {
      ExceptionInformation = {0 <repeats 15 times>},
      AccessViolationInformation = {
 Type = READ_ACCESS_VIOLATION,
 Address = 0x0
      }
    }
  }
  (gdb)

This was in non-stop mode, and the program originally had two threads.
Thread 1 stopped for a breakpoint, then thread 2 was manually
interrupted/paused and then single-stepped. And then I typed Ctrl-C
in the inferior's terminal, which made Windows inject thread 3 in the
inferior, and report a DBG_CONTROL_C exception for it.

Change-Id: I5d4f1b62f59e8aef3606642c6524df2362b0fb7d

b9134b9... by Pedro Alves <email address hidden>

Windows gdb/gdbserver: Make last_sig per-thread state

With non-stop mode, each thread is controlled independently of the
others, and each thread has its own independent reason for its last
stop.

Thus, any thread-specific state that is currently per-process must be
converted to per-thread state.

This patch converts windows_process_info::last_sig to per-thread
state, moving it to windows_thread_info instead.

This adjusts both native gdb and gdbserver.

Change-Id: Ice09a5d932c912210608d5af25e1898f823e3c99