X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fwindows-nat.c;h=67f0c99599a9779bfa5a5c5c33498adf76bba81d;hb=727fc41e077139570ea8b8ddfd6c546b2a55627c;hp=9abe333bd7686d811e44245f1b5e7cc0ef458993;hpb=3ee6f62373efd8801d5a97afd5fe24e339a5f4d5;p=deliverable%2Fbinutils-gdb.git
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index 9abe333bd7..67f0c99599 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -1,7 +1,7 @@
-/* Target-vector operations for controlling win32 child processes, for GDB.
+/* Target-vector operations for controlling windows child processes, for GDB.
- Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
- Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+ 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
Contributed by Cygnus Solutions, A Red Hat Company.
@@ -9,23 +9,19 @@
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without eve nthe implied warranty of
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ along with this program. If not, see . */
/* Originally by Steve Chamberlain, sac@cygnus.com */
-/* We assume we're being built with and will be used for cygwin. */
-
#include "defs.h"
#include "frame.h" /* required by inferior.h */
#include "inferior.h"
@@ -42,11 +38,15 @@
#include
#include
#include
+#ifdef __CYGWIN__
#include
+#endif
+#include
#include "buildsym.h"
#include "symfile.h"
#include "objfiles.h"
+#include "gdb_obstack.h"
#include "gdb_string.h"
#include "gdbthread.h"
#include "gdbcmd.h"
@@ -54,12 +54,25 @@
#include
#include "exec.h"
#include "solist.h"
+#include "solib.h"
+#include "xml-support.h"
#include "i386-tdep.h"
#include "i387-tdep.h"
-static struct target_ops win32_ops;
-static struct target_so_ops win32_so_ops;
+#include "windows-tdep.h"
+#include "windows-nat.h"
+
+static struct target_ops windows_ops;
+
+#ifdef __CYGWIN__
+/* The starting and ending address of the cygwin1.dll text segment. */
+static CORE_ADDR cygwin_load_start;
+static CORE_ADDR cygwin_load_end;
+#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. */
/* If we're not using the old Cygwin header file set, define the
following which never should have been in the generic Win32 API
@@ -71,19 +84,27 @@ enum
CONTEXT_DEBUGGER = (CONTEXT_FULL | CONTEXT_FLOATING_POINT)
};
#endif
-#include
#include
+#ifndef CONTEXT_EXTENDED_REGISTERS
+/* This macro is only defined on ia32. It only makes sense on this target,
+ so define it as zero if not already defined. */
+#define CONTEXT_EXTENDED_REGISTERS 0
+#endif
+
#define CONTEXT_DEBUGGER_DR CONTEXT_DEBUGGER | CONTEXT_DEBUG_REGISTERS \
| CONTEXT_EXTENDED_REGISTERS
static unsigned dr[8];
static int debug_registers_changed;
static int debug_registers_used;
+#define DR6_CLEAR_VALUE 0xffff0ff0
/* The string sent by cygwin when it processes a signal.
FIXME: This should be in a cygwin include file. */
-#define CYGWIN_SIGNAL_STRING "cygwin: signal"
+#ifndef _CYGWIN_SIGNAL_STRING
+#define _CYGWIN_SIGNAL_STRING "cYgSiGw00f"
+#endif
#define CHECK(x) check (x, __FILE__,__LINE__)
#define DEBUG_EXEC(x) if (debug_exec) printf_unfiltered x
@@ -91,22 +112,22 @@ static int debug_registers_used;
#define DEBUG_MEM(x) if (debug_memory) printf_unfiltered x
#define DEBUG_EXCEPT(x) if (debug_exceptions) printf_unfiltered x
-static void win32_stop (void);
-static int win32_win32_thread_alive (ptid_t);
-static void win32_kill_inferior (void);
+static void windows_stop (ptid_t);
+static int windows_thread_alive (struct target_ops *, ptid_t);
+static void windows_kill_inferior (void);
static enum target_signal last_sig = TARGET_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. */
+ not available in gdb's thread structure. */
typedef struct thread_info_struct
{
struct thread_info_struct *next;
DWORD id;
HANDLE h;
char *name;
- int suspend_count;
+ int suspended;
int reload_context;
CONTEXT context;
STACKFRAME sf;
@@ -127,9 +148,13 @@ static DWORD main_thread_id; /* Thread ID of the main thread */
static int exception_count = 0;
static int event_count = 0;
static int saw_create;
+static int open_process_used = 0;
/* User options. */
static int new_console = 0;
+#ifdef __CYGWIN__
+static int cygwin_exceptions = 0;
+#endif
static int new_group = 1;
static int debug_exec = 0; /* show execution */
static int debug_events = 0; /* show events from kernel */
@@ -137,11 +162,16 @@ static int debug_memory = 0; /* show target memory accesses */
static int debug_exceptions = 0; /* show target exceptions */
static int useshell = 0; /* use shell for subprocesses */
-/* This vector maps GDB's idea of a register's number into an address
- in the win32 exception context vector.
+/* This vector maps GDB's idea of a register's number into an offset
+ in the windows exception context vector.
It also contains the bit mask needed to load the register in question.
+ The contents of this table can only be computed by the units
+ that provide CPU-specific support for Windows native debugging.
+ These units should set the table by calling
+ windows_set_context_register_offsets.
+
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
@@ -150,55 +180,7 @@ static int useshell = 0; /* use shell for subprocesses */
the other regs of the group, and then we copy the info in and set
out bit. */
-#define context_offset(x) ((int)&(((CONTEXT *)NULL)->x))
-static const int mappings[] =
-{
- context_offset (Eax),
- context_offset (Ecx),
- context_offset (Edx),
- context_offset (Ebx),
- context_offset (Esp),
- context_offset (Ebp),
- context_offset (Esi),
- context_offset (Edi),
- context_offset (Eip),
- context_offset (EFlags),
- context_offset (SegCs),
- context_offset (SegSs),
- context_offset (SegDs),
- context_offset (SegEs),
- context_offset (SegFs),
- context_offset (SegGs),
- context_offset (FloatSave.RegisterArea[0 * 10]),
- context_offset (FloatSave.RegisterArea[1 * 10]),
- context_offset (FloatSave.RegisterArea[2 * 10]),
- context_offset (FloatSave.RegisterArea[3 * 10]),
- context_offset (FloatSave.RegisterArea[4 * 10]),
- context_offset (FloatSave.RegisterArea[5 * 10]),
- context_offset (FloatSave.RegisterArea[6 * 10]),
- context_offset (FloatSave.RegisterArea[7 * 10]),
- context_offset (FloatSave.ControlWord),
- context_offset (FloatSave.StatusWord),
- context_offset (FloatSave.TagWord),
- context_offset (FloatSave.ErrorSelector),
- context_offset (FloatSave.ErrorOffset),
- context_offset (FloatSave.DataSelector),
- context_offset (FloatSave.DataOffset),
- context_offset (FloatSave.ErrorSelector)
- /* XMM0-7 */ ,
- context_offset (ExtendedRegisters[10*16]),
- context_offset (ExtendedRegisters[11*16]),
- context_offset (ExtendedRegisters[12*16]),
- context_offset (ExtendedRegisters[13*16]),
- context_offset (ExtendedRegisters[14*16]),
- context_offset (ExtendedRegisters[15*16]),
- context_offset (ExtendedRegisters[16*16]),
- context_offset (ExtendedRegisters[17*16]),
- /* MXCSR */
- context_offset (ExtendedRegisters[24])
-};
-
-#undef context_offset
+static const int *mappings;
/* This vector maps the target's idea of an exception (extracted
from the DEBUG_EVENT structure) to GDB's idea. */
@@ -220,6 +202,15 @@ static const struct xlate_exception
{STATUS_FLOAT_DIVIDE_BY_ZERO, TARGET_SIGNAL_FPE},
{-1, -1}};
+/* Set the MAPPINGS static global to OFFSETS.
+ See the description of MAPPINGS for more details. */
+
+void
+windows_set_context_register_offsets (const int *offsets)
+{
+ mappings = offsets;
+}
+
static void
check (BOOL ok, const char *file, int line)
{
@@ -228,9 +219,9 @@ check (BOOL ok, const char *file, int line)
GetLastError ());
}
-/* Find a thread record given a thread id.
- If get_context then also retrieve the context for this
- thread. */
+/* 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 *
thread_rec (DWORD id, int get_context)
{
@@ -239,12 +230,21 @@ thread_rec (DWORD id, int get_context)
for (th = &thread_head; (th = th->next) != NULL;)
if (th->id == id)
{
- if (!th->suspend_count && get_context)
+ if (!th->suspended && get_context)
{
if (get_context > 0 && id != current_event.dwThreadId)
- th->suspend_count = SuspendThread (th->h) + 1;
+ {
+ if (SuspendThread (th->h) == (DWORD) -1)
+ {
+ DWORD err = GetLastError ();
+ warning (_("SuspendThread failed. (winerr %d)"),
+ (int) err);
+ return NULL;
+ }
+ th->suspended = 1;
+ }
else if (get_context < 0)
- th->suspend_count = -1;
+ th->suspended = -1;
th->reload_context = 1;
}
return th;
@@ -253,23 +253,27 @@ thread_rec (DWORD id, int get_context)
return NULL;
}
-/* Add a thread to the thread list */
+/* Add a thread to the thread list. */
static thread_info *
-win32_add_thread (DWORD id, HANDLE h)
+windows_add_thread (ptid_t ptid, HANDLE h)
{
thread_info *th;
+ DWORD id;
+
+ gdb_assert (ptid_get_tid (ptid) != 0);
+
+ id = ptid_get_tid (ptid);
if ((th = thread_rec (id, FALSE)))
return th;
- th = (thread_info *) xmalloc (sizeof (*th));
- memset (th, 0, sizeof (*th));
+ th = XZALLOC (thread_info);
th->id = id;
th->h = h;
th->next = thread_head.next;
thread_head.next = th;
- add_thread (pid_to_ptid (id));
- /* Set the debug registers for the new thread in they are used. */
+ add_thread (ptid);
+ /* Set the debug registers for the new thread if they are used. */
if (debug_registers_used)
{
/* Only change the value of the debug registers. */
@@ -279,8 +283,7 @@ win32_add_thread (DWORD id, HANDLE h)
th->context.Dr1 = dr[1];
th->context.Dr2 = dr[2];
th->context.Dr3 = dr[3];
- /* th->context.Dr6 = dr[6];
- FIXME: should we set dr6 also ?? */
+ th->context.Dr6 = DR6_CLEAR_VALUE;
th->context.Dr7 = dr[7];
CHECK (SetThreadContext (th->h, &th->context));
th->context.ContextFlags = 0;
@@ -291,17 +294,16 @@ win32_add_thread (DWORD id, HANDLE h)
/* Clear out any old thread list and reintialize it to a
pristine state. */
static void
-win32_init_thread_list (void)
+windows_init_thread_list (void)
{
thread_info *th = &thread_head;
- DEBUG_EVENTS (("gdb: win32_init_thread_list\n"));
+ DEBUG_EVENTS (("gdb: windows_init_thread_list\n"));
init_thread_list ();
while (th->next != NULL)
{
thread_info *here = th->next;
th->next = here->next;
- (void) CloseHandle (here->h);
xfree (here);
}
thread_head.next = NULL;
@@ -309,13 +311,18 @@ win32_init_thread_list (void)
/* Delete a thread from the list of threads */
static void
-win32_delete_thread (DWORD id)
+windows_delete_thread (ptid_t ptid)
{
thread_info *th;
+ DWORD id;
+
+ gdb_assert (ptid_get_tid (ptid) != 0);
+
+ id = ptid_get_tid (ptid);
if (info_verbose)
- printf_unfiltered ("[Deleting %s]\n", target_pid_to_str (pid_to_ptid (id)));
- delete_thread (pid_to_ptid (id));
+ printf_unfiltered ("[Deleting %s]\n", target_pid_to_str (ptid));
+ delete_thread (ptid);
for (th = &thread_head;
th->next != NULL && th->next->id != id;
@@ -326,15 +333,16 @@ win32_delete_thread (DWORD id)
{
thread_info *here = th->next;
th->next = here->next;
- CloseHandle (here->h);
xfree (here);
}
}
static void
-do_win32_fetch_inferior_registers (int r)
+do_windows_fetch_inferior_registers (struct regcache *regcache, int r)
{
char *context_offset = ((char *) ¤t_thread->context) + mappings[r];
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
long l;
if (!current_thread)
@@ -343,161 +351,166 @@ do_win32_fetch_inferior_registers (int r)
if (current_thread->reload_context)
{
- thread_info *th = current_thread;
- th->context.ContextFlags = CONTEXT_DEBUGGER_DR;
- GetThreadContext (th->h, &th->context);
- /* Copy dr values from that thread. */
- dr[0] = th->context.Dr0;
- dr[1] = th->context.Dr1;
- dr[2] = th->context.Dr2;
- dr[3] = th->context.Dr3;
- dr[6] = th->context.Dr6;
- dr[7] = th->context.Dr7;
+#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);
+ have_saved_context = 0;
+ }
+ else
+#endif
+ {
+ thread_info *th = current_thread;
+ 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 */
+ if (!debug_registers_changed)
+ {
+ dr[0] = th->context.Dr0;
+ dr[1] = th->context.Dr1;
+ dr[2] = th->context.Dr2;
+ dr[3] = th->context.Dr3;
+ dr[6] = th->context.Dr6;
+ dr[7] = th->context.Dr7;
+ }
+ }
current_thread->reload_context = 0;
}
-#define I387_ST0_REGNUM I386_ST0_REGNUM
-
- if (r == I387_FISEG_REGNUM)
+ if (r == I387_FISEG_REGNUM (tdep))
{
l = *((long *) context_offset) & 0xffff;
- regcache_raw_supply (current_regcache, r, (char *) &l);
+ regcache_raw_supply (regcache, r, (char *) &l);
}
- else if (r == I387_FOP_REGNUM)
+ else if (r == I387_FOP_REGNUM (tdep))
{
l = (*((long *) context_offset) >> 16) & ((1 << 11) - 1);
- regcache_raw_supply (current_regcache, r, (char *) &l);
+ regcache_raw_supply (regcache, r, (char *) &l);
}
else if (r >= 0)
- regcache_raw_supply (current_regcache, r, context_offset);
+ regcache_raw_supply (regcache, r, context_offset);
else
{
- for (r = 0; r < NUM_REGS; r++)
- do_win32_fetch_inferior_registers (r);
+ for (r = 0; r < gdbarch_num_regs (gdbarch); r++)
+ do_windows_fetch_inferior_registers (regcache, r);
}
-
-#undef I387_ST0_REGNUM
}
static void
-win32_fetch_inferior_registers (int r)
+windows_fetch_inferior_registers (struct target_ops *ops,
+ struct regcache *regcache, int r)
{
- current_thread = thread_rec (PIDGET (inferior_ptid), TRUE);
+ 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 */
if (current_thread)
- do_win32_fetch_inferior_registers (r);
+ do_windows_fetch_inferior_registers (regcache, r);
}
static void
-do_win32_store_inferior_registers (int 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 */;
else if (r >= 0)
- regcache_raw_collect (current_regcache, r,
+ regcache_raw_collect (regcache, r,
((char *) ¤t_thread->context) + mappings[r]);
else
{
- for (r = 0; r < NUM_REGS; r++)
- do_win32_store_inferior_registers (r);
+ for (r = 0; r < gdbarch_num_regs (get_regcache_arch (regcache)); r++)
+ do_windows_store_inferior_registers (regcache, r);
}
}
/* Store a new register value into the current thread context */
static void
-win32_store_inferior_registers (int r)
+windows_store_inferior_registers (struct target_ops *ops,
+ struct regcache *regcache, int r)
{
- current_thread = thread_rec (PIDGET (inferior_ptid), TRUE);
+ 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 */
if (current_thread)
- do_win32_store_inferior_registers (r);
+ do_windows_store_inferior_registers (regcache, r);
}
static int psapi_loaded = 0;
-static HMODULE psapi_module_handle = NULL;
-static BOOL WINAPI (*psapi_EnumProcessModules) (HANDLE, HMODULE *, DWORD, LPDWORD) = NULL;
-static BOOL WINAPI (*psapi_GetModuleInformation) (HANDLE, HMODULE, LPMODULEINFO, DWORD) = NULL;
-static DWORD WINAPI (*psapi_GetModuleFileNameExA) (HANDLE, HMODULE, LPSTR, DWORD) = NULL;
-
+static BOOL WINAPI (*psapi_EnumProcessModules) (HANDLE, HMODULE *, DWORD,
+ LPDWORD);
+static BOOL WINAPI (*psapi_GetModuleInformation) (HANDLE, HMODULE, LPMODULEINFO,
+ DWORD);
+static DWORD WINAPI (*psapi_GetModuleFileNameExA) (HANDLE, HMODULE, LPSTR,
+ DWORD);
+
+/* Get the name of a given module at at given base address. If base_address
+ is zero return the first loaded module (which is always the name of the
+ executable). */
static int
-psapi_get_dll_name (DWORD BaseAddress, char *dll_name_ret)
+get_module_name (LPVOID base_address, char *dll_name_ret)
{
DWORD len;
MODULEINFO mi;
int i;
HMODULE dh_buf[1];
- HMODULE *DllHandle = dh_buf;
+ HMODULE *DllHandle = dh_buf; /* Set to temporary storage for initial query */
DWORD cbNeeded;
- BOOL ok;
+#ifdef __CYGWIN__
+ char pathbuf[PATH_MAX + 1]; /* Temporary storage prior to converting to
+ posix form */
+#else
+ char *pathbuf = dll_name_ret; /* Just copy directly to passed-in arg */
+#endif
- if (!psapi_loaded ||
- psapi_EnumProcessModules == NULL ||
- psapi_GetModuleInformation == NULL ||
- psapi_GetModuleFileNameExA == NULL)
- {
- if (psapi_loaded)
- goto failed;
- psapi_loaded = 1;
- psapi_module_handle = LoadLibrary ("psapi.dll");
- if (!psapi_module_handle)
- {
- /* printf_unfiltered ("error loading psapi.dll: %u", GetLastError ()); */
- goto failed;
- }
- psapi_EnumProcessModules = GetProcAddress (psapi_module_handle, "EnumProcessModules");
- psapi_GetModuleInformation = GetProcAddress (psapi_module_handle, "GetModuleInformation");
- psapi_GetModuleFileNameExA = (void *) GetProcAddress (psapi_module_handle,
- "GetModuleFileNameExA");
- if (psapi_EnumProcessModules == NULL ||
- psapi_GetModuleInformation == NULL ||
- psapi_GetModuleFileNameExA == NULL)
- goto failed;
- }
+ /* If psapi_loaded < 0 either psapi.dll is not available or it does not contain
+ the needed functions. */
+ if (psapi_loaded <= 0)
+ goto failed;
cbNeeded = 0;
- ok = (*psapi_EnumProcessModules) (current_process_handle,
- DllHandle,
- sizeof (HMODULE),
- &cbNeeded);
-
- if (!ok || !cbNeeded)
+ /* Find size of buffer needed to handle list of modules loaded in inferior */
+ if (!psapi_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;
- ok = (*psapi_EnumProcessModules) (current_process_handle,
- DllHandle,
- cbNeeded,
- &cbNeeded);
- if (!ok)
+ /* Get the list of modules */
+ if (!psapi_EnumProcessModules (current_process_handle, DllHandle, cbNeeded,
+ &cbNeeded))
goto failed;
for (i = 0; i < (int) (cbNeeded / sizeof (HMODULE)); i++)
{
- if (!(*psapi_GetModuleInformation) (current_process_handle,
- DllHandle[i],
- &mi,
- sizeof (mi)))
+ /* Get information on this module */
+ if (!psapi_GetModuleInformation (current_process_handle, DllHandle[i],
+ &mi, sizeof (mi)))
error (_("Can't get module info"));
- len = (*psapi_GetModuleFileNameExA) (current_process_handle,
- DllHandle[i],
- dll_name_ret,
- MAX_PATH);
- if (len == 0)
- error (_("Error getting dll name: %u."), (unsigned) GetLastError ());
-
- if ((DWORD) (mi.lpBaseOfDll) == BaseAddress)
- return 1;
+ if (!base_address || mi.lpBaseOfDll == base_address)
+ {
+ /* Try to find the name of the given module */
+ len = psapi_GetModuleFileNameExA (current_process_handle,
+ DllHandle[i], pathbuf, MAX_PATH);
+ if (len == 0)
+ error (_("Error getting dll name: %u."), (unsigned) GetLastError ());
+#ifdef __CYGWIN__
+ /* Cygwin prefers that the path be in /x/y/z format */
+ cygwin_conv_to_full_posix_path (pathbuf, dll_name_ret);
+#endif
+ return 1; /* success */
+ }
}
failed:
dll_name_ret[0] = '\0';
- return 0;
+ return 0; /* failure */
}
/* Encapsulate the information required in a call to
@@ -513,12 +526,10 @@ struct safe_symbol_file_add_args
struct objfile *ret;
};
-/*CGF*/
/* Maintain a linked list of "so" information. */
struct lm_info
{
- DWORD load_addr;
- DWORD end_addr;
+ LPVOID load_addr;
};
static struct so_list solib_start, *solib_end;
@@ -529,8 +540,6 @@ static int
safe_symbol_file_add_stub (void *argv)
{
#define p ((struct safe_symbol_file_add_args *) argv)
- struct so_list *so = &solib_start;
-
p->ret = symbol_file_add (p->name, p->from_tty, p->addrs, p->mainline, p->flags);
return !!p->ret;
#undef p
@@ -578,21 +587,16 @@ safe_symbol_file_add (char *name, int from_tty,
return p.ret;
}
-/* Remember the maximum DLL length for printing in info dll command. */
-static int max_dll_name_len;
-
-static void
-register_loaded_dll (const char *name, DWORD load_addr)
+static struct so_list *
+windows_make_so (const char *name, LPVOID load_addr)
{
struct so_list *so;
- char ppath[MAX_PATH + 1];
char buf[MAX_PATH + 1];
char cwd[MAX_PATH + 1];
char *p;
WIN32_FIND_DATA w32_fd;
HANDLE h = FindFirstFile(name, &w32_fd);
MEMORY_BASIC_INFORMATION m;
- size_t len;
if (h == INVALID_HANDLE_VALUE)
strcpy (buf, name);
@@ -616,25 +620,47 @@ register_loaded_dll (const char *name, DWORD load_addr)
GetSystemDirectory (buf, sizeof (buf));
strcat (buf, "\\ntdll.dll");
}
- cygwin_conv_to_posix_path (buf, ppath);
- so = (struct so_list *) xmalloc (sizeof (struct so_list) + strlen (ppath) + 8 + 1);
- memset (so, 0, sizeof (*so));
+ so = XZALLOC (struct so_list);
so->lm_info = (struct lm_info *) xmalloc (sizeof (struct lm_info));
so->lm_info->load_addr = load_addr;
- if (VirtualQueryEx (current_process_handle, (void *) load_addr, &m,
- sizeof (m)))
- so->lm_info->end_addr = (DWORD) m.AllocationBase + m.RegionSize;
- else
- so->lm_info->end_addr = load_addr + 0x2000; /* completely arbitrary */
+ strcpy (so->so_original_name, name);
+#ifndef __CYGWIN__
+ strcpy (so->so_name, buf);
+#else
+ cygwin_conv_to_posix_path (buf, so->so_name);
+ /* Record cygwin1.dll .text start/end. */
+ p = strchr (so->so_name, '\0') - (sizeof ("/cygwin1.dll") - 1);
+ if (p >= so->so_name && strcasecmp (p, "/cygwin1.dll") == 0)
+ {
+ bfd *abfd;
+ asection *text = NULL;
+ CORE_ADDR text_vma;
+
+ abfd = bfd_openr (so->so_name, "pei-i386");
+
+ if (!abfd)
+ return so;
+
+ if (bfd_check_format (abfd, bfd_object))
+ text = bfd_get_section_by_name (abfd, ".text");
- so->next = NULL;
- strcpy (so->so_name, ppath);
+ if (!text)
+ {
+ bfd_close (abfd);
+ return so;
+ }
- solib_end->next = so;
- solib_end = so;
- len = strlen (ppath);
- if (len > max_dll_name_len)
- max_dll_name_len = len;
+ /* The symbols in a dll are offset by 0x1000, which is the 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);
+ cygwin_load_end = cygwin_load_start + bfd_section_size (abfd, text);
+
+ bfd_close (abfd);
+ }
+#endif
+
+ return so;
}
static char *
@@ -645,7 +671,7 @@ get_image_name (HANDLE h, void *address, int unicode)
char *address_ptr;
int len = 0;
char b[2];
- DWORD done;
+ SIZE_T done;
/* Attempt to read the name of the dll that was detected.
This is documented to work only when actively debugging
@@ -686,52 +712,41 @@ handle_load_dll (void *dummy)
LOAD_DLL_DEBUG_INFO *event = ¤t_event.u.LoadDll;
char dll_buf[MAX_PATH + 1];
char *dll_name = NULL;
- char *p;
dll_buf[0] = dll_buf[sizeof (dll_buf) - 1] = '\0';
- if (!psapi_get_dll_name ((DWORD) (event->lpBaseOfDll), dll_buf))
+ 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);
+ dll_name = get_image_name (current_process_handle,
+ event->lpImageName, event->fUnicode);
if (!dll_name)
return 1;
- register_loaded_dll (dll_name, (DWORD) event->lpBaseOfDll + 0x1000);
+ solib_end->next = windows_make_so (dll_name, event->lpBaseOfDll);
+ solib_end = solib_end->next;
+
+ DEBUG_EVENTS (("gdb: Loading dll \"%s\" at %p.\n", solib_end->so_name,
+ solib_end->lm_info->load_addr));
return 1;
}
static void
-win32_free_so (struct so_list *so)
+windows_free_so (struct so_list *so)
{
- if (so->objfile)
- free_objfile (so->objfile);
if (so->lm_info)
xfree (so->lm_info);
-}
-
-static struct so_list *
-win32_current_sos (void)
-{
- return solib_start.next;
-}
-
-static void
-win32_relocate_section_addresses (struct so_list *so,
- struct section_table *sec)
-{
- /* FIXME */
- return;
+ xfree (so);
}
static int
handle_unload_dll (void *dummy)
{
- DWORD lpBaseOfDll = (DWORD) current_event.u.UnloadDll.lpBaseOfDll + 0x1000;
+ LPVOID lpBaseOfDll = current_event.u.UnloadDll.lpBaseOfDll;
struct so_list *so;
for (so = &solib_start; so->next != NULL; so = so->next)
@@ -741,23 +756,24 @@ handle_unload_dll (void *dummy)
so->next = sodel->next;
if (!so->next)
solib_end = so;
- free_so (sodel);
+ DEBUG_EVENTS (("gdb: Unloading dll \"%s\".\n", sodel->so_name));
+
+ windows_free_so (sodel);
+ solib_add (NULL, 0, NULL, auto_solib_add);
return 1;
}
- error (_("Error: dll starting at 0x%lx not found."), (DWORD) lpBaseOfDll);
+
+ error (_("Error: dll starting at %p not found."), lpBaseOfDll);
return 0;
}
/* Clear list of loaded DLLs. */
static void
-win32_clear_solib (void)
+windows_clear_solib (void)
{
- struct so_list *so, *so1 = solib_start.next;
-
solib_start.next = NULL;
solib_end = &solib_start;
- max_dll_name_len = sizeof ("DLL Name") - 1;
}
/* Load DLL symbol info. */
@@ -782,53 +798,60 @@ dll_symbol_command (char *args, int from_tty)
safe_symbol_file_add (args, from_tty, NULL, 0, OBJF_SHARED | OBJF_USERLOADED);
}
-/* List currently loaded DLLs. */
-static void
-info_dll_command (char *ignore, int from_tty)
-{
- struct so_list *so = &solib_start;
-
- if (!so->next)
- return;
-
- printf_filtered ("%*s Load Address\n", -max_dll_name_len, "DLL Name");
- while ((so = so->next) != NULL)
- printf_filtered ("%*s %08lx\n", -max_dll_name_len, so->so_name, so->lm_info->load_addr);
-
- return;
-}
-
/* 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. */
static int
handle_output_debug_string (struct target_waitstatus *ourstatus)
{
- char *s;
- int gotasig = FALSE;
+ char *s = NULL;
+ int retval = 0;
if (!target_read_string
- ((CORE_ADDR) current_event.u.DebugString.lpDebugStringData, &s, 1024, 0)
+ ((CORE_ADDR) (uintptr_t) current_event.u.DebugString.lpDebugStringData,
+ &s, 1024, 0)
|| !s || !*s)
- return gotasig;
-
- if (strncmp (s, CYGWIN_SIGNAL_STRING, sizeof (CYGWIN_SIGNAL_STRING) - 1) != 0)
+ /* nothing to do */;
+ else if (strncmp (s, _CYGWIN_SIGNAL_STRING, sizeof (_CYGWIN_SIGNAL_STRING) - 1) != 0)
{
+#ifdef __CYGWIN__
if (strncmp (s, "cYg", 3) != 0)
+#endif
warning (("%s"), s);
}
+#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. */
char *p;
- int sig = strtol (s + sizeof (CYGWIN_SIGNAL_STRING) - 1, &p, 0);
- gotasig = target_signal_from_host (sig);
+ int sig = strtol (s + sizeof (_CYGWIN_SIGNAL_STRING) - 1, &p, 0);
+ int gotasig = target_signal_from_host (sig);
ourstatus->value.sig = gotasig;
if (gotasig)
- ourstatus->kind = TARGET_WAITKIND_STOPPED;
+ {
+ LPCVOID x;
+ DWORD 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))
+ && ReadProcessMemory (current_process_handle, x,
+ &saved_context, __COPY_CONTEXT_SIZE, &n)
+ && n == __COPY_CONTEXT_SIZE)
+ have_saved_context = 1;
+ current_event.dwThreadId = retval;
+ }
}
+#endif
- xfree (s);
- return gotasig;
+ if (s)
+ xfree (s);
+ return retval;
}
static int
@@ -952,8 +975,8 @@ info_w32_command (char *args, int from_tty)
#define DEBUG_EXCEPTION_SIMPLE(x) if (debug_exceptions) \
- printf_unfiltered ("gdb: Target exception %s at 0x%08lx\n", x, \
- (DWORD) current_event.u.Exception.ExceptionRecord.ExceptionAddress)
+ printf_unfiltered ("gdb: Target exception %s at %p\n", x, \
+ current_event.u.Exception.ExceptionRecord.ExceptionAddress)
static int
handle_exception (struct target_waitstatus *ourstatus)
@@ -971,14 +994,22 @@ handle_exception (struct target_waitstatus *ourstatus)
case EXCEPTION_ACCESS_VIOLATION:
DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ACCESS_VIOLATION");
ourstatus->value.sig = TARGET_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;
- if (find_pc_partial_function ((CORE_ADDR) current_event.u.Exception
- .ExceptionRecord.ExceptionAddress,
- &fn, NULL, NULL)
- && strncmp (fn, "KERNEL32!IsBad", strlen ("KERNEL32!IsBad")) == 0)
+ 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))
return 0;
}
+#endif
break;
case STATUS_STACK_OVERFLOW:
DEBUG_EXCEPTION_SIMPLE ("STATUS_STACK_OVERFLOW");
@@ -1053,11 +1084,12 @@ handle_exception (struct target_waitstatus *ourstatus)
ourstatus->value.sig = TARGET_SIGNAL_ILL;
break;
default:
+ /* Treat unhandled first chance exceptions specially. */
if (current_event.u.Exception.dwFirstChance)
- return 0;
- printf_unfiltered ("gdb: unknown target exception 0x%08lx at 0x%08lx\n",
+ return -1;
+ printf_unfiltered ("gdb: unknown target exception 0x%08lx at %p\n",
current_event.u.Exception.ExceptionRecord.ExceptionCode,
- (DWORD) current_event.u.Exception.ExceptionRecord.ExceptionAddress);
+ current_event.u.Exception.ExceptionRecord.ExceptionAddress);
ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN;
break;
}
@@ -1069,7 +1101,7 @@ handle_exception (struct target_waitstatus *ourstatus)
/* Resume all artificially suspended threads if we are continuing
execution */
static BOOL
-win32_continue (DWORD continue_status, int id)
+windows_continue (DWORD continue_status, int id)
{
int i;
thread_info *th;
@@ -1079,33 +1111,34 @@ win32_continue (DWORD continue_status, int id)
current_event.dwProcessId, current_event.dwThreadId,
continue_status == DBG_CONTINUE ?
"DBG_CONTINUE" : "DBG_EXCEPTION_NOT_HANDLED"));
+
+ for (th = &thread_head; (th = th->next) != NULL;)
+ if ((id == -1 || id == (int) th->id)
+ && th->suspended)
+ {
+ if (debug_registers_changed)
+ {
+ th->context.ContextFlags |= CONTEXT_DEBUG_REGISTERS;
+ th->context.Dr0 = dr[0];
+ th->context.Dr1 = dr[1];
+ th->context.Dr2 = dr[2];
+ th->context.Dr3 = dr[3];
+ th->context.Dr6 = DR6_CLEAR_VALUE;
+ th->context.Dr7 = dr[7];
+ }
+ if (th->context.ContextFlags)
+ {
+ CHECK (SetThreadContext (th->h, &th->context));
+ th->context.ContextFlags = 0;
+ }
+ if (th->suspended > 0)
+ (void) ResumeThread (th->h);
+ th->suspended = 0;
+ }
+
res = ContinueDebugEvent (current_event.dwProcessId,
current_event.dwThreadId,
continue_status);
- continue_status = 0;
- if (res)
- for (th = &thread_head; (th = th->next) != NULL;)
- if (((id == -1) || (id == (int) th->id)) && th->suspend_count)
- {
-
- for (i = 0; i < th->suspend_count; i++)
- (void) ResumeThread (th->h);
- th->suspend_count = 0;
- if (debug_registers_changed)
- {
- /* Only change the value of the debug registers */
- th->context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
- th->context.Dr0 = dr[0];
- th->context.Dr1 = dr[1];
- th->context.Dr2 = dr[2];
- th->context.Dr3 = dr[3];
- /* th->context.Dr6 = dr[6];
- FIXME: should we set dr6 also ?? */
- th->context.Dr7 = dr[7];
- CHECK (SetThreadContext (th->h, &th->context));
- th->context.ContextFlags = 0;
- }
- }
debug_registers_changed = 0;
return res;
@@ -1118,17 +1151,119 @@ fake_create_process (void)
{
current_process_handle = OpenProcess (PROCESS_ALL_ACCESS, FALSE,
current_event.dwProcessId);
+ if (current_process_handle != NULL)
+ open_process_used = 1;
+ else
+ {
+ error (_("OpenProcess call failed, GetLastError = %lud\n"),
+ GetLastError ());
+ /* We can not debug anything in that case. */
+ }
main_thread_id = current_event.dwThreadId;
- current_thread = win32_add_thread (main_thread_id,
- current_event.u.CreateThread.hThread);
+ current_thread = windows_add_thread (ptid_build (current_event.dwProcessId, 0,
+ current_event.dwThreadId),
+ current_event.u.CreateThread.hThread);
return main_thread_id;
}
+static void
+windows_resume (struct target_ops *ops,
+ ptid_t ptid, int step, enum target_signal sig)
+{
+ thread_info *th;
+ DWORD continue_status = DBG_CONTINUE;
+
+ /* A specific PTID means `step only this thread id'. */
+ int resume_all = ptid_equal (ptid, minus_one_ptid);
+
+ /* If we're continuing all threads, it's the current inferior that
+ should be handled specially. */
+ if (resume_all)
+ ptid = inferior_ptid;
+
+ if (sig != TARGET_SIGNAL_0)
+ {
+ if (current_event.dwDebugEventCode != EXCEPTION_DEBUG_EVENT)
+ {
+ DEBUG_EXCEPT(("Cannot continue with signal %d here.\n",sig));
+ }
+ else if (sig == last_sig)
+ continue_status = DBG_EXCEPTION_NOT_HANDLED;
+ else
+#if 0
+/* This code does not seem to work, because
+ the kernel does probably not consider changes in the ExceptionRecord
+ structure when passing the exception to the inferior.
+ Note that this seems possible in the exception handler itself. */
+ {
+ int i;
+ for (i = 0; xlate[i].them != -1; i++)
+ if (xlate[i].us == sig)
+ {
+ current_event.u.Exception.ExceptionRecord.ExceptionCode =
+ xlate[i].them;
+ continue_status = DBG_EXCEPTION_NOT_HANDLED;
+ break;
+ }
+ if (continue_status == DBG_CONTINUE)
+ {
+ DEBUG_EXCEPT(("Cannot continue with signal %d.\n",sig));
+ }
+ }
+#endif
+ DEBUG_EXCEPT(("Can only continue with recieved signal %d.\n",
+ last_sig));
+ }
+
+ last_sig = TARGET_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 */
+ th = thread_rec (ptid_get_tid (inferior_ptid), FALSE);
+ if (th)
+ {
+ if (step)
+ {
+ /* Single step by setting t bit */
+ windows_fetch_inferior_registers (ops,
+ get_current_regcache (),
+ gdbarch_ps_regnum (current_gdbarch));
+ th->context.EFlags |= FLAG_TRACE_BIT;
+ }
+
+ if (th->context.ContextFlags)
+ {
+ if (debug_registers_changed)
+ {
+ th->context.Dr0 = dr[0];
+ th->context.Dr1 = dr[1];
+ th->context.Dr2 = dr[2];
+ th->context.Dr3 = dr[3];
+ th->context.Dr6 = DR6_CLEAR_VALUE;
+ th->context.Dr7 = dr[7];
+ }
+ CHECK (SetThreadContext (th->h, &th->context));
+ th->context.ContextFlags = 0;
+ }
+ }
+
+ /* Allow continuing with the same signal that interrupted us.
+ Otherwise complain. */
+
+ if (resume_all)
+ windows_continue (continue_status, -1);
+ else
+ windows_continue (continue_status, ptid_get_tid (ptid));
+}
+
/* Get the next event from the child. Return 1 if the event requires
handling by WFI (or whatever).
*/
static int
-get_win32_debug_event (int pid, struct target_waitstatus *ourstatus)
+get_windows_debug_event (struct target_ops *ops,
+ int pid, struct target_waitstatus *ourstatus)
{
BOOL debug_event;
DWORD continue_status, event_code;
@@ -1147,6 +1282,7 @@ get_win32_debug_event (int pid, struct target_waitstatus *ourstatus)
event_code = current_event.dwDebugEventCode;
ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
th = NULL;
+ have_saved_context = 0;
switch (event_code)
{
@@ -1157,24 +1293,24 @@ get_win32_debug_event (int pid, struct target_waitstatus *ourstatus)
"CREATE_THREAD_DEBUG_EVENT"));
if (saw_create != 1)
{
- if (!saw_create && attach_flag)
+ struct inferior *inf;
+ inf = find_inferior_pid (current_event.dwProcessId);
+ if (!saw_create && inf->attach_flag)
{
/* Kludge around a Windows bug where first event is a create
thread event. Caused when attached process does not have
a main thread. */
- retval = ourstatus->value.related_pid = fake_create_process ();
- saw_create++;
+ retval = fake_create_process ();
+ if (retval)
+ saw_create++;
}
break;
}
/* Record the existence of this thread */
- th = win32_add_thread (current_event.dwThreadId,
- current_event.u.CreateThread.hThread);
- if (info_verbose)
- printf_unfiltered ("[New %s]\n",
- target_pid_to_str (
- pid_to_ptid (current_event.dwThreadId)));
retval = 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:
@@ -1184,7 +1320,8 @@ get_win32_debug_event (int pid, struct target_waitstatus *ourstatus)
"EXIT_THREAD_DEBUG_EVENT"));
if (current_event.dwThreadId != main_thread_id)
{
- win32_delete_thread (current_event.dwThreadId);
+ windows_delete_thread (ptid_build (current_event.dwProcessId, 0,
+ current_event.dwThreadId));
th = &dummy_thread_info;
}
break;
@@ -1196,19 +1333,18 @@ get_win32_debug_event (int pid, struct target_waitstatus *ourstatus)
"CREATE_PROCESS_DEBUG_EVENT"));
CloseHandle (current_event.u.CreateProcessInfo.hFile);
if (++saw_create != 1)
- {
- CloseHandle (current_event.u.CreateProcessInfo.hProcess);
- break;
- }
+ break;
current_process_handle = current_event.u.CreateProcessInfo.hProcess;
if (main_thread_id)
- win32_delete_thread (main_thread_id);
+ windows_delete_thread (ptid_build (current_event.dwProcessId, 0,
+ main_thread_id));
main_thread_id = current_event.dwThreadId;
/* Add the main thread */
- th = win32_add_thread (main_thread_id,
+ th = windows_add_thread (ptid_build (current_event.dwProcessId, 0,
+ current_event.dwThreadId),
current_event.u.CreateProcessInfo.hThread);
- retval = ourstatus->value.related_pid = current_event.dwThreadId;
+ retval = current_event.dwThreadId;
break;
case EXIT_PROCESS_DEBUG_EVENT:
@@ -1220,7 +1356,6 @@ get_win32_debug_event (int pid, struct target_waitstatus *ourstatus)
break;
ourstatus->kind = TARGET_WAITKIND_EXITED;
ourstatus->value.integer = current_event.u.ExitProcess.dwExitCode;
- CloseHandle (current_process_handle);
retval = main_thread_id;
break;
@@ -1233,11 +1368,9 @@ get_win32_debug_event (int pid, struct target_waitstatus *ourstatus)
if (saw_create != 1)
break;
catch_errors (handle_load_dll, NULL, (char *) "", RETURN_MASK_ALL);
- registers_changed (); /* mark all regs invalid */
ourstatus->kind = TARGET_WAITKIND_LOADED;
ourstatus->value.integer = 0;
retval = main_thread_id;
- re_enable_breakpoints_in_shlibs ();
break;
case UNLOAD_DLL_DEBUG_EVENT:
@@ -1248,9 +1381,9 @@ get_win32_debug_event (int pid, struct target_waitstatus *ourstatus)
if (saw_create != 1)
break;
catch_errors (handle_unload_dll, NULL, (char *) "", RETURN_MASK_ALL);
- registers_changed (); /* mark all regs invalid */
- /* ourstatus->kind = TARGET_WAITKIND_UNLOADED;
- does not exist yet. */
+ ourstatus->kind = TARGET_WAITKIND_LOADED;
+ ourstatus->value.integer = 0;
+ retval = main_thread_id;
break;
case EXCEPTION_DEBUG_EVENT:
@@ -1260,10 +1393,19 @@ get_win32_debug_event (int pid, struct target_waitstatus *ourstatus)
"EXCEPTION_DEBUG_EVENT"));
if (saw_create != 1)
break;
- if (handle_exception (ourstatus))
- retval = current_event.dwThreadId;
- else
- continue_status = DBG_EXCEPTION_NOT_HANDLED;
+ switch (handle_exception (ourstatus))
+ {
+ case 0:
+ continue_status = DBG_EXCEPTION_NOT_HANDLED;
+ break;
+ case 1:
+ retval = current_event.dwThreadId;
+ break;
+ case -1:
+ last_sig = 1;
+ continue_status = -1;
+ break;
+ }
break;
case OUTPUT_DEBUG_STRING_EVENT: /* message from the kernel */
@@ -1273,8 +1415,7 @@ get_win32_debug_event (int pid, struct target_waitstatus *ourstatus)
"OUTPUT_DEBUG_STRING_EVENT"));
if (saw_create != 1)
break;
- if (handle_output_debug_string (ourstatus))
- retval = main_thread_id;
+ retval = handle_output_debug_string (ourstatus);
break;
default:
@@ -1289,10 +1430,16 @@ get_win32_debug_event (int pid, struct target_waitstatus *ourstatus)
}
if (!retval || saw_create != 1)
- CHECK (win32_continue (continue_status, -1));
+ {
+ if (continue_status == -1)
+ windows_resume (ops, minus_one_ptid, 0, 1);
+ else
+ CHECK (windows_continue (continue_status, -1));
+ }
else
{
- inferior_ptid = pid_to_ptid (retval);
+ inferior_ptid = ptid_build (current_event.dwProcessId, 0,
+ retval);
current_thread = th ?: thread_rec (current_event.dwThreadId, TRUE);
}
@@ -1300,11 +1447,14 @@ out:
return retval;
}
-/* Wait for interesting events to occur in the target process. */
+/* Wait for interesting events to occur in the target process. */
static ptid_t
-win32_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
+windows_wait (struct target_ops *ops,
+ ptid_t ptid, struct target_waitstatus *ourstatus)
{
- int pid = PIDGET (ptid);
+ int pid = -1;
+
+ target_terminal_ours ();
/* We loop when we get a non-standard exception rather than return
with a SPURIOUS because resume can try and step or modify things,
@@ -1314,9 +1464,27 @@ win32_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
while (1)
{
- int retval = get_win32_debug_event (pid, ourstatus);
+ int retval;
+
+ /* Ignore CTRL+C signals while waiting for a debug event.
+ FIXME: brobecker/2008-05-20: When the user presses CTRL+C while
+ the inferior is running, both the inferior and GDB receive the
+ associated signal. If the inferior receives the signal first
+ and the delay until GDB receives that signal is sufficiently long,
+ GDB can sometimes receive the SIGINT after we have unblocked
+ the CTRL+C handler. This would lead to the debugger to stop
+ prematurely while handling the new-thread event that comes
+ with the handling of the SIGINT inside the inferior, and then
+ stop again immediately when the user tries to resume the execution
+ in the inferior. This is a classic race, and it would be nice
+ to find a better solution to that problem. But in the meantime,
+ the current approach already greatly mitigate this issue. */
+ SetConsoleCtrlHandler (NULL, TRUE);
+ retval = get_windows_debug_event (ops, pid, ourstatus);
+ SetConsoleCtrlHandler (NULL, FALSE);
+
if (retval)
- return pid_to_ptid (retval);
+ return ptid_build (current_event.dwProcessId, 0, retval);
else
{
int detach = 0;
@@ -1325,44 +1493,63 @@ win32_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
detach = deprecated_ui_loop_hook (0);
if (detach)
- win32_kill_inferior ();
+ windows_kill_inferior ();
}
}
}
static void
-do_initial_win32_stuff (DWORD pid)
+do_initial_windows_stuff (struct target_ops *ops, DWORD pid, int attaching)
{
extern int stop_after_trap;
int i;
+ struct inferior *inf;
+ struct thread_info *tp;
last_sig = TARGET_SIGNAL_0;
event_count = 0;
exception_count = 0;
+ open_process_used = 0;
debug_registers_changed = 0;
debug_registers_used = 0;
for (i = 0; i < sizeof (dr) / sizeof (dr[0]); i++)
dr[i] = 0;
+#ifdef __CYGWIN__
+ cygwin_load_start = cygwin_load_end = 0;
+#endif
current_event.dwProcessId = pid;
memset (¤t_event, 0, sizeof (current_event));
- push_target (&win32_ops);
- disable_breakpoints_in_shlibs (1);
- win32_clear_solib ();
+ push_target (ops);
+ disable_breakpoints_in_shlibs ();
+ windows_clear_solib ();
clear_proceed_status ();
init_wait_for_inferior ();
- target_terminal_init ();
+ inf = add_inferior (pid);
+ inf->attach_flag = attaching;
+
+ /* Make the new process the current inferior, so terminal handling
+ can rely on it. When attaching, we don't know about any thread
+ id here, but that's OK --- nothing should be referencing the
+ 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_inferior ();
+ inf->stop_soon = STOP_QUIETLY;
while (1)
{
stop_after_trap = 1;
- wait_for_inferior ();
- if (stop_signal != TARGET_SIGNAL_TRAP)
- resume (0, stop_signal);
+ wait_for_inferior (0);
+ tp = inferior_thread ();
+ if (tp->stop_signal != TARGET_SIGNAL_TRAP)
+ resume (0, tp->stop_signal);
else
break;
}
+
+ inf->stop_soon = NO_STOP_QUIETLY;
stop_after_trap = 0;
return;
}
@@ -1372,8 +1559,8 @@ do_initial_win32_stuff (DWORD pid)
If loading these functions succeeds use them to actually detach from
the inferior process, otherwise behave as usual, pretending that
detach has worked. */
-static BOOL WINAPI (*DebugSetProcessKillOnExit)(BOOL);
-static BOOL WINAPI (*DebugActiveProcessStop)(DWORD);
+static BOOL WINAPI (*kernel32_DebugSetProcessKillOnExit)(BOOL);
+static BOOL WINAPI (*kernel32_DebugActiveProcessStop)(DWORD);
static int
has_detach_ability (void)
@@ -1384,13 +1571,14 @@ has_detach_ability (void)
kernel32 = LoadLibrary ("kernel32.dll");
if (kernel32)
{
- if (!DebugSetProcessKillOnExit)
- DebugSetProcessKillOnExit = GetProcAddress (kernel32,
- "DebugSetProcessKillOnExit");
- if (!DebugActiveProcessStop)
- DebugActiveProcessStop = GetProcAddress (kernel32,
- "DebugActiveProcessStop");
- if (DebugSetProcessKillOnExit && DebugActiveProcessStop)
+ if (!kernel32_DebugSetProcessKillOnExit)
+ kernel32_DebugSetProcessKillOnExit =
+ (void *) GetProcAddress (kernel32, "DebugSetProcessKillOnExit");
+ if (!kernel32_DebugActiveProcessStop)
+ kernel32_DebugActiveProcessStop =
+ (void *) GetProcAddress (kernel32, "DebugActiveProcessStop");
+ if (kernel32_DebugSetProcessKillOnExit
+ && kernel32_DebugActiveProcessStop)
return 1;
}
return 0;
@@ -1425,13 +1613,14 @@ set_process_privilege (const char *privilege, BOOL enable)
if (!(advapi32 = LoadLibrary ("advapi32.dll")))
goto out;
if (!OpenProcessToken)
- OpenProcessToken = GetProcAddress (advapi32, "OpenProcessToken");
+ OpenProcessToken =
+ (void *) GetProcAddress (advapi32, "OpenProcessToken");
if (!LookupPrivilegeValue)
- LookupPrivilegeValue = GetProcAddress (advapi32,
- "LookupPrivilegeValueA");
+ LookupPrivilegeValue =
+ (void *) GetProcAddress (advapi32, "LookupPrivilegeValueA");
if (!AdjustTokenPrivileges)
- AdjustTokenPrivileges = GetProcAddress (advapi32,
- "AdjustTokenPrivileges");
+ AdjustTokenPrivileges =
+ (void *) GetProcAddress (advapi32, "AdjustTokenPrivileges");
if (!OpenProcessToken || !LookupPrivilegeValue || !AdjustTokenPrivileges)
{
advapi32 = NULL;
@@ -1457,7 +1646,7 @@ 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
- win32_attach(). */
+ windows_attach(). */
/* AdjustTokenPrivileges returns TRUE even if the privilege could not
be enabled. GetLastError () returns an correct error code, though. */
if (enable && GetLastError () == ERROR_NOT_ALL_ASSIGNED)
@@ -1475,7 +1664,7 @@ out:
/* Attach to process PID, then initialize for debugging it. */
static void
-win32_attach (char *args, int from_tty)
+windows_attach (struct target_ops *ops, char *args, int from_tty)
{
BOOL ok;
DWORD pid;
@@ -1491,10 +1680,11 @@ win32_attach (char *args, int from_tty)
pid = strtoul (args, 0, 0); /* Windows pid */
- win32_init_thread_list ();
+ windows_init_thread_list ();
ok = DebugActiveProcess (pid);
saw_create = 0;
+#ifdef __CYGWIN__
if (!ok)
{
/* Try fall back to Cygwin pid */
@@ -1502,15 +1692,14 @@ win32_attach (char *args, int from_tty)
if (pid > 0)
ok = DebugActiveProcess (pid);
+ }
+#endif
- if (!ok)
- error (_("Can't attach to process."));
- }
+ if (!ok)
+ error (_("Can't attach to process."));
if (has_detach_ability ())
- DebugSetProcessKillOnExit (FALSE);
-
- attach_flag = 1;
+ kernel32_DebugSetProcessKillOnExit (FALSE);
if (from_tty)
{
@@ -1526,26 +1715,27 @@ win32_attach (char *args, int from_tty)
gdb_flush (gdb_stdout);
}
- do_initial_win32_stuff (pid);
+ do_initial_windows_stuff (ops, pid, 1);
target_terminal_ours ();
}
static void
-win32_detach (char *args, int from_tty)
+windows_detach (struct target_ops *ops, char *args, int from_tty)
{
int detached = 1;
if (has_detach_ability ())
{
- delete_command (NULL, 0);
- win32_continue (DBG_CONTINUE, -1);
- if (!DebugActiveProcessStop (current_event.dwProcessId))
+ ptid_t ptid = {-1};
+ windows_resume (ops, ptid, 0, TARGET_SIGNAL_0);
+
+ if (!kernel32_DebugActiveProcessStop (current_event.dwProcessId))
{
error (_("Can't detach process %lu (error %lu)"),
current_event.dwProcessId, GetLastError ());
detached = 0;
}
- DebugSetProcessKillOnExit (FALSE);
+ kernel32_DebugSetProcessKillOnExit (FALSE);
}
if (detached && from_tty)
{
@@ -1556,68 +1746,66 @@ win32_detach (char *args, int from_tty)
current_event.dwProcessId);
gdb_flush (gdb_stdout);
}
+
inferior_ptid = null_ptid;
- unpush_target (&win32_ops);
+ detach_inferior (current_event.dwProcessId);
+
+ unpush_target (ops);
}
static char *
-win32_pid_to_exec_file (int pid)
+windows_pid_to_exec_file (int pid)
{
- /* Try to find the process path using the Cygwin internal process list
- pid isn't a valid pid, unfortunately. Use current_event.dwProcessId
- instead. */
- /* TODO: Also find native Windows processes using CW_GETPINFO_FULL. */
-
static char path[MAX_PATH + 1];
- char *path_ptr = NULL;
- int cpid;
- struct external_pinfo *pinfo;
-
- cygwin_internal (CW_LOCK_PINFO, 1000);
- for (cpid = 0;
- (pinfo = (struct external_pinfo *)
- cygwin_internal (CW_GETPINFO, cpid | CW_NEXTPID));
- cpid = pinfo->pid)
+
+#ifdef __CYGWIN__
+ /* Try to find exe name as symlink target of /proc//exe */
+ int nchars;
+ char procexe[sizeof ("/proc/4294967295/exe")];
+ sprintf (procexe, "/proc/%u/exe", pid);
+ nchars = readlink (procexe, path, sizeof(path));
+ if (nchars > 0 && nchars < sizeof (path))
{
- if (pinfo->dwProcessId == current_event.dwProcessId) /* Got it */
- {
- cygwin_conv_to_full_posix_path (pinfo->progname, path);
- path_ptr = path;
- break;
- }
+ path[nchars] = '\0'; /* Got it */
+ return path;
}
- cygwin_internal (CW_UNLOCK_PINFO);
- return path_ptr;
+#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. */
+ if (!get_module_name (0, path))
+ path[0] = '\0';
+
+ return path;
}
/* Print status information about what we're accessing. */
static void
-win32_files_info (struct target_ops *ignore)
+windows_files_info (struct target_ops *ignore)
{
+ struct inferior *inf = current_inferior ();
+
printf_unfiltered ("\tUsing the running image of %s %s.\n",
- attach_flag ? "attached" : "child", target_pid_to_str (inferior_ptid));
+ inf->attach_flag ? "attached" : "child",
+ target_pid_to_str (inferior_ptid));
}
static void
-win32_open (char *arg, int from_tty)
+windows_open (char *arg, int from_tty)
{
error (_("Use the \"run\" command to start a Unix child process."));
}
-/* Start an inferior win32 child process and sets inferior_ptid to its pid.
+/* 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.
ENV is the environment vector to pass. Errors reported with error(). */
static void
-win32_create_inferior (char *exec_file, char *allargs, char **env,
- int from_tty)
+windows_create_inferior (struct target_ops *ops, char *exec_file,
+ char *allargs, char **in_env, int from_tty)
{
- char *winenv;
- char *temp;
- int envlen;
- int i;
STARTUPINFO si;
PROCESS_INFORMATION pi;
BOOL ret;
@@ -1637,6 +1825,7 @@ win32_create_inferior (char *exec_file, char *allargs, char **env,
memset (&si, 0, sizeof (si));
si.cb = sizeof (si);
+#ifdef __CYGWIN__
if (!useshell)
{
flags = DEBUG_ONLY_THIS_PROCESS;
@@ -1657,6 +1846,10 @@ win32_create_inferior (char *exec_file, char *allargs, char **env,
toexec = shell;
flags = DEBUG_PROCESS;
}
+#else
+ toexec = exec_file;
+ flags = DEBUG_ONLY_THIS_PROCESS;
+#endif
if (new_group)
flags |= CREATE_NEW_PROCESS_GROUP;
@@ -1664,85 +1857,14 @@ win32_create_inferior (char *exec_file, char *allargs, char **env,
if (new_console)
flags |= CREATE_NEW_CONSOLE;
- attach_flag = 0;
-
args = alloca (strlen (toexec) + strlen (allargs) + 2);
strcpy (args, toexec);
strcat (args, " ");
strcat (args, allargs);
+#ifdef __CYGWIN__
/* Prepare the environment vars for CreateProcess. */
- {
- /* This code used to assume all env vars were file names and would
- translate them all to win32 style. That obviously doesn't work in the
- general case. The current rule is that we only translate PATH.
- We need to handle PATH because we're about to call CreateProcess and
- it uses PATH to find DLL's. Fortunately PATH has a well-defined value
- in both posix and win32 environments. cygwin.dll will change it back
- to posix style if necessary. */
-
- static const char *conv_path_names[] =
- {
- "PATH=",
- 0
- };
-
- /* 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; env[i] && *env[i]; i++)
- {
- int j, len;
-
- for (j = 0; conv_path_names[j]; j++)
- {
- len = strlen (conv_path_names[j]);
- if (strncmp (conv_path_names[j], env[i], len) == 0)
- {
- if (cygwin_posix_path_list_p (env[i] + len))
- envlen += len
- + cygwin_posix_to_win32_path_list_buf_size (env[i] + len);
- else
- envlen += strlen (env[i]) + 1;
- break;
- }
- }
- if (conv_path_names[j] == NULL)
- envlen += strlen (env[i]) + 1;
- }
-
- winenv = alloca (envlen + 1);
-
- /* Copy env strings into new buffer. */
- for (temp = winenv, i = 0; env[i] && *env[i]; i++)
- {
- int j, len;
-
- for (j = 0; conv_path_names[j]; j++)
- {
- len = strlen (conv_path_names[j]);
- if (strncmp (conv_path_names[j], env[i], len) == 0)
- {
- if (cygwin_posix_path_list_p (env[i] + len))
- {
- memcpy (temp, env[i], len);
- cygwin_posix_to_win32_path_list (env[i] + len, temp + len);
- }
- else
- strcpy (temp, env[i]);
- break;
- }
- }
- if (conv_path_names[j] == NULL)
- strcpy (temp, env[i]);
-
- temp += strlen (temp) + 1;
- }
-
- /* Final nil string to terminate new env. */
- *temp = 0;
- }
+ cygwin_internal (CW_SYNC_WINENV);
if (!inferior_io_terminal)
tty = ostdin = ostdout = ostderr = -1;
@@ -1764,18 +1886,21 @@ win32_create_inferior (char *exec_file, char *allargs, char **env,
dup2 (tty, 2);
}
}
+#endif
- win32_init_thread_list ();
+ windows_init_thread_list ();
ret = CreateProcess (0,
args, /* command line */
NULL, /* Security */
NULL, /* thread */
TRUE, /* inherit handles */
flags, /* start flags */
- winenv,
+ NULL, /* environment */
NULL, /* current directory */
&si,
&pi);
+
+#ifdef __CYGWIN__
if (tty >= 0)
{
close (tty);
@@ -1786,6 +1911,7 @@ win32_create_inferior (char *exec_file, char *allargs, char **env,
close (ostdout);
close (ostderr);
}
+#endif
if (!ret)
error (_("Error creating process %s, (error %d)."),
@@ -1799,18 +1925,22 @@ win32_create_inferior (char *exec_file, char *allargs, char **env,
else
saw_create = 0;
- do_initial_win32_stuff (pi.dwProcessId);
+ do_initial_windows_stuff (ops, pi.dwProcessId, 0);
- /* win32_continue (DBG_CONTINUE, -1); */
- proceed ((CORE_ADDR) - 1, TARGET_SIGNAL_0, 0);
+ /* windows_continue (DBG_CONTINUE, -1); */
}
static void
-win32_mourn_inferior (void)
+windows_mourn_inferior (struct target_ops *ops)
{
- (void) win32_continue (DBG_CONTINUE, -1);
+ (void) windows_continue (DBG_CONTINUE, -1);
i386_cleanup_dregs();
- unpush_target (&win32_ops);
+ if (open_process_used)
+ {
+ CHECK (CloseHandle (current_process_handle));
+ open_process_used = 0;
+ }
+ unpush_target (ops);
generic_mourn_inferior ();
}
@@ -1818,7 +1948,7 @@ win32_mourn_inferior (void)
^C on the controlling terminal. */
static void
-win32_stop (void)
+windows_stop (ptid_t ptid)
{
DEBUG_EVENTS (("gdb: GenerateConsoleCtrlEvent (CTRLC_EVENT, 0)\n"));
CHECK (GenerateConsoleCtrlEvent (CTRL_C_EVENT, current_event.dwProcessId));
@@ -1826,25 +1956,28 @@ win32_stop (void)
}
static int
-win32_xfer_memory (CORE_ADDR memaddr, gdb_byte *our, int len,
+windows_xfer_memory (CORE_ADDR memaddr, gdb_byte *our, int len,
int write, struct mem_attrib *mem,
struct target_ops *target)
{
- DWORD done = 0;
+ SIZE_T done = 0;
if (write)
{
DEBUG_MEM (("gdb: write target memory, %d bytes at 0x%08lx\n",
- len, (DWORD) memaddr));
- if (!WriteProcessMemory (current_process_handle, (LPVOID) memaddr, our,
+ len, (DWORD) (uintptr_t) memaddr));
+ if (!WriteProcessMemory (current_process_handle,
+ (LPVOID) (uintptr_t) memaddr, our,
len, &done))
done = 0;
- FlushInstructionCache (current_process_handle, (LPCVOID) memaddr, len);
+ FlushInstructionCache (current_process_handle,
+ (LPCVOID) (uintptr_t) memaddr, len);
}
else
{
DEBUG_MEM (("gdb: read target memory, %d bytes at 0x%08lx\n",
- len, (DWORD) memaddr));
- if (!ReadProcessMemory (current_process_handle, (LPCVOID) memaddr, our,
+ len, (DWORD) (uintptr_t) memaddr));
+ if (!ReadProcessMemory (current_process_handle,
+ (LPCVOID) (uintptr_t) memaddr, our,
len, &done))
done = 0;
}
@@ -1852,13 +1985,13 @@ win32_xfer_memory (CORE_ADDR memaddr, gdb_byte *our, int len,
}
static void
-win32_kill_inferior (void)
+windows_kill_inferior (void)
{
CHECK (TerminateProcess (current_process_handle, 0));
for (;;)
{
- if (!win32_continue (DBG_CONTINUE, -1))
+ if (!windows_continue (DBG_CONTINUE, -1))
break;
if (!WaitForDebugEvent (¤t_event, INFINITE))
break;
@@ -1866,188 +1999,164 @@ win32_kill_inferior (void)
break;
}
- CHECK (CloseHandle (current_process_handle));
-
- /* this may fail in an attached process so don't check. */
- if (current_thread && current_thread->h)
- (void) CloseHandle (current_thread->h);
- target_mourn_inferior (); /* or just win32_mourn_inferior? */
+ target_mourn_inferior (); /* or just windows_mourn_inferior? */
}
static void
-win32_resume (ptid_t ptid, int step, enum target_signal sig)
-{
- thread_info *th;
- DWORD continue_status = DBG_CONTINUE;
-
- int pid = PIDGET (ptid);
-
- if (sig != TARGET_SIGNAL_0)
- {
- if (current_event.dwDebugEventCode != EXCEPTION_DEBUG_EVENT)
- {
- DEBUG_EXCEPT(("Cannot continue with signal %d here.\n",sig));
- }
- else if (sig == last_sig)
- continue_status = DBG_EXCEPTION_NOT_HANDLED;
- else
-#if 0
-/* This code does not seem to work, because
- the kernel does probably not consider changes in the ExceptionRecord
- structure when passing the exception to the inferior.
- Note that this seems possible in the exception handler itself. */
- {
- int i;
- for (i = 0; xlate[i].them != -1; i++)
- if (xlate[i].us == sig)
- {
- current_event.u.Exception.ExceptionRecord.ExceptionCode =
- xlate[i].them;
- continue_status = DBG_EXCEPTION_NOT_HANDLED;
- break;
- }
- if (continue_status == DBG_CONTINUE)
- {
- DEBUG_EXCEPT(("Cannot continue with signal %d.\n",sig));
- }
- }
-#endif
- DEBUG_EXCEPT(("Can only continue with recieved signal %d.\n",
- last_sig));
- }
-
- last_sig = TARGET_SIGNAL_0;
-
- DEBUG_EXEC (("gdb: win32_resume (pid=%d, step=%d, sig=%d);\n",
- pid, step, sig));
-
- /* Get context for currently selected thread */
- th = thread_rec (current_event.dwThreadId, FALSE);
- if (th)
- {
- if (step)
- {
- /* Single step by setting t bit */
- win32_fetch_inferior_registers (PS_REGNUM);
- th->context.EFlags |= FLAG_TRACE_BIT;
- }
-
- if (th->context.ContextFlags)
- {
- if (debug_registers_changed)
- {
- th->context.Dr0 = dr[0];
- th->context.Dr1 = dr[1];
- th->context.Dr2 = dr[2];
- th->context.Dr3 = dr[3];
- /* th->context.Dr6 = dr[6];
- FIXME: should we set dr6 also ?? */
- th->context.Dr7 = dr[7];
- }
- CHECK (SetThreadContext (th->h, &th->context));
- th->context.ContextFlags = 0;
- }
- }
-
- /* Allow continuing with the same signal that interrupted us.
- Otherwise complain. */
-
- win32_continue (continue_status, pid);
-}
-
-static void
-win32_prepare_to_store (void)
+windows_prepare_to_store (struct regcache *regcache)
{
/* Do nothing, since we can store individual regs */
}
static int
-win32_can_run (void)
+windows_can_run (void)
{
return 1;
}
static void
-win32_close (int x)
+windows_close (int x)
{
- DEBUG_EVENTS (("gdb: win32_close, inferior_ptid=%d\n",
+ DEBUG_EVENTS (("gdb: windows_close, inferior_ptid=%d\n",
PIDGET (inferior_ptid)));
}
/* Convert pid to printable format. */
static char *
-cygwin_pid_to_str (ptid_t ptid)
+windows_pid_to_str (struct target_ops *ops, ptid_t ptid)
{
static char buf[80];
- int pid = PIDGET (ptid);
- if ((DWORD) pid == current_event.dwProcessId)
- sprintf (buf, "process %d", pid);
- else
- sprintf (buf, "thread %ld.0x%x", current_event.dwProcessId, pid);
- return buf;
+ if (ptid_get_tid (ptid) != 0)
+ {
+ snprintf (buf, sizeof (buf), "Thread %d.0x%lx",
+ ptid_get_pid (ptid), ptid_get_tid (ptid));
+ return buf;
+ }
+
+ return normal_pid_to_str (ptid);
+}
+
+static LONGEST
+windows_xfer_shared_libraries (struct target_ops *ops,
+ enum target_object object, const char *annex,
+ gdb_byte *readbuf, const gdb_byte *writebuf,
+ ULONGEST offset, LONGEST len)
+{
+ struct obstack obstack;
+ const char *buf;
+ LONGEST len_avail;
+ struct so_list *so;
+
+ if (writebuf)
+ return -1;
+
+ obstack_init (&obstack);
+ obstack_grow_str (&obstack, "\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,
+ &obstack);
+ obstack_grow_str0 (&obstack, "\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);
+
+ 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)
+{
+ 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;
+
+ case TARGET_OBJECT_LIBRARIES:
+ return windows_xfer_shared_libraries (ops, object, annex, readbuf,
+ writebuf, offset, len);
+
+ default:
+ if (ops->beneath != NULL)
+ return ops->beneath->to_xfer_partial (ops->beneath, object, annex,
+ readbuf, writebuf, offset, len);
+ return -1;
+ }
+}
+
+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 = 1;
+ windows_ops.to_has_memory = 1;
+ windows_ops.to_has_stack = 1;
+ windows_ops.to_has_registers = 1;
+ windows_ops.to_has_execution = 1;
+ windows_ops.to_pid_to_exec_file = windows_pid_to_exec_file;
+ i386_use_watchpoints (&windows_ops);
+
+ windows_ops.to_magic = OPS_MAGIC;
}
static void
-init_win32_ops (void)
+set_windows_aliases (char *argv0)
{
- win32_ops.to_shortname = "child";
- win32_ops.to_longname = "Win32 child process";
- win32_ops.to_doc = "Win32 child process (started by the \"run\" command).";
- win32_ops.to_open = win32_open;
- win32_ops.to_close = win32_close;
- win32_ops.to_attach = win32_attach;
- win32_ops.to_detach = win32_detach;
- win32_ops.to_resume = win32_resume;
- win32_ops.to_wait = win32_wait;
- win32_ops.to_fetch_registers = win32_fetch_inferior_registers;
- win32_ops.to_store_registers = win32_store_inferior_registers;
- win32_ops.to_prepare_to_store = win32_prepare_to_store;
- win32_ops.deprecated_xfer_memory = win32_xfer_memory;
- win32_ops.to_files_info = win32_files_info;
- win32_ops.to_insert_breakpoint = memory_insert_breakpoint;
- win32_ops.to_remove_breakpoint = memory_remove_breakpoint;
- win32_ops.to_terminal_init = terminal_init_inferior;
- win32_ops.to_terminal_inferior = terminal_inferior;
- win32_ops.to_terminal_ours_for_output = terminal_ours_for_output;
- win32_ops.to_terminal_ours = terminal_ours;
- win32_ops.to_terminal_save_ours = terminal_save_ours;
- win32_ops.to_terminal_info = child_terminal_info;
- win32_ops.to_kill = win32_kill_inferior;
- win32_ops.to_create_inferior = win32_create_inferior;
- win32_ops.to_mourn_inferior = win32_mourn_inferior;
- win32_ops.to_can_run = win32_can_run;
- win32_ops.to_thread_alive = win32_win32_thread_alive;
- win32_ops.to_pid_to_str = cygwin_pid_to_str;
- win32_ops.to_stop = win32_stop;
- win32_ops.to_stratum = process_stratum;
- win32_ops.to_has_all_memory = 1;
- win32_ops.to_has_memory = 1;
- win32_ops.to_has_stack = 1;
- win32_ops.to_has_registers = 1;
- win32_ops.to_has_execution = 1;
- win32_ops.to_magic = OPS_MAGIC;
- win32_ops.to_pid_to_exec_file = win32_pid_to_exec_file;
-
- win32_so_ops.relocate_section_addresses = win32_relocate_section_addresses;
- win32_so_ops.free_so = win32_free_so;
- win32_so_ops.clear_solib = win32_clear_solib;
- win32_so_ops.solib_create_inferior_hook = NULL;
- win32_so_ops.special_symbol_handling = NULL;
- win32_so_ops.current_sos = win32_current_sos;
- win32_so_ops.open_symbol_file_object = NULL;
- win32_so_ops.in_dynsym_resolve_code = NULL;
-
- /* FIXME: Don't do this here. *_gdbarch_init() should set so_ops. */
- current_target_so_ops = &win32_so_ops;
+ add_info_alias ("dll", "sharedlibrary", 1);
}
void
-_initialize_win32_nat (void)
+_initialize_windows_nat (void)
{
struct cmd_list_element *c;
- init_win32_ops ();
+ init_windows_ops ();
c = add_com ("dll-symbols", class_files, dll_symbol_command,
_("Load dll library symbols from FILE."));
@@ -2055,6 +2164,7 @@ _initialize_win32_nat (void)
add_com_alias ("sharedlibrary", "dll-symbols", class_alias, 1);
+#ifdef __CYGWIN__
add_setshow_boolean_cmd ("shell", class_support, &useshell, _("\
Set use of shell to start subprocess."), _("\
Show use of shell to start subprocess."), NULL,
@@ -2062,6 +2172,14 @@ Show use of shell to start subprocess."), NULL,
NULL, /* FIXME: i18n: */
&setlist, &showlist);
+ 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,
+ NULL, /* FIXME: i18n: */
+ &setlist, &showlist);
+#endif
+
add_setshow_boolean_cmd ("new-console", class_support, &new_console, _("\
Set creation of new console when creating child process."), _("\
Show creation of new console when creating child process."), NULL,
@@ -2105,9 +2223,6 @@ Show whether to display kernel exceptions in child process."), NULL,
NULL, /* FIXME: i18n: */
&setlist, &showlist);
- add_info ("dll", info_dll_command, _("Status of loaded DLLs."));
- add_info_alias ("sharedlibrary", "dll", 1);
-
add_prefix_cmd ("w32", class_info, info_w32_command,
_("Print information specific to Win32 debugging."),
&info_w32_cmdlist, "info w32 ", 0, &infolist);
@@ -2115,14 +2230,15 @@ Show whether to display kernel exceptions in child process."), NULL,
add_cmd ("selector", class_info, display_selectors,
_("Display selectors infos."),
&info_w32_cmdlist);
- add_target (&win32_ops);
+ add_target (&windows_ops);
+ deprecated_init_ui_hook = set_windows_aliases;
}
/* Hardware watchpoint support, adapted from go32-nat.c code. */
/* Pass the address ADDR to the inferior in the I'th debug register.
Here we just store the address in dr array, the registers will be
- actually set up when win32_continue is called. */
+ actually set up when windows_continue is called. */
void
cygwin_set_dr (int i, CORE_ADDR addr)
{
@@ -2136,7 +2252,7 @@ cygwin_set_dr (int i, CORE_ADDR addr)
/* Pass the value VAL to the inferior in the DR7 debug control
register. Here we just store the address in D_REGS, the watchpoint
- will be actually set up in win32_wait. */
+ will be actually set up in windows_wait. */
void
cygwin_set_dr7 (unsigned val)
{
@@ -2154,47 +2270,19 @@ cygwin_get_dr6 (void)
return dr[6];
}
-/* Determine if the thread referenced by "pid" is alive
+/* Determine if the thread referenced by "ptid" is alive
by "polling" it. If WaitForSingleObject returns WAIT_OBJECT_0
- it means that the pid 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
-win32_win32_thread_alive (ptid_t ptid)
-{
- int pid = PIDGET (ptid);
-
- return WaitForSingleObject (thread_rec (pid, FALSE)->h, 0) == WAIT_OBJECT_0 ?
- FALSE : TRUE;
-}
-
-static void
-fetch_elf_core_registers (char *core_reg_sect,
- unsigned core_reg_size,
- int which,
- CORE_ADDR reg_addr)
+windows_thread_alive (struct target_ops *ops, ptid_t ptid)
{
- int r;
- if (core_reg_size < sizeof (CONTEXT))
- {
- error (_("Core file register section too small (%u bytes)."), core_reg_size);
- return;
- }
- for (r = 0; r < NUM_REGS; r++)
- regcache_raw_supply (current_regcache, r, core_reg_sect + mappings[r]);
-}
+ int tid;
-static struct core_fns win32_elf_core_fns =
-{
- bfd_target_elf_flavour,
- default_check_format,
- default_core_sniffer,
- fetch_elf_core_registers,
- NULL
-};
+ gdb_assert (ptid_get_tid (ptid) != 0);
+ tid = ptid_get_tid (ptid);
-void
-_initialize_core_win32 (void)
-{
- deprecated_add_core_fns (&win32_elf_core_fns);
+ return WaitForSingleObject (thread_rec (tid, FALSE)->h, 0) == WAIT_OBJECT_0 ?
+ FALSE : TRUE;
}
void
@@ -2225,3 +2313,34 @@ _initialize_check_for_gdb_ini (void)
}
}
}
+
+void
+_initialize_psapi (void)
+{
+ /* Load optional functions used for retrieving filename information
+ associated with the currently debugged process or its dlls. */
+ if (!psapi_loaded)
+ {
+ HMODULE psapi_module_handle;
+
+ psapi_loaded = -1;
+
+ psapi_module_handle = LoadLibrary ("psapi.dll");
+ if (psapi_module_handle)
+ {
+ psapi_EnumProcessModules = (void *) GetProcAddress (psapi_module_handle, "EnumProcessModules");
+ psapi_GetModuleInformation = (void *) GetProcAddress (psapi_module_handle, "GetModuleInformation");
+ psapi_GetModuleFileNameExA = (void *) GetProcAddress (psapi_module_handle, "GetModuleFileNameExA");
+
+ if (psapi_EnumProcessModules != NULL
+ && psapi_GetModuleInformation != NULL
+ && psapi_GetModuleFileNameExA != NULL)
+ psapi_loaded = 1;
+ }
+ }
+
+ /* This will probably fail on Windows 9x/Me. Let the user know that we're
+ missing some functionality. */
+ if (psapi_loaded < 0)
+ warning(_("cannot automatically find executable file or library to read symbols. Use \"file\" or \"dll\" command to load executable/libraries directly."));
+}