X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fwindows-nat.c;h=10d5c95d091d02a1e50406b186c5e48864911528;hb=d9fa87f4f6e732f5feb41f2fa7dc6faddb1fb627;hp=be5d7e814b9795deaa22ff9aa93557deac3754bd;hpb=f16eab5ffbd9128410241abc48edcd5871c91137;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c index be5d7e814b..10d5c95d09 100644 --- a/gdb/windows-nat.c +++ b/gdb/windows-nat.c @@ -1,6 +1,6 @@ /* Target-vector operations for controlling windows child processes, for GDB. - Copyright (C) 1995-2015 Free Software Foundation, Inc. + Copyright (C) 1995-2019 Free Software Foundation, Inc. Contributed by Cygnus Solutions, A Red Hat Company. @@ -42,8 +42,8 @@ #include #include #endif +#include -#include "buildsym.h" #include "filenames.h" #include "symfile.h" #include "objfiles.h" @@ -56,6 +56,7 @@ #include "solist.h" #include "solib.h" #include "xml-support.h" +#include "inttypes.h" #include "i386-tdep.h" #include "i387-tdep.h" @@ -65,6 +66,8 @@ #include "x86-nat.h" #include "complaints.h" #include "inf-child.h" +#include "gdbsupport/gdb_tilde_expand.h" +#include "gdbsupport/pathstuff.h" #define AdjustTokenPrivileges dyn_AdjustTokenPrivileges #define DebugActiveProcessStop dyn_DebugActiveProcessStop @@ -77,20 +80,41 @@ #define GetConsoleFontSize dyn_GetConsoleFontSize #define GetCurrentConsoleFont dyn_GetCurrentConsoleFont -static BOOL WINAPI (*AdjustTokenPrivileges)(HANDLE, BOOL, PTOKEN_PRIVILEGES, - DWORD, PTOKEN_PRIVILEGES, PDWORD); -static BOOL WINAPI (*DebugActiveProcessStop) (DWORD); -static BOOL WINAPI (*DebugBreakProcess) (HANDLE); -static BOOL WINAPI (*DebugSetProcessKillOnExit) (BOOL); -static BOOL WINAPI (*EnumProcessModules) (HANDLE, HMODULE *, DWORD, - LPDWORD); -static BOOL WINAPI (*GetModuleInformation) (HANDLE, HMODULE, LPMODULEINFO, - DWORD); -static BOOL WINAPI (*LookupPrivilegeValueA)(LPCSTR, LPCSTR, PLUID); -static BOOL WINAPI (*OpenProcessToken)(HANDLE, DWORD, PHANDLE); -static BOOL WINAPI (*GetCurrentConsoleFont) (HANDLE, BOOL, - CONSOLE_FONT_INFO *); -static COORD WINAPI (*GetConsoleFontSize) (HANDLE, DWORD); +typedef BOOL WINAPI (AdjustTokenPrivileges_ftype) (HANDLE, BOOL, + PTOKEN_PRIVILEGES, + DWORD, PTOKEN_PRIVILEGES, + PDWORD); +static AdjustTokenPrivileges_ftype *AdjustTokenPrivileges; + +typedef BOOL WINAPI (DebugActiveProcessStop_ftype) (DWORD); +static DebugActiveProcessStop_ftype *DebugActiveProcessStop; + +typedef BOOL WINAPI (DebugBreakProcess_ftype) (HANDLE); +static DebugBreakProcess_ftype *DebugBreakProcess; + +typedef BOOL WINAPI (DebugSetProcessKillOnExit_ftype) (BOOL); +static DebugSetProcessKillOnExit_ftype *DebugSetProcessKillOnExit; + +typedef BOOL WINAPI (EnumProcessModules_ftype) (HANDLE, HMODULE *, DWORD, + LPDWORD); +static EnumProcessModules_ftype *EnumProcessModules; + +typedef BOOL WINAPI (GetModuleInformation_ftype) (HANDLE, HMODULE, + LPMODULEINFO, DWORD); +static GetModuleInformation_ftype *GetModuleInformation; + +typedef BOOL WINAPI (LookupPrivilegeValueA_ftype) (LPCSTR, LPCSTR, PLUID); +static LookupPrivilegeValueA_ftype *LookupPrivilegeValueA; + +typedef BOOL WINAPI (OpenProcessToken_ftype) (HANDLE, DWORD, PHANDLE); +static OpenProcessToken_ftype *OpenProcessToken; + +typedef BOOL WINAPI (GetCurrentConsoleFont_ftype) (HANDLE, BOOL, + CONSOLE_FONT_INFO *); +static GetCurrentConsoleFont_ftype *GetCurrentConsoleFont; + +typedef COORD WINAPI (GetConsoleFontSize_ftype) (HANDLE, DWORD); +static GetConsoleFontSize_ftype *GetConsoleFontSize; #undef STARTUPINFO #undef CreateProcess @@ -98,7 +122,8 @@ static COORD WINAPI (*GetConsoleFontSize) (HANDLE, DWORD); #ifndef __CYGWIN__ # define __PMAX (MAX_PATH + 1) - static DWORD WINAPI (*GetModuleFileNameEx) (HANDLE, HMODULE, LPSTR, DWORD); + typedef DWORD WINAPI (GetModuleFileNameEx_ftype) (HANDLE, HMODULE, LPSTR, DWORD); + static GetModuleFileNameEx_ftype *GetModuleFileNameEx; # define STARTUPINFO STARTUPINFOA # define CreateProcess CreateProcessA # define GetModuleFileNameEx_name "GetModuleFileNameExA" @@ -110,8 +135,9 @@ static COORD WINAPI (*GetConsoleFontSize) (HANDLE, DWORD); static CORE_ADDR cygwin_load_end; # define __USEWIDE typedef wchar_t cygwin_buf_t; - static DWORD WINAPI (*GetModuleFileNameEx) (HANDLE, HMODULE, - LPWSTR, DWORD); + typedef DWORD WINAPI (GetModuleFileNameEx_ftype) (HANDLE, HMODULE, + LPWSTR, DWORD); + static GetModuleFileNameEx_ftype *GetModuleFileNameEx; # define STARTUPINFO STARTUPINFOW # define CreateProcess CreateProcessW # define GetModuleFileNameEx_name "GetModuleFileNameExW" @@ -120,8 +146,10 @@ static COORD WINAPI (*GetConsoleFontSize) (HANDLE, DWORD); 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 +#ifdef __CYGWIN__ +static CONTEXT saved_context; /* Contains the saved context from a cygwin signal. */ +#endif /* If we're not using the old Cygwin header file set, define the following which never should have been in the generic Win32 API @@ -150,6 +178,19 @@ static int debug_registers_used; static int windows_initialization_done; #define DR6_CLEAR_VALUE 0xffff0ff0 +/* The exception thrown by a program to tell the debugger the name of + a thread. The exception record contains an ID of a thread and a + name to give it. This exception has no documented name, but MSDN + dubs it "MS_VC_EXCEPTION" in one code example. */ +#define MS_VC_EXCEPTION 0x406d1388 + +typedef enum +{ + HANDLE_EXCEPTION_UNHANDLED = 0, + HANDLE_EXCEPTION_HANDLED, + HANDLE_EXCEPTION_IGNORED +} handle_exception_result; + /* The string sent by cygwin when it processes a signal. FIXME: This should be in a cygwin include file. */ #ifndef _CYGWIN_SIGNAL_STRING @@ -162,10 +203,6 @@ static int windows_initialization_done; #define DEBUG_MEM(x) if (debug_memory) printf_unfiltered x #define DEBUG_EXCEPT(x) if (debug_exceptions) printf_unfiltered x -static void windows_stop (struct target_ops *self, ptid_t); -static int windows_thread_alive (struct target_ops *, ptid_t); -static void windows_kill_inferior (struct target_ops *); - static void cygwin_set_dr (int i, CORE_ADDR addr); static void cygwin_set_dr7 (unsigned long val); static CORE_ADDR cygwin_get_dr (int i); @@ -187,7 +224,6 @@ typedef struct windows_thread_info_struct int suspended; int reload_context; CONTEXT context; - STACKFRAME sf; } windows_thread_info; @@ -199,7 +235,6 @@ static DEBUG_EVENT current_event; /* The current debug event from WaitForDebugEvent */ static HANDLE current_process_handle; /* Currently executing process */ static windows_thread_info *current_thread; /* Info on currently selected thread */ -static DWORD main_thread_id; /* Thread ID of the main thread */ /* Counts of things. */ static int exception_count = 0; @@ -208,16 +243,16 @@ static int saw_create; static int open_process_used = 0; /* User options. */ -static int new_console = 0; +static bool new_console = false; #ifdef __CYGWIN__ -static int cygwin_exceptions = 0; +static bool cygwin_exceptions = false; #endif -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 */ +static bool new_group = true; +static bool debug_exec = false; /* show execution */ +static bool debug_events = false; /* show events from kernel */ +static bool debug_memory = false; /* show target memory accesses */ +static bool debug_exceptions = false; /* show target exceptions */ +static bool useshell = false; /* use shell for subprocesses */ /* This vector maps GDB's idea of a register's number into an offset in the windows exception context vector. @@ -243,25 +278,80 @@ static const int *mappings; a segment register or not. */ static segment_register_p_ftype *segment_register_p; +/* See windows_nat_target::resume to understand why this is commented + out. */ +#if 0 /* 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; + DWORD them; enum gdb_signal us; }; -static const struct xlate_exception - xlate[] = +static const struct xlate_exception xlate[] = { {EXCEPTION_ACCESS_VIOLATION, GDB_SIGNAL_SEGV}, {STATUS_STACK_OVERFLOW, GDB_SIGNAL_SEGV}, {EXCEPTION_BREAKPOINT, GDB_SIGNAL_TRAP}, {DBG_CONTROL_C, GDB_SIGNAL_INT}, {EXCEPTION_SINGLE_STEP, GDB_SIGNAL_TRAP}, - {STATUS_FLOAT_DIVIDE_BY_ZERO, GDB_SIGNAL_FPE}, - {-1, -1}}; + {STATUS_FLOAT_DIVIDE_BY_ZERO, GDB_SIGNAL_FPE} +}; + +#endif /* 0 */ + +struct windows_nat_target final : public x86_nat_target +{ + void close () override; + + void attach (const char *, int) override; + + bool attach_no_wait () override + { return true; } + + void detach (inferior *, int) override; + + void resume (ptid_t, int , enum gdb_signal) override; + + ptid_t wait (ptid_t, struct target_waitstatus *, int) override; + + void fetch_registers (struct regcache *, int) override; + void store_registers (struct regcache *, int) override; + + enum target_xfer_status xfer_partial (enum target_object object, + const char *annex, + gdb_byte *readbuf, + const gdb_byte *writebuf, + ULONGEST offset, ULONGEST len, + ULONGEST *xfered_len) override; + + void files_info () override; + + void kill () override; + + void create_inferior (const char *, const std::string &, + char **, int) override; + + void mourn_inferior () override; + + bool thread_alive (ptid_t ptid) override; + + std::string pid_to_str (ptid_t) override; + + void interrupt () override; + + char *pid_to_exec_file (int pid) override; + + ptid_t get_ada_task_ptid (long lwp, long thread) override; + + bool get_tib_address (ptid_t ptid, CORE_ADDR *addr) override; + + const char *thread_name (struct thread_info *) override; +}; + +static windows_nat_target the_windows_nat_target; /* Set the MAPPINGS static global to OFFSETS. See the description of MAPPINGS for more details. */ @@ -310,8 +400,11 @@ thread_rec (DWORD id, int get_context) /* We get Access Denied (5) when trying to suspend threads that Windows started on behalf of the debuggee, usually when those threads are just - about to exit. */ - if (err != ERROR_ACCESS_DENIED) + about to exit. + We can get Invalid Handle (6) if the main thread + has exited. */ + if (err != ERROR_INVALID_HANDLE + && err != ERROR_ACCESS_DENIED) warning (_("SuspendThread (tid=0x%x) failed." " (winerr %u)"), (unsigned) id, (unsigned) err); @@ -330,16 +423,23 @@ thread_rec (DWORD id, int get_context) return NULL; } -/* Add a thread to the thread list. */ +/* Add a thread to the thread list. + + PTID is the ptid of the thread to be added. + H is its Windows handle. + TLB is its thread local base. + MAIN_THREAD_P should be true if the thread to be added is + the main thread, false otherwise. */ + static windows_thread_info * -windows_add_thread (ptid_t ptid, HANDLE h, void *tlb) +windows_add_thread (ptid_t ptid, HANDLE h, void *tlb, bool main_thread_p) { windows_thread_info *th; DWORD id; - gdb_assert (ptid_get_tid (ptid) != 0); + gdb_assert (ptid.tid () != 0); - id = ptid_get_tid (ptid); + id = ptid.tid (); if ((th = thread_rec (id, FALSE))) return th; @@ -350,7 +450,17 @@ windows_add_thread (ptid_t ptid, HANDLE h, void *tlb) th->thread_local_base = (CORE_ADDR) (uintptr_t) tlb; th->next = thread_head.next; thread_head.next = th; - add_thread (ptid); + + /* Add this new thread to the list of threads. + + To be consistent with what's done on other platforms, we add + the main thread silently (in reality, this thread is really + more of a process to the user than a thread). */ + if (main_thread_p) + add_thread_silent (ptid); + else + add_thread (ptid); + /* Set the debug registers for the new thread if they are used. */ if (debug_registers_used) { @@ -369,7 +479,7 @@ windows_add_thread (ptid_t ptid, HANDLE h, void *tlb) return th; } -/* Clear out any old thread list and reintialize it to a +/* Clear out any old thread list and reinitialize it to a pristine state. */ static void windows_init_thread_list (void) @@ -387,23 +497,38 @@ windows_init_thread_list (void) thread_head.next = NULL; } -/* Delete a thread from the list of threads. */ +/* Delete a thread from the list of threads. + + PTID is the ptid of the thread to be deleted. + EXIT_CODE is the thread's exit code. + MAIN_THREAD_P should be true if the thread to be deleted is + the main thread, false otherwise. */ + static void -windows_delete_thread (ptid_t ptid, DWORD exit_code) +windows_delete_thread (ptid_t ptid, DWORD exit_code, bool main_thread_p) { windows_thread_info *th; DWORD id; - gdb_assert (ptid_get_tid (ptid) != 0); + gdb_assert (ptid.tid () != 0); - id = ptid_get_tid (ptid); + id = ptid.tid (); + + /* Emit a notification about the thread being deleted. + + Note that no notification was printed when the main thread + was created, and thus, unless in verbose mode, we should be + symmetrical, and avoid that notification for the main thread + here as well. */ if (info_verbose) - printf_unfiltered ("[Deleting %s]\n", target_pid_to_str (ptid)); - else if (print_thread_events && id != main_thread_id) + printf_unfiltered ("[Deleting %s]\n", target_pid_to_str (ptid).c_str ()); + else if (print_thread_events && !main_thread_p) printf_unfiltered (_("[%s exited with code %u]\n"), - target_pid_to_str (ptid), (unsigned) exit_code); - delete_thread (ptid); + target_pid_to_str (ptid).c_str (), + (unsigned) exit_code); + + delete_thread (find_thread_ptid (ptid)); for (th = &thread_head; th->next != NULL && th->next->id != id; @@ -414,39 +539,81 @@ windows_delete_thread (ptid_t ptid, DWORD exit_code) { windows_thread_info *here = th->next; th->next = here->next; + xfree (here->name); xfree (here); } } +/* Fetches register number R from the given windows_thread_info, + and supplies its value to the given regcache. + + This function assumes that R is non-negative. A failed assertion + is raised if that is not true. + + This function assumes that TH->RELOAD_CONTEXT is not set, meaning + that the windows_thread_info has an up-to-date context. A failed + assertion is raised if that assumption is violated. */ + static void -do_windows_fetch_inferior_registers (struct regcache *regcache, int r) +windows_fetch_one_register (struct regcache *regcache, + windows_thread_info *th, int r) { - char *context_offset = ((char *) ¤t_thread->context) + mappings[r]; - struct gdbarch *gdbarch = get_regcache_arch (regcache); + gdb_assert (r >= 0); + gdb_assert (!th->reload_context); + + char *context_offset = ((char *) &th->context) + mappings[r]; + struct gdbarch *gdbarch = regcache->arch (); struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - long l; - if (!current_thread) - return; /* Windows sometimes uses a non-existent thread id in its - events. */ + if (r == I387_FISEG_REGNUM (tdep)) + { + long l = *((long *) context_offset) & 0xffff; + regcache->raw_supply (r, (char *) &l); + } + else if (r == I387_FOP_REGNUM (tdep)) + { + long l = (*((long *) context_offset) >> 16) & ((1 << 11) - 1); + regcache->raw_supply (r, (char *) &l); + } + else if (segment_register_p (r)) + { + /* GDB treats segment registers as 32bit registers, but they are + in fact only 16 bits long. Make sure we do not read extra + bits from our source buffer. */ + long l = *((long *) context_offset) & 0xffff; + regcache->raw_supply (r, (char *) &l); + } + else + regcache->raw_supply (r, context_offset); +} + +void +windows_nat_target::fetch_registers (struct regcache *regcache, int r) +{ + DWORD tid = regcache->ptid ().tid (); + windows_thread_info *th = thread_rec (tid, TRUE); - if (current_thread->reload_context) + /* Check if TH exists. Windows sometimes uses a non-existent + thread id in its events. */ + if (th == NULL) + return; + + if (th->reload_context) { -#ifdef __COPY_CONTEXT_SIZE +#ifdef __CYGWIN__ 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, + memcpy (&th->context, &saved_context, __COPY_CONTEXT_SIZE); have_saved_context = 0; } else #endif { - windows_thread_info *th = current_thread; th->context.ContextFlags = CONTEXT_DEBUGGER_DR; CHECK (GetThreadContext (th->h, &th->context)); /* Copy dr values from that thread. @@ -462,91 +629,56 @@ do_windows_fetch_inferior_registers (struct regcache *regcache, int r) dr[7] = th->context.Dr7; } } - current_thread->reload_context = 0; + th->reload_context = 0; } - if (r == I387_FISEG_REGNUM (tdep)) - { - l = *((long *) context_offset) & 0xffff; - regcache_raw_supply (regcache, r, (char *) &l); - } - else if (r == I387_FOP_REGNUM (tdep)) - { - l = (*((long *) context_offset) >> 16) & ((1 << 11) - 1); - regcache_raw_supply (regcache, r, (char *) &l); - } - else if (segment_register_p (r)) - { - /* GDB treats segment registers as 32bit registers, but they are - in fact only 16 bits long. Make sure we do not read extra - bits from our source buffer. */ - l = *((long *) context_offset) & 0xffff; - regcache_raw_supply (regcache, r, (char *) &l); - } - else if (r >= 0) - regcache_raw_supply (regcache, r, context_offset); + if (r < 0) + for (r = 0; r < gdbarch_num_regs (regcache->arch()); r++) + windows_fetch_one_register (regcache, th, r); else - { - for (r = 0; r < gdbarch_num_regs (gdbarch); r++) - do_windows_fetch_inferior_registers (regcache, r); - } + windows_fetch_one_register (regcache, th, r); } -static void -windows_fetch_inferior_registers (struct target_ops *ops, - struct regcache *regcache, int r) -{ - current_thread = thread_rec (ptid_get_tid (inferior_ptid), TRUE); - /* Check if current_thread exists. Windows sometimes uses a non-existent - thread id in its events. */ - if (current_thread) - do_windows_fetch_inferior_registers (regcache, r); -} +/* Collect the register number R from the given regcache, and store + its value into the corresponding area of the given thread's context. + + This function assumes that R is non-negative. A failed assertion + assertion is raised if that is not true. */ static void -do_windows_store_inferior_registers (const struct regcache *regcache, int r) +windows_store_one_register (const struct regcache *regcache, + windows_thread_info *th, int 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 < gdbarch_num_regs (get_regcache_arch (regcache)); r++) - do_windows_store_inferior_registers (regcache, r); - } + gdb_assert (r >= 0); + + regcache->raw_collect (r, ((char *) &th->context) + mappings[r]); } -/* Store a new register value into the current thread context. */ -static void -windows_store_inferior_registers (struct target_ops *ops, - struct regcache *regcache, int r) +/* Store a new register value into the context of the thread tied to + REGCACHE. */ + +void +windows_nat_target::store_registers (struct regcache *regcache, int r) { - current_thread = thread_rec (ptid_get_tid (inferior_ptid), TRUE); - /* Check if current_thread exists. Windows sometimes uses a non-existent + DWORD tid = regcache->ptid ().tid (); + windows_thread_info *th = thread_rec (tid, TRUE); + + /* Check if TH exists. Windows sometimes uses a non-existent thread id in its events. */ - if (current_thread) - do_windows_store_inferior_registers (regcache, r); -} + if (th == NULL) + return; -/* 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; -}; + if (r < 0) + for (r = 0; r < gdbarch_num_regs (regcache->arch ()); r++) + windows_store_one_register (regcache, th, r); + else + windows_store_one_register (regcache, th, r); +} /* Maintain a linked list of "so" information. */ -struct lm_info +struct lm_info_windows : public lm_info_base { - LPVOID load_addr; + LPVOID load_addr = 0; }; static struct so_list solib_start, *solib_end; @@ -604,8 +736,9 @@ windows_make_so (const char *name, LPVOID load_addr) } #endif so = XCNEW (struct so_list); - so->lm_info = (struct lm_info *) xmalloc (sizeof (struct lm_info)); - so->lm_info->load_addr = load_addr; + lm_info_windows *li = new lm_info_windows; + so->lm_info = li; + li->load_addr = load_addr; strcpy (so->so_original_name, name); #ifndef __CYGWIN__ strcpy (so->so_name, buf); @@ -628,32 +761,25 @@ windows_make_so (const char *name, LPVOID load_addr) 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 = gdb_bfd_open (so->so_name, "pei-i386", -1); + gdb_bfd_ref_ptr abfd (gdb_bfd_open (so->so_name, "pei-i386", -1)); - if (!abfd) + if (abfd == NULL) return so; - if (bfd_check_format (abfd, bfd_object)) - text = bfd_get_section_by_name (abfd, ".text"); + if (bfd_check_format (abfd.get (), bfd_object)) + text = bfd_get_section_by_name (abfd.get (), ".text"); if (!text) - { - gdb_bfd_unref (abfd); - return so; - } + return so; /* The symbols in a dll are offset by 0x1000, which is the offset from 0 of the first byte in an image - because of the file header and the section alignment. */ cygwin_load_start = (CORE_ADDR) (uintptr_t) ((char *) load_addr + 0x1000); - cygwin_load_end = cygwin_load_start + bfd_section_size (abfd, text); - - gdb_bfd_unref (abfd); + cygwin_load_end = cygwin_load_start + bfd_section_size (text); } #endif @@ -717,8 +843,8 @@ get_image_name (HANDLE h, void *address, int unicode) do_initial_windows_stuff and windows_add_all_dlls for more info on how we handle DLL loading during that phase). */ -static int -handle_load_dll (void *dummy) +static void +handle_load_dll () { LOAD_DLL_DEBUG_INFO *event = ¤t_event.u.LoadDll; char *dll_name; @@ -731,22 +857,23 @@ handle_load_dll (void *dummy) dll_name = get_image_name (current_process_handle, event->lpImageName, event->fUnicode); if (!dll_name) - return 1; + return; solib_end->next = windows_make_so (dll_name, event->lpBaseOfDll); solib_end = solib_end->next; - DEBUG_EVENTS (("gdb: Loading dll \"%s\" at %s.\n", solib_end->so_name, - host_address_to_string (solib_end->lm_info->load_addr))); + lm_info_windows *li = (lm_info_windows *) solib_end->lm_info; - return 1; + DEBUG_EVENTS (("gdb: Loading dll \"%s\" at %s.\n", solib_end->so_name, + host_address_to_string (li->load_addr))); } static void windows_free_so (struct so_list *so) { - if (so->lm_info) - xfree (so->lm_info); + lm_info_windows *li = (lm_info_windows *) so->lm_info; + + delete li; xfree (so); } @@ -758,25 +885,29 @@ windows_free_so (struct so_list *so) do_initial_windows_stuff and windows_add_all_dlls for more info on how we handle DLL loading during that phase). */ -static int -handle_unload_dll (void *dummy) +static void +handle_unload_dll () { LPVOID lpBaseOfDll = current_event.u.UnloadDll.lpBaseOfDll; 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; + { + lm_info_windows *li_next = (lm_info_windows *) so->next->lm_info; - so->next = sodel->next; - if (!so->next) - solib_end = so; - DEBUG_EVENTS (("gdb: Unloading dll \"%s\".\n", sodel->so_name)); + if (li_next->load_addr == lpBaseOfDll) + { + struct so_list *sodel = so->next; - windows_free_so (sodel); - return 1; - } + so->next = sodel->next; + if (!so->next) + solib_end = so; + DEBUG_EVENTS (("gdb: Unloading dll \"%s\".\n", sodel->so_name)); + + windows_free_so (sodel); + return; + } + } /* We did not find any DLL that was previously loaded at this address, so register a complaint. We do not report an error, because we have @@ -785,10 +916,24 @@ handle_unload_dll (void *dummy) 4 mysterious UNLOAD_DLL_DEBUG_EVENTs during the startup phase (these events are apparently caused by the WOW layer, the interface between 32bit and 64bit worlds). */ - complaint (&symfile_complaints, _("dll starting at %s not found."), + complaint (_("dll starting at %s not found."), host_address_to_string (lpBaseOfDll)); +} - return 0; +/* Call FUNC wrapped in a TRY/CATCH that swallows all GDB + exceptions. */ + +static void +catch_errors (void (*func) ()) +{ + try + { + func (); + } + catch (const gdb_exception &ex) + { + exception_print (gdb_stderr, ex); + } } /* Clear list of loaded DLLs. */ @@ -799,28 +944,53 @@ windows_clear_solib (void) solib_end = &solib_start; } +static void +signal_event_command (const char *args, int from_tty) +{ + uintptr_t event_id = 0; + char *endargs = NULL; + + if (args == NULL) + error (_("signal-event requires an argument (integer event id)")); + + event_id = strtoumax (args, &endargs, 10); + + if ((errno == ERANGE) || (event_id == 0) || (event_id > UINTPTR_MAX) || + ((HANDLE) event_id == INVALID_HANDLE_VALUE)) + error (_("Failed to convert `%s' to event id"), args); + + SetEvent ((HANDLE) event_id); + CloseHandle ((HANDLE) event_id); +} + /* 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; + gdb::unique_xmalloc_ptr s; int retval = 0; if (!target_read_string ((CORE_ADDR) (uintptr_t) current_event.u.DebugString.lpDebugStringData, - &s, 1024, 0) - || !s || !*s) + &s, 1024, 0) + || !s || !*(s.get ())) /* nothing to do */; - else if (!startswith (s, _CYGWIN_SIGNAL_STRING)) + else if (!startswith (s.get (), _CYGWIN_SIGNAL_STRING)) { #ifdef __CYGWIN__ - if (!startswith (s, "cYg")) + if (!startswith (s.get (), "cYg")) #endif - warning (("%s"), s); + { + char *p = strchr (s.get (), '\0'); + + if (p > s.get () && *--p == '\n') + *p = '\0'; + warning (("%s"), s.get ()); + } } -#ifdef __COPY_CONTEXT_SIZE +#ifdef __CYGWIN__ else { /* Got a cygwin signal marker. A cygwin signal is followed by @@ -831,8 +1001,8 @@ handle_output_debug_string (struct target_waitstatus *ourstatus) 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 = gdb_signal_from_host (sig); + int sig = strtol (s.get () + sizeof (_CYGWIN_SIGNAL_STRING) - 1, &p, 0); + gdb_signal gotasig = gdb_signal_from_host (sig); ourstatus->value.sig = gotasig; if (gotasig) @@ -843,7 +1013,7 @@ handle_output_debug_string (struct target_waitstatus *ourstatus) ourstatus->kind = TARGET_WAITKIND_STOPPED; retval = strtoul (p, &p, 0); if (!retval) - retval = main_thread_id; + retval = current_event.dwThreadId; else if ((x = (LPCVOID) (uintptr_t) strtoull (p, NULL, 0)) && ReadProcessMemory (current_process_handle, x, &saved_context, @@ -854,8 +1024,6 @@ handle_output_debug_string (struct target_waitstatus *ourstatus) } #endif - if (s) - xfree (s); return retval; } @@ -910,14 +1078,16 @@ display_selector (HANDLE thread, DWORD sel) puts_filtered ("Code (Exec/Read, Conf"); break; default: - printf_filtered ("Unknown type 0x%x",info.HighWord.Bits.Type); + printf_filtered ("Unknown type 0x%lx", + (unsigned long) 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); + printf_filtered ("Priviledge level = %ld. ", + (unsigned long) info.HighWord.Bits.Dpl); if (info.HighWord.Bits.Granularity) puts_filtered ("Page granular.\n"); else @@ -936,7 +1106,7 @@ display_selector (HANDLE thread, DWORD sel) } static void -display_selectors (char * args, int from_tty) +display_selectors (const char * args, int from_tty) { if (!current_thread) { @@ -979,16 +1149,17 @@ display_selectors (char * args, int from_tty) host_address_to_string (\ current_event.u.Exception.ExceptionRecord.ExceptionAddress)) -static int +static handle_exception_result handle_exception (struct target_waitstatus *ourstatus) { - windows_thread_info *th; - DWORD code = current_event.u.Exception.ExceptionRecord.ExceptionCode; + EXCEPTION_RECORD *rec = ¤t_event.u.Exception.ExceptionRecord; + DWORD code = rec->ExceptionCode; + handle_exception_result result = HANDLE_EXCEPTION_HANDLED; ourstatus->kind = TARGET_WAITKIND_STOPPED; /* Record the context of the current thread. */ - th = thread_rec (current_event.dwThreadId, -1); + thread_rec (current_event.dwThreadId, -1); switch (code) { @@ -1006,14 +1177,13 @@ handle_exception (struct target_waitstatus *ourstatus) cygwin-specific-signal. So, ignore SEGVs if they show up within the text segment of the DLL itself. */ const char *fn; - CORE_ADDR addr = (CORE_ADDR) (uintptr_t) - current_event.u.Exception.ExceptionRecord.ExceptionAddress; + CORE_ADDR addr = (CORE_ADDR) (uintptr_t) rec->ExceptionAddress; if ((!cygwin_exceptions && (addr >= cygwin_load_start && addr < cygwin_load_end)) || (find_pc_partial_function (addr, &fn, NULL, NULL) && startswith (fn, "KERNEL32!IsBad"))) - return 0; + return HANDLE_EXCEPTION_UNHANDLED; } #endif break; @@ -1089,10 +1259,47 @@ handle_exception (struct target_waitstatus *ourstatus) DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_NONCONTINUABLE_EXCEPTION"); ourstatus->value.sig = GDB_SIGNAL_ILL; break; + case MS_VC_EXCEPTION: + if (rec->NumberParameters >= 3 + && (rec->ExceptionInformation[0] & 0xffffffff) == 0x1000) + { + DWORD named_thread_id; + windows_thread_info *named_thread; + CORE_ADDR thread_name_target; + + DEBUG_EXCEPTION_SIMPLE ("MS_VC_EXCEPTION"); + + thread_name_target = rec->ExceptionInformation[1]; + named_thread_id = (DWORD) (0xffffffff & rec->ExceptionInformation[2]); + + if (named_thread_id == (DWORD) -1) + named_thread_id = current_event.dwThreadId; + + named_thread = thread_rec (named_thread_id, 0); + if (named_thread != NULL) + { + int thread_name_len; + gdb::unique_xmalloc_ptr thread_name; + + thread_name_len = target_read_string (thread_name_target, + &thread_name, 1025, NULL); + if (thread_name_len > 0) + { + thread_name.get ()[thread_name_len - 1] = '\0'; + xfree (named_thread->name); + named_thread->name = thread_name.release (); + } + } + ourstatus->value.sig = GDB_SIGNAL_TRAP; + result = HANDLE_EXCEPTION_IGNORED; + break; + } + /* treat improperly formed exception as unknown */ + /* FALLTHROUGH */ default: /* Treat unhandled first chance exceptions specially. */ if (current_event.u.Exception.dwFirstChance) - return -1; + return HANDLE_EXCEPTION_UNHANDLED; printf_unfiltered ("gdb: unknown target exception 0x%08x at %s\n", (unsigned) current_event.u.Exception.ExceptionRecord.ExceptionCode, host_address_to_string ( @@ -1102,7 +1309,7 @@ handle_exception (struct target_waitstatus *ourstatus) } exception_count++; last_sig = ourstatus->value.sig; - return 1; + return result; } /* Resume thread specified by ID, or all artificially suspended @@ -1112,7 +1319,6 @@ handle_exception (struct target_waitstatus *ourstatus) static BOOL windows_continue (DWORD continue_status, int id, int killed) { - int i; windows_thread_info *th; BOOL res; @@ -1183,24 +1389,23 @@ fake_create_process (void) (unsigned) GetLastError ()); /* We can not debug anything in that case. */ } - main_thread_id = current_event.dwThreadId; - current_thread = windows_add_thread ( - ptid_build (current_event.dwProcessId, 0, - current_event.dwThreadId), - current_event.u.CreateThread.hThread, - current_event.u.CreateThread.lpThreadLocalBase); - return main_thread_id; + current_thread + = windows_add_thread (ptid_t (current_event.dwProcessId, 0, + current_event.dwThreadId), + current_event.u.CreateThread.hThread, + current_event.u.CreateThread.lpThreadLocalBase, + true /* main_thread_p */); + return current_event.dwThreadId; } -static void -windows_resume (struct target_ops *ops, - ptid_t ptid, int step, enum gdb_signal sig) +void +windows_nat_target::resume (ptid_t ptid, int step, enum gdb_signal sig) { windows_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); + int resume_all = ptid == minus_one_ptid; /* If we're continuing all threads, it's the current inferior that should be handled specially. */ @@ -1222,12 +1427,11 @@ windows_resume (struct target_ops *ops, 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) + for (const xlate_exception &x : xlate) + if (x.us == sig) { current_event.u.Exception.ExceptionRecord.ExceptionCode - = xlate[i].them; + = x.them; continue_status = DBG_EXCEPTION_NOT_HANDLED; break; } @@ -1243,20 +1447,19 @@ windows_resume (struct target_ops *ops, last_sig = GDB_SIGNAL_0; - DEBUG_EXEC (("gdb: windows_resume (pid=%d, tid=%ld, step=%d, sig=%d);\n", - ptid_get_pid (ptid), ptid_get_tid (ptid), step, sig)); + DEBUG_EXEC (("gdb: windows_resume (pid=%d, tid=0x%x, step=%d, sig=%d);\n", + ptid.pid (), (unsigned) ptid.tid (), step, sig)); /* Get context for currently selected thread. */ - th = thread_rec (ptid_get_tid (inferior_ptid), FALSE); + th = thread_rec (inferior_ptid.tid (), FALSE); if (th) { if (step) { /* Single step by setting t bit. */ struct regcache *regcache = get_current_regcache (); - struct gdbarch *gdbarch = get_regcache_arch (regcache); - windows_fetch_inferior_registers (ops, regcache, - gdbarch_ps_regnum (gdbarch)); + struct gdbarch *gdbarch = regcache->arch (); + fetch_registers (regcache, gdbarch_ps_regnum (gdbarch)); th->context.EFlags |= FLAG_TRACE_BIT; } @@ -1282,7 +1485,7 @@ windows_resume (struct target_ops *ops, if (resume_all) windows_continue (continue_status, -1, 0); else - windows_continue (continue_status, ptid_get_tid (ptid), 0); + windows_continue (continue_status, ptid.tid (), 0); } /* Ctrl-C handler used when the inferior is not run in the same console. The @@ -1360,10 +1563,11 @@ get_windows_debug_event (struct target_ops *ops, } /* Record the existence of this thread. */ thread_id = current_event.dwThreadId; - th = windows_add_thread (ptid_build (current_event.dwProcessId, 0, - current_event.dwThreadId), - current_event.u.CreateThread.hThread, - current_event.u.CreateThread.lpThreadLocalBase); + th = windows_add_thread + (ptid_t (current_event.dwProcessId, 0, current_event.dwThreadId), + current_event.u.CreateThread.hThread, + current_event.u.CreateThread.lpThreadLocalBase, + false /* main_thread_p */); break; @@ -1372,14 +1576,11 @@ get_windows_debug_event (struct target_ops *ops, (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId, "EXIT_THREAD_DEBUG_EVENT")); - - if (current_event.dwThreadId != main_thread_id) - { - windows_delete_thread (ptid_build (current_event.dwProcessId, 0, - current_event.dwThreadId), - current_event.u.ExitThread.dwExitCode); - th = &dummy_thread_info; - } + windows_delete_thread (ptid_t (current_event.dwProcessId, 0, + current_event.dwThreadId), + current_event.u.ExitThread.dwExitCode, + false /* main_thread_p */); + th = &dummy_thread_info; break; case CREATE_PROCESS_DEBUG_EVENT: @@ -1392,16 +1593,13 @@ get_windows_debug_event (struct target_ops *ops, break; current_process_handle = current_event.u.CreateProcessInfo.hProcess; - if (main_thread_id) - windows_delete_thread (ptid_build (current_event.dwProcessId, 0, - main_thread_id), - 0); - main_thread_id = current_event.dwThreadId; /* Add the main thread. */ - th = windows_add_thread (ptid_build (current_event.dwProcessId, 0, - current_event.dwThreadId), - current_event.u.CreateProcessInfo.hThread, - current_event.u.CreateProcessInfo.lpThreadLocalBase); + th = windows_add_thread + (ptid_t (current_event.dwProcessId, 0, + current_event.dwThreadId), + current_event.u.CreateProcessInfo.hThread, + current_event.u.CreateProcessInfo.lpThreadLocalBase, + true /* main_thread_p */); thread_id = current_event.dwThreadId; break; @@ -1412,16 +1610,19 @@ get_windows_debug_event (struct target_ops *ops, "EXIT_PROCESS_DEBUG_EVENT")); if (!windows_initialization_done) { - target_terminal_ours (); - target_mourn_inferior (); + target_terminal::ours (); + target_mourn_inferior (inferior_ptid); error (_("During startup program exited with code 0x%x."), (unsigned int) current_event.u.ExitProcess.dwExitCode); } else if (saw_create == 1) { + windows_delete_thread (ptid_t (current_event.dwProcessId, 0, + current_event.dwThreadId), + 0, true /* main_thread_p */); ourstatus->kind = TARGET_WAITKIND_EXITED; ourstatus->value.integer = current_event.u.ExitProcess.dwExitCode; - thread_id = main_thread_id; + thread_id = current_event.dwThreadId; } break; @@ -1433,10 +1634,10 @@ get_windows_debug_event (struct target_ops *ops, CloseHandle (current_event.u.LoadDll.hFile); if (saw_create != 1 || ! windows_initialization_done) break; - catch_errors (handle_load_dll, NULL, (char *) "", RETURN_MASK_ALL); + catch_errors (handle_load_dll); ourstatus->kind = TARGET_WAITKIND_LOADED; ourstatus->value.integer = 0; - thread_id = main_thread_id; + thread_id = current_event.dwThreadId; break; case UNLOAD_DLL_DEBUG_EVENT: @@ -1446,10 +1647,10 @@ get_windows_debug_event (struct target_ops *ops, "UNLOAD_DLL_DEBUG_EVENT")); if (saw_create != 1 || ! windows_initialization_done) break; - catch_errors (handle_unload_dll, NULL, (char *) "", RETURN_MASK_ALL); + catch_errors (handle_unload_dll); ourstatus->kind = TARGET_WAITKIND_LOADED; ourstatus->value.integer = 0; - thread_id = main_thread_id; + thread_id = current_event.dwThreadId; break; case EXCEPTION_DEBUG_EVENT: @@ -1461,15 +1662,15 @@ get_windows_debug_event (struct target_ops *ops, break; switch (handle_exception (ourstatus)) { - case 0: + case HANDLE_EXCEPTION_UNHANDLED: + default: continue_status = DBG_EXCEPTION_NOT_HANDLED; break; - case 1: + case HANDLE_EXCEPTION_HANDLED: thread_id = current_event.dwThreadId; break; - case -1: - last_sig = 1; - continue_status = -1; + case HANDLE_EXCEPTION_IGNORED: + continue_status = DBG_CONTINUE; break; } break; @@ -1497,15 +1698,11 @@ get_windows_debug_event (struct target_ops *ops, if (!thread_id || saw_create != 1) { - if (continue_status == -1) - windows_resume (ops, minus_one_ptid, 0, 1); - else - CHECK (windows_continue (continue_status, -1, 0)); + CHECK (windows_continue (continue_status, -1, 0)); } else { - inferior_ptid = ptid_build (current_event.dwProcessId, 0, - thread_id); + inferior_ptid = ptid_t (current_event.dwProcessId, 0, thread_id); current_thread = th; if (!current_thread) current_thread = thread_rec (thread_id, TRUE); @@ -1516,14 +1713,12 @@ out: } /* Wait for interesting events to occur in the target process. */ -static ptid_t -windows_wait (struct target_ops *ops, - ptid_t ptid, struct target_waitstatus *ourstatus, int options) +ptid_t +windows_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus, + int options) { 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, which needs a current_thread->h. But some of these exceptions mark @@ -1561,11 +1756,11 @@ windows_wait (struct target_ops *ops, the user tries to resume the execution in the inferior. This is a classic race that we should try to fix one day. */ SetConsoleCtrlHandler (&ctrl_c_handler, TRUE); - retval = get_windows_debug_event (ops, pid, ourstatus); + retval = get_windows_debug_event (this, pid, ourstatus); SetConsoleCtrlHandler (&ctrl_c_handler, FALSE); if (retval) - return ptid_build (current_event.dwProcessId, 0, retval); + return ptid_t (current_event.dwProcessId, 0, retval); else { int detach = 0; @@ -1574,7 +1769,7 @@ windows_wait (struct target_ops *ops, detach = deprecated_ui_loop_hook (0); if (detach) - windows_kill_inferior (ops); + kill (); } } } @@ -1585,7 +1780,6 @@ windows_wait (struct target_ops *ops, static void windows_add_all_dlls (void) { - struct so_list *so; HMODULE dummy_hmodule; DWORD cb_needed; HMODULE *hmodules; @@ -1633,10 +1827,8 @@ windows_add_all_dlls (void) static void do_initial_windows_stuff (struct target_ops *ops, DWORD pid, int attaching) { - extern int stop_after_trap; int i; struct inferior *inf; - struct thread_info *tp; last_sig = GDB_SIGNAL_0; event_count = 0; @@ -1666,22 +1858,26 @@ do_initial_windows_stuff (struct target_ops *ops, DWORD pid, int attaching) can rely on it. When attaching, we don't know about any thread id here, but that's OK --- nothing should be referencing the current thread until we report an event out of windows_wait. */ - inferior_ptid = pid_to_ptid (pid); + inferior_ptid = ptid_t (pid); - target_terminal_init (); - target_terminal_inferior (); + target_terminal::init (); + target_terminal::inferior (); windows_initialization_done = 0; - inf->control.stop_soon = STOP_QUIETLY; + while (1) { - stop_after_trap = 1; - wait_for_inferior (); - tp = inferior_thread (); - if (tp->suspend.stop_signal != GDB_SIGNAL_TRAP) - resume (tp->suspend.stop_signal); - else + struct target_waitstatus status; + + ops->wait (minus_one_ptid, &status, 0); + + /* Note windows_wait returns TARGET_WAITKIND_SPURIOUS for thread + events. */ + if (status.kind != TARGET_WAITKIND_LOADED + && status.kind != TARGET_WAITKIND_SPURIOUS) break; + + ops->resume (minus_one_ptid, 0, GDB_SIGNAL_0); } /* Now that the inferior has been started and all DLLs have been mapped, @@ -1702,8 +1898,6 @@ do_initial_windows_stuff (struct target_ops *ops, DWORD pid, int attaching) windows_add_all_dlls (); windows_initialization_done = 1; - inf->control.stop_soon = NO_STOP_QUIETLY; - stop_after_trap = 0; return; } @@ -1757,8 +1951,9 @@ out: } /* Attach to process PID, then initialize for debugging it. */ -static void -windows_attach (struct target_ops *ops, const char *args, int from_tty) + +void +windows_nat_target::attach (const char *args, int from_tty) { BOOL ok; DWORD pid; @@ -1788,35 +1983,34 @@ windows_attach (struct target_ops *ops, const char *args, int from_tty) #endif if (!ok) - error (_("Can't attach to process.")); + error (_("Can't attach to process %u (error %u)"), + (unsigned) pid, (unsigned) GetLastError ()); DebugSetProcessKillOnExit (FALSE); if (from_tty) { - char *exec_file = (char *) get_exec_file (0); + const char *exec_file = 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))); + target_pid_to_str (ptid_t (pid)).c_str ()); else printf_unfiltered ("Attaching to %s\n", - target_pid_to_str (pid_to_ptid (pid))); - - gdb_flush (gdb_stdout); + target_pid_to_str (ptid_t (pid)).c_str ()); } - do_initial_windows_stuff (ops, pid, 1); - target_terminal_ours (); + do_initial_windows_stuff (this, pid, 1); + target_terminal::ours (); } -static void -windows_detach (struct target_ops *ops, const char *args, int from_tty) +void +windows_nat_target::detach (inferior *inf, int from_tty) { int detached = 1; - ptid_t ptid = {-1}; - windows_resume (ops, ptid, 0, GDB_SIGNAL_0); + ptid_t ptid = minus_one_ptid; + resume (ptid, 0, GDB_SIGNAL_0); if (!DebugActiveProcessStop (current_event.dwProcessId)) { @@ -1828,19 +2022,18 @@ windows_detach (struct target_ops *ops, const char *args, int from_tty) if (detached && from_tty) { - char *exec_file = get_exec_file (0); + const char *exec_file = get_exec_file (0); if (exec_file == 0) exec_file = ""; printf_unfiltered ("Detaching from program: %s, Pid %u\n", exec_file, (unsigned) current_event.dwProcessId); - gdb_flush (gdb_stdout); } x86_cleanup_dregs (); inferior_ptid = null_ptid; - detach_inferior (current_event.dwProcessId); + detach_inferior (inf); - inf_child_maybe_unpush_target (ops); + maybe_unpush_target (); } /* Try to determine the executable filename. @@ -1873,7 +2066,7 @@ windows_get_exec_module_filename (char *exe_name_ret, size_t exe_name_max_len) /* Cygwin prefers that the path be in /x/y/z format, so extract the filename into a temporary buffer first, and then convert it to POSIX format into the destination buffer. */ - cygwin_buf_t *pathbuf = alloca (exe_name_max_len * sizeof (cygwin_buf_t)); + cygwin_buf_t *pathbuf = (cygwin_buf_t *) alloca (exe_name_max_len * sizeof (cygwin_buf_t)); len = GetModuleFileNameEx (current_process_handle, dh_buf, pathbuf, exe_name_max_len); @@ -1897,8 +2090,8 @@ windows_get_exec_module_filename (char *exe_name_ret, size_t exe_name_max_len) /* The pid_to_exec_file target_ops method for this platform. */ -static char * -windows_pid_to_exec_file (struct target_ops *self, int pid) +char * +windows_nat_target::pid_to_exec_file (int pid) { static char path[__PMAX]; #ifdef __CYGWIN__ @@ -1925,14 +2118,14 @@ windows_pid_to_exec_file (struct target_ops *self, int pid) /* Print status information about what we're accessing. */ -static void -windows_files_info (struct target_ops *ignore) +void +windows_nat_target::files_info () { struct inferior *inf = current_inferior (); printf_unfiltered ("\tUsing the running image of %s %s.\n", inf->attach_flag ? "attached" : "child", - target_pid_to_str (inferior_ptid)); + target_pid_to_str (inferior_ptid).c_str ()); } /* Modify CreateProcess parameters for use of a new separate console. @@ -2014,19 +2207,316 @@ clear_win32_environment (char **env) } #endif +#ifndef __CYGWIN__ + +/* Redirection of inferior I/O streams for native MS-Windows programs. + Unlike on Unix, where this is handled by invoking the inferior via + the shell, on MS-Windows we need to emulate the cmd.exe shell. + + The official documentation of the cmd.exe redirection features is here: + + http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/redirection.mspx + + (That page talks about Windows XP, but there's no newer + documentation, so we assume later versions of cmd.exe didn't change + anything.) + + Caveat: the documentation on that page seems to include a few lies. + For example, it describes strange constructs 1<&2 and 2<&1, which + seem to work only when 1>&2 resp. 2>&1 would make sense, and so I + think the cmd.exe parser of the redirection symbols simply doesn't + care about the < vs > distinction in these cases. Therefore, the + supported features are explicitly documented below. + + The emulation below aims at supporting all the valid use cases + supported by cmd.exe, which include: + + < FILE redirect standard input from FILE + 0< FILE redirect standard input from FILE + <&N redirect standard input from file descriptor N + 0<&N redirect standard input from file descriptor N + > FILE redirect standard output to FILE + >> FILE append standard output to FILE + 1>> FILE append standard output to FILE + >&N redirect standard output to file descriptor N + 1>&N redirect standard output to file descriptor N + >>&N append standard output to file descriptor N + 1>>&N append standard output to file descriptor N + 2> FILE redirect standard error to FILE + 2>> FILE append standard error to FILE + 2>&N redirect standard error to file descriptor N + 2>>&N append standard error to file descriptor N + + Note that using N > 2 in the above construct is supported, but + requires that the corresponding file descriptor be open by some + means elsewhere or outside GDB. Also note that using ">&0" or + "<&2" will generally fail, because the file descriptor redirected + from is normally open in an incompatible mode (e.g., FD 0 is open + for reading only). IOW, use of such tricks is not recommended; + you are on your own. + + We do NOT support redirection of file descriptors above 2, as in + "3>SOME-FILE", because MinGW compiled programs don't (supporting + that needs special handling in the startup code that MinGW + doesn't have). Pipes are also not supported. + + As for invalid use cases, where the redirection contains some + error, the emulation below will detect that and produce some + error and/or failure. But the behavior in those cases is not + bug-for-bug compatible with what cmd.exe does in those cases. + That's because what cmd.exe does then is not well defined, and + seems to be a side effect of the cmd.exe parsing of the command + line more than anything else. For example, try redirecting to an + invalid file name, as in "> foo:bar". + + There are also minor syntactic deviations from what cmd.exe does + in some corner cases. For example, it doesn't support the likes + of "> &foo" to mean redirect to file named literally "&foo"; we + do support that here, because that, too, sounds like some issue + with the cmd.exe parser. Another nicety is that we support + redirection targets that use file names with forward slashes, + something cmd.exe doesn't -- this comes in handy since GDB + file-name completion can be used when typing the command line for + the inferior. */ + +/* Support routines for redirecting standard handles of the inferior. */ + +/* Parse a single redirection spec, open/duplicate the specified + file/fd, and assign the appropriate value to one of the 3 standard + file descriptors. */ +static int +redir_open (const char *redir_string, int *inp, int *out, int *err) +{ + int *fd, ref_fd = -2; + int mode; + const char *fname = redir_string + 1; + int rc = *redir_string; + + switch (rc) + { + case '0': + fname++; + /* FALLTHROUGH */ + case '<': + fd = inp; + mode = O_RDONLY; + break; + case '1': case '2': + fname++; + /* FALLTHROUGH */ + case '>': + fd = (rc == '2') ? err : out; + mode = O_WRONLY | O_CREAT; + if (*fname == '>') + { + fname++; + mode |= O_APPEND; + } + else + mode |= O_TRUNC; + break; + default: + return -1; + } + + if (*fname == '&' && '0' <= fname[1] && fname[1] <= '9') + { + /* A reference to a file descriptor. */ + char *fdtail; + ref_fd = (int) strtol (fname + 1, &fdtail, 10); + if (fdtail > fname + 1 && *fdtail == '\0') + { + /* Don't allow redirection when open modes are incompatible. */ + if ((ref_fd == 0 && (fd == out || fd == err)) + || ((ref_fd == 1 || ref_fd == 2) && fd == inp)) + { + errno = EPERM; + return -1; + } + if (ref_fd == 0) + ref_fd = *inp; + else if (ref_fd == 1) + ref_fd = *out; + else if (ref_fd == 2) + ref_fd = *err; + } + else + { + errno = EBADF; + return -1; + } + } + else + fname++; /* skip the separator space */ + /* If the descriptor is already open, close it. This allows + multiple specs of redirections for the same stream, which is + somewhat nonsensical, but still valid and supported by cmd.exe. + (But cmd.exe only opens a single file in this case, the one + specified by the last redirection spec on the command line.) */ + if (*fd >= 0) + _close (*fd); + if (ref_fd == -2) + { + *fd = _open (fname, mode, _S_IREAD | _S_IWRITE); + if (*fd < 0) + return -1; + } + else if (ref_fd == -1) + *fd = -1; /* reset to default destination */ + else + { + *fd = _dup (ref_fd); + if (*fd < 0) + return -1; + } + /* _open just sets a flag for O_APPEND, which won't be passed to the + inferior, so we need to actually move the file pointer. */ + if ((mode & O_APPEND) != 0) + _lseek (*fd, 0L, SEEK_END); + return 0; +} + +/* Canonicalize a single redirection spec and set up the corresponding + file descriptor as specified. */ +static int +redir_set_redirection (const char *s, int *inp, int *out, int *err) +{ + char buf[__PMAX + 2 + 5]; /* extra space for quotes & redirection string */ + char *d = buf; + const char *start = s; + int quote = 0; + + *d++ = *s++; /* copy the 1st character, < or > or a digit */ + if ((*start == '>' || *start == '1' || *start == '2') + && *s == '>') + { + *d++ = *s++; + if (*s == '>' && *start != '>') + *d++ = *s++; + } + else if (*start == '0' && *s == '<') + *d++ = *s++; + /* cmd.exe recognizes "&N" only immediately after the redirection symbol. */ + if (*s != '&') + { + while (isspace (*s)) /* skip whitespace before file name */ + s++; + *d++ = ' '; /* separate file name with a single space */ + } + + /* Copy the file name. */ + while (*s) + { + /* Remove quoting characters from the file name in buf[]. */ + if (*s == '"') /* could support '..' quoting here */ + { + if (!quote) + quote = *s++; + else if (*s == quote) + { + quote = 0; + s++; + } + else + *d++ = *s++; + } + else if (*s == '\\') + { + if (s[1] == '"') /* could support '..' here */ + s++; + *d++ = *s++; + } + else if (isspace (*s) && !quote) + break; + else + *d++ = *s++; + if (d - buf >= sizeof (buf) - 1) + { + errno = ENAMETOOLONG; + return 0; + } + } + *d = '\0'; + + /* Windows doesn't allow redirection characters in file names, so we + can bail out early if they use them, or if there's no target file + name after the redirection symbol. */ + if (d[-1] == '>' || d[-1] == '<') + { + errno = ENOENT; + return 0; + } + if (redir_open (buf, inp, out, err) == 0) + return s - start; + return 0; +} + +/* Parse the command line for redirection specs and prepare the file + descriptors for the 3 standard streams accordingly. */ +static bool +redirect_inferior_handles (const char *cmd_orig, char *cmd, + int *inp, int *out, int *err) +{ + const char *s = cmd_orig; + char *d = cmd; + int quote = 0; + bool retval = false; + + while (isspace (*s)) + *d++ = *s++; + + while (*s) + { + if (*s == '"') /* could also support '..' quoting here */ + { + if (!quote) + quote = *s; + else if (*s == quote) + quote = 0; + } + else if (*s == '\\') + { + if (s[1] == '"') /* escaped quote char */ + s++; + } + else if (!quote) + { + /* Process a single redirection candidate. */ + if (*s == '<' || *s == '>' + || ((*s == '1' || *s == '2') && s[1] == '>') + || (*s == '0' && s[1] == '<')) + { + int skip = redir_set_redirection (s, inp, out, err); + + if (skip <= 0) + return false; + retval = true; + s += skip; + } + } + if (*s) + *d++ = *s++; + } + *d = '\0'; + return retval; +} +#endif /* !__CYGWIN__ */ + /* Start an inferior windows child process and sets inferior_ptid to its pid. EXEC_FILE is the file to run. ALLARGS is a string containing the arguments to the program. ENV is the environment vector to pass. Errors reported with error(). */ -static void -windows_create_inferior (struct target_ops *ops, char *exec_file, - char *allargs, char **in_env, int from_tty) +void +windows_nat_target::create_inferior (const char *exec_file, + const std::string &origallargs, + char **in_env, int from_tty) { STARTUPINFO si; #ifdef __CYGWIN__ cygwin_buf_t real_path[__PMAX]; cygwin_buf_t shell[__PMAX]; /* Path to shell */ + cygwin_buf_t infcwd[__PMAX]; const char *sh; cygwin_buf_t *toexec; cygwin_buf_t *cygallargs; @@ -2036,20 +2526,22 @@ windows_create_inferior (struct target_ops *ops, char *exec_file, size_t len; int tty; int ostdin, ostdout, ostderr; -#else - char real_path[__PMAX]; +#else /* !__CYGWIN__ */ char shell[__PMAX]; /* Path to shell */ - char *toexec; - char *args; - size_t args_len; - HANDLE tty; + const char *toexec; + char *args, *allargs_copy; + size_t args_len, allargs_len; + int fd_inp = -1, fd_out = -1, fd_err = -1; + HANDLE tty = INVALID_HANDLE_VALUE; + bool redirected = false; char *w32env; char *temp; size_t envlen; int i; size_t envsize; char **env; -#endif +#endif /* !__CYGWIN__ */ + const char *allargs = origallargs.c_str (); PROCESS_INFORMATION pi; BOOL ret; DWORD flags = 0; @@ -2058,6 +2550,17 @@ windows_create_inferior (struct target_ops *ops, char *exec_file, if (!exec_file) error (_("No executable specified, use `target exec'.")); + const char *inferior_cwd = get_inferior_cwd (); + std::string expanded_infcwd; + if (inferior_cwd != NULL) + { + expanded_infcwd = gdb_tilde_expand (inferior_cwd); + /* Mirror slashes on inferior's cwd. */ + std::replace (expanded_infcwd.begin (), expanded_infcwd.end (), + '/', '\\'); + inferior_cwd = expanded_infcwd.c_str (); + } + memset (&si, 0, sizeof (si)); si.cb = sizeof (si); @@ -2081,15 +2584,13 @@ windows_create_inferior (struct target_ops *ops, char *exec_file, error (_("Error starting executable: %d"), errno); cygallargs = (wchar_t *) alloca (len * sizeof (wchar_t)); mbstowcs (cygallargs, allargs, len); -#else +#else /* !__USEWIDE */ cygallargs = allargs; #endif } else { - sh = getenv ("SHELL"); - if (!sh) - sh = "/bin/sh"; + sh = get_shell (); if (cygwin_conv_path (CCP_POSIX_TO_WIN_W, sh, shell, __PMAX) < 0) error (_("Error starting executable via shell: %d"), errno); #ifdef __USEWIDE @@ -2097,28 +2598,33 @@ windows_create_inferior (struct target_ops *ops, char *exec_file, + mbstowcs (NULL, allargs, 0) + 2; cygallargs = (wchar_t *) alloca (len * sizeof (wchar_t)); swprintf (cygallargs, len, L" -c 'exec %s %s'", exec_file, allargs); -#else +#else /* !__USEWIDE */ len = (sizeof (" -c 'exec '") + strlen (exec_file) + strlen (allargs) + 2); cygallargs = (char *) alloca (len); xsnprintf (cygallargs, len, " -c 'exec %s %s'", exec_file, allargs); -#endif +#endif /* __USEWIDE */ toexec = shell; flags |= DEBUG_PROCESS; } + if (inferior_cwd != NULL + && cygwin_conv_path (CCP_POSIX_TO_WIN_W, inferior_cwd, + infcwd, strlen (inferior_cwd)) < 0) + error (_("Error converting inferior cwd: %d"), errno); + #ifdef __USEWIDE args = (cygwin_buf_t *) alloca ((wcslen (toexec) + wcslen (cygallargs) + 2) * sizeof (wchar_t)); wcscpy (args, toexec); wcscat (args, L" "); wcscat (args, cygallargs); -#else +#else /* !__USEWIDE */ args = (cygwin_buf_t *) alloca (strlen (toexec) + strlen (cygallargs) + 2); strcpy (args, toexec); strcat (args, " "); strcat (args, cygallargs); -#endif +#endif /* !__USEWIDE */ #ifdef CW_CVT_ENV_TO_WINENV /* First try to create a direct Win32 copy of the POSIX environment. */ @@ -2127,7 +2633,7 @@ windows_create_inferior (struct target_ops *ops, char *exec_file, flags |= CREATE_UNICODE_ENVIRONMENT; else /* If that fails, fall back to old method tweaking GDB's environment. */ -#endif +#endif /* CW_CVT_ENV_TO_WINENV */ { /* Reset all Win32 environment variables to avoid leftover on next run. */ clear_win32_environment (environ); @@ -2167,7 +2673,8 @@ windows_create_inferior (struct target_ops *ops, char *exec_file, TRUE, /* inherit handles */ flags, /* start flags */ w32_env, /* environment */ - NULL, /* current directory */ + inferior_cwd != NULL ? infcwd : NULL, /* current + directory */ &si, &pi); if (w32_env) @@ -2184,29 +2691,34 @@ windows_create_inferior (struct target_ops *ops, char *exec_file, if (tty >= 0) { - close (tty); + ::close (tty); dup2 (ostdin, 0); dup2 (ostdout, 1); dup2 (ostderr, 2); - close (ostdin); - close (ostdout); - close (ostderr); + ::close (ostdin); + ::close (ostdout); + ::close (ostderr); } -#else - toexec = exec_file; - /* Build the command line, a space-separated list of tokens where - the first token is the name of the module to be executed. - To avoid ambiguities introduced by spaces in the module name, - we quote it. */ - args_len = strlen (toexec) + 2 /* quotes */ + strlen (allargs) + 2; - args = alloca (args_len); - xsnprintf (args, args_len, "\"%s\" %s", toexec, allargs); - - flags |= DEBUG_ONLY_THIS_PROCESS; - - if (!inferior_io_terminal) - tty = INVALID_HANDLE_VALUE; - else +#else /* !__CYGWIN__ */ + allargs_len = strlen (allargs); + allargs_copy = strcpy ((char *) alloca (allargs_len + 1), allargs); + if (strpbrk (allargs_copy, "<>") != NULL) + { + int e = errno; + errno = 0; + redirected = + redirect_inferior_handles (allargs, allargs_copy, + &fd_inp, &fd_out, &fd_err); + if (errno) + warning (_("Error in redirection: %s."), safe_strerror (errno)); + else + errno = e; + allargs_len = strlen (allargs_copy); + } + /* If not all the standard streams are redirected by the command + line, use inferior_io_terminal for those which aren't. */ + if (inferior_io_terminal + && !(fd_inp >= 0 && fd_out >= 0 && fd_err >= 0)) { SECURITY_ATTRIBUTES sa; sa.nLength = sizeof(sa); @@ -2217,15 +2729,41 @@ windows_create_inferior (struct target_ops *ops, char *exec_file, if (tty == INVALID_HANDLE_VALUE) warning (_("Warning: Failed to open TTY %s, error %#x."), inferior_io_terminal, (unsigned) GetLastError ()); + } + if (redirected || tty != INVALID_HANDLE_VALUE) + { + if (fd_inp >= 0) + si.hStdInput = (HANDLE) _get_osfhandle (fd_inp); + else if (tty != INVALID_HANDLE_VALUE) + si.hStdInput = tty; else - { - si.hStdInput = tty; - si.hStdOutput = tty; - si.hStdError = tty; - si.dwFlags |= STARTF_USESTDHANDLES; - } + si.hStdInput = GetStdHandle (STD_INPUT_HANDLE); + if (fd_out >= 0) + si.hStdOutput = (HANDLE) _get_osfhandle (fd_out); + else if (tty != INVALID_HANDLE_VALUE) + si.hStdOutput = tty; + else + si.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE); + if (fd_err >= 0) + si.hStdError = (HANDLE) _get_osfhandle (fd_err); + else if (tty != INVALID_HANDLE_VALUE) + si.hStdError = tty; + else + si.hStdError = GetStdHandle (STD_ERROR_HANDLE); + si.dwFlags |= STARTF_USESTDHANDLES; } + toexec = exec_file; + /* Build the command line, a space-separated list of tokens where + the first token is the name of the module to be executed. + To avoid ambiguities introduced by spaces in the module name, + we quote it. */ + args_len = strlen (toexec) + 2 /* quotes */ + allargs_len + 2; + args = (char *) alloca (args_len); + xsnprintf (args, args_len, "\"%s\" %s", toexec, allargs_copy); + + flags |= DEBUG_ONLY_THIS_PROCESS; + /* CreateProcess takes the environment list as a null terminated set of strings (i.e. two nulls terminate the list). */ @@ -2239,7 +2777,7 @@ windows_create_inferior (struct target_ops *ops, char *exec_file, /* Windows programs expect the environment block to be sorted. */ qsort (env, i, sizeof (char *), envvar_cmp); - w32env = alloca (envlen + 1); + w32env = (char *) alloca (envlen + 1); /* Copy env strings into new buffer. */ for (temp = w32env, i = 0; env[i] && *env[i]; i++) @@ -2259,12 +2797,18 @@ windows_create_inferior (struct target_ops *ops, char *exec_file, TRUE, /* inherit handles */ flags, /* start flags */ w32env, /* environment */ - NULL, /* current directory */ + inferior_cwd, /* current directory */ &si, &pi); if (tty != INVALID_HANDLE_VALUE) CloseHandle (tty); -#endif + if (fd_inp >= 0) + _close (fd_inp); + if (fd_out >= 0) + _close (fd_out); + if (fd_err >= 0) + _close (fd_err); +#endif /* !__CYGWIN__ */ if (!ret) error (_("Error creating process %s, (error %u)."), @@ -2278,13 +2822,13 @@ windows_create_inferior (struct target_ops *ops, char *exec_file, else saw_create = 0; - do_initial_windows_stuff (ops, pi.dwProcessId, 0); + do_initial_windows_stuff (this, pi.dwProcessId, 0); /* windows_continue (DBG_CONTINUE, -1, 0); */ } -static void -windows_mourn_inferior (struct target_ops *ops) +void +windows_nat_target::mourn_inferior () { (void) windows_continue (DBG_CONTINUE, -1, 0); x86_cleanup_dregs(); @@ -2293,14 +2837,14 @@ windows_mourn_inferior (struct target_ops *ops) CHECK (CloseHandle (current_process_handle)); open_process_used = 0; } - inf_child_mourn_inferior (ops); + inf_child_target::mourn_inferior (); } /* Send a SIGINT to the process group. This acts just like the user typed a ^C on the controlling terminal. */ -static void -windows_stop (struct target_ops *self, ptid_t ptid) +void +windows_nat_target::interrupt () { DEBUG_EVENTS (("gdb: GenerateConsoleCtrlEvent (CTRLC_EVENT, 0)\n")); CHECK (GenerateConsoleCtrlEvent (CTRL_C_EVENT, current_event.dwProcessId)); @@ -2347,8 +2891,8 @@ windows_xfer_memory (gdb_byte *readbuf, const gdb_byte *writebuf, return success ? TARGET_XFER_OK : TARGET_XFER_E_IO; } -static void -windows_kill_inferior (struct target_ops *ops) +void +windows_nat_target::kill () { CHECK (TerminateProcess (current_process_handle, 0)); @@ -2362,28 +2906,22 @@ windows_kill_inferior (struct target_ops *ops) break; } - target_mourn_inferior (); /* Or just windows_mourn_inferior? */ + target_mourn_inferior (inferior_ptid); /* Or just windows_mourn_inferior? */ } -static void -windows_close (struct target_ops *self) +void +windows_nat_target::close () { DEBUG_EVENTS (("gdb: windows_close, inferior_ptid=%d\n", - ptid_get_pid (inferior_ptid))); + inferior_ptid.pid ())); } /* Convert pid to printable format. */ -static char * -windows_pid_to_str (struct target_ops *ops, ptid_t ptid) +std::string +windows_nat_target::pid_to_str (ptid_t ptid) { - static char buf[80]; - - if (ptid_get_tid (ptid) != 0) - { - snprintf (buf, sizeof (buf), "Thread %d.0x%lx", - ptid_get_pid (ptid), ptid_get_tid (ptid)); - return buf; - } + if (ptid.tid () != 0) + return string_printf ("Thread %d.0x%lx", ptid.pid (), ptid.tid ()); return normal_pid_to_str (ptid); } @@ -2406,12 +2944,16 @@ windows_xfer_shared_libraries (struct target_ops *ops, obstack_init (&obstack); obstack_grow_str (&obstack, "\n"); for (so = solib_start.next; so; so = so->next) - windows_xfer_shared_library (so->so_name, (CORE_ADDR) - (uintptr_t) so->lm_info->load_addr, - target_gdbarch (), &obstack); + { + lm_info_windows *li = (lm_info_windows *) so->lm_info; + + windows_xfer_shared_library (so->so_name, (CORE_ADDR) + (uintptr_t) li->load_addr, + target_gdbarch (), &obstack); + } obstack_grow_str0 (&obstack, "\n"); - buf = obstack_finish (&obstack); + buf = (const char *) obstack_finish (&obstack); len_avail = strlen (buf); if (offset >= len_avail) len= 0; @@ -2427,11 +2969,11 @@ windows_xfer_shared_libraries (struct target_ops *ops, return len != 0 ? TARGET_XFER_OK : TARGET_XFER_EOF; } -static enum target_xfer_status -windows_xfer_partial (struct target_ops *ops, enum target_object object, - const char *annex, gdb_byte *readbuf, - const gdb_byte *writebuf, ULONGEST offset, ULONGEST len, - ULONGEST *xfered_len) +enum target_xfer_status +windows_nat_target::xfer_partial (enum target_object object, + const char *annex, gdb_byte *readbuf, + const gdb_byte *writebuf, ULONGEST offset, + ULONGEST len, ULONGEST *xfered_len) { switch (object) { @@ -2439,87 +2981,59 @@ windows_xfer_partial (struct target_ops *ops, enum target_object object, return windows_xfer_memory (readbuf, writebuf, offset, len, xfered_len); case TARGET_OBJECT_LIBRARIES: - return windows_xfer_shared_libraries (ops, object, annex, readbuf, + return windows_xfer_shared_libraries (this, object, annex, readbuf, writebuf, offset, len, xfered_len); default: - return ops->beneath->to_xfer_partial (ops->beneath, object, annex, - readbuf, writebuf, offset, len, - xfered_len); + if (beneath () == NULL) + { + /* This can happen when requesting the transfer of unsupported + objects before a program has been started (and therefore + with the current_target having no target beneath). */ + return TARGET_XFER_E_IO; + } + return beneath ()->xfer_partial (object, annex, + readbuf, writebuf, offset, len, + xfered_len); } } /* Provide thread local base, i.e. Thread Information Block address. Returns 1 if ptid is found and sets *ADDR to thread_local_base. */ -static int -windows_get_tib_address (struct target_ops *self, - ptid_t ptid, CORE_ADDR *addr) +bool +windows_nat_target::get_tib_address (ptid_t ptid, CORE_ADDR *addr) { windows_thread_info *th; - th = thread_rec (ptid_get_tid (ptid), 0); + th = thread_rec (ptid.tid (), 0); if (th == NULL) - return 0; + return false; if (addr != NULL) *addr = th->thread_local_base; - return 1; + return true; } -static ptid_t -windows_get_ada_task_ptid (struct target_ops *self, long lwp, long thread) +ptid_t +windows_nat_target::get_ada_task_ptid (long lwp, long thread) { - return ptid_build (ptid_get_pid (inferior_ptid), 0, lwp); + return ptid_t (inferior_ptid.pid (), 0, lwp); } -static struct target_ops * -windows_target (void) -{ - struct target_ops *t = inf_child_target (); - - t->to_close = windows_close; - t->to_attach = windows_attach; - t->to_attach_no_wait = 1; - t->to_detach = windows_detach; - t->to_resume = windows_resume; - t->to_wait = windows_wait; - t->to_fetch_registers = windows_fetch_inferior_registers; - t->to_store_registers = windows_store_inferior_registers; - t->to_xfer_partial = windows_xfer_partial; - t->to_files_info = windows_files_info; - t->to_kill = windows_kill_inferior; - t->to_create_inferior = windows_create_inferior; - t->to_mourn_inferior = windows_mourn_inferior; - t->to_thread_alive = windows_thread_alive; - t->to_pid_to_str = windows_pid_to_str; - t->to_stop = windows_stop; - t->to_pid_to_exec_file = windows_pid_to_exec_file; - t->to_get_ada_task_ptid = windows_get_ada_task_ptid; - t->to_get_tib_address = windows_get_tib_address; - - return t; -} +/* Implementation of the to_thread_name method. */ -static void -set_windows_aliases (char *argv0) +const char * +windows_nat_target::thread_name (struct thread_info *thr) { - add_info_alias ("dll", "sharedlibrary", 1); + return thread_rec (thr->ptid.tid (), 0)->name; } -/* -Wmissing-prototypes */ -extern initialize_file_ftype _initialize_windows_nat; void _initialize_windows_nat (void) { - struct target_ops *t; - - t = windows_target (); - - x86_use_watchpoints (t); - x86_dr_low.set_control = cygwin_set_dr7; x86_dr_low.set_addr = cygwin_set_dr; x86_dr_low.get_addr = cygwin_get_dr; @@ -2530,12 +3044,19 @@ _initialize_windows_nat (void) calling x86_set_debug_register_length function in processor windows specific native file. */ - add_target (t); + add_inf_child_target (&the_windows_nat_target); #ifdef __CYGWIN__ cygwin_internal (CW_SET_DOS_FILE_WARNING, 0); #endif + add_com ("signal-event", class_run, signal_event_command, _("\ +Signal a crashed process with event ID, to allow its debugging.\n\ +This command is needed in support of setting up GDB as JIT debugger on \ +MS-Windows. The command should be invoked from the GDB command line using \ +the '-ex' command-line option. The ID of the event that blocks the \ +crashed process will be supplied by the Windows JIT debugging mechanism.")); + #ifdef __CYGWIN__ add_setshow_boolean_cmd ("shell", class_support, &useshell, _("\ Set use of shell to start subprocess."), _("\ @@ -2601,7 +3122,6 @@ Show whether to display kernel exceptions in child process."), NULL, add_cmd ("selector", class_info, display_selectors, _("Display selectors infos."), &info_w32_cmdlist); - deprecated_init_ui_hook = set_windows_aliases; } /* Hardware watchpoint support, adapted from go32-nat.c code. */ @@ -2661,21 +3181,18 @@ cygwin_get_dr7 (void) /* Determine if the thread referenced by "ptid" is alive by "polling" it. If WaitForSingleObject returns WAIT_OBJECT_0 it means that the thread has died. Otherwise it is assumed to be alive. */ -static int -windows_thread_alive (struct target_ops *ops, ptid_t ptid) + +bool +windows_nat_target::thread_alive (ptid_t ptid) { int tid; - gdb_assert (ptid_get_tid (ptid) != 0); - tid = ptid_get_tid (ptid); + gdb_assert (ptid.tid () != 0); + tid = ptid.tid (); - return WaitForSingleObject (thread_rec (tid, FALSE)->h, 0) == WAIT_OBJECT_0 - ? FALSE : TRUE; + return WaitForSingleObject (thread_rec (tid, FALSE)->h, 0) != WAIT_OBJECT_0; } -/* -Wmissing-prototypes */ -extern initialize_file_ftype _initialize_check_for_gdb_ini; - void _initialize_check_for_gdb_ini (void) { @@ -2688,7 +3205,7 @@ _initialize_check_for_gdb_ini (void) { char *p; char *oldini = (char *) alloca (strlen (homedir) + - sizeof ("/gdb.ini")); + sizeof ("gdb.ini") + 1); strcpy (oldini, homedir); p = strchr (oldini, '\0'); if (p > oldini && !IS_DIR_SEPARATOR (p[-1])) @@ -2697,9 +3214,9 @@ _initialize_check_for_gdb_ini (void) if (access (oldini, 0) == 0) { int len = strlen (oldini); - char *newini = alloca (len + 1); + char *newini = (char *) alloca (len + 2); - xsnprintf (newini, len + 1, "%.*s.gdbinit", + xsnprintf (newini, len + 2, "%.*s.gdbinit", (int) (len - (sizeof ("gdb.ini") - 1)), oldini); warning (_("obsolete '%s' found. Rename to '%s'."), oldini, newini); } @@ -2770,9 +3287,6 @@ bad_GetConsoleFontSize (HANDLE w, DWORD nFont) return size; } -/* -Wmissing-prototypes */ -extern initialize_file_ftype _initialize_loadable; - /* Load any functions which may not be available in ancient versions of Windows. */ @@ -2781,19 +3295,18 @@ _initialize_loadable (void) { HMODULE hm = NULL; +#define GPA(m, func) \ + func = (func ## _ftype *) GetProcAddress (m, #func) + hm = LoadLibrary ("kernel32.dll"); if (hm) { - DebugActiveProcessStop = (void *) - GetProcAddress (hm, "DebugActiveProcessStop"); - DebugBreakProcess = (void *) - GetProcAddress (hm, "DebugBreakProcess"); - DebugSetProcessKillOnExit = (void *) - GetProcAddress (hm, "DebugSetProcessKillOnExit"); - GetConsoleFontSize = (void *) - GetProcAddress (hm, "GetConsoleFontSize"); - GetCurrentConsoleFont = (void *) - GetProcAddress (hm, "GetCurrentConsoleFont"); + GPA (hm, DebugActiveProcessStop); + GPA (hm, DebugBreakProcess); + GPA (hm, DebugSetProcessKillOnExit); + GPA (hm, GetConsoleFontSize); + GPA (hm, DebugActiveProcessStop); + GPA (hm, GetCurrentConsoleFont); } /* Set variables to dummy versions of these processes if the function @@ -2815,12 +3328,10 @@ _initialize_loadable (void) hm = LoadLibrary ("psapi.dll"); if (hm) { - EnumProcessModules = (void *) - GetProcAddress (hm, "EnumProcessModules"); - GetModuleInformation = (void *) - GetProcAddress (hm, "GetModuleInformation"); - GetModuleFileNameEx = (void *) - GetProcAddress (hm, GetModuleFileNameEx_name); + GPA (hm, EnumProcessModules); + GPA (hm, GetModuleInformation); + GetModuleFileNameEx = (GetModuleFileNameEx_ftype *) + GetProcAddress (hm, GetModuleFileNameEx_name); } if (!EnumProcessModules || !GetModuleInformation || !GetModuleFileNameEx) @@ -2840,15 +3351,15 @@ Use \"file\" or \"dll\" command to load executable/libraries directly.")); hm = LoadLibrary ("advapi32.dll"); if (hm) { - OpenProcessToken = (void *) GetProcAddress (hm, "OpenProcessToken"); - LookupPrivilegeValueA = (void *) - GetProcAddress (hm, "LookupPrivilegeValueA"); - AdjustTokenPrivileges = (void *) - GetProcAddress (hm, "AdjustTokenPrivileges"); + GPA (hm, OpenProcessToken); + GPA (hm, LookupPrivilegeValueA); + GPA (hm, AdjustTokenPrivileges); /* Only need to set one of these since if OpenProcessToken fails nothing else is needed. */ if (!OpenProcessToken || !LookupPrivilegeValueA || !AdjustTokenPrivileges) OpenProcessToken = bad_OpenProcessToken; } + +#undef GPA }