summaryrefslogtreecommitdiff
path: root/sysdeps/mach/hurd/i386
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/mach/hurd/i386')
-rw-r--r--sysdeps/mach/hurd/i386/Makefile5
-rw-r--r--sysdeps/mach/hurd/i386/bits/sigcontext.h4
-rw-r--r--sysdeps/mach/hurd/i386/exc2signal.c123
-rw-r--r--sysdeps/mach/hurd/i386/getcontext.S74
-rw-r--r--sysdeps/mach/hurd/i386/init-first.c91
-rw-r--r--sysdeps/mach/hurd/i386/makecontext-helper.c71
-rw-r--r--sysdeps/mach/hurd/i386/makecontext.S130
-rw-r--r--sysdeps/mach/hurd/i386/setcontext.S92
-rw-r--r--sysdeps/mach/hurd/i386/sigreturn.c15
-rw-r--r--sysdeps/mach/hurd/i386/swapcontext.S110
-rw-r--r--sysdeps/mach/hurd/i386/tls.h147
-rw-r--r--sysdeps/mach/hurd/i386/tlsdesc.sym19
-rw-r--r--sysdeps/mach/hurd/i386/trampoline.c121
-rw-r--r--sysdeps/mach/hurd/i386/ucontext_i.sym29
14 files changed, 889 insertions, 142 deletions
diff --git a/sysdeps/mach/hurd/i386/Makefile b/sysdeps/mach/hurd/i386/Makefile
index 5f988097c2..9e1a978b6f 100644
--- a/sysdeps/mach/hurd/i386/Makefile
+++ b/sysdeps/mach/hurd/i386/Makefile
@@ -6,3 +6,8 @@ endif
ifeq ($(subdir),debug)
gen-as-const-headers += signal-defines.sym
endif
+
+ifeq ($(subdir),stdlib)
+gen-as-const-headers += ucontext_i.sym
+sysdep_routines += makecontext-helper
+endif
diff --git a/sysdeps/mach/hurd/i386/bits/sigcontext.h b/sysdeps/mach/hurd/i386/bits/sigcontext.h
index c51a94ef1a..321bbb4804 100644
--- a/sysdeps/mach/hurd/i386/bits/sigcontext.h
+++ b/sysdeps/mach/hurd/i386/bits/sigcontext.h
@@ -95,6 +95,10 @@ struct sigcontext
#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 */
diff --git a/sysdeps/mach/hurd/i386/exc2signal.c b/sysdeps/mach/hurd/i386/exc2signal.c
index b67acff08d..b4e35e9040 100644
--- a/sysdeps/mach/hurd/i386/exc2signal.c
+++ b/sysdeps/mach/hurd/i386/exc2signal.c
@@ -23,8 +23,8 @@
/* 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;
@@ -36,44 +36,62 @@ _hurd_exception2signal (struct hurd_signal_detail *detail, int *signo)
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;
@@ -82,51 +100,43 @@ _hurd_exception2signal (struct hurd_signal_detail *detail, int *signo)
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;
@@ -143,7 +153,7 @@ _hurd_exception2signal (struct hurd_signal_detail *detail, int *signo)
if (detail->exc_code == EXC_I386_BOUND)
{
*signo = SIGFPE;
- detail->code = FPE_SUBRNG_FAULT;
+ detail->code = posix ? FPE_FLTSUB : FPE_SUBRNG_FAULT;
}
else
{
@@ -154,12 +164,33 @@ _hurd_exception2signal (struct hurd_signal_detail *detail, int *signo)
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/getcontext.S b/sysdeps/mach/hurd/i386/getcontext.S
new file mode 100644
index 0000000000..e71f3bc645
--- /dev/null
+++ b/sysdeps/mach/hurd/i386/getcontext.S
@@ -0,0 +1,74 @@
+/* Save current context.
+ Copyright (C) 2001-2015 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2001.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+
+#include "ucontext_i.h"
+
+
+ENTRY(__getcontext)
+ /* Load address of the context data structure. */
+ movl 4(%esp), %eax
+
+ /* Return value of getcontext. EAX is the only register whose
+ value is not preserved. */
+ movl $0, oEAX(%eax)
+
+ /* Save the 32-bit register values and the return address. */
+ movl %ecx, oECX(%eax)
+ movl %edx, oEDX(%eax)
+ movl %edi, oEDI(%eax)
+ movl %esi, oESI(%eax)
+ movl %ebp, oEBP(%eax)
+ movl (%esp), %ecx
+ movl %ecx, oEIP(%eax)
+ leal 4(%esp), %ecx /* Exclude the return address. */
+ movl %ecx, oESP(%eax)
+ movl %ebx, oEBX(%eax)
+
+ /* Save the FS segment register. We don't touch the GS register
+ since it is used for threads. */
+ xorl %edx, %edx
+ movw %fs, %dx
+ movl %edx, oFS(%eax)
+
+ leal oFPREGS(%eax), %ecx
+ /* Save the floating-point context. */
+ fnstenv (%ecx)
+ /* And load it right back since the processor changes the mask.
+ Intel thought this opcode to be used in interrupt handlers which
+ would block all exceptions. */
+ fldenv (%ecx)
+
+ /* Save the current signal mask. */
+ subl $12, %esp
+ cfi_adjust_cfa_offset (12)
+ leal oSIGMASK(%eax), %eax
+ movl %eax, 8(%esp)
+ movl $0, 4(%esp)
+ movl $SIG_BLOCK, (%esp)
+ call HIDDEN_JUMPTARGET (__sigprocmask)
+ addl $12, %esp
+ cfi_adjust_cfa_offset (-12)
+ /* Propagate %eax (and errno, in case). */
+
+ ret
+PSEUDO_END(__getcontext)
+
+weak_alias (__getcontext, getcontext)
diff --git a/sysdeps/mach/hurd/i386/init-first.c b/sysdeps/mach/hurd/i386/init-first.c
index fc355ed6c3..064561a63d 100644
--- a/sysdeps/mach/hurd/i386/init-first.c
+++ b/sysdeps/mach/hurd/i386/init-first.c
@@ -112,32 +112,10 @@ init1 (int argc, char *arg0, ...)
then after the environment pointers there is no Hurd
data block; the argument strings start there. */
if ((void *) d == argv[0])
- {
-#ifndef SHARED
- /* With a new enough linker (binutils-2.23 or better),
- the magic __ehdr_start symbol will be available and
- __libc_start_main will have done this that way already. */
- if (_dl_phdr == NULL)
- {
- /* We may need to see our own phdrs, e.g. for TLS setup.
- Try the usual kludge to find the headers without help from
- the exec server. */
- extern const void __executable_start;
- const ElfW(Ehdr) *const ehdr = &__executable_start;
- _dl_phdr = (const void *) ehdr + ehdr->e_phoff;
- _dl_phnum = ehdr->e_phnum;
- assert (ehdr->e_phentsize == sizeof (ElfW(Phdr)));
- }
-#endif
- return;
- }
+ return;
#ifndef SHARED
__libc_enable_secure = d->flags & EXEC_SECURE;
-
- _dl_phdr = (ElfW(Phdr) *) d->phdr;
- _dl_phnum = d->phdrsz / sizeof (ElfW(Phdr));
- assert (d->phdrsz % sizeof (ElfW(Phdr)) == 0);
#endif
_hurd_init_dtable = d->dtable;
@@ -172,15 +150,6 @@ init (int *data)
char **argv = (void *) (data + 1);
char **envp = &argv[argc + 1];
struct hurd_startup_data *d;
- unsigned long int threadvars[_HURD_THREADVAR_MAX];
-
- /* Provide temporary storage for thread-specific variables on the
- startup stack so the cthreads initialization code can use them
- for malloc et al, or so we can use malloc below for the real
- threadvars array. */
- memset (threadvars, 0, sizeof threadvars);
- threadvars[_HURD_THREADVAR_LOCALE] = (unsigned long int) &_nl_global_locale;
- __hurd_threadvar_stack_offset = (unsigned long int) threadvars;
/* Since the cthreads initialization code uses malloc, and the
malloc initialization code needs to get at the environment, make
@@ -193,12 +162,38 @@ init (int *data)
++envp;
d = (void *) ++envp;
- /* The user might have defined a value for this, to get more variables.
- Otherwise it will be zero on startup. We must make sure it is set
- properly before before cthreads initialization, so cthreads can know
- how much space to leave for thread variables. */
- if (__hurd_threadvar_max < _HURD_THREADVAR_MAX)
- __hurd_threadvar_max = _HURD_THREADVAR_MAX;
+#ifndef SHARED
+ /* If we are the bootstrap task started by the kernel,
+ then after the environment pointers there is no Hurd
+ data block; the argument strings start there. */
+ if ((void *) d == argv[0] || !d->phdr)
+ {
+ /* With a new enough linker (binutils-2.23 or better),
+ the magic __ehdr_start symbol will be available and
+ __libc_start_main will have done this that way already. */
+ if (_dl_phdr == NULL)
+ {
+ /* We may need to see our own phdrs, e.g. for TLS setup.
+ Try the usual kludge to find the headers without help from
+ the exec server. */
+ extern const void __executable_start;
+ const ElfW(Ehdr) *const ehdr = &__executable_start;
+ _dl_phdr = (const void *) ehdr + ehdr->e_phoff;
+ _dl_phnum = ehdr->e_phnum;
+ assert (ehdr->e_phentsize == sizeof (ElfW(Phdr)));
+ }
+ }
+ else
+ {
+ _dl_phdr = (ElfW(Phdr) *) d->phdr;
+ _dl_phnum = d->phdrsz / sizeof (ElfW(Phdr));
+ assert (d->phdrsz % sizeof (ElfW(Phdr)) == 0);
+ }
+
+ /* We need to setup TLS before starting the signal thread. */
+ extern void __pthread_initialize_minimal (void);
+ __pthread_initialize_minimal ();
+#endif
/* After possibly switching stacks, call `init1' (above) with the user
@@ -215,11 +210,6 @@ init (int *data)
__libc_stack_end = newsp;
- /* Copy per-thread variables from that temporary
- area onto the new cthread stack. */
- memcpy (__hurd_threadvar_location_from_sp (0, newsp),
- threadvars, sizeof threadvars);
-
/* Copy the argdata from the old stack to the new one. */
newsp = memcpy (newsp - ((char *) &d[1] - (char *) data), data,
(char *) d - (char *) data);
@@ -260,25 +250,10 @@ init (int *data)
}
else
{
- /* We are not using cthreads, so we will have just a single allocated
- area for the per-thread variables of the main user thread. */
- unsigned long int *array;
- unsigned int i;
int usercode;
void call_init1 (void);
- array = malloc (__hurd_threadvar_max * sizeof (unsigned long int));
- if (array == NULL)
- __libc_fatal ("Can't allocate single-threaded thread variables.");
-
- /* Copy per-thread variables from the temporary array into the
- newly malloc'd space. */
- memcpy (array, threadvars, sizeof threadvars);
- __hurd_threadvar_stack_offset = (unsigned long int) array;
- for (i = _HURD_THREADVAR_MAX; i < __hurd_threadvar_max; ++i)
- array[i] = 0;
-
/* The argument data is just above the stack frame we will unwind by
returning. Mutate our own return address to run the code below. */
/* The following expression would typically be written as
diff --git a/sysdeps/mach/hurd/i386/makecontext-helper.c b/sysdeps/mach/hurd/i386/makecontext-helper.c
new file mode 100644
index 0000000000..c6fb90ca5a
--- /dev/null
+++ b/sysdeps/mach/hurd/i386/makecontext-helper.c
@@ -0,0 +1,71 @@
+/* Helper for makecontext: handle threadvars.
+ Copyright (C) 2013-2015 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <hurd/threadvar.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ucontext.h>
+
+#if 0
+
+void
+__makecontext_helper (ucontext_t *ucp)
+{
+ if (__hurd_threadvar_stack_mask == 0)
+ {
+ /* We are not using threads, so per init-first.c:init, the threadvars
+ live in a malloced space, addressed relative to the base of the
+ virtual address space. Just keep using that one. */
+ }
+ else
+ {
+ /* The following is only prepared to work with libpthread, which only
+ keeps the threadvars at the bottom of the stack -- contrary to
+ libthreads, which also puts additional data there. */
+
+ void *s = ucp->uc_stack.ss_sp;
+ size_t s_size = ucp->uc_stack.ss_size;
+
+ /* Is the new stack suitable? Check that that the last threadvar
+ occupies the last storage unit within the bounds of the new stack.
+ Alignment according to (sp & __hurd_threadvar_stack_mask) == sp is not
+ actually a requirement (though, in practice it often will be). */
+ if (__hurd_threadvar_location_from_sp (_HURD_THREADVAR_MAX, s)
+ != s + s_size)
+ {
+ /* Instead of having makecontext return an error, we bail out the
+ hard way, as we can't expect its caller to be able to properly
+ react to this situation. */
+ fprintf (stderr,
+ "*** makecontext: a stack at %p with size %#x is not "
+ "usable with threadvars\n",
+ s, s_size);
+ abort ();
+ }
+
+ /* Copy the threadvars to the new stack. */
+ void *t_old = __hurd_threadvar_location (0);
+ void *t_new = __hurd_threadvar_location_from_sp (0, s);
+ size_t t_size = __hurd_threadvar_max * sizeof (unsigned long int);
+ memcpy (t_new, t_old, t_size);
+ /* Account for the space taken by the threadvars. */
+ ucp->uc_stack.ss_size -= t_size;
+ }
+}
+#endif
diff --git a/sysdeps/mach/hurd/i386/makecontext.S b/sysdeps/mach/hurd/i386/makecontext.S
new file mode 100644
index 0000000000..95ae3411a8
--- /dev/null
+++ b/sysdeps/mach/hurd/i386/makecontext.S
@@ -0,0 +1,130 @@
+/* Create new context.
+ Copyright (C) 2001-2015 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2001.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+
+#include "ucontext_i.h"
+
+
+ENTRY(__makecontext)
+ movl 4(%esp), %eax
+ subl $4, %esp
+ cfi_adjust_cfa_offset (4)
+ movl %eax, (%esp)
+ /* call HIDDEN_JUMPTARGET (__makecontext_helper) */
+ addl $4, %esp
+ cfi_adjust_cfa_offset (-4)
+
+ movl 4(%esp), %eax
+
+ /* Load the address of the function we are supposed to run. */
+ movl 8(%esp), %ecx
+
+ /* Compute the address of the stack. The information comes from
+ to us_stack element. */
+ movl oSS_SP(%eax), %edx
+ movl %ecx, oEIP(%eax)
+ addl oSS_SIZE(%eax), %edx
+
+ /* Remember the number of parameters for the exit handler since
+ it has to remove them. We store the number in the EBX register
+ which the function we will call must preserve. */
+ movl 12(%esp), %ecx
+ movl %ecx, oEBX(%eax)
+
+ /* Make room on the new stack for the parameters.
+ Room for the arguments, return address (== L(exitcode)) and
+ oLINK pointer is needed. One of the pointer sizes is subtracted
+ after aligning the stack. */
+ negl %ecx
+ leal -4(%edx,%ecx,4), %edx
+ negl %ecx
+
+ /* Align the stack. */
+ andl $0xfffffff0, %edx
+ subl $4, %edx
+
+ /* Store the future stack pointer. */
+ movl %edx, oESP(%eax)
+
+ /* Put the next context on the new stack (from the uc_link
+ element). */
+ movl oLINK(%eax), %eax
+ movl %eax, 4(%edx,%ecx,4)
+
+ /* Copy all the parameters. */
+ jecxz 2f
+1: movl 12(%esp,%ecx,4), %eax
+ movl %eax, (%edx,%ecx,4)
+ decl %ecx
+ jnz 1b
+2:
+
+ /* If the function we call returns we must continue with the
+ context which is given in the uc_link element. To do this
+ set the return address for the function the user provides
+ to a little bit of helper code which does the magic (see
+ below). */
+#ifdef PIC
+ call 1f
+ cfi_adjust_cfa_offset (4)
+1: popl %ecx
+ cfi_adjust_cfa_offset (-4)
+ addl $L(exitcode)-1b, %ecx
+ movl %ecx, (%edx)
+#else
+ movl $L(exitcode), (%edx)
+#endif
+ /* 'makecontext' returns no value. */
+ ret
+
+ /* This is the helper code which gets called if a function which
+ is registered with 'makecontext' returns. In this case we
+ have to install the context listed in the uc_link element of
+ the context 'makecontext' manipulated at the time of the
+ 'makecontext' call. If the pointer is NULL the process must
+ terminate. */
+ cfi_endproc
+L(exitcode):
+ /* This removes the parameters passed to the function given to
+ 'makecontext' from the stack. EBX contains the number of
+ parameters (see above). */
+ leal (%esp,%ebx,4), %esp
+
+#ifdef PIC
+ call 1f
+1: popl %ebx
+ addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ebx
+#endif
+ cmpl $0, (%esp) /* Check the next context. */
+ je 2f /* If it is zero exit. */
+
+ call JUMPTARGET(__setcontext)
+ /* If this returns (which can happen if the syscall fails) we'll
+ exit the program with the return error value (-1). */
+
+ movl %eax, (%esp)
+2: call HIDDEN_JUMPTARGET(exit)
+ /* The 'exit' call should never return. In case it does cause
+ the process to terminate. */
+ hlt
+ cfi_startproc
+END(__makecontext)
+
+weak_alias (__makecontext, makecontext)
diff --git a/sysdeps/mach/hurd/i386/setcontext.S b/sysdeps/mach/hurd/i386/setcontext.S
new file mode 100644
index 0000000000..3f38ff2018
--- /dev/null
+++ b/sysdeps/mach/hurd/i386/setcontext.S
@@ -0,0 +1,92 @@
+/* Install given context.
+ Copyright (C) 2001-2015 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2001.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+
+#include "ucontext_i.h"
+
+
+ENTRY(__setcontext)
+ /* Load address of the context data structure. */
+ movl 4(%esp), %eax
+
+ /* Get the current signal mask. */
+ subl $12, %esp
+ cfi_adjust_cfa_offset (12)
+ movl $0, 8(%esp)
+ leal oSIGMASK(%eax), %eax
+ movl %eax, 4(%esp)
+ movl $SIG_SETMASK, (%esp)
+ call HIDDEN_JUMPTARGET (__sigprocmask)
+ addl $12, %esp
+ cfi_adjust_cfa_offset (-12)
+ testl %eax, %eax
+ jne L(pseudo_end)
+
+ /* EAX was modified, reload it. */
+ movl 4(%esp), %eax
+
+ /* Restore the floating-point context. Not the registers, only the
+ rest. */
+ leal oFPREGS(%eax), %ecx
+ fldenv (%ecx)
+
+ /* Restore the FS segment register. We don't touch the GS register
+ since it is used for threads. */
+ movl oFS(%eax), %ecx
+ movw %cx, %fs
+
+ /* Fetch the address to return to. */
+ movl oEIP(%eax), %ecx
+
+ /* Load the new stack pointer. */
+ cfi_def_cfa (eax, 0)
+ cfi_offset (edi, oEDI)
+ cfi_offset (esi, oESI)
+ cfi_offset (ebp, oEBP)
+ cfi_offset (ebx, oEBX)
+ cfi_offset (edx, oEDX)
+ cfi_offset (ecx, oECX)
+ movl oESP(%eax), %esp
+
+ /* Push the return address on the new stack so we can return there. */
+ pushl %ecx
+
+ /* Load the values of all the 32-bit registers (except ESP).
+ Since we are loading from EAX, it must be last. */
+ movl oEDI(%eax), %edi
+ movl oESI(%eax), %esi
+ movl oEBP(%eax), %ebp
+ movl oEBX(%eax), %ebx
+ movl oEDX(%eax), %edx
+ movl oECX(%eax), %ecx
+ movl oEAX(%eax), %eax
+
+ /* End FDE here, we fall into another context. */
+ cfi_endproc
+ cfi_startproc
+
+ /* The following 'ret' will pop the address of the code and jump
+ to it. */
+
+L(pseudo_end):
+ ret
+PSEUDO_END(__setcontext)
+
+weak_alias (__setcontext, setcontext)
diff --git a/sysdeps/mach/hurd/i386/sigreturn.c b/sysdeps/mach/hurd/i386/sigreturn.c
index 6dba161d7c..8776cca896 100644
--- a/sysdeps/mach/hurd/i386/sigreturn.c
+++ b/sysdeps/mach/hurd/i386/sigreturn.c
@@ -38,7 +38,7 @@ __sigreturn (struct sigcontext *scp)
}
ss = _hurd_self_sigstate ();
- __spin_lock (&ss->lock);
+ _hurd_sigstate_lock (ss);
/* Remove the link on the `active resources' chain added by
_hurd_setup_sighandler. Its purpose was to make sure
@@ -50,35 +50,34 @@ __sigreturn (struct sigcontext *scp)
ss->intr_port = scp->sc_intr_port;
/* Check for pending signals that were blocked by the old set. */
- if (ss->pending & ~ss->blocked)
+ if (_hurd_sigstate_pending (ss) & ~ss->blocked)
{
/* There are pending signals that just became unblocked. Wake up the
signal thread to deliver them. But first, squirrel away SCP where
the signal thread will notice it if it runs another handler, and
arrange to have us called over again in the new reality. */
ss->context = scp;
- __spin_unlock (&ss->lock);
+ _hurd_sigstate_unlock (ss);
__msg_sig_post (_hurd_msgport, 0, 0, __mach_task_self ());
/* If a pending signal was handled, sig_post never returned.
If it did return, the pending signal didn't run a handler;
proceed as usual. */
- __spin_lock (&ss->lock);
+ _hurd_sigstate_lock (ss);
ss->context = NULL;
}
if (scp->sc_onstack)
{
- ss->sigaltstack.ss_flags &= ~SS_ONSTACK; /* XXX threadvars */
+ ss->sigaltstack.ss_flags &= ~SS_ONSTACK;
/* XXX cannot unlock until off sigstack */
abort ();
}
else
- __spin_unlock (&ss->lock);
+ _hurd_sigstate_unlock (ss);
/* Destroy the MiG reply port used by the signal handler, and restore the
reply port in use by the thread when interrupted. */
- reply_port =
- (mach_port_t *) __hurd_threadvar_location (_HURD_THREADVAR_MIG_REPLY);
+ reply_port = &__hurd_local_reply_port;
if (*reply_port)
{
mach_port_t port = *reply_port;
diff --git a/sysdeps/mach/hurd/i386/swapcontext.S b/sysdeps/mach/hurd/i386/swapcontext.S
new file mode 100644
index 0000000000..5a35eaa56b
--- /dev/null
+++ b/sysdeps/mach/hurd/i386/swapcontext.S
@@ -0,0 +1,110 @@
+/* Save current context and install the given one.
+ Copyright (C) 2001-2015 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2001.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+
+#include "ucontext_i.h"
+
+
+ENTRY(__swapcontext)
+ /* Load address of the context data structure we save in. */
+ movl 4(%esp), %eax
+
+ /* Return value of swapcontext. EAX is the only register whose
+ value is not preserved. */
+ movl $0, oEAX(%eax)
+
+ /* Save the 32-bit register values and the return address. */
+ movl %ecx, oECX(%eax)
+ movl %edx, oEDX(%eax)
+ movl %edi, oEDI(%eax)
+ movl %esi, oESI(%eax)
+ movl %ebp, oEBP(%eax)
+ movl (%esp), %ecx
+ movl %ecx, oEIP(%eax)
+ leal 4(%esp), %ecx
+ movl %ecx, oESP(%eax)
+ movl %ebx, oEBX(%eax)
+
+ /* Save the FS segment register. */
+ xorl %edx, %edx
+ movw %fs, %dx
+ movl %edx, oFS(%eax)
+
+ leal oFPREGS(%eax), %ecx
+ /* Save the floating-point context. */
+ fnstenv (%ecx)
+
+ /* Load address of the context data structure we have to load. */
+ movl 8(%esp), %ecx
+
+ /* Save the current signal mask and install the new one. */
+ subl $12, %esp
+ cfi_adjust_cfa_offset (12)
+ leal oSIGMASK(%eax), %eax
+ movl %eax, 8(%esp)
+ leal oSIGMASK(%ecx), %eax
+ movl %eax, 4(%esp)
+ movl $SIG_SETMASK, (%esp)
+ call HIDDEN_JUMPTARGET (__sigprocmask)
+ addl $12, %esp
+ cfi_adjust_cfa_offset (-12)
+ testl %eax, %eax
+ jne L(pseudo_end)
+
+ /* EAX was modified, reload it. */
+ movl 8(%esp), %eax
+
+ /* Restore the floating-point context. Not the registers, only the
+ rest. */
+ leal oFPREGS(%eax), %ecx
+ fldenv (%ecx)
+
+ /* Restore the FS segment register. We don't touch the GS register
+ since it is used for threads. */
+ movl oFS(%eax), %edx
+ movw %dx, %fs
+
+ /* Fetch the address to return to. */
+ movl oEIP(%eax), %ecx
+
+ /* Load the new stack pointer. */
+ movl oESP(%eax), %esp
+
+ /* Push the return address on the new stack so we can return there. */
+ pushl %ecx
+
+ /* Load the values of all the 32-bit registers (except ESP).
+ Since we are loading from EAX, it must be last. */
+ movl oEDI(%eax), %edi
+ movl oESI(%eax), %esi
+ movl oEBP(%eax), %ebp
+ movl oEBX(%eax), %ebx
+ movl oEDX(%eax), %edx
+ movl oECX(%eax), %ecx
+ movl oEAX(%eax), %eax
+
+ /* The following 'ret' will pop the address of the code and jump
+ to it. */
+
+L(pseudo_end):
+ ret
+PSEUDO_END(__swapcontext)
+
+weak_alias (__swapcontext, swapcontext)
diff --git a/sysdeps/mach/hurd/i386/tls.h b/sysdeps/mach/hurd/i386/tls.h
index 3f84300206..00b611e903 100644
--- a/sysdeps/mach/hurd/i386/tls.h
+++ b/sysdeps/mach/hurd/i386/tls.h
@@ -23,6 +23,44 @@
/* Some things really need not be machine-dependent. */
#include <sysdeps/mach/hurd/tls.h>
+
+#ifndef __ASSEMBLER__
+/* Type for the dtv. */
+typedef union dtv
+{
+ size_t counter;
+ struct
+ {
+ void *val;
+ bool is_static;
+ } pointer;
+} dtv_t;
+
+
+/* Type of the TCB. */
+typedef struct
+{
+ void *tcb; /* Points to this structure. */
+ dtv_t *dtv; /* Vector of pointers to TLS data. */
+ thread_t self; /* This thread's control port. */
+ int multiple_threads;
+ uintptr_t sysinfo;
+ uintptr_t stack_guard;
+ uintptr_t pointer_guard;
+ int gscope_flag;
+ int private_futex;
+ /* Reservation of some values for the TM ABI. */
+ void *__private_tm[4];
+ /* GCC split stack support. */
+ void *__private_ss;
+
+ /* Keep this field last */
+ mach_port_t reply_port; /* This thread's reply port. */
+ struct hurd_sigstate *_hurd_sigstate;
+} tcbhead_t;
+#endif
+
+
/* The TCB can have any size and the memory following the address the
thread pointer points to is unspecified. Allocate the TCB there. */
#define TLS_TCB_AT_TP 1
@@ -37,6 +75,8 @@
# define __i386_set_gdt(thr, sel, desc) ((void) (thr), (void) (sel), (void) (desc), MIG_BAD_ID)
# endif
+#define __i386_selector_is_ldt(sel) (!!((sel) & 4))
+
# include <errno.h>
# include <assert.h>
@@ -53,11 +93,24 @@
| (((unsigned int) (tcb)) & 0xff000000) /* base 24..31 */ \
}
+# define HURD_DESC_TLS(desc) \
+ ({ \
+ (tcbhead_t *) ( (desc->low_word >> 16) \
+ | ((desc->high_word & 0xff) << 16) \
+ | (desc->high_word & 0xff000000) \
+ );})
+
+#define __LIBC_NO_TLS() \
+ ({ unsigned short ds, gs; \
+ asm ("movw %%ds,%w0; movw %%gs,%w1" : "=q" (ds), "=q" (gs)); \
+ ds == gs; })
static inline const char * __attribute__ ((unused))
_hurd_tls_init (tcbhead_t *tcb, int secondcall)
{
HURD_TLS_DESC_DECL (desc, tcb);
+ thread_t self = __mach_thread_self ();
+ const char *msg = NULL;
if (!secondcall)
{
@@ -65,25 +118,26 @@ _hurd_tls_init (tcbhead_t *tcb, int secondcall)
from the TLS point of view. */
tcb->tcb = tcb;
- /* Cache our thread port. */
- tcb->self = __mach_thread_self ();
-
/* Get the first available selector. */
int sel = -1;
- error_t err = __i386_set_gdt (tcb->self, &sel, desc);
+ kern_return_t err = __i386_set_gdt (self, &sel, desc);
if (err == MIG_BAD_ID)
{
/* Old kernel, use a per-thread LDT. */
sel = 0x27;
- err = __i386_set_ldt (tcb->self, sel, &desc, 1);
+ err = __i386_set_ldt (self, sel, &desc, 1);
assert_perror (err);
if (err)
- return "i386_set_ldt failed";
+ {
+ msg = "i386_set_ldt failed";
+ goto out;
+ }
}
else if (err)
{
assert_perror (err); /* Separate from above with different line #. */
- return "i386_set_gdt failed";
+ msg = "i386_set_gdt failed";
+ goto out;
}
/* Now install the new selector. */
@@ -94,23 +148,31 @@ _hurd_tls_init (tcbhead_t *tcb, int secondcall)
/* Fetch the selector set by the first call. */
int sel;
asm ("mov %%gs, %w0" : "=q" (sel) : "0" (0));
- if (__builtin_expect (sel, 0x50) & 4) /* LDT selector */
+ if (__glibc_unlikely (__i386_selector_is_ldt(sel)))
{
- error_t err = __i386_set_ldt (tcb->self, sel, &desc, 1);
+ kern_return_t err = __i386_set_ldt (self, sel, &desc, 1);
assert_perror (err);
if (err)
- return "i386_set_ldt failed";
+ {
+ msg = "i386_set_ldt failed";
+ goto out;
+ }
}
else
{
- error_t err = __i386_set_gdt (tcb->self, &sel, desc);
+ kern_return_t err = __i386_set_gdt (self, &sel, desc);
assert_perror (err);
if (err)
- return "i386_set_gdt failed";
+ {
+ msg = "i386_set_gdt failed";
+ goto out;
+ }
}
}
- return 0;
+out:
+ __mach_port_deallocate (__mach_task_self (), self);
+ return msg;
}
/* Code to initially initialize the thread pointer. This might need
@@ -126,6 +188,20 @@ _hurd_tls_init (tcbhead_t *tcb, int secondcall)
: "i" (offsetof (tcbhead_t, tcb))); \
__tcb;})
+/* Return the TCB address of a thread given its state. */
+# define THREAD_TCB(thread, thread_state) \
+ ({ int __sel = (thread_state)->basic.gs; \
+ struct descriptor __desc, *___desc = &__desc; \
+ unsigned int __count = 1; \
+ kern_return_t __err; \
+ if (__builtin_expect (__sel, 0x48) & 4) /* LDT selector */ \
+ __err = __i386_get_ldt ((thread), __sel, 1, &___desc, &__count); \
+ else \
+ __err = __i386_get_gdt ((thread), __sel, &__desc); \
+ assert_perror (__err); \
+ assert (__count == 1); \
+ HURD_DESC_TLS(___desc);})
+
/* Install new dtv for current thread. */
# define INSTALL_NEW_DTV(dtvp) \
({ asm volatile ("movl %0,%%gs:%P1" \
@@ -139,9 +215,40 @@ _hurd_tls_init (tcbhead_t *tcb, int secondcall)
# include <mach/machine/thread_status.h>
-/* Set up TLS in the new thread of a fork child, copying from our own. */
-static inline error_t __attribute__ ((unused))
-_hurd_tls_fork (thread_t child, struct i386_thread_state *state)
+/* Set up TLS in the new thread of a fork child, copying from the original. */
+static inline kern_return_t __attribute__ ((unused))
+_hurd_tls_fork (thread_t child, thread_t orig, struct i386_thread_state *state)
+{
+ /* Fetch the selector set by _hurd_tls_init. */
+ int sel;
+ asm ("mov %%gs, %w0" : "=q" (sel) : "0" (0));
+ if (sel == state->ds) /* _hurd_tls_init was never called. */
+ return 0;
+
+ struct descriptor desc, *_desc = &desc;
+ kern_return_t err;
+ unsigned int count = 1;
+
+ if (__glibc_unlikely (__i386_selector_is_ldt(sel)))
+ err = __i386_get_ldt (orig, sel, 1, &_desc, &count);
+ else
+ err = __i386_get_gdt (orig, sel, &desc);
+
+ assert_perror (err);
+ if (err)
+ return err;
+
+ if (__glibc_unlikely (__i386_selector_is_ldt(sel)))
+ err = __i386_set_ldt (child, sel, &desc, 1);
+ else
+ err = __i386_set_gdt (child, &sel, desc);
+
+ state->gs = sel;
+ return err;
+}
+
+static inline kern_return_t __attribute__ ((unused))
+_hurd_tls_new (thread_t child, struct i386_thread_state *state, tcbhead_t *tcb)
{
/* Fetch the selector set by _hurd_tls_init. */
int sel;
@@ -149,11 +256,13 @@ _hurd_tls_fork (thread_t child, struct i386_thread_state *state)
if (sel == state->ds) /* _hurd_tls_init was never called. */
return 0;
- tcbhead_t *const tcb = THREAD_SELF;
HURD_TLS_DESC_DECL (desc, tcb);
- error_t err;
+ kern_return_t err;
+
+ tcb->tcb = tcb;
+ tcb->self = child;
- if (__builtin_expect (sel, 0x50) & 4) /* LDT selector */
+ if (__glibc_unlikely (__i386_selector_is_ldt(sel)))
err = __i386_set_ldt (child, sel, &desc, 1);
else
err = __i386_set_gdt (child, &sel, desc);
diff --git a/sysdeps/mach/hurd/i386/tlsdesc.sym b/sysdeps/mach/hurd/i386/tlsdesc.sym
new file mode 100644
index 0000000000..a358f7e325
--- /dev/null
+++ b/sysdeps/mach/hurd/i386/tlsdesc.sym
@@ -0,0 +1,19 @@
+#include <stddef.h>
+#include <sysdep.h>
+#include <tls.h>
+#include <link.h>
+#include <dl-tlsdesc.h>
+
+--
+
+-- We have to override sysdeps/i386/tlsdesc.sym to adapt to our libpthread.
+
+-- Abuse tls.h macros to derive offsets relative to the thread register.
+
+DTV_OFFSET offsetof(tcbhead_t, dtv)
+
+TLSDESC_ARG offsetof(struct tlsdesc, arg)
+
+TLSDESC_GEN_COUNT offsetof(struct tlsdesc_dynamic_arg, gen_count)
+TLSDESC_MODID offsetof(struct tlsdesc_dynamic_arg, tlsinfo.ti_module)
+TLSDESC_MODOFF offsetof(struct tlsdesc_dynamic_arg, tlsinfo.ti_offset)
diff --git a/sysdeps/mach/hurd/i386/trampoline.c b/sysdeps/mach/hurd/i386/trampoline.c
index d4a839304b..0b1f07234b 100644
--- a/sysdeps/mach/hurd/i386/trampoline.c
+++ b/sysdeps/mach/hurd/i386/trampoline.c
@@ -19,13 +19,66 @@
#include <hurd/signal.h>
#include <hurd/userlink.h>
#include <thread_state.h>
+#include <mach/exception.h>
#include <mach/machine/eflags.h>
#include <assert.h>
#include <errno.h>
#include "hurdfault.h"
#include <intr-msg.h>
+#include <sys/ucontext.h>
+/* Fill in a siginfo_t structure for SA_SIGINFO-enabled handlers. */
+static void fill_siginfo (siginfo_t *si, int signo,
+ const struct hurd_signal_detail *detail,
+ const struct machine_thread_all_state *state)
+{
+ si->si_signo = signo;
+ si->si_errno = detail->error;
+ si->si_code = detail->code;
+
+ /* XXX We would need a protocol change for sig_post to include
+ * this information. */
+ si->si_pid = -1;
+ si->si_uid = -1;
+
+ /* Address of the faulting instruction or memory access. */
+ if (detail->exc == EXC_BAD_ACCESS)
+ si->si_addr = (void *) detail->exc_subcode;
+ else
+ si->si_addr = (void *) state->basic.eip;
+
+ /* XXX On SIGCHLD, this should be the exit status of the child
+ * process. We would need a protocol change for the proc server
+ * to send this information along with the signal. */
+ si->si_status = 0;
+
+ si->si_band = 0; /* SIGPOLL is not supported yet. */
+ si->si_value.sival_int = 0; /* sigqueue() is not supported yet. */
+}
+
+/* Fill in a ucontext_t structure SA_SIGINFO-enabled handlers. */
+static void fill_ucontext (ucontext_t *uc, const struct sigcontext *sc)
+{
+ uc->uc_flags = 0;
+ uc->uc_link = NULL;
+ uc->uc_sigmask = sc->sc_mask;
+ uc->uc_stack.ss_sp = (__ptr_t) sc->sc_esp;
+ uc->uc_stack.ss_size = 0;
+ uc->uc_stack.ss_flags = 0;
+
+ /* Registers. */
+ memcpy (&uc->uc_mcontext.gregs[REG_GS], &sc->sc_gs,
+ (REG_TRAPNO - REG_GS) * sizeof (int));
+ uc->uc_mcontext.gregs[REG_TRAPNO] = 0;
+ uc->uc_mcontext.gregs[REG_ERR] = 0;
+ memcpy (&uc->uc_mcontext.gregs[REG_EIP], &sc->sc_eip,
+ (NGREG - REG_EIP) * sizeof (int));
+
+ /* XXX FPU state. */
+ memset (&uc->uc_mcontext.fpregs, 0, sizeof (fpregset_t));
+}
+
struct sigcontext *
_hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
int signo, struct hurd_signal_detail *detail,
@@ -38,18 +91,37 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
extern const void _hurd_intr_rpc_msg_in_trap;
extern const void _hurd_intr_rpc_msg_cx_sp;
extern const void _hurd_intr_rpc_msg_sp_restored;
+ struct sigaction *action;
void *volatile sigsp;
struct sigcontext *scp;
struct
{
int signo;
- long int sigcode;
- struct sigcontext *scp; /* Points to ctx, below. */
+ union
+ {
+ /* Extra arguments for traditional signal handlers */
+ struct
+ {
+ long int sigcode;
+ struct sigcontext *scp; /* Points to ctx, below. */
+ } legacy;
+
+ /* Extra arguments for SA_SIGINFO handlers */
+ struct
+ {
+ siginfo_t *siginfop; /* Points to siginfo, below. */
+ ucontext_t *uctxp; /* Points to uctx, below. */
+ } posix;
+ };
void *sigreturn_addr;
void *sigreturn_returns_here;
struct sigcontext *return_scp; /* Same; arg to sigreturn. */
+
+ /* NB: sigreturn assumes link is next to ctx. */
struct sigcontext ctx;
struct hurd_userlink link;
+ ucontext_t ucontext;
+ siginfo_t siginfo;
} *stackframe;
if (ss->context)
@@ -63,7 +135,7 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
sizeof (state->basic));
memcpy (&state->fpu, &ss->context->sc_i386_float_state,
sizeof (state->fpu));
- state->set |= (1 << i386_THREAD_STATE) | (1 << i386_FLOAT_STATE);
+ state->set |= (1 << i386_REGS_SEGS_STATE) | (1 << i386_FLOAT_STATE);
}
}
@@ -75,7 +147,11 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
interrupted RPC frame. */
state->basic.esp = state->basic.uesp;
- if ((ss->actions[signo].sa_flags & SA_ONSTACK) &&
+ /* XXX what if handler != action->handler (for instance, if a signal
+ * preemptor took over) ? */
+ action = & _hurd_sigstate_actions (ss) [signo];
+
+ if ((action->sa_flags & SA_ONSTACK) &&
!(ss->sigaltstack.ss_flags & (SS_DISABLE|SS_ONSTACK)))
{
sigsp = ss->sigaltstack.ss_sp + ss->sigaltstack.ss_size;
@@ -137,15 +213,9 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
= &stackframe->link.thread.next;
ss->active_resources = &stackframe->link;
- /* Set up the arguments for the signal handler. */
- stackframe->signo = signo;
- stackframe->sigcode = detail->code;
- stackframe->scp = stackframe->return_scp = scp = &stackframe->ctx;
- stackframe->sigreturn_addr = &__sigreturn;
- stackframe->sigreturn_returns_here = firewall; /* Crash on return. */
-
/* Set up the sigcontext from the current state of the thread. */
+ scp = &stackframe->ctx;
scp->sc_onstack = ss->sigaltstack.ss_flags & SS_ONSTACK ? 1 : 0;
/* struct sigcontext is laid out so that starting at sc_gs mimics a
@@ -159,6 +229,35 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
&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)
diff --git a/sysdeps/mach/hurd/i386/ucontext_i.sym b/sysdeps/mach/hurd/i386/ucontext_i.sym
new file mode 100644
index 0000000000..cc1cfd578d
--- /dev/null
+++ b/sysdeps/mach/hurd/i386/ucontext_i.sym
@@ -0,0 +1,29 @@
+#include <stddef.h>
+#include <signal.h>
+#include <sys/ucontext.h>
+
+--
+
+SIG_BLOCK
+SIG_SETMASK
+
+#define ucontext(member) offsetof (ucontext_t, member)
+#define mcontext(member) ucontext (uc_mcontext.member)
+#define mreg(reg) mcontext (gregs[REG_##reg])
+
+oLINK ucontext (uc_link)
+oSS_SP ucontext (uc_stack.ss_sp)
+oSS_SIZE ucontext (uc_stack.ss_size)
+oGS mreg (GS)
+oFS mreg (FS)
+oEDI mreg (EDI)
+oESI mreg (ESI)
+oEBP mreg (EBP)
+oESP mreg (ESP)
+oEBX mreg (EBX)
+oEDX mreg (EDX)
+oECX mreg (ECX)
+oEAX mreg (EAX)
+oEIP mreg (EIP)
+oFPREGS mcontext (fpregs)
+oSIGMASK ucontext (uc_sigmask)