#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"
# 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, ...) \
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__
#endif /* 0 */
-static void
+void
check (BOOL ok, const char *file, int line)
{
if (!ok)
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;
}
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 ();
}
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.
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;
target_announce_detach (from_tty);
- x86_cleanup_dregs ();
+ cleanup_windows_arch ();
switch_to_no_thread ();
detach_inferior (inf);
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));
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
}
}
-/* 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. */
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;
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,
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;
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);