/* Target-vector operations for controlling windows child processes, for GDB.
- Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
- 2005, 2006, 2007, 2008, 2009, 2010, 2011 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>
#ifdef __CYGWIN__
+#include <wchar.h>
#include <sys/cygwin.h>
+#include <cygwin/version.h>
#endif
-#include <signal.h>
#include "buildsym.h"
#include "filenames.h"
#include "symfile.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_interrupt (struct target_ops *self, ptid_t);
static int windows_thread_alive (struct target_ops *, ptid_t);
static void windows_kill_inferior (struct target_ops *);
static void cygwin_set_dr (int i, CORE_ADDR addr);
static void cygwin_set_dr7 (unsigned long val);
+static CORE_ADDR cygwin_get_dr (int i);
static unsigned long cygwin_get_dr6 (void);
+static unsigned long cygwin_get_dr7 (void);
-static enum target_signal last_sig = TARGET_SIGNAL_0;
+static enum gdb_signal last_sig = GDB_SIGNAL_0;
/* Set if a signal was received from the debugged process. */
/* Thread information structure used to track information that is
not available in gdb's thread structure. */
-typedef struct thread_info_struct
+typedef struct windows_thread_info_struct
{
- struct thread_info_struct *next;
+ struct windows_thread_info_struct *next;
DWORD id;
HANDLE h;
CORE_ADDR thread_local_base;
CONTEXT context;
STACKFRAME sf;
}
-thread_info;
+windows_thread_info;
-static thread_info thread_head;
+static windows_thread_info thread_head;
/* The process and thread handles for the above context. */
static DEBUG_EVENT current_event; /* The current debug event from
WaitForDebugEvent */
static HANDLE current_process_handle; /* Currently executing process */
-static thread_info *current_thread; /* Info on currently selected thread */
+static windows_thread_info *current_thread; /* Info on currently selected thread */
static DWORD main_thread_id; /* Thread ID of the main thread */
/* Counts of things. */
static const int *mappings;
+/* The function to use in order to determine whether a register is
+ a segment register or not. */
+static segment_register_p_ftype *segment_register_p;
+
/* This vector maps the target's idea of an exception (extracted
from the DEBUG_EVENT structure) to GDB's idea. */
struct xlate_exception
{
int them;
- enum target_signal us;
+ enum gdb_signal us;
};
static const struct xlate_exception
xlate[] =
{
- {EXCEPTION_ACCESS_VIOLATION, TARGET_SIGNAL_SEGV},
- {STATUS_STACK_OVERFLOW, TARGET_SIGNAL_SEGV},
- {EXCEPTION_BREAKPOINT, TARGET_SIGNAL_TRAP},
- {DBG_CONTROL_C, TARGET_SIGNAL_INT},
- {EXCEPTION_SINGLE_STEP, TARGET_SIGNAL_TRAP},
- {STATUS_FLOAT_DIVIDE_BY_ZERO, TARGET_SIGNAL_FPE},
+ {EXCEPTION_ACCESS_VIOLATION, GDB_SIGNAL_SEGV},
+ {STATUS_STACK_OVERFLOW, GDB_SIGNAL_SEGV},
+ {EXCEPTION_BREAKPOINT, GDB_SIGNAL_TRAP},
+ {DBG_CONTROL_C, GDB_SIGNAL_INT},
+ {EXCEPTION_SINGLE_STEP, GDB_SIGNAL_TRAP},
+ {STATUS_FLOAT_DIVIDE_BY_ZERO, GDB_SIGNAL_FPE},
{-1, -1}};
/* Set the MAPPINGS static global to OFFSETS.
mappings = offsets;
}
+/* See windows-nat.h. */
+
+void
+windows_set_segment_register_p (segment_register_p_ftype *fun)
+{
+ segment_register_p = fun;
+}
+
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,
then also retrieve the context for this thread. If GET_CONTEXT is
negative, then don't suspend the thread. */
-static thread_info *
+static windows_thread_info *
thread_rec (DWORD id, int get_context)
{
- thread_info *th;
+ windows_thread_info *th;
for (th = &thread_head; (th = th->next) != NULL;)
if (th->id == id)
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.
+ We can get Invalid Handle (6) if the main thread
+ has exited. */
+ if (err != ERROR_INVALID_HANDLE
+ && 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;
}
/* Add a thread to the thread list. */
-static thread_info *
+static windows_thread_info *
windows_add_thread (ptid_t ptid, HANDLE h, void *tlb)
{
- thread_info *th;
+ windows_thread_info *th;
DWORD id;
gdb_assert (ptid_get_tid (ptid) != 0);
if ((th = thread_rec (id, FALSE)))
return th;
- th = XZALLOC (thread_info);
+ th = XCNEW (windows_thread_info);
th->id = id;
th->h = h;
th->thread_local_base = (CORE_ADDR) (uintptr_t) tlb;
static void
windows_init_thread_list (void)
{
- thread_info *th = &thread_head;
+ windows_thread_info *th = &thread_head;
DEBUG_EVENTS (("gdb: windows_init_thread_list\n"));
init_thread_list ();
while (th->next != NULL)
{
- thread_info *here = th->next;
+ windows_thread_info *here = th->next;
th->next = here->next;
xfree (here);
}
/* 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;
+ windows_thread_info *th;
DWORD id;
gdb_assert (ptid_get_tid (ptid) != 0);
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;
if (th->next != NULL)
{
- thread_info *here = th->next;
+ windows_thread_info *here = th->next;
th->next = here->next;
xfree (here);
}
if (current_thread->reload_context)
{
-#ifdef __COPY_CONTEXT_SIZE
+#ifdef __CYGWIN__
if (have_saved_context)
{
/* Lie about where the program actually is stopped since
else
#endif
{
- thread_info *th = current_thread;
+ windows_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 */
l = (*((long *) context_offset) >> 16) & ((1 << 11) - 1);
regcache_raw_supply (regcache, r, (char *) &l);
}
+ else if (segment_register_p (r))
+ {
+ /* GDB treats segment registers as 32bit registers, but they are
+ in fact only 16 bits long. Make sure we do not read extra
+ bits from our source buffer. */
+ l = *((long *) context_offset) & 0xffff;
+ regcache_raw_supply (regcache, r, (char *) &l);
+ }
else if (r >= 0)
regcache_raw_supply (regcache, r, context_offset);
else
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->lm_info = (struct lm_info *) xmalloc (sizeof (struct lm_info));
+ so = XCNEW (struct so_list);
+ so->lm_info = XNEW (struct lm_info);
so->lm_info->load_addr = load_addr;
strcpy (so->so_original_name, name);
#ifndef __CYGWIN__
asection *text = NULL;
CORE_ADDR text_vma;
- abfd = bfd_openr (so->so_name, "pei-i386");
+ abfd = gdb_bfd_open (so->so_name, "pei-i386", -1);
if (!abfd)
return so;
if (!text)
{
- bfd_close (abfd);
+ gdb_bfd_unref (abfd);
return so;
}
load_addr + 0x1000);
cygwin_load_end = cygwin_load_start + bfd_section_size (abfd, text);
- bfd_close (abfd);
+ gdb_bfd_unref (abfd);
}
#endif
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. */
-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. */
&s, 1024, 0)
|| !s || !*s)
/* nothing to do */;
- else if (strncmp (s, _CYGWIN_SIGNAL_STRING,
- sizeof (_CYGWIN_SIGNAL_STRING) - 1) != 0)
+ else if (!startswith (s, _CYGWIN_SIGNAL_STRING))
{
#ifdef __CYGWIN__
- if (strncmp (s, "cYg", 3) != 0)
+ if (!startswith (s, "cYg"))
#endif
- warning (("%s"), s);
+ {
+ char *p = strchr (s, '\0');
+
+ if (p > s && *--p == '\n')
+ *p = '\0';
+ warning (("%s"), s);
+ }
}
-#ifdef __COPY_CONTEXT_SIZE
+#ifdef __CYGWIN__
else
{
/* Got a cygwin signal marker. A cygwin signal is followed by
to treat this like a real signal. */
char *p;
int sig = strtol (s + sizeof (_CYGWIN_SIGNAL_STRING) - 1, &p, 0);
- int gotasig = target_signal_from_host (sig);
+ 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)
&& n == __COPY_CONTEXT_SIZE)
have_saved_context = 1;
- current_event.dwThreadId = retval;
}
}
#endif
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;
}
}
static int
handle_exception (struct target_waitstatus *ourstatus)
{
- thread_info *th;
+ windows_thread_info *th;
DWORD code = current_event.u.Exception.ExceptionRecord.ExceptionCode;
ourstatus->kind = TARGET_WAITKIND_STOPPED;
{
case EXCEPTION_ACCESS_VIOLATION:
DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ACCESS_VIOLATION");
- ourstatus->value.sig = TARGET_SIGNAL_SEGV;
+ ourstatus->value.sig = GDB_SIGNAL_SEGV;
#ifdef __CYGWIN__
{
/* See if the access violation happened within the cygwin DLL
cygwin later in the process and will be sent as a
cygwin-specific-signal. So, ignore SEGVs if they show up
within the text segment of the DLL itself. */
- char *fn;
+ const char *fn;
CORE_ADDR addr = (CORE_ADDR) (uintptr_t)
current_event.u.Exception.ExceptionRecord.ExceptionAddress;
if ((!cygwin_exceptions && (addr >= cygwin_load_start
&& addr < cygwin_load_end))
|| (find_pc_partial_function (addr, &fn, NULL, NULL)
- && strncmp (fn, "KERNEL32!IsBad",
- strlen ("KERNEL32!IsBad")) == 0))
+ && startswith (fn, "KERNEL32!IsBad")))
return 0;
}
#endif
break;
case STATUS_STACK_OVERFLOW:
DEBUG_EXCEPTION_SIMPLE ("STATUS_STACK_OVERFLOW");
- ourstatus->value.sig = TARGET_SIGNAL_SEGV;
+ ourstatus->value.sig = GDB_SIGNAL_SEGV;
break;
case STATUS_FLOAT_DENORMAL_OPERAND:
DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_DENORMAL_OPERAND");
- ourstatus->value.sig = TARGET_SIGNAL_FPE;
+ ourstatus->value.sig = GDB_SIGNAL_FPE;
break;
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ARRAY_BOUNDS_EXCEEDED");
- ourstatus->value.sig = TARGET_SIGNAL_FPE;
+ ourstatus->value.sig = GDB_SIGNAL_FPE;
break;
case STATUS_FLOAT_INEXACT_RESULT:
DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_INEXACT_RESULT");
- ourstatus->value.sig = TARGET_SIGNAL_FPE;
+ ourstatus->value.sig = GDB_SIGNAL_FPE;
break;
case STATUS_FLOAT_INVALID_OPERATION:
DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_INVALID_OPERATION");
- ourstatus->value.sig = TARGET_SIGNAL_FPE;
+ ourstatus->value.sig = GDB_SIGNAL_FPE;
break;
case STATUS_FLOAT_OVERFLOW:
DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_OVERFLOW");
- ourstatus->value.sig = TARGET_SIGNAL_FPE;
+ ourstatus->value.sig = GDB_SIGNAL_FPE;
break;
case STATUS_FLOAT_STACK_CHECK:
DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_STACK_CHECK");
- ourstatus->value.sig = TARGET_SIGNAL_FPE;
+ ourstatus->value.sig = GDB_SIGNAL_FPE;
break;
case STATUS_FLOAT_UNDERFLOW:
DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_UNDERFLOW");
- ourstatus->value.sig = TARGET_SIGNAL_FPE;
+ ourstatus->value.sig = GDB_SIGNAL_FPE;
break;
case STATUS_FLOAT_DIVIDE_BY_ZERO:
DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_DIVIDE_BY_ZERO");
- ourstatus->value.sig = TARGET_SIGNAL_FPE;
+ ourstatus->value.sig = GDB_SIGNAL_FPE;
break;
case STATUS_INTEGER_DIVIDE_BY_ZERO:
DEBUG_EXCEPTION_SIMPLE ("STATUS_INTEGER_DIVIDE_BY_ZERO");
- ourstatus->value.sig = TARGET_SIGNAL_FPE;
+ ourstatus->value.sig = GDB_SIGNAL_FPE;
break;
case STATUS_INTEGER_OVERFLOW:
DEBUG_EXCEPTION_SIMPLE ("STATUS_INTEGER_OVERFLOW");
- ourstatus->value.sig = TARGET_SIGNAL_FPE;
+ ourstatus->value.sig = GDB_SIGNAL_FPE;
break;
case EXCEPTION_BREAKPOINT:
DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_BREAKPOINT");
- ourstatus->value.sig = TARGET_SIGNAL_TRAP;
+ ourstatus->value.sig = GDB_SIGNAL_TRAP;
break;
case DBG_CONTROL_C:
DEBUG_EXCEPTION_SIMPLE ("DBG_CONTROL_C");
- ourstatus->value.sig = TARGET_SIGNAL_INT;
+ ourstatus->value.sig = GDB_SIGNAL_INT;
break;
case DBG_CONTROL_BREAK:
DEBUG_EXCEPTION_SIMPLE ("DBG_CONTROL_BREAK");
- ourstatus->value.sig = TARGET_SIGNAL_INT;
+ ourstatus->value.sig = GDB_SIGNAL_INT;
break;
case EXCEPTION_SINGLE_STEP:
DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_SINGLE_STEP");
- ourstatus->value.sig = TARGET_SIGNAL_TRAP;
+ ourstatus->value.sig = GDB_SIGNAL_TRAP;
break;
case EXCEPTION_ILLEGAL_INSTRUCTION:
DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ILLEGAL_INSTRUCTION");
- ourstatus->value.sig = TARGET_SIGNAL_ILL;
+ ourstatus->value.sig = GDB_SIGNAL_ILL;
break;
case EXCEPTION_PRIV_INSTRUCTION:
DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_PRIV_INSTRUCTION");
- ourstatus->value.sig = TARGET_SIGNAL_ILL;
+ ourstatus->value.sig = GDB_SIGNAL_ILL;
break;
case EXCEPTION_NONCONTINUABLE_EXCEPTION:
DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_NONCONTINUABLE_EXCEPTION");
- ourstatus->value.sig = TARGET_SIGNAL_ILL;
+ ourstatus->value.sig = GDB_SIGNAL_ILL;
break;
default:
/* 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 = TARGET_SIGNAL_UNKNOWN;
+ ourstatus->value.sig = GDB_SIGNAL_UNKNOWN;
break;
}
exception_count++;
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;
+ windows_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)
current_event.dwThreadId,
continue_status);
+ if (!res)
+ error (_("Failed to resume program execution"
+ " (ContinueDebugEvent failed, error %u)"),
+ (unsigned int) GetLastError ());
+
debug_registers_changed = 0;
return res;
}
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;
static void
windows_resume (struct target_ops *ops,
- ptid_t ptid, int step, enum target_signal sig)
+ ptid_t ptid, int step, enum gdb_signal sig)
{
- thread_info *th;
+ windows_thread_info *th;
DWORD continue_status = DBG_CONTINUE;
/* A specific PTID means `step only this thread id'. */
if (resume_all)
ptid = inferior_ptid;
- if (sig != TARGET_SIGNAL_0)
+ if (sig != GDB_SIGNAL_0)
{
if (current_event.dwDebugEventCode != EXCEPTION_DEBUG_EVENT)
{
}
}
#endif
- DEBUG_EXCEPT(("Can only continue with recieved signal %d.\n",
+ DEBUG_EXCEPT(("Can only continue with received signal %d.\n",
last_sig));
}
- last_sig = TARGET_SIGNAL_0;
+ last_sig = GDB_SIGNAL_0;
DEBUG_EXEC (("gdb: windows_resume (pid=%d, tid=%ld, step=%d, sig=%d);\n",
ptid_get_pid (ptid), ptid_get_tid (ptid), step, sig));
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
handler is in charge of interrupting the inferior using DebugBreakProcess.
Note that this function is not available prior to Windows XP. In this case
we emit a warning. */
-BOOL WINAPI
+static BOOL WINAPI
ctrl_c_handler (DWORD event_type)
{
const int attach_flag = current_inferior ()->attach_flag;
return TRUE;
}
-/* Get the next event from the child. Return 1 if the event requires
- handling by WFI (or whatever). */
+/* Get the next event from the child. Returns a non-zero thread id if the event
+ requires handling by WFI (or whatever). */
static int
get_windows_debug_event (struct target_ops *ops,
int pid, struct target_waitstatus *ourstatus)
{
BOOL debug_event;
DWORD continue_status, event_code;
- thread_info *th;
- static thread_info dummy_thread_info;
- int retval = 0;
+ windows_thread_info *th;
+ static windows_thread_info dummy_thread_info;
+ DWORD thread_id = 0;
- last_sig = TARGET_SIGNAL_0;
+ last_sig = GDB_SIGNAL_0;
if (!(debug_event = WaitForDebugEvent (¤t_event, 1000)))
goto out;
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"));
/* Kludge around a Windows bug where first event is a create
thread event. Caused when attached process does not have
a main thread. */
- retval = fake_create_process ();
- if (retval)
+ thread_id = fake_create_process ();
+ if (thread_id)
saw_create++;
}
break;
}
/* Record the existence of this thread. */
- retval = current_event.dwThreadId;
+ thread_id = current_event.dwThreadId;
th = windows_add_thread (ptid_build (current_event.dwProcessId, 0,
current_event.dwThreadId),
current_event.u.CreateThread.hThread,
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,
current_event.dwThreadId),
current_event.u.CreateProcessInfo.hThread,
current_event.u.CreateProcessInfo.lpThreadLocalBase);
- retval = current_event.dwThreadId;
+ thread_id = current_event.dwThreadId;
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"));
{
ourstatus->kind = TARGET_WAITKIND_EXITED;
ourstatus->value.integer = current_event.u.ExitProcess.dwExitCode;
- retval = main_thread_id;
+ thread_id = main_thread_id;
}
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;
ourstatus->value.integer = 0;
- retval = main_thread_id;
+ thread_id = main_thread_id;
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;
ourstatus->value.integer = 0;
- retval = main_thread_id;
+ thread_id = main_thread_id;
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"));
continue_status = DBG_EXCEPTION_NOT_HANDLED;
break;
case 1:
- retval = current_event.dwThreadId;
+ thread_id = current_event.dwThreadId;
break;
case -1:
last_sig = 1;
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"));
if (saw_create != 1)
break;
- retval = handle_output_debug_string (ourstatus);
+ thread_id = handle_output_debug_string (ourstatus);
break;
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 (!retval || saw_create != 1)
+ if (!thread_id || saw_create != 1)
{
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
{
inferior_ptid = ptid_build (current_event.dwProcessId, 0,
- retval);
- current_thread = th ?: thread_rec (current_event.dwThreadId, TRUE);
+ thread_id);
+ current_thread = th;
+ if (!current_thread)
+ current_thread = thread_rec (thread_id, TRUE);
}
out:
- return retval;
+ return thread_id;
}
/* Wait for interesting events to occur in the target process. */
}
}
+/* 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)
{
struct inferior *inf;
struct thread_info *tp;
- last_sig = TARGET_SIGNAL_0;
+ last_sig = GDB_SIGNAL_0;
event_count = 0;
exception_count = 0;
open_process_used = 0;
#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;
stop_after_trap = 1;
wait_for_inferior ();
tp = inferior_thread ();
- if (tp->suspend.stop_signal != TARGET_SIGNAL_TRAP)
- resume (0, tp->suspend.stop_signal);
+ if (tp->suspend.stop_signal != GDB_SIGNAL_TRAP)
+ resume (tp->suspend.stop_signal);
else
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;
ptid_t ptid = {-1};
- windows_resume (ops, ptid, 0, TARGET_SIGNAL_0);
+ windows_resume (ops, ptid, 0, GDB_SIGNAL_0);
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.
}
#endif
+#ifdef __CYGWIN__
+static void
+clear_win32_environment (char **env)
+{
+ int i;
+ size_t len;
+ wchar_t *copy = NULL, *equalpos;
+
+ for (i = 0; env[i] && *env[i]; i++)
+ {
+ len = mbstowcs (NULL, env[i], 0) + 1;
+ copy = (wchar_t *) xrealloc (copy, len * sizeof (wchar_t));
+ mbstowcs (copy, env[i], len);
+ equalpos = wcschr (copy, L'=');
+ if (equalpos)
+ *equalpos = L'\0';
+ SetEnvironmentVariableW (copy, NULL);
+ }
+ xfree (copy);
+}
+#endif
+
/* Start an inferior windows child process and sets inferior_ptid to its pid.
EXEC_FILE is the file to run.
ALLARGS is a string containing the arguments to the program.
cygwin_buf_t *toexec;
cygwin_buf_t *cygallargs;
cygwin_buf_t *args;
+ char **old_env = NULL;
+ PWCHAR w32_env;
size_t len;
int tty;
int ostdin, ostdout, ostderr;
char shell[__PMAX]; /* Path to shell */
char *toexec;
char *args;
+ size_t args_len;
HANDLE tty;
char *w32env;
char *temp;
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;
strcat (args, cygallargs);
#endif
- /* Prepare the environment vars for CreateProcess. */
- cygwin_internal (CW_SYNC_WINENV);
+#ifdef CW_CVT_ENV_TO_WINENV
+ /* First try to create a direct Win32 copy of the POSIX environment. */
+ w32_env = (PWCHAR) cygwin_internal (CW_CVT_ENV_TO_WINENV, in_env);
+ if (w32_env != (PWCHAR) -1)
+ flags |= CREATE_UNICODE_ENVIRONMENT;
+ else
+ /* If that fails, fall back to old method tweaking GDB's environment. */
+#endif
+ {
+ /* Reset all Win32 environment variables to avoid leftover on next run. */
+ clear_win32_environment (environ);
+ /* Prepare the environment vars for CreateProcess. */
+ old_env = environ;
+ environ = in_env;
+ cygwin_internal (CW_SYNC_WINENV);
+ w32_env = NULL;
+ }
if (!inferior_io_terminal)
tty = ostdin = ostdout = ostderr = -1;
NULL, /* thread */
TRUE, /* inherit handles */
flags, /* start flags */
- NULL, /* environment */
+ w32_env, /* environment */
NULL, /* current directory */
&si,
&pi);
+ if (w32_env)
+ /* Just free the Win32 environment, if it could be created. */
+ free (w32_env);
+ else
+ {
+ /* Reset all environment variables to avoid leftover on next run. */
+ clear_win32_environment (in_env);
+ /* Restore normal GDB environment variables. */
+ environ = old_env;
+ cygwin_internal (CW_SYNC_WINENV);
+ }
+
if (tty >= 0)
{
close (tty);
}
#else
toexec = exec_file;
- args = alloca (strlen (toexec) + strlen (allargs) + 2);
- strcpy (args, toexec);
- strcat (args, " ");
- strcat (args, allargs);
+ /* Build the command line, a space-separated list of tokens where
+ the first token is the name of the module to be executed.
+ To avoid ambiguities introduced by spaces in the module name,
+ we quote it. */
+ args_len = strlen (toexec) + 2 /* quotes */ + strlen (allargs) + 2;
+ args = alloca (args_len);
+ xsnprintf (args, args_len, "\"%s\" %s", toexec, allargs);
flags |= DEBUG_ONLY_THIS_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_interrupt (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");
for (so = solib_start.next; so; so = so->next)
windows_xfer_shared_library (so->so_name, (CORE_ADDR)
(uintptr_t) so->lm_info->load_addr,
- target_gdbarch, &obstack);
+ target_gdbarch (), &obstack);
obstack_grow_str0 (&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;
+ windows_thread_info *th;
th = thread_rec (ptid_get_tid (ptid), 0);
if (th == NULL)
}
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.reset_addr = NULL;
- i386_dr_low.get_status = cygwin_get_dr6;
-
- /* 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_interrupt = windows_interrupt;
+ 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;
-static void
-set_windows_aliases (char *argv0)
-{
- add_info_alias ("dll", "sharedlibrary", 1);
+ return t;
}
+/* -Wmissing-prototypes */
+extern initialize_file_ftype _initialize_windows_nat;
+
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;
}
/* Hardware watchpoint support, adapted from go32-nat.c code. */
debug_registers_used = 1;
}
+/* Get the value of debug register I from the inferior. */
+
+static CORE_ADDR
+cygwin_get_dr (int i)
+{
+ return dr[i];
+}
+
/* Get the value of the DR6 debug status register from the inferior.
Here we just return the value stored in dr[6]
by the last call to thread_rec for current_event.dwThreadId id. */
return (unsigned long) dr[6];
}
+/* Get the value of the DR7 debug status register from the inferior.
+ Here we just return the value stored in dr[7] by the last call to
+ thread_rec for current_event.dwThreadId id. */
+
+static unsigned long
+cygwin_get_dr7 (void)
+{
+ return (unsigned long) dr[7];
+}
+
/* Determine if the thread referenced by "ptid" is alive
by "polling" it. If WaitForSingleObject returns WAIT_OBJECT_0
it means that the thread has died. Otherwise it is assumed to be alive. */
? FALSE : TRUE;
}
+/* -Wmissing-prototypes */
+extern initialize_file_ftype _initialize_check_for_gdb_ini;
+
void
_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);
}
}
return size;
}
+/* -Wmissing-prototypes */
+extern initialize_file_ftype _initialize_loadable;
+
/* Load any functions which may not be available in ancient versions
of Windows. */
+
void
_initialize_loadable (void)
{