* [PATCH v2 01/11] Remove duplicate code from windows_nat_target::resume
[not found] <20260117134052.2660009-1-ssbssa.ref@yahoo.de>
@ 2026-01-17 13:36 ` Hannes Domani
2026-01-17 13:36 ` [PATCH v2 02/11] Simplify windows_nat_target::resume Hannes Domani
` (14 more replies)
0 siblings, 15 replies; 44+ messages in thread
From: Hannes Domani @ 2026-01-17 13:36 UTC (permalink / raw)
To: gdb-patches; +Cc: Tom Tromey
Updating the debug registers and calling SetThreadContext is already
done in windows_continue, called directly afterwards, so this removes it
from windows_nat_target::resume.
Approved-By: Tom Tromey <tom@tromey.com>
---
No changes in v2
---
gdb/windows-nat.c | 16 ----------------
1 file changed, 16 deletions(-)
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index e86877b4c50..a6fd199530c 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -1378,22 +1378,6 @@ windows_nat_target::resume (ptid_t ptid, int step, enum gdb_signal sig)
fetch_registers (regcache, gdbarch_ps_regnum (gdbarch));
context->EFlags |= FLAG_TRACE_BIT;
}
-
- if (context->ContextFlags)
- {
- if (th->debug_registers_changed)
- {
- context->Dr0 = windows_process.dr[0];
- context->Dr1 = windows_process.dr[1];
- context->Dr2 = windows_process.dr[2];
- context->Dr3 = windows_process.dr[3];
- context->Dr6 = DR6_CLEAR_VALUE;
- context->Dr7 = windows_process.dr[7];
- th->debug_registers_changed = false;
- }
- CHECK (set_thread_context (th->h, context));
- context->ContextFlags = 0;
- }
});
}
--
2.52.0
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH v2 02/11] Simplify windows_nat_target::resume
2026-01-17 13:36 ` [PATCH v2 01/11] Remove duplicate code from windows_nat_target::resume Hannes Domani
@ 2026-01-17 13:36 ` Hannes Domani
2026-01-19 13:55 ` Schimpe, Christina
2026-01-17 13:36 ` [PATCH v2 03/11] Move struct declarations into windows-nat.h Hannes Domani
` (13 subsequent siblings)
14 siblings, 1 reply; 44+ messages in thread
From: Hannes Domani @ 2026-01-17 13:36 UTC (permalink / raw)
To: gdb-patches; +Cc: Tom Tromey
Now the thread context is only needed for setting the trace bit, so move
the rest out of the with_context lambda.
Approved-By: Tom Tromey <tom@tromey.com>
---
No changes in v2
---
gdb/windows-nat.c | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index a6fd199530c..8ee52768cb1 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -1366,18 +1366,15 @@ windows_nat_target::resume (ptid_t ptid, int step, enum gdb_signal sig)
/* Get context for currently selected thread. */
th = windows_process.thread_rec (inferior_ptid, DONT_INVALIDATE_CONTEXT);
- if (th)
+ if (th && step)
{
+ /* Single step by setting t bit. */
+ regcache *regcache = get_thread_regcache (inferior_thread ());
+ struct gdbarch *gdbarch = regcache->arch ();
+ fetch_registers (regcache, gdbarch_ps_regnum (gdbarch));
windows_process.with_context (th, [&] (auto *context)
{
- if (step)
- {
- /* Single step by setting t bit. */
- regcache *regcache = get_thread_regcache (inferior_thread ());
- struct gdbarch *gdbarch = regcache->arch ();
- fetch_registers (regcache, gdbarch_ps_regnum (gdbarch));
- context->EFlags |= FLAG_TRACE_BIT;
- }
+ context->EFlags |= FLAG_TRACE_BIT;
});
}
--
2.52.0
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH v2 03/11] Move struct declarations into windows-nat.h
2026-01-17 13:36 ` [PATCH v2 01/11] Remove duplicate code from windows_nat_target::resume Hannes Domani
2026-01-17 13:36 ` [PATCH v2 02/11] Simplify windows_nat_target::resume Hannes Domani
@ 2026-01-17 13:36 ` Hannes Domani
2026-01-17 13:36 ` [PATCH v2 04/11] Create x86-windows-nat.c Hannes Domani
` (12 subsequent siblings)
14 siblings, 0 replies; 44+ messages in thread
From: Hannes Domani @ 2026-01-17 13:36 UTC (permalink / raw)
To: gdb-patches; +Cc: Tom Tromey
This is done as preparation for aarch64-windows-nat, since both x86 and
aarch64 will use them as base (after the x86 parts are split off into
x86-windows-nat).
Approved-By: Tom Tromey <tom@tromey.com>
---
No changes in v2
---
gdb/windows-nat.c | 576 ++++++++++++++--------------------------------
gdb/windows-nat.h | 230 ++++++++++++++++++
2 files changed, 409 insertions(+), 397 deletions(-)
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index 8ee52768cb1..7fdd6cf81b5 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -42,9 +42,6 @@
#include <cygwin/version.h>
#endif
#include <algorithm>
-#include <atomic>
-#include <vector>
-#include <queue>
#include "filenames.h"
#include "symfile.h"
@@ -67,84 +64,17 @@
#include "windows-nat.h"
#include "x86-nat.h"
#include "complaints.h"
-#include "inf-child.h"
#include "gdbsupport/gdb_tilde_expand.h"
#include "gdbsupport/pathstuff.h"
#include "gdbsupport/gdb_wait.h"
-#include "nat/windows-nat.h"
#include "gdbsupport/symbol.h"
-#include "ser-event.h"
#include "inf-loop.h"
using namespace windows_nat;
-/* Maintain a linked list of "so" information. */
-struct windows_solib
-{
- LPVOID load_addr = 0;
- CORE_ADDR text_offset = 0;
-
- /* Original name. */
- std::string original_name;
- /* Expanded form of the name. */
- std::string name;
-};
-
-struct windows_per_inferior : public windows_process_info
-{
- windows_thread_info *thread_rec (ptid_t ptid,
- thread_disposition_type disposition) override;
- int handle_output_debug_string (struct target_waitstatus *ourstatus) override;
- void handle_load_dll (const char *dll_name, LPVOID base) override;
- void handle_unload_dll () override;
- bool handle_access_violation (const EXCEPTION_RECORD *rec) override;
-
- uintptr_t dr[8] {};
-
- int windows_initialization_done = 0;
-
- std::vector<std::unique_ptr<windows_thread_info>> thread_list;
-
- /* Counts of things. */
- int saw_create = 0;
- int open_process_used = 0;
-#ifdef __x86_64__
- void *wow64_dbgbreak = nullptr;
-#endif
-
- /* This vector maps GDB's idea of a register's number into an offset
- in the windows exception context vector.
-
- It also contains the bit mask needed to load the register in question.
-
- The contents of this table can only be computed by the units
- that provide CPU-specific support for Windows native debugging.
-
- One day we could read a reg, we could inspect the context we
- already have loaded, if it doesn't have the bit set that we need,
- we read that set of registers in using GetThreadContext. If the
- context already contains what we need, we just unpack it. Then to
- write a register, first we have to ensure that the context contains
- the other regs of the group, and then we copy the info in and set
- out bit. */
-
- const int *mappings = nullptr;
-
- /* The function to use in order to determine whether a register is
- a segment register or not. */
- segment_register_p_ftype *segment_register_p = nullptr;
-
- std::vector<windows_solib> solibs;
-
-#ifdef __CYGWIN__
- /* The starting and ending address of the cygwin1.dll text segment. */
- CORE_ADDR cygwin_load_start = 0;
- CORE_ADDR cygwin_load_end = 0;
-#endif /* __CYGWIN__ */
-};
-
/* The current process. */
-static windows_per_inferior windows_process;
+static windows_per_inferior x86_windows_process;
+windows_per_inferior *windows_process = &x86_windows_process;
#undef STARTUPINFO
@@ -229,162 +159,6 @@ static const struct xlate_exception xlate[] =
#endif /* 0 */
-struct windows_nat_target final : public x86_nat_target<inf_child_target>
-{
- windows_nat_target ();
-
- void close () override;
-
- void attach (const char *, int) override;
-
- bool attach_no_wait () override
- { return true; }
-
- void detach (inferior *, int) override;
-
- void resume (ptid_t, int , enum gdb_signal) override;
-
- ptid_t wait (ptid_t, struct target_waitstatus *, target_wait_flags) override;
-
- void fetch_registers (struct regcache *, int) override;
- void store_registers (struct regcache *, int) override;
-
- bool stopped_by_sw_breakpoint () override
- {
- windows_thread_info *th
- = windows_process.thread_rec (inferior_ptid, DONT_INVALIDATE_CONTEXT);
- return th->stopped_at_software_breakpoint;
- }
-
- bool supports_stopped_by_sw_breakpoint () override
- {
- return true;
- }
-
- enum target_xfer_status xfer_partial (enum target_object object,
- const char *annex,
- gdb_byte *readbuf,
- const gdb_byte *writebuf,
- ULONGEST offset, ULONGEST len,
- ULONGEST *xfered_len) override;
-
- void files_info () override;
-
- void kill () override;
-
- void create_inferior (const char *, const std::string &,
- char **, int) override;
-
- void mourn_inferior () override;
-
- bool thread_alive (ptid_t ptid) override;
-
- std::string pid_to_str (ptid_t) override;
-
- void interrupt () override;
- void pass_ctrlc () override;
-
- const char *pid_to_exec_file (int pid) override;
-
- ptid_t get_ada_task_ptid (long lwp, ULONGEST thread) override;
-
- bool get_tib_address (ptid_t ptid, CORE_ADDR *addr) override;
-
- const char *thread_name (struct thread_info *) override;
-
- ptid_t get_windows_debug_event (int pid, struct target_waitstatus *ourstatus,
- target_wait_flags options);
-
- void do_initial_windows_stuff (DWORD pid, bool attaching);
-
- bool supports_disable_randomization () override
- {
- return disable_randomization_available ();
- }
-
- bool can_async_p () override
- {
- return true;
- }
-
- bool is_async_p () override
- {
- return m_is_async;
- }
-
- void async (bool enable) override;
-
- int async_wait_fd () override
- {
- return serial_event_fd (m_wait_event);
- }
-
-private:
-
- windows_thread_info *add_thread (ptid_t ptid, HANDLE h, void *tlb,
- bool main_thread_p);
- void delete_thread (ptid_t ptid, DWORD exit_code, bool main_thread_p);
- DWORD fake_create_process ();
-
- BOOL windows_continue (DWORD continue_status, int id, int killed,
- bool last_call = false);
-
- /* Helper function to start process_thread. */
- static DWORD WINAPI process_thread_starter (LPVOID self);
-
- /* This function implements the background thread that starts
- inferiors and waits for events. */
- void process_thread ();
-
- /* Push FUNC onto the queue of requests for process_thread, and wait
- until it has been called. On Windows, certain debugging
- functions can only be called by the thread that started (or
- attached to) the inferior. These are all done in the worker
- thread, via calls to this method. If FUNC returns true,
- process_thread will wait for debug events when FUNC returns. */
- void do_synchronously (gdb::function_view<bool ()> func);
-
- /* This waits for a debug event, dispatching to the worker thread as
- needed. */
- void wait_for_debug_event_main_thread (DEBUG_EVENT *event);
-
- /* Force the process_thread thread to return from WaitForDebugEvent.
- PROCESS_ALIVE is set to false if the inferior process exits while
- we're trying to break out the process_thread thread. This can
- happen because this is called while all threads are running free,
- while we're trying to detach. */
- void break_out_process_thread (bool &process_alive);
-
- /* Queue used to send requests to process_thread. This is
- implicitly locked. */
- std::queue<gdb::function_view<bool ()>> m_queue;
-
- /* Event used to signal process_thread that an item has been
- pushed. */
- HANDLE m_pushed_event;
- /* Event used by process_thread to indicate that it has processed a
- single function call. */
- HANDLE m_response_event;
-
- /* Serial event used to communicate wait event availability to the
- main loop. */
- serial_event *m_wait_event;
-
- /* The last debug event, when M_WAIT_EVENT has been set. */
- DEBUG_EVENT m_last_debug_event {};
- /* True if a debug event is pending. */
- std::atomic<bool> m_debug_event_pending { false };
-
- /* True if currently in async mode. */
- bool m_is_async = false;
-
- /* True if we last called ContinueDebugEvent and the process_thread
- thread is now waiting for events. False if WaitForDebugEvent
- already returned an event, and we need to ContinueDebugEvent
- again to restart the inferior. */
- bool m_continued = false;
-};
-
static void
check (BOOL ok, const char *file, int line)
{
@@ -560,18 +334,18 @@ windows_nat_target::add_thread (ptid_t ptid, HANDLE h, void *tlb,
gdb_assert (ptid.lwp () != 0);
- if ((th = windows_process.thread_rec (ptid, DONT_INVALIDATE_CONTEXT)))
+ if ((th = windows_process->thread_rec (ptid, DONT_INVALIDATE_CONTEXT)))
return th;
CORE_ADDR base = (CORE_ADDR) (uintptr_t) tlb;
#ifdef __x86_64__
/* For WOW64 processes, this is actually the pointer to the 64bit TIB,
and the 32bit TIB is exactly 2 pages after it. */
- if (windows_process.wow64_process)
+ if (windows_process->wow64_process)
base += 0x2000;
#endif
th = new windows_thread_info (ptid.lwp (), h, base);
- windows_process.thread_list.emplace_back (th);
+ windows_process->thread_list.emplace_back (th);
/* Add this new thread to the list of threads.
@@ -596,7 +370,7 @@ static void
windows_init_thread_list (void)
{
DEBUG_EVENTS ("called");
- windows_process.thread_list.clear ();
+ windows_process->thread_list.clear ();
}
/* Delete a thread from the list of threads.
@@ -624,15 +398,15 @@ windows_nat_target::delete_thread (ptid_t ptid, DWORD exit_code,
thread_info *to_del = this->find_thread (ptid);
delete_thread_with_exit_code (to_del, exit_code, silent);
- auto iter = std::find_if (windows_process.thread_list.begin (),
- windows_process.thread_list.end (),
+ auto iter = std::find_if (windows_process->thread_list.begin (),
+ windows_process->thread_list.end (),
[=] (std::unique_ptr<windows_thread_info> &th)
{
return th->tid == id;
});
- if (iter != windows_process.thread_list.end ())
- windows_process.thread_list.erase (iter);
+ if (iter != windows_process->thread_list.end ())
+ windows_process->thread_list.erase (iter);
}
/* Fetches register number R from the given windows_thread_info,
@@ -652,12 +426,12 @@ windows_fetch_one_register (struct regcache *regcache,
gdb_assert (r >= 0);
gdb_assert (!th->reload_context);
- char *context_ptr = windows_process.with_context (th, [] (auto *context)
+ char *context_ptr = windows_process->with_context (th, [] (auto *context)
{
return (char *) context;
});
- char *context_offset = context_ptr + windows_process.mappings[r];
+ char *context_offset = context_ptr + windows_process->mappings[r];
struct gdbarch *gdbarch = regcache->arch ();
i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
@@ -668,7 +442,7 @@ windows_fetch_one_register (struct regcache *regcache,
/* GDB treats some registers as 32-bit, where they are in fact only
16 bits long. These cases must be handled specially to avoid
reading extraneous bits from the context. */
- if (r == I387_FISEG_REGNUM (tdep) || windows_process.segment_register_p (r))
+ if (r == I387_FISEG_REGNUM (tdep) || windows_process->segment_register_p (r))
{
gdb_byte bytes[4] = {};
memcpy (bytes, context_offset, 2);
@@ -712,7 +486,7 @@ void
windows_nat_target::fetch_registers (struct regcache *regcache, int r)
{
windows_thread_info *th
- = windows_process.thread_rec (regcache->ptid (), INVALIDATE_CONTEXT);
+ = windows_process->thread_rec (regcache->ptid (), INVALIDATE_CONTEXT);
/* Check if TH exists. Windows sometimes uses a non-existent
thread id in its events. */
@@ -721,7 +495,7 @@ windows_nat_target::fetch_registers (struct regcache *regcache, int r)
if (th->reload_context)
{
- windows_process.with_context (th, [&] (auto *context)
+ windows_process->with_context (th, [&] (auto *context)
{
context->ContextFlags = WindowsContext<decltype(context)>::all;
CHECK (get_thread_context (th->h, context));
@@ -730,12 +504,12 @@ windows_nat_target::fetch_registers (struct regcache *regcache, int r)
PR gdb/2388 */
if (!th->debug_registers_changed)
{
- windows_process.dr[0] = context->Dr0;
- windows_process.dr[1] = context->Dr1;
- windows_process.dr[2] = context->Dr2;
- windows_process.dr[3] = context->Dr3;
- windows_process.dr[6] = context->Dr6;
- windows_process.dr[7] = context->Dr7;
+ windows_process->dr[0] = context->Dr0;
+ windows_process->dr[1] = context->Dr1;
+ windows_process->dr[2] = context->Dr2;
+ windows_process->dr[3] = context->Dr3;
+ windows_process->dr[6] = context->Dr6;
+ windows_process->dr[7] = context->Dr7;
}
});
@@ -761,7 +535,7 @@ windows_store_one_register (const struct regcache *regcache,
{
gdb_assert (r >= 0);
- char *context_ptr = windows_process.with_context (th, [] (auto *context)
+ char *context_ptr = windows_process->with_context (th, [] (auto *context)
{
return (char *) context;
});
@@ -772,11 +546,11 @@ windows_store_one_register (const struct regcache *regcache,
/* GDB treats some registers as 32-bit, where they are in fact only
16 bits long. These cases must be handled specially to avoid
overwriting other registers in the context. */
- if (r == I387_FISEG_REGNUM (tdep) || windows_process.segment_register_p (r))
+ if (r == I387_FISEG_REGNUM (tdep) || windows_process->segment_register_p (r))
{
gdb_byte bytes[4];
regcache->raw_collect (r, bytes);
- memcpy (context_ptr + windows_process.mappings[r], bytes, 2);
+ memcpy (context_ptr + windows_process->mappings[r], bytes, 2);
}
else if (r == I387_FOP_REGNUM (tdep))
{
@@ -785,10 +559,10 @@ windows_store_one_register (const struct regcache *regcache,
/* The value of FOP occupies the top two bytes in the context,
so write the two low-order bytes from the cache into the
appropriate spot. */
- memcpy (context_ptr + windows_process.mappings[r] + 2, bytes, 2);
+ memcpy (context_ptr + windows_process->mappings[r] + 2, bytes, 2);
}
else
- regcache->raw_collect (r, context_ptr + windows_process.mappings[r]);
+ regcache->raw_collect (r, context_ptr + windows_process->mappings[r]);
}
/* Store a new register value into the context of the thread tied to
@@ -798,7 +572,7 @@ void
windows_nat_target::store_registers (struct regcache *regcache, int r)
{
windows_thread_info *th
- = windows_process.thread_rec (regcache->ptid (), INVALIDATE_CONTEXT);
+ = windows_process->thread_rec (regcache->ptid (), INVALIDATE_CONTEXT);
/* Check if TH exists. Windows sometimes uses a non-existent
thread id in its events. */
@@ -812,12 +586,20 @@ windows_nat_target::store_registers (struct regcache *regcache, int r)
windows_store_one_register (regcache, th, r);
}
+bool
+windows_nat_target::stopped_by_sw_breakpoint ()
+{
+ windows_thread_info *th
+ = windows_process->thread_rec (inferior_ptid, DONT_INVALIDATE_CONTEXT);
+ return th->stopped_at_software_breakpoint;
+}
+
/* See nat/windows-nat.h. */
static windows_solib *
windows_make_so (const char *name, LPVOID load_addr)
{
- windows_solib *so = &windows_process.solibs.emplace_back ();
+ windows_solib *so = &windows_process->solibs.emplace_back ();
so->load_addr = load_addr;
so->original_name = name;
@@ -913,9 +695,9 @@ windows_make_so (const char *name, LPVOID load_addr)
/* The symbols in a dll are offset by 0x1000, which is the
offset from 0 of the first byte in an image - because of the
file header and the section alignment. */
- windows_process.cygwin_load_start = (CORE_ADDR) (uintptr_t) ((char *)
- load_addr + 0x1000);
- windows_process.cygwin_load_end = windows_process.cygwin_load_start +
+ windows_process->cygwin_load_start = (CORE_ADDR) (uintptr_t) ((char *)
+ load_addr + 0x1000);
+ windows_process->cygwin_load_end = windows_process->cygwin_load_start +
bfd_section_size (text);
}
#endif
@@ -940,8 +722,8 @@ windows_per_inferior::handle_unload_dll ()
{
LPVOID lpBaseOfDll = current_event.u.UnloadDll.lpBaseOfDll;
- auto iter = std::remove_if (windows_process.solibs.begin (),
- windows_process.solibs.end (),
+ auto iter = std::remove_if (windows_process->solibs.begin (),
+ windows_process->solibs.end (),
[&] (windows_solib &lib)
{
if (lib.load_addr == lpBaseOfDll)
@@ -952,9 +734,9 @@ windows_per_inferior::handle_unload_dll ()
return false;
});
- if (iter != windows_process.solibs.end ())
+ if (iter != windows_process->solibs.end ())
{
- windows_process.solibs.erase (iter, windows_process.solibs.end ());
+ windows_process->solibs.erase (iter, windows_process->solibs.end ());
return;
}
@@ -973,7 +755,7 @@ windows_per_inferior::handle_unload_dll ()
static void
windows_clear_solib (void)
{
- windows_process.solibs.clear ();
+ windows_process->solibs.clear ();
}
static void
@@ -1061,7 +843,7 @@ static int
display_selector (HANDLE thread, DWORD sel)
{
LDT_ENTRY info;
- BOOL ret = windows_process.with_context (nullptr, [&] (auto *context)
+ BOOL ret = windows_process->with_context (nullptr, [&] (auto *context)
{
return get_thread_selector_entry (context, thread, sel, &info);
});
@@ -1149,11 +931,11 @@ display_selectors (const char * args, int from_tty)
}
windows_thread_info *current_windows_thread
- = windows_process.thread_rec (inferior_ptid, DONT_INVALIDATE_CONTEXT);
+ = windows_process->thread_rec (inferior_ptid, DONT_INVALIDATE_CONTEXT);
if (!args)
{
- windows_process.with_context (current_windows_thread, [&] (auto *context)
+ windows_process->with_context (current_windows_thread, [&] (auto *context)
{
gdb_puts ("Selector $cs\n");
display_selector (current_windows_thread->h, context->SegCs);
@@ -1214,9 +996,9 @@ BOOL
windows_nat_target::windows_continue (DWORD continue_status, int id,
int killed, bool last_call)
{
- windows_process.desired_stop_thread_id = id;
+ windows_process->desired_stop_thread_id = id;
- if (windows_process.matching_pending_stop (debug_events))
+ if (windows_process->matching_pending_stop (debug_events))
{
/* There's no need to really continue, because there's already
another event pending. However, we do need to inform the
@@ -1225,21 +1007,21 @@ windows_nat_target::windows_continue (DWORD continue_status, int id,
return TRUE;
}
- for (auto &th : windows_process.thread_list)
+ for (auto &th : windows_process->thread_list)
if (id == -1 || id == (int) th->tid)
{
- windows_process.with_context (th.get (), [&] (auto *context)
+ windows_process->with_context (th.get (), [&] (auto *context)
{
if (th->debug_registers_changed)
{
context->ContextFlags
|= WindowsContext<decltype(context)>::debug;
- context->Dr0 = windows_process.dr[0];
- context->Dr1 = windows_process.dr[1];
- context->Dr2 = windows_process.dr[2];
- context->Dr3 = windows_process.dr[3];
+ context->Dr0 = windows_process->dr[0];
+ context->Dr1 = windows_process->dr[1];
+ context->Dr2 = windows_process->dr[2];
+ context->Dr3 = windows_process->dr[3];
context->Dr6 = DR6_CLEAR_VALUE;
- context->Dr7 = windows_process.dr[7];
+ context->Dr7 = windows_process->dr[7];
th->debug_registers_changed = false;
}
if (context->ContextFlags)
@@ -1292,23 +1074,23 @@ windows_nat_target::windows_continue (DWORD continue_status, int id,
DWORD
windows_nat_target::fake_create_process ()
{
- windows_process.handle
+ windows_process->handle
= OpenProcess (PROCESS_ALL_ACCESS, FALSE,
- windows_process.current_event.dwProcessId);
- if (windows_process.handle != NULL)
- windows_process.open_process_used = 1;
+ windows_process->current_event.dwProcessId);
+ if (windows_process->handle != NULL)
+ windows_process->open_process_used = 1;
else
{
unsigned err = (unsigned) GetLastError ();
throw_winerror_with_name (_("OpenProcess call failed"), err);
/* We can not debug anything in that case. */
}
- add_thread (ptid_t (windows_process.current_event.dwProcessId,
- windows_process.current_event.dwThreadId, 0),
- windows_process.current_event.u.CreateThread.hThread,
- windows_process.current_event.u.CreateThread.lpThreadLocalBase,
+ add_thread (ptid_t (windows_process->current_event.dwProcessId,
+ windows_process->current_event.dwThreadId, 0),
+ windows_process->current_event.u.CreateThread.hThread,
+ windows_process->current_event.u.CreateThread.lpThreadLocalBase,
true /* main_thread_p */);
- return windows_process.current_event.dwThreadId;
+ return windows_process->current_event.dwThreadId;
}
void
@@ -1327,12 +1109,12 @@ windows_nat_target::resume (ptid_t ptid, int step, enum gdb_signal sig)
if (sig != GDB_SIGNAL_0)
{
- if (windows_process.current_event.dwDebugEventCode
+ if (windows_process->current_event.dwDebugEventCode
!= EXCEPTION_DEBUG_EVENT)
{
DEBUG_EXCEPT ("Cannot continue with signal %d here.", sig);
}
- else if (sig == windows_process.last_sig)
+ else if (sig == windows_process->last_sig)
continue_status = DBG_EXCEPTION_NOT_HANDLED;
else
#if 0
@@ -1356,23 +1138,23 @@ windows_nat_target::resume (ptid_t ptid, int step, enum gdb_signal sig)
}
#endif
DEBUG_EXCEPT ("Can only continue with received signal %d.",
- windows_process.last_sig);
+ windows_process->last_sig);
}
- windows_process.last_sig = GDB_SIGNAL_0;
+ windows_process->last_sig = GDB_SIGNAL_0;
DEBUG_EXEC ("pid=%d, tid=0x%x, step=%d, sig=%d",
ptid.pid (), (unsigned) ptid.lwp (), step, sig);
/* Get context for currently selected thread. */
- th = windows_process.thread_rec (inferior_ptid, DONT_INVALIDATE_CONTEXT);
+ th = windows_process->thread_rec (inferior_ptid, DONT_INVALIDATE_CONTEXT);
if (th && step)
{
/* Single step by setting t bit. */
regcache *regcache = get_thread_regcache (inferior_thread ());
struct gdbarch *gdbarch = regcache->arch ();
fetch_registers (regcache, gdbarch_ps_regnum (gdbarch));
- windows_process.with_context (th, [&] (auto *context)
+ windows_process->with_context (th, [&] (auto *context)
{
context->EFlags |= FLAG_TRACE_BIT;
});
@@ -1394,24 +1176,24 @@ windows_nat_target::interrupt ()
{
DEBUG_EVENTS ("interrupt");
#ifdef __x86_64__
- if (windows_process.wow64_process)
+ if (windows_process->wow64_process)
{
/* Call DbgUiRemoteBreakin of the 32bit ntdll.dll in the target process.
DebugBreakProcess would call the one of the 64bit ntdll.dll, which
can't be correctly handled by gdb. */
- if (windows_process.wow64_dbgbreak == nullptr)
+ if (windows_process->wow64_dbgbreak == nullptr)
{
CORE_ADDR addr;
if (!find_minimal_symbol_address ("ntdll!DbgUiRemoteBreakin",
&addr, 0))
- windows_process.wow64_dbgbreak = (void *) addr;
+ windows_process->wow64_dbgbreak = (void *) addr;
}
- if (windows_process.wow64_dbgbreak != nullptr)
+ if (windows_process->wow64_dbgbreak != nullptr)
{
- HANDLE thread = CreateRemoteThread (windows_process.handle, NULL,
+ HANDLE thread = CreateRemoteThread (windows_process->handle, NULL,
0, (LPTHREAD_START_ROUTINE)
- windows_process.wow64_dbgbreak,
+ windows_process->wow64_dbgbreak,
NULL, 0, NULL);
if (thread)
{
@@ -1422,7 +1204,7 @@ windows_nat_target::interrupt ()
}
else
#endif
- if (DebugBreakProcess (windows_process.handle))
+ if (DebugBreakProcess (windows_process->handle))
return;
warning (_("Could not interrupt program. "
"Press Ctrl-c in the program console."));
@@ -1447,22 +1229,22 @@ windows_nat_target::get_windows_debug_event
comment by the definition of "pending_stops" for details on why
this is needed. */
std::optional<pending_stop> stop
- = windows_process.fetch_pending_stop (debug_events);
+ = windows_process->fetch_pending_stop (debug_events);
if (stop.has_value ())
{
thread_id = stop->thread_id;
*ourstatus = stop->status;
- ptid_t ptid (windows_process.current_event.dwProcessId, thread_id);
+ ptid_t ptid (windows_process->current_event.dwProcessId, thread_id);
windows_thread_info *th
- = windows_process.thread_rec (ptid, INVALIDATE_CONTEXT);
+ = windows_process->thread_rec (ptid, INVALIDATE_CONTEXT);
th->reload_context = true;
return ptid;
}
- windows_process.last_sig = GDB_SIGNAL_0;
- DEBUG_EVENT *current_event = &windows_process.current_event;
+ windows_process->last_sig = GDB_SIGNAL_0;
+ DEBUG_EVENT *current_event = &windows_process->current_event;
if ((options & TARGET_WNOHANG) != 0 && !m_debug_event_pending)
{
@@ -1470,11 +1252,11 @@ windows_nat_target::get_windows_debug_event
return minus_one_ptid;
}
- wait_for_debug_event_main_thread (&windows_process.current_event);
+ wait_for_debug_event_main_thread (&windows_process->current_event);
continue_status = DBG_CONTINUE;
- event_code = windows_process.current_event.dwDebugEventCode;
+ event_code = windows_process->current_event.dwDebugEventCode;
ourstatus->set_spurious ();
switch (event_code)
@@ -1484,17 +1266,17 @@ windows_nat_target::get_windows_debug_event
(unsigned) current_event->dwProcessId,
(unsigned) current_event->dwThreadId,
"CREATE_THREAD_DEBUG_EVENT");
- if (windows_process.saw_create != 1)
+ if (windows_process->saw_create != 1)
{
inferior *inf = find_inferior_pid (this, current_event->dwProcessId);
- if (!windows_process.saw_create && inf->attach_flag)
+ if (!windows_process->saw_create && inf->attach_flag)
{
/* Kludge around a Windows bug where first event is a create
thread event. Caused when attached process does not have
a main thread. */
thread_id = fake_create_process ();
if (thread_id)
- windows_process.saw_create++;
+ windows_process->saw_create++;
}
break;
}
@@ -1525,10 +1307,10 @@ windows_nat_target::get_windows_debug_event
(unsigned) current_event->dwThreadId,
"CREATE_PROCESS_DEBUG_EVENT");
CloseHandle (current_event->u.CreateProcessInfo.hFile);
- if (++windows_process.saw_create != 1)
+ if (++windows_process->saw_create != 1)
break;
- windows_process.handle = current_event->u.CreateProcessInfo.hProcess;
+ windows_process->handle = current_event->u.CreateProcessInfo.hProcess;
/* Add the main thread. */
add_thread
(ptid_t (current_event->dwProcessId,
@@ -1544,14 +1326,14 @@ windows_nat_target::get_windows_debug_event
(unsigned) current_event->dwProcessId,
(unsigned) current_event->dwThreadId,
"EXIT_PROCESS_DEBUG_EVENT");
- if (!windows_process.windows_initialization_done)
+ if (!windows_process->windows_initialization_done)
{
target_terminal::ours ();
target_mourn_inferior (inferior_ptid);
error (_("During startup program exited with code 0x%x."),
(unsigned int) current_event->u.ExitProcess.dwExitCode);
}
- else if (windows_process.saw_create == 1)
+ else if (windows_process->saw_create == 1)
{
delete_thread (ptid_t (current_event->dwProcessId,
current_event->dwThreadId, 0),
@@ -1578,12 +1360,12 @@ windows_nat_target::get_windows_debug_event
(unsigned) current_event->dwThreadId,
"LOAD_DLL_DEBUG_EVENT");
CloseHandle (current_event->u.LoadDll.hFile);
- if (windows_process.saw_create != 1
- || ! windows_process.windows_initialization_done)
+ if (windows_process->saw_create != 1
+ || ! windows_process->windows_initialization_done)
break;
try
{
- windows_process.dll_loaded_event ();
+ windows_process->dll_loaded_event ();
}
catch (const gdb_exception &ex)
{
@@ -1598,12 +1380,12 @@ windows_nat_target::get_windows_debug_event
(unsigned) current_event->dwProcessId,
(unsigned) current_event->dwThreadId,
"UNLOAD_DLL_DEBUG_EVENT");
- if (windows_process.saw_create != 1
- || ! windows_process.windows_initialization_done)
+ if (windows_process->saw_create != 1
+ || ! windows_process->windows_initialization_done)
break;
try
{
- windows_process.handle_unload_dll ();
+ windows_process->handle_unload_dll ();
}
catch (const gdb_exception &ex)
{
@@ -1618,9 +1400,9 @@ windows_nat_target::get_windows_debug_event
(unsigned) current_event->dwProcessId,
(unsigned) current_event->dwThreadId,
"EXCEPTION_DEBUG_EVENT");
- if (windows_process.saw_create != 1)
+ if (windows_process->saw_create != 1)
break;
- switch (windows_process.handle_exception (ourstatus, debug_exceptions))
+ switch (windows_process->handle_exception (ourstatus, debug_exceptions))
{
case HANDLE_EXCEPTION_UNHANDLED:
default:
@@ -1640,13 +1422,13 @@ windows_nat_target::get_windows_debug_event
(unsigned) current_event->dwProcessId,
(unsigned) current_event->dwThreadId,
"OUTPUT_DEBUG_STRING_EVENT");
- if (windows_process.saw_create != 1)
+ if (windows_process->saw_create != 1)
break;
- thread_id = windows_process.handle_output_debug_string (ourstatus);
+ thread_id = windows_process->handle_output_debug_string (ourstatus);
break;
default:
- if (windows_process.saw_create != 1)
+ if (windows_process->saw_create != 1)
break;
gdb_printf ("gdb: kernel event for pid=%u tid=0x%x\n",
(unsigned) current_event->dwProcessId,
@@ -1656,43 +1438,43 @@ windows_nat_target::get_windows_debug_event
break;
}
- if (!thread_id || windows_process.saw_create != 1)
+ if (!thread_id || windows_process->saw_create != 1)
{
CHECK (windows_continue (continue_status,
- windows_process.desired_stop_thread_id, 0));
+ windows_process->desired_stop_thread_id, 0));
}
- else if (windows_process.desired_stop_thread_id != -1
- && windows_process.desired_stop_thread_id != thread_id)
+ else if (windows_process->desired_stop_thread_id != -1
+ && windows_process->desired_stop_thread_id != thread_id)
{
/* Pending stop. See the comment by the definition of
"pending_stops" for details on why this is needed. */
DEBUG_EVENTS ("get_windows_debug_event - "
"unexpected stop in 0x%x (expecting 0x%x)",
- thread_id, windows_process.desired_stop_thread_id);
+ thread_id, windows_process->desired_stop_thread_id);
if (current_event->dwDebugEventCode == EXCEPTION_DEBUG_EVENT
&& ((current_event->u.Exception.ExceptionRecord.ExceptionCode
== EXCEPTION_BREAKPOINT)
|| (current_event->u.Exception.ExceptionRecord.ExceptionCode
== STATUS_WX86_BREAKPOINT))
- && windows_process.windows_initialization_done)
+ && windows_process->windows_initialization_done)
{
ptid_t ptid = ptid_t (current_event->dwProcessId, thread_id, 0);
windows_thread_info *th
- = windows_process.thread_rec (ptid, INVALIDATE_CONTEXT);
+ = windows_process->thread_rec (ptid, INVALIDATE_CONTEXT);
th->stopped_at_software_breakpoint = true;
th->pc_adjusted = false;
}
- windows_process.pending_stops.push_back
- ({thread_id, *ourstatus, windows_process.current_event});
+ windows_process->pending_stops.push_back
+ ({thread_id, *ourstatus, windows_process->current_event});
thread_id = 0;
CHECK (windows_continue (continue_status,
- windows_process.desired_stop_thread_id, 0));
+ windows_process->desired_stop_thread_id, 0));
}
if (thread_id == 0)
return null_ptid;
- return ptid_t (windows_process.current_event.dwProcessId, thread_id, 0);
+ return ptid_t (windows_process->current_event.dwProcessId, thread_id, 0);
}
/* Wait for interesting events to occur in the target process. */
@@ -1718,18 +1500,18 @@ windows_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
&& ourstatus->kind () != TARGET_WAITKIND_SIGNALLED)
{
windows_thread_info *th
- = windows_process.thread_rec (result, INVALIDATE_CONTEXT);
+ = windows_process->thread_rec (result, INVALIDATE_CONTEXT);
if (th != nullptr)
{
th->stopped_at_software_breakpoint = false;
- if (windows_process.current_event.dwDebugEventCode
+ if (windows_process->current_event.dwDebugEventCode
== EXCEPTION_DEBUG_EVENT
- && ((windows_process.current_event.u.Exception.ExceptionRecord.ExceptionCode
+ && ((windows_process->current_event.u.Exception.ExceptionRecord.ExceptionCode
== EXCEPTION_BREAKPOINT)
- || (windows_process.current_event.u.Exception.ExceptionRecord.ExceptionCode
+ || (windows_process->current_event.u.Exception.ExceptionRecord.ExceptionCode
== STATUS_WX86_BREAKPOINT))
- && windows_process.windows_initialization_done)
+ && windows_process->windows_initialization_done)
{
th->stopped_at_software_breakpoint = true;
th->pc_adjusted = false;
@@ -1758,19 +1540,19 @@ windows_nat_target::do_initial_windows_stuff (DWORD pid, bool attaching)
int i;
struct inferior *inf;
- windows_process.last_sig = GDB_SIGNAL_0;
- windows_process.open_process_used = 0;
+ windows_process->last_sig = GDB_SIGNAL_0;
+ windows_process->open_process_used = 0;
for (i = 0;
- i < sizeof (windows_process.dr) / sizeof (windows_process.dr[0]);
+ i < sizeof (windows_process->dr) / sizeof (windows_process->dr[0]);
i++)
- windows_process.dr[i] = 0;
+ windows_process->dr[i] = 0;
#ifdef __CYGWIN__
- windows_process.cygwin_load_start = 0;
- windows_process.cygwin_load_end = 0;
+ windows_process->cygwin_load_start = 0;
+ windows_process->cygwin_load_end = 0;
#endif
- windows_process.current_event.dwProcessId = pid;
- memset (&windows_process.current_event, 0,
- sizeof (windows_process.current_event));
+ windows_process->current_event.dwProcessId = pid;
+ memset (&windows_process->current_event, 0,
+ sizeof (windows_process->current_event));
inf = current_inferior ();
if (!inf->target_is_pushed (this))
inf->push_target (this);
@@ -1779,19 +1561,19 @@ windows_nat_target::do_initial_windows_stuff (DWORD pid, bool attaching)
init_wait_for_inferior ();
#ifdef __x86_64__
- windows_process.ignore_first_breakpoint
- = !attaching && windows_process.wow64_process;
+ windows_process->ignore_first_breakpoint
+ = !attaching && windows_process->wow64_process;
- if (!windows_process.wow64_process)
+ if (!windows_process->wow64_process)
{
- windows_process.mappings = amd64_mappings;
- windows_process.segment_register_p = amd64_windows_segment_register_p;
+ windows_process->mappings = amd64_mappings;
+ windows_process->segment_register_p = amd64_windows_segment_register_p;
}
else
#endif
{
- windows_process.mappings = i386_mappings;
- windows_process.segment_register_p = i386_windows_segment_register_p;
+ windows_process->mappings = i386_mappings;
+ windows_process->segment_register_p = i386_windows_segment_register_p;
}
inferior_appeared (inf, pid);
@@ -1800,7 +1582,7 @@ windows_nat_target::do_initial_windows_stuff (DWORD pid, bool attaching)
target_terminal::init ();
target_terminal::inferior ();
- windows_process.windows_initialization_done = 0;
+ windows_process->windows_initialization_done = 0;
ptid_t last_ptid;
@@ -1836,9 +1618,9 @@ windows_nat_target::do_initial_windows_stuff (DWORD pid, bool attaching)
Rather than try to work around this sort of issue, it is much
simpler to just ignore DLL load/unload events during the startup
phase, and then process them all in one batch now. */
- windows_process.add_all_dlls ();
+ windows_process->add_all_dlls ();
- windows_process.windows_initialization_done = 1;
+ windows_process->windows_initialization_done = 1;
return;
}
@@ -1905,7 +1687,7 @@ windows_nat_target::attach (const char *args, int from_tty)
"This can cause attach to fail on Windows NT/2K/XP");
windows_init_thread_list ();
- windows_process.saw_create = 0;
+ windows_process->saw_create = 0;
std::optional<unsigned> err;
do_synchronously ([&] ()
@@ -1955,7 +1737,7 @@ windows_nat_target::attach (const char *args, int from_tty)
{
BOOL wow64;
if (IsWow64Process (h, &wow64))
- windows_process.wow64_process = wow64;
+ windows_process->wow64_process = wow64;
CloseHandle (h);
}
#endif
@@ -2006,7 +1788,7 @@ windows_nat_target::break_out_process_thread (bool &process_alive)
DWORD injected_thread_id = 0;
HANDLE injected_thread_handle
- = CreateRemoteThread (windows_process.handle, NULL,
+ = CreateRemoteThread (windows_process->handle, NULL,
0, (LPTHREAD_START_ROUTINE) 0,
NULL, 0, &injected_thread_id);
@@ -2092,7 +1874,7 @@ windows_nat_target::detach (inferior *inf, int from_tty)
if (process_alive)
do_synchronously ([&] ()
{
- if (!DebugActiveProcessStop (windows_process.current_event.dwProcessId))
+ if (!DebugActiveProcessStop (windows_process->current_event.dwProcessId))
err = (unsigned) GetLastError ();
else
DebugSetProcessKillOnExit (FALSE);
@@ -2103,7 +1885,7 @@ windows_nat_target::detach (inferior *inf, int from_tty)
{
std::string msg
= string_printf (_("Can't detach process %u"),
- (unsigned) windows_process.current_event.dwProcessId);
+ (unsigned) windows_process->current_event.dwProcessId);
throw_winerror_with_name (msg.c_str (), *err);
}
@@ -2121,7 +1903,7 @@ windows_nat_target::detach (inferior *inf, int from_tty)
const char *
windows_nat_target::pid_to_exec_file (int pid)
{
- return windows_process.pid_to_exec_file (pid);
+ return windows_process->pid_to_exec_file (pid);
}
/* Print status information about what we're accessing. */
@@ -2821,16 +2603,16 @@ windows_nat_target::create_inferior (const char *exec_file,
#ifdef __x86_64__
BOOL wow64;
if (IsWow64Process (pi.hProcess, &wow64))
- windows_process.wow64_process = wow64;
+ windows_process->wow64_process = wow64;
#endif
CloseHandle (pi.hThread);
CloseHandle (pi.hProcess);
if (useshell && shell[0] != '\0')
- windows_process.saw_create = -1;
+ windows_process->saw_create = -1;
else
- windows_process.saw_create = 0;
+ windows_process->saw_create = 0;
do_initial_windows_stuff (pi.dwProcessId, 0);
@@ -2842,12 +2624,12 @@ windows_nat_target::mourn_inferior ()
{
(void) windows_continue (DBG_CONTINUE, -1, 0, true);
x86_cleanup_dregs();
- if (windows_process.open_process_used)
+ if (windows_process->open_process_used)
{
- CHECK (CloseHandle (windows_process.handle));
- windows_process.open_process_used = 0;
+ CHECK (CloseHandle (windows_process->handle));
+ windows_process->open_process_used = 0;
}
- windows_process.siginfo_er.ExceptionCode = 0;
+ windows_process->siginfo_er.ExceptionCode = 0;
inf_child_target::mourn_inferior ();
}
@@ -2866,19 +2648,19 @@ windows_xfer_memory (gdb_byte *readbuf, const gdb_byte *writebuf,
{
DEBUG_MEM ("write target memory, %s bytes at %s",
pulongest (len), core_addr_to_string (memaddr));
- success = WriteProcessMemory (windows_process.handle,
+ success = WriteProcessMemory (windows_process->handle,
(LPVOID) (uintptr_t) memaddr, writebuf,
len, &done);
if (!success)
lasterror = GetLastError ();
- FlushInstructionCache (windows_process.handle,
+ FlushInstructionCache (windows_process->handle,
(LPCVOID) (uintptr_t) memaddr, len);
}
else
{
DEBUG_MEM ("read target memory, %s bytes at %s",
pulongest (len), core_addr_to_string (memaddr));
- success = ReadProcessMemory (windows_process.handle,
+ success = ReadProcessMemory (windows_process->handle,
(LPCVOID) (uintptr_t) memaddr, readbuf,
len, &done);
if (!success)
@@ -2894,14 +2676,14 @@ windows_xfer_memory (gdb_byte *readbuf, const gdb_byte *writebuf,
void
windows_nat_target::kill ()
{
- CHECK (TerminateProcess (windows_process.handle, 0));
+ CHECK (TerminateProcess (windows_process->handle, 0));
for (;;)
{
if (!windows_continue (DBG_CONTINUE, -1, 1))
break;
- wait_for_debug_event_main_thread (&windows_process.current_event);
- if (windows_process.current_event.dwDebugEventCode
+ wait_for_debug_event_main_thread (&windows_process->current_event);
+ if (windows_process->current_event.dwDebugEventCode
== EXIT_PROCESS_DEBUG_EVENT)
break;
}
@@ -2937,7 +2719,7 @@ windows_xfer_shared_libraries (struct target_ops *ops,
return TARGET_XFER_E_IO;
std::string xml = "<library-list>\n";
- for (windows_solib &so : windows_process.solibs)
+ for (windows_solib &so : windows_process->solibs)
windows_xfer_shared_library (so.name.c_str (),
(CORE_ADDR) (uintptr_t) so.load_addr,
&so.text_offset,
@@ -2964,31 +2746,31 @@ static enum target_xfer_status
windows_xfer_siginfo (gdb_byte *readbuf, ULONGEST offset, ULONGEST len,
ULONGEST *xfered_len)
{
- char *buf = (char *) &windows_process.siginfo_er;
- size_t bufsize = sizeof (windows_process.siginfo_er);
+ char *buf = (char *) &windows_process->siginfo_er;
+ size_t bufsize = sizeof (windows_process->siginfo_er);
#ifdef __x86_64__
EXCEPTION_RECORD32 er32;
- if (windows_process.wow64_process)
+ if (windows_process->wow64_process)
{
buf = (char *) &er32;
bufsize = sizeof (er32);
- er32.ExceptionCode = windows_process.siginfo_er.ExceptionCode;
- er32.ExceptionFlags = windows_process.siginfo_er.ExceptionFlags;
+ er32.ExceptionCode = windows_process->siginfo_er.ExceptionCode;
+ er32.ExceptionFlags = windows_process->siginfo_er.ExceptionFlags;
er32.ExceptionRecord
- = (uintptr_t) windows_process.siginfo_er.ExceptionRecord;
+ = (uintptr_t) windows_process->siginfo_er.ExceptionRecord;
er32.ExceptionAddress
- = (uintptr_t) windows_process.siginfo_er.ExceptionAddress;
- er32.NumberParameters = windows_process.siginfo_er.NumberParameters;
+ = (uintptr_t) windows_process->siginfo_er.ExceptionAddress;
+ er32.NumberParameters = windows_process->siginfo_er.NumberParameters;
int i;
for (i = 0; i < EXCEPTION_MAXIMUM_PARAMETERS; i++)
er32.ExceptionInformation[i]
- = windows_process.siginfo_er.ExceptionInformation[i];
+ = windows_process->siginfo_er.ExceptionInformation[i];
}
#endif
- if (windows_process.siginfo_er.ExceptionCode == 0)
+ if (windows_process->siginfo_er.ExceptionCode == 0)
return TARGET_XFER_E_IO;
if (readbuf == nullptr)
@@ -3046,7 +2828,7 @@ windows_nat_target::get_tib_address (ptid_t ptid, CORE_ADDR *addr)
{
windows_thread_info *th;
- th = windows_process.thread_rec (ptid, DONT_INVALIDATE_CONTEXT);
+ th = windows_process->thread_rec (ptid, DONT_INVALIDATE_CONTEXT);
if (th == NULL)
return false;
@@ -3068,7 +2850,7 @@ const char *
windows_nat_target::thread_name (struct thread_info *thr)
{
windows_thread_info *th
- = windows_process.thread_rec (thr->ptid,
+ = windows_process->thread_rec (thr->ptid,
DONT_INVALIDATE_CONTEXT);
return th->thread_name ();
}
@@ -3088,7 +2870,7 @@ INIT_GDB_FILE (windows_nat)
/* The target is not a global specifically to avoid a C++ "static
initializer fiasco" situation. */
- add_inf_child_target (new windows_nat_target);
+ add_inf_child_target (new x86_nat_target<windows_nat_target>);
#ifdef __CYGWIN__
cygwin_internal (CW_SET_DOS_FILE_WARNING, 0);
@@ -3189,9 +2971,9 @@ cygwin_set_dr (int i, CORE_ADDR addr)
{
if (i < 0 || i > 3)
internal_error (_("Invalid register %d in cygwin_set_dr.\n"), i);
- windows_process.dr[i] = addr;
+ windows_process->dr[i] = addr;
- for (auto &th : windows_process.thread_list)
+ for (auto &th : windows_process->thread_list)
th->debug_registers_changed = true;
}
@@ -3201,9 +2983,9 @@ cygwin_set_dr (int i, CORE_ADDR addr)
static void
cygwin_set_dr7 (unsigned long val)
{
- windows_process.dr[7] = (CORE_ADDR) val;
+ windows_process->dr[7] = (CORE_ADDR) val;
- for (auto &th : windows_process.thread_list)
+ for (auto &th : windows_process->thread_list)
th->debug_registers_changed = true;
}
@@ -3212,7 +2994,7 @@ cygwin_set_dr7 (unsigned long val)
static CORE_ADDR
cygwin_get_dr (int i)
{
- return windows_process.dr[i];
+ return windows_process->dr[i];
}
/* Get the value of the DR6 debug status register from the inferior.
@@ -3221,7 +3003,7 @@ cygwin_get_dr (int i)
static unsigned long
cygwin_get_dr6 (void)
{
- return (unsigned long) windows_process.dr[6];
+ return (unsigned long) windows_process->dr[6];
}
/* Get the value of the DR7 debug status register from the inferior.
@@ -3231,7 +3013,7 @@ cygwin_get_dr6 (void)
static unsigned long
cygwin_get_dr7 (void)
{
- return (unsigned long) windows_process.dr[7];
+ return (unsigned long) windows_process->dr[7];
}
/* Determine if the thread referenced by "ptid" is alive
@@ -3244,7 +3026,7 @@ windows_nat_target::thread_alive (ptid_t ptid)
gdb_assert (ptid.lwp () != 0);
windows_thread_info *th
- = windows_process.thread_rec (ptid, DONT_INVALIDATE_CONTEXT);
+ = windows_process->thread_rec (ptid, DONT_INVALIDATE_CONTEXT);
return WaitForSingleObject (th->h, 0) != WAIT_OBJECT_0;
}
diff --git a/gdb/windows-nat.h b/gdb/windows-nat.h
index 81f08aea114..03c358fac54 100644
--- a/gdb/windows-nat.h
+++ b/gdb/windows-nat.h
@@ -18,10 +18,240 @@
#ifndef GDB_WINDOWS_NAT_H
#define GDB_WINDOWS_NAT_H
+#include <atomic>
+#include <queue>
+#include <vector>
+
+#include "inf-child.h"
+#include "nat/windows-nat.h"
+#include "ser-event.h"
+
+using windows_nat::windows_thread_info;
+using windows_nat::thread_disposition_type;
+
/* A pointer to a function that should return non-zero iff REGNUM
corresponds to one of the segment registers. */
typedef int (segment_register_p_ftype) (int regnum);
+/* Maintain a linked list of "so" information. */
+struct windows_solib
+{
+ LPVOID load_addr = 0;
+ CORE_ADDR text_offset = 0;
+
+ /* Original name. */
+ std::string original_name;
+ /* Expanded form of the name. */
+ std::string name;
+};
+
+struct windows_per_inferior : public windows_nat::windows_process_info
+{
+ windows_thread_info *thread_rec (ptid_t ptid,
+ thread_disposition_type disposition) override;
+ int handle_output_debug_string (struct target_waitstatus *ourstatus) override;
+ void handle_load_dll (const char *dll_name, LPVOID base) override;
+ void handle_unload_dll () override;
+ bool handle_access_violation (const EXCEPTION_RECORD *rec) override;
+
+ uintptr_t dr[8] {};
+
+ int windows_initialization_done = 0;
+
+ std::vector<std::unique_ptr<windows_thread_info>> thread_list;
+
+ /* Counts of things. */
+ int saw_create = 0;
+ int open_process_used = 0;
+#ifdef __x86_64__
+ void *wow64_dbgbreak = nullptr;
+#endif
+
+ /* This vector maps GDB's idea of a register's number into an offset
+ in the windows exception context vector.
+
+ It also contains the bit mask needed to load the register in question.
+
+ The contents of this table can only be computed by the units
+ that provide CPU-specific support for Windows native debugging.
+
+ One day we could read a reg, we could inspect the context we
+ already have loaded, if it doesn't have the bit set that we need,
+ we read that set of registers in using GetThreadContext. If the
+ context already contains what we need, we just unpack it. Then to
+ write a register, first we have to ensure that the context contains
+ the other regs of the group, and then we copy the info in and set
+ out bit. */
+
+ const int *mappings = nullptr;
+
+ /* The function to use in order to determine whether a register is
+ a segment register or not. */
+ segment_register_p_ftype *segment_register_p = nullptr;
+
+ std::vector<windows_solib> solibs;
+
+#ifdef __CYGWIN__
+ /* The starting and ending address of the cygwin1.dll text segment. */
+ CORE_ADDR cygwin_load_start = 0;
+ CORE_ADDR cygwin_load_end = 0;
+#endif /* __CYGWIN__ */
+};
+
+struct windows_nat_target : public inf_child_target
+{
+ windows_nat_target ();
+
+ void close () override;
+
+ void attach (const char *, int) override;
+
+ bool attach_no_wait () override
+ { return true; }
+
+ void detach (inferior *, int) override;
+
+ void resume (ptid_t, int , enum gdb_signal) override;
+
+ ptid_t wait (ptid_t, struct target_waitstatus *, target_wait_flags) override;
+
+ void fetch_registers (struct regcache *, int) override;
+ void store_registers (struct regcache *, int) override;
+
+ bool stopped_by_sw_breakpoint () override;
+
+ bool supports_stopped_by_sw_breakpoint () override
+ {
+ return true;
+ }
+
+ enum target_xfer_status xfer_partial (enum target_object object,
+ const char *annex,
+ gdb_byte *readbuf,
+ const gdb_byte *writebuf,
+ ULONGEST offset, ULONGEST len,
+ ULONGEST *xfered_len) override;
+
+ void files_info () override;
+
+ void kill () override;
+
+ void create_inferior (const char *, const std::string &,
+ char **, int) override;
+
+ void mourn_inferior () override;
+
+ bool thread_alive (ptid_t ptid) override;
+
+ std::string pid_to_str (ptid_t) override;
+
+ void interrupt () override;
+ void pass_ctrlc () override;
+
+ const char *pid_to_exec_file (int pid) override;
+
+ ptid_t get_ada_task_ptid (long lwp, ULONGEST thread) override;
+
+ bool get_tib_address (ptid_t ptid, CORE_ADDR *addr) override;
+
+ const char *thread_name (struct thread_info *) override;
+
+ ptid_t get_windows_debug_event (int pid, struct target_waitstatus *ourstatus,
+ target_wait_flags options);
+
+ void do_initial_windows_stuff (DWORD pid, bool attaching);
+
+ bool supports_disable_randomization () override
+ {
+ return windows_nat::disable_randomization_available ();
+ }
+
+ bool can_async_p () override
+ {
+ return true;
+ }
+
+ bool is_async_p () override
+ {
+ return m_is_async;
+ }
+
+ void async (bool enable) override;
+
+ int async_wait_fd () override
+ {
+ return serial_event_fd (m_wait_event);
+ }
+
+private:
+
+ windows_thread_info *add_thread (ptid_t ptid, HANDLE h, void *tlb,
+ bool main_thread_p);
+ void delete_thread (ptid_t ptid, DWORD exit_code, bool main_thread_p);
+ DWORD fake_create_process ();
+
+ BOOL windows_continue (DWORD continue_status, int id, int killed,
+ bool last_call = false);
+
+ /* Helper function to start process_thread. */
+ static DWORD WINAPI process_thread_starter (LPVOID self);
+
+ /* This function implements the background thread that starts
+ inferiors and waits for events. */
+ void process_thread ();
+
+ /* Push FUNC onto the queue of requests for process_thread, and wait
+ until it has been called. On Windows, certain debugging
+ functions can only be called by the thread that started (or
+ attached to) the inferior. These are all done in the worker
+ thread, via calls to this method. If FUNC returns true,
+ process_thread will wait for debug events when FUNC returns. */
+ void do_synchronously (gdb::function_view<bool ()> func);
+
+ /* This waits for a debug event, dispatching to the worker thread as
+ needed. */
+ void wait_for_debug_event_main_thread (DEBUG_EVENT *event);
+
+ /* Force the process_thread thread to return from WaitForDebugEvent.
+ PROCESS_ALIVE is set to false if the inferior process exits while
+ we're trying to break out the process_thread thread. This can
+ happen because this is called while all threads are running free,
+ while we're trying to detach. */
+ void break_out_process_thread (bool &process_alive);
+
+ /* Queue used to send requests to process_thread. This is
+ implicitly locked. */
+ std::queue<gdb::function_view<bool ()>> m_queue;
+
+ /* Event used to signal process_thread that an item has been
+ pushed. */
+ HANDLE m_pushed_event;
+ /* Event used by process_thread to indicate that it has processed a
+ single function call. */
+ HANDLE m_response_event;
+
+ /* Serial event used to communicate wait event availability to the
+ main loop. */
+ serial_event *m_wait_event;
+
+ /* The last debug event, when M_WAIT_EVENT has been set. */
+ DEBUG_EVENT m_last_debug_event {};
+ /* True if a debug event is pending. */
+ std::atomic<bool> m_debug_event_pending { false };
+
+ /* True if currently in async mode. */
+ bool m_is_async = false;
+
+ /* True if we last called ContinueDebugEvent and the process_thread
+ thread is now waiting for events. False if WaitForDebugEvent
+ already returned an event, and we need to ContinueDebugEvent
+ again to restart the inferior. */
+ bool m_continued = false;
+};
+
+/* The current process. */
+extern windows_per_inferior *windows_process;
+
/* segment_register_p_ftype implementation for x86. */
int i386_windows_segment_register_p (int regnum);
--
2.52.0
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH v2 04/11] Create x86-windows-nat.c
2026-01-17 13:36 ` [PATCH v2 01/11] Remove duplicate code from windows_nat_target::resume Hannes Domani
2026-01-17 13:36 ` [PATCH v2 02/11] Simplify windows_nat_target::resume Hannes Domani
2026-01-17 13:36 ` [PATCH v2 03/11] Move struct declarations into windows-nat.h Hannes Domani
@ 2026-01-17 13:36 ` Hannes Domani
2026-01-21 15:38 ` Tom Tromey
2026-01-17 13:36 ` [PATCH v2 05/11] Move x86 debug registers and related code into x86-windows-nat.c Hannes Domani
` (11 subsequent siblings)
14 siblings, 1 reply; 44+ messages in thread
From: Hannes Domani @ 2026-01-17 13:36 UTC (permalink / raw)
To: gdb-patches
Also creates the x86_windows_per_inferior and x86_windows_nat_target
derived classes in there which will then hold the arch-specific data and
function overrides.
---
Changes in v2:
- kept windows_process variable in windows-nat.c and initialized it
in INIT_GDB_FILE(x86_windows_nat)
---
gdb/Makefile.in | 1 +
gdb/configure.nat | 12 ++++++++----
gdb/windows-nat.c | 7 +------
gdb/x86-windows-nat.c | 42 ++++++++++++++++++++++++++++++++++++++++++
4 files changed, 52 insertions(+), 10 deletions(-)
create mode 100644 gdb/x86-windows-nat.c
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 161e8128e98..b564048f9fa 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1985,6 +1985,7 @@ ALLDEPFILES = \
x86-gnu-nat.c \
x86-nat.c \
x86-tdep.c \
+ x86-windows-nat.c \
xstormy16-tdep.c \
xtensa-config.c \
xtensa-linux-nat.c \
diff --git a/gdb/configure.nat b/gdb/configure.nat
index 1325d584bea..3ac0319328f 100644
--- a/gdb/configure.nat
+++ b/gdb/configure.nat
@@ -128,7 +128,8 @@ case ${gdb_host} in
i386)
# Native config information for GDB on i386
# systems running Cygwin.
- NATDEPFILES="${NATDEPFILES} i386-windows-nat.o"
+ NATDEPFILES="${NATDEPFILES} i386-windows-nat.o \
+ x86-windows-nat.o"
;;
esac
;;
@@ -137,7 +138,8 @@ case ${gdb_host} in
i386)
# Native config information for GDB on amd64
# systems running Cygwin.
- NATDEPFILES="${NATDEPFILES} i386-windows-nat.o amd64-windows-nat.o"
+ NATDEPFILES="${NATDEPFILES} i386-windows-nat.o \
+ amd64-windows-nat.o x86-windows-nat.o"
;;
esac
;;
@@ -361,14 +363,16 @@ case ${gdb_host} in
mingw)
case ${gdb_host_cpu} in
i386)
- NATDEPFILES="${NATDEPFILES} i386-windows-nat.o"
+ NATDEPFILES="${NATDEPFILES} i386-windows-nat.o \
+ x86-windows-nat.o"
;;
esac
;;
mingw64)
case ${gdb_host_cpu} in
i386)
- NATDEPFILES="${NATDEPFILES} i386-windows-nat.o amd64-windows-nat.o"
+ NATDEPFILES="${NATDEPFILES} i386-windows-nat.o \
+ amd64-windows-nat.o x86-windows-nat.o"
;;
esac
;;
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index 7fdd6cf81b5..68eebe1eaf9 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -73,8 +73,7 @@
using namespace windows_nat;
/* The current process. */
-static windows_per_inferior x86_windows_process;
-windows_per_inferior *windows_process = &x86_windows_process;
+windows_per_inferior *windows_process;
#undef STARTUPINFO
@@ -2868,10 +2867,6 @@ INIT_GDB_FILE (windows_nat)
calling x86_set_debug_register_length function
in processor windows specific native file. */
- /* The target is not a global specifically to avoid a C++ "static
- initializer fiasco" situation. */
- add_inf_child_target (new x86_nat_target<windows_nat_target>);
-
#ifdef __CYGWIN__
cygwin_internal (CW_SET_DOS_FILE_WARNING, 0);
#endif
diff --git a/gdb/x86-windows-nat.c b/gdb/x86-windows-nat.c
new file mode 100644
index 00000000000..d1f78a01255
--- /dev/null
+++ b/gdb/x86-windows-nat.c
@@ -0,0 +1,42 @@
+/* Native-dependent code for Windows x86 (i386 and x86-64).
+
+ Copyright (C) 2025-2026 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "windows-nat.h"
+
+#include "x86-nat.h"
+
+struct x86_windows_per_inferior : public windows_per_inferior
+{
+};
+
+struct x86_windows_nat_target final : public x86_nat_target<windows_nat_target>
+{
+};
+
+/* The current process. */
+static x86_windows_per_inferior x86_windows_process;
+
+INIT_GDB_FILE (x86_windows_nat)
+{
+ /* The target is not a global specifically to avoid a C++ "static
+ initializer fiasco" situation. */
+ add_inf_child_target (new x86_windows_nat_target);
+
+ windows_process = &x86_windows_process;
+}
--
2.52.0
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH v2 05/11] Move x86 debug registers and related code into x86-windows-nat.c
2026-01-17 13:36 ` [PATCH v2 01/11] Remove duplicate code from windows_nat_target::resume Hannes Domani
` (2 preceding siblings ...)
2026-01-17 13:36 ` [PATCH v2 04/11] Create x86-windows-nat.c Hannes Domani
@ 2026-01-17 13:36 ` Hannes Domani
2026-01-19 12:49 ` Schimpe, Christina
2026-01-23 13:17 ` [PATCH v3] " Hannes Domani
2026-01-17 13:36 ` [PATCH v2 06/11] Move x86 register " Hannes Domani
` (10 subsequent siblings)
14 siblings, 2 replies; 44+ messages in thread
From: Hannes Domani @ 2026-01-17 13:36 UTC (permalink / raw)
To: gdb-patches
---
Changes in v2:
- changed new windows_nat_target functions from public to protected
- better comments for these functions
---
gdb/windows-nat.c | 148 ++------------------------------
gdb/windows-nat.h | 19 ++++-
gdb/x86-windows-nat.c | 191 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 215 insertions(+), 143 deletions(-)
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index 68eebe1eaf9..e1da956b125 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -62,7 +62,6 @@
#include "windows-tdep.h"
#include "windows-nat.h"
-#include "x86-nat.h"
#include "complaints.h"
#include "gdbsupport/gdb_tilde_expand.h"
#include "gdbsupport/pathstuff.h"
@@ -85,18 +84,6 @@ windows_per_inferior *windows_process;
# define STARTUPINFO STARTUPINFOW
#endif
-/* If we're not using the old Cygwin header file set, define the
- following which never should have been in the generic Win32 API
- headers in the first place since they were our own invention... */
-#ifndef _GNU_H_WINDOWS_H
-enum
- {
- FLAG_TRACE_BIT = 0x100,
- };
-#endif
-
-#define DR6_CLEAR_VALUE 0xffff0ff0
-
/* The string sent by cygwin when it processes a signal.
FIXME: This should be in a cygwin include file. */
#ifndef _CYGWIN_SIGNAL_STRING
@@ -116,12 +103,6 @@ enum
debug_prefixed_printf_cond (debug_exceptions, "windows except", fmt, \
## __VA_ARGS__)
-static void cygwin_set_dr (int i, CORE_ADDR addr);
-static void cygwin_set_dr7 (unsigned long val);
-static CORE_ADDR cygwin_get_dr (int i);
-static unsigned long cygwin_get_dr6 (void);
-static unsigned long cygwin_get_dr7 (void);
-
/* User options. */
static bool new_console = false;
#ifdef __CYGWIN__
@@ -494,23 +475,7 @@ windows_nat_target::fetch_registers (struct regcache *regcache, int r)
if (th->reload_context)
{
- windows_process->with_context (th, [&] (auto *context)
- {
- context->ContextFlags = WindowsContext<decltype(context)>::all;
- CHECK (get_thread_context (th->h, context));
- /* Copy dr values from that thread.
- But only if there were not modified since last stop.
- PR gdb/2388 */
- if (!th->debug_registers_changed)
- {
- windows_process->dr[0] = context->Dr0;
- windows_process->dr[1] = context->Dr1;
- windows_process->dr[2] = context->Dr2;
- windows_process->dr[3] = context->Dr3;
- windows_process->dr[6] = context->Dr6;
- windows_process->dr[7] = context->Dr7;
- }
- });
+ fill_thread_context (th);
th->reload_context = false;
}
@@ -1009,35 +974,7 @@ windows_nat_target::windows_continue (DWORD continue_status, int id,
for (auto &th : windows_process->thread_list)
if (id == -1 || id == (int) th->tid)
{
- windows_process->with_context (th.get (), [&] (auto *context)
- {
- if (th->debug_registers_changed)
- {
- context->ContextFlags
- |= WindowsContext<decltype(context)>::debug;
- context->Dr0 = windows_process->dr[0];
- context->Dr1 = windows_process->dr[1];
- context->Dr2 = windows_process->dr[2];
- context->Dr3 = windows_process->dr[3];
- context->Dr6 = DR6_CLEAR_VALUE;
- context->Dr7 = windows_process->dr[7];
- th->debug_registers_changed = false;
- }
- if (context->ContextFlags)
- {
- DWORD ec = 0;
-
- if (GetExitCodeThread (th->h, &ec)
- && ec == STILL_ACTIVE)
- {
- BOOL status = set_thread_context (th->h, context);
-
- if (!killed)
- CHECK (status);
- }
- context->ContextFlags = 0;
- }
- });
+ thread_context_continue (th.get (), killed);
th->resume ();
}
@@ -1153,10 +1090,7 @@ windows_nat_target::resume (ptid_t ptid, int step, enum gdb_signal sig)
regcache *regcache = get_thread_regcache (inferior_thread ());
struct gdbarch *gdbarch = regcache->arch ();
fetch_registers (regcache, gdbarch_ps_regnum (gdbarch));
- windows_process->with_context (th, [&] (auto *context)
- {
- context->EFlags |= FLAG_TRACE_BIT;
- });
+ thread_context_step (th);
}
/* Allow continuing with the same signal that interrupted us.
@@ -1536,15 +1470,12 @@ windows_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
void
windows_nat_target::do_initial_windows_stuff (DWORD pid, bool attaching)
{
- int i;
struct inferior *inf;
+ initialize_windows_arch ();
+
windows_process->last_sig = GDB_SIGNAL_0;
windows_process->open_process_used = 0;
- for (i = 0;
- i < sizeof (windows_process->dr) / sizeof (windows_process->dr[0]);
- i++)
- windows_process->dr[i] = 0;
#ifdef __CYGWIN__
windows_process->cygwin_load_start = 0;
windows_process->cygwin_load_end = 0;
@@ -1890,7 +1821,7 @@ windows_nat_target::detach (inferior *inf, int from_tty)
target_announce_detach (from_tty);
- x86_cleanup_dregs ();
+ cleanup_windows_arch ();
switch_to_no_thread ();
detach_inferior (inf);
@@ -2622,7 +2553,7 @@ void
windows_nat_target::mourn_inferior ()
{
(void) windows_continue (DBG_CONTINUE, -1, 0, true);
- x86_cleanup_dregs();
+ cleanup_windows_arch ();
if (windows_process->open_process_used)
{
CHECK (CloseHandle (windows_process->handle));
@@ -2857,16 +2788,6 @@ windows_nat_target::thread_name (struct thread_info *thr)
INIT_GDB_FILE (windows_nat)
{
- x86_dr_low.set_control = cygwin_set_dr7;
- x86_dr_low.set_addr = cygwin_set_dr;
- x86_dr_low.get_addr = cygwin_get_dr;
- x86_dr_low.get_status = cygwin_get_dr6;
- x86_dr_low.get_control = cygwin_get_dr7;
-
- /* x86_dr_low.debug_register_length field is set by
- calling x86_set_debug_register_length function
- in processor windows specific native file. */
-
#ifdef __CYGWIN__
cygwin_internal (CW_SET_DOS_FILE_WARNING, 0);
#endif
@@ -2956,61 +2877,6 @@ Use \"%ps\" or \"%ps\" command to load executable/libraries directly."),
}
}
-/* Hardware watchpoint support, adapted from go32-nat.c code. */
-
-/* Pass the address ADDR to the inferior in the I'th debug register.
- Here we just store the address in dr array, the registers will be
- actually set up when windows_continue is called. */
-static void
-cygwin_set_dr (int i, CORE_ADDR addr)
-{
- if (i < 0 || i > 3)
- internal_error (_("Invalid register %d in cygwin_set_dr.\n"), i);
- windows_process->dr[i] = addr;
-
- for (auto &th : windows_process->thread_list)
- th->debug_registers_changed = true;
-}
-
-/* Pass the value VAL to the inferior in the DR7 debug control
- register. Here we just store the address in D_REGS, the watchpoint
- will be actually set up in windows_wait. */
-static void
-cygwin_set_dr7 (unsigned long val)
-{
- windows_process->dr[7] = (CORE_ADDR) val;
-
- for (auto &th : windows_process->thread_list)
- th->debug_registers_changed = true;
-}
-
-/* Get the value of debug register I from the inferior. */
-
-static CORE_ADDR
-cygwin_get_dr (int i)
-{
- return windows_process->dr[i];
-}
-
-/* Get the value of the DR6 debug status register from the inferior.
- Here we just return the value stored in dr[6]
- by the last call to thread_rec for current_event.dwThreadId id. */
-static unsigned long
-cygwin_get_dr6 (void)
-{
- return (unsigned long) windows_process->dr[6];
-}
-
-/* Get the value of the DR7 debug status register from the inferior.
- Here we just return the value stored in dr[7] by the last call to
- thread_rec for current_event.dwThreadId id. */
-
-static unsigned long
-cygwin_get_dr7 (void)
-{
- return (unsigned long) windows_process->dr[7];
-}
-
/* Determine if the thread referenced by "ptid" is alive
by "polling" it. If WaitForSingleObject returns WAIT_OBJECT_0
it means that the thread has died. Otherwise it is assumed to be alive. */
diff --git a/gdb/windows-nat.h b/gdb/windows-nat.h
index 03c358fac54..6553052f420 100644
--- a/gdb/windows-nat.h
+++ b/gdb/windows-nat.h
@@ -54,8 +54,6 @@ struct windows_per_inferior : public windows_nat::windows_process_info
void handle_unload_dll () override;
bool handle_access_violation (const EXCEPTION_RECORD *rec) override;
- uintptr_t dr[8] {};
-
int windows_initialization_done = 0;
std::vector<std::unique_ptr<windows_thread_info>> thread_list;
@@ -183,6 +181,23 @@ struct windows_nat_target : public inf_child_target
return serial_event_fd (m_wait_event);
}
+protected:
+
+ /* Initialize arch-specific data for a new inferior (debug registers,
+ register mappings). */
+ virtual void initialize_windows_arch () = 0;
+ /* Cleanup arch-specific data after inferior exit. */
+ virtual void cleanup_windows_arch () = 0;
+
+ /* Reload the thread context. */
+ virtual void fill_thread_context (windows_thread_info *th) = 0;
+
+ /* Prepare the thread context for continuing. */
+ virtual void thread_context_continue (windows_thread_info *th,
+ int killed) = 0;
+ /* Set the stepping bit in the thread context. */
+ virtual void thread_context_step (windows_thread_info *th) = 0;
+
private:
windows_thread_info *add_thread (ptid_t ptid, HANDLE h, void *tlb,
diff --git a/gdb/x86-windows-nat.c b/gdb/x86-windows-nat.c
index d1f78a01255..88844e0675a 100644
--- a/gdb/x86-windows-nat.c
+++ b/gdb/x86-windows-nat.c
@@ -18,22 +18,213 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "windows-nat.h"
+#include "regcache.h"
+#include "gdbarch.h"
#include "x86-nat.h"
+using namespace windows_nat;
+
+/* If we're not using the old Cygwin header file set, define the
+ following which never should have been in the generic Win32 API
+ headers in the first place since they were our own invention... */
+#ifndef _GNU_H_WINDOWS_H
+enum
+ {
+ FLAG_TRACE_BIT = 0x100,
+ };
+#endif
+
+#define DR6_CLEAR_VALUE 0xffff0ff0
+
+#define CHECK(x) check (x, __FILE__,__LINE__)
+
+static void
+check (BOOL ok, const char *file, int line)
+{
+ if (!ok)
+ {
+ unsigned err = (unsigned) GetLastError ();
+ gdb_printf ("error return %s:%d was %u: %s\n", file, line,
+ err, strwinerror (err));
+ }
+}
+
struct x86_windows_per_inferior : public windows_per_inferior
{
+ uintptr_t dr[8] {};
};
struct x86_windows_nat_target final : public x86_nat_target<windows_nat_target>
{
+ void initialize_windows_arch () override;
+ void cleanup_windows_arch () override;
+
+ void fill_thread_context (windows_thread_info *th) override;
+
+ void thread_context_continue (windows_thread_info *th, int killed) override;
+ void thread_context_step (windows_thread_info *th) override;
};
/* The current process. */
static x86_windows_per_inferior x86_windows_process;
+/* See windows-nat.h. */
+
+void
+x86_windows_nat_target::initialize_windows_arch ()
+{
+ memset (x86_windows_process.dr, 0, sizeof (x86_windows_process.dr));
+}
+
+/* See windows-nat.h. */
+
+void
+x86_windows_nat_target::cleanup_windows_arch ()
+{
+ x86_cleanup_dregs ();
+}
+
+/* See windows-nat.h. */
+
+void
+x86_windows_nat_target::fill_thread_context (windows_thread_info *th)
+{
+ x86_windows_process.with_context (th, [&] (auto *context)
+ {
+ context->ContextFlags = WindowsContext<decltype(context)>::all;
+ CHECK (get_thread_context (th->h, context));
+
+ /* Copy dr values from that thread.
+ But only if there were not modified since last stop.
+ PR gdb/2388 */
+ if (!th->debug_registers_changed)
+ {
+ x86_windows_process.dr[0] = context->Dr0;
+ x86_windows_process.dr[1] = context->Dr1;
+ x86_windows_process.dr[2] = context->Dr2;
+ x86_windows_process.dr[3] = context->Dr3;
+ x86_windows_process.dr[6] = context->Dr6;
+ x86_windows_process.dr[7] = context->Dr7;
+ }
+ });
+}
+
+/* See windows-nat.h. */
+
+void
+x86_windows_nat_target::thread_context_continue (windows_thread_info *th,
+ int killed)
+{
+ x86_windows_process.with_context (th, [&] (auto *context)
+ {
+ if (th->debug_registers_changed)
+ {
+ context->ContextFlags |= WindowsContext<decltype(context)>::debug;
+ context->Dr0 = x86_windows_process.dr[0];
+ context->Dr1 = x86_windows_process.dr[1];
+ context->Dr2 = x86_windows_process.dr[2];
+ context->Dr3 = x86_windows_process.dr[3];
+ context->Dr6 = DR6_CLEAR_VALUE;
+ context->Dr7 = x86_windows_process.dr[7];
+ th->debug_registers_changed = false;
+ }
+
+ if (context->ContextFlags)
+ {
+ DWORD ec = 0;
+
+ if (GetExitCodeThread (th->h, &ec)
+ && ec == STILL_ACTIVE)
+ {
+ BOOL status = set_thread_context (th->h, context);
+
+ if (!killed)
+ CHECK (status);
+ }
+ context->ContextFlags = 0;
+ }
+ });
+}
+
+/* See windows-nat.h. */
+
+void
+x86_windows_nat_target::thread_context_step (windows_thread_info *th)
+{
+ x86_windows_process.with_context (th, [&] (auto *context)
+ {
+ context->EFlags |= FLAG_TRACE_BIT;
+ });
+}
+
+/* Hardware watchpoint support, adapted from go32-nat.c code. */
+
+/* Pass the address ADDR to the inferior in the I'th debug register.
+ Here we just store the address in dr array, the registers will be
+ actually set up when windows_continue is called. */
+static void
+cygwin_set_dr (int i, CORE_ADDR addr)
+{
+ if (i < 0 || i > 3)
+ internal_error (_("Invalid register %d in cygwin_set_dr.\n"), i);
+ x86_windows_process.dr[i] = addr;
+
+ for (auto &th : x86_windows_process.thread_list)
+ th->debug_registers_changed = true;
+}
+
+/* Pass the value VAL to the inferior in the DR7 debug control
+ register. Here we just store the address in D_REGS, the watchpoint
+ will be actually set up in windows_wait. */
+static void
+cygwin_set_dr7 (unsigned long val)
+{
+ x86_windows_process.dr[7] = (CORE_ADDR) val;
+
+ for (auto &th : x86_windows_process.thread_list)
+ th->debug_registers_changed = true;
+}
+
+/* Get the value of debug register I from the inferior. */
+
+static CORE_ADDR
+cygwin_get_dr (int i)
+{
+ return x86_windows_process.dr[i];
+}
+
+/* Get the value of the DR6 debug status register from the inferior.
+ Here we just return the value stored in dr[6]
+ by the last call to thread_rec for current_event.dwThreadId id. */
+static unsigned long
+cygwin_get_dr6 (void)
+{
+ return (unsigned long) x86_windows_process.dr[6];
+}
+
+/* Get the value of the DR7 debug status register from the inferior.
+ Here we just return the value stored in dr[7] by the last call to
+ thread_rec for current_event.dwThreadId id. */
+
+static unsigned long
+cygwin_get_dr7 (void)
+{
+ return (unsigned long) x86_windows_process.dr[7];
+}
+
INIT_GDB_FILE (x86_windows_nat)
{
+ x86_dr_low.set_control = cygwin_set_dr7;
+ x86_dr_low.set_addr = cygwin_set_dr;
+ x86_dr_low.get_addr = cygwin_get_dr;
+ x86_dr_low.get_status = cygwin_get_dr6;
+ x86_dr_low.get_control = cygwin_get_dr7;
+
+ /* x86_dr_low.debug_register_length field is set by
+ calling x86_set_debug_register_length function
+ in processor windows specific native file. */
+
/* The target is not a global specifically to avoid a C++ "static
initializer fiasco" situation. */
add_inf_child_target (new x86_windows_nat_target);
--
2.52.0
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH v2 06/11] Move x86 register code into x86-windows-nat.c
2026-01-17 13:36 ` [PATCH v2 01/11] Remove duplicate code from windows_nat_target::resume Hannes Domani
` (3 preceding siblings ...)
2026-01-17 13:36 ` [PATCH v2 05/11] Move x86 debug registers and related code into x86-windows-nat.c Hannes Domani
@ 2026-01-17 13:36 ` Hannes Domani
2026-01-19 12:50 ` Schimpe, Christina
2026-01-17 13:36 ` [PATCH v2 07/11] Move x86 selector " Hannes Domani
` (9 subsequent siblings)
14 siblings, 1 reply; 44+ messages in thread
From: Hannes Domani @ 2026-01-17 13:36 UTC (permalink / raw)
To: gdb-patches
---
Changes in v2:
- updated comment for initialize_windows_arch() describing the ATTACHING
argument
---
gdb/windows-nat.c | 144 ++----------------------------------------
gdb/windows-nat.h | 29 +++++++--
gdb/x86-windows-nat.c | 137 +++++++++++++++++++++++++++++++++++++++-
3 files changed, 163 insertions(+), 147 deletions(-)
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index e1da956b125..926b85d479b 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -57,9 +57,6 @@
#include "xml-support.h"
#include "inttypes.h"
-#include "i386-tdep.h"
-#include "i387-tdep.h"
-
#include "windows-tdep.h"
#include "windows-nat.h"
#include "complaints.h"
@@ -389,79 +386,6 @@ windows_nat_target::delete_thread (ptid_t ptid, DWORD exit_code,
windows_process->thread_list.erase (iter);
}
-/* Fetches register number R from the given windows_thread_info,
- and supplies its value to the given regcache.
-
- This function assumes that R is non-negative. A failed assertion
- is raised if that is not true.
-
- This function assumes that TH->RELOAD_CONTEXT is not set, meaning
- that the windows_thread_info has an up-to-date context. A failed
- assertion is raised if that assumption is violated. */
-
-static void
-windows_fetch_one_register (struct regcache *regcache,
- windows_thread_info *th, int r)
-{
- gdb_assert (r >= 0);
- gdb_assert (!th->reload_context);
-
- char *context_ptr = windows_process->with_context (th, [] (auto *context)
- {
- return (char *) context;
- });
-
- char *context_offset = context_ptr + windows_process->mappings[r];
- struct gdbarch *gdbarch = regcache->arch ();
- i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
-
- gdb_assert (!gdbarch_read_pc_p (gdbarch));
- gdb_assert (gdbarch_pc_regnum (gdbarch) >= 0);
- gdb_assert (!gdbarch_write_pc_p (gdbarch));
-
- /* GDB treats some registers as 32-bit, where they are in fact only
- 16 bits long. These cases must be handled specially to avoid
- reading extraneous bits from the context. */
- if (r == I387_FISEG_REGNUM (tdep) || windows_process->segment_register_p (r))
- {
- gdb_byte bytes[4] = {};
- memcpy (bytes, context_offset, 2);
- regcache->raw_supply (r, bytes);
- }
- else if (r == I387_FOP_REGNUM (tdep))
- {
- long l = (*((long *) context_offset) >> 16) & ((1 << 11) - 1);
- regcache->raw_supply (r, &l);
- }
- else
- {
- if (th->stopped_at_software_breakpoint
- && !th->pc_adjusted
- && r == gdbarch_pc_regnum (gdbarch))
- {
- int size = register_size (gdbarch, r);
- if (size == 4)
- {
- uint32_t value;
- memcpy (&value, context_offset, size);
- value -= gdbarch_decr_pc_after_break (gdbarch);
- memcpy (context_offset, &value, size);
- }
- else
- {
- gdb_assert (size == 8);
- uint64_t value;
- memcpy (&value, context_offset, size);
- value -= gdbarch_decr_pc_after_break (gdbarch);
- memcpy (context_offset, &value, size);
- }
- /* Make sure we only rewrite the PC a single time. */
- th->pc_adjusted = true;
- }
- regcache->raw_supply (r, context_offset);
- }
-}
-
void
windows_nat_target::fetch_registers (struct regcache *regcache, int r)
{
@@ -482,51 +406,9 @@ windows_nat_target::fetch_registers (struct regcache *regcache, int r)
if (r < 0)
for (r = 0; r < gdbarch_num_regs (regcache->arch()); r++)
- windows_fetch_one_register (regcache, th, r);
- else
- windows_fetch_one_register (regcache, th, r);
-}
-
-/* Collect the register number R from the given regcache, and store
- its value into the corresponding area of the given thread's context.
-
- This function assumes that R is non-negative. A failed assertion
- assertion is raised if that is not true. */
-
-static void
-windows_store_one_register (const struct regcache *regcache,
- windows_thread_info *th, int r)
-{
- gdb_assert (r >= 0);
-
- char *context_ptr = windows_process->with_context (th, [] (auto *context)
- {
- return (char *) context;
- });
-
- struct gdbarch *gdbarch = regcache->arch ();
- i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
-
- /* GDB treats some registers as 32-bit, where they are in fact only
- 16 bits long. These cases must be handled specially to avoid
- overwriting other registers in the context. */
- if (r == I387_FISEG_REGNUM (tdep) || windows_process->segment_register_p (r))
- {
- gdb_byte bytes[4];
- regcache->raw_collect (r, bytes);
- memcpy (context_ptr + windows_process->mappings[r], bytes, 2);
- }
- else if (r == I387_FOP_REGNUM (tdep))
- {
- gdb_byte bytes[4];
- regcache->raw_collect (r, bytes);
- /* The value of FOP occupies the top two bytes in the context,
- so write the two low-order bytes from the cache into the
- appropriate spot. */
- memcpy (context_ptr + windows_process->mappings[r] + 2, bytes, 2);
- }
+ fetch_one_register (regcache, th, r);
else
- regcache->raw_collect (r, context_ptr + windows_process->mappings[r]);
+ fetch_one_register (regcache, th, r);
}
/* Store a new register value into the context of the thread tied to
@@ -545,9 +427,9 @@ windows_nat_target::store_registers (struct regcache *regcache, int r)
if (r < 0)
for (r = 0; r < gdbarch_num_regs (regcache->arch ()); r++)
- windows_store_one_register (regcache, th, r);
+ store_one_register (regcache, th, r);
else
- windows_store_one_register (regcache, th, r);
+ store_one_register (regcache, th, r);
}
bool
@@ -1472,7 +1354,7 @@ windows_nat_target::do_initial_windows_stuff (DWORD pid, bool attaching)
{
struct inferior *inf;
- initialize_windows_arch ();
+ initialize_windows_arch (attaching);
windows_process->last_sig = GDB_SIGNAL_0;
windows_process->open_process_used = 0;
@@ -1490,22 +1372,6 @@ windows_nat_target::do_initial_windows_stuff (DWORD pid, bool attaching)
clear_proceed_status (0);
init_wait_for_inferior ();
-#ifdef __x86_64__
- windows_process->ignore_first_breakpoint
- = !attaching && windows_process->wow64_process;
-
- if (!windows_process->wow64_process)
- {
- windows_process->mappings = amd64_mappings;
- windows_process->segment_register_p = amd64_windows_segment_register_p;
- }
- else
-#endif
- {
- windows_process->mappings = i386_mappings;
- windows_process->segment_register_p = i386_windows_segment_register_p;
- }
-
inferior_appeared (inf, pid);
inf->attach_flag = attaching;
diff --git a/gdb/windows-nat.h b/gdb/windows-nat.h
index 6553052f420..df872907535 100644
--- a/gdb/windows-nat.h
+++ b/gdb/windows-nat.h
@@ -83,10 +83,6 @@ struct windows_per_inferior : public windows_nat::windows_process_info
const int *mappings = nullptr;
- /* The function to use in order to determine whether a register is
- a segment register or not. */
- segment_register_p_ftype *segment_register_p = nullptr;
-
std::vector<windows_solib> solibs;
#ifdef __CYGWIN__
@@ -184,8 +180,9 @@ struct windows_nat_target : public inf_child_target
protected:
/* Initialize arch-specific data for a new inferior (debug registers,
- register mappings). */
- virtual void initialize_windows_arch () = 0;
+ register mappings). If ATTACHING is true, we're attaching to an
+ already-running process. */
+ virtual void initialize_windows_arch (bool attaching) = 0;
/* Cleanup arch-specific data after inferior exit. */
virtual void cleanup_windows_arch () = 0;
@@ -198,6 +195,26 @@ struct windows_nat_target : public inf_child_target
/* Set the stepping bit in the thread context. */
virtual void thread_context_step (windows_thread_info *th) = 0;
+ /* Fetches register number R from the given windows_thread_info,
+ and supplies its value to the given regcache.
+
+ This function assumes that R is non-negative. A failed assertion
+ is raised if that is not true.
+
+ This function assumes that TH->RELOAD_CONTEXT is not set, meaning
+ that the windows_thread_info has an up-to-date context. A failed
+ assertion is raised if that assumption is violated. */
+ virtual void fetch_one_register (struct regcache *regcache,
+ windows_thread_info *th, int r) = 0;
+
+ /* Collect the register number R from the given regcache, and store
+ its value into the corresponding area of the given thread's context.
+
+ This function assumes that R is non-negative. A failed assertion
+ assertion is raised if that is not true. */
+ virtual void store_one_register (const struct regcache *regcache,
+ windows_thread_info *th, int r) = 0;
+
private:
windows_thread_info *add_thread (ptid_t ptid, HANDLE h, void *tlb,
diff --git a/gdb/x86-windows-nat.c b/gdb/x86-windows-nat.c
index 88844e0675a..96dd61b39fb 100644
--- a/gdb/x86-windows-nat.c
+++ b/gdb/x86-windows-nat.c
@@ -23,6 +23,9 @@
#include "x86-nat.h"
+#include "i386-tdep.h"
+#include "i387-tdep.h"
+
using namespace windows_nat;
/* If we're not using the old Cygwin header file set, define the
@@ -53,17 +56,26 @@ check (BOOL ok, const char *file, int line)
struct x86_windows_per_inferior : public windows_per_inferior
{
uintptr_t dr[8] {};
+
+ /* The function to use in order to determine whether a register is
+ a segment register or not. */
+ segment_register_p_ftype *segment_register_p = nullptr;
};
struct x86_windows_nat_target final : public x86_nat_target<windows_nat_target>
{
- void initialize_windows_arch () override;
+ void initialize_windows_arch (bool attaching) override;
void cleanup_windows_arch () override;
void fill_thread_context (windows_thread_info *th) override;
void thread_context_continue (windows_thread_info *th, int killed) override;
void thread_context_step (windows_thread_info *th) override;
+
+ void fetch_one_register (struct regcache *regcache,
+ windows_thread_info *th, int r) override;
+ void store_one_register (const struct regcache *regcache,
+ windows_thread_info *th, int r) override;
};
/* The current process. */
@@ -72,9 +84,25 @@ static x86_windows_per_inferior x86_windows_process;
/* See windows-nat.h. */
void
-x86_windows_nat_target::initialize_windows_arch ()
+x86_windows_nat_target::initialize_windows_arch (bool attaching)
{
memset (x86_windows_process.dr, 0, sizeof (x86_windows_process.dr));
+
+#ifdef __x86_64__
+ x86_windows_process.ignore_first_breakpoint
+ = !attaching && x86_windows_process.wow64_process;
+
+ if (!x86_windows_process.wow64_process)
+ {
+ x86_windows_process.mappings = amd64_mappings;
+ x86_windows_process.segment_register_p = amd64_windows_segment_register_p;
+ }
+ else
+#endif
+ {
+ x86_windows_process.mappings = i386_mappings;
+ x86_windows_process.segment_register_p = i386_windows_segment_register_p;
+ }
}
/* See windows-nat.h. */
@@ -158,6 +186,111 @@ x86_windows_nat_target::thread_context_step (windows_thread_info *th)
});
}
+/* See windows-nat.h. */
+
+void
+x86_windows_nat_target::fetch_one_register (struct regcache *regcache,
+ windows_thread_info *th, int r)
+{
+ gdb_assert (r >= 0);
+ gdb_assert (!th->reload_context);
+
+ char *context_ptr = x86_windows_process.with_context (th, [] (auto *context)
+ {
+ return (char *) context;
+ });
+
+ char *context_offset = context_ptr + x86_windows_process.mappings[r];
+ struct gdbarch *gdbarch = regcache->arch ();
+ i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
+
+ gdb_assert (!gdbarch_read_pc_p (gdbarch));
+ gdb_assert (gdbarch_pc_regnum (gdbarch) >= 0);
+ gdb_assert (!gdbarch_write_pc_p (gdbarch));
+
+ /* GDB treats some registers as 32-bit, where they are in fact only
+ 16 bits long. These cases must be handled specially to avoid
+ reading extraneous bits from the context. */
+ if (r == I387_FISEG_REGNUM (tdep)
+ || x86_windows_process.segment_register_p (r))
+ {
+ gdb_byte bytes[4] = {};
+ memcpy (bytes, context_offset, 2);
+ regcache->raw_supply (r, bytes);
+ }
+ else if (r == I387_FOP_REGNUM (tdep))
+ {
+ long l = (*((long *) context_offset) >> 16) & ((1 << 11) - 1);
+ regcache->raw_supply (r, &l);
+ }
+ else
+ {
+ if (th->stopped_at_software_breakpoint
+ && !th->pc_adjusted
+ && r == gdbarch_pc_regnum (gdbarch))
+ {
+ int size = register_size (gdbarch, r);
+ if (size == 4)
+ {
+ uint32_t value;
+ memcpy (&value, context_offset, size);
+ value -= gdbarch_decr_pc_after_break (gdbarch);
+ memcpy (context_offset, &value, size);
+ }
+ else
+ {
+ gdb_assert (size == 8);
+ uint64_t value;
+ memcpy (&value, context_offset, size);
+ value -= gdbarch_decr_pc_after_break (gdbarch);
+ memcpy (context_offset, &value, size);
+ }
+ /* Make sure we only rewrite the PC a single time. */
+ th->pc_adjusted = true;
+ }
+ regcache->raw_supply (r, context_offset);
+ }
+}
+
+/* See windows-nat.h. */
+
+void
+x86_windows_nat_target::store_one_register (const struct regcache *regcache,
+ windows_thread_info *th, int r)
+{
+ gdb_assert (r >= 0);
+
+ char *context_ptr = x86_windows_process.with_context (th, [] (auto *context)
+ {
+ return (char *) context;
+ });
+
+ struct gdbarch *gdbarch = regcache->arch ();
+ i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
+
+ /* GDB treats some registers as 32-bit, where they are in fact only
+ 16 bits long. These cases must be handled specially to avoid
+ overwriting other registers in the context. */
+ if (r == I387_FISEG_REGNUM (tdep)
+ || x86_windows_process.segment_register_p (r))
+ {
+ gdb_byte bytes[4];
+ regcache->raw_collect (r, bytes);
+ memcpy (context_ptr + x86_windows_process.mappings[r], bytes, 2);
+ }
+ else if (r == I387_FOP_REGNUM (tdep))
+ {
+ gdb_byte bytes[4];
+ regcache->raw_collect (r, bytes);
+ /* The value of FOP occupies the top two bytes in the context,
+ so write the two low-order bytes from the cache into the
+ appropriate spot. */
+ memcpy (context_ptr + x86_windows_process.mappings[r] + 2, bytes, 2);
+ }
+ else
+ regcache->raw_collect (r, context_ptr + x86_windows_process.mappings[r]);
+}
+
/* Hardware watchpoint support, adapted from go32-nat.c code. */
/* Pass the address ADDR to the inferior in the I'th debug register.
--
2.52.0
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH v2 07/11] Move x86 selector code into x86-windows-nat.c
2026-01-17 13:36 ` [PATCH v2 01/11] Remove duplicate code from windows_nat_target::resume Hannes Domani
` (4 preceding siblings ...)
2026-01-17 13:36 ` [PATCH v2 06/11] Move x86 register " Hannes Domani
@ 2026-01-17 13:36 ` Hannes Domani
2026-01-19 13:56 ` Schimpe, Christina
2026-01-17 13:36 ` [PATCH v2 08/11] Move software breakpoint recognition " Hannes Domani
` (8 subsequent siblings)
14 siblings, 1 reply; 44+ messages in thread
From: Hannes Domani @ 2026-01-17 13:36 UTC (permalink / raw)
To: gdb-patches; +Cc: Tom Tromey
Approved-By: Tom Tromey <tom@tromey.com>
---
No changes in v2
---
gdb/windows-nat.c | 125 -----------------------------------------
gdb/x86-windows-nat.c | 127 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 127 insertions(+), 125 deletions(-)
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index 926b85d479b..f9d07336cca 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -685,127 +685,6 @@ windows_per_inferior::handle_output_debug_string
return retval;
}
-static int
-display_selector (HANDLE thread, DWORD sel)
-{
- LDT_ENTRY info;
- BOOL ret = windows_process->with_context (nullptr, [&] (auto *context)
- {
- return get_thread_selector_entry (context, thread, sel, &info);
- });
- if (ret)
- {
- int base, limit;
- gdb_printf ("0x%03x: ", (unsigned) sel);
- if (!info.HighWord.Bits.Pres)
- {
- gdb_puts ("Segment not present\n");
- return 0;
- }
- base = (info.HighWord.Bits.BaseHi << 24) +
- (info.HighWord.Bits.BaseMid << 16)
- + info.BaseLow;
- limit = (info.HighWord.Bits.LimitHi << 16) + info.LimitLow;
- if (info.HighWord.Bits.Granularity)
- limit = (limit << 12) | 0xfff;
- gdb_printf ("base=0x%08x limit=0x%08x", base, limit);
- if (info.HighWord.Bits.Default_Big)
- gdb_puts(" 32-bit ");
- else
- gdb_puts(" 16-bit ");
- switch ((info.HighWord.Bits.Type & 0xf) >> 1)
- {
- case 0:
- gdb_puts ("Data (Read-Only, Exp-up");
- break;
- case 1:
- gdb_puts ("Data (Read/Write, Exp-up");
- break;
- case 2:
- gdb_puts ("Unused segment (");
- break;
- case 3:
- gdb_puts ("Data (Read/Write, Exp-down");
- break;
- case 4:
- gdb_puts ("Code (Exec-Only, N.Conf");
- break;
- case 5:
- gdb_puts ("Code (Exec/Read, N.Conf");
- break;
- case 6:
- gdb_puts ("Code (Exec-Only, Conf");
- break;
- case 7:
- gdb_puts ("Code (Exec/Read, Conf");
- break;
- default:
- gdb_printf ("Unknown type 0x%lx",
- (unsigned long) info.HighWord.Bits.Type);
- }
- if ((info.HighWord.Bits.Type & 0x1) == 0)
- gdb_puts(", N.Acc");
- gdb_puts (")\n");
- if ((info.HighWord.Bits.Type & 0x10) == 0)
- gdb_puts("System selector ");
- gdb_printf ("Privilege level = %ld. ",
- (unsigned long) info.HighWord.Bits.Dpl);
- if (info.HighWord.Bits.Granularity)
- gdb_puts ("Page granular.\n");
- else
- gdb_puts ("Byte granular.\n");
- return 1;
- }
- else
- {
- DWORD err = GetLastError ();
- if (err == ERROR_NOT_SUPPORTED)
- gdb_printf ("Function not supported\n");
- else
- gdb_printf ("Invalid selector 0x%x.\n", (unsigned) sel);
- return 0;
- }
-}
-
-static void
-display_selectors (const char * args, int from_tty)
-{
- if (inferior_ptid == null_ptid)
- {
- gdb_puts ("Impossible to display selectors now.\n");
- return;
- }
-
- windows_thread_info *current_windows_thread
- = windows_process->thread_rec (inferior_ptid, DONT_INVALIDATE_CONTEXT);
-
- if (!args)
- {
- windows_process->with_context (current_windows_thread, [&] (auto *context)
- {
- gdb_puts ("Selector $cs\n");
- display_selector (current_windows_thread->h, context->SegCs);
- gdb_puts ("Selector $ds\n");
- display_selector (current_windows_thread->h, context->SegDs);
- gdb_puts ("Selector $es\n");
- display_selector (current_windows_thread->h, context->SegEs);
- gdb_puts ("Selector $ss\n");
- display_selector (current_windows_thread->h, context->SegSs);
- gdb_puts ("Selector $fs\n");
- display_selector (current_windows_thread->h, context->SegFs);
- gdb_puts ("Selector $gs\n");
- display_selector (current_windows_thread->h, context->SegGs);
- });
- }
- else
- {
- int sel;
- sel = parse_and_eval_long (args);
- gdb_printf ("Selector \"%s\"\n",args);
- display_selector (current_windows_thread->h, sel);
- }
-}
-
/* See nat/windows-nat.h. */
bool
@@ -2727,10 +2606,6 @@ Show whether to display kernel exceptions in child process."), NULL,
init_w32_command_list ();
- add_cmd ("selector", class_info, display_selectors,
- _("Display selectors infos."),
- &info_w32_cmdlist);
-
if (!initialize_loadable ())
{
/* This will probably fail on Windows 9x/Me. Let the user know
diff --git a/gdb/x86-windows-nat.c b/gdb/x86-windows-nat.c
index 96dd61b39fb..7538c360bfe 100644
--- a/gdb/x86-windows-nat.c
+++ b/gdb/x86-windows-nat.c
@@ -17,9 +17,11 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
+#include "windows-tdep.h"
#include "windows-nat.h"
#include "regcache.h"
#include "gdbarch.h"
+#include "inferior.h"
#include "x86-nat.h"
@@ -346,6 +348,127 @@ cygwin_get_dr7 (void)
return (unsigned long) x86_windows_process.dr[7];
}
+static int
+display_selector (HANDLE thread, DWORD sel)
+{
+ LDT_ENTRY info;
+ BOOL ret = windows_process->with_context (nullptr, [&] (auto *context)
+ {
+ return get_thread_selector_entry (context, thread, sel, &info);
+ });
+ if (ret)
+ {
+ int base, limit;
+ gdb_printf ("0x%03x: ", (unsigned) sel);
+ if (!info.HighWord.Bits.Pres)
+ {
+ gdb_puts ("Segment not present\n");
+ return 0;
+ }
+ base = (info.HighWord.Bits.BaseHi << 24) +
+ (info.HighWord.Bits.BaseMid << 16)
+ + info.BaseLow;
+ limit = (info.HighWord.Bits.LimitHi << 16) + info.LimitLow;
+ if (info.HighWord.Bits.Granularity)
+ limit = (limit << 12) | 0xfff;
+ gdb_printf ("base=0x%08x limit=0x%08x", base, limit);
+ if (info.HighWord.Bits.Default_Big)
+ gdb_puts(" 32-bit ");
+ else
+ gdb_puts(" 16-bit ");
+ switch ((info.HighWord.Bits.Type & 0xf) >> 1)
+ {
+ case 0:
+ gdb_puts ("Data (Read-Only, Exp-up");
+ break;
+ case 1:
+ gdb_puts ("Data (Read/Write, Exp-up");
+ break;
+ case 2:
+ gdb_puts ("Unused segment (");
+ break;
+ case 3:
+ gdb_puts ("Data (Read/Write, Exp-down");
+ break;
+ case 4:
+ gdb_puts ("Code (Exec-Only, N.Conf");
+ break;
+ case 5:
+ gdb_puts ("Code (Exec/Read, N.Conf");
+ break;
+ case 6:
+ gdb_puts ("Code (Exec-Only, Conf");
+ break;
+ case 7:
+ gdb_puts ("Code (Exec/Read, Conf");
+ break;
+ default:
+ gdb_printf ("Unknown type 0x%lx",
+ (unsigned long) info.HighWord.Bits.Type);
+ }
+ if ((info.HighWord.Bits.Type & 0x1) == 0)
+ gdb_puts(", N.Acc");
+ gdb_puts (")\n");
+ if ((info.HighWord.Bits.Type & 0x10) == 0)
+ gdb_puts("System selector ");
+ gdb_printf ("Privilege level = %ld. ",
+ (unsigned long) info.HighWord.Bits.Dpl);
+ if (info.HighWord.Bits.Granularity)
+ gdb_puts ("Page granular.\n");
+ else
+ gdb_puts ("Byte granular.\n");
+ return 1;
+ }
+ else
+ {
+ DWORD err = GetLastError ();
+ if (err == ERROR_NOT_SUPPORTED)
+ gdb_printf ("Function not supported\n");
+ else
+ gdb_printf ("Invalid selector 0x%x.\n", (unsigned) sel);
+ return 0;
+ }
+}
+
+static void
+display_selectors (const char * args, int from_tty)
+{
+ if (inferior_ptid == null_ptid)
+ {
+ gdb_puts ("Impossible to display selectors now.\n");
+ return;
+ }
+
+ windows_thread_info *current_windows_thread
+ = windows_process->thread_rec (inferior_ptid, DONT_INVALIDATE_CONTEXT);
+
+ if (!args)
+ {
+ windows_process->with_context (current_windows_thread, [&] (auto *context)
+ {
+ gdb_puts ("Selector $cs\n");
+ display_selector (current_windows_thread->h, context->SegCs);
+ gdb_puts ("Selector $ds\n");
+ display_selector (current_windows_thread->h, context->SegDs);
+ gdb_puts ("Selector $es\n");
+ display_selector (current_windows_thread->h, context->SegEs);
+ gdb_puts ("Selector $ss\n");
+ display_selector (current_windows_thread->h, context->SegSs);
+ gdb_puts ("Selector $fs\n");
+ display_selector (current_windows_thread->h, context->SegFs);
+ gdb_puts ("Selector $gs\n");
+ display_selector (current_windows_thread->h, context->SegGs);
+ });
+ }
+ else
+ {
+ int sel;
+ sel = parse_and_eval_long (args);
+ gdb_printf ("Selector \"%s\"\n",args);
+ display_selector (current_windows_thread->h, sel);
+ }
+}
+
INIT_GDB_FILE (x86_windows_nat)
{
x86_dr_low.set_control = cygwin_set_dr7;
@@ -363,4 +486,8 @@ INIT_GDB_FILE (x86_windows_nat)
add_inf_child_target (new x86_windows_nat_target);
windows_process = &x86_windows_process;
+
+ add_cmd ("selector", class_info, display_selectors,
+ _("Display selectors infos."),
+ &info_w32_cmdlist);
}
--
2.52.0
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH v2 08/11] Move software breakpoint recognition code into x86-windows-nat.c
2026-01-17 13:36 ` [PATCH v2 01/11] Remove duplicate code from windows_nat_target::resume Hannes Domani
` (5 preceding siblings ...)
2026-01-17 13:36 ` [PATCH v2 07/11] Move x86 selector " Hannes Domani
@ 2026-01-17 13:36 ` Hannes Domani
2026-01-19 12:51 ` Schimpe, Christina
2026-01-17 13:36 ` [PATCH v2 09/11] Move auto_wide_charset gdbarch method to windows-tdep Hannes Domani
` (7 subsequent siblings)
14 siblings, 1 reply; 44+ messages in thread
From: Hannes Domani @ 2026-01-17 13:36 UTC (permalink / raw)
To: gdb-patches; +Cc: Tom Tromey
Approved-By: Tom Tromey <tom@tromey.com>
---
Changes in v2:
- changed EXCEPTION_RECORD to ER in comment
---
gdb/windows-nat.c | 11 +++--------
gdb/windows-nat.h | 3 +++
gdb/x86-windows-nat.c | 11 +++++++++++
3 files changed, 17 insertions(+), 8 deletions(-)
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index f9d07336cca..3ed34087bf9 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -1147,10 +1147,7 @@ windows_nat_target::get_windows_debug_event
thread_id, windows_process->desired_stop_thread_id);
if (current_event->dwDebugEventCode == EXCEPTION_DEBUG_EVENT
- && ((current_event->u.Exception.ExceptionRecord.ExceptionCode
- == EXCEPTION_BREAKPOINT)
- || (current_event->u.Exception.ExceptionRecord.ExceptionCode
- == STATUS_WX86_BREAKPOINT))
+ && is_sw_breakpoint (¤t_event->u.Exception.ExceptionRecord)
&& windows_process->windows_initialization_done)
{
ptid_t ptid = ptid_t (current_event->dwProcessId, thread_id, 0);
@@ -1201,10 +1198,8 @@ windows_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
th->stopped_at_software_breakpoint = false;
if (windows_process->current_event.dwDebugEventCode
== EXCEPTION_DEBUG_EVENT
- && ((windows_process->current_event.u.Exception.ExceptionRecord.ExceptionCode
- == EXCEPTION_BREAKPOINT)
- || (windows_process->current_event.u.Exception.ExceptionRecord.ExceptionCode
- == STATUS_WX86_BREAKPOINT))
+ && is_sw_breakpoint (&windows_process->current_event
+ .u.Exception.ExceptionRecord)
&& windows_process->windows_initialization_done)
{
th->stopped_at_software_breakpoint = true;
diff --git a/gdb/windows-nat.h b/gdb/windows-nat.h
index df872907535..9257211dfd2 100644
--- a/gdb/windows-nat.h
+++ b/gdb/windows-nat.h
@@ -215,6 +215,9 @@ struct windows_nat_target : public inf_child_target
virtual void store_one_register (const struct regcache *regcache,
windows_thread_info *th, int r) = 0;
+ /* Determine if ER contains a software-breakpoint. */
+ virtual bool is_sw_breakpoint (EXCEPTION_RECORD *er) = 0;
+
private:
windows_thread_info *add_thread (ptid_t ptid, HANDLE h, void *tlb,
diff --git a/gdb/x86-windows-nat.c b/gdb/x86-windows-nat.c
index 7538c360bfe..52795235c9b 100644
--- a/gdb/x86-windows-nat.c
+++ b/gdb/x86-windows-nat.c
@@ -78,6 +78,8 @@ struct x86_windows_nat_target final : public x86_nat_target<windows_nat_target>
windows_thread_info *th, int r) override;
void store_one_register (const struct regcache *regcache,
windows_thread_info *th, int r) override;
+
+ bool is_sw_breakpoint (EXCEPTION_RECORD *er) override;
};
/* The current process. */
@@ -293,6 +295,15 @@ x86_windows_nat_target::store_one_register (const struct regcache *regcache,
regcache->raw_collect (r, context_ptr + x86_windows_process.mappings[r]);
}
+/* See windows-nat.h. */
+
+bool
+x86_windows_nat_target::is_sw_breakpoint (EXCEPTION_RECORD *er)
+{
+ return (er->ExceptionCode == EXCEPTION_BREAKPOINT
+ || er->ExceptionCode == STATUS_WX86_BREAKPOINT);
+}
+
/* Hardware watchpoint support, adapted from go32-nat.c code. */
/* Pass the address ADDR to the inferior in the I'th debug register.
--
2.52.0
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH v2 09/11] Move auto_wide_charset gdbarch method to windows-tdep
2026-01-17 13:36 ` [PATCH v2 01/11] Remove duplicate code from windows_nat_target::resume Hannes Domani
` (6 preceding siblings ...)
2026-01-17 13:36 ` [PATCH v2 08/11] Move software breakpoint recognition " Hannes Domani
@ 2026-01-17 13:36 ` Hannes Domani
2026-01-17 13:36 ` [PATCH v2 10/11] Move setting size of long " Hannes Domani
` (6 subsequent siblings)
14 siblings, 0 replies; 44+ messages in thread
From: Hannes Domani @ 2026-01-17 13:36 UTC (permalink / raw)
To: gdb-patches
It's UTF-16 for all Windows ABIs.
---
This patch didn't exist in v1
---
gdb/amd64-windows-tdep.c | 10 ----------
gdb/i386-windows-tdep.c | 8 --------
gdb/windows-tdep.c | 9 +++++++++
3 files changed, 9 insertions(+), 18 deletions(-)
diff --git a/gdb/amd64-windows-tdep.c b/gdb/amd64-windows-tdep.c
index b46f74c6461..aeed266e713 100644
--- a/gdb/amd64-windows-tdep.c
+++ b/gdb/amd64-windows-tdep.c
@@ -1271,14 +1271,6 @@ amd64_windows_skip_trampoline_code (const frame_info_ptr &frame, CORE_ADDR pc)
return destination;
}
-/* Implement the "auto_wide_charset" gdbarch method. */
-
-static const char *
-amd64_windows_auto_wide_charset (void)
-{
- return "UTF-16";
-}
-
/* Common parts for gdbarch initialization for Windows and Cygwin on AMD64. */
static void
@@ -1320,8 +1312,6 @@ amd64_windows_init_abi_common (gdbarch_info info, struct gdbarch *gdbarch)
set_gdbarch_core_xfer_shared_libraries
(gdbarch, windows_core_xfer_shared_libraries);
set_gdbarch_core_pid_to_str (gdbarch, windows_core_pid_to_str);
-
- set_gdbarch_auto_wide_charset (gdbarch, amd64_windows_auto_wide_charset);
}
/* gdbarch initialization for Windows on AMD64. */
diff --git a/gdb/i386-windows-tdep.c b/gdb/i386-windows-tdep.c
index 2861d60fef2..daaa556d171 100644
--- a/gdb/i386-windows-tdep.c
+++ b/gdb/i386-windows-tdep.c
@@ -95,12 +95,6 @@ i386_windows_skip_trampoline_code (const frame_info_ptr &frame, CORE_ADDR pc)
return i386_pe_skip_trampoline_code (frame, pc, NULL);
}
-static const char *
-i386_windows_auto_wide_charset (void)
-{
- return "UTF-16";
-}
-
/* Implement the "push_dummy_call" gdbarch method. */
static CORE_ADDR
@@ -154,8 +148,6 @@ i386_windows_init_abi_common (struct gdbarch_info info, struct gdbarch *gdbarch)
set_gdbarch_core_xfer_shared_libraries
(gdbarch, windows_core_xfer_shared_libraries);
set_gdbarch_core_pid_to_str (gdbarch, windows_core_pid_to_str);
-
- set_gdbarch_auto_wide_charset (gdbarch, i386_windows_auto_wide_charset);
}
/* gdbarch initialization for Windows on i386. */
diff --git a/gdb/windows-tdep.c b/gdb/windows-tdep.c
index 6164bc34312..e69db28c2dc 100644
--- a/gdb/windows-tdep.c
+++ b/gdb/windows-tdep.c
@@ -930,6 +930,14 @@ windows_solib_ops::iterate_over_objfiles_in_search_order
}
}
+/* Implement the "auto_wide_charset" gdbarch method. */
+
+static const char *
+windows_auto_wide_charset (void)
+{
+ return "UTF-16";
+}
+
/* Common parts for gdbarch initialization for the Windows and Cygwin OS
ABIs. */
@@ -938,6 +946,7 @@ windows_init_abi_common (struct gdbarch_info info, struct gdbarch *gdbarch)
{
set_gdbarch_wchar_bit (gdbarch, 16);
set_gdbarch_wchar_signed (gdbarch, 0);
+ set_gdbarch_auto_wide_charset (gdbarch, windows_auto_wide_charset);
/* Canonical paths on this target look like
`c:\Program Files\Foo App\mydll.dll', for example. */
--
2.52.0
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH v2 10/11] Move setting size of long to windows-tdep
2026-01-17 13:36 ` [PATCH v2 01/11] Remove duplicate code from windows_nat_target::resume Hannes Domani
` (7 preceding siblings ...)
2026-01-17 13:36 ` [PATCH v2 09/11] Move auto_wide_charset gdbarch method to windows-tdep Hannes Domani
@ 2026-01-17 13:36 ` Hannes Domani
2026-01-21 15:47 ` Tom Tromey
2026-01-17 13:54 ` [PATCH v2 04/11] Create x86-windows-nat.c Hannes Domani
` (5 subsequent siblings)
14 siblings, 1 reply; 44+ messages in thread
From: Hannes Domani @ 2026-01-17 13:36 UTC (permalink / raw)
To: gdb-patches
It's 32bit for all (non-cygwin) Windows ABIs.
---
This patch didn't exist in v1
---
gdb/amd64-windows-tdep.c | 3 ---
gdb/windows-tdep.c | 3 +++
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/gdb/amd64-windows-tdep.c b/gdb/amd64-windows-tdep.c
index aeed266e713..a9ca7b2ac79 100644
--- a/gdb/amd64-windows-tdep.c
+++ b/gdb/amd64-windows-tdep.c
@@ -1321,9 +1321,6 @@ amd64_windows_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
amd64_windows_init_abi_common (info, gdbarch);
windows_init_abi (info, gdbarch);
-
- /* On Windows, "long"s are only 32bit. */
- set_gdbarch_long_bit (gdbarch, 32);
}
/* Sigwrapper unwinder instruction patterns for AMD64. */
diff --git a/gdb/windows-tdep.c b/gdb/windows-tdep.c
index e69db28c2dc..5d27e0c3dd2 100644
--- a/gdb/windows-tdep.c
+++ b/gdb/windows-tdep.c
@@ -963,6 +963,9 @@ windows_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
windows_init_abi_common (info, gdbarch);
set_gdbarch_gdb_signal_to_target (gdbarch, windows_gdb_signal_to_target);
+
+ /* On Windows, "long"s are only 32bit. */
+ set_gdbarch_long_bit (gdbarch, 32);
}
/* See windows-tdep.h. */
--
2.52.0
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH v2 04/11] Create x86-windows-nat.c
2026-01-17 13:36 ` [PATCH v2 01/11] Remove duplicate code from windows_nat_target::resume Hannes Domani
` (8 preceding siblings ...)
2026-01-17 13:36 ` [PATCH v2 10/11] Move setting size of long " Hannes Domani
@ 2026-01-17 13:54 ` Hannes Domani
2026-01-17 14:01 ` Hannes Domani
2026-01-17 13:54 ` [PATCH v2 05/11] Move x86 debug registers and related code into x86-windows-nat.c Hannes Domani
` (4 subsequent siblings)
14 siblings, 1 reply; 44+ messages in thread
From: Hannes Domani @ 2026-01-17 13:54 UTC (permalink / raw)
To: gdb-patches
Also creates the x86_windows_per_inferior and x86_windows_nat_target
derived classes in there which will then hold the arch-specific data and
function overrides.
---
gdb/Makefile.in | 1 +
gdb/configure.nat | 12 ++++++++----
gdb/windows-nat.c | 7 +------
gdb/x86-windows-nat.c | 42 ++++++++++++++++++++++++++++++++++++++++++
4 files changed, 52 insertions(+), 10 deletions(-)
create mode 100644 gdb/x86-windows-nat.c
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 161e8128e98..b564048f9fa 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1985,6 +1985,7 @@ ALLDEPFILES = \
x86-gnu-nat.c \
x86-nat.c \
x86-tdep.c \
+ x86-windows-nat.c \
xstormy16-tdep.c \
xtensa-config.c \
xtensa-linux-nat.c \
diff --git a/gdb/configure.nat b/gdb/configure.nat
index 1325d584bea..3ac0319328f 100644
--- a/gdb/configure.nat
+++ b/gdb/configure.nat
@@ -128,7 +128,8 @@ case ${gdb_host} in
i386)
# Native config information for GDB on i386
# systems running Cygwin.
- NATDEPFILES="${NATDEPFILES} i386-windows-nat.o"
+ NATDEPFILES="${NATDEPFILES} i386-windows-nat.o \
+ x86-windows-nat.o"
;;
esac
;;
@@ -137,7 +138,8 @@ case ${gdb_host} in
i386)
# Native config information for GDB on amd64
# systems running Cygwin.
- NATDEPFILES="${NATDEPFILES} i386-windows-nat.o amd64-windows-nat.o"
+ NATDEPFILES="${NATDEPFILES} i386-windows-nat.o \
+ amd64-windows-nat.o x86-windows-nat.o"
;;
esac
;;
@@ -361,14 +363,16 @@ case ${gdb_host} in
mingw)
case ${gdb_host_cpu} in
i386)
- NATDEPFILES="${NATDEPFILES} i386-windows-nat.o"
+ NATDEPFILES="${NATDEPFILES} i386-windows-nat.o \
+ x86-windows-nat.o"
;;
esac
;;
mingw64)
case ${gdb_host_cpu} in
i386)
- NATDEPFILES="${NATDEPFILES} i386-windows-nat.o amd64-windows-nat.o"
+ NATDEPFILES="${NATDEPFILES} i386-windows-nat.o \
+ amd64-windows-nat.o x86-windows-nat.o"
;;
esac
;;
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index 7fdd6cf81b5..68eebe1eaf9 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -73,8 +73,7 @@
using namespace windows_nat;
/* The current process. */
-static windows_per_inferior x86_windows_process;
-windows_per_inferior *windows_process = &x86_windows_process;
+windows_per_inferior *windows_process;
#undef STARTUPINFO
@@ -2868,10 +2867,6 @@ INIT_GDB_FILE (windows_nat)
calling x86_set_debug_register_length function
in processor windows specific native file. */
- /* The target is not a global specifically to avoid a C++ "static
- initializer fiasco" situation. */
- add_inf_child_target (new x86_nat_target<windows_nat_target>);
-
#ifdef __CYGWIN__
cygwin_internal (CW_SET_DOS_FILE_WARNING, 0);
#endif
diff --git a/gdb/x86-windows-nat.c b/gdb/x86-windows-nat.c
new file mode 100644
index 00000000000..d1f78a01255
--- /dev/null
+++ b/gdb/x86-windows-nat.c
@@ -0,0 +1,42 @@
+/* Native-dependent code for Windows x86 (i386 and x86-64).
+
+ Copyright (C) 2025-2026 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "windows-nat.h"
+
+#include "x86-nat.h"
+
+struct x86_windows_per_inferior : public windows_per_inferior
+{
+};
+
+struct x86_windows_nat_target final : public x86_nat_target<windows_nat_target>
+{
+};
+
+/* The current process. */
+static x86_windows_per_inferior x86_windows_process;
+
+INIT_GDB_FILE (x86_windows_nat)
+{
+ /* The target is not a global specifically to avoid a C++ "static
+ initializer fiasco" situation. */
+ add_inf_child_target (new x86_windows_nat_target);
+
+ windows_process = &x86_windows_process;
+}
--
2.52.0
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH v2 05/11] Move x86 debug registers and related code into x86-windows-nat.c
2026-01-17 13:36 ` [PATCH v2 01/11] Remove duplicate code from windows_nat_target::resume Hannes Domani
` (9 preceding siblings ...)
2026-01-17 13:54 ` [PATCH v2 04/11] Create x86-windows-nat.c Hannes Domani
@ 2026-01-17 13:54 ` Hannes Domani
2026-01-17 13:54 ` [PATCH v2 06/11] Move x86 register " Hannes Domani
` (3 subsequent siblings)
14 siblings, 0 replies; 44+ messages in thread
From: Hannes Domani @ 2026-01-17 13:54 UTC (permalink / raw)
To: gdb-patches
---
gdb/windows-nat.c | 148 ++------------------------------
gdb/windows-nat.h | 19 ++++-
gdb/x86-windows-nat.c | 191 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 215 insertions(+), 143 deletions(-)
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index 68eebe1eaf9..e1da956b125 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -62,7 +62,6 @@
#include "windows-tdep.h"
#include "windows-nat.h"
-#include "x86-nat.h"
#include "complaints.h"
#include "gdbsupport/gdb_tilde_expand.h"
#include "gdbsupport/pathstuff.h"
@@ -85,18 +84,6 @@ windows_per_inferior *windows_process;
# define STARTUPINFO STARTUPINFOW
#endif
-/* If we're not using the old Cygwin header file set, define the
- following which never should have been in the generic Win32 API
- headers in the first place since they were our own invention... */
-#ifndef _GNU_H_WINDOWS_H
-enum
- {
- FLAG_TRACE_BIT = 0x100,
- };
-#endif
-
-#define DR6_CLEAR_VALUE 0xffff0ff0
-
/* The string sent by cygwin when it processes a signal.
FIXME: This should be in a cygwin include file. */
#ifndef _CYGWIN_SIGNAL_STRING
@@ -116,12 +103,6 @@ enum
debug_prefixed_printf_cond (debug_exceptions, "windows except", fmt, \
## __VA_ARGS__)
-static void cygwin_set_dr (int i, CORE_ADDR addr);
-static void cygwin_set_dr7 (unsigned long val);
-static CORE_ADDR cygwin_get_dr (int i);
-static unsigned long cygwin_get_dr6 (void);
-static unsigned long cygwin_get_dr7 (void);
-
/* User options. */
static bool new_console = false;
#ifdef __CYGWIN__
@@ -494,23 +475,7 @@ windows_nat_target::fetch_registers (struct regcache *regcache, int r)
if (th->reload_context)
{
- windows_process->with_context (th, [&] (auto *context)
- {
- context->ContextFlags = WindowsContext<decltype(context)>::all;
- CHECK (get_thread_context (th->h, context));
- /* Copy dr values from that thread.
- But only if there were not modified since last stop.
- PR gdb/2388 */
- if (!th->debug_registers_changed)
- {
- windows_process->dr[0] = context->Dr0;
- windows_process->dr[1] = context->Dr1;
- windows_process->dr[2] = context->Dr2;
- windows_process->dr[3] = context->Dr3;
- windows_process->dr[6] = context->Dr6;
- windows_process->dr[7] = context->Dr7;
- }
- });
+ fill_thread_context (th);
th->reload_context = false;
}
@@ -1009,35 +974,7 @@ windows_nat_target::windows_continue (DWORD continue_status, int id,
for (auto &th : windows_process->thread_list)
if (id == -1 || id == (int) th->tid)
{
- windows_process->with_context (th.get (), [&] (auto *context)
- {
- if (th->debug_registers_changed)
- {
- context->ContextFlags
- |= WindowsContext<decltype(context)>::debug;
- context->Dr0 = windows_process->dr[0];
- context->Dr1 = windows_process->dr[1];
- context->Dr2 = windows_process->dr[2];
- context->Dr3 = windows_process->dr[3];
- context->Dr6 = DR6_CLEAR_VALUE;
- context->Dr7 = windows_process->dr[7];
- th->debug_registers_changed = false;
- }
- if (context->ContextFlags)
- {
- DWORD ec = 0;
-
- if (GetExitCodeThread (th->h, &ec)
- && ec == STILL_ACTIVE)
- {
- BOOL status = set_thread_context (th->h, context);
-
- if (!killed)
- CHECK (status);
- }
- context->ContextFlags = 0;
- }
- });
+ thread_context_continue (th.get (), killed);
th->resume ();
}
@@ -1153,10 +1090,7 @@ windows_nat_target::resume (ptid_t ptid, int step, enum gdb_signal sig)
regcache *regcache = get_thread_regcache (inferior_thread ());
struct gdbarch *gdbarch = regcache->arch ();
fetch_registers (regcache, gdbarch_ps_regnum (gdbarch));
- windows_process->with_context (th, [&] (auto *context)
- {
- context->EFlags |= FLAG_TRACE_BIT;
- });
+ thread_context_step (th);
}
/* Allow continuing with the same signal that interrupted us.
@@ -1536,15 +1470,12 @@ windows_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
void
windows_nat_target::do_initial_windows_stuff (DWORD pid, bool attaching)
{
- int i;
struct inferior *inf;
+ initialize_windows_arch ();
+
windows_process->last_sig = GDB_SIGNAL_0;
windows_process->open_process_used = 0;
- for (i = 0;
- i < sizeof (windows_process->dr) / sizeof (windows_process->dr[0]);
- i++)
- windows_process->dr[i] = 0;
#ifdef __CYGWIN__
windows_process->cygwin_load_start = 0;
windows_process->cygwin_load_end = 0;
@@ -1890,7 +1821,7 @@ windows_nat_target::detach (inferior *inf, int from_tty)
target_announce_detach (from_tty);
- x86_cleanup_dregs ();
+ cleanup_windows_arch ();
switch_to_no_thread ();
detach_inferior (inf);
@@ -2622,7 +2553,7 @@ void
windows_nat_target::mourn_inferior ()
{
(void) windows_continue (DBG_CONTINUE, -1, 0, true);
- x86_cleanup_dregs();
+ cleanup_windows_arch ();
if (windows_process->open_process_used)
{
CHECK (CloseHandle (windows_process->handle));
@@ -2857,16 +2788,6 @@ windows_nat_target::thread_name (struct thread_info *thr)
INIT_GDB_FILE (windows_nat)
{
- x86_dr_low.set_control = cygwin_set_dr7;
- x86_dr_low.set_addr = cygwin_set_dr;
- x86_dr_low.get_addr = cygwin_get_dr;
- x86_dr_low.get_status = cygwin_get_dr6;
- x86_dr_low.get_control = cygwin_get_dr7;
-
- /* x86_dr_low.debug_register_length field is set by
- calling x86_set_debug_register_length function
- in processor windows specific native file. */
-
#ifdef __CYGWIN__
cygwin_internal (CW_SET_DOS_FILE_WARNING, 0);
#endif
@@ -2956,61 +2877,6 @@ Use \"%ps\" or \"%ps\" command to load executable/libraries directly."),
}
}
-/* Hardware watchpoint support, adapted from go32-nat.c code. */
-
-/* Pass the address ADDR to the inferior in the I'th debug register.
- Here we just store the address in dr array, the registers will be
- actually set up when windows_continue is called. */
-static void
-cygwin_set_dr (int i, CORE_ADDR addr)
-{
- if (i < 0 || i > 3)
- internal_error (_("Invalid register %d in cygwin_set_dr.\n"), i);
- windows_process->dr[i] = addr;
-
- for (auto &th : windows_process->thread_list)
- th->debug_registers_changed = true;
-}
-
-/* Pass the value VAL to the inferior in the DR7 debug control
- register. Here we just store the address in D_REGS, the watchpoint
- will be actually set up in windows_wait. */
-static void
-cygwin_set_dr7 (unsigned long val)
-{
- windows_process->dr[7] = (CORE_ADDR) val;
-
- for (auto &th : windows_process->thread_list)
- th->debug_registers_changed = true;
-}
-
-/* Get the value of debug register I from the inferior. */
-
-static CORE_ADDR
-cygwin_get_dr (int i)
-{
- return windows_process->dr[i];
-}
-
-/* Get the value of the DR6 debug status register from the inferior.
- Here we just return the value stored in dr[6]
- by the last call to thread_rec for current_event.dwThreadId id. */
-static unsigned long
-cygwin_get_dr6 (void)
-{
- return (unsigned long) windows_process->dr[6];
-}
-
-/* Get the value of the DR7 debug status register from the inferior.
- Here we just return the value stored in dr[7] by the last call to
- thread_rec for current_event.dwThreadId id. */
-
-static unsigned long
-cygwin_get_dr7 (void)
-{
- return (unsigned long) windows_process->dr[7];
-}
-
/* Determine if the thread referenced by "ptid" is alive
by "polling" it. If WaitForSingleObject returns WAIT_OBJECT_0
it means that the thread has died. Otherwise it is assumed to be alive. */
diff --git a/gdb/windows-nat.h b/gdb/windows-nat.h
index 03c358fac54..6553052f420 100644
--- a/gdb/windows-nat.h
+++ b/gdb/windows-nat.h
@@ -54,8 +54,6 @@ struct windows_per_inferior : public windows_nat::windows_process_info
void handle_unload_dll () override;
bool handle_access_violation (const EXCEPTION_RECORD *rec) override;
- uintptr_t dr[8] {};
-
int windows_initialization_done = 0;
std::vector<std::unique_ptr<windows_thread_info>> thread_list;
@@ -183,6 +181,23 @@ struct windows_nat_target : public inf_child_target
return serial_event_fd (m_wait_event);
}
+protected:
+
+ /* Initialize arch-specific data for a new inferior (debug registers,
+ register mappings). */
+ virtual void initialize_windows_arch () = 0;
+ /* Cleanup arch-specific data after inferior exit. */
+ virtual void cleanup_windows_arch () = 0;
+
+ /* Reload the thread context. */
+ virtual void fill_thread_context (windows_thread_info *th) = 0;
+
+ /* Prepare the thread context for continuing. */
+ virtual void thread_context_continue (windows_thread_info *th,
+ int killed) = 0;
+ /* Set the stepping bit in the thread context. */
+ virtual void thread_context_step (windows_thread_info *th) = 0;
+
private:
windows_thread_info *add_thread (ptid_t ptid, HANDLE h, void *tlb,
diff --git a/gdb/x86-windows-nat.c b/gdb/x86-windows-nat.c
index d1f78a01255..88844e0675a 100644
--- a/gdb/x86-windows-nat.c
+++ b/gdb/x86-windows-nat.c
@@ -18,22 +18,213 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "windows-nat.h"
+#include "regcache.h"
+#include "gdbarch.h"
#include "x86-nat.h"
+using namespace windows_nat;
+
+/* If we're not using the old Cygwin header file set, define the
+ following which never should have been in the generic Win32 API
+ headers in the first place since they were our own invention... */
+#ifndef _GNU_H_WINDOWS_H
+enum
+ {
+ FLAG_TRACE_BIT = 0x100,
+ };
+#endif
+
+#define DR6_CLEAR_VALUE 0xffff0ff0
+
+#define CHECK(x) check (x, __FILE__,__LINE__)
+
+static void
+check (BOOL ok, const char *file, int line)
+{
+ if (!ok)
+ {
+ unsigned err = (unsigned) GetLastError ();
+ gdb_printf ("error return %s:%d was %u: %s\n", file, line,
+ err, strwinerror (err));
+ }
+}
+
struct x86_windows_per_inferior : public windows_per_inferior
{
+ uintptr_t dr[8] {};
};
struct x86_windows_nat_target final : public x86_nat_target<windows_nat_target>
{
+ void initialize_windows_arch () override;
+ void cleanup_windows_arch () override;
+
+ void fill_thread_context (windows_thread_info *th) override;
+
+ void thread_context_continue (windows_thread_info *th, int killed) override;
+ void thread_context_step (windows_thread_info *th) override;
};
/* The current process. */
static x86_windows_per_inferior x86_windows_process;
+/* See windows-nat.h. */
+
+void
+x86_windows_nat_target::initialize_windows_arch ()
+{
+ memset (x86_windows_process.dr, 0, sizeof (x86_windows_process.dr));
+}
+
+/* See windows-nat.h. */
+
+void
+x86_windows_nat_target::cleanup_windows_arch ()
+{
+ x86_cleanup_dregs ();
+}
+
+/* See windows-nat.h. */
+
+void
+x86_windows_nat_target::fill_thread_context (windows_thread_info *th)
+{
+ x86_windows_process.with_context (th, [&] (auto *context)
+ {
+ context->ContextFlags = WindowsContext<decltype(context)>::all;
+ CHECK (get_thread_context (th->h, context));
+
+ /* Copy dr values from that thread.
+ But only if there were not modified since last stop.
+ PR gdb/2388 */
+ if (!th->debug_registers_changed)
+ {
+ x86_windows_process.dr[0] = context->Dr0;
+ x86_windows_process.dr[1] = context->Dr1;
+ x86_windows_process.dr[2] = context->Dr2;
+ x86_windows_process.dr[3] = context->Dr3;
+ x86_windows_process.dr[6] = context->Dr6;
+ x86_windows_process.dr[7] = context->Dr7;
+ }
+ });
+}
+
+/* See windows-nat.h. */
+
+void
+x86_windows_nat_target::thread_context_continue (windows_thread_info *th,
+ int killed)
+{
+ x86_windows_process.with_context (th, [&] (auto *context)
+ {
+ if (th->debug_registers_changed)
+ {
+ context->ContextFlags |= WindowsContext<decltype(context)>::debug;
+ context->Dr0 = x86_windows_process.dr[0];
+ context->Dr1 = x86_windows_process.dr[1];
+ context->Dr2 = x86_windows_process.dr[2];
+ context->Dr3 = x86_windows_process.dr[3];
+ context->Dr6 = DR6_CLEAR_VALUE;
+ context->Dr7 = x86_windows_process.dr[7];
+ th->debug_registers_changed = false;
+ }
+
+ if (context->ContextFlags)
+ {
+ DWORD ec = 0;
+
+ if (GetExitCodeThread (th->h, &ec)
+ && ec == STILL_ACTIVE)
+ {
+ BOOL status = set_thread_context (th->h, context);
+
+ if (!killed)
+ CHECK (status);
+ }
+ context->ContextFlags = 0;
+ }
+ });
+}
+
+/* See windows-nat.h. */
+
+void
+x86_windows_nat_target::thread_context_step (windows_thread_info *th)
+{
+ x86_windows_process.with_context (th, [&] (auto *context)
+ {
+ context->EFlags |= FLAG_TRACE_BIT;
+ });
+}
+
+/* Hardware watchpoint support, adapted from go32-nat.c code. */
+
+/* Pass the address ADDR to the inferior in the I'th debug register.
+ Here we just store the address in dr array, the registers will be
+ actually set up when windows_continue is called. */
+static void
+cygwin_set_dr (int i, CORE_ADDR addr)
+{
+ if (i < 0 || i > 3)
+ internal_error (_("Invalid register %d in cygwin_set_dr.\n"), i);
+ x86_windows_process.dr[i] = addr;
+
+ for (auto &th : x86_windows_process.thread_list)
+ th->debug_registers_changed = true;
+}
+
+/* Pass the value VAL to the inferior in the DR7 debug control
+ register. Here we just store the address in D_REGS, the watchpoint
+ will be actually set up in windows_wait. */
+static void
+cygwin_set_dr7 (unsigned long val)
+{
+ x86_windows_process.dr[7] = (CORE_ADDR) val;
+
+ for (auto &th : x86_windows_process.thread_list)
+ th->debug_registers_changed = true;
+}
+
+/* Get the value of debug register I from the inferior. */
+
+static CORE_ADDR
+cygwin_get_dr (int i)
+{
+ return x86_windows_process.dr[i];
+}
+
+/* Get the value of the DR6 debug status register from the inferior.
+ Here we just return the value stored in dr[6]
+ by the last call to thread_rec for current_event.dwThreadId id. */
+static unsigned long
+cygwin_get_dr6 (void)
+{
+ return (unsigned long) x86_windows_process.dr[6];
+}
+
+/* Get the value of the DR7 debug status register from the inferior.
+ Here we just return the value stored in dr[7] by the last call to
+ thread_rec for current_event.dwThreadId id. */
+
+static unsigned long
+cygwin_get_dr7 (void)
+{
+ return (unsigned long) x86_windows_process.dr[7];
+}
+
INIT_GDB_FILE (x86_windows_nat)
{
+ x86_dr_low.set_control = cygwin_set_dr7;
+ x86_dr_low.set_addr = cygwin_set_dr;
+ x86_dr_low.get_addr = cygwin_get_dr;
+ x86_dr_low.get_status = cygwin_get_dr6;
+ x86_dr_low.get_control = cygwin_get_dr7;
+
+ /* x86_dr_low.debug_register_length field is set by
+ calling x86_set_debug_register_length function
+ in processor windows specific native file. */
+
/* The target is not a global specifically to avoid a C++ "static
initializer fiasco" situation. */
add_inf_child_target (new x86_windows_nat_target);
--
2.52.0
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH v2 06/11] Move x86 register code into x86-windows-nat.c
2026-01-17 13:36 ` [PATCH v2 01/11] Remove duplicate code from windows_nat_target::resume Hannes Domani
` (10 preceding siblings ...)
2026-01-17 13:54 ` [PATCH v2 05/11] Move x86 debug registers and related code into x86-windows-nat.c Hannes Domani
@ 2026-01-17 13:54 ` Hannes Domani
2026-01-21 16:08 ` Tom Tromey
2026-01-17 13:54 ` [PATCH v2 09/11] Move auto_wide_charset gdbarch method to windows-tdep Hannes Domani
` (2 subsequent siblings)
14 siblings, 1 reply; 44+ messages in thread
From: Hannes Domani @ 2026-01-17 13:54 UTC (permalink / raw)
To: gdb-patches
---
gdb/windows-nat.c | 144 ++----------------------------------------
gdb/windows-nat.h | 29 +++++++--
gdb/x86-windows-nat.c | 137 +++++++++++++++++++++++++++++++++++++++-
3 files changed, 163 insertions(+), 147 deletions(-)
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index e1da956b125..926b85d479b 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -57,9 +57,6 @@
#include "xml-support.h"
#include "inttypes.h"
-#include "i386-tdep.h"
-#include "i387-tdep.h"
-
#include "windows-tdep.h"
#include "windows-nat.h"
#include "complaints.h"
@@ -389,79 +386,6 @@ windows_nat_target::delete_thread (ptid_t ptid, DWORD exit_code,
windows_process->thread_list.erase (iter);
}
-/* Fetches register number R from the given windows_thread_info,
- and supplies its value to the given regcache.
-
- This function assumes that R is non-negative. A failed assertion
- is raised if that is not true.
-
- This function assumes that TH->RELOAD_CONTEXT is not set, meaning
- that the windows_thread_info has an up-to-date context. A failed
- assertion is raised if that assumption is violated. */
-
-static void
-windows_fetch_one_register (struct regcache *regcache,
- windows_thread_info *th, int r)
-{
- gdb_assert (r >= 0);
- gdb_assert (!th->reload_context);
-
- char *context_ptr = windows_process->with_context (th, [] (auto *context)
- {
- return (char *) context;
- });
-
- char *context_offset = context_ptr + windows_process->mappings[r];
- struct gdbarch *gdbarch = regcache->arch ();
- i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
-
- gdb_assert (!gdbarch_read_pc_p (gdbarch));
- gdb_assert (gdbarch_pc_regnum (gdbarch) >= 0);
- gdb_assert (!gdbarch_write_pc_p (gdbarch));
-
- /* GDB treats some registers as 32-bit, where they are in fact only
- 16 bits long. These cases must be handled specially to avoid
- reading extraneous bits from the context. */
- if (r == I387_FISEG_REGNUM (tdep) || windows_process->segment_register_p (r))
- {
- gdb_byte bytes[4] = {};
- memcpy (bytes, context_offset, 2);
- regcache->raw_supply (r, bytes);
- }
- else if (r == I387_FOP_REGNUM (tdep))
- {
- long l = (*((long *) context_offset) >> 16) & ((1 << 11) - 1);
- regcache->raw_supply (r, &l);
- }
- else
- {
- if (th->stopped_at_software_breakpoint
- && !th->pc_adjusted
- && r == gdbarch_pc_regnum (gdbarch))
- {
- int size = register_size (gdbarch, r);
- if (size == 4)
- {
- uint32_t value;
- memcpy (&value, context_offset, size);
- value -= gdbarch_decr_pc_after_break (gdbarch);
- memcpy (context_offset, &value, size);
- }
- else
- {
- gdb_assert (size == 8);
- uint64_t value;
- memcpy (&value, context_offset, size);
- value -= gdbarch_decr_pc_after_break (gdbarch);
- memcpy (context_offset, &value, size);
- }
- /* Make sure we only rewrite the PC a single time. */
- th->pc_adjusted = true;
- }
- regcache->raw_supply (r, context_offset);
- }
-}
-
void
windows_nat_target::fetch_registers (struct regcache *regcache, int r)
{
@@ -482,51 +406,9 @@ windows_nat_target::fetch_registers (struct regcache *regcache, int r)
if (r < 0)
for (r = 0; r < gdbarch_num_regs (regcache->arch()); r++)
- windows_fetch_one_register (regcache, th, r);
- else
- windows_fetch_one_register (regcache, th, r);
-}
-
-/* Collect the register number R from the given regcache, and store
- its value into the corresponding area of the given thread's context.
-
- This function assumes that R is non-negative. A failed assertion
- assertion is raised if that is not true. */
-
-static void
-windows_store_one_register (const struct regcache *regcache,
- windows_thread_info *th, int r)
-{
- gdb_assert (r >= 0);
-
- char *context_ptr = windows_process->with_context (th, [] (auto *context)
- {
- return (char *) context;
- });
-
- struct gdbarch *gdbarch = regcache->arch ();
- i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
-
- /* GDB treats some registers as 32-bit, where they are in fact only
- 16 bits long. These cases must be handled specially to avoid
- overwriting other registers in the context. */
- if (r == I387_FISEG_REGNUM (tdep) || windows_process->segment_register_p (r))
- {
- gdb_byte bytes[4];
- regcache->raw_collect (r, bytes);
- memcpy (context_ptr + windows_process->mappings[r], bytes, 2);
- }
- else if (r == I387_FOP_REGNUM (tdep))
- {
- gdb_byte bytes[4];
- regcache->raw_collect (r, bytes);
- /* The value of FOP occupies the top two bytes in the context,
- so write the two low-order bytes from the cache into the
- appropriate spot. */
- memcpy (context_ptr + windows_process->mappings[r] + 2, bytes, 2);
- }
+ fetch_one_register (regcache, th, r);
else
- regcache->raw_collect (r, context_ptr + windows_process->mappings[r]);
+ fetch_one_register (regcache, th, r);
}
/* Store a new register value into the context of the thread tied to
@@ -545,9 +427,9 @@ windows_nat_target::store_registers (struct regcache *regcache, int r)
if (r < 0)
for (r = 0; r < gdbarch_num_regs (regcache->arch ()); r++)
- windows_store_one_register (regcache, th, r);
+ store_one_register (regcache, th, r);
else
- windows_store_one_register (regcache, th, r);
+ store_one_register (regcache, th, r);
}
bool
@@ -1472,7 +1354,7 @@ windows_nat_target::do_initial_windows_stuff (DWORD pid, bool attaching)
{
struct inferior *inf;
- initialize_windows_arch ();
+ initialize_windows_arch (attaching);
windows_process->last_sig = GDB_SIGNAL_0;
windows_process->open_process_used = 0;
@@ -1490,22 +1372,6 @@ windows_nat_target::do_initial_windows_stuff (DWORD pid, bool attaching)
clear_proceed_status (0);
init_wait_for_inferior ();
-#ifdef __x86_64__
- windows_process->ignore_first_breakpoint
- = !attaching && windows_process->wow64_process;
-
- if (!windows_process->wow64_process)
- {
- windows_process->mappings = amd64_mappings;
- windows_process->segment_register_p = amd64_windows_segment_register_p;
- }
- else
-#endif
- {
- windows_process->mappings = i386_mappings;
- windows_process->segment_register_p = i386_windows_segment_register_p;
- }
-
inferior_appeared (inf, pid);
inf->attach_flag = attaching;
diff --git a/gdb/windows-nat.h b/gdb/windows-nat.h
index 6553052f420..df872907535 100644
--- a/gdb/windows-nat.h
+++ b/gdb/windows-nat.h
@@ -83,10 +83,6 @@ struct windows_per_inferior : public windows_nat::windows_process_info
const int *mappings = nullptr;
- /* The function to use in order to determine whether a register is
- a segment register or not. */
- segment_register_p_ftype *segment_register_p = nullptr;
-
std::vector<windows_solib> solibs;
#ifdef __CYGWIN__
@@ -184,8 +180,9 @@ struct windows_nat_target : public inf_child_target
protected:
/* Initialize arch-specific data for a new inferior (debug registers,
- register mappings). */
- virtual void initialize_windows_arch () = 0;
+ register mappings). If ATTACHING is true, we're attaching to an
+ already-running process. */
+ virtual void initialize_windows_arch (bool attaching) = 0;
/* Cleanup arch-specific data after inferior exit. */
virtual void cleanup_windows_arch () = 0;
@@ -198,6 +195,26 @@ struct windows_nat_target : public inf_child_target
/* Set the stepping bit in the thread context. */
virtual void thread_context_step (windows_thread_info *th) = 0;
+ /* Fetches register number R from the given windows_thread_info,
+ and supplies its value to the given regcache.
+
+ This function assumes that R is non-negative. A failed assertion
+ is raised if that is not true.
+
+ This function assumes that TH->RELOAD_CONTEXT is not set, meaning
+ that the windows_thread_info has an up-to-date context. A failed
+ assertion is raised if that assumption is violated. */
+ virtual void fetch_one_register (struct regcache *regcache,
+ windows_thread_info *th, int r) = 0;
+
+ /* Collect the register number R from the given regcache, and store
+ its value into the corresponding area of the given thread's context.
+
+ This function assumes that R is non-negative. A failed assertion
+ assertion is raised if that is not true. */
+ virtual void store_one_register (const struct regcache *regcache,
+ windows_thread_info *th, int r) = 0;
+
private:
windows_thread_info *add_thread (ptid_t ptid, HANDLE h, void *tlb,
diff --git a/gdb/x86-windows-nat.c b/gdb/x86-windows-nat.c
index 88844e0675a..96dd61b39fb 100644
--- a/gdb/x86-windows-nat.c
+++ b/gdb/x86-windows-nat.c
@@ -23,6 +23,9 @@
#include "x86-nat.h"
+#include "i386-tdep.h"
+#include "i387-tdep.h"
+
using namespace windows_nat;
/* If we're not using the old Cygwin header file set, define the
@@ -53,17 +56,26 @@ check (BOOL ok, const char *file, int line)
struct x86_windows_per_inferior : public windows_per_inferior
{
uintptr_t dr[8] {};
+
+ /* The function to use in order to determine whether a register is
+ a segment register or not. */
+ segment_register_p_ftype *segment_register_p = nullptr;
};
struct x86_windows_nat_target final : public x86_nat_target<windows_nat_target>
{
- void initialize_windows_arch () override;
+ void initialize_windows_arch (bool attaching) override;
void cleanup_windows_arch () override;
void fill_thread_context (windows_thread_info *th) override;
void thread_context_continue (windows_thread_info *th, int killed) override;
void thread_context_step (windows_thread_info *th) override;
+
+ void fetch_one_register (struct regcache *regcache,
+ windows_thread_info *th, int r) override;
+ void store_one_register (const struct regcache *regcache,
+ windows_thread_info *th, int r) override;
};
/* The current process. */
@@ -72,9 +84,25 @@ static x86_windows_per_inferior x86_windows_process;
/* See windows-nat.h. */
void
-x86_windows_nat_target::initialize_windows_arch ()
+x86_windows_nat_target::initialize_windows_arch (bool attaching)
{
memset (x86_windows_process.dr, 0, sizeof (x86_windows_process.dr));
+
+#ifdef __x86_64__
+ x86_windows_process.ignore_first_breakpoint
+ = !attaching && x86_windows_process.wow64_process;
+
+ if (!x86_windows_process.wow64_process)
+ {
+ x86_windows_process.mappings = amd64_mappings;
+ x86_windows_process.segment_register_p = amd64_windows_segment_register_p;
+ }
+ else
+#endif
+ {
+ x86_windows_process.mappings = i386_mappings;
+ x86_windows_process.segment_register_p = i386_windows_segment_register_p;
+ }
}
/* See windows-nat.h. */
@@ -158,6 +186,111 @@ x86_windows_nat_target::thread_context_step (windows_thread_info *th)
});
}
+/* See windows-nat.h. */
+
+void
+x86_windows_nat_target::fetch_one_register (struct regcache *regcache,
+ windows_thread_info *th, int r)
+{
+ gdb_assert (r >= 0);
+ gdb_assert (!th->reload_context);
+
+ char *context_ptr = x86_windows_process.with_context (th, [] (auto *context)
+ {
+ return (char *) context;
+ });
+
+ char *context_offset = context_ptr + x86_windows_process.mappings[r];
+ struct gdbarch *gdbarch = regcache->arch ();
+ i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
+
+ gdb_assert (!gdbarch_read_pc_p (gdbarch));
+ gdb_assert (gdbarch_pc_regnum (gdbarch) >= 0);
+ gdb_assert (!gdbarch_write_pc_p (gdbarch));
+
+ /* GDB treats some registers as 32-bit, where they are in fact only
+ 16 bits long. These cases must be handled specially to avoid
+ reading extraneous bits from the context. */
+ if (r == I387_FISEG_REGNUM (tdep)
+ || x86_windows_process.segment_register_p (r))
+ {
+ gdb_byte bytes[4] = {};
+ memcpy (bytes, context_offset, 2);
+ regcache->raw_supply (r, bytes);
+ }
+ else if (r == I387_FOP_REGNUM (tdep))
+ {
+ long l = (*((long *) context_offset) >> 16) & ((1 << 11) - 1);
+ regcache->raw_supply (r, &l);
+ }
+ else
+ {
+ if (th->stopped_at_software_breakpoint
+ && !th->pc_adjusted
+ && r == gdbarch_pc_regnum (gdbarch))
+ {
+ int size = register_size (gdbarch, r);
+ if (size == 4)
+ {
+ uint32_t value;
+ memcpy (&value, context_offset, size);
+ value -= gdbarch_decr_pc_after_break (gdbarch);
+ memcpy (context_offset, &value, size);
+ }
+ else
+ {
+ gdb_assert (size == 8);
+ uint64_t value;
+ memcpy (&value, context_offset, size);
+ value -= gdbarch_decr_pc_after_break (gdbarch);
+ memcpy (context_offset, &value, size);
+ }
+ /* Make sure we only rewrite the PC a single time. */
+ th->pc_adjusted = true;
+ }
+ regcache->raw_supply (r, context_offset);
+ }
+}
+
+/* See windows-nat.h. */
+
+void
+x86_windows_nat_target::store_one_register (const struct regcache *regcache,
+ windows_thread_info *th, int r)
+{
+ gdb_assert (r >= 0);
+
+ char *context_ptr = x86_windows_process.with_context (th, [] (auto *context)
+ {
+ return (char *) context;
+ });
+
+ struct gdbarch *gdbarch = regcache->arch ();
+ i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
+
+ /* GDB treats some registers as 32-bit, where they are in fact only
+ 16 bits long. These cases must be handled specially to avoid
+ overwriting other registers in the context. */
+ if (r == I387_FISEG_REGNUM (tdep)
+ || x86_windows_process.segment_register_p (r))
+ {
+ gdb_byte bytes[4];
+ regcache->raw_collect (r, bytes);
+ memcpy (context_ptr + x86_windows_process.mappings[r], bytes, 2);
+ }
+ else if (r == I387_FOP_REGNUM (tdep))
+ {
+ gdb_byte bytes[4];
+ regcache->raw_collect (r, bytes);
+ /* The value of FOP occupies the top two bytes in the context,
+ so write the two low-order bytes from the cache into the
+ appropriate spot. */
+ memcpy (context_ptr + x86_windows_process.mappings[r] + 2, bytes, 2);
+ }
+ else
+ regcache->raw_collect (r, context_ptr + x86_windows_process.mappings[r]);
+}
+
/* Hardware watchpoint support, adapted from go32-nat.c code. */
/* Pass the address ADDR to the inferior in the I'th debug register.
--
2.52.0
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH v2 09/11] Move auto_wide_charset gdbarch method to windows-tdep
2026-01-17 13:36 ` [PATCH v2 01/11] Remove duplicate code from windows_nat_target::resume Hannes Domani
` (11 preceding siblings ...)
2026-01-17 13:54 ` [PATCH v2 06/11] Move x86 register " Hannes Domani
@ 2026-01-17 13:54 ` Hannes Domani
2026-01-21 15:48 ` Tom Tromey
2026-01-17 13:54 ` [PATCH v2 10/11] Move setting size of long " Hannes Domani
2026-01-17 13:54 ` [PATCH v2 11/11] Add aarch64-windows support Hannes Domani
14 siblings, 1 reply; 44+ messages in thread
From: Hannes Domani @ 2026-01-17 13:54 UTC (permalink / raw)
To: gdb-patches
It's the same for all Windows ABIs.
---
gdb/amd64-windows-tdep.c | 10 ----------
gdb/i386-windows-tdep.c | 8 --------
gdb/windows-tdep.c | 9 +++++++++
3 files changed, 9 insertions(+), 18 deletions(-)
diff --git a/gdb/amd64-windows-tdep.c b/gdb/amd64-windows-tdep.c
index b46f74c6461..aeed266e713 100644
--- a/gdb/amd64-windows-tdep.c
+++ b/gdb/amd64-windows-tdep.c
@@ -1271,14 +1271,6 @@ amd64_windows_skip_trampoline_code (const frame_info_ptr &frame, CORE_ADDR pc)
return destination;
}
-/* Implement the "auto_wide_charset" gdbarch method. */
-
-static const char *
-amd64_windows_auto_wide_charset (void)
-{
- return "UTF-16";
-}
-
/* Common parts for gdbarch initialization for Windows and Cygwin on AMD64. */
static void
@@ -1320,8 +1312,6 @@ amd64_windows_init_abi_common (gdbarch_info info, struct gdbarch *gdbarch)
set_gdbarch_core_xfer_shared_libraries
(gdbarch, windows_core_xfer_shared_libraries);
set_gdbarch_core_pid_to_str (gdbarch, windows_core_pid_to_str);
-
- set_gdbarch_auto_wide_charset (gdbarch, amd64_windows_auto_wide_charset);
}
/* gdbarch initialization for Windows on AMD64. */
diff --git a/gdb/i386-windows-tdep.c b/gdb/i386-windows-tdep.c
index 2861d60fef2..daaa556d171 100644
--- a/gdb/i386-windows-tdep.c
+++ b/gdb/i386-windows-tdep.c
@@ -95,12 +95,6 @@ i386_windows_skip_trampoline_code (const frame_info_ptr &frame, CORE_ADDR pc)
return i386_pe_skip_trampoline_code (frame, pc, NULL);
}
-static const char *
-i386_windows_auto_wide_charset (void)
-{
- return "UTF-16";
-}
-
/* Implement the "push_dummy_call" gdbarch method. */
static CORE_ADDR
@@ -154,8 +148,6 @@ i386_windows_init_abi_common (struct gdbarch_info info, struct gdbarch *gdbarch)
set_gdbarch_core_xfer_shared_libraries
(gdbarch, windows_core_xfer_shared_libraries);
set_gdbarch_core_pid_to_str (gdbarch, windows_core_pid_to_str);
-
- set_gdbarch_auto_wide_charset (gdbarch, i386_windows_auto_wide_charset);
}
/* gdbarch initialization for Windows on i386. */
diff --git a/gdb/windows-tdep.c b/gdb/windows-tdep.c
index 6164bc34312..e69db28c2dc 100644
--- a/gdb/windows-tdep.c
+++ b/gdb/windows-tdep.c
@@ -930,6 +930,14 @@ windows_solib_ops::iterate_over_objfiles_in_search_order
}
}
+/* Implement the "auto_wide_charset" gdbarch method. */
+
+static const char *
+windows_auto_wide_charset (void)
+{
+ return "UTF-16";
+}
+
/* Common parts for gdbarch initialization for the Windows and Cygwin OS
ABIs. */
@@ -938,6 +946,7 @@ windows_init_abi_common (struct gdbarch_info info, struct gdbarch *gdbarch)
{
set_gdbarch_wchar_bit (gdbarch, 16);
set_gdbarch_wchar_signed (gdbarch, 0);
+ set_gdbarch_auto_wide_charset (gdbarch, windows_auto_wide_charset);
/* Canonical paths on this target look like
`c:\Program Files\Foo App\mydll.dll', for example. */
--
2.52.0
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH v2 10/11] Move setting size of long to windows-tdep
2026-01-17 13:36 ` [PATCH v2 01/11] Remove duplicate code from windows_nat_target::resume Hannes Domani
` (12 preceding siblings ...)
2026-01-17 13:54 ` [PATCH v2 09/11] Move auto_wide_charset gdbarch method to windows-tdep Hannes Domani
@ 2026-01-17 13:54 ` Hannes Domani
2026-01-21 15:59 ` Tom Tromey
2026-01-17 13:54 ` [PATCH v2 11/11] Add aarch64-windows support Hannes Domani
14 siblings, 1 reply; 44+ messages in thread
From: Hannes Domani @ 2026-01-17 13:54 UTC (permalink / raw)
To: gdb-patches
It's 32bit for all (non-cygwin) Windows ABIs.
---
gdb/amd64-windows-tdep.c | 3 ---
gdb/windows-tdep.c | 3 +++
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/gdb/amd64-windows-tdep.c b/gdb/amd64-windows-tdep.c
index aeed266e713..a9ca7b2ac79 100644
--- a/gdb/amd64-windows-tdep.c
+++ b/gdb/amd64-windows-tdep.c
@@ -1321,9 +1321,6 @@ amd64_windows_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
amd64_windows_init_abi_common (info, gdbarch);
windows_init_abi (info, gdbarch);
-
- /* On Windows, "long"s are only 32bit. */
- set_gdbarch_long_bit (gdbarch, 32);
}
/* Sigwrapper unwinder instruction patterns for AMD64. */
diff --git a/gdb/windows-tdep.c b/gdb/windows-tdep.c
index e69db28c2dc..5d27e0c3dd2 100644
--- a/gdb/windows-tdep.c
+++ b/gdb/windows-tdep.c
@@ -963,6 +963,9 @@ windows_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
windows_init_abi_common (info, gdbarch);
set_gdbarch_gdb_signal_to_target (gdbarch, windows_gdb_signal_to_target);
+
+ /* On Windows, "long"s are only 32bit. */
+ set_gdbarch_long_bit (gdbarch, 32);
}
/* See windows-tdep.h. */
--
2.52.0
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH v2 11/11] Add aarch64-windows support
2026-01-17 13:36 ` [PATCH v2 01/11] Remove duplicate code from windows_nat_target::resume Hannes Domani
` (13 preceding siblings ...)
2026-01-17 13:54 ` [PATCH v2 10/11] Move setting size of long " Hannes Domani
@ 2026-01-17 13:54 ` Hannes Domani
2026-01-17 16:04 ` Eli Zaretskii
2026-01-21 16:18 ` Tom Tromey
14 siblings, 2 replies; 44+ messages in thread
From: Hannes Domani @ 2026-01-17 13:54 UTC (permalink / raw)
To: gdb-patches
This makes most debugging work, except unwinding doesn't always work
from inside dlls where no debug info is available, because SEH unwinding
is not implemented.
The number of available hardware breakpoints is taken from
ID_AA64DFR0_EL1 (registry key "CP 4028").
As for hardware watchpoints, even though ARM64_MAX_WATCHPOINTS is 2,
testing showed that only 1 ever works, so it's fixed to that value.
---
Changes in v2:
- added new source files to ALLDEPFILES
- created NEWS entry
- removed set_gdbarch_auto_wide_charset and set_gdbarch_long_bit calls
since these are now done in windows-tdep.c
- added comments to aarch64_windows_breakpoint and
set_gdbarch_decr_pc_after_break
- removed unused 32bit code in
aarch64_windows_nat_target::fetch_one_register()
- changed stopped_data_address() to stopped_data_addresses() in
aarch64_windows_nat_target, and updated stopped_by_watchpoint()
- initialize windows_process inside INIT_GDB_FILE(aarch64_windows_nat)
---
gdb/Makefile.in | 3 +
gdb/NEWS | 2 +
gdb/aarch64-windows-nat.c | 346 +++++++++++++++++++++++++++++++++++++
gdb/aarch64-windows-tdep.c | 70 ++++++++
gdb/coff-pe-read.c | 6 +-
gdb/configure.host | 3 +
gdb/configure.nat | 4 +
gdb/configure.tgt | 5 +
gdb/nat/windows-nat.c | 5 +
gdb/nat/windows-nat.h | 2 +
10 files changed, 444 insertions(+), 2 deletions(-)
create mode 100644 gdb/aarch64-windows-nat.c
create mode 100644 gdb/aarch64-windows-tdep.c
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index b564048f9fa..fc76925344f 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -735,6 +735,7 @@ ALL_64_TARGET_OBS = \
aarch64-newlib-tdep.o \
aarch64-ravenscar-thread.o \
aarch64-tdep.o \
+ aarch64-windows-tdep.o \
alpha-bsd-tdep.o \
alpha-linux-tdep.o \
alpha-netbsd-tdep.o \
@@ -1784,6 +1785,8 @@ ALLDEPFILES = \
aarch64-newlib-tdep.c \
aarch64-ravenscar-thread.c \
aarch64-tdep.c \
+ aarch64-windows-nat.c \
+ aarch64-windows-tdep.c \
aix-thread.c \
alpha-bsd-nat.c \
alpha-bsd-tdep.c \
diff --git a/gdb/NEWS b/gdb/NEWS
index 74fc353d7e9..7ea41940566 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -61,6 +61,8 @@
GNU/Linux/MicroBlaze (gdbserver) microblazeel-*linux*
+AArch64 MinGW aarch64-*-mingw*
+
* New commands
set local-environment
diff --git a/gdb/aarch64-windows-nat.c b/gdb/aarch64-windows-nat.c
new file mode 100644
index 00000000000..838a9483634
--- /dev/null
+++ b/gdb/aarch64-windows-nat.c
@@ -0,0 +1,346 @@
+/* Native-dependent code for Windows AArch64.
+
+ Copyright (C) 2025-2026 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "windows-nat.h"
+#include "regcache.h"
+#include "gdbarch.h"
+#include "inferior.h"
+
+#include "aarch64-nat.h"
+
+using namespace windows_nat;
+
+#define CHECK(x) check (x, __FILE__,__LINE__)
+
+static void
+check (BOOL ok, const char *file, int line)
+{
+ if (!ok)
+ {
+ unsigned err = (unsigned) GetLastError ();
+ gdb_printf ("error return %s:%d was %u: %s\n", file, line,
+ err, strwinerror (err));
+ }
+}
+
+struct aarch64_windows_per_inferior : public windows_per_inferior
+{
+ aarch64_debug_reg_state dr_state;
+};
+
+struct aarch64_windows_nat_target final :
+ public aarch64_nat_target<windows_nat_target>
+{
+ std::vector<CORE_ADDR> stopped_data_addresses () override;
+ bool stopped_by_watchpoint () override;
+
+ void initialize_windows_arch (bool attaching) override;
+ void cleanup_windows_arch () override;
+
+ void fill_thread_context (windows_thread_info *th) override;
+
+ void thread_context_continue (windows_thread_info *th, int killed) override;
+ void thread_context_step (windows_thread_info *th) override;
+
+ void fetch_one_register (struct regcache *regcache,
+ windows_thread_info *th, int r) override;
+ void store_one_register (const struct regcache *regcache,
+ windows_thread_info *th, int r) override;
+
+ bool is_sw_breakpoint (EXCEPTION_RECORD *er) override;
+};
+
+/* The current process. */
+static aarch64_windows_per_inferior aarch64_windows_process;
+
+#define context_offset(x) (offsetof (CONTEXT, x))
+const int aarch64_mappings[] =
+{
+ context_offset (X0),
+ context_offset (X1),
+ context_offset (X2),
+ context_offset (X3),
+ context_offset (X4),
+ context_offset (X5),
+ context_offset (X6),
+ context_offset (X7),
+ context_offset (X8),
+ context_offset (X9),
+ context_offset (X10),
+ context_offset (X11),
+ context_offset (X12),
+ context_offset (X13),
+ context_offset (X14),
+ context_offset (X15),
+ context_offset (X16),
+ context_offset (X17),
+ context_offset (X18),
+ context_offset (X19),
+ context_offset (X20),
+ context_offset (X21),
+ context_offset (X22),
+ context_offset (X23),
+ context_offset (X24),
+ context_offset (X25),
+ context_offset (X26),
+ context_offset (X27),
+ context_offset (X28),
+ context_offset (Fp),
+ context_offset (Lr),
+ context_offset (Sp),
+ context_offset (Pc),
+ context_offset (Cpsr),
+ context_offset (V[0]),
+ context_offset (V[1]),
+ context_offset (V[2]),
+ context_offset (V[3]),
+ context_offset (V[4]),
+ context_offset (V[5]),
+ context_offset (V[6]),
+ context_offset (V[7]),
+ context_offset (V[8]),
+ context_offset (V[9]),
+ context_offset (V[10]),
+ context_offset (V[11]),
+ context_offset (V[12]),
+ context_offset (V[13]),
+ context_offset (V[14]),
+ context_offset (V[15]),
+ context_offset (V[16]),
+ context_offset (V[17]),
+ context_offset (V[18]),
+ context_offset (V[19]),
+ context_offset (V[20]),
+ context_offset (V[21]),
+ context_offset (V[22]),
+ context_offset (V[23]),
+ context_offset (V[24]),
+ context_offset (V[25]),
+ context_offset (V[26]),
+ context_offset (V[27]),
+ context_offset (V[28]),
+ context_offset (V[29]),
+ context_offset (V[30]),
+ context_offset (V[31]),
+ context_offset (Fpsr),
+ context_offset (Fpcr),
+};
+#undef context_offset
+
+/* Implement the "stopped_data_addresses" target_ops method. */
+
+std::vector<CORE_ADDR>
+aarch64_windows_nat_target::stopped_data_addresses ()
+{
+ if (aarch64_windows_process.siginfo_er.ExceptionCode != EXCEPTION_BREAKPOINT
+ || aarch64_windows_process.siginfo_er.NumberParameters != 2)
+ return {};
+
+ const CORE_ADDR addr_trap
+ = (CORE_ADDR) aarch64_windows_process.siginfo_er.ExceptionInformation[1];
+
+ struct aarch64_debug_reg_state *state
+ = aarch64_get_debug_reg_state (inferior_ptid.pid ());
+ return aarch64_stopped_data_addresses (state, addr_trap);
+}
+
+/* Implement the "stopped_by_watchpoint" target_ops method. */
+
+bool
+aarch64_windows_nat_target::stopped_by_watchpoint ()
+{
+ return !stopped_data_addresses ().empty ();
+}
+
+/* See windows-nat.h. */
+
+void
+aarch64_windows_nat_target::initialize_windows_arch (bool attaching)
+{
+ memset (&aarch64_windows_process.dr_state, 0,
+ sizeof (aarch64_windows_process.dr_state));
+
+ aarch64_windows_process.mappings = aarch64_mappings;
+}
+
+/* See windows-nat.h. */
+
+void
+aarch64_windows_nat_target::cleanup_windows_arch ()
+{
+ aarch64_remove_debug_reg_state (inferior_ptid.pid ());
+}
+
+/* See windows-nat.h. */
+
+void
+aarch64_windows_nat_target::fill_thread_context (windows_thread_info *th)
+{
+ CONTEXT *context = &th->context;
+
+ context->ContextFlags = WindowsContext<decltype(context)>::all;
+ CHECK (get_thread_context (th->h, context));
+}
+
+/* See windows-nat.h. */
+
+void
+aarch64_windows_nat_target::thread_context_continue (windows_thread_info *th,
+ int killed)
+{
+ CONTEXT *context = &th->context;
+
+ if (th->debug_registers_changed)
+ {
+ context->ContextFlags |= WindowsContext<decltype(context)>::debug;
+ for (int i = 0; i < aarch64_num_bp_regs; i++)
+ {
+ context->Bvr[i] = aarch64_windows_process.dr_state.dr_addr_bp[i];
+ context->Bcr[i] = aarch64_windows_process.dr_state.dr_ctrl_bp[i];
+ }
+ for (int i = 0; i < aarch64_num_wp_regs; i++)
+ {
+ context->Wvr[i] = aarch64_windows_process.dr_state.dr_addr_wp[i];
+ context->Wcr[i] = aarch64_windows_process.dr_state.dr_ctrl_wp[i];
+ }
+ th->debug_registers_changed = false;
+ }
+
+ if (context->ContextFlags)
+ {
+ DWORD ec = 0;
+
+ if (GetExitCodeThread (th->h, &ec)
+ && ec == STILL_ACTIVE)
+ {
+ BOOL status = set_thread_context (th->h, context);
+
+ if (!killed)
+ CHECK (status);
+ }
+ context->ContextFlags = 0;
+ }
+}
+
+/* See windows-nat.h. */
+
+void
+aarch64_windows_nat_target::thread_context_step (windows_thread_info *th)
+{
+ th->context.Cpsr |= 0x200000;
+}
+
+/* See windows-nat.h. */
+
+void
+aarch64_windows_nat_target::fetch_one_register (struct regcache *regcache,
+ windows_thread_info *th, int r)
+{
+ gdb_assert (r >= 0);
+ gdb_assert (!th->reload_context);
+
+ char *context_ptr = (char *) &th->context;
+ char *context_offset = context_ptr + aarch64_windows_process.mappings[r];
+ struct gdbarch *gdbarch = regcache->arch ();
+
+ gdb_assert (!gdbarch_read_pc_p (gdbarch));
+ gdb_assert (gdbarch_pc_regnum (gdbarch) >= 0);
+ gdb_assert (!gdbarch_write_pc_p (gdbarch));
+
+ if (th->stopped_at_software_breakpoint
+ && !th->pc_adjusted
+ && r == gdbarch_pc_regnum (gdbarch))
+ {
+ uint64_t value;
+ memcpy (&value, context_offset, 8);
+ value -= gdbarch_decr_pc_after_break (gdbarch);
+ memcpy (context_offset, &value, 8);
+ /* Make sure we only rewrite the PC a single time. */
+ th->pc_adjusted = true;
+ }
+ regcache->raw_supply (r, context_offset);
+}
+
+/* See windows-nat.h. */
+
+void
+aarch64_windows_nat_target::store_one_register (const struct regcache *regcache,
+ windows_thread_info *th, int r)
+{
+ gdb_assert (r >= 0);
+
+ char *context_ptr = (char *) &th->context;
+
+ regcache->raw_collect (r, context_ptr + aarch64_windows_process.mappings[r]);
+}
+
+/* See windows-nat.h. */
+
+bool
+aarch64_windows_nat_target::is_sw_breakpoint (EXCEPTION_RECORD *er)
+{
+ /* On aarch64, hardware breakpoints also get EXCEPTION_BREAKPOINT,
+ but they can be recognized with ExceptionInformation. */
+ return (er->ExceptionCode == EXCEPTION_BREAKPOINT
+ && er->NumberParameters == 1
+ && er->ExceptionInformation[0] == 0);
+}
+
+/* Notify all threads that the debug registers changed. */
+
+void
+aarch64_notify_debug_reg_change (ptid_t ptid,
+ int is_watchpoint, unsigned int idx)
+{
+ struct aarch64_debug_reg_state *state
+ = aarch64_get_debug_reg_state (inferior_ptid.pid ());
+ aarch64_windows_process.dr_state = *state;
+
+ for (auto &th : aarch64_windows_process.thread_list)
+ th->debug_registers_changed = true;
+}
+
+INIT_GDB_FILE (aarch64_windows_nat)
+{
+ aarch64_initialize_hw_point ();
+
+ /* Get ID_AA64DFR0_EL1 value (CP 4028) from registry. */
+ aarch64_num_bp_regs = 0;
+ uint64_t cp4028;
+ DWORD cp4028_size = sizeof(cp4028);
+ if (RegGetValueA (HKEY_LOCAL_MACHINE,
+ "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0",
+ "CP 4028", RRF_RT_REG_QWORD, NULL, &cp4028, &cp4028_size)
+ == ERROR_SUCCESS)
+ {
+ /* Bits 12-15 are the number of breakpoints, minus 1. */
+ aarch64_num_bp_regs = ((cp4028 & 0xf000) >> 12) + 1;
+ if (aarch64_num_bp_regs > ARM64_MAX_BREAKPOINTS)
+ aarch64_num_bp_regs = ARM64_MAX_BREAKPOINTS;
+ }
+
+ /* ARM64_MAX_WATCHPOINTS is 2, but only 1 works. */
+ aarch64_num_wp_regs = 1;
+
+ /* The target is not a global specifically to avoid a C++ "static
+ initializer fiasco" situation. */
+ add_inf_child_target (new aarch64_windows_nat_target);
+
+ windows_process = &aarch64_windows_process;
+}
diff --git a/gdb/aarch64-windows-tdep.c b/gdb/aarch64-windows-tdep.c
new file mode 100644
index 00000000000..e7312d296ae
--- /dev/null
+++ b/gdb/aarch64-windows-tdep.c
@@ -0,0 +1,70 @@
+/* Target-dependent code for Windows AArch64.
+
+ Copyright (C) 2025-2026 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "gdbarch.h"
+#include "aarch64-tdep.h"
+#include "arch-utils.h"
+#include "regset.h"
+#include "windows-tdep.h"
+
+/* Windows uses the various BRK instruction variants for special operations,
+ and BRK #0xf000 triggers a breakpoint exception in the debugger. */
+constexpr gdb_byte aarch64_windows_breakpoint[] = {0x00, 0x00, 0x3e, 0xd4};
+
+typedef BP_MANIPULATION (aarch64_windows_breakpoint) aarch64_w_breakpoint;
+
+/* gdbarch initialization for Windows on AArch64. */
+
+static void
+aarch64_windows_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ set_gdbarch_ps_regnum (gdbarch, AARCH64_CPSR_REGNUM);
+
+ set_gdbarch_breakpoint_kind_from_pc (gdbarch,
+ aarch64_w_breakpoint::kind_from_pc);
+ set_gdbarch_sw_breakpoint_from_kind (gdbarch,
+ aarch64_w_breakpoint::bp_from_kind);
+
+ /* Usually the arm BRK instruction triggers with the PC still at the
+ instruction, but Windows increments the PC before notifying the
+ debugger. */
+ set_gdbarch_decr_pc_after_break (gdbarch, 4);
+
+ windows_init_abi (info, gdbarch);
+}
+
+static gdb_osabi
+aarch64_windows_osabi_sniffer (bfd *abfd)
+{
+ const char *target_name = bfd_get_target (abfd);
+
+ if (!streq (target_name, "pei-aarch64-little"))
+ return GDB_OSABI_UNKNOWN;
+
+ return GDB_OSABI_WINDOWS;
+}
+
+INIT_GDB_FILE (aarch64_windows_tdep)
+{
+ gdbarch_register_osabi (bfd_arch_aarch64, 0, GDB_OSABI_WINDOWS,
+ aarch64_windows_init_abi);
+
+ gdbarch_register_osabi_sniffer (bfd_arch_aarch64, bfd_target_coff_flavour,
+ aarch64_windows_osabi_sniffer);
+}
diff --git a/gdb/coff-pe-read.c b/gdb/coff-pe-read.c
index f78f825fa12..5073a4b0c4b 100644
--- a/gdb/coff-pe-read.c
+++ b/gdb/coff-pe-read.c
@@ -339,7 +339,8 @@ read_pe_exported_syms (minimal_symbol_reader &reader,
is_pe64 = (strcmp (target, "pe-x86-64") == 0
|| strcmp (target, "pei-x86-64") == 0
|| strcmp (target, "pe-aarch64") == 0
- || strcmp (target, "pei-aarch64") == 0);
+ || strcmp (target, "pei-aarch64") == 0
+ || strcmp (target, "pei-aarch64-little") == 0);
is_pe32 = (strcmp (target, "pe-i386") == 0
|| strcmp (target, "pei-i386") == 0
|| strcmp (target, "pe-arm-wince-little") == 0
@@ -638,7 +639,8 @@ pe_text_section_offset (struct bfd *abfd)
is_pe64 = (strcmp (target, "pe-x86-64") == 0
|| strcmp (target, "pei-x86-64") == 0
|| strcmp (target, "pe-aarch64") == 0
- || strcmp (target, "pei-aarch64") == 0);
+ || strcmp (target, "pei-aarch64") == 0
+ || strcmp (target, "pei-aarch64-little") == 0);
is_pe32 = (strcmp (target, "pe-i386") == 0
|| strcmp (target, "pei-i386") == 0
|| strcmp (target, "pe-arm-wince-little") == 0
diff --git a/gdb/configure.host b/gdb/configure.host
index fdd651987e3..e83b944c0b8 100644
--- a/gdb/configure.host
+++ b/gdb/configure.host
@@ -81,6 +81,9 @@ case "${host}" in
aarch64*-*-linux*) gdb_host=linux ;;
aarch64*-*-freebsd*) gdb_host=fbsd ;;
+aarch64*-*-mingw*) gdb_host=mingw64a
+ gdb_host_obs=mingw-hdep.o
+ ;;
alpha*-*-linux*) gdb_host=alpha-linux ;;
alpha*-*-netbsdaout* | alpha*-*-knetbsdaout*-gnu)
diff --git a/gdb/configure.nat b/gdb/configure.nat
index 3ac0319328f..38dd4179511 100644
--- a/gdb/configure.nat
+++ b/gdb/configure.nat
@@ -77,6 +77,10 @@ case ${gdb_host} in
cygwin*)
NATDEPFILES='x86-nat.o nat/x86-dregs.o windows-nat.o nat/windows-nat.o'
;;
+ mingw64a)
+ NATDEPFILES='aarch64-nat.o aarch64-windows-nat.o windows-nat.o \
+ nat/windows-nat.o nat/aarch64-hw-point.o'
+ ;;
mingw*)
NATDEPFILES='x86-nat.o nat/x86-dregs.o windows-nat.o nat/windows-nat.o'
;;
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index c0031e3f7a6..ba418653e86 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -155,6 +155,11 @@ aarch64*-*-linux*)
symfile-mem.o linux-record.o"
;;
+aarch64-*-mingw*)
+ # Target: MingW/aarch64
+ gdb_target_obs="aarch64-windows-tdep.o windows-tdep.o"
+ ;;
+
alpha*-*-linux*)
# Target: Little-endian Alpha running Linux
gdb_target_obs="alpha-linux-tdep.o \
diff --git a/gdb/nat/windows-nat.c b/gdb/nat/windows-nat.c
index 2d0c7ddc2ca..a74bab75238 100644
--- a/gdb/nat/windows-nat.c
+++ b/gdb/nat/windows-nat.c
@@ -530,6 +530,7 @@ windows_process_info::add_dll (LPVOID load_addr)
if (!ret)
return;
+#if defined __i386__ || defined __x86_64__
char system_dir[MAX_PATH];
char syswow_dir[MAX_PATH];
size_t system_dir_len = 0;
@@ -560,6 +561,7 @@ windows_process_info::add_dll (LPVOID load_addr)
}
}
+#endif
for (i = 1; i < (int) (cb_needed / sizeof (HMODULE)); i++)
{
MODULEINFO mi;
@@ -583,6 +585,8 @@ windows_process_info::add_dll (LPVOID load_addr)
#else
name = dll_name;
#endif
+
+#if defined __i386__ || defined __x86_64__
/* Convert the DLL path of 32bit processes returned by
GetModuleFileNameEx from the 64bit system directory to the
32bit syswow64 directory if necessary. */
@@ -595,6 +599,7 @@ windows_process_info::add_dll (LPVOID load_addr)
syswow_dll_path += name + system_dir_len;
name = syswow_dll_path.c_str();
}
+#endif
/* Record the DLL if either LOAD_ADDR is NULL or the address
at which the DLL was loaded is equal to LOAD_ADDR. */
diff --git a/gdb/nat/windows-nat.h b/gdb/nat/windows-nat.h
index c9cae999a70..5411c73ff97 100644
--- a/gdb/nat/windows-nat.h
+++ b/gdb/nat/windows-nat.h
@@ -474,7 +474,9 @@ struct WindowsContext<CONTEXT *>
static constexpr DWORD full = CONTEXT_FULL;
static constexpr DWORD all = (CONTEXT_FULL
| CONTEXT_FLOATING_POINT
+#ifdef CONTEXT_SEGMENTS
| CONTEXT_SEGMENTS
+#endif
| CONTEXT_DEBUG_REGISTERS
| CONTEXT_EXTENDED_REGISTERS);
};
--
2.52.0
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [PATCH v2 04/11] Create x86-windows-nat.c
2026-01-17 13:54 ` [PATCH v2 04/11] Create x86-windows-nat.c Hannes Domani
@ 2026-01-17 14:01 ` Hannes Domani
2026-01-17 14:14 ` Hannes Domani
2026-01-17 15:04 ` Simon Marchi
0 siblings, 2 replies; 44+ messages in thread
From: Hannes Domani @ 2026-01-17 14:01 UTC (permalink / raw)
To: gdb-patches
Am Samstag, 17. Januar 2026 um 14:56:45 MEZ hat Hannes Domani <ssbssa@yahoo.de> Folgendes geschrieben:
> Also creates the x86_windows_per_inferior and x86_windows_nat_target
> derived classes in there which will then hold the arch-specific data and
> function overrides.
> ---
> gdb/Makefile.in | 1 +
> gdb/configure.nat | 12 ++++++++----
> gdb/windows-nat.c | 7 +------
> gdb/x86-windows-nat.c | 42 ++++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 52 insertions(+), 10 deletions(-)
> create mode 100644 gdb/x86-windows-nat.c
I'm sorry about these duplicate mails.
When I first used git send-email, it only succeeded for 10 of the 11 patches.
So I tried again, and since it asks me for each patch individually if
I want to send it, I thought I could use that to only send patch 11 again.
But for some reason it didn't ask me for some of them, and just sent
these duplicates.
Is there a correct way to do this?
Hannes
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [PATCH v2 04/11] Create x86-windows-nat.c
2026-01-17 14:01 ` Hannes Domani
@ 2026-01-17 14:14 ` Hannes Domani
2026-01-17 15:04 ` Simon Marchi
1 sibling, 0 replies; 44+ messages in thread
From: Hannes Domani @ 2026-01-17 14:14 UTC (permalink / raw)
To: gdb-patches
Am Samstag, 17. Januar 2026 um 15:02:34 MEZ hat Hannes Domani <ssbssa@yahoo.de> Folgendes geschrieben:
> Am Samstag, 17. Januar 2026 um 14:56:45 MEZ hat Hannes Domani <ssbssa@yahoo.de> Folgendes geschrieben:
>
> > Also creates the x86_windows_per_inferior and x86_windows_nat_target
> > derived classes in there which will then hold the arch-specific data and
> > function overrides.
> > ---
> > gdb/Makefile.in | 1 +
> > gdb/configure.nat | 12 ++++++++----
> > gdb/windows-nat.c | 7 +------
> > gdb/x86-windows-nat.c | 42 ++++++++++++++++++++++++++++++++++++++++++
> > 4 files changed, 52 insertions(+), 10 deletions(-)
> > create mode 100644 gdb/x86-windows-nat.c
>
>
> I'm sorry about these duplicate mails.
>
> When I first used git send-email, it only succeeded for 10 of the 11 patches.
> So I tried again, and since it asks me for each patch individually if
> I want to send it, I thought I could use that to only send patch 11 again.
> But for some reason it didn't ask me for some of them, and just sent
> these duplicates.
>
> Is there a correct way to do this?
I just found out that by default send-email only ask if it automatically
added CC's, which happened for the ones already containing Approved-By.
So I was missing --confirm=always, then it probably would have done what
I wanted.
Hannes
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [PATCH v2 04/11] Create x86-windows-nat.c
2026-01-17 14:01 ` Hannes Domani
2026-01-17 14:14 ` Hannes Domani
@ 2026-01-17 15:04 ` Simon Marchi
2026-01-17 15:15 ` Hannes Domani
1 sibling, 1 reply; 44+ messages in thread
From: Simon Marchi @ 2026-01-17 15:04 UTC (permalink / raw)
To: Hannes Domani, gdb-patches
On 2026-01-17 09:01, Hannes Domani wrote:
> Am Samstag, 17. Januar 2026 um 14:56:45 MEZ hat Hannes Domani <ssbssa@yahoo.de> Folgendes geschrieben:
>
>> Also creates the x86_windows_per_inferior and x86_windows_nat_target
>> derived classes in there which will then hold the arch-specific data and
>> function overrides.
>> ---
>> gdb/Makefile.in | 1 +
>> gdb/configure.nat | 12 ++++++++----
>> gdb/windows-nat.c | 7 +------
>> gdb/x86-windows-nat.c | 42 ++++++++++++++++++++++++++++++++++++++++++
>> 4 files changed, 52 insertions(+), 10 deletions(-)
>> create mode 100644 gdb/x86-windows-nat.c
>
> I'm sorry about these duplicate mails.
>
> When I first used git send-email, it only succeeded for 10 of the 11 patches.
> So I tried again, and since it asks me for each patch individually if
> I want to send it, I thought I could use that to only send patch 11 again.
> But for some reason it didn't ask me for some of them, and just sent
> these duplicates.
>
> Is there a correct way to do this?
Not sure if this is what happened to you, but my mail provider only accepts
up to about X messages in short span of time (I don't remember the exact
value of X, but it's around 10). Did the server respond with some
rejection status code/message for the last message?
I have these settings in my git config to work around this:
[sendemail]
smtpReloginDelay = 120
smtpBatchSize = 8
This means that git-send-email will send up to 8 messages in a given
session. After 8, it will wait 120 seconds and do a fresh login to
continue.
Simon
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [PATCH v2 04/11] Create x86-windows-nat.c
2026-01-17 15:04 ` Simon Marchi
@ 2026-01-17 15:15 ` Hannes Domani
0 siblings, 0 replies; 44+ messages in thread
From: Hannes Domani @ 2026-01-17 15:15 UTC (permalink / raw)
To: gdb-patches, Simon Marchi
Am Samstag, 17. Januar 2026 um 16:05:00 MEZ hat Simon Marchi <simark@simark.ca> Folgendes geschrieben:
> On 2026-01-17 09:01, Hannes Domani wrote:
> > Am Samstag, 17. Januar 2026 um 14:56:45 MEZ hat Hannes Domani <ssbssa@yahoo.de> Folgendes geschrieben:
> >
> >> Also creates the x86_windows_per_inferior and x86_windows_nat_target
> >> derived classes in there which will then hold the arch-specific data and
> >> function overrides.
> >> ---
> >> gdb/Makefile.in | 1 +
> >> gdb/configure.nat | 12 ++++++++----
> >> gdb/windows-nat.c | 7 +------
> >> gdb/x86-windows-nat.c | 42 ++++++++++++++++++++++++++++++++++++++++++
> >> 4 files changed, 52 insertions(+), 10 deletions(-)
> >> create mode 100644 gdb/x86-windows-nat.c
> >
> > I'm sorry about these duplicate mails.
> >
> > When I first used git send-email, it only succeeded for 10 of the 11 patches.
> > So I tried again, and since it asks me for each patch individually if
> > I want to send it, I thought I could use that to only send patch 11 again.
> > But for some reason it didn't ask me for some of them, and just sent
> > these duplicates.
> >
> > Is there a correct way to do this?
>
> Not sure if this is what happened to you, but my mail provider only accepts
> up to about X messages in short span of time (I don't remember the exact
> value of X, but it's around 10). Did the server respond with some
> rejection status code/message for the last message?
I only got this message:
6.6.0 Error sending message for delivery.
But I guess my mail provider has a similar limit.
> I have these settings in my git config to work around this:
>
>
> [sendemail]
>
> smtpReloginDelay = 120
> smtpBatchSize = 8
>
> This means that git-send-email will send up to 8 messages in a given
> session. After 8, it will wait 120 seconds and do a fresh login to
> continue.
I added this to my git config, thanks.
Hannes
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [PATCH v2 11/11] Add aarch64-windows support
2026-01-17 13:54 ` [PATCH v2 11/11] Add aarch64-windows support Hannes Domani
@ 2026-01-17 16:04 ` Eli Zaretskii
2026-01-21 16:18 ` Tom Tromey
1 sibling, 0 replies; 44+ messages in thread
From: Eli Zaretskii @ 2026-01-17 16:04 UTC (permalink / raw)
To: Hannes Domani; +Cc: gdb-patches
> From: Hannes Domani <ssbssa@yahoo.de>
> Date: Sat, 17 Jan 2026 14:54:34 +0100
>
> This makes most debugging work, except unwinding doesn't always work
> from inside dlls where no debug info is available, because SEH unwinding
> is not implemented.
>
> The number of available hardware breakpoints is taken from
> ID_AA64DFR0_EL1 (registry key "CP 4028").
> As for hardware watchpoints, even though ARM64_MAX_WATCHPOINTS is 2,
> testing showed that only 1 ever works, so it's fixed to that value.
> ---
> Changes in v2:
> - added new source files to ALLDEPFILES
> - created NEWS entry
> - removed set_gdbarch_auto_wide_charset and set_gdbarch_long_bit calls
> since these are now done in windows-tdep.c
> - added comments to aarch64_windows_breakpoint and
> set_gdbarch_decr_pc_after_break
> - removed unused 32bit code in
> aarch64_windows_nat_target::fetch_one_register()
> - changed stopped_data_address() to stopped_data_addresses() in
> aarch64_windows_nat_target, and updated stopped_by_watchpoint()
> - initialize windows_process inside INIT_GDB_FILE(aarch64_windows_nat)
> ---
> gdb/Makefile.in | 3 +
> gdb/NEWS | 2 +
> gdb/aarch64-windows-nat.c | 346 +++++++++++++++++++++++++++++++++++++
> gdb/aarch64-windows-tdep.c | 70 ++++++++
> gdb/coff-pe-read.c | 6 +-
> gdb/configure.host | 3 +
> gdb/configure.nat | 4 +
> gdb/configure.tgt | 5 +
> gdb/nat/windows-nat.c | 5 +
> gdb/nat/windows-nat.h | 2 +
> 10 files changed, 444 insertions(+), 2 deletions(-)
> create mode 100644 gdb/aarch64-windows-nat.c
> create mode 100644 gdb/aarch64-windows-tdep.c
Thanks, the NEWS part is okay.
Reviewed-By: Eli Zaretskii <eliz@gnu.org>
^ permalink raw reply [flat|nested] 44+ messages in thread
* RE: [PATCH v2 05/11] Move x86 debug registers and related code into x86-windows-nat.c
2026-01-17 13:36 ` [PATCH v2 05/11] Move x86 debug registers and related code into x86-windows-nat.c Hannes Domani
@ 2026-01-19 12:49 ` Schimpe, Christina
2026-01-20 15:49 ` Hannes Domani
2026-01-23 13:17 ` [PATCH v3] " Hannes Domani
1 sibling, 1 reply; 44+ messages in thread
From: Schimpe, Christina @ 2026-01-19 12:49 UTC (permalink / raw)
To: Hannes Domani, gdb-patches
Hi Hannes,
I only have one comment for this patch, please see below.
> -----Original Message-----
> From: Hannes Domani <ssbssa@yahoo.de>
> Sent: Samstag, 17. Januar 2026 14:36
> To: gdb-patches@sourceware.org
> Subject: [PATCH v2 05/11] Move x86 debug registers and related code into
> x86-windows-nat.c
>
> ---
> Changes in v2:
> - changed new windows_nat_target functions from public to protected
> - better comments for these functions
> ---
> gdb/windows-nat.c | 148 ++------------------------------
> gdb/windows-nat.h | 19 ++++-
> gdb/x86-windows-nat.c | 191
> ++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 215 insertions(+), 143 deletions(-)
>
> diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c index
> 68eebe1eaf9..e1da956b125 100644
> --- a/gdb/windows-nat.c
> +++ b/gdb/windows-nat.c
> @@ -62,7 +62,6 @@
>
> #include "windows-tdep.h"
> #include "windows-nat.h"
> -#include "x86-nat.h"
> #include "complaints.h"
> #include "gdbsupport/gdb_tilde_expand.h"
> #include "gdbsupport/pathstuff.h"
> @@ -85,18 +84,6 @@ windows_per_inferior *windows_process;
> # define STARTUPINFO STARTUPINFOW
> #endif
>
> -/* If we're not using the old Cygwin header file set, define the
> - following which never should have been in the generic Win32 API
> - headers in the first place since they were our own invention... */
> -#ifndef _GNU_H_WINDOWS_H
> -enum
> - {
> - FLAG_TRACE_BIT = 0x100,
> - };
> -#endif
> -
> -#define DR6_CLEAR_VALUE 0xffff0ff0
> -
> /* The string sent by cygwin when it processes a signal.
> FIXME: This should be in a cygwin include file. */ #ifndef
> _CYGWIN_SIGNAL_STRING @@ -116,12 +103,6 @@ enum
> debug_prefixed_printf_cond (debug_exceptions, "windows except", fmt, \
> ## __VA_ARGS__)
>
> -static void cygwin_set_dr (int i, CORE_ADDR addr); -static void
> cygwin_set_dr7 (unsigned long val); -static CORE_ADDR cygwin_get_dr (int i);
> -static unsigned long cygwin_get_dr6 (void); -static unsigned long
> cygwin_get_dr7 (void);
> -
> /* User options. */
> static bool new_console = false;
> #ifdef __CYGWIN__
> @@ -494,23 +475,7 @@ windows_nat_target::fetch_registers (struct
> regcache *regcache, int r)
>
> if (th->reload_context)
> {
> - windows_process->with_context (th, [&] (auto *context)
> - {
> - context->ContextFlags = WindowsContext<decltype(context)>::all;
> - CHECK (get_thread_context (th->h, context));
> - /* Copy dr values from that thread.
> - But only if there were not modified since last stop.
> - PR gdb/2388 */
> - if (!th->debug_registers_changed)
> - {
> - windows_process->dr[0] = context->Dr0;
> - windows_process->dr[1] = context->Dr1;
> - windows_process->dr[2] = context->Dr2;
> - windows_process->dr[3] = context->Dr3;
> - windows_process->dr[6] = context->Dr6;
> - windows_process->dr[7] = context->Dr7;
> - }
> - });
> + fill_thread_context (th);
>
> th->reload_context = false;
> }
> @@ -1009,35 +974,7 @@ windows_nat_target::windows_continue (DWORD
> continue_status, int id,
> for (auto &th : windows_process->thread_list)
> if (id == -1 || id == (int) th->tid)
> {
> - windows_process->with_context (th.get (), [&] (auto *context)
> - {
> - if (th->debug_registers_changed)
> - {
> - context->ContextFlags
> - |= WindowsContext<decltype(context)>::debug;
> - context->Dr0 = windows_process->dr[0];
> - context->Dr1 = windows_process->dr[1];
> - context->Dr2 = windows_process->dr[2];
> - context->Dr3 = windows_process->dr[3];
> - context->Dr6 = DR6_CLEAR_VALUE;
> - context->Dr7 = windows_process->dr[7];
> - th->debug_registers_changed = false;
> - }
> - if (context->ContextFlags)
> - {
> - DWORD ec = 0;
> -
> - if (GetExitCodeThread (th->h, &ec)
> - && ec == STILL_ACTIVE)
> - {
> - BOOL status = set_thread_context (th->h, context);
> -
> - if (!killed)
> - CHECK (status);
> - }
> - context->ContextFlags = 0;
> - }
> - });
> + thread_context_continue (th.get (), killed);
>
> th->resume ();
> }
> @@ -1153,10 +1090,7 @@ windows_nat_target::resume (ptid_t ptid, int
> step, enum gdb_signal sig)
> regcache *regcache = get_thread_regcache (inferior_thread ());
> struct gdbarch *gdbarch = regcache->arch ();
> fetch_registers (regcache, gdbarch_ps_regnum (gdbarch));
> - windows_process->with_context (th, [&] (auto *context)
> - {
> - context->EFlags |= FLAG_TRACE_BIT;
> - });
> + thread_context_step (th);
> }
>
> /* Allow continuing with the same signal that interrupted us.
> @@ -1536,15 +1470,12 @@ windows_nat_target::wait (ptid_t ptid, struct
> target_waitstatus *ourstatus, void
> windows_nat_target::do_initial_windows_stuff (DWORD pid, bool attaching)
> {
> - int i;
> struct inferior *inf;
>
> + initialize_windows_arch ();
> +
> windows_process->last_sig = GDB_SIGNAL_0;
> windows_process->open_process_used = 0;
> - for (i = 0;
> - i < sizeof (windows_process->dr) / sizeof (windows_process->dr[0]);
> - i++)
> - windows_process->dr[i] = 0;
> #ifdef __CYGWIN__
> windows_process->cygwin_load_start = 0;
> windows_process->cygwin_load_end = 0; @@ -1890,7 +1821,7 @@
> windows_nat_target::detach (inferior *inf, int from_tty)
>
> target_announce_detach (from_tty);
>
> - x86_cleanup_dregs ();
> + cleanup_windows_arch ();
> switch_to_no_thread ();
> detach_inferior (inf);
>
> @@ -2622,7 +2553,7 @@ void
> windows_nat_target::mourn_inferior ()
> {
> (void) windows_continue (DBG_CONTINUE, -1, 0, true);
> - x86_cleanup_dregs();
> + cleanup_windows_arch ();
> if (windows_process->open_process_used)
> {
> CHECK (CloseHandle (windows_process->handle)); @@ -2857,16 +2788,6
> @@ windows_nat_target::thread_name (struct thread_info *thr)
>
> INIT_GDB_FILE (windows_nat)
> {
> - x86_dr_low.set_control = cygwin_set_dr7;
> - x86_dr_low.set_addr = cygwin_set_dr;
> - x86_dr_low.get_addr = cygwin_get_dr;
> - x86_dr_low.get_status = cygwin_get_dr6;
> - x86_dr_low.get_control = cygwin_get_dr7;
> -
> - /* x86_dr_low.debug_register_length field is set by
> - calling x86_set_debug_register_length function
> - in processor windows specific native file. */
> -
> #ifdef __CYGWIN__
> cygwin_internal (CW_SET_DOS_FILE_WARNING, 0); #endif @@ -2956,61
> +2877,6 @@ Use \"%ps\" or \"%ps\" command to load executable/libraries
> directly."),
> }
> }
>
> -/* Hardware watchpoint support, adapted from go32-nat.c code. */
> -
> -/* Pass the address ADDR to the inferior in the I'th debug register.
> - Here we just store the address in dr array, the registers will be
> - actually set up when windows_continue is called. */
> -static void
> -cygwin_set_dr (int i, CORE_ADDR addr)
> -{
> - if (i < 0 || i > 3)
> - internal_error (_("Invalid register %d in cygwin_set_dr.\n"), i);
> - windows_process->dr[i] = addr;
> -
> - for (auto &th : windows_process->thread_list)
> - th->debug_registers_changed = true;
> -}
> -
> -/* Pass the value VAL to the inferior in the DR7 debug control
> - register. Here we just store the address in D_REGS, the watchpoint
> - will be actually set up in windows_wait. */
> -static void
> -cygwin_set_dr7 (unsigned long val)
> -{
> - windows_process->dr[7] = (CORE_ADDR) val;
> -
> - for (auto &th : windows_process->thread_list)
> - th->debug_registers_changed = true;
> -}
> -
> -/* Get the value of debug register I from the inferior. */
> -
> -static CORE_ADDR
> -cygwin_get_dr (int i)
> -{
> - return windows_process->dr[i];
> -}
> -
> -/* Get the value of the DR6 debug status register from the inferior.
> - Here we just return the value stored in dr[6]
> - by the last call to thread_rec for current_event.dwThreadId id. */
> -static unsigned long
> -cygwin_get_dr6 (void)
> -{
> - return (unsigned long) windows_process->dr[6]; -}
> -
> -/* Get the value of the DR7 debug status register from the inferior.
> - Here we just return the value stored in dr[7] by the last call to
> - thread_rec for current_event.dwThreadId id. */
> -
> -static unsigned long
> -cygwin_get_dr7 (void)
> -{
> - return (unsigned long) windows_process->dr[7]; -}
> -
> /* Determine if the thread referenced by "ptid" is alive
> by "polling" it. If WaitForSingleObject returns WAIT_OBJECT_0
> it means that the thread has died. Otherwise it is assumed to be alive. */
> diff --git a/gdb/windows-nat.h b/gdb/windows-nat.h index
> 03c358fac54..6553052f420 100644
> --- a/gdb/windows-nat.h
> +++ b/gdb/windows-nat.h
> @@ -54,8 +54,6 @@ struct windows_per_inferior : public
> windows_nat::windows_process_info
> void handle_unload_dll () override;
> bool handle_access_violation (const EXCEPTION_RECORD *rec) override;
>
> - uintptr_t dr[8] {};
> -
> int windows_initialization_done = 0;
>
> std::vector<std::unique_ptr<windows_thread_info>> thread_list; @@ -
> 183,6 +181,23 @@ struct windows_nat_target : public inf_child_target
> return serial_event_fd (m_wait_event);
> }
>
> +protected:
> +
> + /* Initialize arch-specific data for a new inferior (debug registers,
> + register mappings). */
> + virtual void initialize_windows_arch () = 0;
> + /* Cleanup arch-specific data after inferior exit. */ virtual void
> + cleanup_windows_arch () = 0;
> +
> + /* Reload the thread context. */
> + virtual void fill_thread_context (windows_thread_info *th) = 0;
> +
> + /* Prepare the thread context for continuing. */
> + virtual void thread_context_continue (windows_thread_info *th,
> + int killed) = 0;
> + /* Set the stepping bit in the thread context. */
> + virtual void thread_context_step (windows_thread_info *th) = 0;
> +
> private:
>
> windows_thread_info *add_thread (ptid_t ptid, HANDLE h, void *tlb, diff --
> git a/gdb/x86-windows-nat.c b/gdb/x86-windows-nat.c index
> d1f78a01255..88844e0675a 100644
> --- a/gdb/x86-windows-nat.c
> +++ b/gdb/x86-windows-nat.c
> @@ -18,22 +18,213 @@
> along with this program. If not, see <http://www.gnu.org/licenses/>. */
>
> #include "windows-nat.h"
> +#include "regcache.h"
> +#include "gdbarch.h"
>
> #include "x86-nat.h"
>
> +using namespace windows_nat;
> +
> +/* If we're not using the old Cygwin header file set, define the
> + following which never should have been in the generic Win32 API
> + headers in the first place since they were our own invention... */
> +#ifndef _GNU_H_WINDOWS_H enum
> + {
> + FLAG_TRACE_BIT = 0x100,
> + };
> +#endif
> +
> +#define DR6_CLEAR_VALUE 0xffff0ff0
> +
> +#define CHECK(x) check (x, __FILE__,__LINE__)
> +
> +static void
> +check (BOOL ok, const char *file, int line) {
Isn't the exact same function also available in windows-nat.c ?
Shouldn't we better share the code?
Christina
Intel Deutschland GmbH
Registered Address: Dornacher Straße 1, 85622 Feldkirchen, Germany
Tel: +49 89 991 430, www.intel.de
Managing Directors: Harry Demas, Jeffrey Schneiderman, Yin Chong Sorrell
Chairperson of the Supervisory Board: Nicole Lau
Registered Seat: Munich
Commercial Register: Amtsgericht München HRB 186928
^ permalink raw reply [flat|nested] 44+ messages in thread
* RE: [PATCH v2 06/11] Move x86 register code into x86-windows-nat.c
2026-01-17 13:36 ` [PATCH v2 06/11] Move x86 register " Hannes Domani
@ 2026-01-19 12:50 ` Schimpe, Christina
0 siblings, 0 replies; 44+ messages in thread
From: Schimpe, Christina @ 2026-01-19 12:50 UTC (permalink / raw)
To: Hannes Domani, gdb-patches
> -----Original Message-----
> From: Hannes Domani <ssbssa@yahoo.de>
> Sent: Samstag, 17. Januar 2026 14:36
> To: gdb-patches@sourceware.org
> Subject: [PATCH v2 06/11] Move x86 register code into x86-windows-nat.c
>
> ---
> Changes in v2:
> - updated comment for initialize_windows_arch() describing the ATTACHING
> argument
> ---
> gdb/windows-nat.c | 144 ++----------------------------------------
> gdb/windows-nat.h | 29 +++++++--
> gdb/x86-windows-nat.c | 137
> +++++++++++++++++++++++++++++++++++++++-
> 3 files changed, 163 insertions(+), 147 deletions(-)
>
> diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c index
> e1da956b125..926b85d479b 100644
> --- a/gdb/windows-nat.c
> +++ b/gdb/windows-nat.c
> @@ -57,9 +57,6 @@
> #include "xml-support.h"
> #include "inttypes.h"
>
> -#include "i386-tdep.h"
> -#include "i387-tdep.h"
> -
> #include "windows-tdep.h"
> #include "windows-nat.h"
> #include "complaints.h"
> @@ -389,79 +386,6 @@ windows_nat_target::delete_thread (ptid_t ptid,
> DWORD exit_code,
> windows_process->thread_list.erase (iter); }
>
> -/* Fetches register number R from the given windows_thread_info,
> - and supplies its value to the given regcache.
> -
> - This function assumes that R is non-negative. A failed assertion
> - is raised if that is not true.
> -
> - This function assumes that TH->RELOAD_CONTEXT is not set, meaning
> - that the windows_thread_info has an up-to-date context. A failed
> - assertion is raised if that assumption is violated. */
> -
> -static void
> -windows_fetch_one_register (struct regcache *regcache,
> - windows_thread_info *th, int r)
> -{
> - gdb_assert (r >= 0);
> - gdb_assert (!th->reload_context);
> -
> - char *context_ptr = windows_process->with_context (th, [] (auto *context)
> - {
> - return (char *) context;
> - });
> -
> - char *context_offset = context_ptr + windows_process->mappings[r];
> - struct gdbarch *gdbarch = regcache->arch ();
> - i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
> -
> - gdb_assert (!gdbarch_read_pc_p (gdbarch));
> - gdb_assert (gdbarch_pc_regnum (gdbarch) >= 0);
> - gdb_assert (!gdbarch_write_pc_p (gdbarch));
> -
> - /* GDB treats some registers as 32-bit, where they are in fact only
> - 16 bits long. These cases must be handled specially to avoid
> - reading extraneous bits from the context. */
> - if (r == I387_FISEG_REGNUM (tdep) || windows_process-
> >segment_register_p (r))
> - {
> - gdb_byte bytes[4] = {};
> - memcpy (bytes, context_offset, 2);
> - regcache->raw_supply (r, bytes);
> - }
> - else if (r == I387_FOP_REGNUM (tdep))
> - {
> - long l = (*((long *) context_offset) >> 16) & ((1 << 11) - 1);
> - regcache->raw_supply (r, &l);
> - }
> - else
> - {
> - if (th->stopped_at_software_breakpoint
> - && !th->pc_adjusted
> - && r == gdbarch_pc_regnum (gdbarch))
> - {
> - int size = register_size (gdbarch, r);
> - if (size == 4)
> - {
> - uint32_t value;
> - memcpy (&value, context_offset, size);
> - value -= gdbarch_decr_pc_after_break (gdbarch);
> - memcpy (context_offset, &value, size);
> - }
> - else
> - {
> - gdb_assert (size == 8);
> - uint64_t value;
> - memcpy (&value, context_offset, size);
> - value -= gdbarch_decr_pc_after_break (gdbarch);
> - memcpy (context_offset, &value, size);
> - }
> - /* Make sure we only rewrite the PC a single time. */
> - th->pc_adjusted = true;
> - }
> - regcache->raw_supply (r, context_offset);
> - }
> -}
> -
> void
> windows_nat_target::fetch_registers (struct regcache *regcache, int r) { @@
> -482,51 +406,9 @@ windows_nat_target::fetch_registers (struct regcache
> *regcache, int r)
>
> if (r < 0)
> for (r = 0; r < gdbarch_num_regs (regcache->arch()); r++)
> - windows_fetch_one_register (regcache, th, r);
> - else
> - windows_fetch_one_register (regcache, th, r);
> -}
> -
> -/* Collect the register number R from the given regcache, and store
> - its value into the corresponding area of the given thread's context.
> -
> - This function assumes that R is non-negative. A failed assertion
> - assertion is raised if that is not true. */
> -
> -static void
> -windows_store_one_register (const struct regcache *regcache,
> - windows_thread_info *th, int r)
> -{
> - gdb_assert (r >= 0);
> -
> - char *context_ptr = windows_process->with_context (th, [] (auto *context)
> - {
> - return (char *) context;
> - });
> -
> - struct gdbarch *gdbarch = regcache->arch ();
> - i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
> -
> - /* GDB treats some registers as 32-bit, where they are in fact only
> - 16 bits long. These cases must be handled specially to avoid
> - overwriting other registers in the context. */
> - if (r == I387_FISEG_REGNUM (tdep) || windows_process-
> >segment_register_p (r))
> - {
> - gdb_byte bytes[4];
> - regcache->raw_collect (r, bytes);
> - memcpy (context_ptr + windows_process->mappings[r], bytes, 2);
> - }
> - else if (r == I387_FOP_REGNUM (tdep))
> - {
> - gdb_byte bytes[4];
> - regcache->raw_collect (r, bytes);
> - /* The value of FOP occupies the top two bytes in the context,
> - so write the two low-order bytes from the cache into the
> - appropriate spot. */
> - memcpy (context_ptr + windows_process->mappings[r] + 2, bytes, 2);
> - }
> + fetch_one_register (regcache, th, r);
> else
> - regcache->raw_collect (r, context_ptr + windows_process->mappings[r]);
> + fetch_one_register (regcache, th, r);
> }
>
> /* Store a new register value into the context of the thread tied to @@ -
> 545,9 +427,9 @@ windows_nat_target::store_registers (struct regcache
> *regcache, int r)
>
> if (r < 0)
> for (r = 0; r < gdbarch_num_regs (regcache->arch ()); r++)
> - windows_store_one_register (regcache, th, r);
> + store_one_register (regcache, th, r);
> else
> - windows_store_one_register (regcache, th, r);
> + store_one_register (regcache, th, r);
> }
>
> bool
> @@ -1472,7 +1354,7 @@ windows_nat_target::do_initial_windows_stuff
> (DWORD pid, bool attaching) {
> struct inferior *inf;
>
> - initialize_windows_arch ();
> + initialize_windows_arch (attaching);
>
> windows_process->last_sig = GDB_SIGNAL_0;
> windows_process->open_process_used = 0; @@ -1490,22 +1372,6 @@
> windows_nat_target::do_initial_windows_stuff (DWORD pid, bool attaching)
> clear_proceed_status (0);
> init_wait_for_inferior ();
>
> -#ifdef __x86_64__
> - windows_process->ignore_first_breakpoint
> - = !attaching && windows_process->wow64_process;
> -
> - if (!windows_process->wow64_process)
> - {
> - windows_process->mappings = amd64_mappings;
> - windows_process->segment_register_p =
> amd64_windows_segment_register_p;
> - }
> - else
> -#endif
> - {
> - windows_process->mappings = i386_mappings;
> - windows_process->segment_register_p =
> i386_windows_segment_register_p;
> - }
> -
> inferior_appeared (inf, pid);
> inf->attach_flag = attaching;
>
> diff --git a/gdb/windows-nat.h b/gdb/windows-nat.h index
> 6553052f420..df872907535 100644
> --- a/gdb/windows-nat.h
> +++ b/gdb/windows-nat.h
> @@ -83,10 +83,6 @@ struct windows_per_inferior : public
> windows_nat::windows_process_info
>
> const int *mappings = nullptr;
>
> - /* The function to use in order to determine whether a register is
> - a segment register or not. */
> - segment_register_p_ftype *segment_register_p = nullptr;
> -
> std::vector<windows_solib> solibs;
>
> #ifdef __CYGWIN__
> @@ -184,8 +180,9 @@ struct windows_nat_target : public inf_child_target
> protected:
>
> /* Initialize arch-specific data for a new inferior (debug registers,
> - register mappings). */
> - virtual void initialize_windows_arch () = 0;
> + register mappings). If ATTACHING is true, we're attaching to an
> + already-running process. */
> + virtual void initialize_windows_arch (bool attaching) = 0;
> /* Cleanup arch-specific data after inferior exit. */
> virtual void cleanup_windows_arch () = 0;
>
> @@ -198,6 +195,26 @@ struct windows_nat_target : public inf_child_target
> /* Set the stepping bit in the thread context. */
> virtual void thread_context_step (windows_thread_info *th) = 0;
>
> + /* Fetches register number R from the given windows_thread_info,
> + and supplies its value to the given regcache.
> +
> + This function assumes that R is non-negative. A failed assertion
> + is raised if that is not true.
> +
> + This function assumes that TH->RELOAD_CONTEXT is not set, meaning
> + that the windows_thread_info has an up-to-date context. A failed
> + assertion is raised if that assumption is violated. */
> + virtual void fetch_one_register (struct regcache *regcache,
> + windows_thread_info *th, int r) = 0;
> +
> + /* Collect the register number R from the given regcache, and store
> + its value into the corresponding area of the given thread's context.
> +
> + This function assumes that R is non-negative. A failed assertion
> + assertion is raised if that is not true. */
> + virtual void store_one_register (const struct regcache *regcache,
> + windows_thread_info *th, int r) = 0;
> +
> private:
>
> windows_thread_info *add_thread (ptid_t ptid, HANDLE h, void *tlb, diff --
> git a/gdb/x86-windows-nat.c b/gdb/x86-windows-nat.c index
> 88844e0675a..96dd61b39fb 100644
> --- a/gdb/x86-windows-nat.c
> +++ b/gdb/x86-windows-nat.c
> @@ -23,6 +23,9 @@
>
> #include "x86-nat.h"
>
> +#include "i386-tdep.h"
> +#include "i387-tdep.h"
> +
> using namespace windows_nat;
>
> /* If we're not using the old Cygwin header file set, define the @@ -53,17
> +56,26 @@ check (BOOL ok, const char *file, int line) struct
> x86_windows_per_inferior : public windows_per_inferior {
> uintptr_t dr[8] {};
> +
> + /* The function to use in order to determine whether a register is
> + a segment register or not. */
> + segment_register_p_ftype *segment_register_p = nullptr;
> };
>
> struct x86_windows_nat_target final : public
> x86_nat_target<windows_nat_target>
> {
> - void initialize_windows_arch () override;
> + void initialize_windows_arch (bool attaching) override;
> void cleanup_windows_arch () override;
>
> void fill_thread_context (windows_thread_info *th) override;
>
> void thread_context_continue (windows_thread_info *th, int killed)
> override;
> void thread_context_step (windows_thread_info *th) override;
> +
> + void fetch_one_register (struct regcache *regcache,
> + windows_thread_info *th, int r) override;
> + void store_one_register (const struct regcache *regcache,
> + windows_thread_info *th, int r) override;
> };
>
> /* The current process. */
> @@ -72,9 +84,25 @@ static x86_windows_per_inferior
> x86_windows_process;
> /* See windows-nat.h. */
>
> void
> -x86_windows_nat_target::initialize_windows_arch ()
> +x86_windows_nat_target::initialize_windows_arch (bool attaching)
> {
> memset (x86_windows_process.dr, 0, sizeof (x86_windows_process.dr));
> +
> +#ifdef __x86_64__
> + x86_windows_process.ignore_first_breakpoint
> + = !attaching && x86_windows_process.wow64_process;
> +
> + if (!x86_windows_process.wow64_process)
> + {
> + x86_windows_process.mappings = amd64_mappings;
> + x86_windows_process.segment_register_p =
> amd64_windows_segment_register_p;
> + }
> + else
> +#endif
> + {
> + x86_windows_process.mappings = i386_mappings;
> + x86_windows_process.segment_register_p =
> i386_windows_segment_register_p;
> + }
> }
> + {
> + x86_windows_process.mappings = i386_mappings;
> + x86_windows_process.segment_register_p =
> i386_windows_segment_register_p;
> + }
>
> /* See windows-nat.h. */
> @@ -158,6 +186,111 @@ x86_windows_nat_target::thread_context_step
> (windows_thread_info *th)
> });
> }
>
> +/* See windows-nat.h. */
> +
> +void
> +x86_windows_nat_target::fetch_one_register (struct regcache *regcache,
> + windows_thread_info *th, int r) {
> + gdb_assert (r >= 0);
> + gdb_assert (!th->reload_context);
> + char *context_ptr = x86_windows_process.with_context (th, [] (auto
> *context)
> + {
> + return (char *) context;
> + });
> +
> + char *context_offset = context_ptr + x86_windows_process.mappings[r];
> + struct gdbarch *gdbarch = regcache->arch (); i386_gdbarch_tdep *tdep
> + = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
> +
> + gdb_assert (!gdbarch_read_pc_p (gdbarch)); gdb_assert
> + (gdbarch_pc_regnum (gdbarch) >= 0); gdb_assert (!gdbarch_write_pc_p
> + (gdbarch));
> +
> + /* GDB treats some registers as 32-bit, where they are in fact only
> + 16 bits long. These cases must be handled specially to avoid
> + reading extraneous bits from the context. */
> + if (r == I387_FISEG_REGNUM (tdep)
> + || x86_windows_process.segment_register_p (r))
> + {
> + gdb_byte bytes[4] = {};
> + memcpy (bytes, context_offset, 2);
> + regcache->raw_supply (r, bytes);
> + }
> + else if (r == I387_FOP_REGNUM (tdep))
> + {
> + long l = (*((long *) context_offset) >> 16) & ((1 << 11) - 1);
> + regcache->raw_supply (r, &l);
> + }
> + else
> + {
> + if (th->stopped_at_software_breakpoint
> + && !th->pc_adjusted
> + && r == gdbarch_pc_regnum (gdbarch))
> + {
> + int size = register_size (gdbarch, r);
> + if (size == 4)
> + {
> + uint32_t value;
> + memcpy (&value, context_offset, size);
> + value -= gdbarch_decr_pc_after_break (gdbarch);
> + memcpy (context_offset, &value, size);
> + }
> + else
> + {
> + gdb_assert (size == 8);
> + uint64_t value;
> + memcpy (&value, context_offset, size);
> + value -= gdbarch_decr_pc_after_break (gdbarch);
> + memcpy (context_offset, &value, size);
> + }
> + /* Make sure we only rewrite the PC a single time. */
> + th->pc_adjusted = true;
> + }
> + regcache->raw_supply (r, context_offset);
> + }
> +}
> +
> +/* See windows-nat.h. */
> +
> +void
> +x86_windows_nat_target::store_one_register (const struct regcache
> *regcache,
> + windows_thread_info *th, int r) {
> + gdb_assert (r >= 0);
> +
> + char *context_ptr = x86_windows_process.with_context (th, [] (auto
> *context)
> + {
> + return (char *) context;
> + });
> +
> + struct gdbarch *gdbarch = regcache->arch (); i386_gdbarch_tdep *tdep
> + = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
> +
> + /* GDB treats some registers as 32-bit, where they are in fact only
> + 16 bits long. These cases must be handled specially to avoid
> + overwriting other registers in the context. */
> + if (r == I387_FISEG_REGNUM (tdep)
> + || x86_windows_process.segment_register_p (r))
> + {
> + gdb_byte bytes[4];
> + regcache->raw_collect (r, bytes);
> + memcpy (context_ptr + x86_windows_process.mappings[r], bytes, 2);
> + }
> + else if (r == I387_FOP_REGNUM (tdep))
> + {
> + gdb_byte bytes[4];
> + regcache->raw_collect (r, bytes);
> + /* The value of FOP occupies the top two bytes in the context,
> + so write the two low-order bytes from the cache into the
> + appropriate spot. */
> + memcpy (context_ptr + x86_windows_process.mappings[r] + 2, bytes,
> 2);
> + }
> + else
> + regcache->raw_collect (r, context_ptr +
> +x86_windows_process.mappings[r]); }
> +
> /* Hardware watchpoint support, adapted from go32-nat.c code. */
>
> /* Pass the address ADDR to the inferior in the I'th debug register.
> --
> 2.52.0
>
This looks good to me, but I don't have much experience on windows.
Due to that and because this patch also contains files which are not x86 specific,
I'll add my reviewed-by tag (and not the approved-by tag).
Reviewed-By: Christina Schimpe <christina.schimpe@intel.com>
Christina
Intel Deutschland GmbH
Registered Address: Dornacher Straße 1, 85622 Feldkirchen, Germany
Tel: +49 89 991 430, www.intel.de
Managing Directors: Harry Demas, Jeffrey Schneiderman, Yin Chong Sorrell
Chairperson of the Supervisory Board: Nicole Lau
Registered Seat: Munich
Commercial Register: Amtsgericht München HRB 186928
^ permalink raw reply [flat|nested] 44+ messages in thread
* RE: [PATCH v2 08/11] Move software breakpoint recognition code into x86-windows-nat.c
2026-01-17 13:36 ` [PATCH v2 08/11] Move software breakpoint recognition " Hannes Domani
@ 2026-01-19 12:51 ` Schimpe, Christina
2026-01-21 15:43 ` Tom Tromey
0 siblings, 1 reply; 44+ messages in thread
From: Schimpe, Christina @ 2026-01-19 12:51 UTC (permalink / raw)
To: Hannes Domani, gdb-patches; +Cc: Tom Tromey
> -----Original Message-----
> From: Hannes Domani <ssbssa@yahoo.de>
> Sent: Samstag, 17. Januar 2026 14:36
> To: gdb-patches@sourceware.org
> Cc: Tom Tromey <tom@tromey.com>
> Subject: [PATCH v2 08/11] Move software breakpoint recognition code into
> x86-windows-nat.c
>
> Approved-By: Tom Tromey <tom@tromey.com>
> ---
> Changes in v2:
> - changed EXCEPTION_RECORD to ER in comment
> ---
> gdb/windows-nat.c | 11 +++--------
> gdb/windows-nat.h | 3 +++
> gdb/x86-windows-nat.c | 11 +++++++++++
> 3 files changed, 17 insertions(+), 8 deletions(-)
>
> diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c index
> f9d07336cca..3ed34087bf9 100644
> --- a/gdb/windows-nat.c
> +++ b/gdb/windows-nat.c
> @@ -1147,10 +1147,7 @@
> windows_nat_target::get_windows_debug_event
> thread_id, windows_process->desired_stop_thread_id);
>
> if (current_event->dwDebugEventCode == EXCEPTION_DEBUG_EVENT
> - && ((current_event->u.Exception.ExceptionRecord.ExceptionCode
> - == EXCEPTION_BREAKPOINT)
> - || (current_event->u.Exception.ExceptionRecord.ExceptionCode
> - == STATUS_WX86_BREAKPOINT))
> + && is_sw_breakpoint (¤t_event-
> >u.Exception.ExceptionRecord)
> && windows_process->windows_initialization_done)
> {
> ptid_t ptid = ptid_t (current_event->dwProcessId, thread_id, 0); @@
> -1201,10 +1198,8 @@ windows_nat_target::wait (ptid_t ptid, struct
> target_waitstatus *ourstatus,
> th->stopped_at_software_breakpoint = false;
> if (windows_process->current_event.dwDebugEventCode
> == EXCEPTION_DEBUG_EVENT
> - && ((windows_process-
> >current_event.u.Exception.ExceptionRecord.ExceptionCode
> - == EXCEPTION_BREAKPOINT)
> - || (windows_process-
> >current_event.u.Exception.ExceptionRecord.ExceptionCode
> - == STATUS_WX86_BREAKPOINT))
> + && is_sw_breakpoint (&windows_process->current_event
> + .u.Exception.ExceptionRecord)
> && windows_process->windows_initialization_done)
> {
> th->stopped_at_software_breakpoint = true; diff --git
> a/gdb/windows-nat.h b/gdb/windows-nat.h index
> df872907535..9257211dfd2 100644
> --- a/gdb/windows-nat.h
> +++ b/gdb/windows-nat.h
> @@ -215,6 +215,9 @@ struct windows_nat_target : public inf_child_target
> virtual void store_one_register (const struct regcache *regcache,
> windows_thread_info *th, int r) = 0;
>
> + /* Determine if ER contains a software-breakpoint. */ virtual bool
> + is_sw_breakpoint (EXCEPTION_RECORD *er) = 0;
Nit: Shouldn't this better be "const EXCEPTION_RECORD *er" ?
Otherwise, this LGTM.
Reviewed-By: Christina Schimpe <christina.schimpe@intel.com>
Christina
Intel Deutschland GmbH
Registered Address: Dornacher Straße 1, 85622 Feldkirchen, Germany
Tel: +49 89 991 430, www.intel.de
Managing Directors: Harry Demas, Jeffrey Schneiderman, Yin Chong Sorrell
Chairperson of the Supervisory Board: Nicole Lau
Registered Seat: Munich
Commercial Register: Amtsgericht München HRB 186928
^ permalink raw reply [flat|nested] 44+ messages in thread
* RE: [PATCH v2 02/11] Simplify windows_nat_target::resume
2026-01-17 13:36 ` [PATCH v2 02/11] Simplify windows_nat_target::resume Hannes Domani
@ 2026-01-19 13:55 ` Schimpe, Christina
2026-01-21 15:42 ` Tom Tromey
2026-01-23 19:11 ` Hannes Domani
0 siblings, 2 replies; 44+ messages in thread
From: Schimpe, Christina @ 2026-01-19 13:55 UTC (permalink / raw)
To: Hannes Domani, gdb-patches; +Cc: Tom Tromey
> -----Original Message-----
> From: Hannes Domani <ssbssa@yahoo.de>
> Sent: Samstag, 17. Januar 2026 14:36
> To: gdb-patches@sourceware.org
> Cc: Tom Tromey <tom@tromey.com>
> Subject: [PATCH v2 02/11] Simplify windows_nat_target::resume
>
> Now the thread context is only needed for setting the trace bit, so move the
> rest out of the with_context lambda.
>
> Approved-By: Tom Tromey <tom@tromey.com>
> ---
> No changes in v2
> ---
> gdb/windows-nat.c | 15 ++++++---------
> 1 file changed, 6 insertions(+), 9 deletions(-)
>
> diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c index
> a6fd199530c..8ee52768cb1 100644
> --- a/gdb/windows-nat.c
> +++ b/gdb/windows-nat.c
> @@ -1366,18 +1366,15 @@ windows_nat_target::resume (ptid_t ptid, int
> step, enum gdb_signal sig)
>
> /* Get context for currently selected thread. */
> th = windows_process.thread_rec (inferior_ptid,
> DONT_INVALIDATE_CONTEXT);
> - if (th)
> + if (th && step)
Nit: better to check th != nullptr here explicitly.
LGTM otherwise.
Reviewed-By: Christina Schimpe <christina.schimpe@intel.com>
Christina
Intel Deutschland GmbH
Registered Address: Dornacher Straße 1, 85622 Feldkirchen, Germany
Tel: +49 89 991 430, www.intel.de
Managing Directors: Harry Demas, Jeffrey Schneiderman, Yin Chong Sorrell
Chairperson of the Supervisory Board: Nicole Lau
Registered Seat: Munich
Commercial Register: Amtsgericht München HRB 186928
^ permalink raw reply [flat|nested] 44+ messages in thread
* RE: [PATCH v2 07/11] Move x86 selector code into x86-windows-nat.c
2026-01-17 13:36 ` [PATCH v2 07/11] Move x86 selector " Hannes Domani
@ 2026-01-19 13:56 ` Schimpe, Christina
0 siblings, 0 replies; 44+ messages in thread
From: Schimpe, Christina @ 2026-01-19 13:56 UTC (permalink / raw)
To: Hannes Domani, gdb-patches; +Cc: Tom Tromey
> -----Original Message-----
> From: Hannes Domani <ssbssa@yahoo.de>
> Sent: Samstag, 17. Januar 2026 14:36
> To: gdb-patches@sourceware.org
> Cc: Tom Tromey <tom@tromey.com>
> Subject: [PATCH v2 07/11] Move x86 selector code into x86-windows-nat.c
>
> Approved-By: Tom Tromey <tom@tromey.com>
> ---
> No changes in v2
> ---
> gdb/windows-nat.c | 125 -----------------------------------------
> gdb/x86-windows-nat.c | 127
> ++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 127 insertions(+), 125 deletions(-)
>
> diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c index
> 926b85d479b..f9d07336cca 100644
> --- a/gdb/windows-nat.c
> +++ b/gdb/windows-nat.c
> @@ -685,127 +685,6 @@
> windows_per_inferior::handle_output_debug_string
> return retval;
> }
>
> -static int
> -display_selector (HANDLE thread, DWORD sel) -{
> - LDT_ENTRY info;
> - BOOL ret = windows_process->with_context (nullptr, [&] (auto *context)
> - {
> - return get_thread_selector_entry (context, thread, sel, &info);
> - });
> - if (ret)
> - {
> - int base, limit;
> - gdb_printf ("0x%03x: ", (unsigned) sel);
> - if (!info.HighWord.Bits.Pres)
> - {
> - gdb_puts ("Segment not present\n");
> - return 0;
> - }
> - base = (info.HighWord.Bits.BaseHi << 24) +
> - (info.HighWord.Bits.BaseMid << 16)
> - + info.BaseLow;
> - limit = (info.HighWord.Bits.LimitHi << 16) + info.LimitLow;
> - if (info.HighWord.Bits.Granularity)
> - limit = (limit << 12) | 0xfff;
> - gdb_printf ("base=0x%08x limit=0x%08x", base, limit);
> - if (info.HighWord.Bits.Default_Big)
> - gdb_puts(" 32-bit ");
> - else
> - gdb_puts(" 16-bit ");
> - switch ((info.HighWord.Bits.Type & 0xf) >> 1)
> - {
> - case 0:
> - gdb_puts ("Data (Read-Only, Exp-up");
> - break;
> - case 1:
> - gdb_puts ("Data (Read/Write, Exp-up");
> - break;
> - case 2:
> - gdb_puts ("Unused segment (");
> - break;
> - case 3:
> - gdb_puts ("Data (Read/Write, Exp-down");
> - break;
> - case 4:
> - gdb_puts ("Code (Exec-Only, N.Conf");
> - break;
> - case 5:
> - gdb_puts ("Code (Exec/Read, N.Conf");
> - break;
> - case 6:
> - gdb_puts ("Code (Exec-Only, Conf");
> - break;
> - case 7:
> - gdb_puts ("Code (Exec/Read, Conf");
> - break;
> - default:
> - gdb_printf ("Unknown type 0x%lx",
> - (unsigned long) info.HighWord.Bits.Type);
> - }
> - if ((info.HighWord.Bits.Type & 0x1) == 0)
> - gdb_puts(", N.Acc");
> - gdb_puts (")\n");
> - if ((info.HighWord.Bits.Type & 0x10) == 0)
> - gdb_puts("System selector ");
> - gdb_printf ("Privilege level = %ld. ",
> - (unsigned long) info.HighWord.Bits.Dpl);
> - if (info.HighWord.Bits.Granularity)
> - gdb_puts ("Page granular.\n");
> - else
> - gdb_puts ("Byte granular.\n");
> - return 1;
> - }
> - else
> - {
> - DWORD err = GetLastError ();
> - if (err == ERROR_NOT_SUPPORTED)
> - gdb_printf ("Function not supported\n");
> - else
> - gdb_printf ("Invalid selector 0x%x.\n", (unsigned) sel);
> - return 0;
> - }
> -}
> -
> -static void
> -display_selectors (const char * args, int from_tty) -{
> - if (inferior_ptid == null_ptid)
> - {
> - gdb_puts ("Impossible to display selectors now.\n");
> - return;
> - }
> -
> - windows_thread_info *current_windows_thread
> - = windows_process->thread_rec (inferior_ptid,
> DONT_INVALIDATE_CONTEXT);
> -
> - if (!args)
> - {
> - windows_process->with_context (current_windows_thread, [&] (auto
> *context)
> - {
> - gdb_puts ("Selector $cs\n");
> - display_selector (current_windows_thread->h, context->SegCs);
> - gdb_puts ("Selector $ds\n");
> - display_selector (current_windows_thread->h, context->SegDs);
> - gdb_puts ("Selector $es\n");
> - display_selector (current_windows_thread->h, context->SegEs);
> - gdb_puts ("Selector $ss\n");
> - display_selector (current_windows_thread->h, context->SegSs);
> - gdb_puts ("Selector $fs\n");
> - display_selector (current_windows_thread->h, context->SegFs);
> - gdb_puts ("Selector $gs\n");
> - display_selector (current_windows_thread->h, context->SegGs);
> - });
> - }
> - else
> - {
> - int sel;
> - sel = parse_and_eval_long (args);
> - gdb_printf ("Selector \"%s\"\n",args);
> - display_selector (current_windows_thread->h, sel);
> - }
> -}
> -
> /* See nat/windows-nat.h. */
>
> bool
> @@ -2727,10 +2606,6 @@ Show whether to display kernel exceptions in
> child process."), NULL,
>
> init_w32_command_list ();
>
> - add_cmd ("selector", class_info, display_selectors,
> - _("Display selectors infos."),
> - &info_w32_cmdlist);
> -
> if (!initialize_loadable ())
> {
> /* This will probably fail on Windows 9x/Me. Let the user know diff --git
> a/gdb/x86-windows-nat.c b/gdb/x86-windows-nat.c index
> 96dd61b39fb..7538c360bfe 100644
> --- a/gdb/x86-windows-nat.c
> +++ b/gdb/x86-windows-nat.c
> @@ -17,9 +17,11 @@
> You should have received a copy of the GNU General Public License
> along with this program. If not, see <http://www.gnu.org/licenses/>. */
>
> +#include "windows-tdep.h"
> #include "windows-nat.h"
> #include "regcache.h"
> #include "gdbarch.h"
> +#include "inferior.h"
>
> #include "x86-nat.h"
>
> @@ -346,6 +348,127 @@ cygwin_get_dr7 (void)
> return (unsigned long) x86_windows_process.dr[7]; }
>
> +static int
> +display_selector (HANDLE thread, DWORD sel) {
> + LDT_ENTRY info;
> + BOOL ret = windows_process->with_context (nullptr, [&] (auto *context)
> + {
> + return get_thread_selector_entry (context, thread, sel, &info);
> + });
> + if (ret)
> + {
> + int base, limit;
> + gdb_printf ("0x%03x: ", (unsigned) sel);
> + if (!info.HighWord.Bits.Pres)
> + {
> + gdb_puts ("Segment not present\n");
> + return 0;
> + }
> + base = (info.HighWord.Bits.BaseHi << 24) +
> + (info.HighWord.Bits.BaseMid << 16)
> + + info.BaseLow;
> + limit = (info.HighWord.Bits.LimitHi << 16) + info.LimitLow;
> + if (info.HighWord.Bits.Granularity)
> + limit = (limit << 12) | 0xfff;
> + gdb_printf ("base=0x%08x limit=0x%08x", base, limit);
> + if (info.HighWord.Bits.Default_Big)
> + gdb_puts(" 32-bit ");
> + else
> + gdb_puts(" 16-bit ");
> + switch ((info.HighWord.Bits.Type & 0xf) >> 1)
> + {
> + case 0:
> + gdb_puts ("Data (Read-Only, Exp-up");
> + break;
> + case 1:
> + gdb_puts ("Data (Read/Write, Exp-up");
> + break;
> + case 2:
> + gdb_puts ("Unused segment (");
> + break;
> + case 3:
> + gdb_puts ("Data (Read/Write, Exp-down");
> + break;
> + case 4:
> + gdb_puts ("Code (Exec-Only, N.Conf");
> + break;
> + case 5:
> + gdb_puts ("Code (Exec/Read, N.Conf");
> + break;
> + case 6:
> + gdb_puts ("Code (Exec-Only, Conf");
> + break;
> + case 7:
> + gdb_puts ("Code (Exec/Read, Conf");
> + break;
> + default:
> + gdb_printf ("Unknown type 0x%lx",
> + (unsigned long) info.HighWord.Bits.Type);
> + }
> + if ((info.HighWord.Bits.Type & 0x1) == 0)
> + gdb_puts(", N.Acc");
> + gdb_puts (")\n");
> + if ((info.HighWord.Bits.Type & 0x10) == 0)
> + gdb_puts("System selector ");
> + gdb_printf ("Privilege level = %ld. ",
> + (unsigned long) info.HighWord.Bits.Dpl);
> + if (info.HighWord.Bits.Granularity)
> + gdb_puts ("Page granular.\n");
> + else
> + gdb_puts ("Byte granular.\n");
> + return 1;
> + }
> + else
> + {
> + DWORD err = GetLastError ();
> + if (err == ERROR_NOT_SUPPORTED)
> + gdb_printf ("Function not supported\n");
> + else
> + gdb_printf ("Invalid selector 0x%x.\n", (unsigned) sel);
> + return 0;
> + }
> +}
> +
> +static void
> +display_selectors (const char * args, int from_tty) {
> + if (inferior_ptid == null_ptid)
> + {
> + gdb_puts ("Impossible to display selectors now.\n");
> + return;
> + }
> +
> + windows_thread_info *current_windows_thread
> + = windows_process->thread_rec (inferior_ptid,
> + DONT_INVALIDATE_CONTEXT);
> +
> + if (!args)
> + {
> + windows_process->with_context (current_windows_thread, [&] (auto
> *context)
> + {
> + gdb_puts ("Selector $cs\n");
> + display_selector (current_windows_thread->h, context->SegCs);
> + gdb_puts ("Selector $ds\n");
> + display_selector (current_windows_thread->h, context->SegDs);
> + gdb_puts ("Selector $es\n");
> + display_selector (current_windows_thread->h, context->SegEs);
> + gdb_puts ("Selector $ss\n");
> + display_selector (current_windows_thread->h, context->SegSs);
> + gdb_puts ("Selector $fs\n");
> + display_selector (current_windows_thread->h, context->SegFs);
> + gdb_puts ("Selector $gs\n");
> + display_selector (current_windows_thread->h, context->SegGs);
> + });
> + }
> + else
> + {
> + int sel;
> + sel = parse_and_eval_long (args);
> + gdb_printf ("Selector \"%s\"\n",args);
> + display_selector (current_windows_thread->h, sel);
> + }
> +}
> +
> INIT_GDB_FILE (x86_windows_nat)
> {
> x86_dr_low.set_control = cygwin_set_dr7; @@ -363,4 +486,8 @@
> INIT_GDB_FILE (x86_windows_nat)
> add_inf_child_target (new x86_windows_nat_target);
>
> windows_process = &x86_windows_process;
> +
> + add_cmd ("selector", class_info, display_selectors,
> + _("Display selectors infos."),
> + &info_w32_cmdlist);
> }
> --
> 2.52.0
>
LGTM.
Reviewed-By: Christina Schimpe <christina.schimpe@intel.com>
Christina
Intel Deutschland GmbH
Registered Address: Dornacher Straße 1, 85622 Feldkirchen, Germany
Tel: +49 89 991 430, www.intel.de
Managing Directors: Harry Demas, Jeffrey Schneiderman, Yin Chong Sorrell
Chairperson of the Supervisory Board: Nicole Lau
Registered Seat: Munich
Commercial Register: Amtsgericht München HRB 186928
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [PATCH v2 05/11] Move x86 debug registers and related code into x86-windows-nat.c
2026-01-19 12:49 ` Schimpe, Christina
@ 2026-01-20 15:49 ` Hannes Domani
2026-01-21 8:06 ` Schimpe, Christina
0 siblings, 1 reply; 44+ messages in thread
From: Hannes Domani @ 2026-01-20 15:49 UTC (permalink / raw)
To: gdb-patches, Schimpe, Christina, Tom Tromey
Am Montag, 19. Januar 2026 um 13:49:30 MEZ hat Schimpe, Christina <christina.schimpe@intel.com> Folgendes geschrieben:
> > --- a/gdb/x86-windows-nat.c
> > +++ b/gdb/x86-windows-nat.c
> > @@ -18,22 +18,213 @@
> > along with this program. If not, see <http://www.gnu.org/licenses/>. */
> >
> > #include "windows-nat.h"
> > +#include "regcache.h"
> > +#include "gdbarch.h"
> >
> > #include "x86-nat.h"
> >
> > +using namespace windows_nat;
> > +
> > +/* If we're not using the old Cygwin header file set, define the
> > + following which never should have been in the generic Win32 API
> > + headers in the first place since they were our own invention... */
> > +#ifndef _GNU_H_WINDOWS_H enum
> > + {
> > + FLAG_TRACE_BIT = 0x100,
> > + };
> > +#endif
> > +
> > +#define DR6_CLEAR_VALUE 0xffff0ff0
> > +
> > +#define CHECK(x) check (x, __FILE__,__LINE__)
> > +
> > +static void
> > +check (BOOL ok, const char *file, int line) {
>
> Isn't the exact same function also available in windows-nat.c ?
> Shouldn't we better share the code?
You're right, I forgot that I copied that function, I wonder if I should
make it a (static) windows_nat_target member.
And should I move the CHECK define to windows-nat.h as well?
Hannes
^ permalink raw reply [flat|nested] 44+ messages in thread
* RE: [PATCH v2 05/11] Move x86 debug registers and related code into x86-windows-nat.c
2026-01-20 15:49 ` Hannes Domani
@ 2026-01-21 8:06 ` Schimpe, Christina
0 siblings, 0 replies; 44+ messages in thread
From: Schimpe, Christina @ 2026-01-21 8:06 UTC (permalink / raw)
To: Hannes Domani, gdb-patches, Tom Tromey
> -----Original Message-----
> From: Hannes Domani <ssbssa@yahoo.de>
> Sent: Dienstag, 20. Januar 2026 16:50
> To: gdb-patches@sourceware.org; Schimpe, Christina
> <christina.schimpe@intel.com>; Tom Tromey <tom@tromey.com>
> Subject: Re: [PATCH v2 05/11] Move x86 debug registers and related code
> into x86-windows-nat.c
>
> Am Montag, 19. Januar 2026 um 13:49:30 MEZ hat Schimpe, Christina
> <christina.schimpe@intel.com> Folgendes geschrieben:
>
> > > --- a/gdb/x86-windows-nat.c
> > > +++ b/gdb/x86-windows-nat.c
> > > @@ -18,22 +18,213 @@
> > > along with this program. If not, see
> > ><http://www.gnu.org/licenses/>. */
> > >
> > > #include "windows-nat.h"
> > > +#include "regcache.h"
> > > +#include "gdbarch.h"
> > >
> > > #include "x86-nat.h"
> > >
> > > +using namespace windows_nat;
> > > +
> > > +/* If we're not using the old Cygwin header file set, define the
> > > + following which never should have been in the generic Win32 API
> > > + headers in the first place since they were our own invention...
> > > +*/ #ifndef _GNU_H_WINDOWS_H enum
> > > + {
> > > + FLAG_TRACE_BIT = 0x100,
> > > + };
> > > +#endif
> > > +
> > > +#define DR6_CLEAR_VALUE 0xffff0ff0
> > > +
> > > +#define CHECK(x) check (x, __FILE__,__LINE__)
> > > +
> > > +static void
> > > +check (BOOL ok, const char *file, int line) {
> >
> > Isn't the exact same function also available in windows-nat.c ?
> > Shouldn't we better share the code?
>
> You're right, I forgot that I copied that function, I wonder if I should make it a
> (static) windows_nat_target member.
I'd have preferred a free function, or what's the benefit of making it a static member ?
> And should I move the CHECK define to windows-nat.h as well?
I think that would make sense.
Christina
Intel Deutschland GmbH
Registered Address: Dornacher Straße 1, 85622 Feldkirchen, Germany
Tel: +49 89 991 430, www.intel.de
Managing Directors: Harry Demas, Jeffrey Schneiderman, Yin Chong Sorrell
Chairperson of the Supervisory Board: Nicole Lau
Registered Seat: Munich
Commercial Register: Amtsgericht München HRB 186928
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [PATCH v2 04/11] Create x86-windows-nat.c
2026-01-17 13:36 ` [PATCH v2 04/11] Create x86-windows-nat.c Hannes Domani
@ 2026-01-21 15:38 ` Tom Tromey
0 siblings, 0 replies; 44+ messages in thread
From: Tom Tromey @ 2026-01-21 15:38 UTC (permalink / raw)
To: Hannes Domani; +Cc: gdb-patches
>>>>> "Hannes" == Hannes Domani <ssbssa@yahoo.de> writes:
Hannes> Also creates the x86_windows_per_inferior and x86_windows_nat_target
Hannes> derived classes in there which will then hold the arch-specific data and
Hannes> function overrides.
Looks good, thank you.
Approved-By: Tom Tromey <tom@tromey.com>
Tom
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [PATCH v2 02/11] Simplify windows_nat_target::resume
2026-01-19 13:55 ` Schimpe, Christina
@ 2026-01-21 15:42 ` Tom Tromey
2026-01-23 19:11 ` Hannes Domani
1 sibling, 0 replies; 44+ messages in thread
From: Tom Tromey @ 2026-01-21 15:42 UTC (permalink / raw)
To: Schimpe, Christina; +Cc: Hannes Domani, gdb-patches, Tom Tromey
>> - if (th)
>> + if (th && step)
> Nit: better to check th != nullptr here explicitly.
Thanks for catching that.
Tom
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [PATCH v2 08/11] Move software breakpoint recognition code into x86-windows-nat.c
2026-01-19 12:51 ` Schimpe, Christina
@ 2026-01-21 15:43 ` Tom Tromey
2026-01-23 19:12 ` Hannes Domani
0 siblings, 1 reply; 44+ messages in thread
From: Tom Tromey @ 2026-01-21 15:43 UTC (permalink / raw)
To: Schimpe, Christina; +Cc: Hannes Domani, gdb-patches, Tom Tromey
>>>>> Schimpe, Christina <christina.schimpe@intel.com> writes:
>> + is_sw_breakpoint (EXCEPTION_RECORD *er) = 0;
> Nit: Shouldn't this better be "const EXCEPTION_RECORD *er" ?
I guess if we're doing that we should consider
is_sw_breakpoint (const EXCEPTION_RECORD *er) const = 0;
since presumably this method isn't mutating *this.
Tom
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [PATCH v2 10/11] Move setting size of long to windows-tdep
2026-01-17 13:36 ` [PATCH v2 10/11] Move setting size of long " Hannes Domani
@ 2026-01-21 15:47 ` Tom Tromey
0 siblings, 0 replies; 44+ messages in thread
From: Tom Tromey @ 2026-01-21 15:47 UTC (permalink / raw)
To: Hannes Domani; +Cc: gdb-patches
>>>>> "Hannes" == Hannes Domani <ssbssa@yahoo.de> writes:
Hannes> It's 32bit for all (non-cygwin) Windows ABIs.
Thank you.
Approved-By: Tom Tromey <tom@tromey.com>
Tom
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [PATCH v2 09/11] Move auto_wide_charset gdbarch method to windows-tdep
2026-01-17 13:54 ` [PATCH v2 09/11] Move auto_wide_charset gdbarch method to windows-tdep Hannes Domani
@ 2026-01-21 15:48 ` Tom Tromey
2026-01-23 19:13 ` Hannes Domani
0 siblings, 1 reply; 44+ messages in thread
From: Tom Tromey @ 2026-01-21 15:48 UTC (permalink / raw)
To: Hannes Domani; +Cc: gdb-patches
>>>>> "Hannes" == Hannes Domani <ssbssa@yahoo.de> writes:
Hannes> It's the same for all Windows ABIs.
Thank you.
Hannes> +static const char *
Hannes> +windows_auto_wide_charset (void)
Please remove the 'void' from this line.
Ok with this change.
Approved-By: Tom Tromey <tom@tromey.com>
Tom
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [PATCH v2 10/11] Move setting size of long to windows-tdep
2026-01-17 13:54 ` [PATCH v2 10/11] Move setting size of long " Hannes Domani
@ 2026-01-21 15:59 ` Tom Tromey
0 siblings, 0 replies; 44+ messages in thread
From: Tom Tromey @ 2026-01-21 15:59 UTC (permalink / raw)
To: Hannes Domani; +Cc: gdb-patches
>>>>> "Hannes" == Hannes Domani <ssbssa@yahoo.de> writes:
Hannes> It's 32bit for all (non-cygwin) Windows ABIs.
Somehow this patch seems to have been sent twice.
No problem but weird.
Tom
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [PATCH v2 06/11] Move x86 register code into x86-windows-nat.c
2026-01-17 13:54 ` [PATCH v2 06/11] Move x86 register " Hannes Domani
@ 2026-01-21 16:08 ` Tom Tromey
0 siblings, 0 replies; 44+ messages in thread
From: Tom Tromey @ 2026-01-21 16:08 UTC (permalink / raw)
To: Hannes Domani; +Cc: gdb-patches
>>>>> "Hannes" == Hannes Domani <ssbssa@yahoo.de> writes:
Thank you, this is ok.
Approved-By: Tom Tromey <tom@tromey.com>
Tom
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [PATCH v2 11/11] Add aarch64-windows support
2026-01-17 13:54 ` [PATCH v2 11/11] Add aarch64-windows support Hannes Domani
2026-01-17 16:04 ` Eli Zaretskii
@ 2026-01-21 16:18 ` Tom Tromey
2026-01-23 19:14 ` Hannes Domani
1 sibling, 1 reply; 44+ messages in thread
From: Tom Tromey @ 2026-01-21 16:18 UTC (permalink / raw)
To: Hannes Domani; +Cc: gdb-patches
>>>>> "Hannes" == Hannes Domani <ssbssa@yahoo.de> writes:
Hannes> Changes in v2:
Hannes> - added new source files to ALLDEPFILES
Hannes> - created NEWS entry
Hannes> - removed set_gdbarch_auto_wide_charset and set_gdbarch_long_bit calls
Hannes> since these are now done in windows-tdep.c
Hannes> - added comments to aarch64_windows_breakpoint and
Hannes> set_gdbarch_decr_pc_after_break
Hannes> - removed unused 32bit code in
Hannes> aarch64_windows_nat_target::fetch_one_register()
Hannes> - changed stopped_data_address() to stopped_data_addresses() in
Hannes> aarch64_windows_nat_target, and updated stopped_by_watchpoint()
Hannes> - initialize windows_process inside INIT_GDB_FILE(aarch64_windows_nat)
Thank you. I have a couple of nits but nothing serious.
Hannes> +struct aarch64_windows_nat_target final :
Hannes> + public aarch64_nat_target<windows_nat_target>
I guess I'd stick the ":" on the second line, following the operator
rule (even though it's not really an operator).
Hannes> +void
Hannes> +aarch64_windows_nat_target::initialize_windows_arch (bool attaching)
Hannes> +{
Hannes> + memset (&aarch64_windows_process.dr_state, 0,
Hannes> + sizeof (aarch64_windows_process.dr_state));
Hannes> +
Hannes> + aarch64_windows_process.mappings = aarch64_mappings;
Extra space before the '=' here.
Ok with these nits fixed.
Approved-By: Tom Tromey <tom@tromey.com>
Tom
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH v3] Move x86 debug registers and related code into x86-windows-nat.c
2026-01-17 13:36 ` [PATCH v2 05/11] Move x86 debug registers and related code into x86-windows-nat.c Hannes Domani
2026-01-19 12:49 ` Schimpe, Christina
@ 2026-01-23 13:17 ` Hannes Domani
2026-01-23 18:50 ` Tom Tromey
1 sibling, 1 reply; 44+ messages in thread
From: Hannes Domani @ 2026-01-23 13:17 UTC (permalink / raw)
To: gdb-patches
---
Changes in v2:
- changed new windows_nat_target functions from public to protected
- better comments for these functions
Changes in v3:
- made check() function non-static, removed duplicate in x86-windows-nat.c
---
gdb/windows-nat.c | 151 ++---------------------------------
gdb/windows-nat.h | 24 +++++-
gdb/x86-windows-nat.c | 178 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 208 insertions(+), 145 deletions(-)
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index 9bcbc740f86..88c821d885d 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -62,7 +62,6 @@
#include "windows-tdep.h"
#include "windows-nat.h"
-#include "x86-nat.h"
#include "complaints.h"
#include "gdbsupport/gdb_tilde_expand.h"
#include "gdbsupport/pathstuff.h"
@@ -85,25 +84,12 @@ windows_per_inferior *windows_process;
# define STARTUPINFO STARTUPINFOW
#endif
-/* If we're not using the old Cygwin header file set, define the
- following which never should have been in the generic Win32 API
- headers in the first place since they were our own invention... */
-#ifndef _GNU_H_WINDOWS_H
-enum
- {
- FLAG_TRACE_BIT = 0x100,
- };
-#endif
-
-#define DR6_CLEAR_VALUE 0xffff0ff0
-
/* The string sent by cygwin when it processes a signal.
FIXME: This should be in a cygwin include file. */
#ifndef _CYGWIN_SIGNAL_STRING
#define _CYGWIN_SIGNAL_STRING "cYgSiGw00f"
#endif
-#define CHECK(x) check (x, __FILE__,__LINE__)
#define DEBUG_EXEC(fmt, ...) \
debug_prefixed_printf_cond (debug_exec, "windows exec", fmt, ## __VA_ARGS__)
#define DEBUG_EVENTS(fmt, ...) \
@@ -116,12 +102,6 @@ enum
debug_prefixed_printf_cond (debug_exceptions, "windows except", fmt, \
## __VA_ARGS__)
-static void cygwin_set_dr (int i, CORE_ADDR addr);
-static void cygwin_set_dr7 (unsigned long val);
-static CORE_ADDR cygwin_get_dr (int i);
-static unsigned long cygwin_get_dr6 (void);
-static unsigned long cygwin_get_dr7 (void);
-
/* User options. */
static bool new_console = false;
#ifdef __CYGWIN__
@@ -158,7 +138,7 @@ static const struct xlate_exception xlate[] =
#endif /* 0 */
-static void
+void
check (BOOL ok, const char *file, int line)
{
if (!ok)
@@ -494,23 +474,7 @@ windows_nat_target::fetch_registers (struct regcache *regcache, int r)
if (th->reload_context)
{
- windows_process->with_context (th, [&] (auto *context)
- {
- context->ContextFlags = WindowsContext<decltype(context)>::all;
- CHECK (get_thread_context (th->h, context));
- /* Copy dr values from that thread.
- But only if there were not modified since last stop.
- PR gdb/2388 */
- if (!th->debug_registers_changed)
- {
- windows_process->dr[0] = context->Dr0;
- windows_process->dr[1] = context->Dr1;
- windows_process->dr[2] = context->Dr2;
- windows_process->dr[3] = context->Dr3;
- windows_process->dr[6] = context->Dr6;
- windows_process->dr[7] = context->Dr7;
- }
- });
+ fill_thread_context (th);
th->reload_context = false;
}
@@ -1009,35 +973,7 @@ windows_nat_target::windows_continue (DWORD continue_status, int id,
for (auto &th : windows_process->thread_list)
if (id == -1 || id == (int) th->tid)
{
- windows_process->with_context (th.get (), [&] (auto *context)
- {
- if (th->debug_registers_changed)
- {
- context->ContextFlags
- |= WindowsContext<decltype(context)>::debug;
- context->Dr0 = windows_process->dr[0];
- context->Dr1 = windows_process->dr[1];
- context->Dr2 = windows_process->dr[2];
- context->Dr3 = windows_process->dr[3];
- context->Dr6 = DR6_CLEAR_VALUE;
- context->Dr7 = windows_process->dr[7];
- th->debug_registers_changed = false;
- }
- if (context->ContextFlags)
- {
- DWORD ec = 0;
-
- if (GetExitCodeThread (th->h, &ec)
- && ec == STILL_ACTIVE)
- {
- BOOL status = set_thread_context (th->h, context);
-
- if (!killed)
- CHECK (status);
- }
- context->ContextFlags = 0;
- }
- });
+ thread_context_continue (th.get (), killed);
th->resume ();
}
@@ -1153,10 +1089,7 @@ windows_nat_target::resume (ptid_t ptid, int step, enum gdb_signal sig)
regcache *regcache = get_thread_regcache (inferior_thread ());
struct gdbarch *gdbarch = regcache->arch ();
fetch_registers (regcache, gdbarch_ps_regnum (gdbarch));
- windows_process->with_context (th, [&] (auto *context)
- {
- context->EFlags |= FLAG_TRACE_BIT;
- });
+ thread_context_step (th);
}
/* Allow continuing with the same signal that interrupted us.
@@ -1536,15 +1469,12 @@ windows_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
void
windows_nat_target::do_initial_windows_stuff (DWORD pid, bool attaching)
{
- int i;
struct inferior *inf;
+ initialize_windows_arch ();
+
windows_process->last_sig = GDB_SIGNAL_0;
windows_process->open_process_used = 0;
- for (i = 0;
- i < sizeof (windows_process->dr) / sizeof (windows_process->dr[0]);
- i++)
- windows_process->dr[i] = 0;
#ifdef __CYGWIN__
windows_process->cygwin_load_start = 0;
windows_process->cygwin_load_end = 0;
@@ -1890,7 +1820,7 @@ windows_nat_target::detach (inferior *inf, int from_tty)
target_announce_detach (from_tty);
- x86_cleanup_dregs ();
+ cleanup_windows_arch ();
switch_to_no_thread ();
detach_inferior (inf);
@@ -2622,7 +2552,7 @@ void
windows_nat_target::mourn_inferior ()
{
(void) windows_continue (DBG_CONTINUE, -1, 0, true);
- x86_cleanup_dregs();
+ cleanup_windows_arch ();
if (windows_process->open_process_used)
{
CHECK (CloseHandle (windows_process->handle));
@@ -2857,16 +2787,6 @@ windows_nat_target::thread_name (struct thread_info *thr)
INIT_GDB_FILE (windows_nat)
{
- x86_dr_low.set_control = cygwin_set_dr7;
- x86_dr_low.set_addr = cygwin_set_dr;
- x86_dr_low.get_addr = cygwin_get_dr;
- x86_dr_low.get_status = cygwin_get_dr6;
- x86_dr_low.get_control = cygwin_get_dr7;
-
- /* x86_dr_low.debug_register_length field is set by
- calling x86_set_debug_register_length function
- in processor windows specific native file. */
-
#ifdef __CYGWIN__
cygwin_internal (CW_SET_DOS_FILE_WARNING, 0);
#endif
@@ -2956,61 +2876,6 @@ Use \"%ps\" or \"%ps\" command to load executable/libraries directly."),
}
}
-/* Hardware watchpoint support, adapted from go32-nat.c code. */
-
-/* Pass the address ADDR to the inferior in the I'th debug register.
- Here we just store the address in dr array, the registers will be
- actually set up when windows_continue is called. */
-static void
-cygwin_set_dr (int i, CORE_ADDR addr)
-{
- if (i < 0 || i > 3)
- internal_error (_("Invalid register %d in cygwin_set_dr.\n"), i);
- windows_process->dr[i] = addr;
-
- for (auto &th : windows_process->thread_list)
- th->debug_registers_changed = true;
-}
-
-/* Pass the value VAL to the inferior in the DR7 debug control
- register. Here we just store the address in D_REGS, the watchpoint
- will be actually set up in windows_wait. */
-static void
-cygwin_set_dr7 (unsigned long val)
-{
- windows_process->dr[7] = (CORE_ADDR) val;
-
- for (auto &th : windows_process->thread_list)
- th->debug_registers_changed = true;
-}
-
-/* Get the value of debug register I from the inferior. */
-
-static CORE_ADDR
-cygwin_get_dr (int i)
-{
- return windows_process->dr[i];
-}
-
-/* Get the value of the DR6 debug status register from the inferior.
- Here we just return the value stored in dr[6]
- by the last call to thread_rec for current_event.dwThreadId id. */
-static unsigned long
-cygwin_get_dr6 (void)
-{
- return (unsigned long) windows_process->dr[6];
-}
-
-/* Get the value of the DR7 debug status register from the inferior.
- Here we just return the value stored in dr[7] by the last call to
- thread_rec for current_event.dwThreadId id. */
-
-static unsigned long
-cygwin_get_dr7 (void)
-{
- return (unsigned long) windows_process->dr[7];
-}
-
/* Determine if the thread referenced by "ptid" is alive
by "polling" it. If WaitForSingleObject returns WAIT_OBJECT_0
it means that the thread has died. Otherwise it is assumed to be alive. */
diff --git a/gdb/windows-nat.h b/gdb/windows-nat.h
index 03c358fac54..f67ca3ad193 100644
--- a/gdb/windows-nat.h
+++ b/gdb/windows-nat.h
@@ -54,8 +54,6 @@ struct windows_per_inferior : public windows_nat::windows_process_info
void handle_unload_dll () override;
bool handle_access_violation (const EXCEPTION_RECORD *rec) override;
- uintptr_t dr[8] {};
-
int windows_initialization_done = 0;
std::vector<std::unique_ptr<windows_thread_info>> thread_list;
@@ -183,6 +181,23 @@ struct windows_nat_target : public inf_child_target
return serial_event_fd (m_wait_event);
}
+protected:
+
+ /* Initialize arch-specific data for a new inferior (debug registers,
+ register mappings). */
+ virtual void initialize_windows_arch () = 0;
+ /* Cleanup arch-specific data after inferior exit. */
+ virtual void cleanup_windows_arch () = 0;
+
+ /* Reload the thread context. */
+ virtual void fill_thread_context (windows_thread_info *th) = 0;
+
+ /* Prepare the thread context for continuing. */
+ virtual void thread_context_continue (windows_thread_info *th,
+ int killed) = 0;
+ /* Set the stepping bit in the thread context. */
+ virtual void thread_context_step (windows_thread_info *th) = 0;
+
private:
windows_thread_info *add_thread (ptid_t ptid, HANDLE h, void *tlb,
@@ -249,6 +264,11 @@ struct windows_nat_target : public inf_child_target
bool m_continued = false;
};
+/* Check if Windows API call succeeds, and otherwise print error code
+ and description. */
+void check (BOOL ok, const char *file, int line);
+#define CHECK(x) check (x, __FILE__,__LINE__)
+
/* The current process. */
extern windows_per_inferior *windows_process;
diff --git a/gdb/x86-windows-nat.c b/gdb/x86-windows-nat.c
index d1f78a01255..58a9d3d8866 100644
--- a/gdb/x86-windows-nat.c
+++ b/gdb/x86-windows-nat.c
@@ -18,22 +18,200 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "windows-nat.h"
+#include "regcache.h"
+#include "gdbarch.h"
#include "x86-nat.h"
+using namespace windows_nat;
+
+/* If we're not using the old Cygwin header file set, define the
+ following which never should have been in the generic Win32 API
+ headers in the first place since they were our own invention... */
+#ifndef _GNU_H_WINDOWS_H
+enum
+ {
+ FLAG_TRACE_BIT = 0x100,
+ };
+#endif
+
+#define DR6_CLEAR_VALUE 0xffff0ff0
+
struct x86_windows_per_inferior : public windows_per_inferior
{
+ uintptr_t dr[8] {};
};
struct x86_windows_nat_target final : public x86_nat_target<windows_nat_target>
{
+ void initialize_windows_arch () override;
+ void cleanup_windows_arch () override;
+
+ void fill_thread_context (windows_thread_info *th) override;
+
+ void thread_context_continue (windows_thread_info *th, int killed) override;
+ void thread_context_step (windows_thread_info *th) override;
};
/* The current process. */
static x86_windows_per_inferior x86_windows_process;
+/* See windows-nat.h. */
+
+void
+x86_windows_nat_target::initialize_windows_arch ()
+{
+ memset (x86_windows_process.dr, 0, sizeof (x86_windows_process.dr));
+}
+
+/* See windows-nat.h. */
+
+void
+x86_windows_nat_target::cleanup_windows_arch ()
+{
+ x86_cleanup_dregs ();
+}
+
+/* See windows-nat.h. */
+
+void
+x86_windows_nat_target::fill_thread_context (windows_thread_info *th)
+{
+ x86_windows_process.with_context (th, [&] (auto *context)
+ {
+ context->ContextFlags = WindowsContext<decltype(context)>::all;
+ CHECK (get_thread_context (th->h, context));
+
+ /* Copy dr values from that thread.
+ But only if there were not modified since last stop.
+ PR gdb/2388 */
+ if (!th->debug_registers_changed)
+ {
+ x86_windows_process.dr[0] = context->Dr0;
+ x86_windows_process.dr[1] = context->Dr1;
+ x86_windows_process.dr[2] = context->Dr2;
+ x86_windows_process.dr[3] = context->Dr3;
+ x86_windows_process.dr[6] = context->Dr6;
+ x86_windows_process.dr[7] = context->Dr7;
+ }
+ });
+}
+
+/* See windows-nat.h. */
+
+void
+x86_windows_nat_target::thread_context_continue (windows_thread_info *th,
+ int killed)
+{
+ x86_windows_process.with_context (th, [&] (auto *context)
+ {
+ if (th->debug_registers_changed)
+ {
+ context->ContextFlags |= WindowsContext<decltype(context)>::debug;
+ context->Dr0 = x86_windows_process.dr[0];
+ context->Dr1 = x86_windows_process.dr[1];
+ context->Dr2 = x86_windows_process.dr[2];
+ context->Dr3 = x86_windows_process.dr[3];
+ context->Dr6 = DR6_CLEAR_VALUE;
+ context->Dr7 = x86_windows_process.dr[7];
+ th->debug_registers_changed = false;
+ }
+
+ if (context->ContextFlags)
+ {
+ DWORD ec = 0;
+
+ if (GetExitCodeThread (th->h, &ec)
+ && ec == STILL_ACTIVE)
+ {
+ BOOL status = set_thread_context (th->h, context);
+
+ if (!killed)
+ CHECK (status);
+ }
+ context->ContextFlags = 0;
+ }
+ });
+}
+
+/* See windows-nat.h. */
+
+void
+x86_windows_nat_target::thread_context_step (windows_thread_info *th)
+{
+ x86_windows_process.with_context (th, [&] (auto *context)
+ {
+ context->EFlags |= FLAG_TRACE_BIT;
+ });
+}
+
+/* Hardware watchpoint support, adapted from go32-nat.c code. */
+
+/* Pass the address ADDR to the inferior in the I'th debug register.
+ Here we just store the address in dr array, the registers will be
+ actually set up when windows_continue is called. */
+static void
+cygwin_set_dr (int i, CORE_ADDR addr)
+{
+ if (i < 0 || i > 3)
+ internal_error (_("Invalid register %d in cygwin_set_dr.\n"), i);
+ x86_windows_process.dr[i] = addr;
+
+ for (auto &th : x86_windows_process.thread_list)
+ th->debug_registers_changed = true;
+}
+
+/* Pass the value VAL to the inferior in the DR7 debug control
+ register. Here we just store the address in D_REGS, the watchpoint
+ will be actually set up in windows_wait. */
+static void
+cygwin_set_dr7 (unsigned long val)
+{
+ x86_windows_process.dr[7] = (CORE_ADDR) val;
+
+ for (auto &th : x86_windows_process.thread_list)
+ th->debug_registers_changed = true;
+}
+
+/* Get the value of debug register I from the inferior. */
+
+static CORE_ADDR
+cygwin_get_dr (int i)
+{
+ return x86_windows_process.dr[i];
+}
+
+/* Get the value of the DR6 debug status register from the inferior.
+ Here we just return the value stored in dr[6]
+ by the last call to thread_rec for current_event.dwThreadId id. */
+static unsigned long
+cygwin_get_dr6 (void)
+{
+ return (unsigned long) x86_windows_process.dr[6];
+}
+
+/* Get the value of the DR7 debug status register from the inferior.
+ Here we just return the value stored in dr[7] by the last call to
+ thread_rec for current_event.dwThreadId id. */
+
+static unsigned long
+cygwin_get_dr7 (void)
+{
+ return (unsigned long) x86_windows_process.dr[7];
+}
+
INIT_GDB_FILE (x86_windows_nat)
{
+ x86_dr_low.set_control = cygwin_set_dr7;
+ x86_dr_low.set_addr = cygwin_set_dr;
+ x86_dr_low.get_addr = cygwin_get_dr;
+ x86_dr_low.get_status = cygwin_get_dr6;
+ x86_dr_low.get_control = cygwin_get_dr7;
+
+ /* x86_dr_low.debug_register_length field is set by
+ calling x86_set_debug_register_length function
+ in processor windows specific native file. */
+
/* The target is not a global specifically to avoid a C++ "static
initializer fiasco" situation. */
add_inf_child_target (new x86_windows_nat_target);
--
2.52.0
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [PATCH v3] Move x86 debug registers and related code into x86-windows-nat.c
2026-01-23 13:17 ` [PATCH v3] " Hannes Domani
@ 2026-01-23 18:50 ` Tom Tromey
2026-01-23 19:20 ` Hannes Domani
0 siblings, 1 reply; 44+ messages in thread
From: Tom Tromey @ 2026-01-23 18:50 UTC (permalink / raw)
To: Hannes Domani; +Cc: gdb-patches
>>>>> "Hannes" == Hannes Domani <ssbssa@yahoo.de> writes:
Hannes> Changes in v3:
Hannes> - made check() function non-static, removed duplicate in x86-windows-nat.c
Thanks, this is ok.
Approved-By: Tom Tromey <tom@tromey.com>
Tom
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [PATCH v2 02/11] Simplify windows_nat_target::resume
2026-01-19 13:55 ` Schimpe, Christina
2026-01-21 15:42 ` Tom Tromey
@ 2026-01-23 19:11 ` Hannes Domani
1 sibling, 0 replies; 44+ messages in thread
From: Hannes Domani @ 2026-01-23 19:11 UTC (permalink / raw)
To: gdb-patches, Schimpe, Christina; +Cc: Tom Tromey
Am Montag, 19. Januar 2026 um 14:55:44 MEZ hat Schimpe, Christina <christina.schimpe@intel.com> Folgendes geschrieben:
> > -----Original Message-----
>
> > From: Hannes Domani <ssbssa@yahoo.de>
> > Sent: Samstag, 17. Januar 2026 14:36
> > To: gdb-patches@sourceware.org
> > Cc: Tom Tromey <tom@tromey.com>
> > Subject: [PATCH v2 02/11] Simplify windows_nat_target::resume
> >
> > Now the thread context is only needed for setting the trace bit, so move the
> > rest out of the with_context lambda.
> >
> > Approved-By: Tom Tromey <tom@tromey.com>
> > ---
> > No changes in v2
> > ---
> > gdb/windows-nat.c | 15 ++++++---------
> > 1 file changed, 6 insertions(+), 9 deletions(-)
> >
> > diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c index
> > a6fd199530c..8ee52768cb1 100644
> > --- a/gdb/windows-nat.c
> > +++ b/gdb/windows-nat.c
> > @@ -1366,18 +1366,15 @@ windows_nat_target::resume (ptid_t ptid, int
> > step, enum gdb_signal sig)
> >
> > /* Get context for currently selected thread. */
> > th = windows_process.thread_rec (inferior_ptid,
> > DONT_INVALIDATE_CONTEXT);
> > - if (th)
> > + if (th && step)
>
>
> Nit: better to check th != nullptr here explicitly.
Thanks, I've made this change.
Hannes
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [PATCH v2 08/11] Move software breakpoint recognition code into x86-windows-nat.c
2026-01-21 15:43 ` Tom Tromey
@ 2026-01-23 19:12 ` Hannes Domani
0 siblings, 0 replies; 44+ messages in thread
From: Hannes Domani @ 2026-01-23 19:12 UTC (permalink / raw)
To: Schimpe, Christina, Tom Tromey; +Cc: gdb-patches
Am Mittwoch, 21. Januar 2026 um 16:43:55 MEZ hat Tom Tromey <tom@tromey.com> Folgendes geschrieben:
> >>>>> Schimpe, Christina <christina.schimpe@intel.com> writes:
>
> >> + is_sw_breakpoint (EXCEPTION_RECORD *er) = 0;
>
> > Nit: Shouldn't this better be "const EXCEPTION_RECORD *er" ?
>
> I guess if we're doing that we should consider
>
> is_sw_breakpoint (const EXCEPTION_RECORD *er) const = 0;
>
> since presumably this method isn't mutating *this.
Thanks, I've added both const.
Hannes
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [PATCH v2 09/11] Move auto_wide_charset gdbarch method to windows-tdep
2026-01-21 15:48 ` Tom Tromey
@ 2026-01-23 19:13 ` Hannes Domani
0 siblings, 0 replies; 44+ messages in thread
From: Hannes Domani @ 2026-01-23 19:13 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
Am Mittwoch, 21. Januar 2026 um 16:48:36 MEZ hat Tom Tromey <tom@tromey.com> Folgendes geschrieben:
> >>>>> "Hannes" == Hannes Domani <ssbssa@yahoo.de> writes:
>
> Hannes> It's the same for all Windows ABIs.
>
> Thank you.
>
> Hannes> +static const char *
> Hannes> +windows_auto_wide_charset (void)
>
> Please remove the 'void' from this line.
>
> Ok with this change.
> Approved-By: Tom Tromey <tom@tromey.com>
I've done this, thanks.
Hannes
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [PATCH v2 11/11] Add aarch64-windows support
2026-01-21 16:18 ` Tom Tromey
@ 2026-01-23 19:14 ` Hannes Domani
0 siblings, 0 replies; 44+ messages in thread
From: Hannes Domani @ 2026-01-23 19:14 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
Am Mittwoch, 21. Januar 2026 um 17:18:43 MEZ hat Tom Tromey <tom@tromey.com> Folgendes geschrieben:
> >>>>> "Hannes" == Hannes Domani <ssbssa@yahoo.de> writes:
>
> Hannes> Changes in v2:
> Hannes> - added new source files to ALLDEPFILES
> Hannes> - created NEWS entry
> Hannes> - removed set_gdbarch_auto_wide_charset and set_gdbarch_long_bit calls
> Hannes> since these are now done in windows-tdep.c
> Hannes> - added comments to aarch64_windows_breakpoint and
> Hannes> set_gdbarch_decr_pc_after_break
> Hannes> - removed unused 32bit code in
> Hannes> aarch64_windows_nat_target::fetch_one_register()
> Hannes> - changed stopped_data_address() to stopped_data_addresses() in
> Hannes> aarch64_windows_nat_target, and updated stopped_by_watchpoint()
> Hannes> - initialize windows_process inside INIT_GDB_FILE(aarch64_windows_nat)
>
> Thank you. I have a couple of nits but nothing serious.
>
> Hannes> +struct aarch64_windows_nat_target final :
> Hannes> + public aarch64_nat_target<windows_nat_target>
>
> I guess I'd stick the ":" on the second line, following the operator
> rule (even though it's not really an operator).
>
> Hannes> +void
> Hannes> +aarch64_windows_nat_target::initialize_windows_arch (bool attaching)
> Hannes> +{
> Hannes> + memset (&aarch64_windows_process.dr_state, 0,
> Hannes> + sizeof (aarch64_windows_process.dr_state));
> Hannes> +
> Hannes> + aarch64_windows_process.mappings = aarch64_mappings;
>
> Extra space before the '=' here.
>
>
> Ok with these nits fixed.
> Approved-By: Tom Tromey <tom@tromey.com>
I've made these changes, thanks.
Hannes
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [PATCH v3] Move x86 debug registers and related code into x86-windows-nat.c
2026-01-23 18:50 ` Tom Tromey
@ 2026-01-23 19:20 ` Hannes Domani
2026-01-23 19:56 ` Tom Tromey
0 siblings, 1 reply; 44+ messages in thread
From: Hannes Domani @ 2026-01-23 19:20 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
Am Freitag, 23. Januar 2026 um 19:50:54 MEZ hat Tom Tromey <tom@tromey.com> Folgendes geschrieben:
> >>>>> "Hannes" == Hannes Domani <ssbssa@yahoo.de> writes:
>
> Hannes> Changes in v3:
> Hannes> - made check() function non-static, removed duplicate in x86-windows-nat.c
>
> Thanks, this is ok.
> Approved-By: Tom Tromey <tom@tromey.com>
Thanks.
Since this was the last patch waiting approval, I've now pushed this series.
Hannes
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [PATCH v3] Move x86 debug registers and related code into x86-windows-nat.c
2026-01-23 19:20 ` Hannes Domani
@ 2026-01-23 19:56 ` Tom Tromey
0 siblings, 0 replies; 44+ messages in thread
From: Tom Tromey @ 2026-01-23 19:56 UTC (permalink / raw)
To: Hannes Domani; +Cc: Tom Tromey, gdb-patches
>>>>> "Hannes" == Hannes Domani <ssbssa@yahoo.de> writes:
Hannes> Thanks.
Hannes> Since this was the last patch waiting approval, I've now pushed this series.
Thank you very much for doing this.
Tom
^ permalink raw reply [flat|nested] 44+ messages in thread
end of thread, other threads:[~2026-01-23 19:57 UTC | newest]
Thread overview: 44+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
[not found] <20260117134052.2660009-1-ssbssa.ref@yahoo.de>
2026-01-17 13:36 ` [PATCH v2 01/11] Remove duplicate code from windows_nat_target::resume Hannes Domani
2026-01-17 13:36 ` [PATCH v2 02/11] Simplify windows_nat_target::resume Hannes Domani
2026-01-19 13:55 ` Schimpe, Christina
2026-01-21 15:42 ` Tom Tromey
2026-01-23 19:11 ` Hannes Domani
2026-01-17 13:36 ` [PATCH v2 03/11] Move struct declarations into windows-nat.h Hannes Domani
2026-01-17 13:36 ` [PATCH v2 04/11] Create x86-windows-nat.c Hannes Domani
2026-01-21 15:38 ` Tom Tromey
2026-01-17 13:36 ` [PATCH v2 05/11] Move x86 debug registers and related code into x86-windows-nat.c Hannes Domani
2026-01-19 12:49 ` Schimpe, Christina
2026-01-20 15:49 ` Hannes Domani
2026-01-21 8:06 ` Schimpe, Christina
2026-01-23 13:17 ` [PATCH v3] " Hannes Domani
2026-01-23 18:50 ` Tom Tromey
2026-01-23 19:20 ` Hannes Domani
2026-01-23 19:56 ` Tom Tromey
2026-01-17 13:36 ` [PATCH v2 06/11] Move x86 register " Hannes Domani
2026-01-19 12:50 ` Schimpe, Christina
2026-01-17 13:36 ` [PATCH v2 07/11] Move x86 selector " Hannes Domani
2026-01-19 13:56 ` Schimpe, Christina
2026-01-17 13:36 ` [PATCH v2 08/11] Move software breakpoint recognition " Hannes Domani
2026-01-19 12:51 ` Schimpe, Christina
2026-01-21 15:43 ` Tom Tromey
2026-01-23 19:12 ` Hannes Domani
2026-01-17 13:36 ` [PATCH v2 09/11] Move auto_wide_charset gdbarch method to windows-tdep Hannes Domani
2026-01-17 13:36 ` [PATCH v2 10/11] Move setting size of long " Hannes Domani
2026-01-21 15:47 ` Tom Tromey
2026-01-17 13:54 ` [PATCH v2 04/11] Create x86-windows-nat.c Hannes Domani
2026-01-17 14:01 ` Hannes Domani
2026-01-17 14:14 ` Hannes Domani
2026-01-17 15:04 ` Simon Marchi
2026-01-17 15:15 ` Hannes Domani
2026-01-17 13:54 ` [PATCH v2 05/11] Move x86 debug registers and related code into x86-windows-nat.c Hannes Domani
2026-01-17 13:54 ` [PATCH v2 06/11] Move x86 register " Hannes Domani
2026-01-21 16:08 ` Tom Tromey
2026-01-17 13:54 ` [PATCH v2 09/11] Move auto_wide_charset gdbarch method to windows-tdep Hannes Domani
2026-01-21 15:48 ` Tom Tromey
2026-01-23 19:13 ` Hannes Domani
2026-01-17 13:54 ` [PATCH v2 10/11] Move setting size of long " Hannes Domani
2026-01-21 15:59 ` Tom Tromey
2026-01-17 13:54 ` [PATCH v2 11/11] Add aarch64-windows support Hannes Domani
2026-01-17 16:04 ` Eli Zaretskii
2026-01-21 16:18 ` Tom Tromey
2026-01-23 19:14 ` Hannes Domani
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox