| /* Target-vector operations for controlling win32 child processes, for GDB. | 
 |  | 
 |    Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, | 
 |    2005, 2006 | 
 |    Free Software Foundation, Inc. | 
 |  | 
 |    Contributed by Cygnus Solutions, A Red Hat Company. | 
 |  | 
 |    This file is part of GDB. | 
 |  | 
 |    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 | 
 |    (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 | 
 |    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., 51 Franklin Street, Fifth Floor, | 
 |    Boston, MA 02110-1301, USA.  */ | 
 |  | 
 | /* 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" | 
 | #include "target.h" | 
 | #include "exceptions.h" | 
 | #include "gdbcore.h" | 
 | #include "command.h" | 
 | #include "completer.h" | 
 | #include "regcache.h" | 
 | #include "top.h" | 
 | #include <signal.h> | 
 | #include <sys/types.h> | 
 | #include <fcntl.h> | 
 | #include <stdlib.h> | 
 | #include <windows.h> | 
 | #include <imagehlp.h> | 
 | #include <sys/cygwin.h> | 
 | #include <signal.h> | 
 |  | 
 | #include "buildsym.h" | 
 | #include "symfile.h" | 
 | #include "objfiles.h" | 
 | #include "gdb_string.h" | 
 | #include "gdbthread.h" | 
 | #include "gdbcmd.h" | 
 | #include <sys/param.h> | 
 | #include <unistd.h> | 
 | #include "exec.h" | 
 | #include "solist.h" | 
 | #include "solib.h" | 
 |  | 
 | #include "i386-tdep.h" | 
 | #include "i387-tdep.h" | 
 |  | 
 | static struct target_ops win32_ops; | 
 | static struct target_so_ops win32_so_ops; | 
 |  | 
 | /* The starting and ending address of the cygwin1.dll text segment. */ | 
 | static bfd_vma cygwin_load_start; | 
 | static bfd_vma cygwin_load_end; | 
 |  | 
 | 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... */ | 
 | #ifndef _GNU_H_WINDOWS_H | 
 | enum | 
 |   { | 
 |     FLAG_TRACE_BIT = 0x100, | 
 |     CONTEXT_DEBUGGER = (CONTEXT_FULL | CONTEXT_FLOATING_POINT) | 
 |   }; | 
 | #endif | 
 | #include <sys/procfs.h> | 
 | #include <psapi.h> | 
 |  | 
 | #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; | 
 |  | 
 | /* The string sent by cygwin when it processes a signal. | 
 |    FIXME: This should be in a cygwin include file. */ | 
 | #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 | 
 | #define DEBUG_EVENTS(x)	if (debug_events)	printf_unfiltered x | 
 | #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 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. */ | 
 | typedef struct thread_info_struct | 
 |   { | 
 |     struct thread_info_struct *next; | 
 |     DWORD id; | 
 |     HANDLE h; | 
 |     char *name; | 
 |     int suspend_count; | 
 |     int reload_context; | 
 |     CONTEXT context; | 
 |     STACKFRAME sf; | 
 |   } | 
 | thread_info; | 
 |  | 
 | static thread_info thread_head; | 
 |  | 
 | /* The process and thread handles for the above context. */ | 
 |  | 
 | static DEBUG_EVENT current_event;	/* The current debug event from | 
 | 					   WaitForDebugEvent */ | 
 | static HANDLE current_process_handle;	/* Currently executing process */ | 
 | static thread_info *current_thread;	/* Info on currently selected thread */ | 
 | static DWORD main_thread_id;		/* Thread ID of the main thread */ | 
 |  | 
 | /* Counts of things. */ | 
 | static int exception_count = 0; | 
 | static int event_count = 0; | 
 | static int saw_create; | 
 |  | 
 | /* User options. */ | 
 | static int new_console = 0; | 
 | static int cygwin_exceptions = 0; | 
 | static int new_group = 1; | 
 | static int debug_exec = 0;		/* show execution */ | 
 | static int debug_events = 0;		/* show events from kernel */ | 
 | 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. | 
 |  | 
 |    It also contains the bit mask needed to load the register in question. | 
 |  | 
 |    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 | 
 |    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. */ | 
 |  | 
 | #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 | 
 |  | 
 | /* This vector maps the target's idea of an exception (extracted | 
 |    from the DEBUG_EVENT structure) to GDB's idea. */ | 
 |  | 
 | struct xlate_exception | 
 |   { | 
 |     int them; | 
 |     enum target_signal us; | 
 |   }; | 
 |  | 
 | 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}, | 
 |   {-1, -1}}; | 
 |  | 
 | static void | 
 | check (BOOL ok, const char *file, int line) | 
 | { | 
 |   if (!ok) | 
 |     printf_filtered ("error return %s:%d was %lu\n", file, line, | 
 | 		     GetLastError ()); | 
 | } | 
 |  | 
 | /* Find a thread record given a thread id. | 
 |    If get_context then also retrieve the context for this | 
 |    thread. */ | 
 | static thread_info * | 
 | thread_rec (DWORD id, int get_context) | 
 | { | 
 |   thread_info *th; | 
 |  | 
 |   for (th = &thread_head; (th = th->next) != NULL;) | 
 |     if (th->id == id) | 
 |       { | 
 | 	if (!th->suspend_count && get_context) | 
 | 	  { | 
 | 	    if (get_context > 0 && id != current_event.dwThreadId) | 
 | 	      th->suspend_count = SuspendThread (th->h) + 1; | 
 | 	    else if (get_context < 0) | 
 | 	      th->suspend_count = -1; | 
 | 	    th->reload_context = 1; | 
 | 	  } | 
 | 	return th; | 
 |       } | 
 |  | 
 |   return NULL; | 
 | } | 
 |  | 
 | /* Add a thread to the thread list */ | 
 | static thread_info * | 
 | win32_add_thread (DWORD id, HANDLE h) | 
 | { | 
 |   thread_info *th; | 
 |  | 
 |   if ((th = thread_rec (id, FALSE))) | 
 |     return 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.  */ | 
 |   if (debug_registers_used) | 
 |     { | 
 |       /* Only change the value of the debug registers.  */ | 
 |       th->context.ContextFlags = CONTEXT_DEBUG_REGISTERS; | 
 |       CHECK (GetThreadContext (th->h, &th->context)); | 
 |       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; | 
 |     } | 
 |   return th; | 
 | } | 
 |  | 
 | /* Clear out any old thread list and reintialize it to a | 
 |    pristine state. */ | 
 | static void | 
 | win32_init_thread_list (void) | 
 | { | 
 |   thread_info *th = &thread_head; | 
 |  | 
 |   DEBUG_EVENTS (("gdb: win32_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; | 
 | } | 
 |  | 
 | /* Delete a thread from the list of threads */ | 
 | static void | 
 | win32_delete_thread (DWORD id) | 
 | { | 
 |   thread_info *th; | 
 |  | 
 |   if (info_verbose) | 
 |     printf_unfiltered ("[Deleting %s]\n", target_pid_to_str (pid_to_ptid (id))); | 
 |   delete_thread (pid_to_ptid (id)); | 
 |  | 
 |   for (th = &thread_head; | 
 |        th->next != NULL && th->next->id != id; | 
 |        th = th->next) | 
 |     continue; | 
 |  | 
 |   if (th->next != NULL) | 
 |     { | 
 |       thread_info *here = th->next; | 
 |       th->next = here->next; | 
 |       CloseHandle (here->h); | 
 |       xfree (here); | 
 |     } | 
 | } | 
 |  | 
 | static void | 
 | do_win32_fetch_inferior_registers (int r) | 
 | { | 
 |   char *context_offset = ((char *) ¤t_thread->context) + mappings[r]; | 
 |   long l; | 
 |  | 
 |   if (!current_thread) | 
 |     return;	/* Windows sometimes uses a non-existent thread id in its | 
 | 		   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); | 
 | 	  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.  */ | 
 | 	  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) | 
 |     { | 
 |       l = *((long *) context_offset) & 0xffff; | 
 |       regcache_raw_supply (current_regcache, r, (char *) &l); | 
 |     } | 
 |   else if (r == I387_FOP_REGNUM) | 
 |     { | 
 |       l = (*((long *) context_offset) >> 16) & ((1 << 11) - 1); | 
 |       regcache_raw_supply (current_regcache, r, (char *) &l); | 
 |     } | 
 |   else if (r >= 0) | 
 |     regcache_raw_supply (current_regcache, r, context_offset); | 
 |   else | 
 |     { | 
 |       for (r = 0; r < NUM_REGS; r++) | 
 | 	do_win32_fetch_inferior_registers (r); | 
 |     } | 
 |  | 
 | #undef I387_ST0_REGNUM | 
 | } | 
 |  | 
 | static void | 
 | win32_fetch_inferior_registers (int r) | 
 | { | 
 |   current_thread = thread_rec (PIDGET (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); | 
 | } | 
 |  | 
 | static void | 
 | do_win32_store_inferior_registers (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, | 
 | 			  ((char *) ¤t_thread->context) + mappings[r]); | 
 |   else | 
 |     { | 
 |       for (r = 0; r < NUM_REGS; r++) | 
 | 	do_win32_store_inferior_registers (r); | 
 |     } | 
 | } | 
 |  | 
 | /* Store a new register value into the current thread context */ | 
 | static void | 
 | win32_store_inferior_registers (int r) | 
 | { | 
 |   current_thread = thread_rec (PIDGET (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); | 
 | } | 
 |  | 
 | 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 int | 
 | psapi_get_dll_name (DWORD BaseAddress, char *dll_name_ret) | 
 | { | 
 |   DWORD len; | 
 |   MODULEINFO mi; | 
 |   int i; | 
 |   HMODULE dh_buf[1]; | 
 |   HMODULE *DllHandle = dh_buf; | 
 |   DWORD cbNeeded; | 
 |   BOOL ok; | 
 |  | 
 |   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; | 
 |     } | 
 |  | 
 |   cbNeeded = 0; | 
 |   ok = (*psapi_EnumProcessModules) (current_process_handle, | 
 | 				    DllHandle, | 
 | 				    sizeof (HMODULE), | 
 | 				    &cbNeeded); | 
 |  | 
 |   if (!ok || !cbNeeded) | 
 |     goto failed; | 
 |  | 
 |   DllHandle = (HMODULE *) alloca (cbNeeded); | 
 |   if (!DllHandle) | 
 |     goto failed; | 
 |  | 
 |   ok = (*psapi_EnumProcessModules) (current_process_handle, | 
 | 				    DllHandle, | 
 | 				    cbNeeded, | 
 | 				    &cbNeeded); | 
 |   if (!ok) | 
 |     goto failed; | 
 |  | 
 |   for (i = 0; i < (int) (cbNeeded / sizeof (HMODULE)); i++) | 
 |     { | 
 |       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; | 
 |     } | 
 |  | 
 | failed: | 
 |   dll_name_ret[0] = '\0'; | 
 |   return 0; | 
 | } | 
 |  | 
 | /* Encapsulate the information required in a call to | 
 |    symbol_file_add_args */ | 
 | struct safe_symbol_file_add_args | 
 | { | 
 |   char *name; | 
 |   int from_tty; | 
 |   struct section_addr_info *addrs; | 
 |   int mainline; | 
 |   int flags; | 
 |   struct ui_file *err, *out; | 
 |   struct objfile *ret; | 
 | }; | 
 |  | 
 | /* Maintain a linked list of "so" information. */ | 
 | struct lm_info | 
 | { | 
 |   DWORD 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. */ | 
 | 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 | 
 | } | 
 |  | 
 | /* Restore gdb's stderr after calling symbol_file_add */ | 
 | static void | 
 | safe_symbol_file_add_cleanup (void *p) | 
 | { | 
 | #define sp ((struct safe_symbol_file_add_args *)p) | 
 |   gdb_flush (gdb_stderr); | 
 |   gdb_flush (gdb_stdout); | 
 |   ui_file_delete (gdb_stderr); | 
 |   ui_file_delete (gdb_stdout); | 
 |   gdb_stderr = sp->err; | 
 |   gdb_stdout = sp->out; | 
 | #undef sp | 
 | } | 
 |  | 
 | /* symbol_file_add wrapper that prevents errors from being displayed. */ | 
 | static struct objfile * | 
 | safe_symbol_file_add (char *name, int from_tty, | 
 | 		      struct section_addr_info *addrs, | 
 | 		      int mainline, int flags) | 
 | { | 
 |   struct safe_symbol_file_add_args p; | 
 |   struct cleanup *cleanup; | 
 |  | 
 |   cleanup = make_cleanup (safe_symbol_file_add_cleanup, &p); | 
 |  | 
 |   p.err = gdb_stderr; | 
 |   p.out = gdb_stdout; | 
 |   gdb_flush (gdb_stderr); | 
 |   gdb_flush (gdb_stdout); | 
 |   gdb_stderr = ui_file_new (); | 
 |   gdb_stdout = ui_file_new (); | 
 |   p.name = name; | 
 |   p.from_tty = from_tty; | 
 |   p.addrs = addrs; | 
 |   p.mainline = mainline; | 
 |   p.flags = flags; | 
 |   catch_errors (safe_symbol_file_add_stub, &p, "", RETURN_MASK_ERROR); | 
 |  | 
 |   do_cleanups (cleanup); | 
 |   return p.ret; | 
 | } | 
 |  | 
 | /* Get the loaded address of all sections, given that .text was loaded | 
 |    at text_load. Assumes that all sections are subject to the same | 
 |    relocation offset. Returns NULL if problems occur or if the | 
 |    sections were not relocated. */ | 
 |  | 
 | static struct section_addr_info * | 
 | get_relocated_section_addrs (bfd *abfd, CORE_ADDR text_load) | 
 | { | 
 |   struct section_addr_info *result = NULL; | 
 |   int section_count = bfd_count_sections (abfd); | 
 |   asection *text_section = bfd_get_section_by_name (abfd, ".text"); | 
 |   CORE_ADDR text_vma; | 
 |  | 
 |   if (!text_section) | 
 |     { | 
 |       /* Couldn't get the .text section. Weird. */ | 
 |     } | 
 |   else if (text_load == (text_vma = bfd_get_section_vma (abfd, text_section))) | 
 |     { | 
 |       /* DLL wasn't relocated. */ | 
 |     } | 
 |   else | 
 |     { | 
 |       /* Figure out all sections' loaded addresses. The offset here is | 
 | 	 such that taking a bfd_get_section_vma() result and adding | 
 | 	 offset will give the real load address of the section. */ | 
 |  | 
 |       CORE_ADDR offset = text_load - text_vma; | 
 |  | 
 |       struct section_table *table_start = NULL; | 
 |       struct section_table *table_end = NULL; | 
 |       struct section_table *iter = NULL; | 
 |  | 
 |       build_section_table (abfd, &table_start, &table_end); | 
 |  | 
 |       for (iter = table_start; iter < table_end; ++iter) | 
 | 	{ | 
 | 	  /* Relocated addresses. */ | 
 | 	  iter->addr += offset; | 
 | 	  iter->endaddr += offset; | 
 | 	} | 
 |  | 
 |       result = build_section_addr_info_from_section_table (table_start, | 
 | 							   table_end); | 
 |  | 
 |       xfree (table_start); | 
 |     } | 
 |  | 
 |   return result; | 
 | } | 
 |  | 
 | /* Add DLL symbol information. */ | 
 | static void | 
 | solib_symbols_add (struct so_list *so, CORE_ADDR load_addr) | 
 | { | 
 |   struct section_addr_info *addrs = NULL; | 
 |   static struct objfile *result = NULL; | 
 |   char *name = so->so_name; | 
 |   bfd *abfd = NULL; | 
 |   char *p; | 
 |  | 
 |   /* 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. */ | 
 |  | 
 |   if (!name || !name[0]) | 
 |     return; | 
 |  | 
 |   abfd = bfd_openr (name, "pei-i386"); | 
 |  | 
 |   if (!abfd) | 
 |     { | 
 |       /* pei failed - try pe */ | 
 |       abfd = bfd_openr (name, "pe-i386"); | 
 |     } | 
 |  | 
 |   if (abfd) | 
 |     { | 
 |       if (bfd_check_format (abfd, bfd_object)) | 
 | 	addrs = get_relocated_section_addrs (abfd, load_addr); | 
 |     } | 
 |  | 
 |   if (addrs) | 
 |     { | 
 |       result = safe_symbol_file_add (name, 0, addrs, 0, OBJF_SHARED); | 
 |       free_section_addr_info (addrs); | 
 |     } | 
 |   else | 
 |     { | 
 |       /* Fallback on handling just the .text section. */ | 
 |       struct cleanup *my_cleanups; | 
 |  | 
 |       addrs = alloc_section_addr_info (1); | 
 |       my_cleanups = make_cleanup (xfree, addrs); | 
 |       addrs->other[0].name = ".text"; | 
 |       addrs->other[0].addr = load_addr; | 
 |  | 
 |       result = safe_symbol_file_add (name, 0, addrs, 0, OBJF_SHARED); | 
 |       do_cleanups (my_cleanups); | 
 |     } | 
 |  | 
 |   p = strchr (so->so_name, '\0') - (sizeof ("/cygwin1.dll") - 1); | 
 |   if (p >= so->so_name && strcasecmp (p, "/cygwin1.dll") == 0) | 
 |     { | 
 |       asection *text = bfd_get_section_by_name (abfd, ".text"); | 
 |       cygwin_load_start = bfd_section_vma (abfd, text); | 
 |       cygwin_load_end = cygwin_load_start + bfd_section_size (abfd, text); | 
 |     } | 
 |  | 
 |   bfd_close (abfd); | 
 |  | 
 |   so->symbols_loaded = !!result; | 
 |   return; | 
 | } | 
 |  | 
 | static char * | 
 | register_loaded_dll (const char *name, DWORD load_addr, int readsyms) | 
 | { | 
 |   struct so_list *so; | 
 |   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); | 
 |   else | 
 |     { | 
 |       FindClose (h); | 
 |       strcpy (buf, name); | 
 |       if (GetCurrentDirectory (MAX_PATH + 1, cwd)) | 
 | 	{ | 
 | 	  p = strrchr (buf, '\\'); | 
 | 	  if (p) | 
 | 	    p[1] = '\0'; | 
 | 	  SetCurrentDirectory (buf); | 
 | 	  GetFullPathName (w32_fd.cFileName, MAX_PATH, buf, &p); | 
 | 	  SetCurrentDirectory (cwd); | 
 | 	} | 
 |     } | 
 |  | 
 |   if (strcasecmp (buf, "ntdll.dll") == 0) | 
 |     { | 
 |       GetSystemDirectory (buf, sizeof (buf)); | 
 |       strcat (buf, "\\ntdll.dll"); | 
 |     } | 
 |   so = XZALLOC (struct so_list); | 
 |   so->lm_info = (struct lm_info *) xmalloc (sizeof (struct lm_info)); | 
 |   so->lm_info->load_addr = load_addr; | 
 |   cygwin_conv_to_posix_path (buf, so->so_name); | 
 |   strcpy (so->so_original_name, so->so_name); | 
 |  | 
 |   solib_end->next = so; | 
 |   solib_end = so; | 
 |   len = strlen (so->so_name); | 
 |   if (readsyms) | 
 |     solib_symbols_add (so, (CORE_ADDR) load_addr); | 
 |  | 
 |   return so->so_name; | 
 | } | 
 |  | 
 | static char * | 
 | get_image_name (HANDLE h, void *address, int unicode) | 
 | { | 
 |   static char buf[(2 * MAX_PATH) + 1]; | 
 |   DWORD size = unicode ? sizeof (WCHAR) : sizeof (char); | 
 |   char *address_ptr; | 
 |   int len = 0; | 
 |   char b[2]; | 
 |   DWORD done; | 
 |  | 
 |   /* 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. */ | 
 |   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) | 
 |       || done != sizeof (address_ptr) || !address_ptr) | 
 |     return NULL; | 
 |  | 
 |   /* 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; | 
 |  | 
 |   if (!unicode) | 
 |     ReadProcessMemory (h, address_ptr, buf, len, &done); | 
 |   else | 
 |     { | 
 |       WCHAR *unicode_address = (WCHAR *) alloca (len * sizeof (WCHAR)); | 
 |       ReadProcessMemory (h, address_ptr, unicode_address, len * sizeof (WCHAR), | 
 | 			 &done); | 
 |  | 
 |       WideCharToMultiByte (CP_ACP, 0, unicode_address, len, buf, len, 0, 0); | 
 |     } | 
 |  | 
 |   return buf; | 
 | } | 
 |  | 
 | /* Wait for child to do something.  Return pid of child, or -1 in case | 
 |    of error; store status through argument pointer OURSTATUS.  */ | 
 | static int | 
 | handle_load_dll (void *dummy) | 
 | { | 
 |   LOAD_DLL_DEBUG_INFO *event = ¤t_event.u.LoadDll; | 
 |   char dll_buf[MAX_PATH + 1]; | 
 |   char *dll_name = NULL; | 
 |  | 
 |   dll_buf[0] = dll_buf[sizeof (dll_buf) - 1] = '\0'; | 
 |  | 
 |   if (!psapi_get_dll_name ((DWORD) (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); | 
 |   if (!dll_name) | 
 |     return 1; | 
 |  | 
 |   register_loaded_dll (dll_name, (DWORD) event->lpBaseOfDll + 0x1000, auto_solib_add); | 
 |  | 
 |   return 1; | 
 | } | 
 |  | 
 | static void | 
 | win32_free_so (struct so_list *so) | 
 | { | 
 |   if (so->lm_info) | 
 |     xfree (so->lm_info); | 
 | } | 
 |  | 
 | static void | 
 | win32_relocate_section_addresses (struct so_list *so, | 
 | 				  struct section_table *sec) | 
 | { | 
 |   /* FIXME */ | 
 |   return; | 
 | } | 
 |  | 
 | static void | 
 | win32_solib_create_inferior_hook (void) | 
 | { | 
 |   solib_add (NULL, 0, NULL, auto_solib_add); | 
 |   return; | 
 | } | 
 |  | 
 | static int | 
 | handle_unload_dll (void *dummy) | 
 | { | 
 |   DWORD lpBaseOfDll = (DWORD) current_event.u.UnloadDll.lpBaseOfDll + 0x1000; | 
 |   struct so_list *so; | 
 |  | 
 |   for (so = &solib_start; so->next != NULL; so = so->next) | 
 |     if (so->next->lm_info->load_addr == lpBaseOfDll) | 
 |       { | 
 | 	struct so_list *sodel = so->next; | 
 | 	so->next = sodel->next; | 
 | 	if (!so->next) | 
 | 	  solib_end = so; | 
 | 	free_so (sodel); | 
 | 	solib_add (NULL, 0, NULL, auto_solib_add); | 
 | 	return 1; | 
 |       } | 
 |  | 
 |   error (_("Error: dll starting at 0x%lx not found."), (DWORD) lpBaseOfDll); | 
 |  | 
 |   return 0; | 
 | } | 
 |  | 
 | /* Clear list of loaded DLLs. */ | 
 | static void | 
 | win32_clear_solib (void) | 
 | { | 
 |   solib_start.next = NULL; | 
 |   solib_end = &solib_start; | 
 | } | 
 |  | 
 | static void | 
 | win32_special_symbol_handling (void) | 
 | { | 
 |   return; | 
 | } | 
 |  | 
 | /* Load DLL symbol info. */ | 
 | void | 
 | dll_symbol_command (char *args, int from_tty) | 
 | { | 
 |   int n; | 
 |   dont_repeat (); | 
 |  | 
 |   if (args == NULL) | 
 |     error (_("dll-symbols requires a file name")); | 
 |  | 
 |   n = strlen (args); | 
 |   if (n > 4 && strcasecmp (args + n - 4, ".dll") != 0) | 
 |     { | 
 |       char *newargs = (char *) alloca (n + 4 + 1); | 
 |       strcpy (newargs, args); | 
 |       strcat (newargs, ".dll"); | 
 |       args = newargs; | 
 |     } | 
 |  | 
 |   safe_symbol_file_add (args, from_tty, NULL, 0, OBJF_SHARED | OBJF_USERLOADED); | 
 | } | 
 |  | 
 | /* Handle DEBUG_STRING output from child process. | 
 |    Cygwin prepends its messages with a "cygwin:".  Interpret this as | 
 |    a Cygwin signal.  Otherwise just print the string as a warning. */ | 
 | static int | 
 | handle_output_debug_string (struct target_waitstatus *ourstatus) | 
 | { | 
 |   char *s = NULL; | 
 |   int retval = 0; | 
 |  | 
 |   if (!target_read_string | 
 |     ((CORE_ADDR) current_event.u.DebugString.lpDebugStringData, &s, 1024, 0) | 
 |       || !s || !*s) | 
 |     /* nothing to do */; | 
 |   else if (strncmp (s, _CYGWIN_SIGNAL_STRING, sizeof (_CYGWIN_SIGNAL_STRING) - 1) != 0) | 
 |     { | 
 |       if (strncmp (s, "cYg", 3) != 0) | 
 | 	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); | 
 |       int gotasig = target_signal_from_host (sig); | 
 |       ourstatus->value.sig = gotasig; | 
 |       if (gotasig) | 
 | 	{ | 
 | 	  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 | 
 |  | 
 |   if (s) | 
 |     xfree (s); | 
 |   return retval; | 
 | } | 
 |  | 
 | static int | 
 | display_selector (HANDLE thread, DWORD sel) | 
 | { | 
 |   LDT_ENTRY info; | 
 |   if (GetThreadSelectorEntry (thread, sel, &info)) | 
 |     { | 
 |       int base, limit; | 
 |       printf_filtered ("0x%03lx: ", sel); | 
 |       if (!info.HighWord.Bits.Pres) | 
 | 	{ | 
 | 	  puts_filtered ("Segment not present\n"); | 
 | 	  return 0; | 
 | 	} | 
 |       base = (info.HighWord.Bits.BaseHi << 24) + | 
 | 	     (info.HighWord.Bits.BaseMid << 16) | 
 | 	     + info.BaseLow; | 
 |       limit = (info.HighWord.Bits.LimitHi << 16) + info.LimitLow; | 
 |       if (info.HighWord.Bits.Granularity) | 
 | 	limit = (limit << 12) | 0xfff; | 
 |       printf_filtered ("base=0x%08x limit=0x%08x", base, limit); | 
 |       if (info.HighWord.Bits.Default_Big) | 
 | 	puts_filtered(" 32-bit "); | 
 |       else | 
 | 	puts_filtered(" 16-bit "); | 
 |       switch ((info.HighWord.Bits.Type & 0xf) >> 1) | 
 | 	{ | 
 | 	case 0: | 
 | 	  puts_filtered ("Data (Read-Only, Exp-up"); | 
 | 	  break; | 
 | 	case 1: | 
 | 	  puts_filtered ("Data (Read/Write, Exp-up"); | 
 | 	  break; | 
 | 	case 2: | 
 | 	  puts_filtered ("Unused segment ("); | 
 | 	  break; | 
 | 	case 3: | 
 | 	  puts_filtered ("Data (Read/Write, Exp-down"); | 
 | 	  break; | 
 | 	case 4: | 
 | 	  puts_filtered ("Code (Exec-Only, N.Conf"); | 
 | 	  break; | 
 | 	case 5: | 
 | 	  puts_filtered ("Code (Exec/Read, N.Conf"); | 
 | 	  break; | 
 | 	case 6: | 
 | 	  puts_filtered ("Code (Exec-Only, Conf"); | 
 | 	  break; | 
 | 	case 7: | 
 | 	  puts_filtered ("Code (Exec/Read, Conf"); | 
 | 	  break; | 
 | 	default: | 
 | 	  printf_filtered ("Unknown type 0x%x",info.HighWord.Bits.Type); | 
 | 	} | 
 |       if ((info.HighWord.Bits.Type & 0x1) == 0) | 
 | 	puts_filtered(", N.Acc"); | 
 |       puts_filtered (")\n"); | 
 |       if ((info.HighWord.Bits.Type & 0x10) == 0) | 
 | 	puts_filtered("System selector "); | 
 |       printf_filtered ("Priviledge level = %d. ", info.HighWord.Bits.Dpl); | 
 |       if (info.HighWord.Bits.Granularity) | 
 | 	puts_filtered ("Page granular.\n"); | 
 |       else | 
 | 	puts_filtered ("Byte granular.\n"); | 
 |       return 1; | 
 |     } | 
 |   else | 
 |     { | 
 |       printf_filtered ("Invalid selector 0x%lx.\n",sel); | 
 |       return 0; | 
 |     } | 
 | } | 
 |  | 
 | static void | 
 | display_selectors (char * args, int from_tty) | 
 | { | 
 |   if (!current_thread) | 
 |     { | 
 |       puts_filtered ("Impossible to display selectors now.\n"); | 
 |       return; | 
 |     } | 
 |   if (!args) | 
 |     { | 
 |  | 
 |       puts_filtered ("Selector $cs\n"); | 
 |       display_selector (current_thread->h, | 
 | 	current_thread->context.SegCs); | 
 |       puts_filtered ("Selector $ds\n"); | 
 |       display_selector (current_thread->h, | 
 | 	current_thread->context.SegDs); | 
 |       puts_filtered ("Selector $es\n"); | 
 |       display_selector (current_thread->h, | 
 | 	current_thread->context.SegEs); | 
 |       puts_filtered ("Selector $ss\n"); | 
 |       display_selector (current_thread->h, | 
 | 	current_thread->context.SegSs); | 
 |       puts_filtered ("Selector $fs\n"); | 
 |       display_selector (current_thread->h, | 
 | 	current_thread->context.SegFs); | 
 |       puts_filtered ("Selector $gs\n"); | 
 |       display_selector (current_thread->h, | 
 | 	current_thread->context.SegGs); | 
 |     } | 
 |   else | 
 |     { | 
 |       int sel; | 
 |       sel = parse_and_eval_long (args); | 
 |       printf_filtered ("Selector \"%s\"\n",args); | 
 |       display_selector (current_thread->h, sel); | 
 |     } | 
 | } | 
 |  | 
 | static struct cmd_list_element *info_w32_cmdlist = NULL; | 
 |  | 
 | static void | 
 | info_w32_command (char *args, int from_tty) | 
 | { | 
 |   help_list (info_w32_cmdlist, "info w32 ", class_info, gdb_stdout); | 
 | } | 
 |  | 
 |  | 
 | #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) | 
 |  | 
 | static int | 
 | handle_exception (struct target_waitstatus *ourstatus) | 
 | { | 
 |   thread_info *th; | 
 |   DWORD code = current_event.u.Exception.ExceptionRecord.ExceptionCode; | 
 |  | 
 |   ourstatus->kind = TARGET_WAITKIND_STOPPED; | 
 |  | 
 |   /* 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; | 
 |       { | 
 | 	/* 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; | 
 | 	bfd_vma addr = (bfd_vma) 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; | 
 |       } | 
 |       break; | 
 |     case STATUS_STACK_OVERFLOW: | 
 |       DEBUG_EXCEPTION_SIMPLE ("STATUS_STACK_OVERFLOW"); | 
 |       ourstatus->value.sig = TARGET_SIGNAL_SEGV; | 
 |       break; | 
 |     case STATUS_FLOAT_DENORMAL_OPERAND: | 
 |       DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_DENORMAL_OPERAND"); | 
 |       ourstatus->value.sig = TARGET_SIGNAL_FPE; | 
 |       break; | 
 |     case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: | 
 |       DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ARRAY_BOUNDS_EXCEEDED"); | 
 |       ourstatus->value.sig = TARGET_SIGNAL_FPE; | 
 |       break; | 
 |     case STATUS_FLOAT_INEXACT_RESULT: | 
 |       DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_INEXACT_RESULT"); | 
 |       ourstatus->value.sig = TARGET_SIGNAL_FPE; | 
 |       break; | 
 |     case STATUS_FLOAT_INVALID_OPERATION: | 
 |       DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_INVALID_OPERATION"); | 
 |       ourstatus->value.sig = TARGET_SIGNAL_FPE; | 
 |       break; | 
 |     case STATUS_FLOAT_OVERFLOW: | 
 |       DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_OVERFLOW"); | 
 |       ourstatus->value.sig = TARGET_SIGNAL_FPE; | 
 |       break; | 
 |     case STATUS_FLOAT_STACK_CHECK: | 
 |       DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_STACK_CHECK"); | 
 |       ourstatus->value.sig = TARGET_SIGNAL_FPE; | 
 |       break; | 
 |     case STATUS_FLOAT_UNDERFLOW: | 
 |       DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_UNDERFLOW"); | 
 |       ourstatus->value.sig = TARGET_SIGNAL_FPE; | 
 |       break; | 
 |     case STATUS_FLOAT_DIVIDE_BY_ZERO: | 
 |       DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_DIVIDE_BY_ZERO"); | 
 |       ourstatus->value.sig = TARGET_SIGNAL_FPE; | 
 |       break; | 
 |     case STATUS_INTEGER_DIVIDE_BY_ZERO: | 
 |       DEBUG_EXCEPTION_SIMPLE ("STATUS_INTEGER_DIVIDE_BY_ZERO"); | 
 |       ourstatus->value.sig = TARGET_SIGNAL_FPE; | 
 |       break; | 
 |     case STATUS_INTEGER_OVERFLOW: | 
 |       DEBUG_EXCEPTION_SIMPLE ("STATUS_INTEGER_OVERFLOW"); | 
 |       ourstatus->value.sig = TARGET_SIGNAL_FPE; | 
 |       break; | 
 |     case EXCEPTION_BREAKPOINT: | 
 |       DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_BREAKPOINT"); | 
 |       ourstatus->value.sig = TARGET_SIGNAL_TRAP; | 
 |       break; | 
 |     case DBG_CONTROL_C: | 
 |       DEBUG_EXCEPTION_SIMPLE ("DBG_CONTROL_C"); | 
 |       ourstatus->value.sig = TARGET_SIGNAL_INT; | 
 |       break; | 
 |     case DBG_CONTROL_BREAK: | 
 |       DEBUG_EXCEPTION_SIMPLE ("DBG_CONTROL_BREAK"); | 
 |       ourstatus->value.sig = TARGET_SIGNAL_INT; | 
 |       break; | 
 |     case EXCEPTION_SINGLE_STEP: | 
 |       DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_SINGLE_STEP"); | 
 |       ourstatus->value.sig = TARGET_SIGNAL_TRAP; | 
 |       break; | 
 |     case EXCEPTION_ILLEGAL_INSTRUCTION: | 
 |       DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ILLEGAL_INSTRUCTION"); | 
 |       ourstatus->value.sig = TARGET_SIGNAL_ILL; | 
 |       break; | 
 |     case EXCEPTION_PRIV_INSTRUCTION: | 
 |       DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_PRIV_INSTRUCTION"); | 
 |       ourstatus->value.sig = TARGET_SIGNAL_ILL; | 
 |       break; | 
 |     case EXCEPTION_NONCONTINUABLE_EXCEPTION: | 
 |       DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_NONCONTINUABLE_EXCEPTION"); | 
 |       ourstatus->value.sig = TARGET_SIGNAL_ILL; | 
 |       break; | 
 |     default: | 
 |       /* Treat unhandled first chance exceptions specially. */ | 
 |       if (current_event.u.Exception.dwFirstChance) | 
 | 	return -1; | 
 |       printf_unfiltered ("gdb: unknown target exception 0x%08lx at 0x%08lx\n", | 
 | 		    current_event.u.Exception.ExceptionRecord.ExceptionCode, | 
 | 	(DWORD) current_event.u.Exception.ExceptionRecord.ExceptionAddress); | 
 |       ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN; | 
 |       break; | 
 |     } | 
 |   exception_count++; | 
 |   last_sig = ourstatus->value.sig; | 
 |   return 1; | 
 | } | 
 |  | 
 | /* Resume all artificially suspended threads if we are continuing | 
 |    execution */ | 
 | static BOOL | 
 | win32_continue (DWORD continue_status, int id) | 
 | { | 
 |   int i; | 
 |   thread_info *th; | 
 |   BOOL res; | 
 |  | 
 |   DEBUG_EVENTS (("ContinueDebugEvent (cpid=%ld, ctid=%ld, %s);\n", | 
 | 		  current_event.dwProcessId, current_event.dwThreadId, | 
 | 		  continue_status == DBG_CONTINUE ? | 
 | 		  "DBG_CONTINUE" : "DBG_EXCEPTION_NOT_HANDLED")); | 
 |   res = ContinueDebugEvent (current_event.dwProcessId, | 
 | 			    current_event.dwThreadId, | 
 | 			    continue_status); | 
 |   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; | 
 | } | 
 |  | 
 | /* Called in pathological case where Windows fails to send a | 
 |    CREATE_PROCESS_DEBUG_EVENT after an attach.  */ | 
 | static DWORD | 
 | fake_create_process (void) | 
 | { | 
 |   current_process_handle = OpenProcess (PROCESS_ALL_ACCESS, FALSE, | 
 | 					current_event.dwProcessId); | 
 |   main_thread_id = current_event.dwThreadId; | 
 |   current_thread = win32_add_thread (main_thread_id, | 
 | 				     current_event.u.CreateThread.hThread); | 
 |   return main_thread_id; | 
 | } | 
 |  | 
 | 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); | 
 | } | 
 |  | 
 | /* 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) | 
 | { | 
 |   BOOL debug_event; | 
 |   DWORD continue_status, event_code; | 
 |   thread_info *th; | 
 |   static thread_info dummy_thread_info; | 
 |   int retval = 0; | 
 |   ptid_t ptid = {-1}; | 
 |  | 
 |   last_sig = TARGET_SIGNAL_0; | 
 |  | 
 |   if (!(debug_event = WaitForDebugEvent (¤t_event, 1000))) | 
 |     goto out; | 
 |  | 
 |   event_count++; | 
 |   continue_status = DBG_CONTINUE; | 
 |  | 
 |   event_code = current_event.dwDebugEventCode; | 
 |   ourstatus->kind = TARGET_WAITKIND_SPURIOUS; | 
 |   th = NULL; | 
 |   have_saved_context = 0; | 
 |  | 
 |   switch (event_code) | 
 |     { | 
 |     case CREATE_THREAD_DEBUG_EVENT: | 
 |       DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%x code=%s)\n", | 
 | 		     (unsigned) current_event.dwProcessId, | 
 | 		     (unsigned) current_event.dwThreadId, | 
 | 		     "CREATE_THREAD_DEBUG_EVENT")); | 
 |       if (saw_create != 1) | 
 | 	{ | 
 | 	  if (!saw_create && 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++; | 
 | 	    } | 
 | 	  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; | 
 |       break; | 
 |  | 
 |     case EXIT_THREAD_DEBUG_EVENT: | 
 |       DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n", | 
 | 		     (unsigned) current_event.dwProcessId, | 
 | 		     (unsigned) current_event.dwThreadId, | 
 | 		     "EXIT_THREAD_DEBUG_EVENT")); | 
 |       if (current_event.dwThreadId != main_thread_id) | 
 | 	{ | 
 | 	  win32_delete_thread (current_event.dwThreadId); | 
 | 	  th = &dummy_thread_info; | 
 | 	} | 
 |       break; | 
 |  | 
 |     case CREATE_PROCESS_DEBUG_EVENT: | 
 |       DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n", | 
 | 		     (unsigned) current_event.dwProcessId, | 
 | 		     (unsigned) current_event.dwThreadId, | 
 | 		     "CREATE_PROCESS_DEBUG_EVENT")); | 
 |       CloseHandle (current_event.u.CreateProcessInfo.hFile); | 
 |       if (++saw_create != 1) | 
 | 	{ | 
 | 	  CloseHandle (current_event.u.CreateProcessInfo.hProcess); | 
 | 	  break; | 
 | 	} | 
 |  | 
 |       current_process_handle = current_event.u.CreateProcessInfo.hProcess; | 
 |       if (main_thread_id) | 
 | 	win32_delete_thread (main_thread_id); | 
 |       main_thread_id = current_event.dwThreadId; | 
 |       /* Add the main thread */ | 
 |       th = win32_add_thread (main_thread_id, | 
 | 			     current_event.u.CreateProcessInfo.hThread); | 
 |       retval = ourstatus->value.related_pid = current_event.dwThreadId; | 
 |       break; | 
 |  | 
 |     case EXIT_PROCESS_DEBUG_EVENT: | 
 |       DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n", | 
 | 		     (unsigned) current_event.dwProcessId, | 
 | 		     (unsigned) current_event.dwThreadId, | 
 | 		     "EXIT_PROCESS_DEBUG_EVENT")); | 
 |       if (saw_create != 1) | 
 | 	break; | 
 |       ourstatus->kind = TARGET_WAITKIND_EXITED; | 
 |       ourstatus->value.integer = current_event.u.ExitProcess.dwExitCode; | 
 |       CloseHandle (current_process_handle); | 
 |       retval = main_thread_id; | 
 |       break; | 
 |  | 
 |     case LOAD_DLL_DEBUG_EVENT: | 
 |       DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n", | 
 | 		     (unsigned) current_event.dwProcessId, | 
 | 		     (unsigned) current_event.dwThreadId, | 
 | 		     "LOAD_DLL_DEBUG_EVENT")); | 
 |       CloseHandle (current_event.u.LoadDll.hFile); | 
 |       if (saw_create != 1) | 
 | 	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: | 
 |       DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n", | 
 | 		     (unsigned) current_event.dwProcessId, | 
 | 		     (unsigned) current_event.dwThreadId, | 
 | 		     "UNLOAD_DLL_DEBUG_EVENT")); | 
 |       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. */ | 
 |       break; | 
 |  | 
 |     case EXCEPTION_DEBUG_EVENT: | 
 |       DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n", | 
 | 		     (unsigned) current_event.dwProcessId, | 
 | 		     (unsigned) current_event.dwThreadId, | 
 | 		     "EXCEPTION_DEBUG_EVENT")); | 
 |       if (saw_create != 1) | 
 | 	break; | 
 |       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 */ | 
 |       DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n", | 
 | 		     (unsigned) current_event.dwProcessId, | 
 | 		     (unsigned) current_event.dwThreadId, | 
 | 		     "OUTPUT_DEBUG_STRING_EVENT")); | 
 |       if (saw_create != 1) | 
 | 	break; | 
 |       retval = handle_output_debug_string (ourstatus); | 
 |       break; | 
 |  | 
 |     default: | 
 |       if (saw_create != 1) | 
 | 	break; | 
 |       printf_unfiltered ("gdb: kernel event for pid=%ld tid=%ld\n", | 
 | 			 (DWORD) current_event.dwProcessId, | 
 | 			 (DWORD) current_event.dwThreadId); | 
 |       printf_unfiltered ("                 unknown event code %ld\n", | 
 | 			 current_event.dwDebugEventCode); | 
 |       break; | 
 |     } | 
 |  | 
 |   if (!retval || saw_create != 1) | 
 |     { | 
 |       if (continue_status == -1) | 
 | 	win32_resume (ptid, 0, 1); | 
 |       else | 
 | 	CHECK (win32_continue (continue_status, -1)); | 
 |     } | 
 |   else | 
 |     { | 
 |       inferior_ptid = pid_to_ptid (retval); | 
 |       current_thread = th ?: thread_rec (current_event.dwThreadId, TRUE); | 
 |     } | 
 |  | 
 | out: | 
 |   return retval; | 
 | } | 
 |  | 
 | /* Wait for interesting events to occur in the target process. */ | 
 | static ptid_t | 
 | win32_wait (ptid_t ptid, struct target_waitstatus *ourstatus) | 
 | { | 
 |   int pid = PIDGET (ptid); | 
 |  | 
 |   /* We loop when we get a non-standard exception rather than return | 
 |      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. */ | 
 |  | 
 |   while (1) | 
 |     { | 
 |       int retval = get_win32_debug_event (pid, ourstatus); | 
 |       if (retval) | 
 | 	return pid_to_ptid (retval); | 
 |       else | 
 | 	{ | 
 | 	  int detach = 0; | 
 |  | 
 | 	  if (deprecated_ui_loop_hook != NULL) | 
 | 	    detach = deprecated_ui_loop_hook (0); | 
 |  | 
 | 	  if (detach) | 
 | 	    win32_kill_inferior (); | 
 | 	} | 
 |     } | 
 | } | 
 |  | 
 | static void | 
 | do_initial_win32_stuff (DWORD pid) | 
 | { | 
 |   extern int stop_after_trap; | 
 |   int i; | 
 |  | 
 |   last_sig = TARGET_SIGNAL_0; | 
 |   event_count = 0; | 
 |   exception_count = 0; | 
 |   debug_registers_changed = 0; | 
 |   debug_registers_used = 0; | 
 |   for (i = 0; i < sizeof (dr) / sizeof (dr[0]); i++) | 
 |     dr[i] = 0; | 
 |   current_event.dwProcessId = pid; | 
 |   memset (¤t_event, 0, sizeof (current_event)); | 
 |   push_target (&win32_ops); | 
 |   disable_breakpoints_in_shlibs (1); | 
 |   win32_clear_solib (); | 
 |   clear_proceed_status (); | 
 |   init_wait_for_inferior (); | 
 |  | 
 |   target_terminal_init (); | 
 |   target_terminal_inferior (); | 
 |  | 
 |   while (1) | 
 |     { | 
 |       stop_after_trap = 1; | 
 |       wait_for_inferior (); | 
 |       if (stop_signal != TARGET_SIGNAL_TRAP) | 
 | 	resume (0, stop_signal); | 
 |       else | 
 | 	break; | 
 |     } | 
 |   stop_after_trap = 0; | 
 |   return; | 
 | } | 
 |  | 
 | /* Since Windows XP, detaching from a process is supported by Windows. | 
 |    The following code tries loading the appropriate functions dynamically. | 
 |    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 int | 
 | has_detach_ability (void) | 
 | { | 
 |   static HMODULE kernel32 = NULL; | 
 |  | 
 |   if (!kernel32) | 
 |     kernel32 = LoadLibrary ("kernel32.dll"); | 
 |   if (kernel32) | 
 |     { | 
 |       if (!DebugSetProcessKillOnExit) | 
 | 	DebugSetProcessKillOnExit = GetProcAddress (kernel32, | 
 | 						 "DebugSetProcessKillOnExit"); | 
 |       if (!DebugActiveProcessStop) | 
 | 	DebugActiveProcessStop = GetProcAddress (kernel32, | 
 | 						 "DebugActiveProcessStop"); | 
 |       if (DebugSetProcessKillOnExit && DebugActiveProcessStop) | 
 | 	return 1; | 
 |     } | 
 |   return 0; | 
 | } | 
 |  | 
 | /* Try to set or remove a user privilege to the current process.  Return -1 | 
 |    if that fails, the previous setting of that privilege otherwise. | 
 |  | 
 |    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. */ | 
 | static int | 
 | set_process_privilege (const char *privilege, BOOL enable) | 
 | { | 
 |   static HMODULE advapi32 = NULL; | 
 |   static BOOL WINAPI (*OpenProcessToken)(HANDLE, DWORD, PHANDLE); | 
 |   static BOOL WINAPI (*LookupPrivilegeValue)(LPCSTR, LPCSTR, PLUID); | 
 |   static BOOL WINAPI (*AdjustTokenPrivileges)(HANDLE, BOOL, PTOKEN_PRIVILEGES, | 
 | 					      DWORD, PTOKEN_PRIVILEGES, PDWORD); | 
 |  | 
 |   HANDLE token_hdl = NULL; | 
 |   LUID restore_priv; | 
 |   TOKEN_PRIVILEGES new_priv, orig_priv; | 
 |   int ret = -1; | 
 |   DWORD size; | 
 |  | 
 |   if (GetVersion () >= 0x80000000)  /* No security availbale on 9x/Me */ | 
 |     return 0; | 
 |  | 
 |   if (!advapi32) | 
 |     { | 
 |       if (!(advapi32 = LoadLibrary ("advapi32.dll"))) | 
 | 	goto out; | 
 |       if (!OpenProcessToken) | 
 | 	OpenProcessToken = GetProcAddress (advapi32, "OpenProcessToken"); | 
 |       if (!LookupPrivilegeValue) | 
 | 	LookupPrivilegeValue = GetProcAddress (advapi32, | 
 | 					       "LookupPrivilegeValueA"); | 
 |       if (!AdjustTokenPrivileges) | 
 | 	AdjustTokenPrivileges = GetProcAddress (advapi32, | 
 | 						"AdjustTokenPrivileges"); | 
 |       if (!OpenProcessToken || !LookupPrivilegeValue || !AdjustTokenPrivileges) | 
 | 	{ | 
 | 	  advapi32 = NULL; | 
 | 	  goto out; | 
 | 	} | 
 |     } | 
 |  | 
 |   if (!OpenProcessToken (GetCurrentProcess (), | 
 | 			 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, | 
 | 			 &token_hdl)) | 
 |     goto out; | 
 |  | 
 |   if (!LookupPrivilegeValue (NULL, privilege, &restore_priv)) | 
 |     goto out; | 
 |  | 
 |   new_priv.PrivilegeCount = 1; | 
 |   new_priv.Privileges[0].Luid = restore_priv; | 
 |   new_priv.Privileges[0].Attributes = enable ? SE_PRIVILEGE_ENABLED : 0; | 
 |  | 
 |   if (!AdjustTokenPrivileges (token_hdl, FALSE, &new_priv, | 
 | 			      sizeof orig_priv, &orig_priv, &size)) | 
 |     goto out; | 
 | #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(). */ | 
 |   /* 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) | 
 |     goto out; | 
 | #endif | 
 |  | 
 |   ret = orig_priv.Privileges[0].Attributes == SE_PRIVILEGE_ENABLED ? 1 : 0; | 
 |  | 
 | out: | 
 |   if (token_hdl) | 
 |     CloseHandle (token_hdl); | 
 |  | 
 |   return ret; | 
 | } | 
 |  | 
 | /* Attach to process PID, then initialize for debugging it.  */ | 
 | static void | 
 | win32_attach (char *args, int from_tty) | 
 | { | 
 |   BOOL ok; | 
 |   DWORD pid; | 
 |  | 
 |   if (!args) | 
 |     error_no_arg (_("process-id to attach")); | 
 |  | 
 |   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"); | 
 |     } | 
 |  | 
 |   pid = strtoul (args, 0, 0);		/* Windows pid */ | 
 |  | 
 |   win32_init_thread_list (); | 
 |   ok = DebugActiveProcess (pid); | 
 |   saw_create = 0; | 
 |  | 
 |   if (!ok) | 
 |     { | 
 |       /* Try fall back to Cygwin pid */ | 
 |       pid = cygwin_internal (CW_CYGWIN_PID_TO_WINPID, pid); | 
 |  | 
 |       if (pid > 0) | 
 | 	ok = DebugActiveProcess (pid); | 
 |  | 
 |       if (!ok) | 
 | 	error (_("Can't attach to process.")); | 
 |     } | 
 |  | 
 |   if (has_detach_ability ()) | 
 |     DebugSetProcessKillOnExit (FALSE); | 
 |  | 
 |   attach_flag = 1; | 
 |  | 
 |   if (from_tty) | 
 |     { | 
 |       char *exec_file = (char *) get_exec_file (0); | 
 |  | 
 |       if (exec_file) | 
 | 	printf_unfiltered ("Attaching to program `%s', %s\n", exec_file, | 
 | 			   target_pid_to_str (pid_to_ptid (pid))); | 
 |       else | 
 | 	printf_unfiltered ("Attaching to %s\n", | 
 | 			   target_pid_to_str (pid_to_ptid (pid))); | 
 |  | 
 |       gdb_flush (gdb_stdout); | 
 |     } | 
 |  | 
 |   do_initial_win32_stuff (pid); | 
 |   target_terminal_ours (); | 
 | } | 
 |  | 
 | static void | 
 | win32_detach (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)) | 
 | 	{ | 
 | 	  error (_("Can't detach process %lu (error %lu)"), | 
 | 		 current_event.dwProcessId, GetLastError ()); | 
 | 	  detached = 0; | 
 | 	} | 
 |       DebugSetProcessKillOnExit (FALSE); | 
 |     } | 
 |   if (detached && from_tty) | 
 |     { | 
 |       char *exec_file = get_exec_file (0); | 
 |       if (exec_file == 0) | 
 | 	exec_file = ""; | 
 |       printf_unfiltered ("Detaching from program: %s, Pid %lu\n", exec_file, | 
 | 			 current_event.dwProcessId); | 
 |       gdb_flush (gdb_stdout); | 
 |     } | 
 |   inferior_ptid = null_ptid; | 
 |   unpush_target (&win32_ops); | 
 | } | 
 |  | 
 | static char * | 
 | win32_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) | 
 |     { | 
 |       if (pinfo->dwProcessId == current_event.dwProcessId) /* Got it */ | 
 |        { | 
 | 	 cygwin_conv_to_full_posix_path (pinfo->progname, path); | 
 | 	 path_ptr = path; | 
 | 	 break; | 
 |        } | 
 |     } | 
 |   cygwin_internal (CW_UNLOCK_PINFO); | 
 |   return path_ptr; | 
 | } | 
 |  | 
 | /* Print status information about what we're accessing.  */ | 
 |  | 
 | static void | 
 | win32_files_info (struct target_ops *ignore) | 
 | { | 
 |   printf_unfiltered ("\tUsing the running image of %s %s.\n", | 
 |       attach_flag ? "attached" : "child", target_pid_to_str (inferior_ptid)); | 
 | } | 
 |  | 
 | static void | 
 | win32_open (char *arg, int from_tty) | 
 | { | 
 |   error (_("Use the \"run\" command to start a Unix child process.")); | 
 | } | 
 |  | 
 | /* Function called by qsort to sort environment strings.  */ | 
 | static int | 
 | env_sort (const void *a, const void *b) | 
 | {      | 
 |   const char **p = (const char **) a;  | 
 |   const char **q = (const char **) b; | 
 |   return strcasecmp (*p, *q); | 
 | } | 
 |  | 
 | /* Start an inferior win32 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 **in_env, | 
 | 		       int from_tty) | 
 | { | 
 |   char *winenv; | 
 |   char *temp; | 
 |   int envlen; | 
 |   int i; | 
 |   STARTUPINFO si; | 
 |   PROCESS_INFORMATION pi; | 
 |   BOOL ret; | 
 |   DWORD flags; | 
 |   char *args; | 
 |   char real_path[MAXPATHLEN]; | 
 |   char *toexec; | 
 |   char shell[MAX_PATH + 1]; /* Path to shell */ | 
 |   const char *sh; | 
 |   int tty; | 
 |   int ostdin, ostdout, ostderr; | 
 |   const char *inferior_io_terminal = get_inferior_io_terminal (); | 
 |  | 
 |   if (!exec_file) | 
 |     error (_("No executable specified, use `target exec'.")); | 
 |  | 
 |   memset (&si, 0, sizeof (si)); | 
 |   si.cb = sizeof (si); | 
 |  | 
 |   if (!useshell) | 
 |     { | 
 |       flags = DEBUG_ONLY_THIS_PROCESS; | 
 |       cygwin_conv_to_win32_path (exec_file, real_path); | 
 |       toexec = real_path; | 
 |     } | 
 |   else | 
 |     { | 
 |       char *newallargs; | 
 |       sh = getenv ("SHELL"); | 
 |       if (!sh) | 
 | 	sh = "/bin/sh"; | 
 |       cygwin_conv_to_win32_path (sh, shell); | 
 |       newallargs = alloca (sizeof (" -c 'exec  '") + strlen (exec_file) | 
 | 			   + strlen (allargs) + 2); | 
 |       sprintf (newallargs, " -c 'exec %s %s'", exec_file, allargs); | 
 |       allargs = newallargs; | 
 |       toexec = shell; | 
 |       flags = DEBUG_PROCESS; | 
 |     } | 
 |  | 
 |   if (new_group) | 
 |     flags |= CREATE_NEW_PROCESS_GROUP; | 
 |  | 
 |   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); | 
 |  | 
 |   /* 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; in_env[i] && *in_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], in_env[i], len) == 0) | 
 | 	      { | 
 | 		if (cygwin_posix_path_list_p (in_env[i] + len)) | 
 | 		  envlen += len | 
 | 		    + cygwin_posix_to_win32_path_list_buf_size (in_env[i] + len); | 
 | 		else | 
 | 		  envlen += strlen (in_env[i]) + 1; | 
 | 		break; | 
 | 	      } | 
 | 	  } | 
 | 	if (conv_path_names[j] == NULL) | 
 | 	  envlen += strlen (in_env[i]) + 1; | 
 |       } | 
 |  | 
 |     size_t envsize = sizeof (in_env[0]) * (i + 1); | 
 |     char **env = (char **) alloca (envsize); | 
 |     memcpy (env, in_env, envsize); | 
 |     /* Windows programs expect the environment block to be sorted.  */ | 
 |     qsort (env, i, sizeof (char *), env_sort); | 
 |  | 
 |     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; | 
 |   } | 
 |  | 
 |   if (!inferior_io_terminal) | 
 |     tty = ostdin = ostdout = ostderr = -1; | 
 |   else | 
 |     { | 
 |       tty = open (inferior_io_terminal, O_RDWR | O_NOCTTY); | 
 |       if (tty < 0) | 
 | 	{ | 
 | 	  print_sys_errmsg (inferior_io_terminal, errno); | 
 | 	  ostdin = ostdout = ostderr = -1; | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  ostdin = dup (0); | 
 | 	  ostdout = dup (1); | 
 | 	  ostderr = dup (2); | 
 | 	  dup2 (tty, 0); | 
 | 	  dup2 (tty, 1); | 
 | 	  dup2 (tty, 2); | 
 | 	} | 
 |     } | 
 |  | 
 |   win32_init_thread_list (); | 
 |   ret = CreateProcess (0, | 
 | 		       args,	/* command line */ | 
 | 		       NULL,	/* Security */ | 
 | 		       NULL,	/* thread */ | 
 | 		       TRUE,	/* inherit handles */ | 
 | 		       flags,	/* start flags */ | 
 | 		       winenv, | 
 | 		       NULL,	/* current directory */ | 
 | 		       &si, | 
 | 		       &pi); | 
 |   if (tty >= 0) | 
 |     { | 
 |       close (tty); | 
 |       dup2 (ostdin, 0); | 
 |       dup2 (ostdout, 1); | 
 |       dup2 (ostderr, 2); | 
 |       close (ostdin); | 
 |       close (ostdout); | 
 |       close (ostderr); | 
 |     } | 
 |  | 
 |   if (!ret) | 
 |     error (_("Error creating process %s, (error %d)."), | 
 | 	   exec_file, (unsigned) GetLastError ()); | 
 |  | 
 |   CloseHandle (pi.hThread); | 
 |   CloseHandle (pi.hProcess); | 
 |  | 
 |   if (useshell && shell[0] != '\0') | 
 |     saw_create = -1; | 
 |   else | 
 |     saw_create = 0; | 
 |  | 
 |   do_initial_win32_stuff (pi.dwProcessId); | 
 |  | 
 |   /* win32_continue (DBG_CONTINUE, -1); */ | 
 | } | 
 |  | 
 | static void | 
 | win32_mourn_inferior (void) | 
 | { | 
 |   (void) win32_continue (DBG_CONTINUE, -1); | 
 |   i386_cleanup_dregs(); | 
 |   unpush_target (&win32_ops); | 
 |   generic_mourn_inferior (); | 
 | } | 
 |  | 
 | /* Send a SIGINT to the process group.  This acts just like the user typed a | 
 |    ^C on the controlling terminal. */ | 
 |  | 
 | static void | 
 | win32_stop (void) | 
 | { | 
 |   DEBUG_EVENTS (("gdb: GenerateConsoleCtrlEvent (CTRLC_EVENT, 0)\n")); | 
 |   CHECK (GenerateConsoleCtrlEvent (CTRL_C_EVENT, current_event.dwProcessId)); | 
 |   registers_changed ();		/* refresh register state */ | 
 | } | 
 |  | 
 | static int | 
 | win32_xfer_memory (CORE_ADDR memaddr, gdb_byte *our, int len, | 
 | 		   int write, struct mem_attrib *mem, | 
 | 		   struct target_ops *target) | 
 | { | 
 |   DWORD 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, &done)) | 
 | 	done = 0; | 
 |       FlushInstructionCache (current_process_handle, (LPCVOID) 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, &done)) | 
 | 	done = 0; | 
 |     } | 
 |   return done; | 
 | } | 
 |  | 
 | static void | 
 | win32_kill_inferior (void) | 
 | { | 
 |   CHECK (TerminateProcess (current_process_handle, 0)); | 
 |  | 
 |   for (;;) | 
 |     { | 
 |       if (!win32_continue (DBG_CONTINUE, -1)) | 
 | 	break; | 
 |       if (!WaitForDebugEvent (¤t_event, INFINITE)) | 
 | 	break; | 
 |       if (current_event.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) | 
 | 	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? */ | 
 | } | 
 |  | 
 | static void | 
 | win32_prepare_to_store (void) | 
 | { | 
 |   /* Do nothing, since we can store individual regs */ | 
 | } | 
 |  | 
 | static int | 
 | win32_can_run (void) | 
 | { | 
 |   return 1; | 
 | } | 
 |  | 
 | static void | 
 | win32_close (int x) | 
 | { | 
 |   DEBUG_EVENTS (("gdb: win32_close, inferior_ptid=%d\n", | 
 | 		PIDGET (inferior_ptid))); | 
 | } | 
 |  | 
 | /* Convert pid to printable format. */ | 
 | static char * | 
 | cygwin_pid_to_str (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; | 
 | } | 
 |  | 
 | typedef struct | 
 | { | 
 |   struct target_ops *target; | 
 |   bfd_vma addr; | 
 | } map_code_section_args; | 
 |  | 
 | static void | 
 | map_single_dll_code_section (bfd *abfd, asection *sect, void *obj) | 
 | { | 
 |   int old; | 
 |   int update_coreops; | 
 |   struct section_table *new_target_sect_ptr; | 
 |  | 
 |   map_code_section_args *args = (map_code_section_args *) obj; | 
 |   struct target_ops *target = args->target; | 
 |   if (sect->flags & SEC_CODE) | 
 |     { | 
 |       update_coreops = core_ops.to_sections == target->to_sections; | 
 |  | 
 |       if (target->to_sections) | 
 | 	{ | 
 | 	  old = target->to_sections_end - target->to_sections; | 
 | 	  target->to_sections = (struct section_table *) | 
 | 	    xrealloc ((char *) target->to_sections, | 
 | 		      (sizeof (struct section_table)) * (1 + old)); | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  old = 0; | 
 | 	  target->to_sections = (struct section_table *) | 
 | 	    xmalloc ((sizeof (struct section_table))); | 
 | 	} | 
 |       target->to_sections_end = target->to_sections + (1 + old); | 
 |  | 
 |       /* Update the to_sections field in the core_ops structure | 
 | 	 if needed.  */ | 
 |       if (update_coreops) | 
 | 	{ | 
 | 	  core_ops.to_sections = target->to_sections; | 
 | 	  core_ops.to_sections_end = target->to_sections_end; | 
 | 	} | 
 |       new_target_sect_ptr = target->to_sections + old; | 
 |       new_target_sect_ptr->addr = args->addr + bfd_section_vma (abfd, sect); | 
 |       new_target_sect_ptr->endaddr = args->addr + bfd_section_vma (abfd, sect) + | 
 | 	bfd_section_size (abfd, sect);; | 
 |       new_target_sect_ptr->the_bfd_section = sect; | 
 |       new_target_sect_ptr->bfd = abfd; | 
 |     } | 
 | } | 
 |  | 
 | static int | 
 | dll_code_sections_add (const char *dll_name, int base_addr, struct target_ops *target) | 
 | { | 
 |   bfd *dll_bfd; | 
 |   map_code_section_args map_args; | 
 |   asection *lowest_sect; | 
 |   char *name; | 
 |   if (dll_name == NULL || target == NULL) | 
 |     return 0; | 
 |   name = xstrdup (dll_name); | 
 |   dll_bfd = bfd_openr (name, "pei-i386"); | 
 |   if (dll_bfd == NULL) | 
 |     return 0; | 
 |  | 
 |   if (bfd_check_format (dll_bfd, bfd_object)) | 
 |     { | 
 |       lowest_sect = bfd_get_section_by_name (dll_bfd, ".text"); | 
 |       if (lowest_sect == NULL) | 
 | 	return 0; | 
 |       map_args.target = target; | 
 |       map_args.addr = base_addr - bfd_section_vma (dll_bfd, lowest_sect); | 
 |  | 
 |       bfd_map_over_sections (dll_bfd, &map_single_dll_code_section, (void *) (&map_args)); | 
 |     } | 
 |  | 
 |   return 1; | 
 | } | 
 |  | 
 | static void | 
 | core_section_load_dll_symbols (bfd *abfd, asection *sect, void *obj) | 
 | { | 
 |   struct target_ops *target = (struct target_ops *) obj; | 
 |  | 
 |   DWORD base_addr; | 
 |  | 
 |   int dll_name_size; | 
 |   struct win32_pstatus *pstatus; | 
 |   struct so_list *so; | 
 |   char *dll_name; | 
 |   char *buf = NULL; | 
 |   char *p; | 
 |   struct objfile *objfile; | 
 |   const char *dll_basename; | 
 |  | 
 |   if (strncmp (sect->name, ".module", 7) != 0) | 
 |     return; | 
 |  | 
 |   buf = (char *) xmalloc (bfd_get_section_size (sect) + 1); | 
 |   if (!buf) | 
 |     { | 
 |       printf_unfiltered ("memory allocation failed for %s\n", sect->name); | 
 |       goto out; | 
 |     } | 
 |   if (!bfd_get_section_contents (abfd, sect, buf, 0, bfd_get_section_size (sect))) | 
 |     goto out; | 
 |  | 
 |   pstatus = (struct win32_pstatus *) buf; | 
 |  | 
 |   memmove (&base_addr, &(pstatus->data.module_info.base_address), sizeof (base_addr)); | 
 |   dll_name_size = pstatus->data.module_info.module_name_size; | 
 |   if (offsetof (struct win32_pstatus, data.module_info.module_name) + dll_name_size > bfd_get_section_size (sect)) | 
 |       goto out; | 
 |  | 
 |   dll_name = pstatus->data.module_info.module_name; | 
 |  | 
 |   if (!(dll_basename = strrchr (dll_name, '/'))) | 
 |     dll_basename = dll_name; | 
 |   else | 
 |     dll_basename++; | 
 |  | 
 |   ALL_OBJFILES (objfile) | 
 |   { | 
 |     char *objfile_basename = strrchr (objfile->name, '/'); | 
 |  | 
 |     if (objfile_basename && | 
 | 	strcasecmp (dll_basename, objfile_basename + 1) == 0) | 
 |       goto out; | 
 |   } | 
 |  | 
 |   base_addr += 0x1000; | 
 |   dll_name = register_loaded_dll (dll_name, base_addr, 1); | 
 |  | 
 |   if (!dll_code_sections_add (dll_name, (DWORD) base_addr, target)) | 
 |     printf_unfiltered ("%s: Failed to map dll code sections.\n", dll_name); | 
 |  | 
 | out: | 
 |   if (buf) | 
 |     xfree (buf); | 
 |   return; | 
 | } | 
 |  | 
 | static struct so_list * | 
 | win32_current_sos (void) | 
 | { | 
 |   struct so_list *sop; | 
 |   struct so_list *start = NULL; | 
 |   struct so_list *last = NULL; | 
 |  | 
 |   if (!solib_start.next && core_bfd) | 
 |     { | 
 |       win32_clear_solib (); | 
 |       bfd_map_over_sections (core_bfd, &core_section_load_dll_symbols, | 
 | 			     &win32_ops); | 
 |     } | 
 |  | 
 |   for (sop = solib_start.next; sop; sop = sop->next) | 
 |     { | 
 |       struct so_list *new = XZALLOC (struct so_list); | 
 |       strcpy (new->so_name, sop->so_name); | 
 |       strcpy (new->so_original_name, sop->so_original_name); | 
 |       if (!start) | 
 | 	last = start = new; | 
 |       else | 
 | 	{ | 
 | 	  last->next = new; | 
 | 	  last = new; | 
 | 	} | 
 |     } | 
 |  | 
 |   return start; | 
 | } | 
 |  | 
 | static void | 
 | fetch_elf_core_registers (char *core_reg_sect, | 
 | 			  unsigned core_reg_size, | 
 | 			  int which, | 
 | 			  CORE_ADDR reg_addr) | 
 | { | 
 |   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]); | 
 | } | 
 |  | 
 | static int | 
 | open_symbol_file_object (void *from_ttyp) | 
 | { | 
 |   return 0; | 
 | } | 
 |  | 
 | static int | 
 | in_dynsym_resolve_code (CORE_ADDR pc) | 
 | { | 
 |   return 0; | 
 | } | 
 |  | 
 | static void | 
 | init_win32_ops (void) | 
 | { | 
 |   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 = win32_solib_create_inferior_hook; | 
 |   win32_so_ops.special_symbol_handling = win32_special_symbol_handling; | 
 |   win32_so_ops.current_sos = win32_current_sos; | 
 |   win32_so_ops.open_symbol_file_object = open_symbol_file_object; | 
 |   win32_so_ops.in_dynsym_resolve_code = in_dynsym_resolve_code; | 
 |  | 
 |   /* FIXME: Don't do this here.  *_gdbarch_init() should set so_ops. */ | 
 |   current_target_so_ops = &win32_so_ops; | 
 | } | 
 |  | 
 | static void | 
 | set_win32_aliases (char *argv0) | 
 | { | 
 |   add_info_alias ("dll", "sharedlibrary", 1); | 
 | } | 
 |  | 
 | void | 
 | _initialize_win32_nat (void) | 
 | { | 
 |   struct cmd_list_element *c; | 
 |  | 
 |   init_win32_ops (); | 
 |  | 
 |   c = add_com ("dll-symbols", class_files, dll_symbol_command, | 
 | 	       _("Load dll library symbols from FILE.")); | 
 |   set_cmd_completer (c, filename_completer); | 
 |  | 
 |   add_com_alias ("sharedlibrary", "dll-symbols", class_alias, 1); | 
 |  | 
 |   add_setshow_boolean_cmd ("shell", class_support, &useshell, _("\ | 
 | Set use of shell to start subprocess."), _("\ | 
 | Show use of shell to start subprocess."), NULL, | 
 | 			   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); | 
 |  | 
 |   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, | 
 | 			   NULL, | 
 | 			   NULL, /* FIXME: i18n: */ | 
 | 			   &setlist, &showlist); | 
 |  | 
 |   add_setshow_boolean_cmd ("new-group", class_support, &new_group, _("\ | 
 | Set creation of new group when creating child process."), _("\ | 
 | Show creation of new group when creating child process."), NULL, | 
 | 			   NULL, | 
 | 			   NULL, /* FIXME: i18n: */ | 
 | 			   &setlist, &showlist); | 
 |  | 
 |   add_setshow_boolean_cmd ("debugexec", class_support, &debug_exec, _("\ | 
 | Set whether to display execution in child process."), _("\ | 
 | Show whether to display execution in child process."), NULL, | 
 | 			   NULL, | 
 | 			   NULL, /* FIXME: i18n: */ | 
 | 			   &setlist, &showlist); | 
 |  | 
 |   add_setshow_boolean_cmd ("debugevents", class_support, &debug_events, _("\ | 
 | Set whether to display kernel events in child process."), _("\ | 
 | Show whether to display kernel events in child process."), NULL, | 
 | 			   NULL, | 
 | 			   NULL, /* FIXME: i18n: */ | 
 | 			   &setlist, &showlist); | 
 |  | 
 |   add_setshow_boolean_cmd ("debugmemory", class_support, &debug_memory, _("\ | 
 | Set whether to display memory accesses in child process."), _("\ | 
 | Show whether to display memory accesses in child process."), NULL, | 
 | 			   NULL, | 
 | 			   NULL, /* FIXME: i18n: */ | 
 | 			   &setlist, &showlist); | 
 |  | 
 |   add_setshow_boolean_cmd ("debugexceptions", class_support, | 
 | 			   &debug_exceptions, _("\ | 
 | Set whether to display kernel exceptions in child process."), _("\ | 
 | Show whether to display kernel exceptions in child process."), NULL, | 
 | 			   NULL, | 
 | 			   NULL, /* FIXME: i18n: */ | 
 | 			   &setlist, &showlist); | 
 |  | 
 |   add_prefix_cmd ("w32", class_info, info_w32_command, | 
 | 		  _("Print information specific to Win32 debugging."), | 
 | 		  &info_w32_cmdlist, "info w32 ", 0, &infolist); | 
 |  | 
 |   add_cmd ("selector", class_info, display_selectors, | 
 | 	   _("Display selectors infos."), | 
 | 	   &info_w32_cmdlist); | 
 |   add_target (&win32_ops); | 
 |   deprecated_init_ui_hook = set_win32_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.  */ | 
 | void | 
 | cygwin_set_dr (int i, CORE_ADDR addr) | 
 | { | 
 |   if (i < 0 || i > 3) | 
 |     internal_error (__FILE__, __LINE__, | 
 | 		    _("Invalid register %d in cygwin_set_dr.\n"), i); | 
 |   dr[i] = (unsigned) addr; | 
 |   debug_registers_changed = 1; | 
 |   debug_registers_used = 1; | 
 | } | 
 |  | 
 | /* 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.  */ | 
 | void | 
 | cygwin_set_dr7 (unsigned val) | 
 | { | 
 |   dr[7] = val; | 
 |   debug_registers_changed = 1; | 
 |   debug_registers_used = 1; | 
 | } | 
 |  | 
 | /* 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.  */ | 
 | unsigned | 
 | cygwin_get_dr6 (void) | 
 | { | 
 |   return dr[6]; | 
 | } | 
 |  | 
 | /* Determine if the thread referenced by "pid" 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. */ | 
 | 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 struct core_fns win32_elf_core_fns = | 
 | { | 
 |   bfd_target_elf_flavour, | 
 |   default_check_format, | 
 |   default_core_sniffer, | 
 |   fetch_elf_core_registers, | 
 |   NULL | 
 | }; | 
 |  | 
 | void | 
 | _initialize_core_win32 (void) | 
 | { | 
 |   deprecated_add_core_fns (&win32_elf_core_fns); | 
 | } | 
 |  | 
 | void | 
 | _initialize_check_for_gdb_ini (void) | 
 | { | 
 |   char *homedir; | 
 |   if (inhibit_gdbinit) | 
 |     return; | 
 |  | 
 |   homedir = getenv ("HOME"); | 
 |   if (homedir) | 
 |     { | 
 |       char *p; | 
 |       char *oldini = (char *) alloca (strlen (homedir) + | 
 | 				      sizeof ("/gdb.ini")); | 
 |       strcpy (oldini, homedir); | 
 |       p = strchr (oldini, '\0'); | 
 |       if (p > oldini && 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); | 
 | 	  warning (_("obsolete '%s' found. Rename to '%s'."), oldini, newini); | 
 | 	} | 
 |     } | 
 | } |