/* Low level interface to Windows debugging, for gdbserver.
- Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+ Copyright (C) 2006-2018 Free Software Foundation, Inc.
Contributed by Leo Zayas. Based on "win32-nat.c" from GDB.
#include "server.h"
#include "regcache.h"
-#include "gdb/signals.h"
#include "gdb/fileio.h"
#include "mem-break.h"
#include "win32-low.h"
-
+#include "gdbthread.h"
+#include "dll.h"
+#include "hostio.h"
#include <windows.h>
#include <winnt.h>
#include <imagehlp.h>
#include <tlhelp32.h>
#include <psapi.h>
-#include <sys/param.h>
-#include <malloc.h>
#include <process.h>
+#include "gdb_tilde_expand.h"
+#include "common-inferior.h"
#ifndef USE_WIN32API
#include <sys/cygwin.h>
#endif
-#define LOG 0
+#define OUTMSG(X) do { printf X; fflush (stderr); } while (0)
-#define OUTMSG(X) do { printf X; fflush (stdout); } while (0)
-#if LOG
-#define OUTMSG2(X) do { printf X; fflush (stdout); } while (0)
-#else
-#define OUTMSG2(X) do ; while (0)
-#endif
+#define OUTMSG2(X) \
+ do \
+ { \
+ if (debug_threads) \
+ { \
+ printf X; \
+ fflush (stderr); \
+ } \
+ } while (0)
#ifndef _T
#define _T(x) TEXT (x)
static HANDLE current_process_handle = NULL;
static DWORD current_process_id = 0;
static DWORD main_thread_id = 0;
-static enum target_signal last_sig = TARGET_SIGNAL_0;
+static enum gdb_signal last_sig = GDB_SIGNAL_0;
/* The current debug event from WaitForDebugEvent. */
static DEBUG_EVENT current_event;
+/* A status that hasn't been reported to the core yet, and so
+ win32_wait should return it next, instead of fetching the next
+ debug event off the win32 API. */
+static struct target_waitstatus cached_status;
+
/* Non zero if an interrupt request is to be satisfied by suspending
all threads. */
static int soft_interrupt_requested = 0;
by suspending all the threads. */
static int faked_breakpoint = 0;
+const struct target_desc *win32_tdesc;
+
#define NUM_REGS (the_low_target.num_regs)
-typedef BOOL WINAPI (*winapi_DebugActiveProcessStop) (DWORD dwProcessId);
-typedef BOOL WINAPI (*winapi_DebugSetProcessKillOnExit) (BOOL KillOnExit);
-typedef BOOL WINAPI (*winapi_DebugBreakProcess) (HANDLE);
-typedef BOOL WINAPI (*winapi_GenerateConsoleCtrlEvent) (DWORD, DWORD);
+typedef BOOL (WINAPI *winapi_DebugActiveProcessStop) (DWORD dwProcessId);
+typedef BOOL (WINAPI *winapi_DebugSetProcessKillOnExit) (BOOL KillOnExit);
+typedef BOOL (WINAPI *winapi_DebugBreakProcess) (HANDLE);
+typedef BOOL (WINAPI *winapi_GenerateConsoleCtrlEvent) (DWORD, DWORD);
-static void win32_resume (struct thread_resume *resume_info);
+static ptid_t win32_wait (ptid_t ptid, struct target_waitstatus *ourstatus,
+ int options);
+static void win32_resume (struct thread_resume *resume_info, size_t n);
+#ifndef _WIN32_WCE
+static void win32_add_all_dlls (void);
+#endif
/* Get the thread ID from the current selected inferior (the current
thread). */
-static DWORD
-current_inferior_tid (void)
+static ptid_t
+current_thread_ptid (void)
{
- win32_thread_info *th = inferior_target_data (current_inferior);
- return th->tid;
+ return current_ptid;
+}
+
+/* The current debug event from WaitForDebugEvent. */
+static ptid_t
+debug_event_ptid (DEBUG_EVENT *event)
+{
+ return ptid_t (event->dwProcessId, event->dwThreadId, 0);
}
/* Get the thread context of the thread associated with TH. */
win32_get_thread_context (win32_thread_info *th)
{
memset (&th->context, 0, sizeof (CONTEXT));
- (*the_low_target.get_thread_context) (th, ¤t_event);
+ (*the_low_target.get_thread_context) (th);
#ifdef _WIN32_WCE
memcpy (&th->base_context, &th->context, sizeof (CONTEXT));
#endif
it between stopping and resuming. */
if (memcmp (&th->context, &th->base_context, sizeof (CONTEXT)) != 0)
#endif
- (*the_low_target.set_thread_context) (th, ¤t_event);
+ SetThreadContext (th->h, &th->context);
}
-/* Find a thread record given a thread id. If GET_CONTEXT is set then
- also retrieve the context for this thread. */
-static win32_thread_info *
-thread_rec (DWORD id, int get_context)
+/* Set the thread context of the thread associated with TH. */
+
+static void
+win32_prepare_to_resume (win32_thread_info *th)
{
- struct thread_info *thread;
- win32_thread_info *th;
+ if (the_low_target.prepare_to_resume != NULL)
+ (*the_low_target.prepare_to_resume) (th);
+}
- thread = (struct thread_info *) find_inferior_id (&all_threads, id);
- if (thread == NULL)
- return NULL;
+/* See win32-low.h. */
- th = inferior_target_data (thread);
- if (get_context && th->context.ContextFlags == 0)
+void
+win32_require_context (win32_thread_info *th)
+{
+ if (th->context.ContextFlags == 0)
{
if (!th->suspended)
{
win32_get_thread_context (th);
}
+}
+/* Find a thread record given a thread id. If GET_CONTEXT is set then
+ also retrieve the context for this thread. */
+static win32_thread_info *
+thread_rec (ptid_t ptid, int get_context)
+{
+ thread_info *thread = find_thread_ptid (ptid);
+ if (thread == NULL)
+ return NULL;
+
+ win32_thread_info *th = (win32_thread_info *) thread_target_data (thread);
+ if (get_context)
+ win32_require_context (th);
return th;
}
/* Add a thread to the thread list. */
static win32_thread_info *
-child_add_thread (DWORD tid, HANDLE h)
+child_add_thread (DWORD pid, DWORD tid, HANDLE h, void *tlb)
{
win32_thread_info *th;
+ ptid_t ptid = ptid_t (pid, tid, 0);
- if ((th = thread_rec (tid, FALSE)))
+ if ((th = thread_rec (ptid, FALSE)))
return th;
- th = xcalloc (1, sizeof (*th));
+ th = XCNEW (win32_thread_info);
th->tid = tid;
th->h = h;
+ th->thread_local_base = (CORE_ADDR) (uintptr_t) tlb;
- add_thread (tid, th, (unsigned int) tid);
- set_inferior_regcache_data ((struct thread_info *)
- find_inferior_id (&all_threads, tid),
- new_register_cache ());
+ add_thread (ptid, th);
if (the_low_target.thread_added != NULL)
(*the_low_target.thread_added) (th);
/* Delete a thread from the list of threads. */
static void
-delete_thread_info (struct inferior_list_entry *thread)
+delete_thread_info (thread_info *thread)
{
- win32_thread_info *th = inferior_target_data ((struct thread_info *) thread);
+ win32_thread_info *th = (win32_thread_info *) thread_target_data (thread);
- remove_thread ((struct thread_info *) thread);
+ remove_thread (thread);
CloseHandle (th->h);
free (th);
}
/* Delete a thread from the list of threads. */
static void
-child_delete_thread (DWORD id)
+child_delete_thread (DWORD pid, DWORD tid)
{
- struct inferior_list_entry *thread;
-
/* If the last thread is exiting, just return. */
- if (all_threads.head == all_threads.tail)
+ if (all_threads.size () == 1)
return;
- thread = find_inferior_id (&all_threads, id);
+ thread_info *thread = find_thread_ptid (ptid_t (pid, tid));
if (thread == NULL)
return;
delete_thread_info (thread);
}
+/* These watchpoint related wrapper functions simply pass on the function call
+ if the low target has registered a corresponding function. */
+
+static int
+win32_supports_z_point_type (char z_type)
+{
+ return (the_low_target.supports_z_point_type != NULL
+ && the_low_target.supports_z_point_type (z_type));
+}
+
+static int
+win32_insert_point (enum raw_bkpt_type type, CORE_ADDR addr,
+ int size, struct raw_breakpoint *bp)
+{
+ if (the_low_target.insert_point != NULL)
+ return the_low_target.insert_point (type, addr, size, bp);
+ else
+ /* Unsupported (see target.h). */
+ return 1;
+}
+
+static int
+win32_remove_point (enum raw_bkpt_type type, CORE_ADDR addr,
+ int size, struct raw_breakpoint *bp)
+{
+ if (the_low_target.remove_point != NULL)
+ return the_low_target.remove_point (type, addr, size, bp);
+ else
+ /* Unsupported (see target.h). */
+ return 1;
+}
+
+static int
+win32_stopped_by_watchpoint (void)
+{
+ if (the_low_target.stopped_by_watchpoint != NULL)
+ return the_low_target.stopped_by_watchpoint ();
+ else
+ return 0;
+}
+
+static CORE_ADDR
+win32_stopped_data_address (void)
+{
+ if (the_low_target.stopped_data_address != NULL)
+ return the_low_target.stopped_data_address ();
+ else
+ return 0;
+}
+
+
/* 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)
{
- SIZE_T done;
- long addr = (long) memaddr;
+ BOOL success;
+ SIZE_T done = 0;
+ DWORD lasterror = 0;
+ uintptr_t addr = (uintptr_t) memaddr;
if (write)
{
- WriteProcessMemory (current_process_handle, (LPVOID) addr,
- (LPCVOID) our, len, &done);
+ success = WriteProcessMemory (current_process_handle, (LPVOID) addr,
+ (LPCVOID) our, len, &done);
+ if (!success)
+ lasterror = GetLastError ();
FlushInstructionCache (current_process_handle, (LPCVOID) addr, len);
}
else
{
- ReadProcessMemory (current_process_handle, (LPCVOID) addr, (LPVOID) our,
- len, &done);
+ success = ReadProcessMemory (current_process_handle, (LPCVOID) addr,
+ (LPVOID) our, len, &done);
+ if (!success)
+ lasterror = GetLastError ();
}
- return done;
+ if (!success && lasterror == ERROR_PARTIAL_COPY && done > 0)
+ return done;
+ else
+ return success ? done : -1;
}
-/* Generally, what has the program done? */
-enum target_waitkind
-{
- /* The program has exited. The exit status is in value.integer. */
- TARGET_WAITKIND_EXITED,
-
- /* The program has stopped with a signal. Which signal is in
- value.sig. */
- TARGET_WAITKIND_STOPPED,
-
- /* The program is letting us know that it dynamically loaded
- or unloaded something. */
- TARGET_WAITKIND_LOADED,
-
- /* The program has exec'ed a new executable file. The new file's
- pathname is pointed to by value.execd_pathname. */
- TARGET_WAITKIND_EXECD,
-
- /* Nothing interesting happened, but we stopped anyway. We take the
- chance to check if GDB requested an interrupt. */
- TARGET_WAITKIND_SPURIOUS,
-};
-
-struct target_waitstatus
-{
- enum target_waitkind kind;
-
- /* Forked child pid, execd pathname, exit status or signal number. */
- union
- {
- int integer;
- enum target_signal sig;
- int related_pid;
- char *execd_pathname;
- int syscall_id;
- }
- value;
-};
-
/* Clear out any old thread list and reinitialize it to a pristine
state. */
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. */
+
+static int child_initialization_done = 0;
+
static void
-do_initial_child_stuff (HANDLE proch, DWORD pid)
+do_initial_child_stuff (HANDLE proch, DWORD pid, int attached)
{
- last_sig = TARGET_SIGNAL_0;
+ struct process_info *proc;
+
+ last_sig = GDB_SIGNAL_0;
current_process_handle = proch;
current_process_id = pid;
memset (¤t_event, 0, sizeof (current_event));
+ proc = add_process (pid, attached);
+ proc->tdesc = win32_tdesc;
child_init_thread_list ();
+ child_initialization_done = 0;
if (the_low_target.initial_stuff != NULL)
(*the_low_target.initial_stuff) ();
+
+ cached_status.kind = TARGET_WAITKIND_IGNORE;
+
+ /* Flush all currently pending debug events (thread and dll list) up
+ to the initial breakpoint. */
+ while (1)
+ {
+ struct target_waitstatus status;
+
+ win32_wait (minus_one_ptid, &status, 0);
+
+ /* Note win32_wait doesn't return thread events. */
+ if (status.kind != TARGET_WAITKIND_LOADED)
+ {
+ cached_status = status;
+ break;
+ }
+
+ {
+ struct thread_resume resume;
+
+ resume.thread = minus_one_ptid;
+ resume.kind = resume_continue;
+ resume.sig = 0;
+
+ win32_resume (&resume, 1);
+ }
+ }
+
+#ifndef _WIN32_WCE
+ /* Now that the inferior has been started and all DLLs have been mapped,
+ we can iterate over all DLLs and load them in.
+
+ We avoid doing it any earlier because, on certain versions of Windows,
+ LOAD_DLL_DEBUG_EVENTs are sometimes not complete. In particular,
+ we have seen on Windows 8.1 that the ntdll.dll load event does not
+ include the DLL name, preventing us from creating an associated SO.
+ A possible explanation is that ntdll.dll might be mapped before
+ the SO info gets created by the Windows system -- ntdll.dll is
+ the first DLL to be reported via LOAD_DLL_DEBUG_EVENT and other DLLs
+ do not seem to suffer from that problem.
+
+ 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. */
+ win32_add_all_dlls ();
+#endif
+
+ child_initialization_done = 1;
}
/* Resume all artificially suspended threads if we are continuing
execution. */
-static int
-continue_one_thread (struct inferior_list_entry *this_thread, void *id_ptr)
+static void
+continue_one_thread (thread_info *thread, int thread_id)
{
- struct thread_info *thread = (struct thread_info *) this_thread;
- int thread_id = * (int *) id_ptr;
- win32_thread_info *th = inferior_target_data (thread);
+ win32_thread_info *th = (win32_thread_info *) thread_target_data (thread);
- if ((thread_id == -1 || thread_id == th->tid)
- && th->suspended)
+ if (thread_id == -1 || thread_id == th->tid)
{
- if (th->context.ContextFlags)
- {
- win32_set_thread_context (th);
- th->context.ContextFlags = 0;
- }
+ win32_prepare_to_resume (th);
- if (ResumeThread (th->h) == (DWORD) -1)
+ if (th->suspended)
{
- DWORD err = GetLastError ();
- OUTMSG (("warning: ResumeThread failed in continue_one_thread, "
- "(error %d): %s\n", (int) err, strwinerror (err)));
+ if (th->context.ContextFlags)
+ {
+ win32_set_thread_context (th);
+ th->context.ContextFlags = 0;
+ }
+
+ if (ResumeThread (th->h) == (DWORD) -1)
+ {
+ DWORD err = GetLastError ();
+ OUTMSG (("warning: ResumeThread failed in continue_one_thread, "
+ "(error %d): %s\n", (int) err, strwinerror (err)));
+ }
+ th->suspended = 0;
}
- 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,
/* Fetch register(s) from the current thread context. */
static void
-child_fetch_inferior_registers (int r)
+child_fetch_inferior_registers (struct regcache *regcache, int r)
{
int regno;
- win32_thread_info *th = thread_rec (current_inferior_tid (), TRUE);
- if (r == -1 || r == 0 || r > NUM_REGS)
- child_fetch_inferior_registers (NUM_REGS);
+ win32_thread_info *th = thread_rec (current_thread_ptid (), TRUE);
+ if (r == -1 || r > NUM_REGS)
+ child_fetch_inferior_registers (regcache, NUM_REGS);
else
for (regno = 0; regno < r; regno++)
- (*the_low_target.fetch_inferior_register) (th, regno);
+ (*the_low_target.fetch_inferior_register) (regcache, th, regno);
}
/* Store a new register value into the current thread context. We don't
change the program's context until later, when we resume it. */
static void
-child_store_inferior_registers (int r)
+child_store_inferior_registers (struct regcache *regcache, int r)
{
int regno;
- win32_thread_info *th = thread_rec (current_inferior_tid (), TRUE);
+ win32_thread_info *th = thread_rec (current_thread_ptid (), TRUE);
if (r == -1 || r == 0 || r > NUM_REGS)
- child_store_inferior_registers (NUM_REGS);
+ child_store_inferior_registers (regcache, NUM_REGS);
else
for (regno = 0; regno < r; regno++)
- (*the_low_target.store_inferior_register) (th, regno);
+ (*the_low_target.store_inferior_register) (regcache, th, regno);
}
/* Map the Windows error number in ERROR to a locale-dependent error
NULL,
error,
0, /* Default language */
- (LPVOID)&msgbuf,
+ (LPTSTR) &msgbuf,
0,
NULL);
if (chars != 0)
LocalFree (msgbuf);
}
else
- sprintf (buf, "unknown win32 error (%ld)", error);
+ sprintf (buf, "unknown win32 error (%u)", (unsigned) error);
SetLastError (lasterr);
return buf;
create_process (const char *program, char *args,
DWORD flags, PROCESS_INFORMATION *pi)
{
+ const char *inferior_cwd = get_inferior_cwd ();
BOOL ret;
#ifdef _WIN32_WCE
- wchar_t *p, *wprogram, *wargs;
+ wchar_t *p, *wprogram, *wargs, *wcwd = NULL;
size_t argslen;
wprogram = alloca ((strlen (program) + 1) * sizeof (wchar_t));
wargs = alloca ((argslen + 1) * sizeof (wchar_t));
mbstowcs (wargs, args, argslen + 1);
+ 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));
+ if (mbstowcs (wcwd, expanded_infcwd.c_str (),
+ expanded_infcwd.size () + 1) == NULL)
+ {
+ error (_("\
+Could not convert the expanded inferior cwd to wide-char."));
+ }
+ }
+
ret = CreateProcessW (wprogram, /* image name */
- wargs, /* command line */
- NULL, /* security, not supported */
- NULL, /* thread, not supported */
- FALSE, /* inherit handles, not supported */
- flags, /* start flags */
- NULL, /* environment, not supported */
- NULL, /* current directory, not supported */
- NULL, /* start info, not supported */
- pi); /* proc info */
+ wargs, /* command line */
+ NULL, /* security, not supported */
+ NULL, /* thread, not supported */
+ FALSE, /* inherit handles, not supported */
+ flags, /* start flags */
+ NULL, /* environment, not supported */
+ wcwd, /* current directory */
+ NULL, /* start info, not supported */
+ pi); /* proc info */
#else
STARTUPINFOA si = { sizeof (STARTUPINFOA) };
TRUE, /* inherit handles */
flags, /* start flags */
NULL, /* environment */
- NULL, /* current directory */
+ /* current directory */
+ (inferior_cwd == NULL
+ ? NULL
+ : gdb_tilde_expand (inferior_cwd).c_str()),
&si, /* start info */
pi); /* proc info */
#endif
}
/* Start a new process.
- PROGRAM is a path to the program to execute.
- ARGS is a standard NULL-terminated array of arguments,
- to be passed to the inferior as ``argv''.
+ PROGRAM is the program name.
+ PROGRAM_ARGS is the vector containing the inferior's args.
Returns the new PID on success, -1 on failure. Registers the new
process with the process list. */
static int
-win32_create_inferior (char *program, char **program_args)
+win32_create_inferior (const char *program,
+ const std::vector<char *> &program_args)
{
+ client_state &cs = get_client_state ();
#ifndef USE_WIN32API
- char real_path[MAXPATHLEN];
+ char real_path[PATH_MAX];
char *orig_path, *new_path, *path_ptr;
#endif
BOOL ret;
DWORD flags;
- char *args;
- int argslen;
- int argc;
PROCESS_INFORMATION pi;
DWORD err;
+ std::string str_program_args = stringify_argv (program_args);
+ char *args = (char *) str_program_args.c_str ();
/* win32_wait needs to know we're not attaching. */
attaching = 0;
path_ptr = getenv ("PATH");
if (path_ptr)
{
- orig_path = alloca (strlen (path_ptr) + 1);
- new_path = alloca (cygwin_posix_to_win32_path_list_buf_size (path_ptr));
+ int size = cygwin_conv_path_list (CCP_POSIX_TO_WIN_A, path_ptr, NULL, 0);
+ orig_path = (char *) alloca (strlen (path_ptr) + 1);
+ new_path = (char *) alloca (size);
strcpy (orig_path, path_ptr);
- cygwin_posix_to_win32_path_list (path_ptr, new_path);
+ cygwin_conv_path_list (CCP_POSIX_TO_WIN_A, path_ptr, new_path, size);
setenv ("PATH", new_path, 1);
- }
- cygwin_conv_to_win32_path (program, real_path);
+ }
+ cygwin_conv_path (CCP_POSIX_TO_WIN_A, program, real_path, PATH_MAX);
program = real_path;
#endif
- argslen = 1;
- for (argc = 1; program_args[argc]; argc++)
- argslen += strlen (program_args[argc]) + 1;
- args = alloca (argslen);
- args[0] = '\0';
- for (argc = 1; program_args[argc]; argc++)
- {
- /* FIXME: Can we do better about quoting? How does Cygwin
- handle this? */
- strcat (args, " ");
- strcat (args, program_args[argc]);
- }
OUTMSG2 (("Command line is \"%s\"\n", args));
#ifdef CREATE_NEW_PROCESS_GROUP
err = GetLastError ();
if (!ret && err == ERROR_FILE_NOT_FOUND)
{
- char *exename = alloca (strlen (program) + 5);
+ char *exename = (char *) alloca (strlen (program) + 5);
strcat (strcpy (exename, program), ".exe");
ret = create_process (exename, args, flags, &pi);
err = GetLastError ();
CloseHandle (pi.hThread);
#endif
- do_initial_child_stuff (pi.hProcess, pi.dwProcessId);
+ 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;
}
DebugSetProcessKillOnExit (FALSE);
/* win32_wait needs to know we're attaching. */
- attaching = 1;
- do_initial_child_stuff (h, pid);
+ attaching = 1;
+ do_initial_child_stuff (h, pid, 1);
return 0;
}
/* Handle OUTPUT_DEBUG_STRING_EVENT from child process. */
static void
-handle_output_debug_string (struct target_waitstatus *ourstatus)
+handle_output_debug_string (void)
{
#define READ_BUFFER_LEN 1024
CORE_ADDR addr;
if (current_event.u.DebugString.fUnicode)
{
/* The event tells us how many bytes, not chars, even
- in Unicode. */
+ in Unicode. */
WCHAR buffer[(READ_BUFFER_LEN + 1) / sizeof (WCHAR)] = { 0 };
if (read_inferior_memory (addr, (unsigned char *) buffer, nbytes) != 0)
return;
return;
}
- if (strncmp (s, "cYg", 3) != 0)
+ if (!startswith (s, "cYg"))
{
if (!server_waiting)
{
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. */
-static void
-win32_kill (void)
-{
- if (current_process_handle == NULL)
- return;
+/* Implementation of target_ops::kill. */
+static int
+win32_kill (process_info *process)
+{
TerminateProcess (current_process_handle, 0);
for (;;)
{
if (current_event.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT)
break;
else if (current_event.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT)
- {
- struct target_waitstatus our_status = { 0 };
- handle_output_debug_string (&our_status);
- }
+ handle_output_debug_string ();
}
win32_clear_inferiors ();
+
+ remove_process (process);
+ return 0;
}
-/* Detach from all inferiors. */
+/* Implementation of target_ops::detach. */
+
static int
-win32_detach (void)
+win32_detach (process_info *process)
{
winapi_DebugActiveProcessStop DebugActiveProcessStop = NULL;
winapi_DebugSetProcessKillOnExit DebugSetProcessKillOnExit = NULL;
{
struct thread_resume resume;
- resume.thread = -1;
- resume.step = 0;
+ resume.thread = minus_one_ptid;
+ resume.kind = resume_continue;
resume.sig = 0;
- resume.leave_stopped = 0;
- win32_resume (&resume);
+ win32_resume (&resume, 1);
}
if (!DebugActiveProcessStop (current_process_id))
return -1;
DebugSetProcessKillOnExit (FALSE);
+ remove_process (process);
win32_clear_inferiors ();
return 0;
}
-/* Wait for inferiors to end. */
static void
-win32_join (void)
+win32_mourn (struct process_info *process)
{
- extern unsigned long signal_pid;
+ remove_process (process);
+}
+
+/* Implementation of target_ops::join. */
- HANDLE h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, signal_pid);
+static void
+win32_join (process_info *proc)
+{
+ HANDLE h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, proc->pid);
if (h != NULL)
{
WaitForSingleObject (h, INFINITE);
/* Return 1 iff the thread with thread ID TID is alive. */
static int
-win32_thread_alive (unsigned long tid)
+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, tid) != NULL)
- res = 1;
- else
- res = 0;
- return res;
+ return find_thread_ptid (ptid) != NULL;
}
/* Resume the inferior process. RESUME_INFO describes how we want
to resume. */
static void
-win32_resume (struct thread_resume *resume_info)
+win32_resume (struct thread_resume *resume_info, size_t n)
{
DWORD tid;
- enum target_signal sig;
+ enum gdb_signal sig;
int step;
win32_thread_info *th;
DWORD continue_status = DBG_CONTINUE;
+ ptid_t ptid;
/* This handles the very limited set of resume packets that GDB can
currently produce. */
- if (resume_info[0].thread == -1)
+ if (n == 1 && resume_info[0].thread == minus_one_ptid)
tid = -1;
- else if (resume_info[1].thread == -1 && !resume_info[1].leave_stopped)
+ else if (n > 1)
tid = -1;
else
/* Yes, we're ignoring resume_info[0].thread. It'd be tricky to make
the Windows resume code do the right thing for thread switching. */
tid = current_event.dwThreadId;
- if (resume_info[0].thread != -1)
+ if (resume_info[0].thread != minus_one_ptid)
{
- sig = resume_info[0].sig;
- step = resume_info[0].step;
+ sig = gdb_signal_from_host (resume_info[0].sig);
+ step = resume_info[0].kind == resume_step;
}
else
{
- sig = 0;
+ sig = GDB_SIGNAL_0;
step = 0;
}
- if (sig != TARGET_SIGNAL_0)
+ if (sig != GDB_SIGNAL_0)
{
if (current_event.dwDebugEventCode != EXCEPTION_DEBUG_EVENT)
{
- OUTMSG (("Cannot continue with signal %d here.\n", sig));
+ OUTMSG (("Cannot continue with signal %s here.\n",
+ gdb_signal_to_string (sig)));
}
else if (sig == last_sig)
continue_status = DBG_EXCEPTION_NOT_HANDLED;
else
- OUTMSG (("Can only continue with recieved signal %d.\n", last_sig));
+ OUTMSG (("Can only continue with received signal %s.\n",
+ gdb_signal_to_string (last_sig)));
}
- last_sig = TARGET_SIGNAL_0;
+ last_sig = GDB_SIGNAL_0;
/* Get context for the currently selected thread. */
- th = thread_rec (current_event.dwThreadId, FALSE);
+ ptid = debug_event_ptid (¤t_event);
+ th = thread_rec (ptid, FALSE);
if (th)
{
+ win32_prepare_to_resume (th);
+
if (th->context.ContextFlags)
{
/* Move register values from the inferior into the thread
HANDLE h = FindFirstFileA (name, &w32_fd);
#endif
+ /* 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. */
+ load_addr += 0x1000;
+
if (h == INVALID_HANDLE_VALUE)
strcpy (buf, name);
else
#endif
}
+#ifndef _WIN32_WCE
+ if (strcasecmp (buf, "ntdll.dll") == 0)
+ {
+ GetSystemDirectoryA (buf, sizeof (buf));
+ strcat (buf, "\\ntdll.dll");
+ }
+#endif
+
#ifdef __CYGWIN__
- cygwin_conv_to_posix_path (buf, buf2);
+ cygwin_conv_path (CCP_WIN_A_TO_POSIX, buf, buf2, sizeof (buf2));
#else
strcpy (buf2, buf);
#endif
char *address_ptr;
int len = 0;
char b[2];
- DWORD done;
+ SIZE_T done;
/* Attempt to read the name of the dll that was detected.
This is documented to work only when actively debugging
ReadProcessMemory (h, address_ptr, buf, len, &done);
else
{
- WCHAR *unicode_address = (WCHAR *) alloca (len * sizeof (WCHAR));
+ WCHAR *unicode_address = XALLOCAVEC (WCHAR, len);
ReadProcessMemory (h, address_ptr, unicode_address, len * sizeof (WCHAR),
&done);
&& win32_GetModuleFileNameExA != NULL);
}
-static int
-psapi_get_dll_name (DWORD BaseAddress, char *dll_name_ret)
+#ifndef _WIN32_WCE
+
+/* Iterate over all DLLs currently mapped by our inferior, and
+ add them to our list of solibs. */
+
+static void
+win32_add_all_dlls (void)
{
- DWORD len;
- MODULEINFO mi;
size_t i;
HMODULE dh_buf[1];
HMODULE *DllHandle = dh_buf;
BOOL ok;
if (!load_psapi ())
- goto failed;
+ return;
cbNeeded = 0;
ok = (*win32_EnumProcessModules) (current_process_handle,
&cbNeeded);
if (!ok || !cbNeeded)
- goto failed;
+ return;
DllHandle = (HMODULE *) alloca (cbNeeded);
if (!DllHandle)
- goto failed;
+ return;
ok = (*win32_EnumProcessModules) (current_process_handle,
DllHandle,
cbNeeded,
&cbNeeded);
if (!ok)
- goto failed;
+ return;
- for (i = 0; i < ((size_t) cbNeeded / sizeof (HMODULE)); i++)
+ for (i = 1; i < ((size_t) cbNeeded / sizeof (HMODULE)); i++)
{
+ MODULEINFO mi;
+ char dll_name[MAX_PATH];
+
if (!(*win32_GetModuleInformation) (current_process_handle,
DllHandle[i],
&mi,
sizeof (mi)))
- {
- DWORD err = GetLastError ();
- error ("Can't get module info: (error %d): %s\n",
- (int) err, strwinerror (err));
- }
-
- if ((DWORD) (mi.lpBaseOfDll) == BaseAddress)
- {
- len = (*win32_GetModuleFileNameExA) (current_process_handle,
- DllHandle[i],
- dll_name_ret,
- MAX_PATH);
- if (len == 0)
- {
- DWORD err = GetLastError ();
- error ("Error getting dll name: (error %d): %s\n",
- (int) err, strwinerror (err));
- }
- return 1;
- }
+ continue;
+ if ((*win32_GetModuleFileNameExA) (current_process_handle,
+ DllHandle[i],
+ dll_name,
+ MAX_PATH) == 0)
+ continue;
+ win32_add_one_solib (dll_name, (CORE_ADDR) (uintptr_t) mi.lpBaseOfDll);
}
-
-failed:
- dll_name_ret[0] = '\0';
- return 0;
}
+#endif
typedef HANDLE (WINAPI *winapi_CreateToolhelp32Snapshot) (DWORD, DWORD);
typedef BOOL (WINAPI *winapi_Module32First) (HANDLE, LPMODULEENTRY32);
typedef BOOL (WINAPI *winapi_Module32Next) (HANDLE, LPMODULEENTRY32);
-static winapi_CreateToolhelp32Snapshot win32_CreateToolhelp32Snapshot;
-static winapi_Module32First win32_Module32First;
-static winapi_Module32Next win32_Module32Next;
-#ifdef _WIN32_WCE
-typedef BOOL (WINAPI *winapi_CloseToolhelp32Snapshot) (HANDLE);
-static winapi_CloseToolhelp32Snapshot win32_CloseToolhelp32Snapshot;
-#endif
-
-static BOOL
-load_toolhelp (void)
-{
- static int toolhelp_loaded = 0;
- static HMODULE dll = NULL;
-
- if (!toolhelp_loaded)
- {
- toolhelp_loaded = 1;
-#ifndef _WIN32_WCE
- dll = GetModuleHandle (_T("KERNEL32.DLL"));
-#else
- dll = LoadLibrary (L"TOOLHELP.DLL");
-#endif
- if (!dll)
- return FALSE;
-
- win32_CreateToolhelp32Snapshot =
- GETPROCADDRESS (dll, CreateToolhelp32Snapshot);
- win32_Module32First = GETPROCADDRESS (dll, Module32First);
- win32_Module32Next = GETPROCADDRESS (dll, Module32Next);
-#ifdef _WIN32_WCE
- win32_CloseToolhelp32Snapshot =
- GETPROCADDRESS (dll, CloseToolhelp32Snapshot);
-#endif
- }
-
- return (win32_CreateToolhelp32Snapshot != NULL
- && win32_Module32First != NULL
- && win32_Module32Next != NULL
-#ifdef _WIN32_WCE
- && win32_CloseToolhelp32Snapshot != NULL
-#endif
- );
-}
-
-static int
-toolhelp_get_dll_name (DWORD BaseAddress, char *dll_name_ret)
-{
- HANDLE snapshot_module;
- MODULEENTRY32 modEntry = { sizeof (MODULEENTRY32) };
- int found = 0;
+/* Handle a DLL load event.
- if (!load_toolhelp ())
- return 0;
-
- snapshot_module = win32_CreateToolhelp32Snapshot (TH32CS_SNAPMODULE,
- current_event.dwProcessId);
- if (snapshot_module == INVALID_HANDLE_VALUE)
- return 0;
-
- /* Ignore the first module, which is the exe. */
- if (win32_Module32First (snapshot_module, &modEntry))
- while (win32_Module32Next (snapshot_module, &modEntry))
- if ((DWORD) modEntry.modBaseAddr == BaseAddress)
- {
-#ifdef UNICODE
- wcstombs (dll_name_ret, modEntry.szExePath, MAX_PATH + 1);
-#else
- strcpy (dll_name_ret, modEntry.szExePath);
-#endif
- found = 1;
- break;
- }
-
-#ifdef _WIN32_WCE
- win32_CloseToolhelp32Snapshot (snapshot_module);
-#else
- CloseHandle (snapshot_module);
-#endif
- return found;
-}
+ This function assumes that this event did not occur during inferior
+ initialization, where their event info may be incomplete (see
+ do_initial_child_stuff and win32_add_all_dlls for more info on
+ how we handle DLL loading during that phase). */
static void
handle_load_dll (void)
{
LOAD_DLL_DEBUG_INFO *event = ¤t_event.u.LoadDll;
- char dll_buf[MAX_PATH + 1];
- char *dll_name = NULL;
- DWORD load_addr;
+ char *dll_name;
- dll_buf[0] = dll_buf[sizeof (dll_buf) - 1] = '\0';
-
- /* Windows does not report the image name of the dlls in the debug
- event on attaches. We resort to iterating over the list of
- loaded dlls looking for a match by image base. */
- if (!psapi_get_dll_name ((DWORD) event->lpBaseOfDll, dll_buf))
- {
- if (!server_waiting)
- /* On some versions of Windows and Windows CE, we can't create
- toolhelp snapshots while the inferior is stopped in a
- LOAD_DLL_DEBUG_EVENT due to a dll load, but we can while
- Windows is reporting the already loaded dlls. */
- toolhelp_get_dll_name ((DWORD) event->lpBaseOfDll, dll_buf);
- }
-
- dll_name = dll_buf;
-
- if (*dll_name == '\0')
- dll_name = get_image_name (current_process_handle,
- event->lpImageName, event->fUnicode);
+ dll_name = get_image_name (current_process_handle,
+ event->lpImageName, event->fUnicode);
if (!dll_name)
return;
- /* The symbols in a dll are offset by 0x1000, which is the
- the offset from 0 of the first byte in an image - because
- of the file header and the section alignment. */
-
- load_addr = (DWORD) event->lpBaseOfDll + 0x1000;
- win32_add_one_solib (dll_name, load_addr);
+ win32_add_one_solib (dll_name, (CORE_ADDR) (uintptr_t) event->lpBaseOfDll);
}
+/* Handle a DLL unload event.
+
+ This function assumes that this event did not occur during inferior
+ initialization, where their event info may be incomplete (see
+ do_initial_child_stuff and win32_add_one_solib for more info
+ on how we handle DLL loading during that phase). */
+
static void
handle_unload_dll (void)
{
CORE_ADDR load_addr =
- (CORE_ADDR) (DWORD) current_event.u.UnloadDll.lpBaseOfDll;
+ (CORE_ADDR) (uintptr_t) current_event.u.UnloadDll.lpBaseOfDll;
+
+ /* 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. */
load_addr += 0x1000;
unloaded_dll (NULL, load_addr);
}
{
case EXCEPTION_ACCESS_VIOLATION:
OUTMSG2 (("EXCEPTION_ACCESS_VIOLATION"));
- ourstatus->value.sig = TARGET_SIGNAL_SEGV;
+ ourstatus->value.sig = GDB_SIGNAL_SEGV;
break;
case STATUS_STACK_OVERFLOW:
OUTMSG2 (("STATUS_STACK_OVERFLOW"));
- ourstatus->value.sig = TARGET_SIGNAL_SEGV;
+ ourstatus->value.sig = GDB_SIGNAL_SEGV;
break;
case STATUS_FLOAT_DENORMAL_OPERAND:
OUTMSG2 (("STATUS_FLOAT_DENORMAL_OPERAND"));
- ourstatus->value.sig = TARGET_SIGNAL_FPE;
+ ourstatus->value.sig = GDB_SIGNAL_FPE;
break;
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
OUTMSG2 (("EXCEPTION_ARRAY_BOUNDS_EXCEEDED"));
- ourstatus->value.sig = TARGET_SIGNAL_FPE;
+ ourstatus->value.sig = GDB_SIGNAL_FPE;
break;
case STATUS_FLOAT_INEXACT_RESULT:
OUTMSG2 (("STATUS_FLOAT_INEXACT_RESULT"));
- ourstatus->value.sig = TARGET_SIGNAL_FPE;
+ ourstatus->value.sig = GDB_SIGNAL_FPE;
break;
case STATUS_FLOAT_INVALID_OPERATION:
OUTMSG2 (("STATUS_FLOAT_INVALID_OPERATION"));
- ourstatus->value.sig = TARGET_SIGNAL_FPE;
+ ourstatus->value.sig = GDB_SIGNAL_FPE;
break;
case STATUS_FLOAT_OVERFLOW:
OUTMSG2 (("STATUS_FLOAT_OVERFLOW"));
- ourstatus->value.sig = TARGET_SIGNAL_FPE;
+ ourstatus->value.sig = GDB_SIGNAL_FPE;
break;
case STATUS_FLOAT_STACK_CHECK:
OUTMSG2 (("STATUS_FLOAT_STACK_CHECK"));
- ourstatus->value.sig = TARGET_SIGNAL_FPE;
+ ourstatus->value.sig = GDB_SIGNAL_FPE;
break;
case STATUS_FLOAT_UNDERFLOW:
OUTMSG2 (("STATUS_FLOAT_UNDERFLOW"));
- ourstatus->value.sig = TARGET_SIGNAL_FPE;
+ ourstatus->value.sig = GDB_SIGNAL_FPE;
break;
case STATUS_FLOAT_DIVIDE_BY_ZERO:
OUTMSG2 (("STATUS_FLOAT_DIVIDE_BY_ZERO"));
- ourstatus->value.sig = TARGET_SIGNAL_FPE;
+ ourstatus->value.sig = GDB_SIGNAL_FPE;
break;
case STATUS_INTEGER_DIVIDE_BY_ZERO:
OUTMSG2 (("STATUS_INTEGER_DIVIDE_BY_ZERO"));
- ourstatus->value.sig = TARGET_SIGNAL_FPE;
+ ourstatus->value.sig = GDB_SIGNAL_FPE;
break;
case STATUS_INTEGER_OVERFLOW:
OUTMSG2 (("STATUS_INTEGER_OVERFLOW"));
- ourstatus->value.sig = TARGET_SIGNAL_FPE;
+ ourstatus->value.sig = GDB_SIGNAL_FPE;
break;
case EXCEPTION_BREAKPOINT:
OUTMSG2 (("EXCEPTION_BREAKPOINT"));
- ourstatus->value.sig = TARGET_SIGNAL_TRAP;
+ ourstatus->value.sig = GDB_SIGNAL_TRAP;
#ifdef _WIN32_WCE
/* Remove the initial breakpoint. */
check_breakpoints ((CORE_ADDR) (long) current_event
- .u.Exception.ExceptionRecord.ExceptionAddress);
+ .u.Exception.ExceptionRecord.ExceptionAddress);
#endif
break;
case DBG_CONTROL_C:
OUTMSG2 (("DBG_CONTROL_C"));
- ourstatus->value.sig = TARGET_SIGNAL_INT;
+ ourstatus->value.sig = GDB_SIGNAL_INT;
break;
case DBG_CONTROL_BREAK:
OUTMSG2 (("DBG_CONTROL_BREAK"));
- ourstatus->value.sig = TARGET_SIGNAL_INT;
+ ourstatus->value.sig = GDB_SIGNAL_INT;
break;
case EXCEPTION_SINGLE_STEP:
OUTMSG2 (("EXCEPTION_SINGLE_STEP"));
- ourstatus->value.sig = TARGET_SIGNAL_TRAP;
+ ourstatus->value.sig = GDB_SIGNAL_TRAP;
break;
case EXCEPTION_ILLEGAL_INSTRUCTION:
OUTMSG2 (("EXCEPTION_ILLEGAL_INSTRUCTION"));
- ourstatus->value.sig = TARGET_SIGNAL_ILL;
+ ourstatus->value.sig = GDB_SIGNAL_ILL;
break;
case EXCEPTION_PRIV_INSTRUCTION:
OUTMSG2 (("EXCEPTION_PRIV_INSTRUCTION"));
- ourstatus->value.sig = TARGET_SIGNAL_ILL;
+ ourstatus->value.sig = GDB_SIGNAL_ILL;
break;
case EXCEPTION_NONCONTINUABLE_EXCEPTION:
OUTMSG2 (("EXCEPTION_NONCONTINUABLE_EXCEPTION"));
- ourstatus->value.sig = TARGET_SIGNAL_ILL;
+ ourstatus->value.sig = GDB_SIGNAL_ILL;
break;
default:
if (current_event.u.Exception.dwFirstChance)
ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
return;
}
- OUTMSG2 (("gdbserver: unknown target exception 0x%08lx at 0x%08lx",
- current_event.u.Exception.ExceptionRecord.ExceptionCode,
- (DWORD) current_event.u.Exception.ExceptionRecord.
- ExceptionAddress));
- ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN;
+ OUTMSG2 (("gdbserver: unknown target exception 0x%08x at 0x%s",
+ (unsigned) current_event.u.Exception.ExceptionRecord.ExceptionCode,
+ phex_nz ((uintptr_t) current_event.u.Exception.ExceptionRecord.
+ ExceptionAddress, sizeof (uintptr_t))));
+ ourstatus->value.sig = GDB_SIGNAL_UNKNOWN;
break;
}
OUTMSG2 (("\n"));
static void
-suspend_one_thread (struct inferior_list_entry *entry)
+suspend_one_thread (thread_info *thread)
{
- struct thread_info *thread = (struct thread_info *) entry;
- win32_thread_info *th = inferior_target_data (thread);
+ win32_thread_info *th = (win32_thread_info *) thread_target_data (thread);
if (!th->suspended)
{
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
static int
get_child_debug_event (struct target_waitstatus *ourstatus)
{
- last_sig = TARGET_SIGNAL_0;
+ ptid_t ptid;
+
+ last_sig = GDB_SIGNAL_0;
ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
/* Check if GDB sent us an interrupt request. */
if (attaching)
{
/* WinCE doesn't set an initial breakpoint automatically. To
- stop the inferior, we flush all currently pending debug
- events -- the thread list and the dll list are always
- reported immediatelly without delay, then, we suspend all
- threads and pretend we saw a trap at the current PC of the
- main thread.
-
- Contrary to desktop Windows, Windows CE *does* report the dll
- names on LOAD_DLL_DEBUG_EVENTs resulting from a
- DebugActiveProcess call. This limits the way we can detect
- if all the dlls have already been reported. If we get a real
- debug event before leaving attaching, the worst that will
- happen is the user will see a spurious breakpoint. */
+ stop the inferior, we flush all currently pending debug
+ events -- the thread list and the dll list are always
+ reported immediatelly without delay, then, we suspend all
+ threads and pretend we saw a trap at the current PC of the
+ main thread.
+
+ Contrary to desktop Windows, Windows CE *does* report the dll
+ names on LOAD_DLL_DEBUG_EVENTs resulting from a
+ DebugActiveProcess call. This limits the way we can detect
+ if all the dlls have already been reported. If we get a real
+ debug event before leaving attaching, the worst that will
+ happen is the user will see a spurious breakpoint. */
current_event.dwDebugEventCode = 0;
if (!WaitForDebugEvent (¤t_event, 0))
- {
- OUTMSG2(("no attach events left\n"));
- fake_breakpoint_event ();
- attaching = 0;
- }
+ {
+ OUTMSG2(("no attach events left\n"));
+ fake_breakpoint_event ();
+ attaching = 0;
+ }
else
- OUTMSG2(("got attach event\n"));
+ OUTMSG2(("got attach event\n"));
}
else
#endif
{
/* Keep the wait time low enough for confortable remote
- interruption, but high enough so gdbserver doesn't become a
- bottleneck. */
+ interruption, but high enough so gdbserver doesn't become a
+ bottleneck. */
if (!WaitForDebugEvent (¤t_event, 250))
- return 0;
+ {
+ DWORD e = GetLastError();
+
+ if (e == ERROR_PIPE_NOT_CONNECTED)
+ {
+ /* This will happen if the loader fails to succesfully
+ load the application, e.g., if the main executable
+ tries to pull in a non-existing export from a
+ DLL. */
+ ourstatus->kind = TARGET_WAITKIND_EXITED;
+ ourstatus->value.integer = 1;
+ return 1;
+ }
+
+ return 0;
+ }
}
gotevent:
- current_inferior =
- (struct thread_info *) find_inferior_id (&all_threads,
- current_event.dwThreadId);
-
switch (current_event.dwDebugEventCode)
{
case CREATE_THREAD_DEBUG_EVENT:
OUTMSG2 (("gdbserver: kernel event CREATE_THREAD_DEBUG_EVENT "
- "for pid=%d tid=%x)\n",
+ "for pid=%u tid=%x)\n",
(unsigned) current_event.dwProcessId,
(unsigned) current_event.dwThreadId));
/* Record the existence of this thread. */
- child_add_thread (current_event.dwThreadId,
- current_event.u.CreateThread.hThread);
+ child_add_thread (current_event.dwProcessId,
+ current_event.dwThreadId,
+ current_event.u.CreateThread.hThread,
+ current_event.u.CreateThread.lpThreadLocalBase);
break;
case EXIT_THREAD_DEBUG_EVENT:
OUTMSG2 (("gdbserver: kernel event EXIT_THREAD_DEBUG_EVENT "
- "for pid=%d tid=%x\n",
+ "for pid=%u tid=%x\n",
(unsigned) current_event.dwProcessId,
(unsigned) current_event.dwThreadId));
- child_delete_thread (current_event.dwThreadId);
- break;
+ child_delete_thread (current_event.dwProcessId,
+ current_event.dwThreadId);
+
+ current_thread = get_first_thread ();
+ return 1;
case CREATE_PROCESS_DEBUG_EVENT:
OUTMSG2 (("gdbserver: kernel event CREATE_PROCESS_DEBUG_EVENT "
- "for pid=%d tid=%x\n",
+ "for pid=%u tid=%x\n",
(unsigned) current_event.dwProcessId,
(unsigned) current_event.dwThreadId));
CloseHandle (current_event.u.CreateProcessInfo.hFile);
current_process_handle = current_event.u.CreateProcessInfo.hProcess;
main_thread_id = current_event.dwThreadId;
- ourstatus->kind = TARGET_WAITKIND_EXECD;
- ourstatus->value.execd_pathname = "Main executable";
-
/* Add the main thread. */
- child_add_thread (main_thread_id,
- current_event.u.CreateProcessInfo.hThread);
+ child_add_thread (current_event.dwProcessId,
+ main_thread_id,
+ current_event.u.CreateProcessInfo.hThread,
+ current_event.u.CreateProcessInfo.lpThreadLocalBase);
- ourstatus->value.related_pid = current_event.dwThreadId;
#ifdef _WIN32_WCE
if (!attaching)
{
case EXIT_PROCESS_DEBUG_EVENT:
OUTMSG2 (("gdbserver: kernel event EXIT_PROCESS_DEBUG_EVENT "
- "for pid=%d tid=%x\n",
+ "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;
+ child_continue (DBG_CONTINUE, -1);
CloseHandle (current_process_handle);
current_process_handle = NULL;
break;
case LOAD_DLL_DEBUG_EVENT:
OUTMSG2 (("gdbserver: kernel event LOAD_DLL_DEBUG_EVENT "
- "for pid=%d tid=%x\n",
+ "for pid=%u tid=%x\n",
(unsigned) current_event.dwProcessId,
(unsigned) current_event.dwThreadId));
CloseHandle (current_event.u.LoadDll.hFile);
+ if (! child_initialization_done)
+ break;
handle_load_dll ();
ourstatus->kind = TARGET_WAITKIND_LOADED;
- ourstatus->value.sig = TARGET_SIGNAL_TRAP;
+ ourstatus->value.sig = GDB_SIGNAL_TRAP;
break;
case UNLOAD_DLL_DEBUG_EVENT:
OUTMSG2 (("gdbserver: kernel event UNLOAD_DLL_DEBUG_EVENT "
- "for pid=%d tid=%x\n",
+ "for pid=%u tid=%x\n",
(unsigned) current_event.dwProcessId,
(unsigned) current_event.dwThreadId));
+ if (! child_initialization_done)
+ break;
handle_unload_dll ();
ourstatus->kind = TARGET_WAITKIND_LOADED;
- ourstatus->value.sig = TARGET_SIGNAL_TRAP;
+ ourstatus->value.sig = GDB_SIGNAL_TRAP;
break;
case EXCEPTION_DEBUG_EVENT:
OUTMSG2 (("gdbserver: kernel event EXCEPTION_DEBUG_EVENT "
- "for pid=%d tid=%x\n",
+ "for pid=%u tid=%x\n",
(unsigned) current_event.dwProcessId,
(unsigned) current_event.dwThreadId));
handle_exception (ourstatus);
case OUTPUT_DEBUG_STRING_EVENT:
/* A message from the kernel (or Cygwin). */
OUTMSG2 (("gdbserver: kernel event OUTPUT_DEBUG_STRING_EVENT "
- "for pid=%d tid=%x\n",
+ "for pid=%u tid=%x\n",
(unsigned) current_event.dwProcessId,
(unsigned) current_event.dwThreadId));
- handle_output_debug_string (ourstatus);
+ handle_output_debug_string ();
break;
default:
OUTMSG2 (("gdbserver: kernel event unknown "
- "for pid=%d tid=%x code=%ld\n",
+ "for pid=%u tid=%x code=%x\n",
(unsigned) current_event.dwProcessId,
(unsigned) current_event.dwThreadId,
- current_event.dwDebugEventCode));
+ (unsigned) current_event.dwDebugEventCode));
break;
}
- current_inferior =
- (struct thread_info *) find_inferior_id (&all_threads,
- current_event.dwThreadId);
+ ptid = debug_event_ptid (¤t_event);
+ current_thread = find_thread_ptid (ptid);
return 1;
}
/* Wait for the inferior process to change state.
STATUS will be filled in with a response code to send to GDB.
Returns the signal which caused the process to stop. */
-static unsigned char
-win32_wait (char *status)
+static ptid_t
+win32_wait (ptid_t ptid, struct target_waitstatus *ourstatus, int options)
{
- struct target_waitstatus our_status;
+ struct regcache *regcache;
- *status = 'T';
+ if (cached_status.kind != TARGET_WAITKIND_IGNORE)
+ {
+ /* The core always does a wait after creating the inferior, and
+ do_initial_child_stuff already ran the inferior to the
+ initial breakpoint (or an exit, if creating the process
+ fails). Report it now. */
+ *ourstatus = cached_status;
+ cached_status.kind = TARGET_WAITKIND_IGNORE;
+ return debug_event_ptid (¤t_event);
+ }
while (1)
{
- if (!get_child_debug_event (&our_status))
+ if (!get_child_debug_event (ourstatus))
continue;
- switch (our_status.kind)
+ switch (ourstatus->kind)
{
case TARGET_WAITKIND_EXITED:
OUTMSG2 (("Child exited with retcode = %x\n",
- our_status.value.integer));
-
- *status = 'W';
+ ourstatus->value.integer));
win32_clear_inferiors ();
- return our_status.value.integer;
+ return ptid_t (current_event.dwProcessId);
case TARGET_WAITKIND_STOPPED:
- case TARGET_WAITKIND_LOADED:
+ case TARGET_WAITKIND_LOADED:
OUTMSG2 (("Child Stopped with signal = %d \n",
- our_status.value.sig));
-
- *status = 'T';
-
- child_fetch_inferior_registers (-1);
-
- if (our_status.kind == TARGET_WAITKIND_LOADED
- && !server_waiting)
- {
- /* When gdb connects, we want to be stopped at the
- initial breakpoint, not in some dll load event. */
- child_continue (DBG_CONTINUE, -1);
- break;
- }
-
- return our_status.value.sig;
- default:
- OUTMSG (("Ignoring unknown internal event, %d\n", our_status.kind));
- /* fall-through */
- case TARGET_WAITKIND_SPURIOUS:
- case TARGET_WAITKIND_EXECD:
+ ourstatus->value.sig));
+
+ regcache = get_thread_regcache (current_thread, 1);
+ child_fetch_inferior_registers (regcache, -1);
+ return debug_event_ptid (¤t_event);
+ default:
+ OUTMSG (("Ignoring unknown internal event, %d\n", ourstatus->kind));
+ /* fall-through */
+ case TARGET_WAITKIND_SPURIOUS:
/* do nothing, just continue */
child_continue (DBG_CONTINUE, -1);
break;
/* Fetch registers from the inferior process.
If REGNO is -1, fetch all registers; otherwise, fetch at least REGNO. */
static void
-win32_fetch_inferior_registers (int regno)
+win32_fetch_inferior_registers (struct regcache *regcache, int regno)
{
- child_fetch_inferior_registers (regno);
+ child_fetch_inferior_registers (regcache, regno);
}
/* Store registers to the inferior process.
If REGNO is -1, store all registers; otherwise, store at least REGNO. */
static void
-win32_store_inferior_registers (int regno)
+win32_store_inferior_registers (struct regcache *regcache, int regno)
{
- child_store_inferior_registers (regno);
+ child_store_inferior_registers (regcache, regno);
}
/* Read memory from the inferior process. This should generally be
}
#endif
+/* Write Windows OS Thread Information Block address. */
+
+static int
+win32_get_tib_address (ptid_t ptid, CORE_ADDR *addr)
+{
+ win32_thread_info *th;
+ th = thread_rec (ptid, 0);
+ if (th == NULL)
+ return 0;
+ if (addr != NULL)
+ *addr = th->thread_local_base;
+ return 1;
+}
+
+/* Implementation of the target_ops method "sw_breakpoint_from_kind". */
+
+static const gdb_byte *
+win32_sw_breakpoint_from_kind (int kind, int *size)
+{
+ *size = the_low_target.breakpoint_len;
+ return the_low_target.breakpoint;
+}
+
static struct target_ops win32_target_ops = {
win32_create_inferior,
+ NULL, /* post_create_inferior */
win32_attach,
win32_kill,
win32_detach,
+ win32_mourn,
win32_join,
win32_thread_alive,
win32_resume,
win32_wait,
win32_fetch_inferior_registers,
win32_store_inferior_registers,
+ NULL, /* prepare_to_access_memory */
+ NULL, /* done_accessing_memory */
win32_read_inferior_memory,
win32_write_inferior_memory,
- NULL,
+ NULL, /* lookup_symbols */
win32_request_interrupt,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
+ NULL, /* read_auxv */
+ win32_supports_z_point_type,
+ win32_insert_point,
+ win32_remove_point,
+ NULL, /* stopped_by_sw_breakpoint */
+ NULL, /* supports_stopped_by_sw_breakpoint */
+ NULL, /* stopped_by_hw_breakpoint */
+ NULL, /* supports_stopped_by_hw_breakpoint */
+ target_can_do_hardware_single_step,
+ win32_stopped_by_watchpoint,
+ win32_stopped_data_address,
+ NULL, /* read_offsets */
+ NULL, /* get_tls_address */
+ NULL, /* qxfer_spu */
#ifdef _WIN32_WCE
wince_hostio_last_error,
#else
hostio_last_error_from_errno,
#endif
+ NULL, /* qxfer_osdata */
+ NULL, /* qxfer_siginfo */
+ NULL, /* supports_non_stop */
+ NULL, /* async */
+ NULL, /* start_non_stop */
+ NULL, /* supports_multi_process */
+ NULL, /* supports_fork_events */
+ NULL, /* supports_vfork_events */
+ NULL, /* supports_exec_events */
+ NULL, /* handle_new_gdb_connection */
+ NULL, /* handle_monitor_command */
+ NULL, /* core_of_thread */
+ NULL, /* read_loadmap */
+ NULL, /* process_qsupported */
+ NULL, /* supports_tracepoints */
+ NULL, /* read_pc */
+ NULL, /* write_pc */
+ NULL, /* thread_stopped */
+ win32_get_tib_address,
+ NULL, /* pause_all */
+ NULL, /* unpause_all */
+ NULL, /* stabilize_threads */
+ NULL, /* install_fast_tracepoint_jump_pad */
+ NULL, /* emit_ops */
+ NULL, /* supports_disable_randomization */
+ NULL, /* get_min_fast_tracepoint_insn_len */
+ NULL, /* qxfer_libraries_svr4 */
+ NULL, /* support_agent */
+ NULL, /* enable_btrace */
+ NULL, /* disable_btrace */
+ NULL, /* read_btrace */
+ NULL, /* read_btrace_conf */
+ NULL, /* supports_range_stepping */
+ NULL, /* pid_to_exec_file */
+ NULL, /* multifs_open */
+ NULL, /* multifs_unlink */
+ NULL, /* multifs_readlink */
+ NULL, /* breakpoint_kind_from_pc */
+ win32_sw_breakpoint_from_kind,
};
/* Initialize the Win32 backend. */
initialize_low (void)
{
set_target_ops (&win32_target_ops);
- if (the_low_target.breakpoint != NULL)
- set_breakpoint_data (the_low_target.breakpoint,
- the_low_target.breakpoint_len);
the_low_target.arch_setup ();
}