+/* 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
+
+handle_exception_result
+handle_exception (struct target_waitstatus *ourstatus, bool debug_exceptions)
+{
+#define DEBUG_EXCEPTION_SIMPLE(x) if (debug_exceptions) \
+ debug_printf ("gdb: Target exception %s at %s\n", x, \
+ host_address_to_string (\
+ current_event.u.Exception.ExceptionRecord.ExceptionAddress))
+
+ EXCEPTION_RECORD *rec = ¤t_event.u.Exception.ExceptionRecord;
+ DWORD code = rec->ExceptionCode;
+ handle_exception_result result = HANDLE_EXCEPTION_HANDLED;
+
+ memcpy (&siginfo_er, rec, sizeof siginfo_er);
+
+ ourstatus->kind = TARGET_WAITKIND_STOPPED;
+
+ /* Record the context of the current thread. */
+ thread_rec (ptid_t (current_event.dwProcessId, current_event.dwThreadId, 0),
+ DONT_SUSPEND);
+
+ switch (code)
+ {
+ case EXCEPTION_ACCESS_VIOLATION:
+ DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ACCESS_VIOLATION");
+ ourstatus->value.sig = GDB_SIGNAL_SEGV;
+#ifdef __CYGWIN__
+ {
+ /* See if the access violation happened within the cygwin DLL
+ itself. Cygwin uses a kind of exception handling to deal
+ with passed-in invalid addresses. gdb should not treat
+ these as real SEGVs since they will be silently handled by
+ cygwin. A real SEGV will (theoretically) be caught by
+ cygwin later in the process and will be sent as a
+ cygwin-specific-signal. So, ignore SEGVs if they show up
+ within the text segment of the DLL itself. */
+ const char *fn;
+ 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 HANDLE_EXCEPTION_UNHANDLED;
+ }
+#endif
+ break;
+ case STATUS_STACK_OVERFLOW:
+ DEBUG_EXCEPTION_SIMPLE ("STATUS_STACK_OVERFLOW");
+ ourstatus->value.sig = GDB_SIGNAL_SEGV;
+ break;
+ case STATUS_FLOAT_DENORMAL_OPERAND:
+ DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_DENORMAL_OPERAND");
+ ourstatus->value.sig = GDB_SIGNAL_FPE;
+ break;
+ case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
+ DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ARRAY_BOUNDS_EXCEEDED");
+ ourstatus->value.sig = GDB_SIGNAL_FPE;
+ break;
+ case STATUS_FLOAT_INEXACT_RESULT:
+ DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_INEXACT_RESULT");
+ ourstatus->value.sig = GDB_SIGNAL_FPE;
+ break;
+ case STATUS_FLOAT_INVALID_OPERATION:
+ DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_INVALID_OPERATION");
+ ourstatus->value.sig = GDB_SIGNAL_FPE;
+ break;
+ case STATUS_FLOAT_OVERFLOW:
+ DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_OVERFLOW");
+ ourstatus->value.sig = GDB_SIGNAL_FPE;
+ break;
+ case STATUS_FLOAT_STACK_CHECK:
+ DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_STACK_CHECK");
+ ourstatus->value.sig = GDB_SIGNAL_FPE;
+ break;
+ case STATUS_FLOAT_UNDERFLOW:
+ DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_UNDERFLOW");
+ ourstatus->value.sig = GDB_SIGNAL_FPE;
+ break;
+ case STATUS_FLOAT_DIVIDE_BY_ZERO:
+ DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_DIVIDE_BY_ZERO");
+ ourstatus->value.sig = GDB_SIGNAL_FPE;
+ break;
+ case STATUS_INTEGER_DIVIDE_BY_ZERO:
+ DEBUG_EXCEPTION_SIMPLE ("STATUS_INTEGER_DIVIDE_BY_ZERO");
+ ourstatus->value.sig = GDB_SIGNAL_FPE;
+ break;
+ case STATUS_INTEGER_OVERFLOW:
+ DEBUG_EXCEPTION_SIMPLE ("STATUS_INTEGER_OVERFLOW");
+ ourstatus->value.sig = GDB_SIGNAL_FPE;
+ break;
+ case EXCEPTION_BREAKPOINT:
+#ifdef __x86_64__
+ if (ignore_first_breakpoint)
+ {
+ /* For WOW64 processes, there are always 2 breakpoint exceptions
+ on startup, first a BREAKPOINT for the 64bit ntdll.dll,
+ then a WX86_BREAKPOINT for the 32bit ntdll.dll.
+ Here we only care about the WX86_BREAKPOINT's. */
+ ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
+ ignore_first_breakpoint = false;
+ }
+#endif
+ /* FALLTHROUGH */
+ case STATUS_WX86_BREAKPOINT:
+ DEBUG_EXCEPTION_SIMPLE ("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:
+ DEBUG_EXCEPTION_SIMPLE ("DBG_CONTROL_C");
+ ourstatus->value.sig = GDB_SIGNAL_INT;
+ break;
+ case DBG_CONTROL_BREAK:
+ DEBUG_EXCEPTION_SIMPLE ("DBG_CONTROL_BREAK");
+ ourstatus->value.sig = GDB_SIGNAL_INT;
+ break;
+ case EXCEPTION_SINGLE_STEP:
+ case STATUS_WX86_SINGLE_STEP:
+ DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_SINGLE_STEP");
+ ourstatus->value.sig = GDB_SIGNAL_TRAP;
+ break;
+ case EXCEPTION_ILLEGAL_INSTRUCTION:
+ DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ILLEGAL_INSTRUCTION");
+ ourstatus->value.sig = GDB_SIGNAL_ILL;
+ break;
+ case EXCEPTION_PRIV_INSTRUCTION:
+ DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_PRIV_INSTRUCTION");
+ ourstatus->value.sig = GDB_SIGNAL_ILL;
+ break;
+ case EXCEPTION_NONCONTINUABLE_EXCEPTION:
+ DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_NONCONTINUABLE_EXCEPTION");
+ ourstatus->value.sig = GDB_SIGNAL_ILL;
+ break;
+ case MS_VC_EXCEPTION:
+ DEBUG_EXCEPTION_SIMPLE ("MS_VC_EXCEPTION");
+ if (handle_ms_vc_exception (rec))
+ {
+ 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 HANDLE_EXCEPTION_UNHANDLED;
+ debug_printf ("gdb: unknown target exception 0x%08x at %s\n",
+ (unsigned) current_event.u.Exception.ExceptionRecord.ExceptionCode,
+ host_address_to_string (
+ current_event.u.Exception.ExceptionRecord.ExceptionAddress));
+ ourstatus->value.sig = GDB_SIGNAL_UNKNOWN;
+ break;
+ }
+
+ last_sig = ourstatus->value.sig;
+ return result;
+
+#undef DEBUG_EXCEPTION_SIMPLE
+}
+