/* Low level interface to Windows debugging, for gdbserver.
- Copyright (C) 2006-2017 Free Software Foundation, Inc.
+ Copyright (C) 2006-2020 Free Software Foundation, Inc.
Contributed by Leo Zayas. Based on "win32-nat.c" from GDB.
#include <tlhelp32.h>
#include <psapi.h>
#include <process.h>
-#include "gdb_tilde_expand.h"
-#include "common-inferior.h"
+#include "gdbsupport/gdb_tilde_expand.h"
+#include "gdbsupport/common-inferior.h"
+#include "gdbsupport/gdb_wait.h"
#ifndef USE_WIN32API
#include <sys/cygwin.h>
static ptid_t
debug_event_ptid (DEBUG_EVENT *event)
{
- return ptid_build (event->dwProcessId, event->dwThreadId, 0);
+ return ptid_t (event->dwProcessId, event->dwThreadId, 0);
}
/* Get the thread context of the thread associated with TH. */
will often not be true. In those cases, the context returned by
GetThreadContext will not be correct by the time the thread
stops, hence we can't set that context back into the thread when
- resuming - it will most likelly crash the inferior.
+ resuming - it will most likely crash the inferior.
Unfortunately, there is no way to know when the thread will
really stop. To work around it, we'll only write the context
back to the thread when either the user or GDB explicitly change
static win32_thread_info *
thread_rec (ptid_t ptid, int get_context)
{
- struct thread_info *thread;
- win32_thread_info *th;
-
- thread = (struct thread_info *) find_inferior_id (&all_threads, ptid);
+ thread_info *thread = find_thread_ptid (ptid);
if (thread == NULL)
return NULL;
- th = (win32_thread_info *) thread_target_data (thread);
+ win32_thread_info *th = (win32_thread_info *) thread_target_data (thread);
if (get_context)
win32_require_context (th);
return th;
child_add_thread (DWORD pid, DWORD tid, HANDLE h, void *tlb)
{
win32_thread_info *th;
- ptid_t ptid = ptid_build (pid, tid, 0);
+ ptid_t ptid = ptid_t (pid, tid, 0);
if ((th = thread_rec (ptid, FALSE)))
return th;
static void
child_delete_thread (DWORD pid, DWORD tid)
{
- ptid_t ptid;
-
/* If the last thread is exiting, just return. */
if (all_threads.size () == 1)
return;
- ptid = ptid_build (pid, tid, 0);
- thread_info *thread = find_inferior_id (&all_threads, ptid);
+ thread_info *thread = find_thread_ptid (ptid_t (pid, tid));
if (thread == NULL)
return;
/* Transfer memory from/to the debugged process. */
static int
child_xfer_memory (CORE_ADDR memaddr, char *our, int len,
- int write, struct target_ops *target)
+ int write, process_stratum_target *target)
{
BOOL success;
SIZE_T done = 0;
static void
child_init_thread_list (void)
{
- for_each_inferior (&all_threads, delete_thread_info);
+ for_each_thread (delete_thread_info);
}
/* Zero during the child initialization phase, and nonzero otherwise. */
/* Resume all artificially suspended threads if we are continuing
execution. */
-static int
-continue_one_thread (thread_info *thread, void *id_ptr)
+static void
+continue_one_thread (thread_info *thread, int thread_id)
{
- int thread_id = * (int *) id_ptr;
win32_thread_info *th = (win32_thread_info *) thread_target_data (thread);
if (thread_id == -1 || thread_id == th->tid)
th->suspended = 0;
}
}
-
- return 0;
}
static BOOL
{
/* The inferior will only continue after the ContinueDebugEvent
call. */
- find_inferior (&all_threads, continue_one_thread, &thread_id);
+ for_each_thread ([&] (thread_info *thread)
+ {
+ continue_one_thread (thread, thread_id);
+ });
faked_breakpoint = 0;
if (!ContinueDebugEvent (current_event.dwProcessId,
DWORD flags, PROCESS_INFORMATION *pi)
{
const char *inferior_cwd = get_inferior_cwd ();
- std::string expanded_infcwd = gdb_tilde_expand (inferior_cwd);
BOOL ret;
#ifdef _WIN32_WCE
if (inferior_cwd != NULL)
{
+ std::string expanded_infcwd = gdb_tilde_expand (inferior_cwd);
std::replace (expanded_infcwd.begin (), expanded_infcwd.end (),
'/', '\\');
wcwd = alloca ((expanded_infcwd.size () + 1) * sizeof (wchar_t));
TRUE, /* inherit handles */
flags, /* start flags */
NULL, /* environment */
- expanded_infcwd.c_str (), /* current directory */
+ /* current directory */
+ (inferior_cwd == NULL
+ ? NULL
+ : gdb_tilde_expand (inferior_cwd).c_str()),
&si, /* start info */
pi); /* proc info */
#endif
win32_create_inferior (const char *program,
const std::vector<char *> &program_args)
{
+ client_state &cs = get_client_state ();
#ifndef USE_WIN32API
char real_path[PATH_MAX];
char *orig_path, *new_path, *path_ptr;
#endif
BOOL ret;
DWORD flags;
- int argslen;
- int argc;
PROCESS_INFORMATION pi;
DWORD err;
std::string str_program_args = stringify_argv (program_args);
do_initial_child_stuff (pi.hProcess, pi.dwProcessId, 0);
+ /* Wait till we are at 1st instruction in program, return new pid
+ (assuming success). */
+ cs.last_ptid = win32_wait (ptid_t (current_process_id), &cs.last_status, 0);
+
return current_process_id;
}
if (current_process_handle != NULL)
CloseHandle (current_process_handle);
- for_each_inferior (&all_threads, delete_thread_info);
+ for_each_thread (delete_thread_info);
clear_inferiors ();
}
-/* Kill all inferiors. */
+/* Implementation of target_ops::kill. */
+
static int
-win32_kill (int pid)
+win32_kill (process_info *process)
{
- struct process_info *process;
-
- if (current_process_handle == NULL)
- return -1;
-
TerminateProcess (current_process_handle, 0);
for (;;)
{
win32_clear_inferiors ();
- process = find_process_pid (pid);
remove_process (process);
return 0;
}
-/* Detach from inferior PID. */
+/* Implementation of target_ops::detach. */
+
static int
-win32_detach (int pid)
+win32_detach (process_info *process)
{
- struct process_info *process;
winapi_DebugActiveProcessStop DebugActiveProcessStop = NULL;
winapi_DebugSetProcessKillOnExit DebugSetProcessKillOnExit = NULL;
#ifdef _WIN32_WCE
return -1;
DebugSetProcessKillOnExit (FALSE);
- process = find_process_pid (pid);
remove_process (process);
win32_clear_inferiors ();
remove_process (process);
}
-/* Wait for inferiors to end. */
+/* Implementation of target_ops::join. */
+
static void
win32_join (int pid)
{
static int
win32_thread_alive (ptid_t ptid)
{
- int res;
-
/* Our thread list is reliable; don't bother to poll target
threads. */
- if (find_inferior_id (&all_threads, ptid) != NULL)
- res = 1;
- else
- res = 0;
- return res;
+ return find_thread_ptid (ptid) != NULL;
}
/* Resume the inferior process. RESUME_INFO describes how we want
/* This handles the very limited set of resume packets that GDB can
currently produce. */
- if (n == 1 && ptid_equal (resume_info[0].thread, minus_one_ptid))
+ if (n == 1 && resume_info[0].thread == minus_one_ptid)
tid = -1;
else if (n > 1)
tid = -1;
the Windows resume code do the right thing for thread switching. */
tid = current_event.dwThreadId;
- if (!ptid_equal (resume_info[0].thread, minus_one_ptid))
+ if (resume_info[0].thread != minus_one_ptid)
{
sig = gdb_signal_from_host (resume_info[0].sig);
step = resume_info[0].kind == resume_step;
current_event.u.Exception.ExceptionRecord.ExceptionCode
= EXCEPTION_BREAKPOINT;
- for_each_inferior (&all_threads, suspend_one_thread);
+ for_each_thread (suspend_one_thread);
}
#ifdef _WIN32_WCE
else
#endif
{
- /* Keep the wait time low enough for confortable remote
+ /* Keep the wait time low enough for comfortable remote
interruption, but high enough so gdbserver doesn't become a
bottleneck. */
if (!WaitForDebugEvent (¤t_event, 250))
"for pid=%u tid=%x\n",
(unsigned) current_event.dwProcessId,
(unsigned) current_event.dwThreadId));
- ourstatus->kind = TARGET_WAITKIND_EXITED;
- ourstatus->value.integer = current_event.u.ExitProcess.dwExitCode;
+ {
+ DWORD exit_status = current_event.u.ExitProcess.dwExitCode;
+ /* If the exit status looks like a fatal exception, but we
+ don't recognize the exception's code, make the original
+ exit status value available, to avoid losing information. */
+ int exit_signal
+ = WIFSIGNALED (exit_status) ? WTERMSIG (exit_status) : -1;
+ if (exit_signal == -1)
+ {
+ ourstatus->kind = TARGET_WAITKIND_EXITED;
+ ourstatus->value.integer = exit_status;
+ }
+ else
+ {
+ ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
+ ourstatus->value.sig = gdb_signal_from_host (exit_signal);
+ }
+ }
child_continue (DBG_CONTINUE, -1);
CloseHandle (current_process_handle);
current_process_handle = NULL;
}
ptid = debug_event_ptid (¤t_event);
- current_thread =
- (struct thread_info *) find_inferior_id (&all_threads, ptid);
+ current_thread = find_thread_ptid (ptid);
return 1;
}
OUTMSG2 (("Child exited with retcode = %x\n",
ourstatus->value.integer));
win32_clear_inferiors ();
- return pid_to_ptid (current_event.dwProcessId);
+ return ptid_t (current_event.dwProcessId);
case TARGET_WAITKIND_STOPPED:
+ case TARGET_WAITKIND_SIGNALLED:
case TARGET_WAITKIND_LOADED:
OUTMSG2 (("Child Stopped with signal = %d \n",
ourstatus->value.sig));
return the_low_target.breakpoint;
}
-static struct target_ops win32_target_ops = {
+static process_stratum_target win32_target_ops = {
win32_create_inferior,
NULL, /* post_create_inferior */
win32_attach,
win32_stopped_data_address,
NULL, /* read_offsets */
NULL, /* get_tls_address */
- NULL, /* qxfer_spu */
#ifdef _WIN32_WCE
wince_hostio_last_error,
#else
NULL, /* get_min_fast_tracepoint_insn_len */
NULL, /* qxfer_libraries_svr4 */
NULL, /* support_agent */
- NULL, /* support_btrace */
NULL, /* enable_btrace */
NULL, /* disable_btrace */
NULL, /* read_btrace */