diff --git a/hurd/hurd/signal.h b/hurd/hurd/signal.h index 1c4733a..cc96f21 100644 --- a/hurd/hurd/signal.h +++ b/hurd/hurd/signal.h @@ -247,40 +247,45 @@ _hurd_critical_section_unlock (void *our_lock) Arguments give the "init ints" from exec_startup. */ extern void _hurdsig_init (const int *intarray, size_t intarraysize); /* Initialize proc server-assisted fault recovery for the signal thread. */ extern void _hurdsig_fault_init (void); /* Raise a signal as described by SIGNO an DETAIL, on the thread whose sigstate SS points to. If SS is a null pointer, this instead affects the calling thread. */ extern void _hurd_raise_signal (struct hurd_sigstate *ss, int signo, const struct hurd_signal_detail *detail); /* Translate a Mach exception into a signal (machine-dependent). */ extern void _hurd_exception2signal (struct hurd_signal_detail *detail, int *signo); +/* Translate a Mach exception into a signal with a legacy sigcode. */ + +extern void _hurd_exception2signal_legacy (struct hurd_signal_detail *detail, + int *signo); + /* Make the thread described by SS take the signal described by SIGNO and DETAIL. If the process is traced, this will in fact stop with a SIGNO as the stop signal unless UNTRACED is nonzero. When the signal can be considered delivered, sends a sig_post reply message on REPLY_PORT indicating success. SS is not locked. */ extern void _hurd_internal_post_signal (struct hurd_sigstate *ss, int signo, struct hurd_signal_detail *detail, mach_port_t reply_port, mach_msg_type_name_t reply_port_type, int untraced); /* Set up STATE and SS to handle signal SIGNO by running HANDLER. If RPC_WAIT is nonzero, the thread needs to wait for a pending RPC to finish before running the signal handler. The handler is passed SIGNO, SIGCODE, and the returned `struct sigcontext' (which resides on the stack the handler will use, and which describes the state of the thread encoded in STATE before running the handler). */ diff --git a/hurd/hurdinit.c b/hurd/hurdinit.c index 259f8a3..97d3460 100644 --- a/hurd/hurdinit.c +++ b/hurd/hurdinit.c @@ -159,41 +159,41 @@ _hurd_new_proc_init (char **argv, _hurdsig_fault_init (); /* Call other things which want to do some initialization. These are not on the _hurd_subinit hook because things there assume that things done here, like _hurd_pid, are already initialized. */ RUN_HOOK (_hurd_proc_subinit, ()); /* XXX This code should probably be removed entirely at some point. This conditional should make it reasonably usable with old gdb's for a while. Eventually it probably makes most sense for the exec server to mask out EXEC_SIGTRAP so the debugged program is closer to not being able to tell it's being debugged. */ if (!__sigisemptyset (&_hurdsig_traced) #ifdef EXEC_SIGTRAP && !(_hurd_exec_flags & EXEC_SIGTRAP) #endif ) /* This process is "traced", meaning it should stop on signals or exec. We are all set up now to handle signals. Stop ourselves, to inform our parent (presumably a debugger) that the exec has completed. */ - __msg_sig_post (_hurd_msgport, SIGTRAP, 0, __mach_task_self ()); + __msg_sig_post (_hurd_msgport, SIGTRAP, TRAP_TRACE, __mach_task_self ()); } #include versioned_symbol (libc, _hurd_new_proc_init, _hurd_proc_init, GLIBC_2_1); /* Called when we get a message telling us to change our proc server port. */ error_t _hurd_setproc (process_t procserver) { error_t err; mach_port_t oldmsg; /* Give the proc server our message port. */ if (err = __proc_setmsgport (procserver, _hurd_msgport, &oldmsg)) return err; if (oldmsg != MACH_PORT_NULL) /* Deallocate the old msg port we replaced. */ __mach_port_deallocate (__mach_task_self (), oldmsg); diff --git a/sysdeps/mach/hurd/i386/bits/sigcontext.h b/sysdeps/mach/hurd/i386/bits/sigcontext.h index a78dd2f..1956d41 100644 --- a/sysdeps/mach/hurd/i386/bits/sigcontext.h +++ b/sysdeps/mach/hurd/i386/bits/sigcontext.h @@ -79,40 +79,44 @@ struct sigcontext int sc_uesp; /* This stack pointer is used. */ int sc_ss; /* Stack segment register. */ /* Following mimics struct i386_float_state. Structures and symbolic values can be found in . */ #define sc_i386_float_state sc_fpkind int sc_fpkind; /* FP_NO, FP_387, etc. */ int sc_fpused; /* If zero, ignore rest of float state. */ struct i386_fp_save sc_fpsave; struct i386_fp_regs sc_fpregs; int sc_fpexcsr; /* FPSR including exception bits. */ }; /* Traditional BSD names for some members. */ #define sc_sp sc_uesp /* Stack pointer. */ #define sc_fp sc_ebp /* Frame pointer. */ #define sc_pc sc_eip /* Process counter. */ #define sc_ps sc_efl +/* The deprecated sigcode values below are passed as an extra, non-portable + argument to regular signal handlers. You should use SA_SIGINFO handlers + instead, which use the standard POSIX signal codes. */ + /* Codes for SIGFPE. */ #define FPE_INTOVF_TRAP 0x1 /* integer overflow */ #define FPE_INTDIV_FAULT 0x2 /* integer divide by zero */ #define FPE_FLTOVF_FAULT 0x3 /* floating overflow */ #define FPE_FLTDIV_FAULT 0x4 /* floating divide by zero */ #define FPE_FLTUND_FAULT 0x5 /* floating underflow */ #define FPE_SUBRNG_FAULT 0x7 /* BOUNDS instruction failed */ #define FPE_FLTDNR_FAULT 0x8 /* denormalized operand */ #define FPE_FLTINX_FAULT 0x9 /* floating loss of precision */ #define FPE_EMERR_FAULT 0xa /* mysterious emulation error 33 */ #define FPE_EMBND_FAULT 0xb /* emulation BOUNDS instruction failed */ /* Codes for SIGILL. */ #define ILL_INVOPR_FAULT 0x1 /* invalid operation */ #define ILL_STACK_FAULT 0x2 /* fault on microkernel stack access */ #define ILL_FPEOPR_FAULT 0x3 /* invalid floating operation */ /* Codes for SIGTRAP. */ #define DBG_SINGLE_TRAP 0x1 /* single step */ #define DBG_BRKPNT_FAULT 0x2 /* breakpoint instruction */ diff --git a/sysdeps/mach/hurd/i386/exc2signal.c b/sysdeps/mach/hurd/i386/exc2signal.c index a6bf750..7ffeb5f 100644 --- a/sysdeps/mach/hurd/i386/exc2signal.c +++ b/sysdeps/mach/hurd/i386/exc2signal.c @@ -7,160 +7,191 @@ License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include #include #include /* Translate the Mach exception codes, as received in an `exception_raise' RPC, into a signal number and signal subcode. */ -void -_hurd_exception2signal (struct hurd_signal_detail *detail, int *signo) +static void +exception2signal (struct hurd_signal_detail *detail, int *signo, int posix) { detail->error = 0; switch (detail->exc) { default: *signo = SIGIOT; detail->code = detail->exc; break; case EXC_BAD_ACCESS: - if (detail->exc_code == KERN_INVALID_ADDRESS - || detail->exc_code == KERN_PROTECTION_FAILURE - || detail->exc_code == KERN_WRITE_PROTECTION_FAILURE) - *signo = SIGSEGV; - else - *signo = SIGBUS; - detail->code = detail->exc_subcode; + switch (detail->exc_code) + { + case KERN_INVALID_ADDRESS: + case KERN_MEMORY_FAILURE: + *signo = SIGSEGV; + detail->code = posix ? SEGV_MAPERR : detail->exc_subcode; + break; + + case KERN_PROTECTION_FAILURE: + case KERN_WRITE_PROTECTION_FAILURE: + *signo = SIGSEGV; + detail->code = posix ? SEGV_ACCERR : detail->exc_subcode; + break; + + default: + *signo = SIGBUS; + detail->code = 0; + break; + } detail->error = detail->exc_code; break; case EXC_BAD_INSTRUCTION: *signo = SIGILL; - if (detail->exc_code == EXC_I386_INVOP) - detail->code = ILL_INVOPR_FAULT; - else if (detail->exc_code == EXC_I386_STKFLT) - detail->code = ILL_STACK_FAULT; - else - detail->code = 0; + switch (detail->exc_code) + { + case EXC_I386_INVOP: + detail->code = posix ? ILL_ILLOPC : ILL_INVOPR_FAULT; + break; + + case EXC_I386_STKFLT: + detail->code = posix ? ILL_BADSTK : ILL_STACK_FAULT; + break; + + default: + detail->code = 0; + break; + } break; case EXC_ARITHMETIC: + *signo = SIGFPE; switch (detail->exc_code) { case EXC_I386_DIV: /* integer divide by zero */ - *signo = SIGFPE; - detail->code = FPE_INTDIV_FAULT; + detail->code = posix ? FPE_INTDIV : FPE_INTDIV_FAULT; break; case EXC_I386_INTO: /* integer overflow */ - *signo = SIGFPE; - detail->code = FPE_INTOVF_TRAP; + detail->code = posix ? FPE_INTOVF : FPE_INTOVF_TRAP; break; /* These aren't anywhere documented or used in Mach 3.0. */ case EXC_I386_NOEXT: case EXC_I386_EXTOVR: default: - *signo = SIGFPE; detail->code = 0; break; case EXC_I386_EXTERR: /* Subcode is the fp_status word saved by the hardware. Give an error code corresponding to the first bit set. */ if (detail->exc_subcode & FPS_IE) { - *signo = SIGILL; - detail->code = ILL_FPEOPR_FAULT; + /* NB: We used to send SIGILL here but we can't distinguish + POSIX vs. legacy with respect to what signal we send. */ + detail->code = posix ? FPE_FLTINV : 0 /*ILL_FPEOPR_FAULT*/; } else if (detail->exc_subcode & FPS_DE) { - *signo = SIGFPE; - detail->code = FPE_FLTDNR_FAULT; + detail->code = posix ? FPE_FLTUND : FPE_FLTDNR_FAULT; } else if (detail->exc_subcode & FPS_ZE) { - *signo = SIGFPE; - detail->code = FPE_FLTDIV_FAULT; + detail->code = posix ? FPE_FLTDIV : FPE_FLTDIV_FAULT; } else if (detail->exc_subcode & FPS_OE) { - *signo = SIGFPE; - detail->code = FPE_FLTOVF_FAULT; + detail->code = posix ? FPE_FLTOVF : FPE_FLTOVF_FAULT; } else if (detail->exc_subcode & FPS_UE) { - *signo = SIGFPE; - detail->code = FPE_FLTUND_FAULT; + detail->code = posix ? FPE_FLTUND : FPE_FLTUND_FAULT; } else if (detail->exc_subcode & FPS_PE) { - *signo = SIGFPE; - detail->code = FPE_FLTINX_FAULT; + detail->code = posix ? FPE_FLTRES : FPE_FLTINX_FAULT; } else { - *signo = SIGFPE; detail->code = 0; } break; /* These two can only be arithmetic exceptions if we - are in V86 mode, which sounds like emulation to me. - (See Mach 3.0 i386/trap.c.) */ + are in V86 mode. (See Mach 3.0 i386/trap.c.) */ case EXC_I386_EMERR: - *signo = SIGFPE; - detail->code = FPE_EMERR_FAULT; + detail->code = posix ? 0 : FPE_EMERR_FAULT; break; case EXC_I386_BOUND: - *signo = SIGFPE; - detail->code = FPE_EMBND_FAULT; + detail->code = posix ? FPE_FLTSUB : FPE_EMBND_FAULT; break; } break; case EXC_EMULATION: /* 3.0 doesn't give this one, why, I don't know. */ *signo = SIGEMT; detail->code = 0; break; case EXC_SOFTWARE: /* The only time we get this in Mach 3.0 is for an out of bounds trap. */ if (detail->exc_code == EXC_I386_BOUND) { *signo = SIGFPE; - detail->code = FPE_SUBRNG_FAULT; + detail->code = posix ? FPE_FLTSUB : FPE_SUBRNG_FAULT; } else { *signo = SIGEMT; detail->code = 0; } break; case EXC_BREAKPOINT: *signo = SIGTRAP; - if (detail->exc_code == EXC_I386_SGL) - detail->code = DBG_SINGLE_TRAP; - else if (detail->exc_code == EXC_I386_BPT) - detail->code = DBG_BRKPNT_FAULT; - else - detail->code = 0; + switch (detail->exc_code) + { + case EXC_I386_SGL: + detail->code = posix ? TRAP_BRKPT : DBG_SINGLE_TRAP; + break; + + case EXC_I386_BPT: + detail->code = posix ? TRAP_BRKPT : DBG_BRKPNT_FAULT; + break; + + default: + detail->code = 0; + break; + } break; } } + +void +_hurd_exception2signal (struct hurd_signal_detail *detail, int *signo) +{ + exception2signal (detail, signo, 1); +} + +void +_hurd_exception2signal_legacy (struct hurd_signal_detail *detail, int *signo) +{ + exception2signal (detail, signo, 0); +} + diff --git a/sysdeps/mach/hurd/i386/trampoline.c b/sysdeps/mach/hurd/i386/trampoline.c index 0d2660d..5abd33d 100644 --- a/sysdeps/mach/hurd/i386/trampoline.c +++ b/sysdeps/mach/hurd/i386/trampoline.c @@ -225,40 +225,49 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler, memcpy (&scp->sc_i386_thread_state, &state->basic, sizeof (state->basic)); /* struct sigcontext is laid out so that starting at sc_fpkind mimics a struct i386_float_state. */ ok = machine_get_state (ss->thread, state, i386_FLOAT_STATE, &state->fpu, &scp->sc_i386_float_state, sizeof (state->fpu)); /* Set up the arguments for the signal handler. */ stackframe->signo = signo; if (action->sa_flags & SA_SIGINFO) { stackframe->posix.siginfop = &stackframe->siginfo; stackframe->posix.uctxp = &stackframe->ucontext; fill_siginfo (&stackframe->siginfo, signo, detail, state); fill_ucontext (&stackframe->ucontext, scp); } else { + if (detail->exc) + { + int nsigno; + _hurd_exception2signal_legacy (detail, &nsigno); + assert (nsigno == signo); + } + else + detail->code = 0; + stackframe->legacy.sigcode = detail->code; stackframe->legacy.scp = &stackframe->ctx; } /* Set up the bottom of the stack. */ stackframe->sigreturn_addr = &__sigreturn; stackframe->sigreturn_returns_here = firewall; /* Crash on return. */ stackframe->return_scp = &stackframe->ctx; _hurdsig_end_catch_fault (); if (! ok) return NULL; } /* Modify the thread state to call the trampoline code on the new stack. */ if (rpc_wait) { /* The signalee thread was blocked in a mach_msg_trap system call, still waiting for a reply. We will have it run the special diff --git a/sysdeps/mach/hurd/kill.c b/sysdeps/mach/hurd/kill.c index a9946e0..ac7ffc7 100644 --- a/sysdeps/mach/hurd/kill.c +++ b/sysdeps/mach/hurd/kill.c @@ -48,41 +48,41 @@ __kill (pid_t pid, int sig) get MIG_SERVER_DIED. */ do { task_t refport; err = __proc_pid2task (proc, pid, &refport); /* Ignore zombies. */ if (!err && refport != MACH_PORT_NULL) { err = __task_terminate (refport); __mach_port_deallocate (__mach_task_self (), refport); } } while (err == MACH_SEND_INVALID_DEST || err == MIG_SERVER_DIED); else { error_t taskerr; error_t kill_port (mach_port_t msgport, mach_port_t refport) { if (msgport != MACH_PORT_NULL) /* Send a signal message to his message port. */ - return __msg_sig_post (msgport, sig, 0, refport); + return __msg_sig_post (msgport, sig, SI_USER, refport); /* The process has no message port. Perhaps try direct frobnication of the task. */ if (taskerr) /* If we could not get the task port, we can do nothing. */ return taskerr; if (refport == MACH_PORT_NULL) /* proc_pid2task returned success with a null task port. That means the process is a zombie. Signals to zombies should return success and do nothing. */ return 0; /* For user convenience in the case of a task that has not registered any message port with the proc server, translate a few signals to direct task operations. */ switch (sig) { /* The only signals that really make sense for an diff --git a/sysdeps/mach/hurd/setitimer.c b/sysdeps/mach/hurd/setitimer.c index fec64a8..c82bfcd 100644 --- a/sysdeps/mach/hurd/setitimer.c +++ b/sysdeps/mach/hurd/setitimer.c @@ -88,41 +88,41 @@ timer_thread (void) the receive timeout. Notice interrupts so that if we are thread_abort'd, we will loop around and fetch new values from _hurd_itimerval. */ err = __mach_msg (&msg.header, MACH_RCV_MSG|MACH_RCV_TIMEOUT|MACH_RCV_INTERRUPT, 0, 0, _hurd_itimer_port, _hurd_itimerval.it_value.tv_sec * 1000 + _hurd_itimerval.it_value.tv_usec / 1000, MACH_PORT_NULL); switch (err) { case MACH_RCV_TIMED_OUT: /* We got the expected timeout. Send a message to the signal thread to tell it to post a SIGALRM signal. We use _hurd_itimer_port as the reply port just so we will block until the signal thread has frobnicated things to reload the itimer or has terminated this thread. */ __msg_sig_post_request (_hurd_msgport, _hurd_itimer_port, MACH_MSG_TYPE_MAKE_SEND_ONCE, - SIGALRM, 0, __mach_task_self ()); + SIGALRM, SI_TIMER, __mach_task_self ()); break; case MACH_RCV_INTERRUPTED: /* We were thread_abort'd. This is to tell us that _hurd_itimerval has changed and we need to reexamine it and start waiting with the new timeout value. */ break; case MACH_MSG_SUCCESS: /* We got the reply message from the sig_post_request above. Ignore it and reexamine the timer value. */ __mach_msg_destroy (&msg.header); /* Just in case. */ break; default: /* Unexpected lossage. Oh well, keep trying. */ break; } } }