/* Target-vector operations for controlling windows child processes, for GDB.
- Copyright (C) 1995-2020 Free Software Foundation, Inc.
+ Copyright (C) 1995-2021 Free Software Foundation, Inc.
Contributed by Cygnus Solutions, A Red Hat Company.
#include "gdbsupport/pathstuff.h"
#include "gdbsupport/gdb_wait.h"
#include "nat/windows-nat.h"
+#include "gdbsupport/symbol.h"
using namespace windows_nat;
#endif
#define CONTEXT_DEBUGGER_DR CONTEXT_FULL | CONTEXT_FLOATING_POINT \
- | CONTEXT_SEGMENTS | CONTEXT_DEBUG_REGISTERS \
- | CONTEXT_EXTENDED_REGISTERS
+ | CONTEXT_SEGMENTS | CONTEXT_DEBUG_REGISTERS \
+ | CONTEXT_EXTENDED_REGISTERS
static uintptr_t dr[8];
static int debug_registers_changed;
#endif
#define CHECK(x) check (x, __FILE__,__LINE__)
-#define DEBUG_EXEC(x) if (debug_exec) printf_unfiltered x
-#define DEBUG_EVENTS(x) if (debug_events) printf_unfiltered x
-#define DEBUG_MEM(x) if (debug_memory) printf_unfiltered x
-#define DEBUG_EXCEPT(x) if (debug_exceptions) printf_unfiltered x
+#define DEBUG_EXEC(x) if (debug_exec) debug_printf x
+#define DEBUG_EVENTS(x) if (debug_events) debug_printf x
+#define DEBUG_MEM(x) if (debug_memory) debug_printf x
+#define DEBUG_EXCEPT(x) if (debug_exceptions) debug_printf x
static void cygwin_set_dr (int i, CORE_ADDR addr);
static void cygwin_set_dr7 (unsigned long val);
static int saw_create;
static int open_process_used = 0;
#ifdef __x86_64__
-static bool wow64_process = false;
-static bool ignore_first_breakpoint = false;
+static void *wow64_dbgbreak;
#endif
/* User options. */
void resume (ptid_t, int , enum gdb_signal) override;
- ptid_t wait (ptid_t, struct target_waitstatus *, int) 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
{
- return current_windows_thread->stopped_at_software_breakpoint;
+ windows_thread_info *th
+ = thread_rec (inferior_ptid, DONT_INVALIDATE_CONTEXT);
+ return th->stopped_at_software_breakpoint;
}
bool supports_stopped_by_sw_breakpoint () override
const char *thread_name (struct thread_info *) override;
int get_windows_debug_event (int pid, struct target_waitstatus *ourstatus);
+
+ void do_initial_windows_stuff (DWORD pid, bool attaching);
};
static windows_nat_target the_windows_nat_target;
else
{
if (th->stopped_at_software_breakpoint
+ && !th->pc_adjusted
&& r == gdbarch_pc_regnum (gdbarch))
{
int size = register_size (gdbarch, r);
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);
}
free (rname);
}
else
- error (_("dll path too long"));
+ {
+ warning (_("dll path for \"%s\" too long or inaccessible"), name);
+ strcpy (so->so_name, so->so_original_name);
+ }
}
/* Record cygwin1.dll .text start/end. */
p = strchr (so->so_name, '\0') - (sizeof ("/cygwin1.dll") - 1);
{
asection *text = NULL;
- gdb_bfd_ref_ptr abfd (gdb_bfd_open (so->so_name, "pei-i386", -1));
+ gdb_bfd_ref_ptr abfd (gdb_bfd_open (so->so_name, "pei-i386"));
if (abfd == NULL)
return so;
int
windows_nat::handle_output_debug_string (struct target_waitstatus *ourstatus)
{
- gdb::unique_xmalloc_ptr<char> s;
int retval = 0;
- if (!target_read_string
- ((CORE_ADDR) (uintptr_t) current_event.u.DebugString.lpDebugStringData,
- &s, 1024, 0)
- || !s || !*(s.get ()))
+ gdb::unique_xmalloc_ptr<char> s
+ = (target_read_string
+ ((CORE_ADDR) (uintptr_t) current_event.u.DebugString.lpDebugStringData,
+ 1024));
+ if (s == nullptr || !*(s.get ()))
/* nothing to do */;
else if (!startswith (s.get (), _CYGWIN_SIGNAL_STRING))
{
static void
display_selectors (const char * args, int from_tty)
{
- if (!current_windows_thread)
+ if (inferior_ptid == null_ptid)
{
puts_filtered ("Impossible to display selectors now.\n");
return;
}
+
+ windows_thread_info *current_windows_thread
+ = thread_rec (inferior_ptid, DONT_INVALIDATE_CONTEXT);
+
if (!args)
{
#ifdef __x86_64__
if (named_thread != NULL)
{
int thread_name_len;
- gdb::unique_xmalloc_ptr<char> thread_name;
-
- thread_name_len = target_read_string (thread_name_target,
- &thread_name, 1025, NULL);
+ gdb::unique_xmalloc_ptr<char> thread_name
+ = target_read_string (thread_name_target, 1025, &thread_name_len);
if (thread_name_len > 0)
{
thread_name.get ()[thread_name_len - 1] = '\0';
return false;
}
+/* See nat/windows-nat.h. */
+
+bool
+windows_nat::handle_access_violation (const EXCEPTION_RECORD *rec)
+{
+#ifdef __CYGWIN__
+ /* See if the access violation happened within the cygwin DLL
+ itself. Cygwin uses a kind of exception handling to deal with
+ passed-in invalid addresses. gdb should not treat these as real
+ SEGVs since they will be silently handled by cygwin. A real SEGV
+ will (theoretically) be caught by cygwin later in the process and
+ will be sent as a cygwin-specific-signal. So, ignore SEGVs if
+ they show up within the text segment of the DLL itself. */
+ const char *fn;
+ CORE_ADDR addr = (CORE_ADDR) (uintptr_t) rec->ExceptionAddress;
+
+ if ((!cygwin_exceptions && (addr >= cygwin_load_start
+ && addr < cygwin_load_end))
+ || (find_pc_partial_function (addr, &fn, NULL, NULL)
+ && startswith (fn, "KERNEL32!IsBad")))
+ return true;
+#endif
+ return false;
+}
+
/* Resume thread specified by ID, or all artificially suspended
threads, if we are continuing execution. KILLED non-zero means we
have killed the inferior, so we should ignore weird errors due to
(unsigned) GetLastError ());
/* We can not debug anything in that case. */
}
- current_windows_thread
- = windows_add_thread (ptid_t (current_event.dwProcessId,
- current_event.dwThreadId, 0),
- current_event.u.CreateThread.hThread,
- current_event.u.CreateThread.lpThreadLocalBase,
- true /* main_thread_p */);
+ windows_add_thread (ptid_t (current_event.dwProcessId, 0,
+ current_event.dwThreadId),
+ current_event.u.CreateThread.hThread,
+ current_event.u.CreateThread.lpThreadLocalBase,
+ true /* main_thread_p */);
return current_event.dwThreadId;
}
if (!new_console && !attach_flag)
return TRUE;
- if (!DebugBreakProcess (current_process_handle))
- warning (_("Could not interrupt program. "
- "Press Ctrl-c in the program console."));
+#ifdef __x86_64__
+ if (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 (wow64_dbgbreak == nullptr)
+ {
+ CORE_ADDR addr;
+ if (!find_minimal_symbol_address ("ntdll!DbgUiRemoteBreakin",
+ &addr, 0))
+ wow64_dbgbreak = (void *) addr;
+ }
+
+ if (wow64_dbgbreak != nullptr)
+ {
+ HANDLE thread = CreateRemoteThread (current_process_handle, NULL,
+ 0, (LPTHREAD_START_ROUTINE)
+ wow64_dbgbreak, NULL, 0, NULL);
+ if (thread)
+ CloseHandle (thread);
+ }
+ }
+ else
+#endif
+ {
+ if (!DebugBreakProcess (current_process_handle))
+ warning (_("Could not interrupt program. "
+ "Press Ctrl-c in the program console."));
+ }
/* Return true to tell that Ctrl-C has been handled. */
return TRUE;
}
-/* A wrapper for WaitForDebugEvent that sets "last_wait_event"
- appropriately. */
-static BOOL
-wait_for_debug_event (DEBUG_EVENT *event, DWORD timeout)
-{
- BOOL result = WaitForDebugEvent (event, timeout);
- if (result)
- last_wait_event = *event;
- return result;
-}
-
/* Get the next event from the child. Returns a non-zero thread id if the event
requires handling by WFI (or whatever). */
{
BOOL debug_event;
DWORD continue_status, event_code;
- windows_thread_info *th;
- static windows_thread_info dummy_thread_info (0, 0, 0);
DWORD thread_id = 0;
/* If there is a relevant pending stop, report it now. See the
thread_id = stop->thread_id;
*ourstatus = stop->status;
- inferior_ptid = ptid_t (current_event.dwProcessId, thread_id, 0);
- current_windows_thread = thread_rec (inferior_ptid,
- INVALIDATE_CONTEXT);
- current_windows_thread->reload_context = 1;
+ ptid_t ptid (current_event.dwProcessId, thread_id);
+ windows_thread_info *th = thread_rec (ptid, INVALIDATE_CONTEXT);
+ th->reload_context = 1;
return thread_id;
}
event_code = current_event.dwDebugEventCode;
ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
- th = NULL;
have_saved_context = 0;
switch (event_code)
}
/* Record the existence of this thread. */
thread_id = current_event.dwThreadId;
- th = windows_add_thread
- (ptid_t (current_event.dwProcessId, current_event.dwThreadId, 0),
+ windows_add_thread
+ (ptid_t (current_event.dwProcessId, current_event.dwThreadId, 0),
current_event.u.CreateThread.hThread,
current_event.u.CreateThread.lpThreadLocalBase,
false /* main_thread_p */);
current_event.dwThreadId, 0),
current_event.u.ExitThread.dwExitCode,
false /* main_thread_p */);
- th = &dummy_thread_info;
break;
case CREATE_PROCESS_DEBUG_EVENT:
current_process_handle = current_event.u.CreateProcessInfo.hProcess;
/* Add the main thread. */
- th = windows_add_thread
- (ptid_t (current_event.dwProcessId,
+ windows_add_thread
+ (ptid_t (current_event.dwProcessId,
current_event.dwThreadId, 0),
current_event.u.CreateProcessInfo.hThread,
current_event.u.CreateProcessInfo.lpThreadLocalBase,
thread_id, 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
+ == EXCEPTION_BREAKPOINT)
+ || (current_event.u.Exception.ExceptionRecord.ExceptionCode
+ == STATUS_WX86_BREAKPOINT))
&& windows_initialization_done)
{
ptid_t ptid = ptid_t (current_event.dwProcessId, thread_id, 0);
- th = thread_rec (ptid, INVALIDATE_CONTEXT);
+ windows_thread_info *th = thread_rec (ptid, INVALIDATE_CONTEXT);
th->stopped_at_software_breakpoint = true;
+ th->pc_adjusted = false;
}
pending_stops.push_back ({thread_id, *ourstatus, current_event});
thread_id = 0;
CHECK (windows_continue (continue_status, desired_stop_thread_id, 0));
}
- else
- {
- inferior_ptid = ptid_t (current_event.dwProcessId, thread_id, 0);
- current_windows_thread = th;
- if (!current_windows_thread)
- current_windows_thread = thread_rec (inferior_ptid,
- INVALIDATE_CONTEXT);
- }
out:
return thread_id;
/* Wait for interesting events to occur in the target process. */
ptid_t
windows_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
- int options)
+ target_wait_flags options)
{
int pid = -1;
{
ptid_t result = ptid_t (current_event.dwProcessId, retval, 0);
- if (current_windows_thread != nullptr)
+ if (ourstatus->kind != TARGET_WAITKIND_EXITED
+ && ourstatus->kind != TARGET_WAITKIND_SIGNALLED)
{
- current_windows_thread->stopped_at_software_breakpoint = false;
- if (current_event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT
- && (current_event.u.Exception.ExceptionRecord.ExceptionCode
- == EXCEPTION_BREAKPOINT)
- && windows_initialization_done)
- current_windows_thread->stopped_at_software_breakpoint = true;
+ windows_thread_info *th = thread_rec (result, INVALIDATE_CONTEXT);
+
+ if (th != nullptr)
+ {
+ th->stopped_at_software_breakpoint = false;
+ 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_initialization_done)
+ {
+ th->stopped_at_software_breakpoint = true;
+ th->pc_adjusted = false;
+ }
+ }
}
return result;
}
}
-static void
-do_initial_windows_stuff (struct target_ops *ops, DWORD pid, int attaching)
+void
+windows_nat_target::do_initial_windows_stuff (DWORD pid, bool attaching)
{
int i;
struct inferior *inf;
#endif
current_event.dwProcessId = pid;
memset (¤t_event, 0, sizeof (current_event));
- if (!target_is_pushed (ops))
- push_target (ops);
+ if (!target_is_pushed (this))
+ push_target (this);
disable_breakpoints_in_shlibs ();
windows_clear_solib ();
clear_proceed_status (0);
inferior_appeared (inf, pid);
inf->attach_flag = attaching;
- /* Make the new process the current inferior, so terminal handling
- can rely on it. When attaching, we don't know about any thread
- id here, but that's OK --- nothing should be referencing the
- current thread until we report an event out of windows_wait. */
- inferior_ptid = ptid_t (pid);
-
target_terminal::init ();
target_terminal::inferior ();
windows_initialization_done = 0;
+ ptid_t last_ptid;
+
while (1)
{
struct target_waitstatus status;
- ops->wait (minus_one_ptid, &status, 0);
+ last_ptid = this->wait (minus_one_ptid, &status, 0);
/* Note windows_wait returns TARGET_WAITKIND_SPURIOUS for thread
events. */
&& status.kind != TARGET_WAITKIND_SPURIOUS)
break;
- ops->resume (minus_one_ptid, 0, GDB_SIGNAL_0);
+ this->resume (minus_one_ptid, 0, GDB_SIGNAL_0);
}
+ switch_to_thread (find_thread_ptid (this, last_ptid));
+
/* Now that the inferior has been started and all DLLs have been mapped,
we can iterate over all DLLs and load them in.
}
#endif
- do_initial_windows_stuff (this, pid, 1);
+ do_initial_windows_stuff (pid, 1);
target_terminal::ours ();
}
}
x86_cleanup_dregs ();
- inferior_ptid = null_ptid;
+ switch_to_no_thread ();
detach_inferior (inf);
maybe_unpush_target ();
mbstowcs (copy, env[i], len);
equalpos = wcschr (copy, L'=');
if (equalpos)
- *equalpos = L'\0';
+ *equalpos = L'\0';
SetEnvironmentVariableW (copy, NULL);
}
xfree (copy);
PROCESS_INFORMATION pi;
BOOL ret;
DWORD flags = 0;
- const char *inferior_io_terminal = get_inferior_io_terminal ();
+ const char *inferior_tty = current_inferior ()->tty ();
if (!exec_file)
error (_("No executable specified, use `target exec'."));
w32_env = NULL;
}
- if (!inferior_io_terminal)
+ if (inferior_tty == nullptr)
tty = ostdin = ostdout = ostderr = -1;
else
{
- tty = open (inferior_io_terminal, O_RDWR | O_NOCTTY);
+ tty = open (inferior_tty, O_RDWR | O_NOCTTY);
if (tty < 0)
{
- print_sys_errmsg (inferior_io_terminal, errno);
+ print_sys_errmsg (inferior_tty, errno);
ostdin = ostdout = ostderr = -1;
}
else
allargs_len = strlen (allargs_copy);
}
/* If not all the standard streams are redirected by the command
- line, use inferior_io_terminal for those which aren't. */
- if (inferior_io_terminal
+ line, use INFERIOR_TTY for those which aren't. */
+ if (inferior_tty != nullptr
&& !(fd_inp >= 0 && fd_out >= 0 && fd_err >= 0))
{
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = 0;
sa.bInheritHandle = TRUE;
- tty = CreateFileA (inferior_io_terminal, GENERIC_READ | GENERIC_WRITE,
+ tty = CreateFileA (inferior_tty, GENERIC_READ | GENERIC_WRITE,
0, &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (tty == INVALID_HANDLE_VALUE)
warning (_("Warning: Failed to open TTY %s, error %#x."),
- inferior_io_terminal, (unsigned) GetLastError ());
+ inferior_tty, (unsigned) GetLastError ());
}
if (redirected || tty != INVALID_HANDLE_VALUE)
{
else
saw_create = 0;
- do_initial_windows_stuff (this, pi.dwProcessId, 0);
+ do_initial_windows_stuff (pi.dwProcessId, 0);
/* windows_continue (DBG_CONTINUE, -1, 0); */
}
#endif
GPA (hm, GetModuleInformation);
GetModuleFileNameEx = (GetModuleFileNameEx_ftype *)
- GetProcAddress (hm, GetModuleFileNameEx_name);
+ GetProcAddress (hm, GetModuleFileNameEx_name);
}
if (!EnumProcessModules || !GetModuleInformation || !GetModuleFileNameEx)