diff mbox

[i386] add unwinding via signal trampoline for kfreebsd*-gnu

Message ID alpine.LNX.2.00.1307081941340.12746@contest.felk.cvut.cz
State New
Headers show

Commit Message

Petr Salinger July 8, 2013, 5:50 p.m. UTC
Please add support for unwinding through signal handler for GNU/kFreeBSD.

The attached patch is tested on GNU/kFreeBSD, both 32-bit and 64-bit.
The i386/freebsd-unwind.h is probably also suitable for plain FreeBSD.

As suggested in http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57851
I am posting it here.

The patch mainly add new libgcc/config/i386/freebsd-unwind.h
based on linux one.

Thanks

 	Petr
#
# unwinding via signal trampoline
#
diff mbox

Patch

--- a/src/libgcc/config.host
+++ b/src/libgcc/config.host
@@ -523,7 +523,12 @@ 
 	tmake_file="${tmake_file} i386/t-crtpc i386/t-crtfm i386/t-crtstuff t-dfprules"
 	md_unwind_header=i386/linux-unwind.h
 	;;
-i[34567]86-*-kfreebsd*-gnu | i[34567]86-*-knetbsd*-gnu | i[34567]86-*-gnu* | i[34567]86-*-kopensolaris*-gnu)
+i[34567]86-*-kfreebsd*-gnu)
+	extra_parts="$extra_parts crtprec32.o crtprec64.o crtprec80.o crtfastmath.o"
+	tmake_file="${tmake_file} i386/t-crtpc i386/t-crtfm i386/t-crtstuff t-dfprules"
+	md_unwind_header=i386/freebsd-unwind.h
+	;;
+i[34567]86-*-knetbsd*-gnu | i[34567]86-*-gnu* | i[34567]86-*-kopensolaris*-gnu)
 	extra_parts="$extra_parts crtprec32.o crtprec64.o crtprec80.o crtfastmath.o"
 	tmake_file="${tmake_file} i386/t-crtpc i386/t-crtfm i386/t-crtstuff t-dfprules"
 	;;
@@ -532,7 +537,12 @@ 
 	tmake_file="${tmake_file} i386/t-crtpc i386/t-crtfm i386/t-crtstuff t-dfprules"
 	md_unwind_header=i386/linux-unwind.h
 	;;
-x86_64-*-kfreebsd*-gnu | x86_64-*-knetbsd*-gnu)
+x86_64-*-kfreebsd*-gnu)
+	extra_parts="$extra_parts crtprec32.o crtprec64.o crtprec80.o crtfastmath.o"
+	tmake_file="${tmake_file} i386/t-crtpc i386/t-crtfm i386/t-crtstuff t-dfprules"
+	md_unwind_header=i386/freebsd-unwind.h
+	;;
+x86_64-*-knetbsd*-gnu)
 	extra_parts="$extra_parts crtprec32.o crtprec64.o crtprec80.o crtfastmath.o"
 	tmake_file="${tmake_file} i386/t-crtpc i386/t-crtfm i386/t-crtstuff t-dfprules"
 	;;
