diff mbox series

Hurd x86_64: add unwind support for signal trampoline code

Message ID ZeABDXA82kA3UvEJ@mars.tail36e24.ts.net
State New
Headers show
Series Hurd x86_64: add unwind support for signal trampoline code | expand

Commit Message

Flavio Cruz Feb. 29, 2024, 3:59 a.m. UTC
Tested with some simple toy examples where an exception is thrown in the
signal handler.

libgcc/ChangeLog:
	* config/i386/gnu-unwind.h: Support unwinding x86_64 signal frames.

Signed-off-by: Flavio Cruz <flaviocruz@gmail.com>
---
 libgcc/config/i386/gnu-unwind.h | 97 ++++++++++++++++++++++++++++++++-
 1 file changed, 94 insertions(+), 3 deletions(-)

Comments

Samuel Thibault March 1, 2024, 1:33 a.m. UTC | #1
Flavio Cruz, le mer. 28 févr. 2024 22:59:09 -0500, a ecrit:
> Tested with some simple toy examples where an exception is thrown in the
> signal handler.
> 
> libgcc/ChangeLog:
> 	* config/i386/gnu-unwind.h: Support unwinding x86_64 signal frames.
> 
> Signed-off-by: Flavio Cruz <flaviocruz@gmail.com>

Reviewed-by: Samuel Thibault <samuel.thibault@ens-lyon.org>

Thanks!!

> ---
>  libgcc/config/i386/gnu-unwind.h | 97 ++++++++++++++++++++++++++++++++-
>  1 file changed, 94 insertions(+), 3 deletions(-)
> 
> diff --git a/libgcc/config/i386/gnu-unwind.h b/libgcc/config/i386/gnu-unwind.h
> index 0751b5593d4..02b060ab4a5 100644
> --- a/libgcc/config/i386/gnu-unwind.h
> +++ b/libgcc/config/i386/gnu-unwind.h
> @@ -32,9 +32,100 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
>  
>  #ifdef __x86_64__
>  
> -/*
> - * TODO: support for 64 bits needs to be implemented.
> - */
> +#define MD_FALLBACK_FRAME_STATE_FOR x86_gnu_fallback_frame_state
> +
> +static _Unwind_Reason_Code
> +x86_gnu_fallback_frame_state
> +(struct _Unwind_Context *context, _Unwind_FrameState *fs)
> +{
> +  static const unsigned char gnu_sigtramp_code[] =
> +  {
> +    /* rpc_wait_trampoline: */
> +    0x48, 0xc7, 0xc0, 0xe7, 0xff, 0xff, 0xff,    /* mov    $-25,%rax */
> +    0x0f, 0x05,                                  /* syscall */
> +    0x49, 0x89, 0x04, 0x24,                      /* mov    %rax,(%r12) */
> +    0x48, 0x89, 0xdc,                            /* mov    %rbx,%rsp */
> +
> +    /* trampoline: */
> +    0x5f,                                        /* pop    %rdi */
> +    0x5e,                                        /* pop    %rsi */
> +    0x5a,                                        /* pop    %rdx */
> +    0x48, 0x83, 0xc4, 0x08,                      /* add    $0x8,%rsp */
> +    0x41, 0xff, 0xd5,                            /* call   *%r13 */
> +
> +    /* RA HERE */
> +    0x48, 0x8b, 0x7c, 0x24, 0x10,                /* mov    0x10(%rsp),%rdi */
> +    0xc3,                                        /* ret */
> +
> +    /* firewall: */
> +    0xf4,                                        /* hlt */
> +  };
> +
> +  const size_t gnu_sigtramp_len = sizeof gnu_sigtramp_code;
> +  const size_t gnu_sigtramp_tail = 7; /* length of tail after RA */
> +
> +  struct stack_contents {
> +    void *sigreturn_addr;
> +    void *sigreturn_returns_here;
> +    struct sigcontext *return_scp;
> +  } *stack_contents;
> +  struct sigcontext *scp;
> +  unsigned long usp;
> +
> +  unsigned char *adjusted_pc = (unsigned char*)(context->ra) +
> +    gnu_sigtramp_tail - gnu_sigtramp_len;
> +  if (memcmp (adjusted_pc, gnu_sigtramp_code, gnu_sigtramp_len))
> +    return _URC_END_OF_STACK;
> +
> +  stack_contents = context->cfa;
> +
> +  scp = stack_contents->return_scp;
> +  usp = scp->sc_ursp;
> +
> +  fs->regs.reg[0].loc.offset = (unsigned long)&scp->sc_rax - usp;
> +  fs->regs.reg[1].loc.offset = (unsigned long)&scp->sc_rdx - usp;
> +  fs->regs.reg[2].loc.offset = (unsigned long)&scp->sc_rcx - usp;
> +  fs->regs.reg[3].loc.offset = (unsigned long)&scp->sc_rbx - usp;
> +  fs->regs.reg[4].loc.offset = (unsigned long)&scp->sc_rsi - usp;
> +  fs->regs.reg[5].loc.offset = (unsigned long)&scp->sc_rdi - usp;
> +  fs->regs.reg[6].loc.offset = (unsigned long)&scp->sc_rbp - usp;
> +  fs->regs.reg[8].loc.offset = (unsigned long)&scp->sc_r8 - usp;
> +  fs->regs.reg[9].loc.offset = (unsigned long)&scp->sc_r9 - usp;
> +  fs->regs.reg[10].loc.offset = (unsigned long)&scp->sc_r10 - usp;
> +  fs->regs.reg[11].loc.offset = (unsigned long)&scp->sc_r11 - usp;
> +  fs->regs.reg[12].loc.offset = (unsigned long)&scp->sc_r12 - usp;
> +  fs->regs.reg[13].loc.offset = (unsigned long)&scp->sc_r13 - usp;
> +  fs->regs.reg[14].loc.offset = (unsigned long)&scp->sc_r14 - usp;
> +  fs->regs.reg[15].loc.offset = (unsigned long)&scp->sc_r15 - usp;
> +  fs->regs.reg[16].loc.offset = (unsigned long)&scp->sc_rip - usp;
> +
> +  /* Register 7 is rsp  */
> +  fs->regs.cfa_how = CFA_REG_OFFSET;
> +  fs->regs.cfa_reg = 7;
> +  fs->regs.cfa_offset = usp - (unsigned long) context->cfa;
> +
> +  fs->regs.how[0] = REG_SAVED_OFFSET;
> +  fs->regs.how[1] = REG_SAVED_OFFSET;
> +  fs->regs.how[2] = REG_SAVED_OFFSET;
> +  fs->regs.how[3] = REG_SAVED_OFFSET;
> +  fs->regs.how[4] = REG_SAVED_OFFSET;
> +  fs->regs.how[5] = REG_SAVED_OFFSET;
> +  fs->regs.how[6] = REG_SAVED_OFFSET;
> +  fs->regs.how[8] = REG_SAVED_OFFSET;
> +  fs->regs.how[9] = REG_SAVED_OFFSET;
> +  fs->regs.how[10] = REG_SAVED_OFFSET;
> +  fs->regs.how[11] = REG_SAVED_OFFSET;
> +  fs->regs.how[12] = REG_SAVED_OFFSET;
> +  fs->regs.how[13] = REG_SAVED_OFFSET;
> +  fs->regs.how[14] = REG_SAVED_OFFSET;
> +  fs->regs.how[15] = REG_SAVED_OFFSET;
> +  fs->regs.how[16] = REG_SAVED_OFFSET;
> +
> +  fs->retaddr_column = 16;
> +  fs->signal_frame = 1;
> +
> +  return _URC_NO_REASON;
> +}
>  
>  #else /* ifdef __x86_64__  */
>  
> -- 
> 2.43.0
> 
>
Thomas Schwinge March 20, 2024, 7:36 p.m. UTC | #2
Hi!

