X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fwindows-nat.c;h=5bcb7b70cd58d0c1c2ec60a8de989bd690a61c50;hb=17fde6d091a9a661119d152e2304012de5fce056;hp=66c44eb7f316231b922bce75566eb74f0fb742dd;hpb=80e88e1aa2da7e516cfb7148fdd5d8777c2991dd;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c index 66c44eb7f3..5bcb7b70cd 100644 --- a/gdb/windows-nat.c +++ b/gdb/windows-nat.c @@ -1,6 +1,6 @@ /* Target-vector operations for controlling windows child processes, for GDB. - Copyright (C) 1995-2013 Free Software Foundation, Inc. + Copyright (C) 1995-2014 Free Software Foundation, Inc. Contributed by Cygnus Solutions, A Red Hat Company. @@ -43,7 +43,6 @@ #include #include #endif -#include #include "buildsym.h" #include "filenames.h" @@ -51,10 +50,9 @@ #include "objfiles.h" #include "gdb_bfd.h" #include "gdb_obstack.h" -#include "gdb_string.h" +#include #include "gdbthread.h" #include "gdbcmd.h" -#include #include #include "exec.h" #include "solist.h" @@ -311,8 +309,9 @@ thread_rec (DWORD id, int get_context) if (SuspendThread (th->h) == (DWORD) -1) { DWORD err = GetLastError (); + warning (_("SuspendThread (tid=0x%x) failed." - " (winerr %d)"), + " (winerr %u)"), (unsigned) id, (unsigned) err); return NULL; } @@ -342,7 +341,7 @@ windows_add_thread (ptid_t ptid, HANDLE h, void *tlb) if ((th = thread_rec (id, FALSE))) return th; - th = XZALLOC (thread_info); + th = XCNEW (thread_info); th->id = id; th->h = h; th->thread_local_base = (CORE_ADDR) (uintptr_t) tlb; @@ -729,7 +728,7 @@ windows_make_so (const char *name, LPVOID load_addr) #endif } #endif - so = XZALLOC (struct so_list); + so = XCNEW (struct so_list); so->lm_info = (struct lm_info *) xmalloc (sizeof (struct lm_info)); so->lm_info->load_addr = load_addr; strcpy (so->so_original_name, name); @@ -847,11 +846,31 @@ handle_load_dll (void *dummy) dll_buf[0] = dll_buf[sizeof (dll_buf) - 1] = '\0'; + /* Try getting the DLL name by searching the list of known modules + and matching their base address against this new DLL's base address. + + FIXME: brobecker/2013-12-10: + It seems odd to be going through this search if the DLL name could + simply be extracted via "event->lpImageName". Moreover, some + experimentation with various versions of Windows seem to indicate + that it might still be too early for this DLL to be listed when + querying the system about the current list of modules, thus making + this attempt pointless. + + This code can therefore probably be removed. But at the time of + this writing, we are too close to creating the GDB 7.7 branch + for us to make such a change. We are therefore defering it. */ + if (!get_module_name (event->lpBaseOfDll, dll_buf)) dll_buf[0] = dll_buf[sizeof (dll_buf) - 1] = '\0'; dll_name = dll_buf; + /* Try getting the DLL name via the lpImageName field of the event. + Note that Microsoft documents this fields as strictly optional, + in the sense that it might be NULL. And the first DLL event in + particular is explicitly documented as "likely not pass[ed]" + (source: MSDN LOAD_DLL_DEBUG_INFO structure). */ if (*dll_name == '\0') dll_name = get_image_name (current_process_handle, event->lpImageName, event->fUnicode); @@ -1256,7 +1275,7 @@ windows_continue (DWORD continue_status, int id) thread_info *th; BOOL res; - DEBUG_EVENTS (("ContinueDebugEvent (cpid=%d, ctid=%x, %s);\n", + DEBUG_EVENTS (("ContinueDebugEvent (cpid=%d, ctid=0x%x, %s);\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId, continue_status == DBG_CONTINUE ? @@ -1465,7 +1484,7 @@ get_windows_debug_event (struct target_ops *ops, switch (event_code) { case CREATE_THREAD_DEBUG_EVENT: - DEBUG_EVENTS (("gdb: kernel event for pid=%u tid=%x code=%s)\n", + DEBUG_EVENTS (("gdb: kernel event for pid=%u tid=0x%x code=%s)\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId, "CREATE_THREAD_DEBUG_EVENT")); @@ -1494,7 +1513,7 @@ get_windows_debug_event (struct target_ops *ops, break; case EXIT_THREAD_DEBUG_EVENT: - DEBUG_EVENTS (("gdb: kernel event for pid=%u tid=%x code=%s)\n", + DEBUG_EVENTS (("gdb: kernel event for pid=%u tid=0x%x code=%s)\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId, "EXIT_THREAD_DEBUG_EVENT")); @@ -1509,7 +1528,7 @@ get_windows_debug_event (struct target_ops *ops, break; case CREATE_PROCESS_DEBUG_EVENT: - DEBUG_EVENTS (("gdb: kernel event for pid=%u tid=%x code=%s)\n", + DEBUG_EVENTS (("gdb: kernel event for pid=%u tid=0x%x code=%s)\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId, "CREATE_PROCESS_DEBUG_EVENT")); @@ -1532,7 +1551,7 @@ get_windows_debug_event (struct target_ops *ops, break; case EXIT_PROCESS_DEBUG_EVENT: - DEBUG_EVENTS (("gdb: kernel event for pid=%u tid=%x code=%s)\n", + DEBUG_EVENTS (("gdb: kernel event for pid=%u tid=0x%x code=%s)\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId, "EXIT_PROCESS_DEBUG_EVENT")); @@ -1552,7 +1571,7 @@ get_windows_debug_event (struct target_ops *ops, break; case LOAD_DLL_DEBUG_EVENT: - DEBUG_EVENTS (("gdb: kernel event for pid=%u tid=%x code=%s)\n", + DEBUG_EVENTS (("gdb: kernel event for pid=%u tid=0x%x code=%s)\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId, "LOAD_DLL_DEBUG_EVENT")); @@ -1566,7 +1585,7 @@ get_windows_debug_event (struct target_ops *ops, break; case UNLOAD_DLL_DEBUG_EVENT: - DEBUG_EVENTS (("gdb: kernel event for pid=%u tid=%x code=%s)\n", + DEBUG_EVENTS (("gdb: kernel event for pid=%u tid=0x%x code=%s)\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId, "UNLOAD_DLL_DEBUG_EVENT")); @@ -1579,7 +1598,7 @@ get_windows_debug_event (struct target_ops *ops, break; case EXCEPTION_DEBUG_EVENT: - DEBUG_EVENTS (("gdb: kernel event for pid=%u tid=%x code=%s)\n", + DEBUG_EVENTS (("gdb: kernel event for pid=%u tid=0x%x code=%s)\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId, "EXCEPTION_DEBUG_EVENT")); @@ -1601,7 +1620,7 @@ get_windows_debug_event (struct target_ops *ops, break; case OUTPUT_DEBUG_STRING_EVENT: /* Message from the kernel. */ - DEBUG_EVENTS (("gdb: kernel event for pid=%u tid=%x code=%s)\n", + DEBUG_EVENTS (("gdb: kernel event for pid=%u tid=0x%x code=%s)\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId, "OUTPUT_DEBUG_STRING_EVENT")); @@ -1613,7 +1632,7 @@ get_windows_debug_event (struct target_ops *ops, default: if (saw_create != 1) break; - printf_unfiltered ("gdb: kernel event for pid=%u tid=%x\n", + printf_unfiltered ("gdb: kernel event for pid=%u tid=0x%x\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId); printf_unfiltered (" unknown event code %u\n", @@ -1703,6 +1722,74 @@ windows_wait (struct target_ops *ops, } } +/* On certain versions of Windows, the information about ntdll.dll + is not available yet at the time we get the LOAD_DLL_DEBUG_EVENT, + thus preventing us from reporting this DLL as an SO. This has been + witnessed on Windows 8.1, for instance. 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. + + If we indeed are missing ntdll.dll, this function tries to recover + from this issue, after the fact. Do nothing if we encounter any + issue trying to locate that DLL. */ + +static void +windows_ensure_ntdll_loaded (void) +{ + struct so_list *so; + HMODULE dummy_hmodule; + DWORD cb_needed; + HMODULE *hmodules; + int i; + + for (so = solib_start.next; so != NULL; so = so->next) + if (FILENAME_CMP (lbasename (so->so_name), "ntdll.dll") == 0) + return; /* ntdll.dll already loaded, nothing to do. */ + + if (EnumProcessModules (current_process_handle, &dummy_hmodule, + sizeof (HMODULE), &cb_needed) == 0) + return; + + if (cb_needed < 1) + return; + + hmodules = (HMODULE *) alloca (cb_needed); + if (EnumProcessModules (current_process_handle, hmodules, + cb_needed, &cb_needed) == 0) + return; + + for (i = 0; i < (int) (cb_needed / sizeof (HMODULE)); i++) + { + MODULEINFO mi; +#ifdef __USEWIDE + wchar_t dll_name[__PMAX]; + char name[__PMAX]; +#else + char dll_name[__PMAX]; + char *name; +#endif + if (GetModuleInformation (current_process_handle, hmodules[i], + &mi, sizeof (mi)) == 0) + continue; + if (GetModuleFileNameEx (current_process_handle, hmodules[i], + dll_name, sizeof (dll_name)) == 0) + continue; +#ifdef __USEWIDE + wcstombs (name, dll_name, __PMAX); +#else + name = dll_name; +#endif + if (FILENAME_CMP (lbasename (name), "ntdll.dll") == 0) + { + solib_end->next = windows_make_so (name, mi.lpBaseOfDll); + solib_end = solib_end->next; + return; + } + } +} + static void do_initial_windows_stuff (struct target_ops *ops, DWORD pid, int attaching) { @@ -1756,6 +1843,14 @@ do_initial_windows_stuff (struct target_ops *ops, DWORD pid, int attaching) break; } + /* FIXME: brobecker/2013-12-10: We should try another approach where + we first ignore all DLL load/unload events up until this point, + and then iterate over all modules to create the associated shared + objects. This is a fairly significant change, however, and we are + close to creating a release branch, so we are delaying it a bit, + after the branch is created. */ + windows_ensure_ntdll_loaded (); + windows_initialization_done = 1; inf->control.stop_soon = NO_STOP_QUIETLY; stop_after_trap = 0; @@ -1866,7 +1961,7 @@ windows_attach (struct target_ops *ops, char *args, int from_tty) } static void -windows_detach (struct target_ops *ops, char *args, int from_tty) +windows_detach (struct target_ops *ops, const char *args, int from_tty) { int detached = 1; @@ -2315,33 +2410,43 @@ windows_stop (ptid_t ptid) registers_changed (); /* refresh register state */ } -static int -windows_xfer_memory (CORE_ADDR memaddr, gdb_byte *our, int len, - int write, struct mem_attrib *mem, - struct target_ops *target) +/* Helper for windows_xfer_partial that handles memory transfers. + Arguments are like target_xfer_partial. */ + +static LONGEST +windows_xfer_memory (gdb_byte *readbuf, const gdb_byte *writebuf, + ULONGEST memaddr, ULONGEST len) { SIZE_T done = 0; - if (write) + BOOL success; + DWORD lasterror = 0; + + if (writebuf != NULL) { - DEBUG_MEM (("gdb: write target memory, %d bytes at %s\n", - len, core_addr_to_string (memaddr))); - if (!WriteProcessMemory (current_process_handle, - (LPVOID) (uintptr_t) memaddr, our, - len, &done)) - done = 0; + DEBUG_MEM (("gdb: write target memory, %s bytes at %s\n", + pulongest (len), core_addr_to_string (memaddr))); + success = WriteProcessMemory (current_process_handle, + (LPVOID) (uintptr_t) memaddr, writebuf, + len, &done); + if (!success) + lasterror = GetLastError (); FlushInstructionCache (current_process_handle, (LPCVOID) (uintptr_t) memaddr, len); } else { - DEBUG_MEM (("gdb: read target memory, %d bytes at %s\n", - len, core_addr_to_string (memaddr))); - if (!ReadProcessMemory (current_process_handle, - (LPCVOID) (uintptr_t) memaddr, our, - len, &done)) - done = 0; + DEBUG_MEM (("gdb: read target memory, %s bytes at %s\n", + pulongest (len), core_addr_to_string (memaddr))); + success = ReadProcessMemory (current_process_handle, + (LPCVOID) (uintptr_t) memaddr, readbuf, + len, &done); + if (!success) + lasterror = GetLastError (); } - return done; + if (!success && lasterror == ERROR_PARTIAL_COPY && done > 0) + return done; + else + return success ? done : TARGET_XFER_E_IO; } static void @@ -2363,7 +2468,7 @@ windows_kill_inferior (struct target_ops *ops) } static void -windows_prepare_to_store (struct regcache *regcache) +windows_prepare_to_store (struct target_ops *self, struct regcache *regcache) { /* Do nothing, since we can store individual regs. */ } @@ -2378,7 +2483,7 @@ static void windows_close (void) { DEBUG_EVENTS (("gdb: windows_close, inferior_ptid=%d\n", - PIDGET (inferior_ptid))); + ptid_get_pid (inferior_ptid))); } /* Convert pid to printable format. */ @@ -2401,7 +2506,7 @@ static LONGEST windows_xfer_shared_libraries (struct target_ops *ops, enum target_object object, const char *annex, gdb_byte *readbuf, const gdb_byte *writebuf, - ULONGEST offset, LONGEST len) + ULONGEST offset, ULONGEST len) { struct obstack obstack; const char *buf; @@ -2437,18 +2542,12 @@ windows_xfer_shared_libraries (struct target_ops *ops, static LONGEST windows_xfer_partial (struct target_ops *ops, enum target_object object, const char *annex, gdb_byte *readbuf, - const gdb_byte *writebuf, ULONGEST offset, LONGEST len) + const gdb_byte *writebuf, ULONGEST offset, ULONGEST len) { switch (object) { case TARGET_OBJECT_MEMORY: - if (readbuf) - return (*ops->deprecated_xfer_memory) (offset, readbuf, - len, 0/*read*/, NULL, ops); - if (writebuf) - return (*ops->deprecated_xfer_memory) (offset, (gdb_byte *) writebuf, - len, 1/*write*/, NULL, ops); - return -1; + return windows_xfer_memory (readbuf, writebuf, offset, len); case TARGET_OBJECT_LIBRARIES: return windows_xfer_shared_libraries (ops, object, annex, readbuf, @@ -2502,7 +2601,6 @@ init_windows_ops (void) windows_ops.to_fetch_registers = windows_fetch_inferior_registers; windows_ops.to_store_registers = windows_store_inferior_registers; windows_ops.to_prepare_to_store = windows_prepare_to_store; - windows_ops.deprecated_xfer_memory = windows_xfer_memory; windows_ops.to_xfer_partial = windows_xfer_partial; windows_ops.to_files_info = windows_files_info; windows_ops.to_insert_breakpoint = memory_insert_breakpoint;