From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 11148 invoked by alias); 5 Feb 2002 12:59:22 -0000 Mailing-List: contact gdb-patches-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sources.redhat.com Received: (qmail 11058 invoked from network); 5 Feb 2002 12:59:16 -0000 Received: from unknown (HELO cerbere.u-strasbg.fr) (130.79.112.7) by sources.redhat.com with SMTP; 5 Feb 2002 12:59:16 -0000 Received: from laocoon (laocoon.u-strasbg.fr [130.79.112.72]) by cerbere.u-strasbg.fr (8.9.3/8.8.7) with ESMTP id NAA25803 for ; Tue, 5 Feb 2002 13:59:15 +0100 Message-Id: <4.2.0.58.20020205135825.01c36b00@ics.u-strasbg.fr> X-Sender: muller@ics.u-strasbg.fr X-Mailer: QUALCOMM Windows Eudora Pro Version 4.2.0.58 Date: Tue, 05 Feb 2002 04:59:00 -0000 To: gdb-patches@sources.redhat.com From: Pierre Muller Subject: [RFC] handle signal passing to debuggee for win32 native target. Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=====================_69733221==_" X-SW-Source: 2002-02/txt/msg00115.txt.bz2 --=====================_69733221==_ Content-Type: text/plain; charset="us-ascii" Content-length: 2821 The following patch handles (to the best of what I discovered can be done) the passing of signals to the inferior for native win32 targets. Known limitation: -- The main problem is that this will only partially work because of a known bug in the win32 API: Extracted from http://www.microsoft.com/msj/defaultframe.asp?page=/msj/0898/bugslayer0898.htm&nav=/msj/0898/newnav.htm There are a couple of issues to remember when using SetUnhandledExceptionFilter. The first is that any exception filter that you set cannot be debugged. This is a known bug. Knowledge Base article Q173652 says that under a debugger the process wide filter is not called. This can be a bit of a pain, but in a C++ program you can just use your function in a regular SEH exception filter to debug it. If you look at the CH_TEST.CPP test program, which is part of this month's source code (Aug98Bugslayer.exe ), this is exactly what I did to debug it. An alternative is to use a kernel debugger like WinDBG to get around this limitation. But I don't really know if Cygwin library uses SetUnhandledExceptionFilter (I suspect it does as my patch does not work as intended...). The other problem seems to be that changes to the ExceptionRecord structure in the current_event do not seem to be reflected when the exception is passed to the debuggee. (See the disabled code in the patch for child_resume). Passing another signal value then the one generated does not seem possible. Simple test program to check the changes: >>>>test.c begin int x; int * y; int main () { (int) y = 0xfffffff0; x = 56; *y = x; return 0; } >>>>test.c end gcc -g -o test.exe test.c Use the newly build gdb (with the patch below applied) ./gdb ./test (gdb)run (gdb)cont > You should get a stackdump due to an SIGSEGV signal. (gdb)run (gdb)handle SIGSEGV nopass (gdb)cont > You should get a second SIGSEGV report but if you check the assembler instruction (gdb) x /i $eip it should give you something like (gdb) mov %edx,(%eax) with $eax containing 0xfffffff0 if you change the value of $eax to &x you should be able to finish the program without any error. 2002-02-05 Pierre Muller win32-nat.c (last_sig): Changed type of variable to target_signal, to allow easier handling of pass state. (DEBUG_EXCEPTION_SIMPLE): New macro, used in handle_exception, that gives exception name and address. (handle_exception): Use DEBUG_EXCEPTION_SIMPLE macro and set last_sig value to ourstatus->value.sig. Some missing exceptions added. (child_continue): Correctly report continue_status. (get_child_debug_event,do_initial_child_stuff): Set last_sig to TARGET_SIGNAL_0 (new default value). (child_resume): consider sig argument passed to decide if the exception should be passed to debuggee or not. --=====================_69733221==_ Content-Type: text/plain; charset="us-ascii" Content-Disposition: attachment; filename="win32-nat.diffs" Content-length: 8756 Index: win32-nat.c =================================================================== RCS file: /cvs/src/src/gdb/win32-nat.c,v retrieving revision 1.45 diff -u -p -b -r1.45 win32-nat.c --- win32-nat.c 2002/02/05 08:04:22 1.45 +++ win32-nat.c 2002/02/05 12:55:12 @@ -98,8 +98,9 @@ static void child_stop (void); static int win32_child_thread_alive (ptid_t); void child_kill_inferior (void); -static int last_sig = 0; /* Set if a signal was received from the - debugged process */ +static enum target_signal last_sig = TARGET_SIGNAL_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 @@ -218,6 +219,7 @@ static const struct xlate_exception {EXCEPTION_BREAKPOINT, TARGET_SIGNAL_TRAP}, {DBG_CONTROL_C, TARGET_SIGNAL_INT}, {EXCEPTION_SINGLE_STEP, TARGET_SIGNAL_TRAP}, + {STATUS_FLOAT_DIVIDE_BY_ZERO, TARGET_SIGNAL_FPE}, {-1, -1}}; static void @@ -823,6 +825,10 @@ handle_output_debug_string (struct targe return gotasig; } +#define DEBUG_EXCEPTION_SIMPLE(x) if (debug_exceptions) \ + printf ("gdb: Target exception %s at 0x%08lx\n", x, \ + (DWORD) current_event.u.Exception.ExceptionRecord.ExceptionAddress) + static int handle_exception (struct target_waitstatus *ourstatus) { @@ -837,52 +843,80 @@ handle_exception (struct target_waitstat switch (code) { case EXCEPTION_ACCESS_VIOLATION: - DEBUG_EXCEPT (("gdb: Target exception ACCESS_VIOLATION at 0x%08lx\n", - (DWORD) current_event.u.Exception.ExceptionRecord.ExceptionAddress)); + DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ACCESS_VIOLATION"); + ourstatus->value.sig = TARGET_SIGNAL_SEGV; + break; + case STATUS_STACK_OVERFLOW: + DEBUG_EXCEPTION_SIMPLE ("STATUS_STACK_OVERFLOW"); ourstatus->value.sig = TARGET_SIGNAL_SEGV; - last_sig = SIGSEGV; + break; + case STATUS_FLOAT_DENORMAL_OPERAND: + DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_DENORMAL_OPERAND"); + ourstatus->value.sig = TARGET_SIGNAL_FPE; + break; + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: + DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ARRAY_BOUNDS_EXCEEDED"); + ourstatus->value.sig = TARGET_SIGNAL_FPE; + break; + case STATUS_FLOAT_INEXACT_RESULT: + DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_INEXACT_RESULT"); + ourstatus->value.sig = TARGET_SIGNAL_FPE; + break; + case STATUS_FLOAT_INVALID_OPERATION: + DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_INVALID_OPERATION"); + ourstatus->value.sig = TARGET_SIGNAL_FPE; + break; + case STATUS_FLOAT_OVERFLOW: + DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_OVERFLOW"); + ourstatus->value.sig = TARGET_SIGNAL_FPE; + break; + case STATUS_FLOAT_STACK_CHECK: + DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_STACK_CHECK"); + ourstatus->value.sig = TARGET_SIGNAL_FPE; break; case STATUS_FLOAT_UNDERFLOW: + DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_UNDERFLOW"); + ourstatus->value.sig = TARGET_SIGNAL_FPE; + break; case STATUS_FLOAT_DIVIDE_BY_ZERO: - case STATUS_FLOAT_OVERFLOW: + DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_DIVIDE_BY_ZERO"); + ourstatus->value.sig = TARGET_SIGNAL_FPE; + break; case STATUS_INTEGER_DIVIDE_BY_ZERO: - DEBUG_EXCEPT (("gdb: Target exception STACK_OVERFLOW at 0x%08lx\n", - (DWORD) current_event.u.Exception.ExceptionRecord.ExceptionAddress)); + DEBUG_EXCEPTION_SIMPLE ("STATUS_INTEGER_DIVIDE_BY_ZERO"); ourstatus->value.sig = TARGET_SIGNAL_FPE; - last_sig = SIGFPE; break; - case STATUS_STACK_OVERFLOW: - DEBUG_EXCEPT (("gdb: Target exception STACK_OVERFLOW at 0x%08lx\n", - (DWORD) current_event.u.Exception.ExceptionRecord.ExceptionAddress)); - ourstatus->value.sig = TARGET_SIGNAL_SEGV; + case STATUS_INTEGER_OVERFLOW: + DEBUG_EXCEPTION_SIMPLE ("STATUS_INTEGER_OVERFLOW"); + ourstatus->value.sig = TARGET_SIGNAL_FPE; break; case EXCEPTION_BREAKPOINT: - DEBUG_EXCEPT (("gdb: Target exception BREAKPOINT at 0x%08lx\n", - (DWORD) current_event.u.Exception.ExceptionRecord.ExceptionAddress)); + DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_BREAKPOINT"); ourstatus->value.sig = TARGET_SIGNAL_TRAP; break; case DBG_CONTROL_C: - DEBUG_EXCEPT (("gdb: Target exception CONTROL_C at 0x%08lx\n", - (DWORD) current_event.u.Exception.ExceptionRecord.ExceptionAddress)); + DEBUG_EXCEPTION_SIMPLE ("DBG_CONTROL_C"); ourstatus->value.sig = TARGET_SIGNAL_INT; - last_sig = SIGINT; /* FIXME - should check pass state */ break; case DBG_CONTROL_BREAK: - DEBUG_EXCEPT (("gdb: Target exception CONTROL_BREAK at 0x%08lx\n", - (DWORD) current_event.u.Exception.ExceptionRecord.ExceptionAddress)); + DEBUG_EXCEPTION_SIMPLE ("DBG_CONTROL_BREAK"); ourstatus->value.sig = TARGET_SIGNAL_INT; - last_sig = SIGINT; /* FIXME - should check pass state */ break; case EXCEPTION_SINGLE_STEP: - DEBUG_EXCEPT (("gdb: Target exception SINGLE_STEP at 0x%08lx\n", - (DWORD) current_event.u.Exception.ExceptionRecord.ExceptionAddress)); + DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_SINGLE_STEP"); ourstatus->value.sig = TARGET_SIGNAL_TRAP; break; case EXCEPTION_ILLEGAL_INSTRUCTION: - DEBUG_EXCEPT (("gdb: Target exception SINGLE_ILL at 0x%08lx\n", - (DWORD) current_event.u.Exception.ExceptionRecord.ExceptionAddress)); + DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ILLEGAL_INSTRUCTION"); + ourstatus->value.sig = TARGET_SIGNAL_ILL; + break; + case EXCEPTION_PRIV_INSTRUCTION: + DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_PRIV_INSTRUCTION"); + ourstatus->value.sig = TARGET_SIGNAL_ILL; + break; + case EXCEPTION_NONCONTINUABLE_EXCEPTION: + DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_NONCONTINUABLE_EXCEPTION"); ourstatus->value.sig = TARGET_SIGNAL_ILL; - last_sig = SIGILL; break; default: if (current_event.u.Exception.dwFirstChance) @@ -894,6 +928,7 @@ handle_exception (struct target_waitstat break; } exception_count++; + last_sig = ourstatus->value.sig; return 1; } @@ -906,8 +941,10 @@ child_continue (DWORD continue_status, i thread_info *th; BOOL res; - DEBUG_EVENTS (("ContinueDebugEvent (cpid=%ld, ctid=%ld, DBG_CONTINUE);\n", - current_event.dwProcessId, current_event.dwThreadId)); + DEBUG_EVENTS (("ContinueDebugEvent (cpid=%ld, ctid=%ld, %s);\n", + current_event.dwProcessId, current_event.dwThreadId, + continue_status == DBG_CONTINUE ? + "DBG_CONTINUE" : "DBG_EXCEPTION_NOT_HANDLED")); res = ContinueDebugEvent (current_event.dwProcessId, current_event.dwThreadId, continue_status); @@ -952,7 +989,7 @@ get_child_debug_event (int pid, struct t static thread_info dummy_thread_info; int retval = 0; - last_sig = 0; + last_sig = TARGET_SIGNAL_0; if (!(debug_event = WaitForDebugEvent (¤t_event, 1000))) goto out; @@ -1118,7 +1155,7 @@ do_initial_child_stuff (DWORD pid) extern int stop_after_trap; int i; - last_sig = 0; + last_sig = TARGET_SIGNAL_0; event_count = 0; exception_count = 0; debug_registers_changed = 0; @@ -1470,11 +1507,45 @@ void child_resume (ptid_t ptid, int step, enum target_signal sig) { thread_info *th; - DWORD continue_status = last_sig > 0 && last_sig < NSIG ? - DBG_EXCEPTION_NOT_HANDLED : DBG_CONTINUE; + DWORD continue_status = DBG_CONTINUE; + int pid = PIDGET (ptid); + + if (sig != TARGET_SIGNAL_0) + { + if (current_event.dwDebugEventCode != EXCEPTION_DEBUG_EVENT) + { + DEBUG_EXCEPT(("Cannot continue with signal %d here.\n",sig)); + } + else if (sig == last_sig) + continue_status = DBG_EXCEPTION_NOT_HANDLED; + else +#if 0 +/* This code does not seem to work, because + the kernel does probably not consider changes in the ExceptionRecord + 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) + { + current_event.u.Exception.ExceptionRecord.ExceptionCode = + xlate[i].them; + continue_status = DBG_EXCEPTION_NOT_HANDLED; + break; + } + if (continue_status == DBG_CONTINUE) + { + DEBUG_EXCEPT(("Cannot continue with signal %d.\n",sig)); + } + } +#endif + DEBUG_EXCEPT(("Can only continue with recieved signal %d.\n", + last_sig)); + } - last_sig = 0; + last_sig = TARGET_SIGNAL_0; DEBUG_EXEC (("gdb: child_resume (pid=%d, step=%d, sig=%d);\n", pid, step, sig)); --=====================_69733221==_ Content-Type: text/plain; charset="us-ascii" Content-length: 176 Pierre Muller Institut Charles Sadron 6,rue Boussingault F 67083 STRASBOURG CEDEX (France) mailto:muller@ics.u-strasbg.fr Phone : (33)-3-88-41-40-07 Fax : (33)-3-88-41-40-99 --=====================_69733221==_--