Please note that emails to <thomas.schwinge@siemens.com>, or
<thomas_schwinge@mentor.com> don't reach me anymore, and, at least for
the time being, likewise for <thomas@codesourcery.com> --
<tschwinge@baylibre.com> is the new thing; see
<https://baylibre.com/baylibre-expands-open-source-business-to-include-compiler-services/>.
(Or use <thomas@schwinge.name>, <tschwinge@gnu.org>,
<tschwinge@googlemail.com>, as before.)


On 2024-03-01T02:33:10+0100, Samuel Thibault <samuel.thibault@gnu.org> wrote:
> Flavio Cruz, le mer. 28 févr. 2024 22:59:09 -0500, a ecrit:
>> Tested with some simple toy examples where an exception is thrown in the
>> signal handler.
>> 
>> libgcc/ChangeLog:
>> 	* config/i386/gnu-unwind.h: Support unwinding x86_64 signal frames.
>> 
>> Signed-off-by: Flavio Cruz <flaviocruz@gmail.com>
>
> Reviewed-by: Samuel Thibault <samuel.thibault@ens-lyon.org>

Thanks, pushed as commit b7c4ae5ace82b81dafffbc50e8026adfa3cc76e7.


Grüße
 Thomas
diff mbox series

Patch

diff --git a/libgcc/config/i386/gnu-unwind.h b/libgcc/config/i386/gnu-unwind.h
index 0751b5593d4..02b060ab4a5 100644
--- a/libgcc/config/i386/gnu-unwind.h
+++ b/libgcc/config/i386/gnu-unwind.h
@@ -32,9 +32,100 @@  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 
 #ifdef __x86_64__
 
