X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fgdbserver%2Fwin32-low.c;h=49c6cf1b7c9d68f735f5f24a8990e8f2989aa8c4;hb=268a13a5a3f7c6b9b6ffc5ac2d1b24eb41f3fbdc;hp=db9a95ecfbb4cb652e306425088e93103fb1964c;hpb=1b3f60162b504e5231252b748e95913671c431a1;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c index db9a95ecfb..49c6cf1b7c 100644 --- a/gdb/gdbserver/win32-low.c +++ b/gdb/gdbserver/win32-low.c @@ -1,5 +1,5 @@ /* Low level interface to Windows debugging, for gdbserver. - Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc. + Copyright (C) 2006-2019 Free Software Foundation, Inc. Contributed by Leo Zayas. Based on "win32-nat.c" from GDB. @@ -20,32 +20,36 @@ #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 #include #include #include #include -#include -#include #include +#include "gdbsupport/gdb_tilde_expand.h" +#include "gdbsupport/common-inferior.h" #ifndef USE_WIN32API #include #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) @@ -70,11 +74,16 @@ static int attaching = 0; 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; @@ -83,22 +92,35 @@ 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. */ @@ -107,7 +129,7 @@ static void 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 @@ -131,23 +153,24 @@ win32_set_thread_context (win32_thread_info *th) 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) { @@ -163,27 +186,39 @@ thread_rec (DWORD id, int get_context) 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); @@ -193,105 +228,130 @@ child_add_thread (DWORD tid, HANDLE h) /* 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; @@ -302,40 +362,92 @@ do_initial_child_stuff (HANDLE proch, DWORD 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 @@ -343,7 +455,10 @@ child_continue (DWORD continue_status, int thread_id) { /* 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, @@ -356,29 +471,29 @@ child_continue (DWORD continue_status, int thread_id) /* 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 @@ -402,7 +517,7 @@ strwinerror (DWORD error) NULL, error, 0, /* Default language */ - (LPVOID)&msgbuf, + (LPTSTR) &msgbuf, 0, NULL); if (chars != 0) @@ -430,7 +545,7 @@ strwinerror (DWORD error) LocalFree (msgbuf); } else - sprintf (buf, "unknown win32 error (%ld)", error); + sprintf (buf, "unknown win32 error (%u)", (unsigned) error); SetLastError (lasterr); return buf; @@ -440,10 +555,11 @@ static BOOL 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)); @@ -457,6 +573,20 @@ create_process (const char *program, char *args, 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 */ @@ -464,7 +594,7 @@ create_process (const char *program, char *args, FALSE, /* inherit handles, not supported */ flags, /* start flags */ NULL, /* environment, not supported */ - NULL, /* current directory, not supported */ + wcwd, /* current directory */ NULL, /* start info, not supported */ pi); /* proc info */ #else @@ -477,7 +607,10 @@ create_process (const char *program, char *args, 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 @@ -486,25 +619,25 @@ create_process (const char *program, char *args, } /* 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 &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; @@ -519,28 +652,17 @@ win32_create_inferior (char *program, char **program_args) 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 @@ -551,7 +673,7 @@ win32_create_inferior (char *program, char **program_args) 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 (); @@ -579,7 +701,11 @@ win32_create_inferior (char *program, char **program_args) 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; } @@ -610,7 +736,7 @@ win32_attach (unsigned long pid) /* 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; } @@ -624,7 +750,7 @@ win32_attach (unsigned long pid) /* 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; @@ -654,7 +780,7 @@ handle_output_debug_string (struct target_waitstatus *ourstatus) return; } - if (strncmp (s, "cYg", 3) != 0) + if (!startswith (s, "cYg")) { if (!server_waiting) { @@ -673,17 +799,15 @@ win32_clear_inferiors (void) 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 (;;) { @@ -694,18 +818,19 @@ win32_kill (void) 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; @@ -723,29 +848,34 @@ win32_detach (void) { 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); +} - HANDLE h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, signal_pid); +/* Implementation of target_ops::join. */ + +static void +win32_join (int pid) +{ + HANDLE h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid); if (h != NULL) { WaitForSingleObject (h, INFINITE); @@ -755,71 +885,71 @@ win32_join (void) /* 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 @@ -862,6 +992,11 @@ win32_add_one_solib (const char *name, CORE_ADDR load_addr) 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 @@ -885,8 +1020,16 @@ win32_add_one_solib (const char *name, CORE_ADDR load_addr) #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 @@ -902,7 +1045,7 @@ get_image_name (HANDLE h, void *address, int unicode) 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 @@ -933,7 +1076,7 @@ get_image_name (HANDLE h, void *address, int unicode) 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); @@ -979,11 +1122,14 @@ load_psapi (void) && 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; @@ -991,7 +1137,7 @@ psapi_get_dll_name (DWORD BaseAddress, char *dll_name_ret) BOOL ok; if (!load_psapi ()) - goto failed; + return; cbNeeded = 0; ok = (*win32_EnumProcessModules) (current_process_handle, @@ -1000,181 +1146,80 @@ psapi_get_dll_name (DWORD BaseAddress, char *dll_name_ret) &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; - - 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; + char *dll_name; - 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); } @@ -1190,55 +1235,55 @@ handle_exception (struct target_waitstatus *ourstatus) { 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 @@ -1247,27 +1292,27 @@ handle_exception (struct target_waitstatus *ourstatus) 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) @@ -1275,11 +1320,11 @@ handle_exception (struct target_waitstatus *ourstatus) 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")); @@ -1288,10 +1333,9 @@ handle_exception (struct target_waitstatus *ourstatus) 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) { @@ -1319,7 +1363,7 @@ fake_breakpoint_event (void) 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 @@ -1335,7 +1379,9 @@ auto_delete_breakpoint (CORE_ADDR stop_pc) 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. */ @@ -1384,39 +1430,55 @@ get_child_debug_event (struct target_waitstatus *ourstatus) 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); @@ -1424,14 +1486,12 @@ get_child_debug_event (struct target_waitstatus *ourstatus) 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) { @@ -1448,7 +1508,7 @@ get_child_debug_event (struct target_waitstatus *ourstatus) 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; @@ -1460,29 +1520,33 @@ get_child_debug_event (struct target_waitstatus *ourstatus) 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); @@ -1491,75 +1555,69 @@ get_child_debug_event (struct target_waitstatus *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: OUTMSG2 (("Child Stopped with signal = %d \n", - our_status.value.sig)); - - *status = 'T'; + ourstatus->value.sig)); - 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; + 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", our_status.kind)); + OUTMSG (("Ignoring unknown internal event, %d\n", ourstatus->kind)); /* fall-through */ case TARGET_WAITKIND_SPURIOUS: - case TARGET_WAITKIND_EXECD: /* do nothing, just continue */ child_continue (DBG_CONTINUE, -1); break; @@ -1570,17 +1628,17 @@ win32_wait (char *status) /* 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 @@ -1696,34 +1754,106 @@ wince_hostio_last_error (char *buf) } #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. */ @@ -1731,8 +1861,5 @@ void 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 (); }