static void handle_exception (struct target_waitstatus *ourstatus) { DWORD code = current_event.u.Exception.ExceptionRecord.ExceptionCode; ourstatus->kind = TARGET_WAITKIND_STOPPED; switch (code) { case EXCEPTION_ACCESS_VIOLATION: OUTMSG2 (("EXCEPTION_ACCESS_VIOLATION")); ourstatus->value.sig = GDB_SIGNAL_SEGV; break; case STATUS_STACK_OVERFLOW: OUTMSG2 (("STATUS_STACK_OVERFLOW")); ourstatus->value.sig = GDB_SIGNAL_SEGV; break; case STATUS_FLOAT_DENORMAL_OPERAND: OUTMSG2 (("STATUS_FLOAT_DENORMAL_OPERAND")); ourstatus->value.sig = GDB_SIGNAL_FPE; break; case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: OUTMSG2 (("EXCEPTION_ARRAY_BOUNDS_EXCEEDED")); ourstatus->value.sig = GDB_SIGNAL_FPE; break; case STATUS_FLOAT_INEXACT_RESULT: OUTMSG2 (("STATUS_FLOAT_INEXACT_RESULT")); ourstatus->value.sig = GDB_SIGNAL_FPE; break; case STATUS_FLOAT_INVALID_OPERATION: OUTMSG2 (("STATUS_FLOAT_INVALID_OPERATION")); ourstatus->value.sig = GDB_SIGNAL_FPE; break; case STATUS_FLOAT_OVERFLOW: OUTMSG2 (("STATUS_FLOAT_OVERFLOW")); ourstatus->value.sig = GDB_SIGNAL_FPE; break; case STATUS_FLOAT_STACK_CHECK: OUTMSG2 (("STATUS_FLOAT_STACK_CHECK")); ourstatus->value.sig = GDB_SIGNAL_FPE; break; case STATUS_FLOAT_UNDERFLOW: OUTMSG2 (("STATUS_FLOAT_UNDERFLOW")); ourstatus->value.sig = GDB_SIGNAL_FPE; break; case STATUS_FLOAT_DIVIDE_BY_ZERO: OUTMSG2 (("STATUS_FLOAT_DIVIDE_BY_ZERO")); ourstatus->value.sig = GDB_SIGNAL_FPE; break; case STATUS_INTEGER_DIVIDE_BY_ZERO: OUTMSG2 (("STATUS_INTEGER_DIVIDE_BY_ZERO")); ourstatus->value.sig = GDB_SIGNAL_FPE; break; case STATUS_INTEGER_OVERFLOW: OUTMSG2 (("STATUS_INTEGER_OVERFLOW")); ourstatus->value.sig = GDB_SIGNAL_FPE; break; case EXCEPTION_BREAKPOINT: OUTMSG2 (("EXCEPTION_BREAKPOINT")); ourstatus->value.sig = GDB_SIGNAL_TRAP; #ifdef _WIN32_WCE /* Remove the initial breakpoint. */ check_breakpoints ((CORE_ADDR) (long) current_event .u.Exception.ExceptionRecord.ExceptionAddress); #endif break; case DBG_CONTROL_C: OUTMSG2 (("DBG_CONTROL_C")); ourstatus->value.sig = GDB_SIGNAL_INT; break; case DBG_CONTROL_BREAK: OUTMSG2 (("DBG_CONTROL_BREAK")); ourstatus->value.sig = GDB_SIGNAL_INT; break; case EXCEPTION_SINGLE_STEP: OUTMSG2 (("EXCEPTION_SINGLE_STEP")); ourstatus->value.sig = GDB_SIGNAL_TRAP; break; case EXCEPTION_ILLEGAL_INSTRUCTION: OUTMSG2 (("EXCEPTION_ILLEGAL_INSTRUCTION")); ourstatus->value.sig = GDB_SIGNAL_ILL; break; case EXCEPTION_PRIV_INSTRUCTION: OUTMSG2 (("EXCEPTION_PRIV_INSTRUCTION")); ourstatus->value.sig = GDB_SIGNAL_ILL; break; case EXCEPTION_NONCONTINUABLE_EXCEPTION: OUTMSG2 (("EXCEPTION_NONCONTINUABLE_EXCEPTION")); ourstatus->value.sig = GDB_SIGNAL_ILL; break; default: if (current_event.u.Exception.dwFirstChance) { ourstatus->kind = TARGET_WAITKIND_SPURIOUS; return; } OUTMSG2 (("gdbserver: unknown target exception 0x%08x at 0x%s", (unsigned) current_event.u.Exception.ExceptionRecord.ExceptionCode, phex_nz ((uintptr_t) current_event.u.Exception.ExceptionRecord. ExceptionAddress, sizeof (uintptr_t)))); ourstatus->value.sig = GDB_SIGNAL_UNKNOWN; break; } OUTMSG2 (("\n")); last_sig = ourstatus->value.sig; }
static int get_child_debug_event (struct target_waitstatus *ourstatus) { ptid_t ptid; last_sig = GDB_SIGNAL_0; ourstatus->kind = TARGET_WAITKIND_SPURIOUS; /* Check if GDB sent us an interrupt request. */ check_remote_input_interrupt_request (); if (soft_interrupt_requested) { soft_interrupt_requested = 0; fake_breakpoint_event (); goto gotevent; } #ifndef _WIN32_WCE attaching = 0; #else if (attaching) { /* WinCE doesn't set an initial breakpoint automatically. To stop the inferior, we flush all currently pending debug events -- the thread list and the dll list are always reported immediatelly without delay, then, we suspend all threads and pretend we saw a trap at the current PC of the main thread. Contrary to desktop Windows, Windows CE *does* report the dll names on LOAD_DLL_DEBUG_EVENTs resulting from a DebugActiveProcess call. This limits the way we can detect if all the dlls have already been reported. If we get a real debug event before leaving attaching, the worst that will happen is the user will see a spurious breakpoint. */ current_event.dwDebugEventCode = 0; if (!WaitForDebugEvent (¤t_event, 0)) { OUTMSG2(("no attach events left\n")); fake_breakpoint_event (); attaching = 0; } else OUTMSG2(("got attach event\n")); } else #endif { /* Keep the wait time low enough for confortable remote interruption, but high enough so gdbserver doesn't become a bottleneck. */ if (!WaitForDebugEvent (¤t_event, 250)) { DWORD e = GetLastError(); if (e == ERROR_PIPE_NOT_CONNECTED) { /* This will happen if the loader fails to succesfully load the application, e.g., if the main executable tries to pull in a non-existing export from a DLL. */ ourstatus->kind = TARGET_WAITKIND_EXITED; ourstatus->value.integer = 1; return 1; } return 0; } } gotevent: switch (current_event.dwDebugEventCode) { case CREATE_THREAD_DEBUG_EVENT: OUTMSG2 (("gdbserver: kernel event CREATE_THREAD_DEBUG_EVENT " "for pid=%u tid=%x)\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId)); /* Record the existence of this thread. */ child_add_thread (current_event.dwProcessId, current_event.dwThreadId, current_event.u.CreateThread.hThread, current_event.u.CreateThread.lpThreadLocalBase); break; case EXIT_THREAD_DEBUG_EVENT: OUTMSG2 (("gdbserver: kernel event EXIT_THREAD_DEBUG_EVENT " "for pid=%u tid=%x\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId)); child_delete_thread (current_event.dwProcessId, current_event.dwThreadId); current_inferior = (struct thread_info *) all_threads.head; return 1; case CREATE_PROCESS_DEBUG_EVENT: OUTMSG2 (("gdbserver: kernel event CREATE_PROCESS_DEBUG_EVENT " "for pid=%u 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. */ child_add_thread (current_event.dwProcessId, main_thread_id, current_event.u.CreateProcessInfo.hThread, current_event.u.CreateProcessInfo.lpThreadLocalBase); ourstatus->value.related_pid = debug_event_ptid (¤t_event); #ifdef _WIN32_WCE if (!attaching) { /* Windows CE doesn't set the initial breakpoint automatically like the desktop versions of Windows do. We add it explicitly here. It will be removed as soon as it is hit. */ set_breakpoint_at ((CORE_ADDR) (long) current_event.u .CreateProcessInfo.lpStartAddress, auto_delete_breakpoint); } #endif break; case EXIT_PROCESS_DEBUG_EVENT: OUTMSG2 (("gdbserver: kernel event EXIT_PROCESS_DEBUG_EVENT " "for pid=%u tid=%x\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId)); ourstatus->kind = TARGET_WAITKIND_EXITED; ourstatus->value.integer = current_event.u.ExitProcess.dwExitCode; child_continue (DBG_CONTINUE, -1); CloseHandle (current_process_handle); current_process_handle = NULL; break; case LOAD_DLL_DEBUG_EVENT: OUTMSG2 (("gdbserver: kernel event LOAD_DLL_DEBUG_EVENT " "for pid=%u tid=%x\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId)); CloseHandle (current_event.u.LoadDll.hFile); if (! child_initialization_done) break; handle_load_dll (); ourstatus->kind = TARGET_WAITKIND_LOADED; ourstatus->value.sig = GDB_SIGNAL_TRAP; break; case UNLOAD_DLL_DEBUG_EVENT: OUTMSG2 (("gdbserver: kernel event UNLOAD_DLL_DEBUG_EVENT " "for pid=%u tid=%x\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId)); if (! child_initialization_done) break; handle_unload_dll (); ourstatus->kind = TARGET_WAITKIND_LOADED; ourstatus->value.sig = GDB_SIGNAL_TRAP; break; case EXCEPTION_DEBUG_EVENT: OUTMSG2 (("gdbserver: kernel event EXCEPTION_DEBUG_EVENT " "for pid=%u tid=%x\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId)); 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=%u tid=%x\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId)); handle_output_debug_string (ourstatus); break; default: OUTMSG2 (("gdbserver: kernel event unknown " "for pid=%u tid=%x code=%x\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId, (unsigned) current_event.dwDebugEventCode)); break; } ptid = debug_event_ptid (¤t_event); current_inferior = (struct thread_info *) find_inferior_id (&all_threads, ptid); return 1; }
/* Start a new process. PROGRAM is a path to the program to execute. ARGS is a standard NULL-terminated array of arguments, to be passed to the inferior as ``argv''. Returns the new PID on success, -1 on failure. Registers the new process with the process list. */ static int win32_create_inferior (char *program, char **program_args) { #ifndef USE_WIN32API char real_path[MAXPATHLEN]; char *orig_path, *new_path, *path_ptr; #endif BOOL ret; DWORD flags; char *args; int argslen; int argc; PROCESS_INFORMATION pi; DWORD err; /* win32_wait needs to know we're not attaching. */ attaching = 0; if (!program) error ("No executable specified, specify executable to debug.\n"); flags = DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS; #ifndef USE_WIN32API orig_path = NULL; path_ptr = getenv ("PATH"); if (path_ptr) { orig_path = alloca (strlen (path_ptr) + 1); new_path = alloca (cygwin_posix_to_win32_path_list_buf_size (path_ptr)); strcpy (orig_path, path_ptr); cygwin_posix_to_win32_path_list (path_ptr, new_path); setenv ("PATH", new_path, 1); } cygwin_conv_to_win32_path (program, real_path); program = real_path; #endif argslen = 1; for (argc = 1; program_args[argc]; argc++) argslen += strlen (program_args[argc]) + 1; args = alloca (argslen); args[0] = '\0'; for (argc = 1; program_args[argc]; argc++) { /* FIXME: Can we do better about quoting? How does Cygwin handle this? */ strcat (args, " "); strcat (args, program_args[argc]); } OUTMSG2 (("Command line is \"%s\"\n", args)); #ifdef CREATE_NEW_PROCESS_GROUP flags |= CREATE_NEW_PROCESS_GROUP; #endif ret = create_process (program, args, flags, &pi); err = GetLastError (); if (!ret && err == ERROR_FILE_NOT_FOUND) { char *exename = alloca (strlen (program) + 5); strcat (strcpy (exename, program), ".exe"); ret = create_process (exename, args, flags, &pi); err = GetLastError (); } #ifndef USE_WIN32API if (orig_path) setenv ("PATH", orig_path, 1); #endif if (!ret) { error ("Error creating process \"%s%s\", (error %d): %s\n", program, args, (int) err, strwinerror (err)); } else { OUTMSG2 (("Process created: %s\n", (char *) args)); } #ifndef _WIN32_WCE /* On Windows CE this handle can't be closed. The OS reuses it in the debug events, while the 9x/NT versions of Windows probably use a DuplicateHandle'd one. */ CloseHandle (pi.hThread); #endif do_initial_child_stuff (pi.hProcess, pi.dwProcessId); return current_process_id; }