diff options
author | Stan Shebs <shebs@codesourcery.com> | 1999-04-16 01:34:07 +0000 |
---|---|---|
committer | Stan Shebs <shebs@codesourcery.com> | 1999-04-16 01:34:07 +0000 |
commit | 071ea11e85eb9d529cc5eb3d35f6247466a21b99 (patch) | |
tree | 5deda65b8d7b04d1f4cbc534c3206d328e1267ec /gdb/win32-nat.c | |
parent | 1730ec6b1848f0f32154277f788fb29f88d8475b (diff) | |
download | gdb-071ea11e85eb9d529cc5eb3d35f6247466a21b99.zip gdb-071ea11e85eb9d529cc5eb3d35f6247466a21b99.tar.gz gdb-071ea11e85eb9d529cc5eb3d35f6247466a21b99.tar.bz2 |
Initial creation of sourceware repository
Diffstat (limited to 'gdb/win32-nat.c')
-rw-r--r-- | gdb/win32-nat.c | 1122 |
1 files changed, 0 insertions, 1122 deletions
diff --git a/gdb/win32-nat.c b/gdb/win32-nat.c deleted file mode 100644 index 87e96bd..0000000 --- a/gdb/win32-nat.c +++ /dev/null @@ -1,1122 +0,0 @@ -/* Target-vector operations for controlling win32 child processes, for GDB. - Copyright 1995, 1996, 1997, 1998 Free Software Foundation, Inc. - Contributed by Cygnus Support. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without eve nthe implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -/* 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 "wait.h" -#include "gdbcore.h" -#include "command.h" -#include <signal.h> -#include <sys/types.h> -#include <fcntl.h> -#include <stdlib.h> - -#ifdef _MSC_VER -#include "windefs.h" -#else /* other WIN32 compiler */ -#include <windows.h> -#endif - -#include "buildsym.h" -#include "symfile.h" -#include "objfiles.h" -#include "gdb_string.h" -#include "gdbthread.h" -#include "gdbcmd.h" -#include <sys/param.h> -#include <unistd.h> - -/* 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" - -#define CHECK(x) check (x, __FILE__,__LINE__) -#define DEBUG_EXEC(x) if (debug_exec) printf x -#define DEBUG_EVENTS(x) if (debug_events) printf x -#define DEBUG_MEM(x) if (debug_memory) printf x -#define DEBUG_EXCEPT(x) if (debug_exceptions) printf x - -/* Forward declaration */ -extern struct target_ops child_ops; - -static void child_stop PARAMS ((void)); -static int win32_child_thread_alive PARAMS ((int)); - -static int last_sig = 0; /* Set if a signal was received from the - debugged process */ - -/* Thread information structure used to track information that is - not available in gdb's thread structure. */ -typedef struct thread_info_struct -{ - struct thread_info_struct *next; - DWORD id; - HANDLE h; - char *name; - int suspend_count; - CONTEXT context; -} thread_info; - -static thread_info thread_head = {NULL}; - -/* The process and thread handles for the above context. */ - -static DEBUG_EVENT current_event; /* The current debug event from - WaitForDebugEvent */ -static HANDLE current_process_handle; /* Currently executing process */ -static thread_info *current_thread; /* Info on currently selected thread */ -static DWORD main_thread_id; /* Thread ID of the main thread */ - -/* Counts of things. */ -static int exception_count = 0; -static int event_count = 0; - -/* User options. */ -static int new_console = 0; -static int new_group = 0; -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 */ - -/* This vector maps GDB's idea of a register's number into an address - in the win32 exception context vector. - - It also contains the bit mask needed to load the register in question. - - One day we could read a reg, we could inspect the context we - already have loaded, if it doesn't have the bit set that we need, - we read that set of registers in using GetThreadContext. If the - context already contains what we need, we just unpack it. Then to - write a register, first we have to ensure that the context contains - the other regs of the group, and then we copy the info in and set - out bit. */ - -#define context_offset(x) ((int)&(((CONTEXT *)NULL)->x)) -static const int mappings[] = -{ - context_offset(Eax), - context_offset(Ecx), - context_offset(Edx), - context_offset(Ebx), - context_offset(Esp), - context_offset(Ebp), - context_offset(Esi), - context_offset(Edi), - context_offset(Eip), - context_offset(EFlags), - context_offset(SegCs), - context_offset(SegSs), - context_offset(SegDs), - context_offset(SegEs), - context_offset(SegFs), - context_offset(SegGs), - context_offset(FloatSave.RegisterArea[0 * 10]), - context_offset(FloatSave.RegisterArea[1 * 10]), - context_offset(FloatSave.RegisterArea[2 * 10]), - context_offset(FloatSave.RegisterArea[3 * 10]), - context_offset(FloatSave.RegisterArea[4 * 10]), - context_offset(FloatSave.RegisterArea[5 * 10]), - context_offset(FloatSave.RegisterArea[6 * 10]), - context_offset(FloatSave.RegisterArea[7 * 10]), -}; - -/* This vector maps the target's idea of an exception (extracted - from the DEBUG_EVENT structure) to GDB's idea. */ - -struct xlate_exception - { - int them; - enum target_signal us; - }; - -static const struct xlate_exception - xlate[] = -{ - {EXCEPTION_ACCESS_VIOLATION, TARGET_SIGNAL_SEGV}, - {STATUS_STACK_OVERFLOW, TARGET_SIGNAL_SEGV}, - {EXCEPTION_BREAKPOINT, TARGET_SIGNAL_TRAP}, - {DBG_CONTROL_C, TARGET_SIGNAL_INT}, - {EXCEPTION_SINGLE_STEP, TARGET_SIGNAL_TRAP}, - {-1, -1}}; - -/* Find a thread record given a thread id. - If get_context then also retrieve the context for this - thread. */ -static thread_info * -thread_rec (DWORD id, int get_context) -{ - thread_info *th; - - for (th = &thread_head; (th = th->next) != NULL; ) - if (th->id == id) - { - if (!th->suspend_count && get_context) - { - if (get_context > 0) - th->suspend_count = SuspendThread (th->h) + 1; - else if (get_context < 0) - th->suspend_count = -1; - - th->context.ContextFlags = CONTEXT_DEBUGGER; - GetThreadContext (th->h, &th->context); - } - return th; - } - - return NULL; -} - -/* Add a thread to the thread list */ -static thread_info * -child_add_thread(DWORD id, HANDLE h) -{ - thread_info *th; - - if ((th = thread_rec (id, FALSE))) - return th; - - th = (thread_info *) xmalloc (sizeof (*th)); - memset(th, 0, sizeof (*th)); - th->id = id; - th->h = h; - th->next = thread_head.next; - thread_head.next = th; - add_thread (id); - return th; -} - -/* Clear out any old thread list and reintialize it to a - pristine state. */ -static void -child_init_thread_list () -{ - thread_info *th = &thread_head; - - DEBUG_EVENTS (("gdb: child_init_thread_list\n")); - init_thread_list (); - while (th->next != NULL) - { - thread_info *here = th->next; - th->next = here->next; - (void) CloseHandle (here->h); - free (here); - } -} - -/* Delete a thread from the list of threads */ -static void -child_delete_thread (DWORD id) -{ - thread_info *th; - - if (info_verbose) - printf_unfiltered ("[Deleting %s]\n", target_pid_to_str (id)); - delete_thread (id); - - for (th = &thread_head; - th->next != NULL && th->next->id != id; - th = th->next) - continue; - - if (th->next != NULL) - { - thread_info *here = th->next; - th->next = here->next; - CloseHandle (here->h); - free (here); - } -} - -static void -check (BOOL ok, const char *file, int line) -{ - if (!ok) - printf_filtered ("error return %s:%d was %d\n", file, line, GetLastError ()); -} - -static void -do_child_fetch_inferior_registers (int r) -{ - if (r >= 0) - supply_register (r, ((char *) ¤t_thread->context) + mappings[r]); - else - { - for (r = 0; r < NUM_REGS; r++) - do_child_fetch_inferior_registers (r); - } -} - -static void -child_fetch_inferior_registers (int r) -{ - current_thread = thread_rec (inferior_pid, TRUE); - do_child_fetch_inferior_registers (r); -} - -static void -do_child_store_inferior_registers (int r) -{ - if (r >= 0) - read_register_gen (r, ((char *) ¤t_thread->context) + mappings[r]); - else - { - for (r = 0; r < NUM_REGS; r++) - do_child_store_inferior_registers (r); - } -} - -/* Store a new register value into the current thread context */ -static void -child_store_inferior_registers (int r) -{ - current_thread = thread_rec (inferior_pid, TRUE); - do_child_store_inferior_registers (r); -} - -/* Wait for child to do something. Return pid of child, or -1 in case - of error; store status through argument pointer OURSTATUS. */ - -static int -handle_load_dll (PTR dummy) -{ - LOAD_DLL_DEBUG_INFO * event = ¤t_event.u.LoadDll; - DWORD dll_name_ptr; - DWORD done; - char dll_buf[MAX_PATH + 1]; - char *p, *dll_name = NULL, *dll_basename; - struct objfile *objfile; - MEMORY_BASIC_INFORMATION minfo; - - dll_buf[0] = dll_buf[sizeof(dll_buf) - 1] = '\0'; - - /* The following code attempts to find the name of the dll by reading the - name from the processes memory. Unfortunately it doesn't work right. - Doing this the "right way" for Windows is very difficult. FIXME */ -#ifdef DOESNT_WORK - memset (&minfo, 0, sizeof minfo); - if (VirtualQueryEx (current_process_handle, (LPCVOID) event->lpBaseOfDll, - &minfo, sizeof(minfo)) && minfo.BaseAddress) { - DWORD len; - IMAGE_DOS_HEADER *hmm0 = (IMAGE_DOS_HEADER *) minfo.BaseAddress; - HMODULE hmm = (HMODULE) (((DWORD) hmm0) + hmm0->e_lfanew); - - if ((len = GetModuleFileName (hmm, dll_buf, MAX_PATH))) - { - dll_name = dll_buf; - dll_name[len] = '\0'; - } - } -#endif - - /* Attempt to read the name of the dll that was detected. - This is documented to work only when actively debugging - a program. It will not work for attached processes. */ - if (dll_name == NULL || *dll_name == '\0') - { - int size = event->fUnicode ? sizeof (WCHAR) : sizeof (char); - int len = 0; - char b[2]; - - ReadProcessMemory (current_process_handle, - (LPCVOID) event->lpImageName, - (char *) &dll_name_ptr, - sizeof (dll_name_ptr), &done); - - /* See if we could read the address of a string, and that the - address isn't null. */ - - if (done != sizeof (dll_name_ptr) || !dll_name_ptr) - return 1; - - do - { - ReadProcessMemory (current_process_handle, - (LPCVOID) (dll_name_ptr + len * size), - &b, - size, - &done); - len++; - } - while ((b[0] != 0 || b[size - 1] != 0) && done == size); - - dll_name = alloca (len); - - if (event->fUnicode) - { - WCHAR *unicode_dll_name = (WCHAR *) alloca (len * sizeof (WCHAR)); - ReadProcessMemory (current_process_handle, - (LPCVOID) dll_name_ptr, - unicode_dll_name, - len * sizeof (WCHAR), - &done); - - WideCharToMultiByte (CP_ACP, 0, - unicode_dll_name, len, - dll_name, len, 0, 0); - } - else - { - ReadProcessMemory (current_process_handle, - (LPCVOID) dll_name_ptr, - dll_name, - len, - &done); - } - } - - if (!dll_name) - return 1; - - while ((p = strchr (dll_name, '\\'))) - *p = '/'; - - /* FIXME!! It would be nice to define one symbol which pointed to the - front of the dll if we can't find any symbols. */ - - if (!(dll_basename = strrchr(dll_name, '/'))) - dll_basename = dll_name; - else - dll_basename++; - - ALL_OBJFILES(objfile) - { - char *objfile_basename; - objfile_basename = strrchr(objfile->name, '/'); - - if (objfile_basename && - strcmp(dll_basename, objfile_basename + 1) == 0) - { - printf_unfiltered ("%x:%s (symbols previously loaded)\n", - event->lpBaseOfDll, dll_name); - goto out; - } - } - - /* 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. - - FIXME: Is this the real reason that we need the 0x1000 ? */ - - printf_unfiltered ("%x:%s", event->lpBaseOfDll, dll_name); - symbol_file_add (dll_name, 0, (int) event->lpBaseOfDll + 0x1000, 0, 0, 0, 0, 1); - printf_unfiltered ("\n"); - -out: - return 1; -} - -/* 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; - - if (!target_read_string - ((CORE_ADDR) current_event.u.DebugString.lpDebugStringData, &s, 1024, 0) - || !s || !*s) - return gotasig; - - if (strncmp(s, CYGWIN_SIGNAL_STRING, sizeof(CYGWIN_SIGNAL_STRING) - 1)) - { - warning (s); - } - else - { - char *p; - /*last_sig = */strtol(s + sizeof(CYGWIN_SIGNAL_STRING) - 1, &p, 0); - if (gotasig = (ourstatus->value.sig = target_signal_from_host (last_sig))) - ourstatus->kind = TARGET_WAITKIND_STOPPED; - } - - free (s); - return gotasig; -} - -static int -handle_exception (struct target_waitstatus *ourstatus) -{ - int i; - int done = 0; - thread_info *th; - - ourstatus->kind = TARGET_WAITKIND_STOPPED; - - /* Record the context of the current thread */ - th = thread_rec (current_event.dwThreadId, -1); - - switch (current_event.u.Exception.ExceptionRecord.ExceptionCode) - { - case EXCEPTION_ACCESS_VIOLATION: - DEBUG_EXCEPT (("gdb: Target exception ACCESS_VIOLATION at 0x%08x\n", - current_event.u.Exception.ExceptionRecord.ExceptionAddress)); - ourstatus->value.sig = TARGET_SIGNAL_SEGV; - break; - case STATUS_STACK_OVERFLOW: - DEBUG_EXCEPT (("gdb: Target exception STACK_OVERFLOW at 0x%08x\n", - current_event.u.Exception.ExceptionRecord.ExceptionAddress)); - ourstatus->value.sig = TARGET_SIGNAL_SEGV; - break; - case EXCEPTION_BREAKPOINT: - DEBUG_EXCEPT (("gdb: Target exception BREAKPOINT at 0x%08x\n", - current_event.u.Exception.ExceptionRecord.ExceptionAddress)); - ourstatus->value.sig = TARGET_SIGNAL_TRAP; - break; - case DBG_CONTROL_C: - DEBUG_EXCEPT (("gdb: Target exception CONTROL_C at 0x%08x\n", - current_event.u.Exception.ExceptionRecord.ExceptionAddress)); - ourstatus->value.sig = TARGET_SIGNAL_INT; - /* User typed CTRL-C. Continue with this status */ - last_sig = SIGINT; /* FIXME - should check pass state */ - break; - case EXCEPTION_SINGLE_STEP: - DEBUG_EXCEPT (("gdb: Target exception SINGLE_STEP at 0x%08x\n", - current_event.u.Exception.ExceptionRecord.ExceptionAddress)); - ourstatus->value.sig = TARGET_SIGNAL_TRAP; - break; - default: - /* This may be a structured exception handling exception. In - that case, we want to let the program try to handle it, and - only break if we see the exception a second time. */ - if (current_event.u.Exception.dwFirstChance) - return 0; - - printf_unfiltered ("gdb: unknown target exception 0x%08x at 0x%08x\n", - current_event.u.Exception.ExceptionRecord.ExceptionCode, - current_event.u.Exception.ExceptionRecord.ExceptionAddress); - ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN; - break; - } - exception_count++; - return 1; -} - -/* Resume all artificially suspended threads if we are continuing - execution */ -static BOOL -child_continue (DWORD continue_status, int id) -{ - int i; - thread_info *th; - BOOL res; - - DEBUG_EVENTS (("ContinueDebugEvent (cpid=%d, ctid=%d, DBG_CONTINUE);\n", - current_event.dwProcessId, current_event.dwThreadId)); - if (res = ContinueDebugEvent (current_event.dwProcessId, - current_event.dwThreadId, - continue_status)) - for (th = &thread_head; (th = th->next) != NULL; ) - if (((id == -1) || (id == th->id)) && th->suspend_count) - { - for (i = 0; i < th->suspend_count; i++) - (void) ResumeThread (th->h); - th->suspend_count = 0; - } - - return res; -} - -static int -child_wait (int pid, struct target_waitstatus *ourstatus) -{ - /* We loop when we get a non-standard exception rather than return - with a SPURIOUS because resume can try and step or modify things, - which needs a current_thread->h. But some of these exceptions mark - the birth or death of threads, which mean that the current thread - isn't necessarily what you think it is. */ - - while (1) - { - DWORD continue_status; - BOOL t = WaitForDebugEvent (¤t_event, INFINITE); - char *p; - thread_info *th; - int sig; - - event_count++; - - continue_status = DBG_CONTINUE; - - switch (current_event.dwDebugEventCode) - { - case CREATE_THREAD_DEBUG_EVENT: - DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%x code=%s)\n", - current_event.dwProcessId, current_event.dwThreadId, - "CREATE_THREAD_DEBUG_EVENT")); - /* Record the existence of this thread */ - child_add_thread (current_event.dwThreadId, - current_event.u.CreateThread.hThread); - if (info_verbose) - printf_unfiltered ("[New %s]\n", - target_pid_to_str (current_event.dwThreadId)); - break; - - case EXIT_THREAD_DEBUG_EVENT: - DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n", - current_event.dwProcessId, current_event.dwThreadId, - "EXIT_THREAD_DEBUG_EVENT")); - child_delete_thread (current_event.dwThreadId); - break; - - case CREATE_PROCESS_DEBUG_EVENT: - DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n", - current_event.dwProcessId, current_event.dwThreadId, - "CREATE_PROCESS_DEBUG_EVENT")); - current_process_handle = current_event.u.CreateProcessInfo.hProcess; - - main_thread_id = inferior_pid = current_event.dwThreadId; - /* Add the main thread */ - current_thread = child_add_thread (inferior_pid, - current_event.u.CreateProcessInfo.hThread); - break; - - case EXIT_PROCESS_DEBUG_EVENT: - DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n", - current_event.dwProcessId, current_event.dwThreadId, - "EXIT_PROCESS_DEBUG_EVENT")); - ourstatus->kind = TARGET_WAITKIND_EXITED; - ourstatus->value.integer = current_event.u.ExitProcess.dwExitCode; - CloseHandle (current_process_handle); - return current_event.dwProcessId; - break; - - case LOAD_DLL_DEBUG_EVENT: - DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n", - current_event.dwProcessId, current_event.dwThreadId, - "LOAD_DLL_DEBUG_EVENT")); - catch_errors (handle_load_dll, NULL, "", RETURN_MASK_ALL); - registers_changed(); /* mark all regs invalid */ - break; - - case UNLOAD_DLL_DEBUG_EVENT: - DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n", - current_event.dwProcessId, current_event.dwThreadId, - "UNLOAD_DLL_DEBUG_EVENT")); - break; /* FIXME: don't know what to do here */ - - case EXCEPTION_DEBUG_EVENT: - DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n", - current_event.dwProcessId, current_event.dwThreadId, - "EXCEPTION_DEBUG_EVENT")); - if (handle_exception (ourstatus)) - return current_event.dwThreadId; - continue_status = DBG_EXCEPTION_NOT_HANDLED; - break; - - case OUTPUT_DEBUG_STRING_EVENT: /* message from the kernel */ - DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n", - current_event.dwProcessId, current_event.dwThreadId, - "OUTPUT_DEBUG_STRING_EVENT")); - if (handle_output_debug_string (ourstatus)) - return main_thread_id; - break; - default: - printf_unfiltered ("gdb: kernel event for pid=%d tid=%d\n", - current_event.dwProcessId, - current_event.dwThreadId); - printf_unfiltered (" unknown event code %d\n", - current_event.dwDebugEventCode); - break; - } - - CHECK (child_continue (continue_status, -1)); - } -} - -/* Attach to process PID, then initialize for debugging it. */ - -static void -child_attach (args, from_tty) - char *args; - int from_tty; -{ - BOOL ok; - - if (!args) - error_no_arg ("process-id to attach"); - - current_event.dwProcessId = strtoul (args, 0, 0); - - ok = DebugActiveProcess (current_event.dwProcessId); - - if (!ok) - error ("Can't attach to process."); - - exception_count = 0; - event_count = 0; - - if (from_tty) - { - char *exec_file = (char *) get_exec_file (0); - - if (exec_file) - printf_unfiltered ("Attaching to program `%s', %s\n", exec_file, - target_pid_to_str (current_event.dwProcessId)); - else - printf_unfiltered ("Attaching to %s\n", - target_pid_to_str (current_event.dwProcessId)); - - gdb_flush (gdb_stdout); - } - - push_target (&child_ops); -} - -static void -child_detach (args, from_tty) - char *args; - int from_tty; -{ - if (from_tty) - { - char *exec_file = get_exec_file (0); - if (exec_file == 0) - exec_file = ""; - printf_unfiltered ("Detaching from program: %s %s\n", exec_file, - target_pid_to_str (inferior_pid)); - gdb_flush (gdb_stdout); - } - inferior_pid = 0; - unpush_target (&child_ops); -} - -/* Print status information about what we're accessing. */ - -static void -child_files_info (ignore) - struct target_ops *ignore; -{ - printf_unfiltered ("\tUsing the running image of %s %s.\n", - attach_flag ? "attached" : "child", target_pid_to_str (inferior_pid)); -} - -/* ARGSUSED */ -static void -child_open (arg, from_tty) - char *arg; - int from_tty; -{ - error ("Use the \"run\" command to start a Unix child process."); -} - -/* Start an inferior win32 child process and sets inferior_pid 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 -child_create_inferior (exec_file, allargs, env) - char *exec_file; - char *allargs; - char **env; -{ - char real_path[MAXPATHLEN]; - char *winenv; - char *temp; - int envlen; - int i; - - STARTUPINFO si; - PROCESS_INFORMATION pi; - struct target_waitstatus dummy; - BOOL ret; - DWORD flags; - char *args; - - if (!exec_file) - { - error ("No executable specified, use `target exec'.\n"); - } - - memset (&si, 0, sizeof (si)); - si.cb = sizeof (si); - - cygwin32_conv_to_win32_path (exec_file, real_path); - - flags = DEBUG_ONLY_THIS_PROCESS; - - if (new_group) - flags |= CREATE_NEW_PROCESS_GROUP; - - if (new_console) - flags |= CREATE_NEW_CONSOLE; - - args = alloca (strlen (real_path) + strlen (allargs) + 2); - - strcpy (args, real_path); - - strcat (args, " "); - strcat (args, allargs); - - /* Prepare the environment vars for CreateProcess. */ - { - /* This code use 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 (cygwin32_posix_path_list_p (env[i] + len)) - envlen += len - + cygwin32_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 (cygwin32_posix_path_list_p (env[i] + len)) - { - memcpy (temp, env[i], len); - cygwin32_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; - } - - ret = CreateProcess (0, - args, /* command line */ - NULL, /* Security */ - NULL, /* thread */ - TRUE, /* inherit handles */ - flags, /* start flags */ - winenv, - NULL, /* current directory */ - &si, - &pi); - if (!ret) - error ("Error creating process %s, (error %d)\n", exec_file, GetLastError()); - - exception_count = 0; - event_count = 0; - - current_process_handle = pi.hProcess; - current_event.dwProcessId = pi.dwProcessId; - memset (¤t_event, 0, sizeof (current_event)); - inferior_pid = current_event.dwThreadId = pi.dwThreadId; - push_target (&child_ops); - child_init_thread_list (); - init_wait_for_inferior (); - clear_proceed_status (); - target_terminal_init (); - target_terminal_inferior (); - - /* Ignore the first trap */ - child_wait (inferior_pid, &dummy); - - proceed ((CORE_ADDR) - 1, TARGET_SIGNAL_0, 0); -} - -static void -child_mourn_inferior () -{ - (void) child_continue (DBG_CONTINUE, -1); - unpush_target (&child_ops); - generic_mourn_inferior (); -} - -/* Send a SIGINT to the process group. This acts just like the user typed a - ^C on the controlling terminal. */ - -static void -child_stop () -{ - DEBUG_EVENTS (("gdb: GenerateConsoleCtrlEvent (CTRLC_EVENT, 0)\n")); - CHECK (GenerateConsoleCtrlEvent (CTRL_C_EVENT, 0)); - registers_changed(); /* refresh register state */ -} - -int -child_xfer_memory (CORE_ADDR memaddr, char *our, int len, - int write, struct target_ops *target) -{ - DWORD done; - if (write) - { - DEBUG_MEM (("gdb: write target memory, %d bytes at 0x%08x\n", - len, memaddr)); - WriteProcessMemory (current_process_handle, (LPVOID) memaddr, our, - len, &done); - FlushInstructionCache (current_process_handle, (LPCVOID) memaddr, len); - } - else - { - DEBUG_MEM (("gdb: read target memory, %d bytes at 0x%08x\n", - len, memaddr)); - ReadProcessMemory (current_process_handle, (LPCVOID) memaddr, our, len, - &done); - } - return done; -} - -void -child_kill_inferior (void) -{ - CHECK (TerminateProcess (current_process_handle, 0)); - - for (;;) - { - if (!child_continue (DBG_CONTINUE, -1)) - break; - if (!WaitForDebugEvent (¤t_event, INFINITE)) - break; - if (current_event.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) - break; - } - - CHECK (CloseHandle (current_process_handle)); - - /* this may fail in an attached process so don't check. */ - (void) CloseHandle (current_thread->h); - target_mourn_inferior(); /* or just child_mourn_inferior? */ -} - -void -child_resume (int pid, int step, enum target_signal sig) -{ - int i; - thread_info *th; - DWORD continue_status = last_sig > 0 && last_sig < NSIG ? - DBG_EXCEPTION_NOT_HANDLED : DBG_CONTINUE; - - 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 (step) - { -#ifdef i386 - /* Single step by setting t bit */ - child_fetch_inferior_registers (PS_REGNUM); - th->context.EFlags |= FLAG_TRACE_BIT; -#endif - } - - if (th->context.ContextFlags) - { - CHECK (SetThreadContext (th->h, &th->context)); - th->context.ContextFlags = 0; - } - - /* Allow continuing with the same signal that interrupted us. - Otherwise complain. */ - if (sig && sig != last_sig) - fprintf_unfiltered (gdb_stderr, "Can't send signals to the child. signal %d\n", sig); - - last_sig = 0; - child_continue (continue_status, pid); -} - -static void -child_prepare_to_store () -{ - /* Do nothing, since we can store individual regs */ -} - -static int -child_can_run () -{ - return 1; -} - -static void -child_close () -{ - DEBUG_EVENTS (("gdb: child_close, inferior_pid=%d\n", inferior_pid)); -} - -struct target_ops child_ops ; - -static void -init_child_ops(void) -{ - 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_info = child_terminal_info; - child_ops.to_kill = child_kill_inferior; - child_ops.to_load = 0; - child_ops.to_lookup_symbol = 0; - 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_notice_signals = 0; - child_ops.to_thread_alive = win32_child_thread_alive; - child_ops.to_stop = child_stop; - child_ops.to_stratum = process_stratum; - child_ops.DONT_USE = 0; - 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_sections = 0; - child_ops.to_sections_end = 0; - child_ops.to_magic = OPS_MAGIC; -} - -void -_initialize_inftarg () -{ - struct cmd_list_element *c; - init_child_ops() ; - - 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_target (&child_ops); -} - -/* Determine if the thread referenced by "pid" is alive - by "polling" it. If WaitForSingleObject returns WAIT_OBJECT_0 - it means that the pid has died. Otherwise it is assumed to be alive. */ -static int -win32_child_thread_alive (int pid) -{ - return WaitForSingleObject(thread_rec (pid, FALSE)->h, 0) == WAIT_OBJECT_0 ? - FALSE : TRUE; -} - -/* Convert pid to printable format. */ -char * -cygwin_pid_to_str (int pid) -{ - static char buf[80]; - if (pid == current_event.dwProcessId) - sprintf (buf, "process %d", pid); - else - sprintf (buf, "thread %d.0x%x", current_event.dwProcessId, pid); - return buf; -} |