bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: struct sigcontext in Hurd/x86_64


From: Sergey Bugaev
Subject: Re: struct sigcontext in Hurd/x86_64
Date: Sun, 14 May 2023 18:05:09 +0300

On Sun, May 14, 2023 at 5:11 PM Bruno Haible <bruno@clisp.org> wrote:
> But another thing appears to be wrong: The role of sc_rsp versus sc_ursp
> in glibc/sysdeps/mach/hurd/x86_64/bits/sigcontext.h.
>
> What glibc/sysdeps/mach/hurd/x86/trampoline.c does for x86_64 is:
>
> _hurd_setup_sighandler (...)
> {
> ...
>   state->basic.rsp = state->basic.ursp;
> ...
>   sigsp = <appropriate new stack pointer for invoking the signal handler>;
> ...
>   /* Push the arguments to call `trampoline' on the stack.  */
>   sigsp -= sizeof (*stackframe);
> ...
>       state->basic.ursp = (uintptr_t) sigsp;
> ...
> }
>
> But glibc/sysdeps/mach/hurd/x86_64/bits/sigcontext.h has these comments:
>
> struct sigcontext
>   {
> ...
>     long sc_rsp;                /* Not used; sc_ursp is used instead.  */
> ...
>     long sc_ursp;               /* This stack pointer is used.  */

Notice that it's state->basic.{rsp,ursp} being modified, not the
sigcontext structure (ctx / scp) passed to the handler (and to
sigreturn). state->basic is the Mach i386_thread_state structure; the
signal handling machinery first initializes it using thread_get_state
()) to describe the state that the thread had at the time it was
interrupted. It then initializes the sigcontext based on this state
(memcpy'ing from state->basic), and then mutates state->basic to point
%rip to the trampoline, %rsp to sigsp, etc., and then uses this same
state->basic structure in a thread_set_state () call to apply the new
state, to set the thread off to run the handler. But these
modifications never reach the struct sigcontext, which still
represents the state of the thread when it was interrupted.

Moreover, in practice both sc_rsp and sc_ursp will have the same
value, because of the 'state->basic.rsp = state->basic.ursp;' line
(which is the only change to state->basic done before memcpying it
onto the sigcontext).

Here's what this looks like in practice, on i686-gnu:

$ uname -a
GNU hurdle 0.9 GNU-Mach 1.8+git20230410-486/Hurd-0.9 i686-AT386 GNU
$ ./scp-demo
Set sigaltstack to 0x200019c0
Current esp is 0x1037d48
Caught a signal, my esp is 0x2000169c
sc->sc_uesp = 0x1037b6c, sc->sc_esp = 0x1037b6c

scp-demo.c source:

#define _GNU_SOURCE 1

#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <error.h>
#include <errno.h>
#include <stdint.h>

#define esp \
  ({ \
     void *__esp; \
     asm ("mov %%esp, %0" : "=rm" (__esp)); \
     __esp; \
   })

void
handler (int signo, long int sigcode, struct sigcontext *sc)
{
  /* We're not allowed to call printf from inside the signal handler,
     but it's fine for the sake of the demo.  */
  printf ("Caught a signal, my esp is %p\n", esp);
  printf ("sc->sc_uesp = %p, sc->sc_esp = %p\n", sc->sc_uesp, sc->sc_esp);
}

int
main ()
{
  stack_t stack;
  struct sigaction sa;

  stack.ss_size = 4096;
  stack.ss_sp = malloc (stack.ss_size);
  stack.ss_flags = 0;

  if (sigaltstack (&stack, NULL) < 0)
    error (1, errno, "sigaltstack");

  memset (&sa, 0, sizeof (sa));
  sa.sa_handler = handler;
  sa.sa_flags = SA_ONSTACK;  /* not SA_SIGINFO */

  if (sigaction (SIGUSR1, &sa, NULL) < 0)
    error (1, errno, "sigaction");

  /* The stack grows down.  */
  printf ("Set sigaltstack to %p\n", stack.ss_sp + stack.ss_size);
  printf ("Current esp is %p\n", esp);

  raise (SIGUSR1);
}

I hope this makes sense, and I'd be happy to answer more questions :)

Sergey



reply via email to

[Prev in Thread] Current Thread [Next in Thread]