X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gdb%2Fwindows-nat.c;h=754a2d1912fdea599e1e8765e8792bdef79cdcd7;hb=fab39d55fa914ad1cea809848899c76c64eaab9d;hp=a8766cd5500a43de0980e16968a24fb3ecdefc38;hpb=f5656eadf4383cc733b96ff49ba8efbea6922ad3;p=platform%2Fupstream%2Fbinutils.git diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c index a8766cd..754a2d1 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-2012 Free Software Foundation, Inc. + Copyright (C) 1995-2014 Free Software Foundation, Inc. Contributed by Cygnus Solutions, A Red Hat Company. @@ -24,8 +24,8 @@ #include "defs.h" #include "frame.h" /* required by inferior.h */ #include "inferior.h" +#include "infrun.h" #include "target.h" -#include "exceptions.h" #include "gdbcore.h" #include "command.h" #include "completer.h" @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include @@ -43,7 +42,6 @@ #include #include #endif -#include #include "buildsym.h" #include "filenames.h" @@ -51,10 +49,8 @@ #include "objfiles.h" #include "gdb_bfd.h" #include "gdb_obstack.h" -#include "gdb_string.h" #include "gdbthread.h" #include "gdbcmd.h" -#include #include #include "exec.h" #include "solist.h" @@ -66,8 +62,9 @@ #include "windows-tdep.h" #include "windows-nat.h" -#include "i386-nat.h" +#include "x86-nat.h" #include "complaints.h" +#include "inf-child.h" #define AdjustTokenPrivileges dyn_AdjustTokenPrivileges #define DebugActiveProcessStop dyn_DebugActiveProcessStop @@ -95,8 +92,6 @@ static BOOL WINAPI (*GetCurrentConsoleFont) (HANDLE, BOOL, CONSOLE_FONT_INFO *); static COORD WINAPI (*GetConsoleFontSize) (HANDLE, DWORD); -static struct target_ops windows_ops; - #undef STARTUPINFO #undef CreateProcess #undef GetModuleFileNameEx @@ -167,7 +162,7 @@ static int windows_initialization_done; #define DEBUG_MEM(x) if (debug_memory) printf_unfiltered x #define DEBUG_EXCEPT(x) if (debug_exceptions) printf_unfiltered x -static void windows_stop (ptid_t); +static void windows_stop (struct target_ops *self, ptid_t); static int windows_thread_alive (struct target_ops *, ptid_t); static void windows_kill_inferior (struct target_ops *); @@ -289,8 +284,8 @@ static void check (BOOL ok, const char *file, int line) { if (!ok) - printf_filtered ("error return %s:%d was %lu\n", file, line, - GetLastError ()); + printf_filtered ("error return %s:%d was %u\n", file, line, + (unsigned) GetLastError ()); } /* Find a thread record given a thread id. If GET_CONTEXT is not 0, @@ -311,11 +306,19 @@ thread_rec (DWORD id, int get_context) if (SuspendThread (th->h) == (DWORD) -1) { DWORD err = GetLastError (); - warning (_("SuspendThread failed. (winerr %d)"), - (int) err); - return NULL; + + /* We get Access Denied (5) when trying to suspend + threads that Windows started on behalf of the + debuggee, usually when those threads are just + about to exit. */ + if (err != ERROR_ACCESS_DENIED) + warning (_("SuspendThread (tid=0x%x) failed." + " (winerr %u)"), + (unsigned) id, (unsigned) err); + th->suspended = -1; } - th->suspended = 1; + else + th->suspended = 1; } else if (get_context < 0) th->suspended = -1; @@ -341,7 +344,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; @@ -386,7 +389,7 @@ windows_init_thread_list (void) /* Delete a thread from the list of threads. */ static void -windows_delete_thread (ptid_t ptid) +windows_delete_thread (ptid_t ptid, DWORD exit_code) { thread_info *th; DWORD id; @@ -397,6 +400,9 @@ windows_delete_thread (ptid_t ptid) if (info_verbose) printf_unfiltered ("[Deleting %s]\n", target_pid_to_str (ptid)); + else if (print_thread_events && id != main_thread_id) + printf_unfiltered (_("[%s exited with code %u]\n"), + target_pid_to_str (ptid), (unsigned) exit_code); delete_thread (ptid); for (th = &thread_head; @@ -442,7 +448,7 @@ do_windows_fetch_inferior_registers (struct regcache *regcache, int r) { thread_info *th = current_thread; th->context.ContextFlags = CONTEXT_DEBUGGER_DR; - GetThreadContext (th->h, &th->context); + CHECK (GetThreadContext (th->h, &th->context)); /* Copy dr values from that thread. But only if there were not modified since last stop. PR gdb/2388 */ @@ -524,78 +530,6 @@ windows_store_inferior_registers (struct target_ops *ops, do_windows_store_inferior_registers (regcache, r); } -/* Get the name of a given module at given base address. If base_address - is zero return the first loaded module (which is always the name of the - executable). */ -static int -get_module_name (LPVOID base_address, char *dll_name_ret) -{ - DWORD len; - MODULEINFO mi; - int i; - HMODULE dh_buf[1]; - HMODULE *DllHandle = dh_buf; /* Set to temporary storage for - initial query. */ - DWORD cbNeeded; -#ifdef __CYGWIN__ - cygwin_buf_t pathbuf[__PMAX]; /* Temporary storage prior to converting to - posix form. __PMAX is always enough - as long as SO_NAME_MAX_PATH_SIZE is defined - as 512. */ -#endif - - cbNeeded = 0; - /* Find size of buffer needed to handle list of modules loaded in - inferior. */ - if (!EnumProcessModules (current_process_handle, DllHandle, - sizeof (HMODULE), &cbNeeded) || !cbNeeded) - goto failed; - - /* Allocate correct amount of space for module list. */ - DllHandle = (HMODULE *) alloca (cbNeeded); - if (!DllHandle) - goto failed; - - /* Get the list of modules. */ - if (!EnumProcessModules (current_process_handle, DllHandle, cbNeeded, - &cbNeeded)) - goto failed; - - for (i = 0; i < (int) (cbNeeded / sizeof (HMODULE)); i++) - { - /* Get information on this module. */ - if (!GetModuleInformation (current_process_handle, DllHandle[i], - &mi, sizeof (mi))) - error (_("Can't get module info")); - - if (!base_address || mi.lpBaseOfDll == base_address) - { - /* Try to find the name of the given module. */ -#ifdef __CYGWIN__ - /* Cygwin prefers that the path be in /x/y/z format. */ - len = GetModuleFileNameEx (current_process_handle, - DllHandle[i], pathbuf, __PMAX); - if (len == 0) - error (_("Error getting dll name: %lu."), GetLastError ()); - if (cygwin_conv_path (CCP_WIN_W_TO_POSIX, pathbuf, dll_name_ret, - __PMAX) < 0) - error (_("Error converting dll name to POSIX: %d."), errno); -#else - len = GetModuleFileNameEx (current_process_handle, - DllHandle[i], dll_name_ret, __PMAX); - if (len == 0) - error (_("Error getting dll name: %u."), - (unsigned) GetLastError ()); -#endif - return 1; /* success */ - } - } - -failed: - dll_name_ret[0] = '\0'; - return 0; /* failure */ -} - /* Encapsulate the information required in a call to symbol_file_add_args. */ struct safe_symbol_file_add_args @@ -724,7 +658,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); @@ -831,25 +765,26 @@ get_image_name (HANDLE h, void *address, int unicode) return buf; } -/* Wait for child to do something. Return pid of child, or -1 in case - of error; store status through argument pointer OURSTATUS. */ +/* Handle a DLL load event, and return 1. + + This function assumes that this event did not occur during inferior + initialization, where their event info may be incomplete (see + do_initial_windows_stuff and windows_add_all_dlls for more info + on how we handle DLL loading during that phase). */ + static int handle_load_dll (void *dummy) { LOAD_DLL_DEBUG_INFO *event = ¤t_event.u.LoadDll; - char dll_buf[__PMAX]; - char *dll_name = NULL; - - dll_buf[0] = dll_buf[sizeof (dll_buf) - 1] = '\0'; - - if (!get_module_name (event->lpBaseOfDll, dll_buf)) - dll_buf[0] = dll_buf[sizeof (dll_buf) - 1] = '\0'; - - dll_name = dll_buf; - - if (*dll_name == '\0') - dll_name = get_image_name (current_process_handle, - event->lpImageName, event->fUnicode); + char *dll_name; + + /* 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). */ + dll_name = get_image_name (current_process_handle, + event->lpImageName, event->fUnicode); if (!dll_name) return 1; @@ -870,6 +805,14 @@ windows_free_so (struct so_list *so) xfree (so); } +/* Handle a DLL unload event. + Return 1 if successful, or zero otherwise. + + This function assumes that this event did not occur during inferior + initialization, where their event info may be incomplete (see + do_initial_windows_stuff and windows_add_all_dlls for more info + on how we handle DLL loading during that phase). */ + static int handle_unload_dll (void *dummy) { @@ -880,13 +823,13 @@ handle_unload_dll (void *dummy) if (so->next->lm_info->load_addr == lpBaseOfDll) { struct so_list *sodel = so->next; + so->next = sodel->next; if (!so->next) solib_end = so; DEBUG_EVENTS (("gdb: Unloading dll \"%s\".\n", sodel->so_name)); windows_free_so (sodel); - solib_add (NULL, 0, NULL, auto_solib_add); return 1; } @@ -968,16 +911,18 @@ handle_output_debug_string (struct target_waitstatus *ourstatus) char *p; int sig = strtol (s + sizeof (_CYGWIN_SIGNAL_STRING) - 1, &p, 0); int gotasig = gdb_signal_from_host (sig); + ourstatus->value.sig = gotasig; if (gotasig) { LPCVOID x; - DWORD n; + SIZE_T n; + ourstatus->kind = TARGET_WAITKIND_STOPPED; retval = strtoul (p, &p, 0); if (!retval) retval = main_thread_id; - else if ((x = (LPCVOID) strtoul (p, &p, 0)) + else if ((x = (LPCVOID) (uintptr_t) strtoull (p, NULL, 0)) && ReadProcessMemory (current_process_handle, x, &saved_context, __COPY_CONTEXT_SIZE, &n) @@ -1000,7 +945,7 @@ display_selector (HANDLE thread, DWORD sel) if (GetThreadSelectorEntry (thread, sel, &info)) { int base, limit; - printf_filtered ("0x%03lx: ", sel); + printf_filtered ("0x%03x: ", (unsigned) sel); if (!info.HighWord.Bits.Pres) { puts_filtered ("Segment not present\n"); @@ -1064,7 +1009,7 @@ display_selector (HANDLE thread, DWORD sel) if (err == ERROR_NOT_SUPPORTED) printf_filtered ("Function not supported\n"); else - printf_filtered ("Invalid selector 0x%lx.\n",sel); + printf_filtered ("Invalid selector 0x%x.\n", (unsigned) sel); return 0; } } @@ -1228,8 +1173,8 @@ handle_exception (struct target_waitstatus *ourstatus) /* Treat unhandled first chance exceptions specially. */ if (current_event.u.Exception.dwFirstChance) return -1; - printf_unfiltered ("gdb: unknown target exception 0x%08lx at %s\n", - current_event.u.Exception.ExceptionRecord.ExceptionCode, + printf_unfiltered ("gdb: unknown target exception 0x%08x at %s\n", + (unsigned) current_event.u.Exception.ExceptionRecord.ExceptionCode, host_address_to_string ( current_event.u.Exception.ExceptionRecord.ExceptionAddress)); ourstatus->value.sig = GDB_SIGNAL_UNKNOWN; @@ -1240,17 +1185,20 @@ handle_exception (struct target_waitstatus *ourstatus) return 1; } -/* Resume all artificially suspended threads if we are continuing - execution. */ +/* Resume thread specified by ID, or all artificially suspended + threads, if we are continuing execution. KILLED non-zero means we + have killed the inferior, so we should ignore weird errors due to + threads shutting down. */ static BOOL -windows_continue (DWORD continue_status, int id) +windows_continue (DWORD continue_status, int id, int killed) { int i; thread_info *th; BOOL res; - DEBUG_EVENTS (("ContinueDebugEvent (cpid=%ld, ctid=%lx, %s);\n", - current_event.dwProcessId, current_event.dwThreadId, + DEBUG_EVENTS (("ContinueDebugEvent (cpid=%d, ctid=0x%x, %s);\n", + (unsigned) current_event.dwProcessId, + (unsigned) current_event.dwThreadId, continue_status == DBG_CONTINUE ? "DBG_CONTINUE" : "DBG_EXCEPTION_NOT_HANDLED")); @@ -1270,7 +1218,16 @@ windows_continue (DWORD continue_status, int id) } if (th->context.ContextFlags) { - CHECK (SetThreadContext (th->h, &th->context)); + DWORD ec = 0; + + if (GetExitCodeThread (th->h, &ec) + && ec == STILL_ACTIVE) + { + BOOL status = SetThreadContext (th->h, &th->context); + + if (!killed) + CHECK (status); + } th->context.ContextFlags = 0; } if (th->suspended > 0) @@ -1297,8 +1254,8 @@ fake_create_process (void) open_process_used = 1; else { - error (_("OpenProcess call failed, GetLastError = %lud"), - GetLastError ()); + error (_("OpenProcess call failed, GetLastError = %u"), + (unsigned) GetLastError ()); /* We can not debug anything in that case. */ } main_thread_id = current_event.dwThreadId; @@ -1398,9 +1355,9 @@ windows_resume (struct target_ops *ops, Otherwise complain. */ if (resume_all) - windows_continue (continue_status, -1); + windows_continue (continue_status, -1, 0); else - windows_continue (continue_status, ptid_get_tid (ptid)); + windows_continue (continue_status, ptid_get_tid (ptid), 0); } /* Ctrl-C handler used when the inferior is not run in the same console. The @@ -1457,7 +1414,7 @@ get_windows_debug_event (struct target_ops *ops, switch (event_code) { case CREATE_THREAD_DEBUG_EVENT: - DEBUG_EVENTS (("gdb: kernel event for pid=%d 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")); @@ -1486,7 +1443,7 @@ get_windows_debug_event (struct target_ops *ops, break; case EXIT_THREAD_DEBUG_EVENT: - DEBUG_EVENTS (("gdb: kernel event for pid=%d 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")); @@ -1494,13 +1451,14 @@ get_windows_debug_event (struct target_ops *ops, if (current_event.dwThreadId != main_thread_id) { windows_delete_thread (ptid_build (current_event.dwProcessId, 0, - current_event.dwThreadId)); + current_event.dwThreadId), + current_event.u.ExitThread.dwExitCode); th = &dummy_thread_info; } break; case CREATE_PROCESS_DEBUG_EVENT: - DEBUG_EVENTS (("gdb: kernel event for pid=%d 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")); @@ -1511,7 +1469,8 @@ get_windows_debug_event (struct target_ops *ops, current_process_handle = current_event.u.CreateProcessInfo.hProcess; if (main_thread_id) windows_delete_thread (ptid_build (current_event.dwProcessId, 0, - main_thread_id)); + main_thread_id), + 0); main_thread_id = current_event.dwThreadId; /* Add the main thread. */ th = windows_add_thread (ptid_build (current_event.dwProcessId, 0, @@ -1522,7 +1481,7 @@ get_windows_debug_event (struct target_ops *ops, break; case EXIT_PROCESS_DEBUG_EVENT: - DEBUG_EVENTS (("gdb: kernel event for pid=%d 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")); @@ -1542,12 +1501,12 @@ get_windows_debug_event (struct target_ops *ops, break; case LOAD_DLL_DEBUG_EVENT: - DEBUG_EVENTS (("gdb: kernel event for pid=%d 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")); CloseHandle (current_event.u.LoadDll.hFile); - if (saw_create != 1) + if (saw_create != 1 || ! windows_initialization_done) break; catch_errors (handle_load_dll, NULL, (char *) "", RETURN_MASK_ALL); ourstatus->kind = TARGET_WAITKIND_LOADED; @@ -1556,11 +1515,11 @@ get_windows_debug_event (struct target_ops *ops, break; case UNLOAD_DLL_DEBUG_EVENT: - DEBUG_EVENTS (("gdb: kernel event for pid=%d 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")); - if (saw_create != 1) + if (saw_create != 1 || ! windows_initialization_done) break; catch_errors (handle_unload_dll, NULL, (char *) "", RETURN_MASK_ALL); ourstatus->kind = TARGET_WAITKIND_LOADED; @@ -1569,7 +1528,7 @@ get_windows_debug_event (struct target_ops *ops, break; case EXCEPTION_DEBUG_EVENT: - DEBUG_EVENTS (("gdb: kernel event for pid=%d 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")); @@ -1591,7 +1550,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=%d 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")); @@ -1603,11 +1562,11 @@ get_windows_debug_event (struct target_ops *ops, default: if (saw_create != 1) break; - printf_unfiltered ("gdb: kernel event for pid=%ld tid=%ld\n", - (DWORD) current_event.dwProcessId, - (DWORD) current_event.dwThreadId); - printf_unfiltered (" unknown event code %ld\n", - current_event.dwDebugEventCode); + 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", + (unsigned) current_event.dwDebugEventCode); break; } @@ -1616,7 +1575,7 @@ get_windows_debug_event (struct target_ops *ops, if (continue_status == -1) windows_resume (ops, minus_one_ptid, 0, 1); else - CHECK (windows_continue (continue_status, -1)); + CHECK (windows_continue (continue_status, -1, 0)); } else { @@ -1693,6 +1652,57 @@ windows_wait (struct target_ops *ops, } } +/* Iterate over all DLLs currently mapped by our inferior, and + add them to our list of solibs. */ + +static void +windows_add_all_dlls (void) +{ + struct so_list *so; + HMODULE dummy_hmodule; + DWORD cb_needed; + HMODULE *hmodules; + int i; + + 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 = 1; 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 + + solib_end->next = windows_make_so (name, mi.lpBaseOfDll); + solib_end = solib_end->next; + } +} + static void do_initial_windows_stuff (struct target_ops *ops, DWORD pid, int attaching) { @@ -1714,10 +1724,11 @@ do_initial_windows_stuff (struct target_ops *ops, DWORD pid, int attaching) #endif current_event.dwProcessId = pid; memset (¤t_event, 0, sizeof (current_event)); - push_target (ops); + if (!target_is_pushed (ops)) + push_target (ops); disable_breakpoints_in_shlibs (); windows_clear_solib (); - clear_proceed_status (); + clear_proceed_status (0); init_wait_for_inferior (); inf = current_inferior (); @@ -1730,7 +1741,7 @@ do_initial_windows_stuff (struct target_ops *ops, DWORD pid, int attaching) current thread until we report an event out of windows_wait. */ inferior_ptid = pid_to_ptid (pid); - terminal_init_inferior_with_pgrp (pid); + child_terminal_init_with_pgrp (pid); target_terminal_inferior (); windows_initialization_done = 0; @@ -1746,6 +1757,23 @@ do_initial_windows_stuff (struct target_ops *ops, DWORD pid, int attaching) break; } + /* 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. */ + windows_add_all_dlls (); + windows_initialization_done = 1; inf->control.stop_soon = NO_STOP_QUIETLY; stop_after_trap = 0; @@ -1803,7 +1831,7 @@ out: /* Attach to process PID, then initialize for debugging it. */ static void -windows_attach (struct target_ops *ops, char *args, int from_tty) +windows_attach (struct target_ops *ops, const char *args, int from_tty) { BOOL ok; DWORD pid; @@ -1856,7 +1884,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; @@ -1865,8 +1893,8 @@ windows_detach (struct target_ops *ops, char *args, int from_tty) if (!DebugActiveProcessStop (current_event.dwProcessId)) { - error (_("Can't detach process %lu (error %lu)"), - current_event.dwProcessId, GetLastError ()); + error (_("Can't detach process %u (error %u)"), + (unsigned) current_event.dwProcessId, (unsigned) GetLastError ()); detached = 0; } DebugSetProcessKillOnExit (FALSE); @@ -1876,26 +1904,82 @@ windows_detach (struct target_ops *ops, char *args, int from_tty) char *exec_file = get_exec_file (0); if (exec_file == 0) exec_file = ""; - printf_unfiltered ("Detaching from program: %s, Pid %lu\n", exec_file, - current_event.dwProcessId); + printf_unfiltered ("Detaching from program: %s, Pid %u\n", exec_file, + (unsigned) current_event.dwProcessId); gdb_flush (gdb_stdout); } + x86_cleanup_dregs (); inferior_ptid = null_ptid; detach_inferior (current_event.dwProcessId); - unpush_target (ops); + inf_child_maybe_unpush_target (ops); } +/* Try to determine the executable filename. + + EXE_NAME_RET is a pointer to a buffer whose size is EXE_NAME_MAX_LEN. + + Upon success, the filename is stored inside EXE_NAME_RET, and + this function returns nonzero. + + Otherwise, this function returns zero and the contents of + EXE_NAME_RET is undefined. */ + +static int +windows_get_exec_module_filename (char *exe_name_ret, size_t exe_name_max_len) +{ + DWORD len; + HMODULE dh_buf; + DWORD cbNeeded; + + cbNeeded = 0; + if (!EnumProcessModules (current_process_handle, &dh_buf, + sizeof (HMODULE), &cbNeeded) || !cbNeeded) + return 0; + + /* We know the executable is always first in the list of modules, + which we just fetched. So no need to fetch more. */ + +#ifdef __CYGWIN__ + { + /* Cygwin prefers that the path be in /x/y/z format, so extract + the filename into a temporary buffer first, and then convert it + to POSIX format into the destination buffer. */ + cygwin_buf_t *pathbuf = alloca (exe_name_max_len * sizeof (cygwin_buf_t)); + + len = GetModuleFileNameEx (current_process_handle, + dh_buf, pathbuf, exe_name_max_len); + if (len == 0) + error (_("Error getting executable filename: %u."), + (unsigned) GetLastError ()); + if (cygwin_conv_path (CCP_WIN_W_TO_POSIX, pathbuf, exe_name_ret, + exe_name_max_len) < 0) + error (_("Error converting executable filename to POSIX: %d."), errno); + } +#else + len = GetModuleFileNameEx (current_process_handle, + dh_buf, exe_name_ret, exe_name_max_len); + if (len == 0) + error (_("Error getting executable filename: %u."), + (unsigned) GetLastError ()); +#endif + + return 1; /* success */ +} + +/* The pid_to_exec_file target_ops method for this platform. */ + static char * -windows_pid_to_exec_file (int pid) +windows_pid_to_exec_file (struct target_ops *self, int pid) { static char path[__PMAX]; #ifdef __CYGWIN__ /* Try to find exe name as symlink target of /proc//exe. */ int nchars; char procexe[sizeof ("/proc/4294967295/exe")]; - sprintf (procexe, "/proc/%u/exe", pid); + + xsnprintf (procexe, sizeof (procexe), "/proc/%u/exe", pid); nchars = readlink (procexe, path, sizeof(path)); if (nchars > 0 && nchars < sizeof (path)) { @@ -1906,7 +1990,7 @@ windows_pid_to_exec_file (int pid) /* If we get here then either Cygwin is hosed, this isn't a Cygwin version of gdb, or we're trying to debug a non-Cygwin windows executable. */ - if (!get_module_name (0, path)) + if (!windows_get_exec_module_filename (path, sizeof (path))) path[0] = '\0'; return path; @@ -1924,12 +2008,6 @@ windows_files_info (struct target_ops *ignore) target_pid_to_str (inferior_ptid)); } -static void -windows_open (char *arg, int from_tty) -{ - error (_("Use the \"run\" command to start a Unix child process.")); -} - /* Modify CreateProcess parameters for use of a new separate console. Parameters are: *FLAGS: DWORD parameter for general process creation flags. @@ -2093,10 +2171,10 @@ windows_create_inferior (struct target_ops *ops, char *exec_file, cygallargs = (wchar_t *) alloca (len * sizeof (wchar_t)); swprintf (cygallargs, len, L" -c 'exec %s %s'", exec_file, allargs); #else - cygallargs = (char *) - alloca (sizeof (" -c 'exec '") + strlen (exec_file) - + strlen (allargs) + 2); - sprintf (cygallargs, " -c 'exec %s %s'", exec_file, allargs); + len = (sizeof (" -c 'exec '") + strlen (exec_file) + + strlen (allargs) + 2); + cygallargs = (char *) alloca (len); + xsnprintf (cygallargs, len, " -c 'exec %s %s'", exec_file, allargs); #endif toexec = shell; flags |= DEBUG_PROCESS; @@ -2262,7 +2340,7 @@ windows_create_inferior (struct target_ops *ops, char *exec_file, #endif if (!ret) - error (_("Error creating process %s, (error %d)."), + error (_("Error creating process %s, (error %u)."), exec_file, (unsigned) GetLastError ()); CloseHandle (pi.hThread); @@ -2275,61 +2353,71 @@ windows_create_inferior (struct target_ops *ops, char *exec_file, do_initial_windows_stuff (ops, pi.dwProcessId, 0); - /* windows_continue (DBG_CONTINUE, -1); */ + /* windows_continue (DBG_CONTINUE, -1, 0); */ } static void windows_mourn_inferior (struct target_ops *ops) { - (void) windows_continue (DBG_CONTINUE, -1); - i386_cleanup_dregs(); + (void) windows_continue (DBG_CONTINUE, -1, 0); + x86_cleanup_dregs(); if (open_process_used) { CHECK (CloseHandle (current_process_handle)); open_process_used = 0; } - unpush_target (ops); - generic_mourn_inferior (); + inf_child_mourn_inferior (ops); } /* Send a SIGINT to the process group. This acts just like the user typed a ^C on the controlling terminal. */ static void -windows_stop (ptid_t ptid) +windows_stop (struct target_ops *self, ptid_t ptid) { DEBUG_EVENTS (("gdb: GenerateConsoleCtrlEvent (CTRLC_EVENT, 0)\n")); CHECK (GenerateConsoleCtrlEvent (CTRL_C_EVENT, current_event.dwProcessId)); 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 enum target_xfer_status +windows_xfer_memory (gdb_byte *readbuf, const gdb_byte *writebuf, + ULONGEST memaddr, ULONGEST len, ULONGEST *xfered_len) { SIZE_T done = 0; - if (write) + BOOL success; + DWORD lasterror = 0; + + if (writebuf != NULL) { - DEBUG_MEM (("gdb: write target memory, %d bytes at 0x%08lx\n", - len, (DWORD) (uintptr_t) 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 0x%08lx\n", - len, (DWORD) (uintptr_t) 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; + *xfered_len = (ULONGEST) done; + if (!success && lasterror == ERROR_PARTIAL_COPY && done > 0) + return TARGET_XFER_OK; + else + return success ? TARGET_XFER_OK : TARGET_XFER_E_IO; } static void @@ -2339,7 +2427,7 @@ windows_kill_inferior (struct target_ops *ops) for (;;) { - if (!windows_continue (DBG_CONTINUE, -1)) + if (!windows_continue (DBG_CONTINUE, -1, 1)) break; if (!WaitForDebugEvent (¤t_event, INFINITE)) break; @@ -2351,22 +2439,10 @@ windows_kill_inferior (struct target_ops *ops) } static void -windows_prepare_to_store (struct regcache *regcache) -{ - /* Do nothing, since we can store individual regs. */ -} - -static int -windows_can_run (void) -{ - return 1; -} - -static void -windows_close (int x) +windows_close (struct target_ops *self) { DEBUG_EVENTS (("gdb: windows_close, inferior_ptid=%d\n", - PIDGET (inferior_ptid))); + ptid_get_pid (inferior_ptid))); } /* Convert pid to printable format. */ @@ -2385,11 +2461,12 @@ windows_pid_to_str (struct target_ops *ops, ptid_t ptid) return normal_pid_to_str (ptid); } -static LONGEST +static enum target_xfer_status 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) + enum target_object object, const char *annex, + gdb_byte *readbuf, const gdb_byte *writebuf, + ULONGEST offset, ULONGEST len, + ULONGEST *xfered_len) { struct obstack obstack; const char *buf; @@ -2397,7 +2474,7 @@ windows_xfer_shared_libraries (struct target_ops *ops, struct so_list *so; if (writebuf) - return -1; + return TARGET_XFER_E_IO; obstack_init (&obstack); obstack_grow_str (&obstack, "\n"); @@ -2410,41 +2487,38 @@ windows_xfer_shared_libraries (struct target_ops *ops, buf = obstack_finish (&obstack); len_avail = strlen (buf); if (offset >= len_avail) - return 0; - - if (len > len_avail - offset) - len = len_avail - offset; - memcpy (readbuf, buf + offset, len); + len= 0; + else + { + if (len > len_avail - offset) + len = len_avail - offset; + memcpy (readbuf, buf + offset, len); + } obstack_free (&obstack, NULL); - return len; + *xfered_len = (ULONGEST) len; + return len != 0 ? TARGET_XFER_OK : TARGET_XFER_EOF; } -static LONGEST +static enum target_xfer_status 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 char *annex, gdb_byte *readbuf, + const gdb_byte *writebuf, ULONGEST offset, ULONGEST len, + ULONGEST *xfered_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, xfered_len); case TARGET_OBJECT_LIBRARIES: return windows_xfer_shared_libraries (ops, object, annex, readbuf, - writebuf, offset, len); + writebuf, offset, len, xfered_len); default: - if (ops->beneath != NULL) - return ops->beneath->to_xfer_partial (ops->beneath, object, annex, - readbuf, writebuf, offset, len); - return -1; + return ops->beneath->to_xfer_partial (ops->beneath, object, annex, + readbuf, writebuf, offset, len, + xfered_len); } } @@ -2452,7 +2526,8 @@ windows_xfer_partial (struct target_ops *ops, enum target_object object, Returns 1 if ptid is found and sets *ADDR to thread_local_base. */ static int -windows_get_tib_address (ptid_t ptid, CORE_ADDR *addr) +windows_get_tib_address (struct target_ops *self, + ptid_t ptid, CORE_ADDR *addr) { thread_info *th; @@ -2467,68 +2542,37 @@ windows_get_tib_address (ptid_t ptid, CORE_ADDR *addr) } static ptid_t -windows_get_ada_task_ptid (long lwp, long thread) +windows_get_ada_task_ptid (struct target_ops *self, long lwp, long thread) { return ptid_build (ptid_get_pid (inferior_ptid), 0, lwp); } -static void -init_windows_ops (void) -{ - windows_ops.to_shortname = "child"; - windows_ops.to_longname = "Win32 child process"; - windows_ops.to_doc = "Win32 child process (started by the \"run\" command)."; - windows_ops.to_open = windows_open; - windows_ops.to_close = windows_close; - windows_ops.to_attach = windows_attach; - windows_ops.to_attach_no_wait = 1; - windows_ops.to_detach = windows_detach; - windows_ops.to_resume = windows_resume; - windows_ops.to_wait = windows_wait; - 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; - windows_ops.to_remove_breakpoint = memory_remove_breakpoint; - windows_ops.to_terminal_init = terminal_init_inferior; - windows_ops.to_terminal_inferior = terminal_inferior; - windows_ops.to_terminal_ours_for_output = terminal_ours_for_output; - windows_ops.to_terminal_ours = terminal_ours; - windows_ops.to_terminal_save_ours = terminal_save_ours; - windows_ops.to_terminal_info = child_terminal_info; - windows_ops.to_kill = windows_kill_inferior; - windows_ops.to_create_inferior = windows_create_inferior; - windows_ops.to_mourn_inferior = windows_mourn_inferior; - windows_ops.to_can_run = windows_can_run; - windows_ops.to_thread_alive = windows_thread_alive; - windows_ops.to_pid_to_str = windows_pid_to_str; - windows_ops.to_stop = windows_stop; - windows_ops.to_stratum = process_stratum; - windows_ops.to_has_all_memory = default_child_has_all_memory; - windows_ops.to_has_memory = default_child_has_memory; - windows_ops.to_has_stack = default_child_has_stack; - windows_ops.to_has_registers = default_child_has_registers; - windows_ops.to_has_execution = default_child_has_execution; - windows_ops.to_pid_to_exec_file = windows_pid_to_exec_file; - windows_ops.to_get_ada_task_ptid = windows_get_ada_task_ptid; - windows_ops.to_get_tib_address = windows_get_tib_address; - - i386_use_watchpoints (&windows_ops); - - i386_dr_low.set_control = cygwin_set_dr7; - i386_dr_low.set_addr = cygwin_set_dr; - i386_dr_low.get_addr = cygwin_get_dr; - i386_dr_low.get_status = cygwin_get_dr6; - i386_dr_low.get_control = cygwin_get_dr7; - - /* i386_dr_low.debug_register_length field is set by - calling i386_set_debug_register_length function - in processor windows specific native file. */ +static struct target_ops * +windows_target (void) +{ + struct target_ops *t = inf_child_target (); - windows_ops.to_magic = OPS_MAGIC; + t->to_close = windows_close; + t->to_attach = windows_attach; + t->to_attach_no_wait = 1; + t->to_detach = windows_detach; + t->to_resume = windows_resume; + t->to_wait = windows_wait; + t->to_fetch_registers = windows_fetch_inferior_registers; + t->to_store_registers = windows_store_inferior_registers; + t->to_xfer_partial = windows_xfer_partial; + t->to_files_info = windows_files_info; + t->to_kill = windows_kill_inferior; + t->to_create_inferior = windows_create_inferior; + t->to_mourn_inferior = windows_mourn_inferior; + t->to_thread_alive = windows_thread_alive; + t->to_pid_to_str = windows_pid_to_str; + t->to_stop = windows_stop; + t->to_pid_to_exec_file = windows_pid_to_exec_file; + t->to_get_ada_task_ptid = windows_get_ada_task_ptid; + t->to_get_tib_address = windows_get_tib_address; + + return t; } static void @@ -2544,8 +2588,23 @@ void _initialize_windows_nat (void) { struct cmd_list_element *c; + struct target_ops *t; + + t = windows_target (); + + x86_use_watchpoints (t); + + x86_dr_low.set_control = cygwin_set_dr7; + x86_dr_low.set_addr = cygwin_set_dr; + x86_dr_low.get_addr = cygwin_get_dr; + x86_dr_low.get_status = cygwin_get_dr6; + x86_dr_low.get_control = cygwin_get_dr7; - init_windows_ops (); + /* x86_dr_low.debug_register_length field is set by + calling x86_set_debug_register_length function + in processor windows specific native file. */ + + add_target (t); #ifdef __CYGWIN__ cygwin_internal (CW_SET_DOS_FILE_WARNING, 0); @@ -2554,12 +2613,17 @@ _initialize_windows_nat (void) c = add_com ("dll-symbols", class_files, dll_symbol_command, _("Load dll library symbols from FILE.")); set_cmd_completer (c, filename_completer); + deprecate_cmd (c, "sharedlibrary"); - add_com_alias ("sharedlibrary", "dll-symbols", class_alias, 1); - - add_com_alias ("add-shared-symbol-files", "dll-symbols", class_alias, 1); + c = add_com ("add-shared-symbol-files", class_files, dll_symbol_command, + _("Load dll library symbols from FILE.")); + set_cmd_completer (c, filename_completer); + deprecate_cmd (c, "sharedlibrary"); - add_com_alias ("assf", "dll-symbols", class_alias, 1); + c = add_com ("assf", class_files, dll_symbol_command, + _("Load dll library symbols from FILE.")); + set_cmd_completer (c, filename_completer); + deprecate_cmd (c, "sharedlibrary"); #ifdef __CYGWIN__ add_setshow_boolean_cmd ("shell", class_support, &useshell, _("\ @@ -2626,7 +2690,6 @@ Show whether to display kernel exceptions in child process."), NULL, add_cmd ("selector", class_info, display_selectors, _("Display selectors infos."), &info_w32_cmdlist); - add_target (&windows_ops); deprecated_init_ui_hook = set_windows_aliases; } @@ -2724,8 +2787,9 @@ _initialize_check_for_gdb_ini (void) { int len = strlen (oldini); char *newini = alloca (len + 1); - sprintf (newini, "%.*s.gdbinit", - (int) (len - (sizeof ("gdb.ini") - 1)), oldini); + + xsnprintf (newini, len + 1, "%.*s.gdbinit", + (int) (len - (sizeof ("gdb.ini") - 1)), oldini); warning (_("obsolete '%s' found. Rename to '%s'."), oldini, newini); } }