0.pre7.9:
[sbcl.git] / src / runtime / alpha-arch.c
index 001bc18..066355f 100644 (file)
@@ -136,7 +136,6 @@ unsigned long arch_install_breakpoint(void *pc)
     unsigned int *ptr = (unsigned int *)pc;
     unsigned long result = (unsigned long) *ptr;
     *ptr = BREAKPOINT_INST;
-    *(ptr+1)=trap_Breakpoint;
     
     os_flush_icache((os_vm_address_t)ptr, sizeof(unsigned long));
     
@@ -164,7 +163,6 @@ emulate_branch(os_context_t *context,unsigned long orig_inst)
   int op = orig_inst >> 26;
   int reg_a = (orig_inst >> 21) & 0x1f;
   int reg_b = (orig_inst >> 16) & 0x1f;
-  int fn = orig_inst & 0xffff;
   int disp = (orig_inst&(1<<20)) ? orig_inst | (-1 << 21) : orig_inst&0x1fffff;
   int next_pc = *os_context_pc_addr(context);
   int branch = 0; /* was NULL;        */
@@ -231,70 +229,101 @@ emulate_branch(os_context_t *context,unsigned long orig_inst)
 
 static sigset_t orig_sigmask;
 
+/* Perform the instruction that we overwrote with a breakpoint.  As we
+ * don't have a single-step facility, this means we have to:
+ * - put the instruction back
+ * - put a second breakpoint at the following instruction, 
+ *   set after_breakpoint and continue execution.
+ *
+ * When the second breakpoint is hit (very shortly thereafter, we hope)
+ * sigtrap_handler gets called again, but follows the AfterBreakpoint 
+ * arm, which 
+ * - puts a bpt back in the first breakpoint place (running across a 
+ *   breakpoint shouldn't cause it to be uninstalled)
+ * - replaces the second bpt with the instruction it was meant to be
+ * - carries on 
+ *
+ * Clear?
+ */
+
 void arch_do_displaced_inst(os_context_t *context,unsigned int orig_inst)
 {
+    /* Apparent off-by-one errors ahoy.  If you consult the Alpha ARM,
+     * it will tell you that after a BPT, the saved PC is the address
+     * of the instruction _after_ the instruction that caused the trap.
+     *
+     * However, we decremented PC by 4 before calling the Lisp-level
+     * handler that calls this routine (see alpha-arch.c line 322 and
+     * friends) so when we get to this point PC is actually pointing
+     * at the BPT instruction itself.  This is good, because this is
+     * where we want to restart execution when we do that */
+
   unsigned int *pc=(unsigned int *)(*os_context_pc_addr(context));
   unsigned int *next_pc;
-  unsigned int next_inst;
   int op = orig_inst >> 26;;
-  fprintf(stderr,"arch_do_displaced_inst depends on sigreturn, which is not implemented and will\nalways fail\n");
+
   orig_sigmask = *os_context_sigmask_addr(context);
   sigaddset_blockable(os_context_sigmask_addr(context));
 
-  /* Figure out where the displaced inst is going. */
-  if(op == 0x1a || (op&0xf) == 0x30) /* branch...ugh */
-    /* The cast to long is just to shut gcc up. */
-    next_pc = (unsigned int *)((long)emulate_branch(context,orig_inst));
-  else
-    next_pc = pc+1;
-
   /* Put the original instruction back. */
   *pc = orig_inst;
   os_flush_icache((os_vm_address_t)pc, sizeof(unsigned long));
   skipped_break_addr = pc;
 
+    /* Figure out where we will end up after running the displaced 
+     * instruction */
+    if(op == 0x1a || (op&0xf) == 0x30) /* a branch */
+       /* The cast to long is just to shut gcc up. */
+       next_pc = (unsigned int *)((long)emulate_branch(context,orig_inst));
+    else
+       next_pc = pc+1;
+    
   /* Set the after breakpoint. */
   displaced_after_inst = *next_pc;
   *next_pc = BREAKPOINT_INST;
   after_breakpoint=1;
   os_flush_icache((os_vm_address_t)next_pc, sizeof(unsigned long));
-
-  monitor_or_something();
-  sigreturn(context);
-}
-
-#define AfterBreakpoint 100
-
-static void
-sigill_handler(int signal, siginfo_t *siginfo, os_context_t *context) {
-    fake_foreign_function_call(context);
-    monitor_or_something();
 }
 
 static void
 sigtrap_handler(int signal, siginfo_t *siginfo, os_context_t *context)
 {
+    unsigned int code;
+
     /* Don't disallow recursive breakpoint traps.  Otherwise, we can't */
     /* use debugger breakpoints anywhere in here. */
-
     sigset_t *mask=(os_context_sigmask_addr(context));
-    unsigned int code;
-    fprintf(stderr,"sigtrap_handler:signal %d context=%p ",signal,context);
     sigsetmask(mask); 
 
-    /* this is different from how CMUCL does it.  CMUCL used
-     * "call_pal PAL_gentrap", which doesn't do anything on Linux
-     * so screwed up our offsets in odd ways.  We use "bpt" instead
-     */
-
-    /* probably we should
-    assert(*(unsigned int*)(*os_context_pc_addr(context)-4) == BREAKPOINT_INST)
-    but I've not decided a good way to handle it if it turns out not to be
-    */
+    /* this is different from how CMUCL does it.  CMUCL used "call_pal
+     * PAL_gentrap", which doesn't do anything on Linux (unless NL0
+     * contains certain specific values).  We use "bugchk" instead.
+     * It's (for our purposes) just the same as bpt but has a
+     * different opcode so we can test whether we're dealing with a
+     * breakpoint or a "system service" */
+
+    if((*(unsigned int*)(*os_context_pc_addr(context)-4))== BREAKPOINT_INST) {
+       if(after_breakpoint) {
+           /* see comments above arch_do_displaced_inst.  This is where
+            * we reinsert the breakpoint that we removed earlier */
+
+           *os_context_pc_addr(context) -=4;
+           *skipped_break_addr = BREAKPOINT_INST;
+           os_flush_icache((os_vm_address_t)skipped_break_addr,
+                           sizeof(unsigned long));
+           skipped_break_addr = NULL;
+           *(unsigned int *)*os_context_pc_addr(context) =
+               displaced_after_inst;
+           os_flush_icache((os_vm_address_t)*os_context_pc_addr(context), sizeof(unsigned long));
+           *os_context_sigmask_addr(context)= orig_sigmask;
+           after_breakpoint=0; /* false */
+           return;
+       } else 
+           code = trap_Breakpoint;
+    } else
+       /* a "system service" */
     code=*((u32 *)(*os_context_pc_addr(context)));
-    fprintf(stderr,"pc=%lx  code=%d, inst=%x\n",
-           *os_context_pc_addr(context),  code,
-           *(unsigned int*)(*os_context_pc_addr(context)-4));
+    
     switch (code) {
       case trap_PendingInterrupt:
        arch_skip_instruction(context);
@@ -310,43 +339,33 @@ sigtrap_handler(int signal, siginfo_t *siginfo, os_context_t *context)
        interrupt_internal_error(signal, siginfo, context, code==trap_Cerror);
        break;
 
-      case trap_Breakpoint:
+    case trap_Breakpoint:       /* call lisp-level handler */
         *os_context_pc_addr(context) -=4;
        handle_breakpoint(signal, siginfo, context);
        break;
 
       case trap_FunctionEndBreakpoint:
         *os_context_pc_addr(context) -=4;
-       *os_context_pc_addr(context) = (int)handle_function_end_breakpoint(signal, siginfo, context);
-       break;
-
-      case AfterBreakpoint:
-        *os_context_pc_addr(context) -=4;
-       *skipped_break_addr = BREAKPOINT_INST;
-       os_flush_icache((os_vm_address_t)skipped_break_addr,
-                       sizeof(unsigned long));
-       skipped_break_addr = NULL;
-       *(unsigned int *)*os_context_pc_addr(context) = displaced_after_inst;
-       os_flush_icache((os_vm_address_t)*os_context_pc_addr(context), sizeof(unsigned long));
-        *os_context_sigmask_addr(context)= orig_sigmask;
-        after_breakpoint=0; /* NULL; */
+       *os_context_pc_addr(context) =
+           (int)handle_function_end_breakpoint(signal, siginfo, context);
        break;
 
       default:
+       fprintf(stderr, "unidetified breakpoint/trap %d\n",code);
        interrupt_handle_now(signal, siginfo, context);
        break;
     }
 }
 
-#define FIXNUM_VALUE(lispobj) (((int)lispobj)>>2)
-
 static void sigfpe_handler(int signal, int code, os_context_t *context)
 {
+    /* what should this contain?  interesting question.  If it really
+     * is empty, why don't we just ignore the signal? -dan 2001.08.10
+     */
 }
 
 void arch_install_interrupt_handlers()
 {
-    undoably_install_low_level_interrupt_handler(SIGILL,  sigill_handler);
     undoably_install_low_level_interrupt_handler(SIGTRAP, sigtrap_handler);
     undoably_install_low_level_interrupt_handler(SIGFPE,  sigfpe_handler);
 }
@@ -393,12 +412,3 @@ lispobj funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
     return call_into_lisp(function, args, 3);
 }
 
-
-/* This is apparently called by emulate_branch, but isn't defined.  So */
-/* just do nothing and hope it works... */
-void cacheflush(void)
-{
-    /* hoping probably isn't _actually_ enough.  we should call_pal imb,
-       according to the arch ref manual
-    */
-}