-/*
- * TODO: support for 64 bits needs to be implemented.
- */
+#define MD_FALLBACK_FRAME_STATE_FOR x86_gnu_fallback_frame_state
+
+static _Unwind_Reason_Code
+x86_gnu_fallback_frame_state
+(struct _Unwind_Context *context, _Unwind_FrameState *fs)
+{
+  static const unsigned char gnu_sigtramp_code[] =
+  {
+    /* rpc_wait_trampoline: */
+    0x48, 0xc7, 0xc0, 0xe7, 0xff, 0xff, 0xff,    /* mov    $-25,%rax */
+    0x0f, 0x05,                                  /* syscall */
+    0x49, 0x89, 0x04, 0x24,                      /* mov    %rax,(%r12) */
+    0x48, 0x89, 0xdc,                            /* mov    %rbx,%rsp */
+
+    /* trampoline: */
+    0x5f,                                        /* pop    %rdi */
+    0x5e,                                        /* pop    %rsi */
+    0x5a,                                        /* pop    %rdx */
+    0x48, 0x83, 0xc4, 0x08,                      /* add    $0x8,%rsp */
+    0x41, 0xff, 0xd5,                            /* call   *%r13 */
+
+    /* RA HERE */
+    0x48, 0x8b, 0x7c, 0x24, 0x10,                /* mov    0x10(%rsp),%rdi */
+    0xc3,                                        /* ret */
+
+    /* firewall: */
+    0xf4,                                        /* hlt */
+  };
+
+  const size_t gnu_sigtramp_len = sizeof gnu_sigtramp_code;
+  const size_t gnu_sigtramp_tail = 7; /* length of tail after RA */
+
+  struct stack_contents {
+    void *sigreturn_addr;
+    void *sigreturn_returns_here;
+    struct sigcontext *return_scp;
+  } *stack_contents;
+  struct sigcontext *scp;
+  unsigned long usp;
+
+  unsigned char *adjusted_pc = (unsigned char*)(context->ra) +
+    gnu_sigtramp_tail - gnu_sigtramp_len;
+  if (memcmp (adjusted_pc, gnu_sigtramp_code, gnu_sigtramp_len))
+    return _URC_END_OF_STACK;
+
+  stack_contents = context->cfa;
+
+  scp = stack_contents->return_scp;
+  usp = scp->sc_ursp;
+
+  fs->regs.reg[0].loc.offset = (unsigned long)&scp->sc_rax - usp;
+  fs->regs.reg[1].loc.offset = (unsigned long)&scp->sc_rdx - usp;
+  fs->regs.reg[2].loc.offset = (unsigned long)&scp->sc_rcx - usp;
+  fs->regs.reg[3].loc.offset = (unsigned long)&scp->sc_rbx - usp;
+  fs->regs.reg[4].loc.offset = (unsigned long)&scp->sc_rsi - usp;
+  fs->regs.reg[5].loc.offset = (unsigned long)&scp->sc_rdi - usp;
+  fs->regs.reg[6].loc.offset = (unsigned long)&scp->sc_rbp - usp;
+  fs->regs.reg[8].loc.offset = (unsigned long)&scp->sc_r8 - usp;
+  fs->regs.reg[9].loc.offset = (unsigned long)&scp->sc_r9 - usp;
+  fs->regs.reg[10].loc.offset = (unsigned long)&scp->sc_r10 - usp;
+  fs->regs.reg[11].loc.offset = (unsigned long)&scp->sc_r11 - usp;
+  fs->regs.reg[12].loc.offset = (unsigned long)&scp->sc_r12 - usp;
+  fs->regs.reg[13].loc.offset = (unsigned long)&scp->sc_r13 - usp;
+  fs->regs.reg[14].loc.offset = (unsigned long)&scp->sc_r14 - usp;
+  fs->regs.reg[15].loc.offset = (unsigned long)&scp->sc_r15 - usp;
+  fs->regs.reg[16].loc.offset = (unsigned long)&scp->sc_rip - usp;
+
+  /* Register 7 is rsp  */
+  fs->regs.cfa_how = CFA_REG_OFFSET;
+  fs->regs.cfa_reg = 7;
+  fs->regs.cfa_offset = usp - (unsigned long) context->cfa;
+
+  fs->regs.how[0] = REG_SAVED_OFFSET;
+  fs->regs.how[1] = REG_SAVED_OFFSET;
+  fs->regs.how[2] = REG_SAVED_OFFSET;
+  fs->regs.how[3] = REG_SAVED_OFFSET;
+  fs->regs.how[4] = REG_SAVED_OFFSET;
+  fs->regs.how[5] = REG_SAVED_OFFSET;
+  fs->regs.how[6] = REG_SAVED_OFFSET;
+  fs->regs.how[8] = REG_SAVED_OFFSET;
+  fs->regs.how[9] = REG_SAVED_OFFSET;
+  fs->regs.how[10] = REG_SAVED_OFFSET;
+  fs->regs.how[11] = REG_SAVED_OFFSET;
+  fs->regs.how[12] = REG_SAVED_OFFSET;
+  fs->regs.how[13] = REG_SAVED_OFFSET;
+  fs->regs.how[14] = REG_SAVED_OFFSET;
+  fs->regs.how[15] = REG_SAVED_OFFSET;
+  fs->regs.how[16] = REG_SAVED_OFFSET;
+
+  fs->retaddr_column = 16;
+  fs->signal_frame = 1;
+
+  return _URC_NO_REASON;
+}
 
 #else /* ifdef __x86_64__  */