#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
+#include <ucontext.h>
#include "runtime.h"
-#include "go-assert.h"
-#include "go-panic.h"
-#include "signal_unix.h"
#ifndef SA_RESTART
#define SA_RESTART 0
extern void __splitstack_setcontext(void *context[10]);
+extern void *__splitstack_find_context(void *context[10], size_t *,
+ void **, void **, void **);
+
#endif
-#define N SigNotify
-#define K SigKill
-#define T SigThrow
-#define P SigPanic
-#define D SigDefault
+// The rest of the signal handler, written in Go.
-/* Signal actions. This collects the sigtab tables for several
- different targets from the master library. SIGKILL, SIGCONT, and
- SIGSTOP are not listed, as we don't want to set signal handlers for
- them. */
-
-SigTab runtime_sigtab[] = {
-#ifdef SIGHUP
- { SIGHUP, N + K },
-#endif
-#ifdef SIGINT
- { SIGINT, N + K },
-#endif
-#ifdef SIGQUIT
- { SIGQUIT, N + T },
-#endif
-#ifdef SIGILL
- { SIGILL, T },
-#endif
-#ifdef SIGTRAP
- { SIGTRAP, T },
-#endif
-#ifdef SIGABRT
- { SIGABRT, N + T },
-#endif
-#ifdef SIGBUS
- { SIGBUS, P },
-#endif
-#ifdef SIGFPE
- { SIGFPE, P },
-#endif
-#ifdef SIGUSR1
- { SIGUSR1, N },
-#endif
-#ifdef SIGSEGV
- { SIGSEGV, P },
-#endif
-#ifdef SIGUSR2
- { SIGUSR2, N },
-#endif
-#ifdef SIGPIPE
- { SIGPIPE, N },
-#endif
-#ifdef SIGALRM
- { SIGALRM, N },
-#endif
-#ifdef SIGTERM
- { SIGTERM, N + K },
-#endif
-#ifdef SIGSTKFLT
- { SIGSTKFLT, T },
-#endif
-#ifdef SIGCHLD
- { SIGCHLD, N },
-#endif
-#ifdef SIGTSTP
- { SIGTSTP, N + D },
-#endif
-#ifdef SIGTTIN
- { SIGTTIN, N + D },
-#endif
-#ifdef SIGTTOU
- { SIGTTOU, N + D },
-#endif
-#ifdef SIGURG
- { SIGURG, N },
-#endif
-#ifdef SIGXCPU
- { SIGXCPU, N },
-#endif
-#ifdef SIGXFSZ
- { SIGXFSZ, N },
-#endif
-#ifdef SIGVTALRM
- { SIGVTALRM, N },
-#endif
-#ifdef SIGPROF
- { SIGPROF, N },
-#endif
-#ifdef SIGWINCH
- { SIGWINCH, N },
-#endif
-#ifdef SIGIO
- { SIGIO, N },
-#endif
-#ifdef SIGPWR
- { SIGPWR, N },
-#endif
-#ifdef SIGSYS
- { SIGSYS, N },
-#endif
-#ifdef SIGEMT
- { SIGEMT, T },
-#endif
-#ifdef SIGINFO
- { SIGINFO, N },
-#endif
-#ifdef SIGTHR
- { SIGTHR, N },
-#endif
- { -1, 0 }
-};
-#undef N
-#undef K
-#undef T
-#undef P
-#undef D
+extern void sigtrampgo(uint32, siginfo_t *, void *)
+ __asm__(GOSYM_PREFIX "runtime.sigtrampgo");
+// The Go signal handler, written in C. This should be running on the
+// alternate signal stack. This is responsible for setting up the
+// split stack context so that stack guard checks will work as
+// expected.
-static int8 badsignal[] = "runtime: signal received on thread not created by Go.\n";
+void sigtramp(int, siginfo_t *, void *)
+ __attribute__ ((no_split_stack));
-static void
-runtime_badsignal(int32 sig)
-{
- // Avoid -D_FORTIFY_SOURCE problems.
- int rv __attribute__((unused));
+void sigtramp(int, siginfo_t *, void *)
+ __asm__ (GOSYM_PREFIX "runtime.sigtramp");
- if (sig == SIGPROF) {
- return; // Ignore SIGPROFs intended for a non-Go thread.
- }
- rv = runtime_write(2, badsignal, sizeof badsignal - 1);
- runtime_exit(1);
-}
+#ifndef USING_SPLIT_STACK
-/* Handle a signal, for cases where we don't panic. We can split the
- stack here. */
+// When not using split stacks, there are no stack checks, and there
+// is nothing special for this function to do.
void
-runtime_sighandler (int sig, Siginfo *info,
- void *context __attribute__ ((unused)), G *gp)
+sigtramp(int sig, siginfo_t *info, void *context)
{
- M *m;
- int i;
-
- m = runtime_m ();
- if (m == NULL)
- {
- runtime_badsignal (sig);
- return;
- }
-
-#ifdef SIGPROF
- if (sig == SIGPROF)
- {
- if (gp != runtime_m ()->g0 && gp != runtime_m ()->gsignal)
- runtime_sigprof ();
- return;
- }
-#endif
-
- for (i = 0; runtime_sigtab[i].sig != -1; ++i)
- {
- SigTab *t;
- bool notify, crash;
-
- t = &runtime_sigtab[i];
+ sigtrampgo(sig, info, context);
+}
- if (t->sig != sig)
- continue;
+#else // USING_SPLIT_STACK
- notify = false;
-#ifdef SA_SIGINFO
- notify = info != NULL && info->si_code == SI_USER;
-#endif
- if (notify || (t->flags & SigNotify) != 0)
- {
- if (__go_sigsend (sig))
- return;
+void
+sigtramp(int sig, siginfo_t *info, void *context)
+{
+ G *gp;
+ void *stack_context[10];
+ void *stack;
+ void *find_stack;
+ size_t stack_size;
+ void *next_segment;
+ void *next_sp;
+ void *initial_sp;
+ uintptr sp;
+ stack_t st;
+ uintptr stsp;
+
+ gp = runtime_g();
+
+ if (gp == nil) {
+ // Let the Go code handle this case.
+ // It should only call nosplit functions in this case.
+ sigtrampgo(sig, info, context);
+ return;
}
- if ((t->flags & SigKill) != 0)
- runtime_exit (2);
- if ((t->flags & SigThrow) == 0)
- return;
-
- runtime_startpanic ();
-
- {
- const char *name = NULL;
-
-#ifdef HAVE_STRSIGNAL
- name = strsignal (sig);
-#endif
- if (name == NULL)
- runtime_printf ("Signal %d\n", sig);
- else
- runtime_printf ("%s\n", name);
- }
-
- if (m->lockedg != NULL && m->ncgo > 0 && gp == m->g0)
- {
- runtime_printf("signal arrived during cgo execution\n");
- gp = m->lockedg;
+ // If this signal is one for which we will panic, we are not
+ // on the alternate signal stack. It's OK to call split-stack
+ // functions here.
+ if (sig == SIGBUS || sig == SIGFPE || sig == SIGSEGV) {
+ sigtrampgo(sig, info, context);
+ return;
}
- runtime_printf ("\n");
+ // We are running on the alternate signal stack.
- if (runtime_gotraceback (&crash))
- {
- G *g;
+ __splitstack_getcontext(&stack_context[0]);
- g = runtime_g ();
- runtime_traceback (g);
- runtime_tracebackothers (g);
+ find_stack =
+ __splitstack_find_context((void*)(&gp->m->gsignal->stackcontext[0]),
+ &stack_size, &next_segment,
+ &next_sp, &initial_sp);
+ stack = find_stack;
+ if (stack == NULL) {
+ stack = gp->m->gsignalstack;
+ stack_size = gp->m->gsignalstacksize;
+ }
- /* The gc library calls runtime_dumpregs here, and provides
- a function that prints the registers saved in context in
- a readable form. */
+ // If some non-Go code called sigaltstack, adjust.
+ sp = (uintptr)(&stack_size);
+ if (sp < (uintptr)(stack) || sp >= (uintptr)(stack) + stack_size) {
+ sigaltstack(nil, &st);
+ if ((st.ss_flags & SS_DISABLE) != 0) {
+ runtime_printf("signal %d received on thread with no signal stack\n", (int32)(sig));
+ runtime_throw("non-Go code disabled sigaltstack");
+ }
+
+ stsp = (uintptr)(st.ss_sp);
+ if (sp < stsp || sp >= stsp + st.ss_size) {
+ runtime_printf("signal %d received but handler not on signal stack\n", (int32)(sig));
+ runtime_throw("non-Go code set up signal handler without SA_ONSTACK flag");
+ }
+
+ // Unfortunately __splitstack_find_context will return NULL
+ // when it is called on a context that has never been used.
+ // There isn't much we can do but assume all is well.
+ if (find_stack != NULL) {
+ // Here the gc runtime adjusts the gsignal
+ // stack guard to match the values returned by
+ // sigaltstack. Unfortunately we have no way
+ // to do that.
+ runtime_printf("signal %d received on unknown signal stack\n", (int32)(sig));
+ runtime_throw("non-Go code changed signal stack");
+ }
}
- if (crash)
- runtime_crash ();
+ // Set the split stack context so that the stack guards are
+ // checked correctly.
- runtime_exit (2);
- }
+ __splitstack_setcontext((void*)(&gp->m->gsignal->stackcontext[0]));
- __builtin_unreachable ();
-}
+ sigtrampgo(sig, info, context);
-/* The start of handling a signal which panics. */
+ // We are going to return back to the signal trampoline and
+ // then to whatever we were doing before we got the signal.
+ // Restore the split stack context so that stack guards are
+ // checked correctly.
-static void
-sig_panic_leadin (int sig)
-{
- int i;
- sigset_t clear;
-
- if (runtime_m ()->mallocing)
- {
- runtime_printf ("caught signal while mallocing: %d\n", sig);
- runtime_throw ("caught signal while mallocing");
- }
-
- /* The signal handler blocked signals; unblock them. */
- i = sigfillset (&clear);
- __go_assert (i == 0);
- i = sigprocmask (SIG_UNBLOCK, &clear, NULL);
- __go_assert (i == 0);
+ __splitstack_setcontext(&stack_context[0]);
}
-#ifdef SA_SIGINFO
+#endif // USING_SPLIT_STACK
-/* Signal dispatch for signals which panic, on systems which support
- SA_SIGINFO. This is called on the thread stack, and as such it is
- permitted to split the stack. */
+// C function to return the address of the sigtramp function.
+uintptr getSigtramp(void) __asm__ (GOSYM_PREFIX "runtime.getSigtramp");
-static void
-sig_panic_info_handler (int sig, Siginfo *info, void *context)
+uintptr
+getSigtramp()
{
- G *g;
-
- g = runtime_g ();
- if (g == NULL || info->si_code == SI_USER)
- {
- runtime_sighandler (sig, info, context, g);
- return;
- }
-
- g->sig = sig;
- g->sigcode0 = info->si_code;
- g->sigcode1 = (uintptr_t) info->si_addr;
-
- /* It would be nice to set g->sigpc here as the gc library does, but
- I don't know how to get it portably. */
-
- sig_panic_leadin (sig);
-
- switch (sig)
- {
-#ifdef SIGBUS
- case SIGBUS:
- if (info->si_code == BUS_ADRERR && (uintptr_t) info->si_addr < 0x1000)
- runtime_panicstring ("invalid memory address or "
- "nil pointer dereference");
- runtime_printf ("unexpected fault address %p\n", info->si_addr);
- runtime_throw ("fault");
-#endif
-
-#ifdef SIGSEGV
- case SIGSEGV:
- if ((info->si_code == 0
- || info->si_code == SEGV_MAPERR
- || info->si_code == SEGV_ACCERR)
- && (uintptr_t) info->si_addr < 0x1000)
- runtime_panicstring ("invalid memory address or "
- "nil pointer dereference");
- runtime_printf ("unexpected fault address %p\n", info->si_addr);
- runtime_throw ("fault");
-#endif
-
-#ifdef SIGFPE
- case SIGFPE:
- switch (info->si_code)
- {
- case FPE_INTDIV:
- runtime_panicstring ("integer divide by zero");
- case FPE_INTOVF:
- runtime_panicstring ("integer overflow");
- }
- runtime_panicstring ("floating point error");
-#endif
- }
-
- /* All signals with SigPanic should be in cases above, and this
- handler should only be invoked for those signals. */
- __builtin_unreachable ();
+ return (uintptr)(void*)sigtramp;
}
-#else /* !defined (SA_SIGINFO) */
+// C code to manage the sigaction sa_sigaction field, which is
+// typically a union and so hard for mksysinfo.sh to handle.
-static void
-sig_panic_handler (int sig)
-{
- G *g;
-
- g = runtime_g ();
- if (g == NULL)
- {
- runtime_sighandler (sig, NULL, NULL, g);
- return;
- }
-
- g->sig = sig;
- g->sigcode0 = 0;
- g->sigcode1 = 0;
-
- sig_panic_leadin (sig);
-
- switch (sig)
- {
-#ifdef SIGBUS
- case SIGBUS:
- runtime_panicstring ("invalid memory address or "
- "nil pointer dereference");
-#endif
+uintptr getSigactionHandler(struct sigaction*)
+ __attribute__ ((no_split_stack));
-#ifdef SIGSEGV
- case SIGSEGV:
- runtime_panicstring ("invalid memory address or "
- "nil pointer dereference");
-#endif
+uintptr getSigactionHandler(struct sigaction*)
+ __asm__ (GOSYM_PREFIX "runtime.getSigactionHandler");
-#ifdef SIGFPE
- case SIGFPE:
- runtime_panicstring ("integer divide by zero or floating point error");
-#endif
- }
-
- /* All signals with SigPanic should be in cases above, and this
- handler should only be invoked for those signals. */
- __builtin_unreachable ();
-}
-
-#endif /* !defined (SA_SIGINFO) */
-
-/* A signal handler used for signals which are not going to panic.
- This is called on the alternate signal stack so it may not split
- the stack. */
-
-static void
-sig_tramp_info (int, Siginfo *, void *) __attribute__ ((no_split_stack));
-
-static void
-sig_tramp_info (int sig, Siginfo *info, void *context)
+uintptr
+getSigactionHandler(struct sigaction* sa)
{
- G *gp;
- M *mp;
-
- /* We are now running on the stack registered via sigaltstack.
- (Actually there is a small span of time between runtime_siginit
- and sigaltstack when the program starts.) */
- gp = runtime_g ();
- mp = runtime_m ();
-
- if (gp != NULL)
- {
-#ifdef USING_SPLIT_STACK
- __splitstack_getcontext (&gp->stack_context[0]);
-#endif
- }
-
- if (gp != NULL && mp->gsignal != NULL)
- {
- /* We are running on the signal stack. Set the split stack
- context so that the stack guards are checked correctly. */
-#ifdef USING_SPLIT_STACK
- __splitstack_setcontext (&mp->gsignal->stack_context[0]);
-#endif
- }
-
- runtime_sighandler (sig, info, context, gp);
-
- /* We are going to return back to the signal trampoline and then to
- whatever we were doing before we got the signal. Restore the
- split stack context so that stack guards are checked
- correctly. */
-
- if (gp != NULL)
- {
-#ifdef USING_SPLIT_STACK
- __splitstack_setcontext (&gp->stack_context[0]);
-#endif
- }
+ return (uintptr)(sa->sa_sigaction);
}
-#ifndef SA_SIGINFO
+void setSigactionHandler(struct sigaction*, uintptr)
+ __attribute__ ((no_split_stack));
-static void sig_tramp (int sig) __attribute__ ((no_split_stack));
+void setSigactionHandler(struct sigaction*, uintptr)
+ __asm__ (GOSYM_PREFIX "runtime.setSigactionHandler");
-static void
-sig_tramp (int sig)
+void
+setSigactionHandler(struct sigaction* sa, uintptr handler)
{
- sig_tramp_info (sig, NULL, NULL);
+ sa->sa_sigaction = (void*)(handler);
}
-#endif
+#ifdef __linux__
-void
-runtime_setsig (int32 i, GoSighandler *fn, bool restart)
-{
- struct sigaction sa;
- int r;
- SigTab *t;
-
- memset (&sa, 0, sizeof sa);
-
- r = sigfillset (&sa.sa_mask);
- __go_assert (r == 0);
-
- t = &runtime_sigtab[i];
-
- if ((t->flags & SigPanic) == 0)
- {
-#ifdef SA_SIGINFO
- sa.sa_flags = SA_ONSTACK | SA_SIGINFO;
- if (fn == runtime_sighandler)
- fn = (void *) sig_tramp_info;
- sa.sa_sigaction = (void *) fn;
-#else
- sa.sa_flags = SA_ONSTACK;
- if (fn == runtime_sighandler)
- fn = (void *) sig_tramp;
- sa.sa_handler = (void *) fn;
+// Workaround for https://sourceware.org/bugzilla/show_bug.cgi?id=27417
+#ifndef sigev_notify_thread_id
+ #define sigev_notify_thread_id _sigev_un._tid
#endif
- }
- else
- {
-#ifdef SA_SIGINFO
- sa.sa_flags = SA_SIGINFO;
- if (fn == runtime_sighandler)
- fn = (void *) sig_panic_info_handler;
- sa.sa_sigaction = (void *) fn;
-#else
- sa.sa_flags = 0;
- if (fn == runtime_sighandler)
- fn = (void *) sig_panic_handler;
- sa.sa_handler = (void *) fn;
-#endif
- }
-
- if (restart)
- sa.sa_flags |= SA_RESTART;
- if (sigaction (t->sig, &sa, NULL) != 0)
- __go_assert (0);
-}
+void setSigeventTID(struct sigevent*, int32_t)
+ __asm__ (GOSYM_PREFIX "runtime.setSigeventTID");
-GoSighandler*
-runtime_getsig (int32 i)
+void
+setSigeventTID(struct sigevent *sev, int32_t v)
{
- struct sigaction sa;
- int r;
- SigTab *t;
-
- memset (&sa, 0, sizeof sa);
+ sev->sigev_notify_thread_id = v;
+}
- r = sigemptyset (&sa.sa_mask);
- __go_assert (r == 0);
+#endif // defined(__linux__)
- t = &runtime_sigtab[i];
+// C code to fetch values from the siginfo_t and ucontext_t pointers
+// passed to a signal handler.
- if (sigaction (t->sig, NULL, &sa) != 0)
- runtime_throw ("sigaction read failure");
+uintptr getSiginfoCode(siginfo_t *)
+ __attribute__ ((no_split_stack));
- if ((void *) sa.sa_handler == sig_tramp_info)
- return runtime_sighandler;
-#ifdef SA_SIGINFO
- if ((void *) sa.sa_handler == sig_panic_info_handler)
- return runtime_sighandler;
-#else
- if ((void *) sa.sa_handler == sig_tramp
- || (void *) sa.sa_handler == sig_panic_handler)
- return runtime_sighandler;
-#endif
+uintptr getSiginfoCode(siginfo_t *)
+ __asm__ (GOSYM_PREFIX "runtime.getSiginfoCode");
- return (void *) sa.sa_handler;
+uintptr
+getSiginfoCode(siginfo_t *info)
+{
+ return (uintptr)(info->si_code);
}
-/* Used by the os package to raise SIGPIPE. */
+struct getSiginfoRet {
+ uintptr sigaddr;
+ uintptr sigpc;
+};
-void os_sigpipe (void) __asm__ (GOSYM_PREFIX "os.sigpipe");
+struct getSiginfoRet getSiginfo(siginfo_t *, void *)
+ __asm__(GOSYM_PREFIX "runtime.getSiginfo");
-void
-os_sigpipe (void)
+struct getSiginfoRet
+getSiginfo(siginfo_t *info, void *context __attribute__((unused)))
{
- struct sigaction sa;
- int i;
-
- memset (&sa, 0, sizeof sa);
-
- sa.sa_handler = SIG_DFL;
+ struct getSiginfoRet ret;
+ Location loc[1];
+ int32 n;
+
+ if (info == nil) {
+ ret.sigaddr = 0;
+ } else {
+ ret.sigaddr = (uintptr)(info->si_addr);
+ }
+ ret.sigpc = 0;
+
+ // There doesn't seem to be a portable way to get the PC.
+ // Use unportable code to pull it from context, and if that fails
+ // try a stack backtrace across the signal handler.
+
+#if defined(__x86_64__) && defined(__linux__)
+ ret.sigpc = ((ucontext_t*)(context))->uc_mcontext.gregs[REG_RIP];
+#elif defined(__i386__) && defined(__linux__)
+ ret.sigpc = ((ucontext_t*)(context))->uc_mcontext.gregs[REG_EIP];
+#elif defined(__alpha__) && defined(__linux__)
+ ret.sigpc = ((ucontext_t*)(context))->uc_mcontext.sc_pc;
+#elif defined(__PPC64__) && defined(__linux__)
+ ret.sigpc = ((ucontext_t*)(context))->uc_mcontext.gp_regs[32];
+#elif defined(__PPC__) && defined(__linux__)
+# if defined(__GLIBC__)
+ ret.sigpc = ((ucontext_t*)(context))->uc_mcontext.uc_regs->gregs[32];
+# else
+ ret.sigpc = ((ucontext_t*)(context))->uc_mcontext.gregs[32];
+# endif
+#elif defined(__PPC__) && defined(_AIX)
+ ret.sigpc = ((ucontext_t*)(context))->uc_mcontext.jmp_context.iar;
+#elif defined(__aarch64__) && defined(__linux__)
+ ret.sigpc = ((ucontext_t*)(context))->uc_mcontext.pc;
+#elif defined(__NetBSD__)
+ ret.sigpc = _UC_MACHINE_PC(((ucontext_t*)(context)));
+#endif
+
+ if (ret.sigpc == 0) {
+ // Skip getSiginfo/sighandler/sigtrampgo/sigtramp/handler.
+ n = runtime_callers(5, &loc[0], 1, false);
+ if (n > 0) {
+ ret.sigpc = loc[0].pc;
+ }
+ }
- i = sigemptyset (&sa.sa_mask);
- __go_assert (i == 0);
+ return ret;
+}
- if (sigaction (SIGPIPE, &sa, NULL) != 0)
- abort ();
+// Dump registers when crashing in a signal.
+// There is no portable way to write this,
+// so we just have some CPU/OS specific implementations.
- raise (SIGPIPE);
-}
+void dumpregs(siginfo_t *, void *)
+ __asm__(GOSYM_PREFIX "runtime.dumpregs");
void
-runtime_setprof(bool on)
+dumpregs(siginfo_t *info __attribute__((unused)), void *context __attribute__((unused)))
{
- USED(on);
+#if defined(__x86_64__) && defined(__linux__)
+ {
+ mcontext_t *m = &((ucontext_t*)(context))->uc_mcontext;
+
+ runtime_printf("rax %X\n", m->gregs[REG_RAX]);
+ runtime_printf("rbx %X\n", m->gregs[REG_RBX]);
+ runtime_printf("rcx %X\n", m->gregs[REG_RCX]);
+ runtime_printf("rdx %X\n", m->gregs[REG_RDX]);
+ runtime_printf("rdi %X\n", m->gregs[REG_RDI]);
+ runtime_printf("rsi %X\n", m->gregs[REG_RSI]);
+ runtime_printf("rbp %X\n", m->gregs[REG_RBP]);
+ runtime_printf("rsp %X\n", m->gregs[REG_RSP]);
+ runtime_printf("r8 %X\n", m->gregs[REG_R8]);
+ runtime_printf("r9 %X\n", m->gregs[REG_R9]);
+ runtime_printf("r10 %X\n", m->gregs[REG_R10]);
+ runtime_printf("r11 %X\n", m->gregs[REG_R11]);
+ runtime_printf("r12 %X\n", m->gregs[REG_R12]);
+ runtime_printf("r13 %X\n", m->gregs[REG_R13]);
+ runtime_printf("r14 %X\n", m->gregs[REG_R14]);
+ runtime_printf("r15 %X\n", m->gregs[REG_R15]);
+ runtime_printf("rip %X\n", m->gregs[REG_RIP]);
+ runtime_printf("rflags %X\n", m->gregs[REG_EFL]);
+ runtime_printf("cs %X\n", m->gregs[REG_CSGSFS] & 0xffff);
+ runtime_printf("fs %X\n", (m->gregs[REG_CSGSFS] >> 16) & 0xffff);
+ runtime_printf("gs %X\n", (m->gregs[REG_CSGSFS] >> 32) & 0xffff);
+ }
+#elif defined(__i386__) && defined(__linux__)
+ {
+ mcontext_t *m = &((ucontext_t*)(context))->uc_mcontext;
+
+ runtime_printf("eax %x\n", m->gregs[REG_EAX]);
+ runtime_printf("ebx %x\n", m->gregs[REG_EBX]);
+ runtime_printf("ecx %x\n", m->gregs[REG_ECX]);
+ runtime_printf("edx %x\n", m->gregs[REG_EDX]);
+ runtime_printf("edi %x\n", m->gregs[REG_EDI]);
+ runtime_printf("esi %x\n", m->gregs[REG_ESI]);
+ runtime_printf("ebp %x\n", m->gregs[REG_EBP]);
+ runtime_printf("esp %x\n", m->gregs[REG_ESP]);
+ runtime_printf("eip %x\n", m->gregs[REG_EIP]);
+ runtime_printf("eflags %x\n", m->gregs[REG_EFL]);
+ runtime_printf("cs %x\n", m->gregs[REG_CS]);
+ runtime_printf("fs %x\n", m->gregs[REG_FS]);
+ runtime_printf("gs %x\n", m->gregs[REG_GS]);
+ }
+#elif defined(__alpha__) && defined(__linux__)
+ {
+ mcontext_t *m = &((ucontext_t*)(context))->uc_mcontext;
+
+ runtime_printf("v0 %X\n", m->sc_regs[0]);
+ runtime_printf("t0 %X\n", m->sc_regs[1]);
+ runtime_printf("t1 %X\n", m->sc_regs[2]);
+ runtime_printf("t2 %X\n", m->sc_regs[3]);
+ runtime_printf("t3 %X\n", m->sc_regs[4]);
+ runtime_printf("t4 %X\n", m->sc_regs[5]);
+ runtime_printf("t5 %X\n", m->sc_regs[6]);
+ runtime_printf("t6 %X\n", m->sc_regs[7]);
+ runtime_printf("t7 %X\n", m->sc_regs[8]);
+ runtime_printf("s0 %X\n", m->sc_regs[9]);
+ runtime_printf("s1 %X\n", m->sc_regs[10]);
+ runtime_printf("s2 %X\n", m->sc_regs[11]);
+ runtime_printf("s3 %X\n", m->sc_regs[12]);
+ runtime_printf("s4 %X\n", m->sc_regs[13]);
+ runtime_printf("s5 %X\n", m->sc_regs[14]);
+ runtime_printf("fp %X\n", m->sc_regs[15]);
+ runtime_printf("a0 %X\n", m->sc_regs[16]);
+ runtime_printf("a1 %X\n", m->sc_regs[17]);
+ runtime_printf("a2 %X\n", m->sc_regs[18]);
+ runtime_printf("a3 %X\n", m->sc_regs[19]);
+ runtime_printf("a4 %X\n", m->sc_regs[20]);
+ runtime_printf("a5 %X\n", m->sc_regs[21]);
+ runtime_printf("t8 %X\n", m->sc_regs[22]);
+ runtime_printf("t9 %X\n", m->sc_regs[23]);
+ runtime_printf("t10 %X\n", m->sc_regs[24]);
+ runtime_printf("t11 %X\n", m->sc_regs[25]);
+ runtime_printf("ra %X\n", m->sc_regs[26]);
+ runtime_printf("t12 %X\n", m->sc_regs[27]);
+ runtime_printf("at %X\n", m->sc_regs[28]);
+ runtime_printf("gp %X\n", m->sc_regs[29]);
+ runtime_printf("sp %X\n", m->sc_regs[30]);
+ runtime_printf("pc %X\n", m->sc_pc);
+ }
+#elif defined(__PPC__) && defined(__linux__)
+ {
+ int i;
+
+# if defined(__PPC64__)
+ mcontext_t *m = &((ucontext_t*)(context))->uc_mcontext;
+
+ for (i = 0; i < 32; i++)
+ runtime_printf("r%d %X\n", i, m->gp_regs[i]);
+ runtime_printf("pc %X\n", m->gp_regs[32]);
+ runtime_printf("msr %X\n", m->gp_regs[33]);
+ runtime_printf("cr %X\n", m->gp_regs[38]);
+ runtime_printf("lr %X\n", m->gp_regs[36]);
+ runtime_printf("ctr %X\n", m->gp_regs[35]);
+ runtime_printf("xer %X\n", m->gp_regs[37]);
+# else
+# if defined(__GLIBC__)
+ mcontext_t *m = ((ucontext_t*)(context))->uc_mcontext.uc_regs;
+# else
+ mcontext_t *m = &((ucontext_t*)(context))->uc_mcontext;
+# endif
+
+ for (i = 0; i < 32; i++)
+ runtime_printf("r%d %x\n", i, m->gregs[i]);
+ runtime_printf("pc %x\n", m->gregs[32]);
+ runtime_printf("msr %x\n", m->gregs[33]);
+ runtime_printf("cr %x\n", m->gregs[38]);
+ runtime_printf("lr %x\n", m->gregs[36]);
+ runtime_printf("ctr %x\n", m->gregs[35]);
+ runtime_printf("xer %x\n", m->gregs[37]);
+# endif
+ }
+#elif defined(__PPC__) && defined(_AIX)
+ {
+ mcontext_t *m = &((ucontext_t*)(context))->uc_mcontext;
+ int i;
+
+ for (i = 0; i < 32; i++)
+ runtime_printf("r%d %p\n", i, m->jmp_context.gpr[i]);
+ runtime_printf("pc %p\n", m->jmp_context.iar);
+ runtime_printf("msr %p\n", m->jmp_context.msr);
+ runtime_printf("cr %x\n", m->jmp_context.cr);
+ runtime_printf("lr %p\n", m->jmp_context.lr);
+ runtime_printf("ctr %p\n", m->jmp_context.ctr);
+ runtime_printf("xer %x\n", m->jmp_context.xer);
+ }
+#elif defined(__aarch64__) && defined(__linux__)
+ {
+ mcontext_t *m = &((ucontext_t*)(context))->uc_mcontext;
+ int i;
+
+ for (i = 0; i < 31; i++)
+ runtime_printf("x%d %X\n", i, m->regs[i]);
+ runtime_printf("sp %X\n", m->sp);
+ runtime_printf("pc %X\n", m->pc);
+ runtime_printf("pstate %X\n", m->pstate);
+ }
+#endif
}