summaryrefslogtreecommitdiff
path: root/src/grt/config
diff options
context:
space:
mode:
authorTristan Gingold2015-11-18 21:45:45 +0100
committerTristan Gingold2015-11-19 05:47:59 +0100
commit92b0b82ea32982b94eb8bf19a0b498d92053fffe (patch)
tree70b04f103d145dc01d31870e50b5e6a654dc20e0 /src/grt/config
parentff4bc5fb13a997a1d00596578b6d7deb5c0b0da6 (diff)
downloadghdl-92b0b82ea32982b94eb8bf19a0b498d92053fffe.tar.gz
ghdl-92b0b82ea32982b94eb8bf19a0b498d92053fffe.tar.bz2
ghdl-92b0b82ea32982b94eb8bf19a0b498d92053fffe.zip
Add symbolizer (for mcode).
Display a backtrace in case of failed check or assert failure.
Diffstat (limited to 'src/grt/config')
-rw-r--r--src/grt/config/grt_itf.h40
-rw-r--r--src/grt/config/jumps.c104
-rw-r--r--src/grt/config/win32.c17
3 files changed, 136 insertions, 25 deletions
diff --git a/src/grt/config/grt_itf.h b/src/grt/config/grt_itf.h
new file mode 100644
index 0000000..1b17c3a
--- /dev/null
+++ b/src/grt/config/grt_itf.h
@@ -0,0 +1,40 @@
+/* Declarations to interface with Ada code.
+ Copyright (C) 2015 Tristan Gingold.
+
+ GHDL 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 2, or (at your option) any later
+ version.
+
+ GHDL 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.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING. If not, write to the Free
+ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ As a special exception, if other files instantiate generics from this
+ unit, or you link this unit with other files to produce an executable,
+ this unit does not by itself cause the resulting executable to be
+ covered by the GNU General Public License. This exception does not
+ however invalidate any other reasons why the executable file might be
+ covered by the GNU Public License.
+*/
+
+struct backtrace_addrs
+{
+ int size;
+ int skip;
+ void *addrs[32];
+};
+
+void grt_save_backtrace (struct backtrace_addrs *bt, int skip);
+
+extern void grt_overflow_error (struct backtrace_addrs *bt);
+extern void grt_null_access_error (struct backtrace_addrs *bt);
+
+void __ghdl_maybe_return_via_longjump (int val);
+int __ghdl_run_through_longjump (int (*func)(void));
diff --git a/src/grt/config/jumps.c b/src/grt/config/jumps.c
index a544f83..00e17d3 100644
--- a/src/grt/config/jumps.c
+++ b/src/grt/config/jumps.c
@@ -29,11 +29,17 @@
#include <signal.h>
#include <fcntl.h>
-#if defined (__linux__) && defined (__i386__)
-/* On i386/Linux, the context must be inspected. */
+#if defined (__linux__) || defined (__APPLE__)
+#define HAVE_BACKTRACE 1
#include <sys/ucontext.h>
#endif
+#ifdef HAVE_BACKTRACE
+#include <execinfo.h>
+#endif
+
+#include "grt_itf.h"
+
/* There is a simple setjmp/longjmp mechanism used to report failures.
We have the choice between 3 mechanisms:
* USE_BUITLIN_SJLJ: gcc builtin setjmp/longjmp, very fast but gcc specific.
@@ -70,49 +76,89 @@ typedef jmp_buf JMP_BUF;
static int run_env_en;
static JMP_BUF run_env;
-extern void grt_overflow_error (void);
-extern void grt_null_access_error (void);
-
#ifdef __APPLE__
#define NEED_SIGFPE_HANDLER
+#define NEED_SIGBUS_HANDLER
#endif
static struct sigaction prev_sigfpe_act;
+#ifdef NEED_SIGFPE_HANDLER
+static struct sigaction prev_sigsegv_act;
+#endif
+#ifdef NEED_SIGBUS_HANDLER
+static struct sigaction prev_sigbus_act;
+#endif
+
+static void
+get_bt_from_ucontext (void *uctxt, struct backtrace_addrs *bt)
+{
+ void *pc = NULL;
+ int i;
+
+#ifdef HAVE_BACKTRACE
+ bt->size = backtrace (bt->addrs, sizeof (bt->addrs) / sizeof (void *));
+ bt->skip = 0;
+#else
+ bt->size = 0;
+ return;
+#endif
+
+#if defined (__linux__) && defined (__x86_64__)
+ ucontext *u = (ucontext *)uctxt;
+ pc = (void *)u->uc_mcontext.gregs[REG_RIP];
+#endif
+#if defined (__APPLE__) && defined (__i386__)
+ ucontext_t *u = (ucontext_t *)uctxt;
+ pc = (void *)u->uc_mcontext->__ss.__eip;
+ bt->skip = 3; /* This frame + sighandler + trampoline + marker - pc. */
+ bt->addrs[3] = pc;
+#endif
+}
+
/* Handler for SIGFPE signal.
It is also raised in case of overflow (i386 linux). */
-static void grt_overflow_handler (int signo, siginfo_t *info, void *ptr)
+static void
+grt_overflow_handler (int signo, siginfo_t *info, void *ptr)
{
- grt_overflow_error ();
-}
+ struct backtrace_addrs bt;
-static struct sigaction prev_sigsegv_act;
+ get_bt_from_ucontext (ptr, &bt);
+ grt_overflow_error (&bt);
+}
/* Posix handler for overflow. This is used only by mcode. */
-static void grt_sigsegv_handler (int signo, siginfo_t *info, void *ptr)
+static void
+grt_sigsegv_handler (int signo, siginfo_t *info, void *ptr)
{
-#if defined (__linux__) && defined (__i386__)
- ucontext_t *uctxt = (ucontext_t *)ptr;
+ struct backtrace_addrs bt;
- /* Linux generates a SIGSEGV (!) for an overflow exception. */
- if (uctxt->uc_mcontext.gregs[REG_TRAPNO] == 4)
+ get_bt_from_ucontext (ptr, &bt);
+
+#if defined (__linux__) && defined (__i386__)
+ if (signo == SIGSEGV)
{
- grt_overflow_error ();
+ ucontext_t *uctxt = (ucontext_t *)ptr;
+
+ /* Linux generates a SIGSEGV (!) for an overflow exception. */
+ if (uctxt->uc_mcontext.gregs[REG_TRAPNO] == 4)
+ grt_overflow_error (&bt);
}
#endif
/* We loose. */
- grt_null_access_error ();
+ grt_null_access_error (&bt);
}
-static void grt_signal_setup (void)
+static void
+grt_signal_setup (void)
{
{
struct sigaction sigsegv_act;
sigsegv_act.sa_sigaction = &grt_sigsegv_handler;
sigemptyset (&sigsegv_act.sa_mask);
- sigsegv_act.sa_flags = SA_ONSTACK | SA_SIGINFO;
+ sigsegv_act.sa_flags = SA_SIGINFO;
#ifdef SA_ONESHOT
sigsegv_act.sa_flags |= SA_ONESHOT;
#elif defined (SA_RESETHAND)
@@ -122,6 +168,10 @@ static void grt_signal_setup (void)
/* We don't care about the return status.
If the handler is not installed, then some feature are lost. */
sigaction (SIGSEGV, &sigsegv_act, &prev_sigsegv_act);
+
+#ifdef NEED_SIGBUS_HANDLER
+ sigaction (SIGBUS, &sigsegv_act, &prev_sigbus_act);
+#endif
}
#ifdef NEED_SIGFPE_HANDLER
@@ -137,10 +187,15 @@ static void grt_signal_setup (void)
#endif
}
-static void grt_signal_restore (void)
+static void
+grt_signal_restore (void)
{
sigaction (SIGSEGV, &prev_sigsegv_act, NULL);
+#ifdef NEED_SIGBUS_HANDLER
+ sigaction (SIGBUS, &prev_sigbus_act, NULL);
+#endif
+
#ifdef NEED_SIGFPE_HANDLER
sigaction (SIGFPE, &prev_sigfpe_act, NULL);
#endif
@@ -167,3 +222,14 @@ __ghdl_run_through_longjump (int (*func)(void))
run_env_en = 0;
return res;
}
+
+void
+grt_save_backtrace (struct backtrace_addrs *bt, int skip)
+{
+#ifdef HAVE_BACKTRACE
+ bt->size = backtrace (bt->addrs, sizeof (bt->addrs) / sizeof (void *));
+ bt->skip = skip + 1;
+#else
+ bt->size = 0;
+#endif
+}
diff --git a/src/grt/config/win32.c b/src/grt/config/win32.c
index 869c7ca..63d11a2 100644
--- a/src/grt/config/win32.c
+++ b/src/grt/config/win32.c
@@ -30,13 +30,11 @@
#include <assert.h>
#include <excpt.h>
+#include "grt_itf.h"
+
static int run_env_en;
static jmp_buf run_env;
-extern void grt_overflow_error (void);
-extern void grt_null_access_error (void);
-void __ghdl_maybe_return_via_longjump (int val);
-
static EXCEPTION_DISPOSITION
ghdl_SEH_handler (struct _EXCEPTION_RECORD* ExceptionRecord,
void *EstablisherFrame,
@@ -60,7 +58,8 @@ ghdl_SEH_handler (struct _EXCEPTION_RECORD* ExceptionRecord,
switch (ExceptionRecord->ExceptionCode)
{
case EXCEPTION_ACCESS_VIOLATION:
- grt_null_access_error ();
+ /* Pc is ExceptionRecord->ExceptionAddress. */
+ grt_null_access_error (NULL);
break;
case EXCEPTION_FLT_DENORMAL_OPERAND:
@@ -77,7 +76,7 @@ ghdl_SEH_handler (struct _EXCEPTION_RECORD* ExceptionRecord,
break;
case EXCEPTION_INT_OVERFLOW:
- grt_overflow_error ();
+ grt_overflow_error (NULL);
break;
case EXCEPTION_STACK_OVERFLOW:
@@ -132,6 +131,12 @@ __ghdl_run_through_longjump (int (*func)(void))
return res;
}
+void
+grt_save_backtrace (struct backtrace_addrs *bt, int skip)
+{
+ bt->size = 0;
+}
+
#include <math.h>
double acosh (double x)