1.0.36.9: UD2-BREAKPOINTS feature for x86oid systems
authorAlastair Bridgewater <lisphacker@users.sourceforge.net>
Mon, 1 Mar 2010 13:09:00 +0000 (13:09 +0000)
committerAlastair Bridgewater <lisphacker@users.sourceforge.net>
Mon, 1 Mar 2010 13:09:00 +0000 (13:09 +0000)
  * Add new feature UD2-BREAKPOINTS, enabled by default only on x86oid
darwin targets.

  * Use said feature instead of DARWIN for breakpoint trap selection.

  * Make breakpoints work when using UD2-BREAKPOINTS (tested on x86 and
x86-64 linux).

  * This patch brought to you by lp#309067, which remains valid for
three reasons: First, the test case is still disabled.  Second, this
only fixes for x86oids, not for PPC.  And third, I didn't actually test
this on a darwin system.

12 files changed:
NEWS
base-target-features.lisp-expr
make-config.sh
src/compiler/x86-64/insts.lisp
src/compiler/x86-64/macros.lisp
src/compiler/x86/insts.lisp
src/compiler/x86/macros.lisp
src/runtime/x86-64-arch.c
src/runtime/x86-64-assem.S
src/runtime/x86-arch.c
src/runtime/x86-assem.S
version.lisp-expr

