X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fgdbserver%2Fwin32-low.c;h=2242d5c335e1da94a7bc4eb6aea17596928660d9;hb=cb9f1a9bcdd26a6f460a033e641804ba798937fc;hp=d1caa73096016d5eeb3cc8d063bdd0a165241812;hpb=3aee891821f538cfb4e0a08a26196c70127f1474;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c index d1caa73096..2242d5c335 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-2013 Free Software Foundation, Inc. + Copyright (C) 2006-2014 Free Software Foundation, Inc. Contributed by Leo Zayas. Based on "win32-nat.c" from GDB. @@ -20,11 +20,12 @@ #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 @@ -32,7 +33,6 @@ #include #include #include -#include #include #ifndef USE_WIN32API @@ -79,6 +79,11 @@ 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; @@ -91,19 +96,24 @@ 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 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 ptid_t current_inferior_ptid (void) { - return ((struct inferior_list_entry*) current_inferior)->id; + return current_ptid; } /* The current debug event from WaitForDebugEvent. */ @@ -221,7 +231,7 @@ child_delete_thread (DWORD pid, DWORD tid) ptid_t ptid; /* If the last thread is exiting, just return. */ - if (all_threads.head == all_threads.tail) + if (one_inferior_p (&all_threads)) return; ptid = ptid_build (pid, tid, 0); @@ -236,20 +246,29 @@ child_delete_thread (DWORD pid, DWORD tid) if the low target has registered a corresponding function. */ static int -win32_insert_point (char type, CORE_ADDR addr, int len) +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, len); + return the_low_target.insert_point (type, addr, size, bp); else /* Unsupported (see target.h). */ return 1; } static int -win32_remove_point (char type, CORE_ADDR addr, int len) +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, len); + return the_low_target.remove_point (type, addr, size, bp); else /* Unsupported (see target.h). */ return 1; @@ -279,21 +298,30 @@ static int child_xfer_memory (CORE_ADDR memaddr, char *our, int len, int write, struct target_ops *target) { - SIZE_T done; + 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; } /* Clear out any old thread list and reinitialize it to a pristine @@ -304,6 +332,10 @@ child_init_thread_list (void) for_each_inferior (&all_threads, 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, int attached) { @@ -323,9 +355,59 @@ do_initial_child_stuff (HANDLE proch, DWORD pid, int attached) 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 @@ -515,7 +597,7 @@ static int win32_create_inferior (char *program, char **program_args) { #ifndef USE_WIN32API - char real_path[MAXPATHLEN]; + char real_path[PATH_MAX]; char *orig_path, *new_path, *path_ptr; #endif BOOL ret; @@ -546,8 +628,7 @@ win32_create_inferior (char *program, char **program_args) cygwin_conv_path_list (CCP_POSIX_TO_WIN_A, path_ptr, new_path, size); setenv ("PATH", new_path, 1); } - cygwin_conv_path (CCP_POSIX_TO_WIN_A, program, real_path, - MAXPATHLEN); + cygwin_conv_path (CCP_POSIX_TO_WIN_A, program, real_path, PATH_MAX); program = real_path; #endif @@ -898,6 +979,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 @@ -1023,11 +1109,14 @@ load_psapi (void) && win32_GetModuleFileNameExA != NULL); } -static int -psapi_get_dll_name (LPVOID 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; @@ -1035,7 +1124,7 @@ psapi_get_dll_name (LPVOID BaseAddress, char *dll_name_ret) BOOL ok; if (!load_psapi ()) - goto failed; + return; cbNeeded = 0; ok = (*win32_EnumProcessModules) (current_process_handle, @@ -1044,181 +1133,80 @@ psapi_get_dll_name (LPVOID 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 (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 (LPVOID BaseAddress, char *dll_name_ret) -{ - HANDLE snapshot_module; - MODULEENTRY32 modEntry = { sizeof (MODULEENTRY32) }; - int found = 0; - - 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 (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; - } +/* Handle a DLL load event. -#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; - CORE_ADDR 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 (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 (event->lpBaseOfDll, dll_buf); - } + char *dll_name; - 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 - offset from 0 of the first byte in an image - because - of the file header and the section alignment. */ - - load_addr = (CORE_ADDR) (uintptr_t) 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) (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); } @@ -1528,6 +1516,8 @@ get_child_debug_event (struct target_waitstatus *ourstatus) (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; @@ -1539,6 +1529,8 @@ get_child_debug_event (struct target_waitstatus *ourstatus) "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 = GDB_SIGNAL_TRAP; @@ -1584,6 +1576,17 @@ win32_wait (ptid_t ptid, struct target_waitstatus *ourstatus, int options) { struct regcache *regcache; + 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 (ourstatus)) @@ -1603,21 +1606,6 @@ win32_wait (ptid_t ptid, struct target_waitstatus *ourstatus, int options) regcache = get_thread_regcache (current_inferior, 1); child_fetch_inferior_registers (regcache, -1); - - if (ourstatus->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; - } - - /* We don't expose _LOADED events to gdbserver core. See - the `dlls_changed' global. */ - if (ourstatus->kind == TARGET_WAITKIND_LOADED) - ourstatus->kind = TARGET_WAITKIND_STOPPED; - return debug_event_ptid (¤t_event); default: OUTMSG (("Ignoring unknown internal event, %d\n", ourstatus->kind)); @@ -1793,6 +1781,7 @@ static struct target_ops win32_target_ops = { NULL, /* lookup_symbols */ win32_request_interrupt, NULL, /* read_auxv */ + win32_supports_z_point_type, win32_insert_point, win32_remove_point, win32_stopped_by_watchpoint,