/* Low level interface to Windows debugging, for gdbserver.
- Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+ Copyright (C) 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
Contributed by Leo Zayas. Based on "win32-nat.c" from GDB.
#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)
/* Get the thread ID from the current selected inferior (the current
thread). */
-static DWORD
-current_inferior_tid (void)
+static ptid_t
+current_inferior_ptid (void)
+{
+ return ((struct inferior_list_entry*) current_inferior)->id;
+}
+
+/* The current debug event from WaitForDebugEvent. */
+static ptid_t
+debug_event_ptid (DEBUG_EVENT *event)
{
- win32_thread_info *th = inferior_target_data (current_inferior);
- return th->tid;
+ return ptid_build (event->dwProcessId, event->dwThreadId, 0);
}
/* Get the thread context of the thread associated with 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 (DWORD id, int get_context)
+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, id);
+ thread = (struct thread_info *) find_inferior_id (&all_threads, ptid);
if (thread == NULL)
return NULL;
/* 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)
{
win32_thread_info *th;
+ ptid_t ptid = ptid_build (pid, tid, 0);
- if ((th = thread_rec (tid, FALSE)))
+ if ((th = thread_rec (ptid, FALSE)))
return th;
th = xcalloc (1, sizeof (*th));
th->tid = tid;
th->h = h;
- add_thread (tid, th, (unsigned int) tid);
+ add_thread (ptid, th);
set_inferior_regcache_data ((struct thread_info *)
- find_inferior_id (&all_threads, tid),
+ find_inferior_id (&all_threads, ptid),
new_register_cache ());
if (the_low_target.thread_added != NULL)
/* 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;
+ ptid_t ptid;
/* If the last thread is exiting, just return. */
if (all_threads.head == all_threads.tail)
return;
- thread = find_inferior_id (&all_threads, id);
+ ptid = ptid_build (pid, tid, 0);
+ thread = find_inferior_id (&all_threads, ptid);
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_insert_point (char type, CORE_ADDR addr, int len)
+{
+ if (the_low_target.insert_point != NULL)
+ return the_low_target.insert_point (type, addr, len);
+ else
+ /* Unsupported (see target.h). */
+ return 1;
+}
+
+static int
+win32_remove_point (char type, CORE_ADDR addr, int len)
+{
+ if (the_low_target.remove_point != NULL)
+ return the_low_target.remove_point (type, addr, len);
+ 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,
}
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;
memset (¤t_event, 0, sizeof (current_event));
+ add_process (pid, attached);
child_init_thread_list ();
if (the_low_target.initial_stuff != NULL)
/* 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_inferior_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_inferior_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
CloseHandle (pi.hThread);
#endif
- do_initial_child_stuff (pi.hProcess, pi.dwProcessId);
+ do_initial_child_stuff (pi.hProcess, pi.dwProcessId, 0);
return current_process_id;
}
/* win32_wait needs to know we're attaching. */
attaching = 1;
- do_initial_child_stuff (h, pid);
+ do_initial_child_stuff (h, pid, 1);
return 0;
}
}
/* Kill all inferiors. */
-static void
-win32_kill (void)
+static int
+win32_kill (int pid)
{
+ struct process_info *process;
+
if (current_process_handle == NULL)
- return;
+ return -1;
TerminateProcess (current_process_handle, 0);
for (;;)
}
win32_clear_inferiors ();
+
+ process = find_process_pid (pid);
+ remove_process (process);
+ return 0;
}
-/* Detach from all inferiors. */
+/* Detach from inferior PID. */
static int
-win32_detach (void)
+win32_detach (int pid)
{
+ struct process_info *process;
winapi_DebugActiveProcessStop DebugActiveProcessStop = NULL;
winapi_DebugSetProcessKillOnExit DebugSetProcessKillOnExit = NULL;
#ifdef _WIN32_WCE
{
struct thread_resume resume;
- resume.thread = -1;
+ resume.thread = minus_one_ptid;
resume.kind = resume_continue;
resume.sig = 0;
win32_resume (&resume, 1);
return -1;
DebugSetProcessKillOnExit (FALSE);
+ process = find_process_pid (pid);
+ remove_process (process);
win32_clear_inferiors ();
return 0;
/* Wait for inferiors to end. */
static void
-win32_join (void)
+win32_join (int pid)
{
- extern unsigned long signal_pid;
-
- HANDLE h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, signal_pid);
+ HANDLE h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, 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)
+ if (find_inferior_id (&all_threads, ptid) != NULL)
res = 1;
else
res = 0;
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 (n == 1 && resume_info[0].thread == -1)
+ if (n == 1 && ptid_equal (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 (resume_info[0].thread != -1)
+ if (!ptid_equal (resume_info[0].thread, minus_one_ptid))
{
sig = resume_info[0].sig;
step = resume_info[0].kind == resume_step;
last_sig = TARGET_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)
{
if (th->context.ContextFlags)
#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);
#else
static int
get_child_debug_event (struct target_waitstatus *ourstatus)
{
+ ptid_t ptid;
+
last_sig = TARGET_SIGNAL_0;
ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
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:
(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);
break;
case EXIT_THREAD_DEBUG_EVENT:
"for pid=%d 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_inferior = (struct thread_info *) all_threads.head;
+ return 1;
case CREATE_PROCESS_DEBUG_EVENT:
OUTMSG2 (("gdbserver: kernel event CREATE_PROCESS_DEBUG_EVENT "
ourstatus->value.execd_pathname = "Main executable";
/* Add the main thread. */
- child_add_thread (main_thread_id,
+ child_add_thread (current_event.dwProcessId,
+ main_thread_id,
current_event.u.CreateProcessInfo.hThread);
- ourstatus->value.related_pid = current_event.dwThreadId;
+ ourstatus->value.related_pid = debug_event_ptid (¤t_event);
#ifdef _WIN32_WCE
if (!attaching)
{
break;
}
+ ptid = debug_event_ptid (¤t_event);
current_inferior =
- (struct thread_info *) find_inferior_id (&all_threads,
- current_event.dwThreadId);
+ (struct thread_info *) find_inferior_id (&all_threads, 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 long
-win32_wait (struct target_waitstatus *ourstatus, int options)
+static ptid_t
+win32_wait (ptid_t ptid, struct target_waitstatus *ourstatus, int options)
{
+ struct process_info *process;
+ struct regcache *regcache;
+
while (1)
{
if (!get_child_debug_event (ourstatus))
OUTMSG2 (("Child exited with retcode = %x\n",
ourstatus->value.integer));
+ process = find_process_pid (current_process_id);
+ remove_process (process);
win32_clear_inferiors ();
- return current_event.dwProcessId;
+ return pid_to_ptid (current_event.dwProcessId);
case TARGET_WAITKIND_STOPPED:
case TARGET_WAITKIND_LOADED:
OUTMSG2 (("Child Stopped with signal = %d \n",
- our_status.value.sig));
+ ourstatus->value.sig));
- child_fetch_inferior_registers (-1);
+ regcache = get_thread_regcache (current_inferior, 1);
+ child_fetch_inferior_registers (regcache, -1);
if (ourstatus->kind == TARGET_WAITKIND_LOADED
&& !server_waiting)
if (ourstatus->kind == TARGET_WAITKIND_LOADED)
ourstatus->kind = TARGET_WAITKIND_STOPPED;
- return current_event.dwThreadId;
+ return debug_event_ptid (¤t_event);
default:
OUTMSG (("Ignoring unknown internal event, %d\n", ourstatus->kind));
/* fall-through */
/* 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
NULL,
win32_request_interrupt,
NULL,
- NULL,
- NULL,
- NULL,
- NULL,
+ win32_insert_point,
+ win32_remove_point,
+ win32_stopped_by_watchpoint,
+ win32_stopped_data_address,
NULL,
NULL,
NULL,