diff --git a/NEWS b/NEWS
index 5484d8b..741dbcc 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -17,6 +17,10 @@ changes relative to sbcl-1.0.36:
   * bug fix: bogus style warnings from certain (SETF SLOT-VALUE) and
     WITH-SLOTS usages during compilation.
   * bug fix: SB-C::CLASS-INFO now prints correctly (lp#514762)
+  * enhancement: Can now build with ud2 instead of int3 as trap instruction on
+    all x86oid platforms (except win32) with :UD2-BREAKPOINTS target feature.
+  * bug fix: Breakpoints now work when using ud2 instead of int3 as trap
+    instruction (tested on x86oid linux with ud2-breakpoints).
 
 changes in sbcl-1.0.36 relative to sbcl-1.0.35:
   * new feature: SB-EXT:TYPEXPAND-1, SB-EXT:TYPEXPAND, and
index 60161d4..7bd7caf 100644 (file)
  ;; local storage.
  ; :restore-tls-segment-register-from-tls
 
+ ;; On some x86oid operating systems (darwin) SIGTRAP is not reliably
+ ;; delivered for the INT3 instruction, so we use the UD2 instruction
+ ;; which generates SIGILL instead.
+ ; :ud2-breakpoints
+
  ;; Support for detection of unportable code (when applied to the
  ;; COMMON-LISP package, or SBCL-internal pacakges) or bad-neighbourly
  ;; code (when applied to user-level packages), relating to material
index 5f250ec..9cbfa0d 100644 (file)
@@ -240,10 +240,10 @@ case "$sbcl_os" in
         printf ' :bsd' >> $ltf
         printf ' :darwin' >> $ltf
         if [ $sbcl_arch = "x86" ]; then
-            printf ' :mach-exception-handler :sb-lutex :restore-fs-segment-register-from-tls' >> $ltf
+            printf ' :mach-exception-handler :sb-lutex :restore-fs-segment-register-from-tls :ud2-breakpoints' >> $ltf
         fi
         if [ $sbcl_arch = "x86-64" ]; then
-            printf ' :mach-exception-handler :sb-lutex' >> $ltf
+            printf ' :mach-exception-handler :sb-lutex :ud2-breakpoints' >> $ltf
         fi
         link_or_copy $sbcl_arch-darwin-os.h target-arch-os.h
         link_or_copy bsd-os.h target-os.h
index 28ac794..b141f85 100644 (file)
 (defun break-control (chunk inst stream dstate)
   (declare (ignore inst))
   (flet ((nt (x) (if stream (sb!disassem:note x dstate))))
-    ;; FIXME: Make sure that BYTE-IMM-CODE is defined. The genesis
-    ;; map has it undefined; and it should be easier to look in the target
-    ;; Lisp (with (DESCRIBE 'BYTE-IMM-CODE)) than to definitively deduce
-    ;; from first principles whether it's defined in some way that genesis
-    ;; can't grok.
-    (case #!-darwin (byte-imm-code chunk dstate)
-          #!+darwin (word-imm-code chunk dstate)
+    ;; XXX: {BYTE,WORD}-IMM-CODE below is a macro defined by the
+    ;; DEFINE-INSTRUCTION-FORMAT for {BYTE,WORD}-IMM above.  Due to
+    ;; the spectacular design for DEFINE-INSTRUCTION-FORMAT (involving
+    ;; a call to EVAL in order to define the macros at compile-time
+    ;; only) they do not even show up as symbols in the target core.
+    (case #!-ud2-breakpoints (byte-imm-code chunk dstate)
+          #!+ud2-breakpoints (word-imm-code chunk dstate)
       (#.error-trap
        (nt "error trap")
        (sb!disassem:handle-break-args #'snarf-error-junk stream dstate))
 
 (define-instruction break (segment code)
   (:declare (type (unsigned-byte 8) code))
-  #!-darwin (:printer byte-imm ((op #b11001100)) '(:name :tab code)
-                     :control #'break-control)
-  #!+darwin (:printer word-imm ((op #b0000101100001111)) '(:name :tab code)
-                     :control #'break-control)
+  #!-ud2-breakpoints (:printer byte-imm ((op #b11001100)) '(:name :tab code)
+                               :control #'break-control)
+  #!+ud2-breakpoints (:printer word-imm ((op #b0000101100001111)) '(:name :tab code)
+                               :control #'break-control)
   (:emitter
-   #!-darwin (emit-byte segment #b11001100)
+   #!-ud2-breakpoints (emit-byte segment #b11001100)
    ;; On darwin, trap handling via SIGTRAP is unreliable, therefore we
    ;; throw a sigill with 0x0b0f instead and check for this in the
    ;; SIGILL handler and pass it on to the sigtrap handler if
    ;; appropriate
-   #!+darwin (emit-word segment #b0000101100001111)
+   #!+ud2-breakpoints (emit-word segment #b0000101100001111)
    (emit-byte segment code)))
 
 (define-instruction int (segment number)
index e591b24..675700f 100644 (file)
 ;;;; error code
 (defun emit-error-break (vop kind code values)
   (assemble ()
-    #!-darwin
+    #!-ud2-breakpoints
     (inst int 3)                  ; i386 breakpoint instruction
     ;; On Darwin, we need to use #x0b0f instead of int3 in order
     ;; to generate a SIGILL instead of a SIGTRAP as darwin/x86
     ;; handlers. Hopefully this will be fixed by Apple at a
     ;; later date. Do the same on x86-64 as we do on x86 until this gets
     ;; sorted out.
-    #!+darwin
+    #!+ud2-breakpoints
     (inst word #x0b0f)
     ;; The return PC points here; note the location for the debugger.
     (when vop
index 4edb1a4..c7e3005 100644 (file)
     ;; Lisp (with (DESCRIBE 'BYTE-IMM-CODE)) than to definitively deduce
     ;; from first principles whether it's defined in some way that genesis
     ;; can't grok.
-    (case #!-darwin (byte-imm-code chunk dstate)
-          #!+darwin (word-imm-code chunk dstate)
+    (case #!-ud2-breakpoints (byte-imm-code chunk dstate)
+          #!+ud2-breakpoints (word-imm-code chunk dstate)
       (#.error-trap
        (nt "error trap")
        (sb!disassem:handle-break-args #'snarf-error-junk stream dstate))
 
 (define-instruction break (segment code)
   (:declare (type (unsigned-byte 8) code))
-  #!-darwin (:printer byte-imm ((op #b11001100)) '(:name :tab code)
-                     :control #'break-control)
-  #!+darwin (:printer word-imm ((op #b0000101100001111)) '(:name :tab code)
-                     :control #'break-control)
+  #!-ud2-breakpoints (:printer byte-imm ((op #b11001100)) '(:name :tab code)
+                               :control #'break-control)
+  #!+ud2-breakpoints (:printer word-imm ((op #b0000101100001111)) '(:name :tab code)
+                               :control #'break-control)
   (:emitter
-   #!-darwin (emit-byte segment #b11001100)
+   #!-ud2-breakpoints (emit-byte segment #b11001100)
    ;; On darwin, trap handling via SIGTRAP is unreliable, therefore we
    ;; throw a sigill with 0x0b0f instead and check for this in the
    ;; SIGILL handler and pass it on to the sigtrap handler if
    ;; appropriate
-   #!+darwin (emit-word segment #b0000101100001111)
+   #!+ud2-breakpoints (emit-word segment #b0000101100001111)
    (emit-byte segment code)))
 
 (define-instruction int (segment number)
index af6f52d..18251b5 100644 (file)
 ;;;; error code
 (defun emit-error-break (vop kind code values)
   (assemble ()
-    #!-darwin
+    #!-ud2-breakpoints
     (inst int 3)                        ; i386 breakpoint instruction
     ;; CLH 20060314
     ;; On Darwin, we need to use #x0b0f instead of int3 in order
     ;; doesn't seem to be reliably firing SIGTRAP
     ;; handlers. Hopefully this will be fixed by Apple at a
     ;; later date.
-    #!+darwin
+    #!+ud2-breakpoints
     (inst word #x0b0f)
     ;; The return PC points here; note the location for the debugger.
     (when vop
index f3f414b..0612ce9 100644 (file)
 #include "genesis/symbol.h"
 
 #define BREAKPOINT_INST 0xcc    /* INT3 */
+#define UD2_INST 0x0b0f         /* UD2 */
+
+#ifndef LISP_FEATURE_UD2_BREAKPOINTS
+#define BREAKPOINT_WIDTH 1
+#else
+#define BREAKPOINT_WIDTH 2
+#endif
 
 unsigned long fast_random_state = 1;
 
@@ -155,8 +162,14 @@ arch_install_breakpoint(void *pc)
 {
     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;
 }
@@ -166,6 +179,9 @@ arch_remove_breakpoint(void *pc, unsigned int orig_inst)
 {
     *((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
@@ -183,8 +199,7 @@ arch_do_displaced_inst(os_context_t *context, unsigned int orig_inst)
     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:
@@ -209,14 +224,14 @@ arch_do_displaced_inst(os_context_t *context, unsigned int orig_inst)
 void
 arch_handle_breakpoint(os_context_t *context)
 {
-    --*os_context_pc_addr(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);
+    *os_context_pc_addr(context) -= BREAKPOINT_WIDTH;
     *os_context_pc_addr(context) =
         (unsigned long)handle_fun_end_breakpoint(context);
 }
@@ -236,8 +251,7 @@ sigtrap_handler(int signal, siginfo_t *info, os_context_t *context)
 {
     unsigned int trap;
 
-    if (single_stepping && (signal==SIGTRAP))
-    {
+    if (single_stepping) {
 #ifdef CANNOT_GET_TO_SINGLE_STEP_FLAG
         /* Un-install single step helper instructions. */
         *(single_stepping-3) = single_step_save1;
@@ -247,12 +261,13 @@ sigtrap_handler(int signal, siginfo_t *info, os_context_t *context)
         *context_eflags_addr(context) ^= 0x100;
 #endif
         /* Re-install the breakpoint if possible. */
-        if ((char *)*os_context_pc_addr(context) ==
-            (char *)single_stepping + 1) {
+        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 {
-            *((char *)single_stepping) = BREAKPOINT_INST;       /* x86 INT3 */
-            *((char *)single_stepping+1) = trap_Breakpoint;
+            arch_install_breakpoint(single_stepping);
         }
 
         single_stepping = NULL;
@@ -278,8 +293,8 @@ 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_DARWIN) && !defined(LISP_FEATURE_MACH_EXCEPTION_HANDLER)
-    if (*((unsigned short *)*os_context_pc_addr(context)) == 0x0b0f) {
+#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);
     }
index ac42010..388c3bf 100644 (file)
@@ -67,7 +67,7 @@
  * for this instruction in the SIGILL handler and if we see it, we
  * advance the EIP by two bytes to skip over ud2 instruction and
  * call sigtrap_handler. */
-#if defined(LISP_FEATURE_DARWIN)
+#if defined(LISP_FEATURE_UD2_BREAKPOINTS)
 #define TRAP ud2
 #else
 #define TRAP int3
index b9b5250..b000e0f 100644 (file)
 #include "genesis/symbol.h"
 
 #define BREAKPOINT_INST 0xcc    /* INT3 */
+#define UD2_INST 0x0b0f         /* UD2 */
+
+#ifndef LISP_FEATURE_UD2_BREAKPOINTS
+#define BREAKPOINT_WIDTH 1
+#else
+#define BREAKPOINT_WIDTH 2
+#endif
 
 unsigned long fast_random_state = 1;
 
@@ -158,8 +165,14 @@ arch_install_breakpoint(void *pc)
 {
     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;
 }
@@ -169,6 +182,9 @@ arch_remove_breakpoint(void *pc, unsigned int orig_inst)
 {
     *((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
@@ -186,8 +202,7 @@ arch_do_displaced_inst(os_context_t *context, unsigned int orig_inst)
     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:
@@ -222,11 +237,13 @@ restore_breakpoint_from_single_step(os_context_t * context)
     *context_eflags_addr(context) &= ~0x100;
 #endif
     /* Re-install the breakpoint if possible. */
-    if (*os_context_pc_addr(context) == (int)single_stepping + 1) {
+    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 {
-        *((char *)single_stepping) = BREAKPOINT_INST;       /* x86 INT3 */
-        *((char *)single_stepping+1) = trap_Breakpoint;
+        arch_install_breakpoint(single_stepping);
     }
 
     single_stepping = NULL;
@@ -236,14 +253,14 @@ restore_breakpoint_from_single_step(os_context_t * context)
 void
 arch_handle_breakpoint(os_context_t *context)
 {
-    --*os_context_pc_addr(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);
+    *os_context_pc_addr(context) -= BREAKPOINT_WIDTH;
     *os_context_pc_addr(context) =
         (int)handle_fun_end_breakpoint(context);
 }
@@ -263,7 +280,7 @@ sigtrap_handler(int signal, siginfo_t *info, os_context_t *context)
 {
     unsigned int trap;
 
-    if (single_stepping && (signal==SIGTRAP)) {
+    if (single_stepping) {
         restore_breakpoint_from_single_step(context);
         return;
     }
@@ -297,8 +314,8 @@ 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_DARWIN) && !defined(LISP_FEATURE_MACH_EXCEPTION_HANDLER)
-    if (*((unsigned short *)*os_context_pc_addr(context)) == 0x0b0f) {
+#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);
     }
index 37fcafa..8e0db32 100644 (file)
@@ -79,7 +79,7 @@
  * for this instruction in the SIGILL handler and if we see it, we
  * advance the EIP by two bytes to skip over ud2 instruction and
  * call sigtrap_handler. */
-#if defined(LISP_FEATURE_DARWIN)
+#if defined(LISP_FEATURE_UD2_BREAKPOINTS)
 #define END()
 #define TRAP ud2
 #else
index a8629a1..54ad299 100644 (file)
@@ -17,4 +17,4 @@
 ;;; checkins which aren't released. (And occasionally for internal
 ;;; versions, especially for internal versions off the main CVS
 ;;; branch, it gets hairier, e.g. "0.pre7.14.flaky4.13".)
-"1.0.36.8"
+"1.0.36.9"