--- a/src/libgcc/config/i386/freebsd-unwind.h
+++ b/src/libgcc/config/i386/freebsd-unwind.h
@@ -0,0 +1,190 @@ 
+/* DWARF2 EH unwinding support for AMD x86-64 and x86.
+   Copyright (C) 2004-2013 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC 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 General Public License for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  */
+
+/* Do code reading to identify a signal frame, and set the frame
+   state data appropriately.  See unwind-dw2.c for the structs.
+   Don't use this at all if inhibit_libc is used.  */
+
+#ifndef inhibit_libc
+
+#include <signal.h>
+#include <sys/ucontext.h>
+#include <machine/sigframe.h>
+
+#ifdef __x86_64__
+
+#define MD_FALLBACK_FRAME_STATE_FOR x86_64_fb_fallback_frame_state
+
+static _Unwind_Reason_Code
+x86_64_fb_fallback_frame_state (struct _Unwind_Context *context,
+			     _Unwind_FrameState *fs)
+{
+  unsigned int *pc = context->ra;
+  struct sigframe *sf;
+  long new_cfa;
+
+/*  sys/amd64/amd64/sigtramp.S:
+               
+      48 8d 7c 24 10          lea    0x10(%rsp),%rdi
+      6a 00                   pushq  $0x0
+      48 c7 c0 a1 01 00 00    mov    $0x1a1,%rax
+      0f 05                   syscall 
+*/
+
+  if (   (pc[0] == 0x247c8d48U)
+      && (pc[1] == 0x48006a10U)
+      && (pc[2] == 0x01a1c0c7U)
+      && (pc[3] == 0x050f0000U))
+    {
+      sf = (struct sigframe *) context->cfa;
+    }
+  else
+    return _URC_END_OF_STACK;
+
+  new_cfa = sf->sf_uc.uc_mcontext.mc_rsp;
+  fs->regs.cfa_how = CFA_REG_OFFSET;
+  /* Register 7 is rsp  */
+  fs->regs.cfa_reg = 7;
+  fs->regs.cfa_offset = new_cfa - (long) context->cfa;
+
+  /* The SVR4 register numbering macros aren't usable in libgcc.  */
+  fs->regs.reg[0].how = REG_SAVED_OFFSET;
+  fs->regs.reg[0].loc.offset = (long)&sf->sf_uc.uc_mcontext.mc_rax - new_cfa;
+  fs->regs.reg[1].how = REG_SAVED_OFFSET;
+  fs->regs.reg[1].loc.offset = (long)&sf->sf_uc.uc_mcontext.mc_rdx - new_cfa;
+  fs->regs.reg[2].how = REG_SAVED_OFFSET;
+  fs->regs.reg[2].loc.offset = (long)&sf->sf_uc.uc_mcontext.mc_rcx - new_cfa;
+  fs->regs.reg[3].how = REG_SAVED_OFFSET;
+  fs->regs.reg[3].loc.offset = (long)&sf->sf_uc.uc_mcontext.mc_rbx - new_cfa;
+  fs->regs.reg[4].how = REG_SAVED_OFFSET;
+  fs->regs.reg[4].loc.offset = (long)&sf->sf_uc.uc_mcontext.mc_rsi - new_cfa;
+  fs->regs.reg[5].how = REG_SAVED_OFFSET;
+  fs->regs.reg[5].loc.offset = (long)&sf->sf_uc.uc_mcontext.mc_rdi - new_cfa;
+  fs->regs.reg[6].how = REG_SAVED_OFFSET;
+  fs->regs.reg[6].loc.offset = (long)&sf->sf_uc.uc_mcontext.mc_rbp - new_cfa;
+  fs->regs.reg[8].how = REG_SAVED_OFFSET;
+  fs->regs.reg[8].loc.offset = (long)&sf->sf_uc.uc_mcontext.mc_r8 - new_cfa;
+  fs->regs.reg[9].how = REG_SAVED_OFFSET;
+  fs->regs.reg[9].loc.offset = (long)&sf->sf_uc.uc_mcontext.mc_r9 - new_cfa;
+  fs->regs.reg[10].how = REG_SAVED_OFFSET;
+  fs->regs.reg[10].loc.offset = (long)&sf->sf_uc.uc_mcontext.mc_r10 - new_cfa;
+  fs->regs.reg[11].how = REG_SAVED_OFFSET;
+  fs->regs.reg[11].loc.offset = (long)&sf->sf_uc.uc_mcontext.mc_r11 - new_cfa;
+  fs->regs.reg[12].how = REG_SAVED_OFFSET;
+  fs->regs.reg[12].loc.offset = (long)&sf->sf_uc.uc_mcontext.mc_r12 - new_cfa;
+  fs->regs.reg[13].how = REG_SAVED_OFFSET;
+  fs->regs.reg[13].loc.offset = (long)&sf->sf_uc.uc_mcontext.mc_r13 - new_cfa;
+  fs->regs.reg[14].how = REG_SAVED_OFFSET;
+  fs->regs.reg[14].loc.offset = (long)&sf->sf_uc.uc_mcontext.mc_r14 - new_cfa;
+  fs->regs.reg[15].how = REG_SAVED_OFFSET;
+  fs->regs.reg[15].loc.offset = (long)&sf->sf_uc.uc_mcontext.mc_r15 - new_cfa;
+  fs->regs.reg[16].how = REG_SAVED_OFFSET;
+  fs->regs.reg[16].loc.offset = (long)&sf->sf_uc.uc_mcontext.mc_rip - new_cfa;
+  fs->retaddr_column = 16;
+  fs->signal_frame = 1;
+  return _URC_NO_REASON;
+}
+
+#else /* ifdef __x86_64__  */
+
+#define MD_FALLBACK_FRAME_STATE_FOR x86_fb_fallback_frame_state
+
+static _Unwind_Reason_Code
+x86_fb_fallback_frame_state (struct _Unwind_Context *context,
+			  _Unwind_FrameState *fs)
+{
+  unsigned int *pc = context->ra;
+  struct sigframe *sf;
+  long new_cfa;
+
+/* sys/amd64/ia32/ia32_sigtramp.S 
+
+     8d 44 24 20             lea    0x20(%esp),%eax
+     50                      push   %eax
+     b8 a1 01 00 00          mov    $0x1a1,%eax
+     50                      push   %eax
+     cd 80                   int    $0x80
+     eb fe                   jmp    -
+*/
+
+/* sys/i386/i386/locore.s: sigcode()
+
+     8d 44 24 20             lea    0x20(%esp),%eax
+     50                      push   %eax
+     f7 40 54 00 00 02 00    testl  $0x20000,0x54(%eax)
+     75 03                   jne    +
+     8e 68 14                mov    0x14(%eax),%gs
+     b8 a1 01 00 00          mov    $0x1a1,%eax
+     50                      push   %eax
+     cd 80                   int    $0x80
+     eb fe                   jmp    -
+*/
+
+  if ((pc[0] == 0x2024448dU)
+      &&  ((
+	          (pc[1] == 0x01a1b850U)
+	      &&  (pc[2] == 0xcd500000U)
+	      && ((pc[3] & 0xFF) == 0x80)
+	   )
+         
+        || (
+	          (pc[4] == 0x01a1b814U)
+	      &&  (pc[5] == 0xcd500000U)
+	      && ((pc[6] & 0xFF) == 0x80)
+	   )))
+    {
+      sf = (struct sigframe *) context->cfa;
+    }
+  else
+    return _URC_END_OF_STACK;
+
+  new_cfa = sf->sf_uc.uc_mcontext.mc_esp;
+  fs->regs.cfa_how = CFA_REG_OFFSET;
+  fs->regs.cfa_reg = 4;
+  fs->regs.cfa_offset = new_cfa - (long) context->cfa;
+
+  /* The SVR4 register numbering macros aren't usable in libgcc.  */
+  fs->regs.reg[0].how = REG_SAVED_OFFSET;
+  fs->regs.reg[0].loc.offset = (long)&sf->sf_uc.uc_mcontext.mc_eax - new_cfa;
+  fs->regs.reg[3].how = REG_SAVED_OFFSET;
+  fs->regs.reg[3].loc.offset = (long)&sf->sf_uc.uc_mcontext.mc_ebx - new_cfa;
+  fs->regs.reg[1].how = REG_SAVED_OFFSET;
+  fs->regs.reg[1].loc.offset = (long)&sf->sf_uc.uc_mcontext.mc_ecx - new_cfa;
+  fs->regs.reg[2].how = REG_SAVED_OFFSET;
+  fs->regs.reg[2].loc.offset = (long)&sf->sf_uc.uc_mcontext.mc_edx - new_cfa;
+  fs->regs.reg[6].how = REG_SAVED_OFFSET;
+  fs->regs.reg[6].loc.offset = (long)&sf->sf_uc.uc_mcontext.mc_esi - new_cfa;
+  fs->regs.reg[7].how = REG_SAVED_OFFSET;
+  fs->regs.reg[7].loc.offset = (long)&sf->sf_uc.uc_mcontext.mc_edi - new_cfa;
+  fs->regs.reg[5].how = REG_SAVED_OFFSET;
+  fs->regs.reg[5].loc.offset = (long)&sf->sf_uc.uc_mcontext.mc_ebp - new_cfa;
+  fs->regs.reg[8].how = REG_SAVED_OFFSET;
+  fs->regs.reg[8].loc.offset = (long)&sf->sf_uc.uc_mcontext.mc_eip - new_cfa;
+  fs->retaddr_column = 8;
+  fs->signal_frame = 1;
+  return _URC_NO_REASON;
+}
+
+#endif /* ifdef __x86_64__  */
+#endif /* ifdef inhibit_libc  */