/* Target-vector operations for controlling windows child processes, for GDB.
- Copyright (C) 1995-2012 Free Software Foundation, Inc.
+ Copyright (C) 1995-2015 Free Software Foundation, Inc.
Contributed by Cygnus Solutions, A Red Hat Company.
#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"
#include <signal.h>
#include <sys/types.h>
#include <fcntl.h>
-#include <stdlib.h>
#include <windows.h>
#include <imagehlp.h>
#include <psapi.h>
#include <sys/cygwin.h>
#include <cygwin/version.h>
#endif
-#include <signal.h>
#include "buildsym.h"
#include "filenames.h"
#include "objfiles.h"
#include "gdb_bfd.h"
#include "gdb_obstack.h"
-#include "gdb_string.h"
#include "gdbthread.h"
#include "gdbcmd.h"
-#include <sys/param.h>
#include <unistd.h>
#include "exec.h"
#include "solist.h"
#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
CONSOLE_FONT_INFO *);
static COORD WINAPI (*GetConsoleFontSize) (HANDLE, DWORD);
-static struct target_ops windows_ops;
-
#undef STARTUPINFO
#undef CreateProcess
#undef GetModuleFileNameEx
enum
{
FLAG_TRACE_BIT = 0x100,
- CONTEXT_DEBUGGER = (CONTEXT_FULL | CONTEXT_FLOATING_POINT)
};
#endif
#define CONTEXT_EXTENDED_REGISTERS 0
#endif
-#define CONTEXT_DEBUGGER_DR CONTEXT_DEBUGGER | CONTEXT_DEBUG_REGISTERS \
- | CONTEXT_EXTENDED_REGISTERS
+#define CONTEXT_DEBUGGER_DR CONTEXT_FULL | CONTEXT_FLOATING_POINT \
+ | CONTEXT_SEGMENTS | CONTEXT_DEBUG_REGISTERS \
+ | CONTEXT_EXTENDED_REGISTERS
static uintptr_t dr[8];
static int debug_registers_changed;
#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 *);
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,
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;
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;
/* 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;
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;
{
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 */
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
static struct so_list solib_start, *solib_end;
-/* Call symbol_file_add with stderr redirected. We don't care if there
- are errors. */
-static int
-safe_symbol_file_add_stub (void *argv)
-{
-#define p ((struct safe_symbol_file_add_args *) argv)
- const int add_flags = ((p->from_tty ? SYMFILE_VERBOSE : 0)
- | (p->mainline ? SYMFILE_MAINLINE : 0));
- p->ret = symbol_file_add (p->name, add_flags, p->addrs, p->flags);
- return !!p->ret;
-#undef p
-}
-
-/* Restore gdb's stderr after calling symbol_file_add. */
-static void
-safe_symbol_file_add_cleanup (void *p)
-{
-#define sp ((struct safe_symbol_file_add_args *)p)
- gdb_flush (gdb_stderr);
- gdb_flush (gdb_stdout);
- ui_file_delete (gdb_stderr);
- ui_file_delete (gdb_stdout);
- gdb_stderr = sp->err;
- gdb_stdout = sp->out;
-#undef sp
-}
-
-/* symbol_file_add wrapper that prevents errors from being displayed. */
-static struct objfile *
-safe_symbol_file_add (char *name, int from_tty,
- struct section_addr_info *addrs,
- int mainline, int flags)
-{
- struct safe_symbol_file_add_args p;
- struct cleanup *cleanup;
-
- cleanup = make_cleanup (safe_symbol_file_add_cleanup, &p);
-
- p.err = gdb_stderr;
- p.out = gdb_stdout;
- gdb_flush (gdb_stderr);
- gdb_flush (gdb_stdout);
- gdb_stderr = ui_file_new ();
- gdb_stdout = ui_file_new ();
- p.name = name;
- p.from_tty = from_tty;
- p.addrs = addrs;
- p.mainline = mainline;
- p.flags = flags;
- catch_errors (safe_symbol_file_add_stub, &p, "", RETURN_MASK_ERROR);
-
- do_cleanups (cleanup);
- return p.ret;
-}
-
static struct so_list *
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);
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;
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)
{
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;
}
solib_end = &solib_start;
}
-/* Load DLL symbol info. */
-static void
-dll_symbol_command (char *args, int from_tty)
-{
- int n;
- dont_repeat ();
-
- if (args == NULL)
- error (_("dll-symbols requires a file name"));
-
- n = strlen (args);
- if (n > 4 && strcasecmp (args + n - 4, ".dll") != 0)
- {
- char *newargs = (char *) alloca (n + 4 + 1);
- strcpy (newargs, args);
- strcat (newargs, ".dll");
- args = newargs;
- }
-
- safe_symbol_file_add (args, from_tty, NULL, 0, OBJF_SHARED | OBJF_USERLOADED);
-}
-
/* Handle DEBUG_STRING output from child process.
Cygwin prepends its messages with a "cygwin:". Interpret this as
a Cygwin signal. Otherwise just print the string as a warning. */
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)
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");
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;
}
}
/* 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;
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"));
}
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)
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;
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
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"));
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"));
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"));
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,
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"));
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;
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;
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"));
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"));
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;
}
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
{
}
}
+/* 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)
{
#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 ();
current thread until we report an event out of windows_wait. */
inferior_ptid = pid_to_ptid (pid);
- terminal_init_inferior_with_pgrp (pid);
+ target_terminal_init ();
target_terminal_inferior ();
windows_initialization_done = 0;
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;
/* 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;
}
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;
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);
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/<pid>/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))
{
/* 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;
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.
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;
#endif
if (!ret)
- error (_("Error creating process %s, (error %d)."),
+ error (_("Error creating process %s, (error %u)."),
exec_file, (unsigned) GetLastError ());
CloseHandle (pi.hThread);
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
for (;;)
{
- if (!windows_continue (DBG_CONTINUE, -1))
+ if (!windows_continue (DBG_CONTINUE, -1, 1))
break;
if (!WaitForDebugEvent (¤t_event, INFINITE))
break;
}
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. */
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;
struct so_list *so;
if (writebuf)
- return -1;
+ return TARGET_XFER_E_IO;
obstack_init (&obstack);
obstack_grow_str (&obstack, "<library-list>\n");
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);
}
}
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;
}
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
void
_initialize_windows_nat (void)
{
- struct cmd_list_element *c;
+ struct target_ops *t;
- init_windows_ops ();
+ t = windows_target ();
-#ifdef __CYGWIN__
- cygwin_internal (CW_SET_DOS_FILE_WARNING, 0);
-#endif
+ x86_use_watchpoints (t);
- c = add_com ("dll-symbols", class_files, dll_symbol_command,
- _("Load dll library symbols from FILE."));
- set_cmd_completer (c, filename_completer);
+ 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;
- add_com_alias ("sharedlibrary", "dll-symbols", class_alias, 1);
+ /* x86_dr_low.debug_register_length field is set by
+ calling x86_set_debug_register_length function
+ in processor windows specific native file. */
- add_com_alias ("add-shared-symbol-files", "dll-symbols", class_alias, 1);
+ add_target (t);
- add_com_alias ("assf", "dll-symbols", class_alias, 1);
+#ifdef __CYGWIN__
+ cygwin_internal (CW_SET_DOS_FILE_WARNING, 0);
+#endif
#ifdef __CYGWIN__
add_setshow_boolean_cmd ("shell", class_support, &useshell, _("\
add_cmd ("selector", class_info, display_selectors,
_("Display selectors infos."),
&info_w32_cmdlist);
- add_target (&windows_ops);
deprecated_init_ui_hook = set_windows_aliases;
}
{
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);
}
}