#include "os.h"
#include "arch.h"
#include "lispregs.h"
-#include "signal.h"
#include "alloc.h"
#include "interrupt.h"
#include "interr.h"
#include "breakpoint.h"
-#include "monitor.h"
#include "thread.h"
+#include "pseudo-atomic.h"
#include "genesis/static-symbols.h"
#include "genesis/symbol.h"
#define BREAKPOINT_INST 0xcc /* INT3 */
+#define UD2_INST 0x0b0f /* UD2 */
-unsigned long fast_random_state = 1;
+#ifndef LISP_FEATURE_UD2_BREAKPOINTS
+#define BREAKPOINT_WIDTH 1
+#else
+#define BREAKPOINT_WIDTH 2
+#endif
void arch_init(void)
{}
#elif defined __OpenBSD__
return &context->sc_eflags;
#elif defined LISP_FEATURE_DARWIN
- return &context->uc_mcontext->ss.eflags;
+ return (int *)(&context->uc_mcontext->SS.EFLAGS);
#elif defined __NetBSD__
return &(context->uc_mcontext.__gregs[_REG_EFL]);
#elif defined LISP_FEATURE_WIN32
- return (int *)&context->EFlags;
+ return (int *)&context->win32_context->EFlags;
#else
#error unsupported OS
#endif
case trap_FunEndBreakpoint: /* not tested */
break;
+#ifdef LISP_FEATURE_SB_SAFEPOINT
+ case trap_GlobalSafepoint:
+ case trap_CspSafepoint:
+#endif
case trap_PendingInterrupt:
case trap_Halt:
+ case trap_SingleStepAround:
+ case trap_SingleStepBefore:
/* only needed to skip the Code */
break;
boolean
arch_pseudo_atomic_atomic(os_context_t *context)
{
- return SymbolValue(PSEUDO_ATOMIC_ATOMIC,arch_os_get_current_thread());
+ return get_pseudo_atomic_atomic(arch_os_get_current_thread());
}
void
arch_set_pseudo_atomic_interrupted(os_context_t *context)
{
- SetSymbolValue(PSEUDO_ATOMIC_INTERRUPTED, make_fixnum(1),
- arch_os_get_current_thread());
+ struct thread *thread = arch_os_get_current_thread();
+ set_pseudo_atomic_interrupted(thread);
}
void
arch_clear_pseudo_atomic_interrupted(os_context_t *context)
{
- SetSymbolValue(PSEUDO_ATOMIC_INTERRUPTED, make_fixnum(0),
- arch_os_get_current_thread());
+ struct thread *thread = arch_os_get_current_thread();
+ clear_pseudo_atomic_interrupted(thread);
}
\f
/*
{
unsigned int result = *(unsigned int*)pc;
+#ifndef LISP_FEATURE_UD2_BREAKPOINTS
*(char*)pc = BREAKPOINT_INST; /* x86 INT3 */
*((char*)pc+1) = trap_Breakpoint; /* Lisp trap code */
+#else
+ *(char*)pc = UD2_INST & 0xff;
+ *((char*)pc+1) = UD2_INST >> 8;
+ *((char*)pc+2) = trap_Breakpoint;
+#endif
return result;
}
{
*((char *)pc) = orig_inst & 0xff;
*((char *)pc + 1) = (orig_inst & 0xff00) >> 8;
+#if BREAKPOINT_WIDTH > 1
+ *((char *)pc + 2) = (orig_inst & 0xff0000) >> 16;
+#endif
}
\f
/* When single stepping, single_stepping holds the original instruction
unsigned int *pc = (unsigned int*)(*os_context_pc_addr(context));
/* Put the original instruction back. */
- *((char *)pc) = orig_inst & 0xff;
- *((char *)pc + 1) = (orig_inst & 0xff00) >> 8;
+ arch_remove_breakpoint(pc, orig_inst);
#ifdef CANNOT_GET_TO_SINGLE_STEP_FLAG
/* Install helper instructions for the single step:
single_stepping = pc;
#ifdef CANNOT_GET_TO_SINGLE_STEP_FLAG
- *os_context_pc_addr(context) = (char *)pc - 9;
+ *os_context_pc_addr(context) = (os_context_register_t)((char *)pc - 9);
#endif
}
\f
void
-sigtrap_handler(int signal, siginfo_t *info, void *void_context)
+restore_breakpoint_from_single_step(os_context_t * context)
{
- os_context_t *context = (os_context_t*)void_context;
- unsigned int trap;
-
-#ifndef LISP_FEATURE_WIN32
- if (single_stepping && (signal==SIGTRAP))
- {
- /* fprintf(stderr,"* single step trap %x\n", single_stepping); */
-
+ /* fprintf(stderr,"* single step trap %x\n", single_stepping); */
#ifdef CANNOT_GET_TO_SINGLE_STEP_FLAG
- /* Un-install single step helper instructions. */
- *(single_stepping-3) = single_step_save1;
- *(single_stepping-2) = single_step_save2;
- *(single_stepping-1) = single_step_save3;
+ /* Un-install single step helper instructions. */
+ *(single_stepping-3) = single_step_save1;
+ *(single_stepping-2) = single_step_save2;
+ *(single_stepping-1) = single_step_save3;
#else
- *context_eflags_addr(context) ^= 0x100;
+ *context_eflags_addr(context) &= ~0x100;
#endif
- /* Re-install the breakpoint if possible. */
- if (*os_context_pc_addr(context) == (int)single_stepping + 1) {
- fprintf(stderr, "warning: couldn't reinstall breakpoint\n");
- } else {
- *((char *)single_stepping) = BREAKPOINT_INST; /* x86 INT3 */
- *((char *)single_stepping+1) = trap_Breakpoint;
- }
+ /* Re-install the breakpoint if possible. */
+ if (((char *)*os_context_pc_addr(context) >
+ (char *)single_stepping) &&
+ ((char *)*os_context_pc_addr(context) <=
+ (char *)single_stepping + BREAKPOINT_WIDTH)) {
+ fprintf(stderr, "warning: couldn't reinstall breakpoint\n");
+ } else {
+ arch_install_breakpoint(single_stepping);
+ }
+
+ single_stepping = NULL;
+ return;
+}
+
+void
+arch_handle_breakpoint(os_context_t *context)
+{
+ *os_context_pc_addr(context) -= BREAKPOINT_WIDTH;
+ handle_breakpoint(context);
+}
+
+void
+arch_handle_fun_end_breakpoint(os_context_t *context)
+{
+ *os_context_pc_addr(context) -= BREAKPOINT_WIDTH;
+ *os_context_pc_addr(context) =
+ (int)handle_fun_end_breakpoint(context);
+}
+
+void
+arch_handle_single_step_trap(os_context_t *context, int trap)
+{
+ arch_skip_instruction(context);
+ /* On x86 the fdefn / function is always in EAX, so we pass 0
+ * as the register_offset. */
+ handle_single_step_trap(context, trap, 0);
+}
- single_stepping = NULL;
+#ifndef LISP_FEATURE_WIN32
+void
+sigtrap_handler(int signal, siginfo_t *info, os_context_t *context)
+{
+ unsigned int trap;
+
+ if (single_stepping) {
+ restore_breakpoint_from_single_step(context);
return;
}
-#endif
/* This is just for info in case the monitor wants to print an
* approximation. */
- current_control_stack_pointer =
+ access_control_stack_pointer(arch_os_get_current_thread()) =
(lispobj *)*os_context_sp_addr(context);
- /* FIXME: CMUCL puts the float control restoration code here.
- Thus, it seems to me that single-stepping won't restore the
- float control. Since SBCL currently doesn't support
- single-stepping (as far as I can tell) this is somewhat moot,
- but it might be worth either moving this code up or deleting
- the single-stepping code entirely. -- CSR, 2002-07-15 */
-#ifdef LISP_FEATURE_LINUX
- os_restore_fp_control(context);
+#ifdef LISP_FEATURE_SUNOS
+ /* For some reason the breakpoints that :ENCAPSULATE NIL tracing sets up
+ * cause a trace trap (i.e. processor single-stepping trap) on the following
+ * instruction on Solaris 10/x86. -- JES, 2006-04-07
+ */
+ if (info->si_code == TRAP_TRACE) {
+ lose("foo");
+ return;
+ }
#endif
/* On entry %eip points just after the INT3 byte and aims at the
* number of bytes will follow, the first is the length of the byte
* arguments to follow. */
trap = *(unsigned char *)(*os_context_pc_addr(context));
- /* FSHOW((stderr, "/<sigtrap trap %d at pc_addr: %p>\n", trap, *os_context_pc_addr(context))); */
- switch (trap) {
-
- case trap_PendingInterrupt:
- FSHOW((stderr, "/<trap pending interrupt>\n"));
- arch_skip_instruction(context);
- interrupt_handle_pending(context);
- break;
-
- case trap_Halt:
- /* Note: the old CMU CL code tried to save FPU state
- * here, and restore it after we do our thing, but there
- * seems to be no point in doing that, since we're just
- * going to lose(..) anyway. */
- fake_foreign_function_call(context);
- lose("%%PRIMITIVE HALT called; the party is over.\n");
-
- case trap_Error:
- case trap_Cerror:
- FSHOW((stderr, "<trap error/cerror %d>\n", trap));
- interrupt_internal_error(signal, info, context, trap==trap_Cerror);
- break;
-
- case trap_Breakpoint:
- --*os_context_pc_addr(context);
- handle_breakpoint(signal, info, context);
- break;
-
- case trap_FunEndBreakpoint:
- --*os_context_pc_addr(context);
- *os_context_pc_addr(context) =
- (int)handle_fun_end_breakpoint(signal, info, context);
- break;
-
- default:
- FSHOW((stderr,"/[C--trap default %d %d %x]\n",
- signal, trap, context));
- interrupt_handle_now(signal, info, context);
- break;
- }
+ handle_trap(context, trap);
}
-static void
-sigill_handler(int signal, siginfo_t *siginfo, void *void_context) {
- os_context_t *context = (os_context_t*)void_context;
+void
+sigill_handler(int signal, siginfo_t *siginfo, os_context_t *context) {
+ /* Triggering SIGTRAP using int3 is unreliable on OS X/x86, so
+ * we need to use illegal instructions for traps.
+ */
+#if defined(LISP_FEATURE_UD2_BREAKPOINTS) && !defined(LISP_FEATURE_MACH_EXCEPTION_HANDLER)
+ if (*((unsigned short *)*os_context_pc_addr(context)) == UD2_INST) {
+ *os_context_pc_addr(context) += 2;
+ return sigtrap_handler(signal, siginfo, context);
+ }
+#endif
fake_foreign_function_call(context);
- monitor_or_something();
+ lose("Unhandled SIGILL");
}
+#endif /* not LISP_FEATURE_WIN32 */
void
arch_install_interrupt_handlers()
* OS I haven't tested on?) and we have to go back to the old CMU
* CL way, I hope there will at least be a comment to explain
* why.. -- WHN 2001-06-07 */
-#ifndef LISP_FEATURE_WIN32
+#if !defined(LISP_FEATURE_WIN32) && !defined(LISP_FEATURE_MACH_EXCEPTION_HANDLER)
undoably_install_low_level_interrupt_handler(SIGILL , sigill_handler);
undoably_install_low_level_interrupt_handler(SIGTRAP, sigtrap_handler);
#endif
-
SHOW("returning from arch_install_interrupt_handlers()");
}
\f
-/* This is implemented in assembly language and called from C: */
-extern lispobj
-call_into_lisp(lispobj fun, lispobj *args, int nargs);
-
-/* These functions are an interface to the Lisp call-in facility.
- * Since this is C we can know nothing about the calling environment.
- * The control stack might be the C stack if called from the monitor
- * or the Lisp stack if called as a result of an interrupt or maybe
- * even a separate stack. The args are most likely on that stack but
- * could be in registers depending on what the compiler likes. So we
- * copy the args into a portable vector and let the assembly language
- * call-in function figure it out. */
-
-lispobj
-funcall0(lispobj function)
-{
- lispobj *args = NULL;
-
- FSHOW((stderr, "/entering funcall0(0x%lx)\n", (long)function));
- return call_into_lisp(function, args, 0);
-}
-lispobj
-funcall1(lispobj function, lispobj arg0)
-{
- lispobj args[1];
- args[0] = arg0;
- return call_into_lisp(function, args, 1);
-}
-lispobj
-funcall2(lispobj function, lispobj arg0, lispobj arg1)
-{
- lispobj args[2];
- args[0] = arg0;
- args[1] = arg1;
- return call_into_lisp(function, args, 2);
-}
-lispobj
-funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
-{
- lispobj args[3];
- args[0] = arg0;
- args[1] = arg1;
- args[2] = arg2;
- return call_into_lisp(function, args, 3);
-}
-
#ifdef LISP_FEATURE_LINKAGE_TABLE
/* FIXME: It might be cleaner to generate these from the lisp side of
* things.