X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fwindows-nat.c;h=06294bf93bc527b0f7ec41993149757a3f4bbad7;hb=8234eceb5e01be43eca70dbacdb869fc66dbed0a;hp=358bdf7a9f53234e0e188df1ab3983ad64b72453;hpb=6c7de4224ecf600584d3b0bd2ec5c671aa3d9be6;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c index 358bdf7a9f..06294bf93b 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. - Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 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,27 +9,24 @@ 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" #include "target.h" +#include "exceptions.h" #include "gdbcore.h" #include "command.h" #include "completer.h" @@ -41,23 +38,40 @@ #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" #include #include #include "exec.h" +#include "solist.h" +#include "solib.h" +#include "xml-support.h" #include "i386-tdep.h" #include "i387-tdep.h" -/* The ui's event loop. */ -extern int (*ui_loop_hook) (int signo); +#include "i386-cygwin-tdep.h" + +static struct target_ops win32_ops; + +#ifdef __CYGWIN__ +/* The starting and ending address of the cygwin1.dll text segment. */ +static bfd_vma cygwin_load_start; +static bfd_vma 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 @@ -69,19 +83,21 @@ enum CONTEXT_DEBUGGER = (CONTEXT_FULL | CONTEXT_FLOATING_POINT) }; #endif -#include #include #define CONTEXT_DEBUGGER_DR CONTEXT_DEBUGGER | CONTEXT_DEBUG_REGISTERS \ | CONTEXT_EXTENDED_REGISTERS static unsigned dr[8]; -static int debug_registers_changed = 0; -static int debug_registers_used = 0; +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 @@ -89,25 +105,23 @@ static int debug_registers_used = 0; #define DEBUG_MEM(x) if (debug_memory) printf_unfiltered x #define DEBUG_EXCEPT(x) if (debug_exceptions) printf_unfiltered x -/* Forward declaration */ -extern struct target_ops child_ops; - -static void child_stop (void); -static int win32_child_thread_alive (ptid_t); -void child_kill_inferior (void); +static void win32_stop (ptid_t); +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. */ + 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 +141,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 */ @@ -228,10 +246,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) { @@ -240,25 +257,22 @@ 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; - else if (get_context < 0) - th->suspend_count = -1; - - th->context.ContextFlags = CONTEXT_DEBUGGER_DR; - GetThreadContext (th->h, &th->context); - if (id == current_event.dwThreadId) { - /* 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; + 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->suspended = -1; + th->reload_context = 1; } return th; } @@ -266,23 +280,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 * -child_add_thread (DWORD id, HANDLE h) +win32_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. */ @@ -292,8 +310,7 @@ child_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; @@ -304,30 +321,35 @@ child_add_thread (DWORD id, HANDLE h) /* Clear out any old thread list and reintialize it to a pristine state. */ static void -child_init_thread_list (void) +win32_init_thread_list (void) { thread_info *th = &thread_head; - DEBUG_EVENTS (("gdb: child_init_thread_list\n")); + 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 -child_delete_thread (DWORD id) +win32_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; @@ -338,150 +360,182 @@ child_delete_thread (DWORD id) { thread_info *here = th->next; th->next = here->next; - CloseHandle (here->h); xfree (here); } } static void -do_child_fetch_inferior_registers (int r) +do_win32_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; -#define I387_ST0_REGNUM I386_ST0_REGNUM + 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. + 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; + } - if (r == I387_FISEG_REGNUM) + if (r == I387_FISEG_REGNUM (tdep)) { l = *((long *) context_offset) & 0xffff; - supply_register (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); - supply_register (r, (char *) &l); + regcache_raw_supply (regcache, r, (char *) &l); } else if (r >= 0) - supply_register (r, context_offset); + regcache_raw_supply (regcache, r, context_offset); else { - for (r = 0; r < NUM_REGS; r++) - do_child_fetch_inferior_registers (r); + for (r = 0; r < gdbarch_num_regs (gdbarch); r++) + do_win32_fetch_inferior_registers (regcache, r); } - -#undef I387_ST0_REGNUM } static void -child_fetch_inferior_registers (int r) +win32_fetch_inferior_registers (struct regcache *regcache, int r) { - current_thread = thread_rec (PIDGET (inferior_ptid), TRUE); - do_child_fetch_inferior_registers (r); + current_thread = thread_rec (ptid_get_tid (inferior_ptid), TRUE); + /* Check if current_thread exists. Windows sometimes uses a non-existent + thread id in its events */ + if (current_thread) + do_win32_fetch_inferior_registers (regcache, r); } static void -do_child_store_inferior_registers (int r) +do_win32_store_inferior_registers (const struct regcache *regcache, int r) { - if (r >= 0) - regcache_collect (r, ((char *) ¤t_thread->context) + mappings[r]); + if (!current_thread) + /* Windows sometimes uses a non-existent thread id in its events */; + else if (r >= 0) + regcache_raw_collect (regcache, r, + ((char *) ¤t_thread->context) + mappings[r]); else { - for (r = 0; r < NUM_REGS; r++) - do_child_store_inferior_registers (r); + for (r = 0; r < gdbarch_num_regs (get_regcache_arch (regcache)); r++) + do_win32_store_inferior_registers (regcache, r); } } /* Store a new register value into the current thread context */ static void -child_store_inferior_registers (int r) +win32_store_inferior_registers (struct regcache *regcache, int r) { - current_thread = thread_rec (PIDGET (inferior_ptid), TRUE); - do_child_store_inferior_registers (r); + current_thread = thread_rec (ptid_get_tid (inferior_ptid), TRUE); + /* Check if current_thread exists. Windows sometimes uses a non-existent + thread id in its events */ + if (current_thread) + do_win32_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; - -int -psapi_get_dll_name (DWORD BaseAddress, char *dll_name_ret) +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 +get_module_name (DWORD 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))) - 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\n", (unsigned) GetLastError ()); - - if ((DWORD) (mi.lpBaseOfDll) == BaseAddress) - return 1; + /* Get information on this module */ + if (!psapi_GetModuleInformation (current_process_handle, DllHandle[i], + &mi, sizeof (mi))) + error (_("Can't get module info")); + + if (!base_address || (DWORD) (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 @@ -498,27 +552,19 @@ struct safe_symbol_file_add_args }; /* Maintain a linked list of "so" information. */ -struct so_stuff +struct lm_info { - struct so_stuff *next; DWORD load_addr; - DWORD end_addr; - int loaded; - struct objfile *objfile; - char name[1]; -} solib_start, *solib_end; +}; + +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_stuff *so = &solib_start; - - while ((so = so->next)) - if (so->loaded && strcasecmp (so->name, p->name) == 0) - return 0; +#define p ((struct safe_symbol_file_add_args *) argv) p->ret = symbol_file_add (p->name, p->from_tty, p->addrs, p->mainline, p->flags); return !!p->ret; #undef p @@ -566,21 +612,16 @@ safe_symbol_file_add (char *name, int from_tty, return p.ret; } -/* Remember the maximum DLL length for printing in info dll command. */ -int max_dll_name_len; - -static void -register_loaded_dll (const char *name, DWORD load_addr) +static struct so_list * +win32_make_so (const char *name, DWORD load_addr) { - struct so_stuff *so; - char ppath[MAX_PATH + 1]; + 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); @@ -599,28 +640,55 @@ register_loaded_dll (const char *name, DWORD load_addr) } } - cygwin_conv_to_posix_path (buf, ppath); - so = (struct so_stuff *) xmalloc (sizeof (struct so_stuff) + strlen (ppath) + 8 + 1); - so->loaded = 0; - so->load_addr = load_addr; - if (VirtualQueryEx (current_process_handle, (void *) load_addr, &m, - sizeof (m))) - so->end_addr = (DWORD) m.AllocationBase + m.RegionSize; - else - so->end_addr = load_addr + 0x2000; /* completely arbitrary */ + 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; + 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"); - so->next = NULL; - so->objfile = NULL; - strcpy (so->name, ppath); + if (!abfd) + return so; - solib_end->next = so; - solib_end = so; - len = strlen (ppath); - if (len > max_dll_name_len) - max_dll_name_len = len; + if (bfd_check_format (abfd, bfd_object)) + text = bfd_get_section_by_name (abfd, ".text"); + + if (!text) + { + bfd_close (abfd); + return so; + } + + /* 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 = load_addr + 0x1000; + cygwin_load_end = cygwin_load_start + bfd_section_size (abfd, text); + + bfd_close (abfd); + } +#endif + + return so; } -char * +static char * get_image_name (HANDLE h, void *address, int unicode) { static char buf[(2 * MAX_PATH) + 1]; @@ -669,189 +737,68 @@ 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 ((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); + 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 = win32_make_so (dll_name, (DWORD) event->lpBaseOfDll); + solib_end = solib_end->next; + + DEBUG_EVENTS (("gdb: Loading dll \"%s\" at 0x%lx.\n", solib_end->so_name, + (DWORD) solib_end->lm_info->load_addr)); return 1; } +static void +win32_free_so (struct so_list *so) +{ + if (so->lm_info) + xfree (so->lm_info); + xfree (so); +} + static int handle_unload_dll (void *dummy) { - DWORD lpBaseOfDll = (DWORD) current_event.u.UnloadDll.lpBaseOfDll + 0x1000; - struct so_stuff *so; + DWORD lpBaseOfDll = (DWORD) current_event.u.UnloadDll.lpBaseOfDll; + struct so_list *so; for (so = &solib_start; so->next != NULL; so = so->next) - if (so->next->load_addr == lpBaseOfDll) + if (so->next->lm_info->load_addr == lpBaseOfDll) { - struct so_stuff *sodel = so->next; + struct so_list *sodel = so->next; so->next = sodel->next; if (!so->next) solib_end = so; - if (sodel->objfile) - free_objfile (sodel->objfile); - xfree(sodel); + DEBUG_EVENTS (("gdb: Unloading dll \"%s\".\n", sodel->so_name)); + + win32_free_so (sodel); + solib_add (NULL, 0, NULL, auto_solib_add); return 1; } - error ("Error: dll starting at 0x%lx not found.\n", (DWORD) lpBaseOfDll); - - return 0; -} -char * -solib_address (CORE_ADDR address) -{ - struct so_stuff *so; - for (so = &solib_start; so->next != NULL; so = so->next) - if (address >= so->load_addr && address <= so->end_addr) - return so->name; - return NULL; -} + error (_("Error: dll starting at 0x%lx not found."), (DWORD) lpBaseOfDll); -/* Return name of last loaded DLL. */ -char * -child_solib_loaded_library_pathname (int pid) -{ - return !solib_end || !solib_end->name[0] ? NULL : solib_end->name; + return 0; } /* Clear list of loaded DLLs. */ -void -child_clear_solibs (void) +static void +win32_clear_solib (void) { - struct so_stuff *so, *so1 = solib_start.next; - - while ((so = so1) != NULL) - { - so1 = so->next; - xfree (so); - } - solib_start.next = NULL; - solib_start.objfile = NULL; solib_end = &solib_start; - max_dll_name_len = sizeof ("DLL Name") - 1; -} - -/* 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 struct objfile * -solib_symbols_add (char *name, int from_tty, CORE_ADDR load_addr) -{ - struct section_addr_info *addrs = NULL; - static struct objfile *result = NULL; - bfd *abfd = NULL; - - /* 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 NULL; - - 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); - } - - bfd_close (abfd); - } - - if (addrs) - { - result = safe_symbol_file_add (name, from_tty, 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, from_tty, addrs, 0, OBJF_SHARED); - do_cleanups (my_cleanups); - } - - return result; } /* Load DLL symbol info. */ @@ -862,7 +809,7 @@ dll_symbol_command (char *args, int from_tty) dont_repeat (); if (args == NULL) - error ("dll-symbols requires a file name"); + error (_("dll-symbols requires a file name")); n = strlen (args); if (n > 4 && strcasecmp (args + n - 4, ".dll") != 0) @@ -876,53 +823,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. */ -void -info_dll_command (char *ignore, int from_tty) -{ - struct so_stuff *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->name, so->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) - warning ("%s", s); +#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 @@ -1065,6 +1019,23 @@ 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; + bfd_vma addr = (bfd_vma) (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"); @@ -1139,8 +1110,9 @@ 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; + 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); @@ -1155,7 +1127,7 @@ handle_exception (struct target_waitstatus *ourstatus) /* Resume all artificially suspended threads if we are continuing execution */ static BOOL -child_continue (DWORD continue_status, int id) +win32_continue (DWORD continue_status, int id) { int i; thread_info *th; @@ -1165,47 +1137,160 @@ child_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) + + 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); + 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 (ptid_build (current_event.dwProcessId, 0, + current_event.dwThreadId), + 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; + + /* 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: win32_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 */ + win32_fetch_inferior_registers (get_current_regcache (), + gdbarch_ps_regnum (current_gdbarch)); + th->context.EFlags |= FLAG_TRACE_BIT; + } - for (i = 0; i < th->suspend_count; i++) - (void) ResumeThread (th->h); - th->suspend_count = 0; + if (th->context.ContextFlags) + { if (debug_registers_changed) { - /* Only change the value of the debug reisters */ - 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.Dr6 = DR6_CLEAR_VALUE; th->context.Dr7 = dr[7]; - CHECK (SetThreadContext (th->h, &th->context)); - th->context.ContextFlags = 0; } + CHECK (SetThreadContext (th->h, &th->context)); + th->context.ContextFlags = 0; } + } - debug_registers_changed = 0; - return res; + /* Allow continuing with the same signal that interrupted us. + Otherwise complain. */ + + if (resume_all) + win32_continue (continue_status, -1); + else + win32_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_child_debug_event (int pid, struct target_waitstatus *ourstatus) +get_win32_debug_event (int pid, struct target_waitstatus *ourstatus) { BOOL debug_event; DWORD continue_status, event_code; - thread_info *th = NULL; + thread_info *th; static thread_info dummy_thread_info; int retval = 0; @@ -1219,6 +1304,8 @@ get_child_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) { @@ -1228,15 +1315,25 @@ get_child_debug_event (int pid, struct target_waitstatus *ourstatus) (unsigned) current_event.dwThreadId, "CREATE_THREAD_DEBUG_EVENT")); if (saw_create != 1) - break; + { + 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 = fake_create_process (); + if (retval) + saw_create++; + } + break; + } /* Record the existence of this thread */ - th = child_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 = win32_add_thread (ptid_build (current_event.dwProcessId, 0, + current_event.dwThreadId), + current_event.u.CreateThread.hThread); break; case EXIT_THREAD_DEBUG_EVENT: @@ -1244,10 +1341,12 @@ get_child_debug_event (int pid, struct target_waitstatus *ourstatus) (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId, "EXIT_THREAD_DEBUG_EVENT")); - if (saw_create != 1) - break; - child_delete_thread (current_event.dwThreadId); - th = &dummy_thread_info; + if (current_event.dwThreadId != main_thread_id) + { + win32_delete_thread (ptid_build (current_event.dwProcessId, 0, + current_event.dwThreadId)); + th = &dummy_thread_info; + } break; case CREATE_PROCESS_DEBUG_EVENT: @@ -1257,21 +1356,18 @@ get_child_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 (ptid_build (current_event.dwProcessId, 0, + main_thread_id)); main_thread_id = current_event.dwThreadId; /* Add the main thread */ -#if 0 - th = child_add_thread (current_event.dwProcessId, - current_event.u.CreateProcessInfo.hProcess); -#endif - th = child_add_thread (main_thread_id, + th = win32_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: @@ -1283,7 +1379,6 @@ get_child_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; @@ -1296,11 +1391,9 @@ get_child_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: @@ -1311,9 +1404,9 @@ get_child_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: @@ -1323,8 +1416,19 @@ get_child_debug_event (int pid, struct target_waitstatus *ourstatus) "EXCEPTION_DEBUG_EVENT")); if (saw_create != 1) break; - if (handle_exception (ourstatus)) - retval = current_event.dwThreadId; + 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 */ @@ -1334,8 +1438,7 @@ get_child_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: @@ -1350,22 +1453,30 @@ get_child_debug_event (int pid, struct target_waitstatus *ourstatus) } if (!retval || saw_create != 1) - CHECK (child_continue (continue_status, -1)); + { + if (continue_status == -1) + win32_resume (minus_one_ptid, 0, 1); + else + CHECK (win32_continue (continue_status, -1)); + } else { - current_thread = th ? : thread_rec (current_event.dwThreadId, TRUE); - inferior_ptid = pid_to_ptid (retval); + inferior_ptid = ptid_build (current_event.dwProcessId, 0, + retval); + current_thread = th ?: thread_rec (current_event.dwThreadId, TRUE); } 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 -child_wait (ptid_t ptid, struct target_waitstatus *ourstatus) +win32_wait (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, @@ -1375,56 +1486,92 @@ child_wait (ptid_t ptid, struct target_waitstatus *ourstatus) while (1) { - int retval = get_child_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_win32_debug_event (pid, ourstatus); + SetConsoleCtrlHandler (NULL, FALSE); + if (retval) - return pid_to_ptid (retval); + return ptid_build (current_event.dwProcessId, 0, retval); else { int detach = 0; - if (ui_loop_hook != NULL) - detach = ui_loop_hook (0); + if (deprecated_ui_loop_hook != NULL) + detach = deprecated_ui_loop_hook (0); if (detach) - child_kill_inferior (); + win32_kill_inferior (); } } } static void -do_initial_child_stuff (DWORD pid) +do_initial_win32_stuff (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 (&child_ops); - child_init_thread_list (); - disable_breakpoints_in_shlibs (1); - child_clear_solibs (); + push_target (&win32_ops); + disable_breakpoints_in_shlibs (); + win32_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 win32_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; } @@ -1519,7 +1666,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 - child_attach(). */ + 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) @@ -1537,13 +1684,13 @@ out: /* Attach to process PID, then initialize for debugging it. */ static void -child_attach (char *args, int from_tty) +win32_attach (struct target_ops *ops, char *args, int from_tty) { BOOL ok; DWORD pid; if (!args) - error_no_arg ("process-id to attach"); + error_no_arg (_("process-id to attach")); if (set_process_privilege (SE_DEBUG_NAME, TRUE) < 0) { @@ -1553,9 +1700,11 @@ child_attach (char *args, int from_tty) pid = strtoul (args, 0, 0); /* Windows pid */ + win32_init_thread_list (); ok = DebugActiveProcess (pid); saw_create = 0; +#ifdef __CYGWIN__ if (!ok) { /* Try fall back to Cygwin pid */ @@ -1563,16 +1712,14 @@ child_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 ()) - { - attach_flag = 1; - DebugSetProcessKillOnExit (FALSE); - } + DebugSetProcessKillOnExit (FALSE); if (from_tty) { @@ -1588,22 +1735,23 @@ child_attach (char *args, int from_tty) gdb_flush (gdb_stdout); } - do_initial_child_stuff (pid); + do_initial_win32_stuff (pid, 1); target_terminal_ours (); } static void -child_detach (char *args, int from_tty) +win32_detach (struct target_ops *ops, char *args, int from_tty) { int detached = 1; if (has_detach_ability ()) { - delete_command (NULL, 0); - child_continue (DBG_CONTINUE, -1); + ptid_t ptid = {-1}; + win32_resume (ptid, 0, TARGET_SIGNAL_0); + if (!DebugActiveProcessStop (current_event.dwProcessId)) { - error ("Can't detach process %lu (error %lu)", + error (_("Can't detach process %lu (error %lu)"), current_event.dwProcessId, GetLastError ()); detached = 0; } @@ -1618,23 +1766,55 @@ child_detach (char *args, int from_tty) current_event.dwProcessId); gdb_flush (gdb_stdout); } + inferior_ptid = null_ptid; - unpush_target (&child_ops); + detach_inferior (current_event.dwProcessId); + + unpush_target (&win32_ops); +} + +static char * +win32_pid_to_exec_file (int pid) +{ + static char path[MAX_PATH + 1]; + +#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)) + { + path[nchars] = '\0'; /* Got it */ + return path; + } +#endif + + /* If we get here then either Cygwin is hosed, this isn't a Cygwin version + of gdb, or we're trying to debug a non-Cygwin windows executable. */ + if (!get_module_name (0, path)) + path[0] = '\0'; + + return path; } /* Print status information about what we're accessing. */ static void -child_files_info (struct target_ops *ignore) +win32_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 -child_open (char *arg, int from_tty) +win32_open (char *arg, int from_tty) { - error ("Use the \"run\" command to start a Unix child process."); + error (_("Use the \"run\" command to start a Unix child process.")); } /* Start an inferior win32 child process and sets inferior_ptid to its pid. @@ -1643,12 +1823,9 @@ child_open (char *arg, int from_tty) ENV is the environment vector to pass. Errors reported with error(). */ static void -child_create_inferior (char *exec_file, char *allargs, char **env) +win32_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; @@ -1660,13 +1837,15 @@ child_create_inferior (char *exec_file, char *allargs, char **env) 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'.\n"); + error (_("No executable specified, use `target exec'.")); memset (&si, 0, sizeof (si)); si.cb = sizeof (si); +#ifdef __CYGWIN__ if (!useshell) { flags = DEBUG_ONLY_THIS_PROCESS; @@ -1687,6 +1866,10 @@ child_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; @@ -1699,78 +1882,9 @@ child_create_inferior (char *exec_file, char *allargs, char **env) 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; @@ -1792,17 +1906,21 @@ child_create_inferior (char *exec_file, char *allargs, char **env) dup2 (tty, 2); } } +#endif + win32_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); @@ -1813,9 +1931,11 @@ child_create_inferior (char *exec_file, char *allargs, char **env) close (ostdout); close (ostderr); } +#endif if (!ret) - error ("Error creating process %s, (error %d)\n", exec_file, (unsigned) GetLastError ()); + error (_("Error creating process %s, (error %d)."), + exec_file, (unsigned) GetLastError ()); CloseHandle (pi.hThread); CloseHandle (pi.hProcess); @@ -1825,18 +1945,22 @@ child_create_inferior (char *exec_file, char *allargs, char **env) else saw_create = 0; - do_initial_child_stuff (pi.dwProcessId); + do_initial_win32_stuff (pi.dwProcessId, 0); - /* child_continue (DBG_CONTINUE, -1); */ - proceed ((CORE_ADDR) - 1, TARGET_SIGNAL_0, 0); + /* win32_continue (DBG_CONTINUE, -1); */ } static void -child_mourn_inferior (void) +win32_mourn_inferior (struct target_ops *ops) { - (void) child_continue (DBG_CONTINUE, -1); + (void) win32_continue (DBG_CONTINUE, -1); i386_cleanup_dregs(); - unpush_target (&child_ops); + if (open_process_used) + { + CHECK (CloseHandle (current_process_handle)); + open_process_used = 0; + } + unpush_target (&win32_ops); generic_mourn_inferior (); } @@ -1844,15 +1968,15 @@ child_mourn_inferior (void) ^C on the controlling terminal. */ static void -child_stop (void) +win32_stop (ptid_t ptid) { DEBUG_EVENTS (("gdb: GenerateConsoleCtrlEvent (CTRLC_EVENT, 0)\n")); CHECK (GenerateConsoleCtrlEvent (CTRL_C_EVENT, current_event.dwProcessId)); registers_changed (); /* refresh register state */ } -int -child_xfer_memory (CORE_ADDR memaddr, char *our, int len, +static int +win32_xfer_memory (CORE_ADDR memaddr, gdb_byte *our, int len, int write, struct mem_attrib *mem, struct target_ops *target) { @@ -1860,31 +1984,34 @@ child_xfer_memory (CORE_ADDR memaddr, char *our, int len, 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; } return done; } -void -child_kill_inferior (void) +static void +win32_kill_inferior (void) { CHECK (TerminateProcess (current_process_handle, 0)); for (;;) { - if (!child_continue (DBG_CONTINUE, -1)) + if (!win32_continue (DBG_CONTINUE, -1)) break; if (!WaitForDebugEvent (¤t_event, INFINITE)) break; @@ -1892,154 +2019,153 @@ child_kill_inferior (void) break; } - CHECK (CloseHandle (current_process_handle)); + target_mourn_inferior (); /* or just win32_mourn_inferior? */ +} - /* this may fail in an attached process so don't check. */ - (void) CloseHandle (current_thread->h); - target_mourn_inferior (); /* or just child_mourn_inferior? */ +static void +win32_prepare_to_store (struct regcache *regcache) +{ + /* Do nothing, since we can store individual regs */ } -void -child_resume (ptid_t ptid, int step, enum target_signal sig) +static int +win32_can_run (void) { - thread_info *th; - DWORD continue_status = DBG_CONTINUE; + return 1; +} - int pid = PIDGET (ptid); +static void +win32_close (int x) +{ + DEBUG_EVENTS (("gdb: win32_close, inferior_ptid=%d\n", + PIDGET (inferior_ptid))); +} - if (sig != TARGET_SIGNAL_0) +/* Convert pid to printable format. */ +static char * +win32_pid_to_str (ptid_t ptid) +{ + static char buf[80]; + + if (ptid_get_tid (ptid) != 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)); + snprintf (buf, sizeof (buf), "Thread %d.0x%lx", + ptid_get_pid (ptid), ptid_get_tid (ptid)); + return buf; } - last_sig = TARGET_SIGNAL_0; - - DEBUG_EXEC (("gdb: child_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 */ - child_fetch_inferior_registers (PS_REGNUM); - th->context.EFlags |= FLAG_TRACE_BIT; - } + return normal_pid_to_str (ptid); +} - 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; - } - } +static LONGEST +win32_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) + win32_xfer_shared_library (so->so_name, 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; - /* Allow continuing with the same signal that interrupted us. - Otherwise complain. */ + if (len > len_avail - offset) + len = len_avail - offset; + memcpy (readbuf, buf + offset, len); - child_continue (continue_status, pid); + obstack_free (&obstack, NULL); + return len; } -static void -child_prepare_to_store (void) +static LONGEST +win32_xfer_partial (struct target_ops *ops, enum target_object object, + const char *annex, gdb_byte *readbuf, + const gdb_byte *writebuf, ULONGEST offset, LONGEST len) { - /* Do nothing, since we can store individual regs */ -} + 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 win32_xfer_shared_libraries (ops, object, annex, readbuf, + writebuf, offset, len); -static int -child_can_run (void) -{ - return 1; + default: + if (ops->beneath != NULL) + return ops->beneath->to_xfer_partial (ops->beneath, object, annex, + readbuf, writebuf, offset, len); + return -1; + } } static void -child_close (int x) -{ - DEBUG_EVENTS (("gdb: child_close, inferior_ptid=%d\n", - PIDGET (inferior_ptid))); +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_attach_no_wait = 1; + 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_xfer_partial = win32_xfer_partial; + 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 = win32_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_pid_to_exec_file = win32_pid_to_exec_file; + win32_ops.to_magic = OPS_MAGIC; } -struct target_ops child_ops; - static void -init_child_ops (void) +set_win32_aliases (char *argv0) { - child_ops.to_shortname = "child"; - child_ops.to_longname = "Win32 child process"; - child_ops.to_doc = "Win32 child process (started by the \"run\" command)."; - child_ops.to_open = child_open; - child_ops.to_close = child_close; - child_ops.to_attach = child_attach; - child_ops.to_detach = child_detach; - child_ops.to_resume = child_resume; - child_ops.to_wait = child_wait; - child_ops.to_fetch_registers = child_fetch_inferior_registers; - child_ops.to_store_registers = child_store_inferior_registers; - child_ops.to_prepare_to_store = child_prepare_to_store; - child_ops.to_xfer_memory = child_xfer_memory; - child_ops.to_files_info = child_files_info; - child_ops.to_insert_breakpoint = memory_insert_breakpoint; - child_ops.to_remove_breakpoint = memory_remove_breakpoint; - child_ops.to_terminal_init = terminal_init_inferior; - child_ops.to_terminal_inferior = terminal_inferior; - child_ops.to_terminal_ours_for_output = terminal_ours_for_output; - child_ops.to_terminal_ours = terminal_ours; - child_ops.to_terminal_save_ours = terminal_save_ours; - child_ops.to_terminal_info = child_terminal_info; - child_ops.to_kill = child_kill_inferior; - child_ops.to_create_inferior = child_create_inferior; - child_ops.to_mourn_inferior = child_mourn_inferior; - child_ops.to_can_run = child_can_run; - child_ops.to_thread_alive = win32_child_thread_alive; - child_ops.to_pid_to_str = cygwin_pid_to_str; - child_ops.to_stop = child_stop; - child_ops.to_stratum = process_stratum; - child_ops.to_has_all_memory = 1; - child_ops.to_has_memory = 1; - child_ops.to_has_stack = 1; - child_ops.to_has_registers = 1; - child_ops.to_has_execution = 1; - child_ops.to_magic = OPS_MAGIC; + add_info_alias ("dll", "sharedlibrary", 1); } void @@ -2047,81 +2173,95 @@ _initialize_win32_nat (void) { struct cmd_list_element *c; - init_child_ops (); + init_win32_ops (); c = add_com ("dll-symbols", class_files, dll_symbol_command, - "Load dll library symbols from FILE."); + _("Load dll library symbols from FILE.")); set_cmd_completer (c, filename_completer); add_com_alias ("sharedlibrary", "dll-symbols", class_alias, 1); - add_show_from_set (add_set_cmd ("shell", class_support, var_boolean, - (char *) &useshell, - "Set use of shell to start subprocess.", - &setlist), - &showlist); - - add_show_from_set (add_set_cmd ("new-console", class_support, var_boolean, - (char *) &new_console, - "Set creation of new console when creating child process.", - &setlist), - &showlist); - - add_show_from_set (add_set_cmd ("new-group", class_support, var_boolean, - (char *) &new_group, - "Set creation of new group when creating child process.", - &setlist), - &showlist); - - add_show_from_set (add_set_cmd ("debugexec", class_support, var_boolean, - (char *) &debug_exec, - "Set whether to display execution in child process.", - &setlist), - &showlist); - - add_show_from_set (add_set_cmd ("debugevents", class_support, var_boolean, - (char *) &debug_events, - "Set whether to display kernel events in child process.", - &setlist), - &showlist); - - add_show_from_set (add_set_cmd ("debugmemory", class_support, var_boolean, - (char *) &debug_memory, - "Set whether to display memory accesses in child process.", - &setlist), - &showlist); - - add_show_from_set (add_set_cmd ("debugexceptions", class_support, var_boolean, - (char *) &debug_exceptions, - "Set whether to display kernel exceptions in child process.", - &setlist), - &showlist); - - add_info ("dll", info_dll_command, "Status of loaded DLLs."); - add_info_alias ("sharedlibrary", "dll", 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, + 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, + 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.", + _("Print information specific to Win32 debugging."), &info_w32_cmdlist, "info w32 ", 0, &infolist); add_cmd ("selector", class_info, display_selectors, - "Display selectors infos.", + _("Display selectors infos."), &info_w32_cmdlist); - - add_target (&child_ops); + 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 child_continue is called. */ + 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); + _("Invalid register %d in cygwin_set_dr.\n"), i); dr[i] = (unsigned) addr; debug_registers_changed = 1; debug_registers_used = 1; @@ -2129,7 +2269,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 child_wait. */ + will be actually set up in win32_wait. */ void cygwin_set_dr7 (unsigned val) { @@ -2147,248 +2287,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. */ -static int -win32_child_thread_alive (ptid_t ptid) -{ - int pid = PIDGET (ptid); - - return WaitForSingleObject (thread_rec (pid, FALSE)->h, 0) == WAIT_OBJECT_0 ? - FALSE : TRUE; -} - -/* Convert pid to printable format. */ -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; -} - + it means that the thread has died. Otherwise it is assumed to be alive. */ static int -core_dll_symbols_add (char *dll_name, DWORD base_addr) -{ - struct objfile *objfile; - char *objfile_basename; - const char *dll_basename; - - if (!(dll_basename = strrchr (dll_name, '/'))) - dll_basename = dll_name; - else - dll_basename++; - - ALL_OBJFILES (objfile) - { - objfile_basename = strrchr (objfile->name, '/'); - - if (objfile_basename && - strcmp (dll_basename, objfile_basename + 1) == 0) - { - printf_unfiltered ("%08lx:%s (symbols previously loaded)\n", - base_addr, dll_name); - goto out; - } - } - - register_loaded_dll (dll_name, base_addr + 0x1000); - solib_symbols_add (dll_name, 0, (CORE_ADDR) base_addr + 0x1000); - -out: - return 1; -} - -typedef struct +win32_win32_thread_alive (ptid_t ptid) { - struct target_ops *target; - bfd_vma addr; -} map_code_section_args; + int tid; -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; + gdb_assert (ptid_get_tid (ptid) != 0); + tid = ptid_get_tid (ptid); - 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; - char *dll_name = NULL; - char *buf = NULL; - struct win32_pstatus *pstatus; - char *p; - - if (strncmp (sect->name, ".module", 7)) - return; - - buf = (char *) xmalloc (sect->_raw_size + 1); - if (!buf) - { - printf_unfiltered ("memory allocation failed for %s\n", sect->name); - goto out; - } - if (!bfd_get_section_contents (abfd, sect, buf, 0, sect->_raw_size)) - 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 > sect->_raw_size) - goto out; - - dll_name = (char *) xmalloc (dll_name_size + 1); - if (!dll_name) - { - printf_unfiltered ("memory allocation failed for %s\n", sect->name); - goto out; - } - strncpy (dll_name, pstatus->data.module_info.module_name, dll_name_size); - - while ((p = strchr (dll_name, '\\'))) - *p = '/'; - - if (!core_dll_symbols_add (dll_name, (DWORD) base_addr)) - printf_unfiltered ("%s: Failed to load dll symbols.\n", dll_name); - - if (!dll_code_sections_add (dll_name, (DWORD) base_addr + 0x1000, target)) - printf_unfiltered ("%s: Failed to map dll code sections.\n", dll_name); - -out: - if (buf) - xfree (buf); - if (dll_name) - xfree (dll_name); - return; -} - -void -child_solib_add (char *filename, int from_tty, struct target_ops *target, - int readsyms) -{ - if (!readsyms) - return; - if (core_bfd) - { - child_clear_solibs (); - bfd_map_over_sections (core_bfd, &core_section_load_dll_symbols, target); - } - else - { - if (solib_end && solib_end->name) - solib_end->objfile = solib_symbols_add (solib_end->name, from_tty, - solib_end->load_addr); - } -} - -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++) - supply_register (r, core_reg_sect + mappings[r]); -} - -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) -{ - add_core_fns (&win32_elf_core_fns); + return WaitForSingleObject (thread_rec (tid, FALSE)->h, 0) == WAIT_OBJECT_0 ? + FALSE : TRUE; } void @@ -2415,7 +2326,38 @@ _initialize_check_for_gdb_ini (void) 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); + warning (_("obsolete '%s' found. Rename to '%s'."), oldini, newini); + } + } +} + +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.")); }