/* 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 Free Software Foundation, Inc.
+ Copyright (C) 1995-2014 Free Software Foundation, Inc.
Contributed by Cygnus Solutions, A Red Hat Company.
#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 <string.h>
#include "gdbthread.h"
#include "gdbcmd.h"
-#include <sys/param.h>
#include <unistd.h>
#include "exec.h"
#include "solist.h"
DWORD);
static BOOL WINAPI (*LookupPrivilegeValueA)(LPCSTR, LPCSTR, PLUID);
static BOOL WINAPI (*OpenProcessToken)(HANDLE, DWORD, PHANDLE);
-static BOOL WINAPI (*GetCurrentConsoleFont) (HANDLE, BOOL, CONSOLE_FONT_INFO *);
+static BOOL WINAPI (*GetCurrentConsoleFont) (HANDLE, BOOL,
+ CONSOLE_FONT_INFO *);
static COORD WINAPI (*GetConsoleFontSize) (HANDLE, DWORD);
static struct target_ops windows_ops;
# define bad_GetModuleFileNameEx bad_GetModuleFileNameExA
#else
# define __PMAX PATH_MAX
-/* The starting and ending address of the cygwin1.dll text segment. */
+/* The starting and ending address of the cygwin1.dll text segment. */
static CORE_ADDR cygwin_load_start;
static CORE_ADDR cygwin_load_end;
-# if CYGWIN_VERSION_DLL_MAKE_COMBINED(CYGWIN_VERSION_API_MAJOR,CYGWIN_VERSION_API_MINOR) >= 181
# define __USEWIDE
typedef wchar_t cygwin_buf_t;
- static DWORD WINAPI (*GetModuleFileNameEx) (HANDLE, HMODULE, LPWSTR, DWORD);
+ static DWORD WINAPI (*GetModuleFileNameEx) (HANDLE, HMODULE,
+ LPWSTR, DWORD);
# define STARTUPINFO STARTUPINFOW
# define CreateProcess CreateProcessW
# define GetModuleFileNameEx_name "GetModuleFileNameExW"
# define bad_GetModuleFileNameEx bad_GetModuleFileNameExW
-# else
-# define CCP_POSIX_TO_WIN_W 1
-# define CCP_WIN_W_TO_POSIX 3
-# define cygwin_conv_path(op, from, to, size) \
- (op == CCP_WIN_W_TO_POSIX) ? \
- cygwin_conv_to_full_posix_path (from, to) : \
- cygwin_conv_to_win32_path (from, to)
- typedef char cygwin_buf_t;
- static DWORD WINAPI (*GetModuleFileNameEx) (HANDLE, HMODULE, LPSTR, DWORD);
-# define STARTUPINFO STARTUPINFOA
-# define CreateProcess CreateProcessA
-# define GetModuleFileNameEx_name "GetModuleFileNameExA"
-# define bad_GetModuleFileNameEx bad_GetModuleFileNameExA
-# define CW_SET_DOS_FILE_WARNING -1 /* no-op this for older Cygwin */
-# endif
#endif
-static int have_saved_context; /* True if we've saved context from a cygwin signal. */
-static CONTEXT saved_context; /* Containes the saved context from a cygwin signal. */
+static int have_saved_context; /* True if we've saved context from a
+ cygwin signal. */
+static CONTEXT saved_context; /* Containes the saved context from a
+ cygwin signal. */
/* If we're not using the old Cygwin header file set, define the
following which never should have been in the generic Win32 API
- headers in the first place since they were our own invention... */
+ headers in the first place since they were our own invention... */
#ifndef _GNU_H_WINDOWS_H
enum
{
#define DR6_CLEAR_VALUE 0xffff0ff0
/* The string sent by cygwin when it processes a signal.
- FIXME: This should be in a cygwin include file. */
+ FIXME: This should be in a cygwin include file. */
#ifndef _CYGWIN_SIGNAL_STRING
#define _CYGWIN_SIGNAL_STRING "cYgSiGw00f"
#endif
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;
-/* Set if a signal was received from the debugged process */
+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. */
static thread_info thread_head;
-/* The process and thread handles for the above context. */
+/* The process and thread handles for the above context. */
static DEBUG_EVENT current_event; /* The current debug event from
WaitForDebugEvent */
static thread_info *current_thread; /* Info on currently selected thread */
static DWORD main_thread_id; /* Thread ID of the main thread */
-/* Counts of things. */
+/* Counts of things. */
static int exception_count = 0;
static int event_count = 0;
static int saw_create;
static int open_process_used = 0;
-/* User options. */
+/* User options. */
static int new_console = 0;
#ifdef __CYGWIN__
static int cygwin_exceptions = 0;
One day we could read a reg, we could inspect the context we
already have loaded, if it doesn't have the bit set that we need,
we read that set of registers in using GetThreadContext. If the
- context already contains what we need, we just unpack it. Then to
+ context already contains what we need, we just unpack it. Then to
write a register, first we have to ensure that the context contains
the other regs of the group, and then we copy the info in and set
- out bit. */
+ out bit. */
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. */
+ 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,
if (SuspendThread (th->h) == (DWORD) -1)
{
DWORD err = GetLastError ();
- warning (_("SuspendThread failed. (winerr %d)"),
- (int) err);
+
+ warning (_("SuspendThread (tid=0x%x) failed."
+ " (winerr %u)"),
+ (unsigned) id, (unsigned) err);
return NULL;
}
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;
}
/* Clear out any old thread list and reintialize it to a
- pristine state. */
+ pristine state. */
static void
windows_init_thread_list (void)
{
thread_head.next = NULL;
}
-/* Delete a thread from the list of threads */
+/* 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;
if (!current_thread)
return; /* Windows sometimes uses a non-existent thread id in its
- events */
+ events. */
if (current_thread->reload_context)
{
#ifdef __COPY_CONTEXT_SIZE
if (have_saved_context)
{
- /* Lie about where the program actually is stopped since cygwin has informed us that
- we should consider the signal to have occurred at another location which is stored
- in "saved_context. */
- memcpy (¤t_thread->context, &saved_context, __COPY_CONTEXT_SIZE);
+ /* Lie about where the program actually is stopped since
+ cygwin has informed us that we should consider the signal
+ to have occurred at another location which is stored in
+ "saved_context. */
+ memcpy (¤t_thread->context, &saved_context,
+ __COPY_CONTEXT_SIZE);
have_saved_context = 0;
}
else
th->context.ContextFlags = CONTEXT_DEBUGGER_DR;
GetThreadContext (th->h, &th->context);
/* Copy dr values from that thread.
- But only if there were not modified since last stop. PR gdb/2388 */
+ But only if there were not modified since last stop.
+ PR gdb/2388 */
if (!debug_registers_changed)
{
dr[0] = th->context.Dr0;
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
{
current_thread = thread_rec (ptid_get_tid (inferior_ptid), TRUE);
/* Check if current_thread exists. Windows sometimes uses a non-existent
- thread id in its events */
+ thread id in its events. */
if (current_thread)
do_windows_fetch_inferior_registers (regcache, r);
}
do_windows_store_inferior_registers (const struct regcache *regcache, int r)
{
if (!current_thread)
- /* Windows sometimes uses a non-existent thread id in its events */;
+ /* Windows sometimes uses a non-existent thread id in its events. */;
else if (r >= 0)
regcache_raw_collect (regcache, r,
((char *) ¤t_thread->context) + mappings[r]);
}
}
-/* Store a new register value into the current thread context */
+/* Store a new register value into the current thread context. */
static void
windows_store_inferior_registers (struct target_ops *ops,
struct regcache *regcache, int r)
{
current_thread = thread_rec (ptid_get_tid (inferior_ptid), TRUE);
/* Check if current_thread exists. Windows sometimes uses a non-existent
- thread id in its events */
+ thread id in its events. */
if (current_thread)
do_windows_store_inferior_registers (regcache, r);
}
-/* Get the name of a given module at at given base address. If base_address
+/* 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
MODULEINFO mi;
int i;
HMODULE dh_buf[1];
- HMODULE *DllHandle = dh_buf; /* Set to temporary storage for initial query */
+ 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. */
+ as 512. */
#endif
cbNeeded = 0;
- /* Find size of buffer needed to handle list of modules loaded in inferior */
+ /* 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 */
+ /* Allocate correct amount of space for module list. */
DllHandle = (HMODULE *) alloca (cbNeeded);
if (!DllHandle)
goto failed;
- /* Get the list of modules */
+ /* 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 */
+ /* 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 */
+ /* Try to find the name of the given module. */
#ifdef __CYGWIN__
- /* Cygwin prefers that the path be in /x/y/z format */
+ /* 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 ());
+ error (_("Error getting dll name: %u."),
+ (unsigned) 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);
len = GetModuleFileNameEx (current_process_handle,
DllHandle[i], dll_name_ret, __PMAX);
if (len == 0)
- error (_("Error getting dll name: %u."), (unsigned) GetLastError ());
+ error (_("Error getting dll name: %u."),
+ (unsigned) GetLastError ());
#endif
return 1; /* success */
}
}
/* Encapsulate the information required in a call to
- symbol_file_add_args */
+ symbol_file_add_args. */
struct safe_symbol_file_add_args
{
char *name;
struct objfile *ret;
};
-/* Maintain a linked list of "so" information. */
+/* Maintain a linked list of "so" information. */
struct lm_info
{
LPVOID load_addr;
static struct so_list solib_start, *solib_end;
/* Call symbol_file_add with stderr redirected. We don't care if there
- are errors. */
+ are errors. */
static int
safe_symbol_file_add_stub (void *argv)
{
#undef p
}
-/* Restore gdb's stderr after calling symbol_file_add */
+/* Restore gdb's stderr after calling symbol_file_add. */
static void
safe_symbol_file_add_cleanup (void *p)
{
#undef sp
}
-/* symbol_file_add wrapper that prevents errors from being displayed. */
+/* 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,
#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);
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;
}
- /* The symbols in a dll are offset by 0x1000, which is the the
+ /* The symbols in a dll are offset by 0x1000, which is the
offset from 0 of the first byte in an image - because of the
- file header and the section alignment. */
- cygwin_load_start = (CORE_ADDR) (uintptr_t) ((char *) load_addr + 0x1000);
+ file header and the section alignment. */
+ cygwin_load_start = (CORE_ADDR) (uintptr_t) ((char *)
+ load_addr + 0x1000);
cygwin_load_end = cygwin_load_start + bfd_section_size (abfd, text);
- bfd_close (abfd);
+ gdb_bfd_unref (abfd);
}
#endif
/* Attempt to read the name of the dll that was detected.
This is documented to work only when actively debugging
- a program. It will not work for attached processes. */
+ a program. It will not work for attached processes. */
if (address == NULL)
return NULL;
/* See if we could read the address of a string, and that the
- address isn't null. */
- if (!ReadProcessMemory (h, address, &address_ptr, sizeof (address_ptr), &done)
+ address isn't null. */
+ if (!ReadProcessMemory (h, address, &address_ptr,
+ sizeof (address_ptr), &done)
|| done != sizeof (address_ptr) || !address_ptr)
return NULL;
- /* Find the length of the string */
+ /* Find the length of the string. */
while (ReadProcessMemory (h, address_ptr + len++ * size, &b, size, &done)
&& (b[0] != 0 || b[size - 1] != 0) && done == size)
continue;
dll_buf[0] = dll_buf[sizeof (dll_buf) - 1] = '\0';
+ /* Try getting the DLL name by searching the list of known modules
+ and matching their base address against this new DLL's base address.
+
+ FIXME: brobecker/2013-12-10:
+ It seems odd to be going through this search if the DLL name could
+ simply be extracted via "event->lpImageName". Moreover, some
+ experimentation with various versions of Windows seem to indicate
+ that it might still be too early for this DLL to be listed when
+ querying the system about the current list of modules, thus making
+ this attempt pointless.
+
+ This code can therefore probably be removed. But at the time of
+ this writing, we are too close to creating the GDB 7.7 branch
+ for us to make such a change. We are therefore defering it. */
+
if (!get_module_name (event->lpBaseOfDll, dll_buf))
dll_buf[0] = dll_buf[sizeof (dll_buf) - 1] = '\0';
dll_name = dll_buf;
+ /* Try getting the DLL name via the lpImageName field of the event.
+ Note that Microsoft documents this fields as strictly optional,
+ in the sense that it might be NULL. And the first DLL event in
+ particular is explicitly documented as "likely not pass[ed]"
+ (source: MSDN LOAD_DLL_DEBUG_INFO structure). */
if (*dll_name == '\0')
dll_name = get_image_name (current_process_handle,
event->lpImageName, event->fUnicode);
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;
}
return 0;
}
-/* Clear list of loaded DLLs. */
+/* Clear list of loaded DLLs. */
static void
windows_clear_solib (void)
{
solib_end = &solib_start;
}
-/* Load DLL symbol info. */
-void
+/* Load DLL symbol info. */
+static void
dll_symbol_command (char *args, int from_tty)
{
int n;
/* 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. */
+ a Cygwin signal. Otherwise just print the string as a warning. */
static int
handle_output_debug_string (struct target_waitstatus *ourstatus)
{
&s, 1024, 0)
|| !s || !*s)
/* nothing to do */;
- else if (strncmp (s, _CYGWIN_SIGNAL_STRING, sizeof (_CYGWIN_SIGNAL_STRING) - 1) != 0)
+ else if (strncmp (s, _CYGWIN_SIGNAL_STRING,
+ sizeof (_CYGWIN_SIGNAL_STRING) - 1) != 0)
{
#ifdef __CYGWIN__
if (strncmp (s, "cYg", 3) != 0)
#ifdef __COPY_CONTEXT_SIZE
else
{
- /* Got a cygwin signal marker. A cygwin signal is followed by the signal number
- itself and then optionally followed by the thread id and address to saved context
- within the DLL. If these are supplied, then the given thread is assumed to have
- issued the signal and the context from the thread is assumed to be stored at the
- given address in the inferior. Tell gdb to treat this like a real signal. */
+ /* Got a cygwin signal marker. A cygwin signal is followed by
+ the signal number itself and then optionally followed by the
+ thread id and address to saved context within the DLL. If
+ these are supplied, then the given thread is assumed to have
+ issued the signal and the context from the thread is assumed
+ to be stored at the given address in the inferior. Tell gdb
+ 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)
+ &saved_context,
+ __COPY_CONTEXT_SIZE, &n)
&& n == __COPY_CONTEXT_SIZE)
have_saved_context = 1;
current_event.dwThreadId = retval;
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;
}
}
ourstatus->kind = TARGET_WAITKIND_STOPPED;
- /* Record the context of the current thread */
+ /* Record the context of the current thread. */
th = thread_rec (current_event.dwThreadId, -1);
switch (code)
{
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 itself. Cygwin uses
- a kind of exception handling to deal with passed-in invalid addresses. gdb
- should not treat these as real SEGVs since they will be silently handled by
- cygwin. A real SEGV will (theoretically) be caught by 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;
- CORE_ADDR addr = (CORE_ADDR) (uintptr_t) current_event.u.Exception.ExceptionRecord.ExceptionAddress;
- if ((!cygwin_exceptions && (addr >= cygwin_load_start && addr < cygwin_load_end))
+ /* See if the access violation happened within the cygwin DLL
+ itself. Cygwin uses a kind of exception handling to deal
+ with passed-in invalid addresses. gdb should not treat
+ these as real SEGVs since they will be silently handled by
+ cygwin. A real SEGV will (theoretically) be caught by
+ 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. */
+ 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))
+ && strncmp (fn, "KERNEL32!IsBad",
+ strlen ("KERNEL32!IsBad")) == 0))
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. */
+ /* 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++;
}
/* Resume all artificially suspended threads if we are continuing
- execution */
+ execution. */
static BOOL
windows_continue (DWORD continue_status, int id)
{
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"));
open_process_used = 1;
else
{
- error (_("OpenProcess call failed, GetLastError = %lud\n"),
- 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;
DWORD continue_status = DBG_CONTINUE;
if (resume_all)
ptid = inferior_ptid;
- if (sig != TARGET_SIGNAL_0)
+ if (sig != GDB_SIGNAL_0)
{
if (current_event.dwDebugEventCode != EXCEPTION_DEBUG_EVENT)
{
for (i = 0; xlate[i].them != -1; i++)
if (xlate[i].us == sig)
{
- current_event.u.Exception.ExceptionRecord.ExceptionCode =
- xlate[i].them;
+ current_event.u.Exception.ExceptionRecord.ExceptionCode
+ = xlate[i].them;
continue_status = DBG_EXCEPTION_NOT_HANDLED;
break;
}
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));
- /* Get context for currently selected thread */
+ /* Get context for currently selected thread. */
th = thread_rec (ptid_get_tid (inferior_ptid), FALSE);
if (th)
{
if (step)
{
- /* Single step by setting t bit */
+ /* Single step by setting t bit. */
struct regcache *regcache = get_current_regcache ();
struct gdbarch *gdbarch = get_regcache_arch (regcache);
windows_fetch_inferior_registers (ops, regcache,
}
/* Allow continuing with the same signal that interrupted us.
- Otherwise complain. */
+ Otherwise complain. */
if (resume_all)
windows_continue (continue_status, -1);
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;
if (!DebugBreakProcess (current_process_handle))
- warning (_("\
-Could not interrupt program. Press Ctrl-c in the program console."));
+ warning (_("Could not interrupt program. "
+ "Press Ctrl-c in the program console."));
/* Return true to tell that Ctrl-C has been handled. */
return TRUE;
static thread_info dummy_thread_info;
int retval = 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. */
+ a main thread. */
retval = fake_create_process ();
if (retval)
saw_create++;
}
break;
}
- /* Record the existence of this thread */
+ /* Record the existence of this thread. */
retval = current_event.dwThreadId;
th = windows_add_thread (ptid_build (current_event.dwProcessId, 0,
current_event.dwThreadId),
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 */
+ /* Add the main thread. */
th = windows_add_thread (ptid_build (current_event.dwProcessId, 0,
current_event.dwThreadId),
current_event.u.CreateProcessInfo.hThread,
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"));
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"));
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",
+ case OUTPUT_DEBUG_STRING_EVENT: /* Message from the kernel. */
+ 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;
}
with a SPURIOUS because resume can try and step or modify things,
which needs a current_thread->h. But some of these exceptions mark
the birth or death of threads, which mean that the current thread
- isn't necessarily what you think it is. */
+ isn't necessarily what you think it is. */
while (1)
{
- The debugger and the program do not share the console, in
which case the Ctrl-c event only reached the debugger.
In that case, the ctrl_c handler will take care of interrupting
- the inferior. Note that this case is working starting with
- Windows XP. For Windows 2000, Ctrl-C should be pressed in the
+ the inferior. Note that this case is working starting with
+ Windows XP. For Windows 2000, Ctrl-C should be pressed in the
inferior console.
- The debugger and the program share the same console, in which
}
}
+/* On certain versions of Windows, the information about ntdll.dll
+ is not available yet at the time we get the LOAD_DLL_DEBUG_EVENT,
+ thus preventing us from reporting this DLL as an SO. This has been
+ witnessed on Windows 8.1, for instance. A possible explanation
+ is that ntdll.dll might be mapped before the SO info gets created
+ by the Windows system -- ntdll.dll is the first DLL to be reported
+ via LOAD_DLL_DEBUG_EVENT and other DLLs do not seem to suffer from
+ that problem.
+
+ If we indeed are missing ntdll.dll, this function tries to recover
+ from this issue, after the fact. Do nothing if we encounter any
+ issue trying to locate that DLL. */
+
+static void
+windows_ensure_ntdll_loaded (void)
+{
+ struct so_list *so;
+ HMODULE dummy_hmodule;
+ DWORD cb_needed;
+ HMODULE *hmodules;
+ int i;
+
+ for (so = solib_start.next; so != NULL; so = so->next)
+ if (FILENAME_CMP (lbasename (so->so_name), "ntdll.dll") == 0)
+ return; /* ntdll.dll already loaded, nothing to do. */
+
+ if (EnumProcessModules (current_process_handle, &dummy_hmodule,
+ sizeof (HMODULE), &cb_needed) == 0)
+ return;
+
+ if (cb_needed < 1)
+ return;
+
+ hmodules = (HMODULE *) alloca (cb_needed);
+ if (EnumProcessModules (current_process_handle, hmodules,
+ cb_needed, &cb_needed) == 0)
+ return;
+
+ for (i = 0; i < (int) (cb_needed / sizeof (HMODULE)); i++)
+ {
+ MODULEINFO mi;
+#ifdef __USEWIDE
+ wchar_t dll_name[__PMAX];
+ char name[__PMAX];
+#else
+ char dll_name[__PMAX];
+ char *name;
+#endif
+ if (GetModuleInformation (current_process_handle, hmodules[i],
+ &mi, sizeof (mi)) == 0)
+ continue;
+ if (GetModuleFileNameEx (current_process_handle, hmodules[i],
+ dll_name, sizeof (dll_name)) == 0)
+ continue;
+#ifdef __USEWIDE
+ wcstombs (name, dll_name, __PMAX);
+#else
+ name = dll_name;
+#endif
+ if (FILENAME_CMP (lbasename (name), "ntdll.dll") == 0)
+ {
+ solib_end->next = windows_make_so (name, mi.lpBaseOfDll);
+ solib_end = solib_end->next;
+ return;
+ }
+ }
+}
+
static void
do_initial_windows_stuff (struct target_ops *ops, DWORD pid, int attaching)
{
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;
while (1)
{
stop_after_trap = 1;
- wait_for_inferior (0);
+ wait_for_inferior ();
tp = inferior_thread ();
- if (tp->suspend.stop_signal != TARGET_SIGNAL_TRAP)
+ if (tp->suspend.stop_signal != GDB_SIGNAL_TRAP)
resume (0, tp->suspend.stop_signal);
else
break;
}
+ /* FIXME: brobecker/2013-12-10: We should try another approach where
+ we first ignore all DLL load/unload events up until this point,
+ and then iterate over all modules to create the associated shared
+ objects. This is a fairly significant change, however, and we are
+ close to creating a release branch, so we are delaying it a bit,
+ after the branch is created. */
+ windows_ensure_ntdll_loaded ();
+
windows_initialization_done = 1;
inf->control.stop_soon = NO_STOP_QUIETLY;
stop_after_trap = 0;
This code is copied from the Cygwin source code and rearranged to allow
dynamically loading of the needed symbols from advapi32 which is only
- available on NT/2K/XP. */
+ available on NT/2K/XP. */
static int
set_process_privilege (const char *privilege, BOOL enable)
{
#if 0
/* Disabled, otherwise every `attach' in an unprivileged user session
would raise the "Failed to get SE_DEBUG_NAME privilege" warning in
- windows_attach(). */
+ windows_attach(). */
/* AdjustTokenPrivileges returns TRUE even if the privilege could not
- be enabled. GetLastError () returns an correct error code, though. */
+ be enabled. GetLastError () returns an correct error code, though. */
if (enable && GetLastError () == ERROR_NOT_ALL_ASSIGNED)
goto out;
#endif
if (set_process_privilege (SE_DEBUG_NAME, TRUE) < 0)
{
printf_unfiltered ("Warning: Failed to get SE_DEBUG_NAME privilege\n");
- printf_unfiltered ("This can cause attach to fail on Windows NT/2K/XP\n");
+ printf_unfiltered ("This can cause attach to "
+ "fail on Windows NT/2K/XP\n");
}
windows_init_thread_list ();
#ifdef __CYGWIN__
if (!ok)
{
- /* Try fall back to Cygwin pid */
+ /* Try fall back to Cygwin pid. */
pid = cygwin_internal (CW_CYGWIN_PID_TO_WINPID, pid);
if (pid > 0)
}
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);
}
+ i386_cleanup_dregs ();
inferior_ptid = null_ptid;
detach_inferior (current_event.dwProcessId);
{
static char path[__PMAX];
#ifdef __CYGWIN__
- /* Try to find exe name as symlink target of /proc/<pid>/exe */
+ /* 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))
{
#endif
/* 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. */
+ of gdb, or we're trying to debug a non-Cygwin windows executable. */
if (!get_module_name (0, path))
path[0] = '\0';
*flags |= CREATE_NEW_CONSOLE;
}
+#ifndef __CYGWIN__
+/* Function called by qsort to sort environment strings. */
+
+static int
+envvar_cmp (const void *a, const void *b)
+{
+ const char **p = (const char **) a;
+ const char **q = (const char **) b;
+ return strcasecmp (*p, *q);
+}
+#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;
+ size_t envlen;
+ int i;
+ size_t envsize;
+ char **env;
#endif
PROCESS_INFORMATION pi;
BOOL ret;
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;
}
}
+ /* CreateProcess takes the environment list as a null terminated set of
+ strings (i.e. two nulls terminate the list). */
+
+ /* Get total size for env strings. */
+ for (envlen = 0, i = 0; in_env[i] && *in_env[i]; i++)
+ envlen += strlen (in_env[i]) + 1;
+
+ envsize = sizeof (in_env[0]) * (i + 1);
+ env = (char **) alloca (envsize);
+ memcpy (env, in_env, envsize);
+ /* Windows programs expect the environment block to be sorted. */
+ qsort (env, i, sizeof (char *), envvar_cmp);
+
+ w32env = alloca (envlen + 1);
+
+ /* Copy env strings into new buffer. */
+ for (temp = w32env, i = 0; env[i] && *env[i]; i++)
+ {
+ strcpy (temp, env[i]);
+ temp += strlen (temp) + 1;
+ }
+
+ /* Final nil string to terminate new env. */
+ *temp = 0;
+
windows_init_thread_list ();
ret = CreateProcessA (0,
args, /* command line */
NULL, /* thread */
TRUE, /* inherit handles */
flags, /* start flags */
- NULL, /* environment */
+ w32env, /* environment */
NULL, /* current directory */
&si,
&pi);
#endif
if (!ret)
- error (_("Error creating process %s, (error %d)."),
+ error (_("Error creating process %s, (error %u)."),
exec_file, (unsigned) GetLastError ());
CloseHandle (pi.hThread);
}
/* Send a SIGINT to the process group. This acts just like the user typed a
- ^C on the controlling terminal. */
+ ^C on the controlling terminal. */
static void
windows_stop (ptid_t ptid)
registers_changed (); /* refresh register state */
}
-static int
-windows_xfer_memory (CORE_ADDR memaddr, gdb_byte *our, int len,
- int write, struct mem_attrib *mem,
- struct target_ops *target)
+/* Helper for windows_xfer_partial that handles memory transfers.
+ Arguments are like target_xfer_partial. */
+
+static LONGEST
+windows_xfer_memory (gdb_byte *readbuf, const gdb_byte *writebuf,
+ ULONGEST memaddr, ULONGEST len)
{
SIZE_T done = 0;
- if (write)
+ BOOL success;
+ DWORD lasterror = 0;
+
+ if (writebuf != NULL)
{
- DEBUG_MEM (("gdb: write target memory, %d bytes at 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;
+ if (!success && lasterror == ERROR_PARTIAL_COPY && done > 0)
+ return done;
+ else
+ return success ? done : TARGET_XFER_E_IO;
}
static void
break;
}
- target_mourn_inferior (); /* or just windows_mourn_inferior? */
+ target_mourn_inferior (); /* Or just windows_mourn_inferior? */
}
static void
-windows_prepare_to_store (struct regcache *regcache)
+windows_prepare_to_store (struct target_ops *self, struct regcache *regcache)
{
- /* Do nothing, since we can store individual regs */
+ /* Do nothing, since we can store individual regs. */
}
static int
}
static void
-windows_close (int x)
+windows_close (void)
{
DEBUG_EVENTS (("gdb: windows_close, inferior_ptid=%d\n",
- PIDGET (inferior_ptid)));
+ ptid_get_pid (inferior_ptid)));
}
-/* Convert pid to printable format. */
+/* Convert pid to printable format. */
static char *
windows_pid_to_str (struct target_ops *ops, ptid_t ptid)
{
windows_xfer_shared_libraries (struct target_ops *ops,
enum target_object object, const char *annex,
gdb_byte *readbuf, const gdb_byte *writebuf,
- ULONGEST offset, LONGEST len)
+ ULONGEST offset, ULONGEST len)
{
struct obstack obstack;
const char *buf;
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);
+ windows_xfer_shared_library (so->so_name, (CORE_ADDR)
+ (uintptr_t) so->lm_info->load_addr,
+ 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;
static LONGEST
windows_xfer_partial (struct target_ops *ops, enum target_object object,
const char *annex, gdb_byte *readbuf,
- const gdb_byte *writebuf, ULONGEST offset, LONGEST len)
+ const gdb_byte *writebuf, ULONGEST offset, ULONGEST len)
{
switch (object)
{
case TARGET_OBJECT_MEMORY:
- if (readbuf)
- return (*ops->deprecated_xfer_memory) (offset, readbuf,
- len, 0/*read*/, NULL, ops);
- if (writebuf)
- return (*ops->deprecated_xfer_memory) (offset, (gdb_byte *) writebuf,
- len, 1/*write*/, NULL, ops);
- return -1;
+ return windows_xfer_memory (readbuf, writebuf, offset, len);
case TARGET_OBJECT_LIBRARIES:
return windows_xfer_shared_libraries (ops, object, annex, readbuf,
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;
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_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
add_info_alias ("dll", "sharedlibrary", 1);
}
+/* -Wmissing-prototypes */
+extern initialize_file_ftype _initialize_windows_nat;
+
void
_initialize_windows_nat (void)
{
NULL, /* FIXME: i18n: */
&setlist, &showlist);
- add_setshow_boolean_cmd ("cygwin-exceptions", class_support, &cygwin_exceptions, _("\
+ add_setshow_boolean_cmd ("cygwin-exceptions", class_support,
+ &cygwin_exceptions, _("\
Break when an exception is detected in the Cygwin DLL itself."), _("\
Show whether gdb breaks on exceptions in the Cygwin DLL itself."), NULL,
NULL,
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. */
+ it means that the thread has died. Otherwise it is assumed to be alive. */
static int
windows_thread_alive (struct target_ops *ops, ptid_t ptid)
{
gdb_assert (ptid_get_tid (ptid) != 0);
tid = ptid_get_tid (ptid);
- return WaitForSingleObject (thread_rec (tid, FALSE)->h, 0) == WAIT_OBJECT_0 ?
- FALSE : TRUE;
+ return WaitForSingleObject (thread_rec (tid, FALSE)->h, 0) == WAIT_OBJECT_0
+ ? FALSE : TRUE;
}
+/* -Wmissing-prototypes */
+extern initialize_file_ftype _initialize_check_for_gdb_ini;
+
void
_initialize_check_for_gdb_ini (void)
{
sizeof ("/gdb.ini"));
strcpy (oldini, homedir);
p = strchr (oldini, '\0');
- if (p > oldini && p[-1] != '/')
+ if (p > oldini && !IS_DIR_SEPARATOR (p[-1]))
*p++ = '/';
strcpy (p, "gdb.ini");
if (access (oldini, 0) == 0)
{
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);
}
}
}
/* Define dummy functions which always return error for the rare cases where
- these functions could not be found. */
+ these functions could not be found. */
static BOOL WINAPI
bad_DebugActiveProcessStop (DWORD w)
{
return size;
}
+/* -Wmissing-prototypes */
+extern initialize_file_ftype _initialize_loadable;
+
/* Load any functions which may not be available in ancient versions
- of Windows. */
+ of Windows. */
+
void
_initialize_loadable (void)
{
}
/* Set variables to dummy versions of these processes if the function
- wasn't found in kernel32.dll. */
+ wasn't found in kernel32.dll. */
if (!DebugBreakProcess)
DebugBreakProcess = bad_DebugBreakProcess;
if (!DebugActiveProcessStop || !DebugSetProcessKillOnExit)
GetCurrentConsoleFont = bad_GetCurrentConsoleFont;
/* Load optional functions used for retrieving filename information
- associated with the currently debugged process or its dlls. */
+ associated with the currently debugged process or its dlls. */
hm = LoadLibrary ("psapi.dll");
if (hm)
{
if (!EnumProcessModules || !GetModuleInformation || !GetModuleFileNameEx)
{
/* Set variables to dummy versions of these processes if the function
- wasn't found in psapi.dll. */
+ wasn't found in psapi.dll. */
EnumProcessModules = bad_EnumProcessModules;
GetModuleInformation = bad_GetModuleInformation;
GetModuleFileNameEx = bad_GetModuleFileNameEx;
- /* This will probably fail on Windows 9x/Me. Let the user know that we're
- missing some functionality. */
- warning(_("cannot automatically find executable file or library to read symbols.\nUse \"file\" or \"dll\" command to load executable/libraries directly."));
+ /* This will probably fail on Windows 9x/Me. Let the user know
+ that we're missing some functionality. */
+ warning(_("\
+cannot automatically find executable file or library to read symbols.\n\
+Use \"file\" or \"dll\" command to load executable/libraries directly."));
}
hm = LoadLibrary ("advapi32.dll");
AdjustTokenPrivileges = (void *)
GetProcAddress (hm, "AdjustTokenPrivileges");
/* Only need to set one of these since if OpenProcessToken fails nothing
- else is needed. */
- if (!OpenProcessToken || !LookupPrivilegeValueA || !AdjustTokenPrivileges)
+ else is needed. */
+ if (!OpenProcessToken || !LookupPrivilegeValueA
+ || !AdjustTokenPrivileges)
OpenProcessToken = bad_OpenProcessToken;
}
}