-
- if (!ret)
- {
- error ("Error creating process %s, (error %d): %s\n", args,
- (int) GetLastError (), strerror (GetLastError ()));
- }
- else
- {
- OUTMSG2 (("Process created: %s\n", (char *) args));
- }
-
- CloseHandle (pi.hThread);
-
- current_process_handle = pi.hProcess;
- current_process_id = pi.dwProcessId;
-
- do_initial_child_stuff (current_process_id);
-
- return current_process_id;
-}
-
-/* Attach to a running process.
- PID is the process ID to attach to, specified by the user
- or a higher layer. */
-static int
-win32_attach (unsigned long pid)
-{
- int res = 0;
- HMODULE kernel32 = LoadLibrary ("KERNEL32.DLL");
- winapi_DebugActiveProcessStop *DebugActiveProcessStop = NULL;
- winapi_DebugSetProcessKillOnExit *DebugSetProcessKillOnExit = NULL;
-
- DebugActiveProcessStop =
- (winapi_DebugActiveProcessStop *) GetProcAddress (kernel32,
- "DebugActiveProcessStop");
- DebugSetProcessKillOnExit =
- (winapi_DebugSetProcessKillOnExit *) GetProcAddress (kernel32,
- "DebugSetProcessKillOnExit");
-
- res = DebugActiveProcess (pid) ? 1 : 0;
-
- if (!res)
- error ("Attach to process failed.");
-
- if (DebugSetProcessKillOnExit != NULL)
- DebugSetProcessKillOnExit (FALSE);
-
- current_process_id = pid;
- current_process_handle = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid);
-
- if (current_process_handle == NULL)
- {
- res = 0;
- if (DebugActiveProcessStop != NULL)
- DebugActiveProcessStop (current_process_id);
- }
-
- if (res)
- do_initial_child_stuff (pid);
-
- FreeLibrary (kernel32);
-
- return res;
-}
-
-/* Kill all inferiors. */
-static void
-win32_kill (void)
-{
- if (current_process_handle == NULL)
- return;
-
- 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;
- }
-}
-
-/* Detach from all inferiors. */
-static void
-win32_detach (void)
-{
- HMODULE kernel32 = LoadLibrary ("KERNEL32.DLL");
- winapi_DebugActiveProcessStop *DebugActiveProcessStop = NULL;
- winapi_DebugSetProcessKillOnExit *DebugSetProcessKillOnExit = NULL;
-
- DebugActiveProcessStop =
- (winapi_DebugActiveProcessStop *) GetProcAddress (kernel32,
- "DebugActiveProcessStop");
- DebugSetProcessKillOnExit =
- (winapi_DebugSetProcessKillOnExit *) GetProcAddress (kernel32,
- "DebugSetProcessKillOnExit");
-
- if (DebugSetProcessKillOnExit != NULL)
- DebugSetProcessKillOnExit (FALSE);
-
- if (DebugActiveProcessStop != NULL)
- DebugActiveProcessStop (current_process_id);
- else
- win32_kill ();
-
- FreeLibrary (kernel32);
-}
-
-/* Return 1 iff the thread with thread ID TID is alive. */
-static int
-win32_thread_alive (unsigned long tid)
-{
- int res;
-
- /* Our thread list is reliable; don't bother to poll target
- threads. */
- if (find_inferior_id (&all_threads, tid) != NULL)
- res = 1;
- else
- res = 0;
- return res;
-}
-
-/* Resume the inferior process. RESUME_INFO describes how we want
- to resume. */
-static void
-win32_resume (struct thread_resume *resume_info)
-{
- DWORD tid;
- enum target_signal sig;
- int step;
- thread_info *th;
- DWORD continue_status = DBG_CONTINUE;
-
- /* This handles the very limited set of resume packets that GDB can
- currently produce. */
-
- if (resume_info[0].thread == -1)
- tid = -1;
- else if (resume_info[1].thread == -1 && !resume_info[1].leave_stopped)
- tid = -1;
- else
- /* Yes, we're ignoring resume_info[0].thread. It'd be tricky to make
- the Windows resume code do the right thing for thread switching. */
- tid = current_event.dwThreadId;
-
- if (resume_info[0].thread != -1)
- {
- sig = resume_info[0].sig;
- step = resume_info[0].step;
- }
- else
- {
- sig = 0;
- step = 0;
- }
-
- if (sig != TARGET_SIGNAL_0)
- {
- if (current_event.dwDebugEventCode != EXCEPTION_DEBUG_EVENT)
- {
- OUTMSG (("Cannot continue with signal %d here.\n", sig));
- }
- else if (sig == last_sig)
- continue_status = DBG_EXCEPTION_NOT_HANDLED;
- else
- OUTMSG (("Can only continue with recieved signal %d.\n", last_sig));
- }
-
- last_sig = TARGET_SIGNAL_0;
-
- /* Get context for the currently selected thread. */
- th = thread_rec (current_event.dwThreadId, FALSE);
- if (th)
- {
- if (th->context.ContextFlags)
- {
- if (debug_registers_changed)
- {
- th->context.Dr0 = dr[0];
- th->context.Dr1 = dr[1];
- th->context.Dr2 = dr[2];
- th->context.Dr3 = dr[3];
- /* th->context.Dr6 = dr[6];
- FIXME: should we set dr6 also ?? */
- th->context.Dr7 = dr[7];
- }
-
- /* Move register values from the inferior into the thread
- context structure. */
- regcache_invalidate ();
-
- if (step)
- th->context.EFlags |= FLAG_TRACE_BIT;
-
- SetThreadContext (th->h, &th->context);
- th->context.ContextFlags = 0;
- }
- }
-
- /* Allow continuing with the same signal that interrupted us.
- Otherwise complain. */
-
- child_continue (continue_status, tid);
-}
-
-static int
-handle_exception (struct target_waitstatus *ourstatus)
-{
- thread_info *th;
- DWORD code = current_event.u.Exception.ExceptionRecord.ExceptionCode;
-
- ourstatus->kind = TARGET_WAITKIND_STOPPED;
-
- /* Record the context of the current thread. */
- th = thread_rec (current_event.dwThreadId, -1);
-
- switch (code)
- {
- case EXCEPTION_ACCESS_VIOLATION:
- OUTMSG2 (("EXCEPTION_ACCESS_VIOLATION"));
- ourstatus->value.sig = TARGET_SIGNAL_SEGV;
- break;
- case STATUS_STACK_OVERFLOW:
- OUTMSG2 (("STATUS_STACK_OVERFLOW"));
- ourstatus->value.sig = TARGET_SIGNAL_SEGV;
- break;
- case STATUS_FLOAT_DENORMAL_OPERAND:
- OUTMSG2 (("STATUS_FLOAT_DENORMAL_OPERAND"));
- ourstatus->value.sig = TARGET_SIGNAL_FPE;
- break;
- case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
- OUTMSG2 (("EXCEPTION_ARRAY_BOUNDS_EXCEEDED"));
- ourstatus->value.sig = TARGET_SIGNAL_FPE;
- break;
- case STATUS_FLOAT_INEXACT_RESULT:
- OUTMSG2 (("STATUS_FLOAT_INEXACT_RESULT"));
- ourstatus->value.sig = TARGET_SIGNAL_FPE;
- break;
- case STATUS_FLOAT_INVALID_OPERATION:
- OUTMSG2 (("STATUS_FLOAT_INVALID_OPERATION"));
- ourstatus->value.sig = TARGET_SIGNAL_FPE;
- break;
- case STATUS_FLOAT_OVERFLOW:
- OUTMSG2 (("STATUS_FLOAT_OVERFLOW"));
- ourstatus->value.sig = TARGET_SIGNAL_FPE;
- break;
- case STATUS_FLOAT_STACK_CHECK:
- OUTMSG2 (("STATUS_FLOAT_STACK_CHECK"));
- ourstatus->value.sig = TARGET_SIGNAL_FPE;
- break;
- case STATUS_FLOAT_UNDERFLOW:
- OUTMSG2 (("STATUS_FLOAT_UNDERFLOW"));
- ourstatus->value.sig = TARGET_SIGNAL_FPE;
- break;
- case STATUS_FLOAT_DIVIDE_BY_ZERO:
- OUTMSG2 (("STATUS_FLOAT_DIVIDE_BY_ZERO"));
- ourstatus->value.sig = TARGET_SIGNAL_FPE;
- break;
- case STATUS_INTEGER_DIVIDE_BY_ZERO:
- OUTMSG2 (("STATUS_INTEGER_DIVIDE_BY_ZERO"));
- ourstatus->value.sig = TARGET_SIGNAL_FPE;
- break;
- case STATUS_INTEGER_OVERFLOW:
- OUTMSG2 (("STATUS_INTEGER_OVERFLOW"));
- ourstatus->value.sig = TARGET_SIGNAL_FPE;
- break;
- case EXCEPTION_BREAKPOINT:
- OUTMSG2 (("EXCEPTION_BREAKPOINT"));
- ourstatus->value.sig = TARGET_SIGNAL_TRAP;
- break;
- case DBG_CONTROL_C:
- OUTMSG2 (("DBG_CONTROL_C"));
- ourstatus->value.sig = TARGET_SIGNAL_INT;
- break;
- case DBG_CONTROL_BREAK:
- OUTMSG2 (("DBG_CONTROL_BREAK"));
- ourstatus->value.sig = TARGET_SIGNAL_INT;
- break;
- case EXCEPTION_SINGLE_STEP:
- OUTMSG2 (("EXCEPTION_SINGLE_STEP"));
- ourstatus->value.sig = TARGET_SIGNAL_TRAP;
- break;
- case EXCEPTION_ILLEGAL_INSTRUCTION:
- OUTMSG2 (("EXCEPTION_ILLEGAL_INSTRUCTION"));
- ourstatus->value.sig = TARGET_SIGNAL_ILL;
- break;
- case EXCEPTION_PRIV_INSTRUCTION:
- OUTMSG2 (("EXCEPTION_PRIV_INSTRUCTION"));
- ourstatus->value.sig = TARGET_SIGNAL_ILL;
- break;
- case EXCEPTION_NONCONTINUABLE_EXCEPTION:
- OUTMSG2 (("EXCEPTION_NONCONTINUABLE_EXCEPTION"));
- ourstatus->value.sig = TARGET_SIGNAL_ILL;
- break;
- default:
- if (current_event.u.Exception.dwFirstChance)
- return 0;
- OUTMSG2 (("gdbserver: unknown target exception 0x%08lx at 0x%08lx",
- current_event.u.Exception.ExceptionRecord.ExceptionCode,
- (DWORD) current_event.u.Exception.ExceptionRecord.
- ExceptionAddress));
- ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN;
- break;
- }
- OUTMSG2 (("\n"));
- last_sig = ourstatus->value.sig;
- return 1;
-}
-
-/* Get the next event from the child. Return 1 if the event requires
- handling. */
-static int
-get_child_debug_event (struct target_waitstatus *ourstatus)
-{
- BOOL debug_event;
- DWORD continue_status, event_code;
- thread_info *th = NULL;
- static thread_info dummy_thread_info;
- int retval = 0;
-
-in:
-
- last_sig = TARGET_SIGNAL_0;
- ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
-
- if (!(debug_event = WaitForDebugEvent (¤t_event, 1000)))
- goto out;
-
- current_inferior =
- (struct thread_info *) find_inferior_id (&all_threads,
- current_event.dwThreadId);
-
- continue_status = DBG_CONTINUE;
- event_code = current_event.dwDebugEventCode;
-
- switch (event_code)
- {
- case CREATE_THREAD_DEBUG_EVENT:
- OUTMSG2 (("gdbserver: kernel event CREATE_THREAD_DEBUG_EVENT "
- "for pid=%d tid=%x)\n",
- (unsigned) current_event.dwProcessId,
- (unsigned) current_event.dwThreadId));
-
- /* Record the existence of this thread. */
- th = child_add_thread (current_event.dwThreadId,
- current_event.u.CreateThread.hThread);
-
- retval = current_event.dwThreadId;
- break;
-
- case EXIT_THREAD_DEBUG_EVENT:
- OUTMSG2 (("gdbserver: kernel event EXIT_THREAD_DEBUG_EVENT "
- "for pid=%d tid=%x\n",
- (unsigned) current_event.dwProcessId,
- (unsigned) current_event.dwThreadId));
- child_delete_thread (current_event.dwThreadId);
- th = &dummy_thread_info;
- break;
-
- case CREATE_PROCESS_DEBUG_EVENT:
- OUTMSG2 (("gdbserver: kernel event CREATE_PROCESS_DEBUG_EVENT "
- "for pid=%d tid=%x\n",
- (unsigned) current_event.dwProcessId,
- (unsigned) current_event.dwThreadId));
- CloseHandle (current_event.u.CreateProcessInfo.hFile);
-
- current_process_handle = current_event.u.CreateProcessInfo.hProcess;
- main_thread_id = current_event.dwThreadId;
-
- ourstatus->kind = TARGET_WAITKIND_EXECD;
- ourstatus->value.execd_pathname = "Main executable";
-
- /* Add the main thread. */
- th =
- child_add_thread (main_thread_id,
- current_event.u.CreateProcessInfo.hThread);
-
- retval = ourstatus->value.related_pid = current_event.dwThreadId;
- break;
-
- case EXIT_PROCESS_DEBUG_EVENT:
- OUTMSG2 (("gdbserver: kernel event EXIT_PROCESS_DEBUG_EVENT "
- "for pid=%d tid=%x\n",
- (unsigned) current_event.dwProcessId,
- (unsigned) current_event.dwThreadId));
- ourstatus->kind = TARGET_WAITKIND_EXITED;
- ourstatus->value.integer = current_event.u.ExitProcess.dwExitCode;
- CloseHandle (current_process_handle);
- current_process_handle = NULL;
- retval = main_thread_id;
- break;
-
- case LOAD_DLL_DEBUG_EVENT:
- OUTMSG2 (("gdbserver: kernel event LOAD_DLL_DEBUG_EVENT "
- "for pid=%d tid=%x\n",
- (unsigned) current_event.dwProcessId,
- (unsigned) current_event.dwThreadId));
- CloseHandle (current_event.u.LoadDll.hFile);
-
- ourstatus->kind = TARGET_WAITKIND_LOADED;
- ourstatus->value.integer = 0;
- retval = main_thread_id;
- break;
-
- case UNLOAD_DLL_DEBUG_EVENT:
- OUTMSG2 (("gdbserver: kernel event UNLOAD_DLL_DEBUG_EVENT "
- "for pid=%d tid=%x\n",
- (unsigned) current_event.dwProcessId,
- (unsigned) current_event.dwThreadId));
- break;
-
- case EXCEPTION_DEBUG_EVENT:
- OUTMSG2 (("gdbserver: kernel event EXCEPTION_DEBUG_EVENT "
- "for pid=%d tid=%x\n",
- (unsigned) current_event.dwProcessId,
- (unsigned) current_event.dwThreadId));
- retval = handle_exception (ourstatus);
- break;
-
- case OUTPUT_DEBUG_STRING_EVENT:
- /* A message from the kernel (or Cygwin). */
- OUTMSG2 (("gdbserver: kernel event OUTPUT_DEBUG_STRING_EVENT "
- "for pid=%d tid=%x\n",
- (unsigned) current_event.dwProcessId,
- (unsigned) current_event.dwThreadId));
- break;
-
- default:
- OUTMSG2 (("gdbserver: kernel event unknown "
- "for pid=%d tid=%x code=%ld\n",
- (unsigned) current_event.dwProcessId,
- (unsigned) current_event.dwThreadId,
- current_event.dwDebugEventCode));
- break;
- }
-
- current_inferior =
- (struct thread_info *) find_inferior_id (&all_threads,
- current_event.dwThreadId);
-
- if (!retval || (event_code != EXCEPTION_DEBUG_EVENT && event_code != EXIT_PROCESS_DEBUG_EVENT))
- {
- child_continue (continue_status, -1);
- goto in;
- }
-
- if (th == NULL)
- thread_rec (current_event.dwThreadId, TRUE);
-
-out:
- return retval;
-}
-
-/* Wait for the inferior process to change state.
- STATUS will be filled in with a response code to send to GDB.
- Returns the signal which caused the process to stop. */
-static unsigned char
-win32_wait (char *status)
-{
- struct target_waitstatus our_status;
-
- *status = 'T';
-
- while (1)
- {
- get_child_debug_event (&our_status);
-
- if (our_status.kind == TARGET_WAITKIND_EXITED)
- {
- OUTMSG2 (("Child exited with retcode = %x\n",
- our_status.value.integer));
-
- *status = 'W';
-
- child_fetch_inferior_registers (-1);
-
- return our_status.value.integer;
- }
- else if (our_status.kind == TARGET_WAITKIND_STOPPED)
- {
- OUTMSG2 (("Child Stopped with signal = %x \n",
- WSTOPSIG (our_status.value.sig)));
-
- *status = 'T';
-
- child_fetch_inferior_registers (-1);
-
- return our_status.value.sig;
- }
- else
- OUTMSG (("Ignoring unknown internal event, %d\n", our_status.kind));
-
- {
- struct thread_resume resume;
- resume.thread = -1;
- resume.step = 0;
- resume.sig = 0;
- resume.leave_stopped = 0;
- win32_resume (&resume);
- }
- }