Raymond Toy pushed to branch master at cmucl / cmucl

Commits:

9 changed files:

Changes:

  • src/code/x86-vm.lisp
    ... ... @@ -237,12 +237,20 @@
    237 237
       (with-alien ((scp (* unix:sigcontext) scp))
    
    238 238
         (let ((pc (sigcontext-program-counter scp)))
    
    239 239
           (declare (type system-area-pointer pc))
    
    240
    -      ;; using INT3 the pc is .. INT3 <here> code length bytes...
    
    241
    -      (let* ((length (sap-ref-8 pc 1))
    
    240
    +      ;; The pc should point to the start of the UD1 instruction.  So
    
    241
    +      ;; we have something like:
    
    242
    +      ;;
    
    243
    +      ;;   offset  contents
    
    244
    +      ;;   0       UD1 (contains the trap code)
    
    245
    +      ;;   3       length
    
    246
    +      ;;   4...    bytes
    
    247
    +      (let* ((length (sap-ref-8 pc 3))
    
    242 248
     	     (vector (make-array length :element-type '(unsigned-byte 8))))
    
    243 249
     	(declare (type (unsigned-byte 8) length)
    
    244 250
     		 (type (simple-array (unsigned-byte 8) (*)) vector))
    
    245
    -	(copy-from-system-area pc (* vm:byte-bits 2)
    
    251
    +	;; Grab bytes after the length byte where the number of bytes is
    
    252
    +	;; given by value of the length byte.
    
    253
    +	(copy-from-system-area pc (* vm:byte-bits 4)
    
    246 254
     			       vector (* vm:word-bits
    
    247 255
     					 vm:vector-data-offset)
    
    248 256
     			       (* length vm:byte-bits))
    

  • src/compiler/x86/insts.lisp
    ... ... @@ -1779,7 +1779,7 @@
    1779 1779
         (bit-test-reg/mem 24
    
    1780 1780
     		      :default-printer '(:name :tab reg/mem ", " reg))
    
    1781 1781
       (prefix	:field (byte 8 0)	:value #b0001111)
    
    1782
    -  (op		:field (byte 3 11))
    
    1782
    +  (op		:field (byte 8 8))
    
    1783 1783
       ;;(test		:fields (list (byte 2 14) (byte 3 8)))
    
    1784 1784
       (reg/mem	:fields (list (byte 2 22) (byte 3 16))
    
    1785 1785
     		:type 'reg/mem)
    
    ... ... @@ -1788,22 +1788,22 @@
    1788 1788
       (imm))
    
    1789 1789
     
    
    1790 1790
     (define-instruction bt (segment src index)
    
    1791
    -  (:printer bit-test-reg/mem ((op #b100)))
    
    1791
    +  (:printer bit-test-reg/mem ((op #b10100011)))
    
    1792 1792
       (:emitter
    
    1793 1793
        (emit-bit-test-and-mumble segment src index #b100)))
    
    1794 1794
     
    
    1795 1795
     (define-instruction btc (segment src index)
    
    1796
    -  (:printer bit-test-reg/mem ((op #b111)))
    
    1796
    +  (:printer bit-test-reg/mem ((op #b10111011)))
    
    1797 1797
       (:emitter
    
    1798 1798
        (emit-bit-test-and-mumble segment src index #b111)))
    
    1799 1799
     
    
    1800 1800
     (define-instruction btr (segment src index)
    
    1801
    -  (:printer bit-test-reg/mem ((op #b110)))
    
    1801
    +  (:printer bit-test-reg/mem ((op #b10110011)))
    
    1802 1802
       (:emitter
    
    1803 1803
        (emit-bit-test-and-mumble segment src index #b110)))
    
    1804 1804
     
    
    1805 1805
     (define-instruction bts (segment src index)
    
    1806
    -  (:printer bit-test-reg/mem ((op #b101)))
    
    1806
    +  (:printer bit-test-reg/mem ((op #b10101011)))
    
    1807 1807
       (:emitter
    
    1808 1808
        (emit-bit-test-and-mumble segment src index #b101)))
    
    1809 1809
     
    
    ... ... @@ -2061,6 +2061,26 @@
    2061 2061
      (op :field (byte 8 0))
    
    2062 2062
      (code :field (byte 8 8)))
    
    2063 2063
     
    
    2064
    +
    
    2065
    +;; The UD1 instruction.  The mod bits of the mod r/m byte MUST be #b11
    
    2066
    +;; so that the reg/mem field is actually a register.  This is a hack
    
    2067
    +;; to allow us to print out the reg/mem reg as a 32-bit reg.
    
    2068
    +;;
    
    2069
    +;; While the instruction looks like an ext-reg-reg/mem format with
    
    2070
    +;; fixed width value of 1, it isn't because we need to disassemble the
    
    2071
    +;; reg/mem field as a 32-bit reg. ext-reg-reg/mem needs a width prefix
    
    2072
    +;; byte to specify that, and we definitely don't want that.  Hence,
    
    2073
    +;; use a special instruction format for the UD1 instruction.
    
    2074
    +(disassem:define-instruction-format
    
    2075
    +    (ud1 24 :default-printer '(:name :tab reg ", " reg/mem))
    
    2076
    +  (prefix    :field (byte 8 0) :value #b00001111)
    
    2077
    +  (op        :field (byte 8 8) :value #b10111001)
    
    2078
    +  ;; The mod bits ensure that the reg/mem field is interpreted as a
    
    2079
    +  ;; register, not memory.
    
    2080
    +  (reg/mem   :field (byte 3 16) :type 'word-reg)
    
    2081
    +  (reg	     :field (byte 3 19) :type 'word-reg)
    
    2082
    +  (mod       :field (byte 2 22) :value #b11))
    
    2083
    +
    
    2064 2084
     (defun snarf-error-junk (sap offset &optional length-only)
    
    2065 2085
       (let* ((length (system:sap-ref-8 sap offset))
    
    2066 2086
              (vector (make-array length :element-type '(unsigned-byte 8))))
    
    ... ... @@ -2091,53 +2111,64 @@
    2091 2111
                            (sc-offsets)
    
    2092 2112
                            (lengths))))))))
    
    2093 2113
     
    
    2094
    -(defmacro break-cases (breaknum &body cases)
    
    2095
    -  (let ((bn-temp (gensym)))
    
    2096
    -    (collect ((clauses))
    
    2097
    -      (dolist (case cases)
    
    2098
    -        (clauses `((= ,bn-temp ,(car case)) ,@(cdr case))))
    
    2099
    -      `(let ((,bn-temp ,breaknum))
    
    2100
    -         (cond ,@(clauses))))))
    
    2101
    -
    
    2102
    -(defun break-control (chunk inst stream dstate)
    
    2114
    +(defun ud1-control (chunk inst stream dstate)
    
    2103 2115
       (declare (ignore inst))
    
    2104 2116
       (flet ((nt (x) (if stream (disassem:note x dstate))))
    
    2105
    -    (case (byte-imm-code chunk dstate)
    
    2106
    -      (#.vm:error-trap
    
    2107
    -       (nt "Error trap")
    
    2108
    -       (disassem:handle-break-args #'snarf-error-junk stream dstate))
    
    2109
    -      (#.vm:cerror-trap
    
    2110
    -       (nt "Cerror trap")
    
    2111
    -       (disassem:handle-break-args #'snarf-error-junk stream dstate))
    
    2112
    -      (#.vm:breakpoint-trap
    
    2113
    -       (nt "Breakpoint trap"))
    
    2114
    -      (#.vm:pending-interrupt-trap
    
    2115
    -       (nt "Pending interrupt trap"))
    
    2116
    -      (#.vm:halt-trap
    
    2117
    -       (nt "Halt trap"))
    
    2118
    -      (#.vm:function-end-breakpoint-trap
    
    2119
    -       (nt "Function end breakpoint trap"))
    
    2120
    -    )))
    
    2121
    -
    
    2122
    -;; This is really the int3 instruction.
    
    2123
    -(define-instruction break (segment code)
    
    2117
    +    (let ((code (ldb (byte 6 16) chunk)))
    
    2118
    +      (ecase code
    
    2119
    +	(#.vm:error-trap
    
    2120
    +	 (nt #.(format nil "Trap ~D: Error trap" vm:error-trap))
    
    2121
    +	 (disassem:handle-break-args #'snarf-error-junk stream dstate))
    
    2122
    +	(#.vm:cerror-trap
    
    2123
    +	 (nt #.(format nil "Trap ~D: Cerror trap" vm:cerror-trap))
    
    2124
    +	 (disassem:handle-break-args #'snarf-error-junk stream dstate))
    
    2125
    +	(#.vm:pending-interrupt-trap
    
    2126
    +	 (nt #.(format nil "Trap ~D: Pending interrupt trap" vm:pending-interrupt-trap)))
    
    2127
    +	(#.vm:halt-trap
    
    2128
    +	 (nt #.(format nil "Trap ~D: Halt trap" vm:halt-trap)))
    
    2129
    +	(#.vm:function-end-breakpoint-trap
    
    2130
    +	 (nt #.(format nil "Trap ~D: Function end breakpoint trap"
    
    2131
    +		       vm:function-end-breakpoint-trap)))))))
    
    2132
    +
    
    2133
    +;; The ud1 instruction where we smash the code (trap type) into the
    
    2134
    +;; low 6 bits of the mod r/m byte.  The mod bits are set to #b11 to
    
    2135
    +;; make sure the reg/mem part is interpreted to be a register and not
    
    2136
    +;; memory.
    
    2137
    +(define-instruction ud1 (segment code)
    
    2124 2138
       (:declare (type (unsigned-byte 8) code))
    
    2125
    -  (:printer byte-imm ((op #b11001100)) '(:name :tab code)
    
    2126
    -	    :control #'break-control)
    
    2139
    +  (:printer ud1 ((op #b10111001) (reg nil :type 'word-reg))
    
    2140
    +	    :default
    
    2141
    +	    :control #'ud1-control)
    
    2127 2142
       (:emitter
    
    2128
    -   (emit-byte segment #b11001100)
    
    2129
    -   (emit-byte segment code)))
    
    2143
    +   ;; We should not be using the breakpoint trap with UD1 anymore.
    
    2144
    +   ;; Breakpoint traps are handled in C now, using plain int3.
    
    2145
    +   (assert (/= code vm:breakpoint-trap))
    
    2130 2146
     
    
    2147
    +   ;; Emit the bytes of the instruction.
    
    2148
    +   (emit-byte segment #x0f)
    
    2149
    +   (emit-byte segment #xb9)
    
    2150
    +   (emit-mod-reg-r/m-byte segment
    
    2151
    +			  #b11
    
    2152
    +			  (ldb (byte 3 3) code)
    
    2153
    +			  (ldb (byte 3 0) code))))
    
    2154
    +
    
    2155
    +;; Handles both int and int3.  To get int3 you have to say (inst int
    
    2156
    +;; 3).  But int3 should not be used in Lisp code.  This is mainly so
    
    2157
    +;; that int3 gets disassembled correctly if a breakpoint has been set
    
    2158
    +;; in Lisp code.  (But in general the disassembly will be messed up
    
    2159
    +;; because the following byte will in general be the second byte of
    
    2160
    +;; some instruction, and not the first byte of an instruction.)
    
    2131 2161
     (define-instruction int (segment number)
    
    2132 2162
       (:declare (type (unsigned-byte 8) number))
    
    2133 2163
       (:printer byte-imm ((op #b11001101)))
    
    2134 2164
       (:emitter
    
    2135
    -   (etypecase number
    
    2136
    -     ((member 3)
    
    2137
    -      (emit-byte segment #b11001100))
    
    2138
    -     ((unsigned-byte 8)
    
    2139
    -      (emit-byte segment #b11001101)
    
    2140
    -      (emit-byte segment number)))))
    
    2165
    +   (emit-byte segment #b11001101)
    
    2166
    +   (emit-byte segment number)))
    
    2167
    +
    
    2168
    +(define-instruction int3 (segment)
    
    2169
    +  (:printer byte ((op #b11001100)))
    
    2170
    +  (:emitter
    
    2171
    +   (emit-byte segment #b11001100)))
    
    2141 2172
     
    
    2142 2173
     (define-instruction into (segment)
    
    2143 2174
       (:printer byte ((op #b11001110)))
    

  • src/compiler/x86/macros.lisp
    ... ... @@ -243,12 +243,10 @@
    243 243
       (defun emit-error-break (vop kind code values)
    
    244 244
         (let ((vector (gensym))
    
    245 245
     	  (length (gensym)))
    
    246
    -      `((inst int 3)				; i386 breakpoint instruction
    
    247
    -	;; The return PC points here; note the location for the debugger.
    
    248
    -	(let ((vop ,vop))
    
    246
    +      `((let ((vop ,vop))
    
    249 247
       	  (when vop
    
    250
    -		(note-this-location vop :internal-error)))
    
    251
    -	(inst byte ,kind)			; eg trap_Xyyy
    
    248
    +	    (note-this-location vop :internal-error)))
    
    249
    +	(inst ud1 ,kind)		; eg trap_Xyyy
    
    252 250
     	(let ((,vector (make-array 8 :element-type '(unsigned-byte 8)
    
    253 251
     				   :fill-pointer 0 :adjustable t)))
    
    254 252
     	  (write-var-integer (error-number-or-lose ',code) ,vector)
    
    ... ... @@ -342,7 +340,7 @@
    342 340
     				    (- other-pointer-type)))
    
    343 341
     	      0)
    
    344 342
     	(inst jmp :eq ,label)
    
    345
    -	(inst break pending-interrupt-trap)
    
    343
    +	(inst ud1 pending-interrupt-trap)
    
    346 344
     	(emit-label ,label)))))
    
    347 345
     
    
    348 346
     
    

  • src/compiler/x86/system.lisp
    ... ... @@ -284,11 +284,11 @@
    284 284
       (:policy :fast-safe)
    
    285 285
       (:translate unix::do-pending-interrupt)
    
    286 286
       (:generator 1
    
    287
    -    (inst break pending-interrupt-trap)))
    
    287
    +    (inst ud1 pending-interrupt-trap)))
    
    288 288
     
    
    289 289
     (define-vop (halt)
    
    290 290
       (:generator 1
    
    291
    -    (inst break halt-trap)))
    
    291
    +    (inst ud1 halt-trap)))
    
    292 292
     
    
    293 293
     (defknown float-wait () (values))
    
    294 294
     (define-vop (float-wait)
    

  • src/lisp/arch.h
    ... ... @@ -13,15 +13,39 @@
    13 13
     
    
    14 14
     extern char *arch_init(fpu_mode_t);
    
    15 15
     
    
    16
    +/*
    
    17
    + * Skip over the trap instructions for an error trap and also skip
    
    18
    + * over anly following bytes used to encode information for an
    
    19
    + * error-trap or cerror-trap.  The PC in the context is set to address
    
    20
    + * just past the trap instruction and data bytes (if any).
    
    21
    + */
    
    16 22
     extern void arch_skip_instruction(os_context_t * scp);
    
    23
    +
    
    17 24
     extern boolean arch_pseudo_atomic_atomic(os_context_t * scp);
    
    18 25
     extern void arch_set_pseudo_atomic_interrupted(os_context_t * scp);
    
    19 26
     extern os_vm_address_t arch_get_bad_addr(HANDLER_ARGS);
    
    20 27
     extern unsigned char *arch_internal_error_arguments(os_context_t * scp);
    
    28
    +
    
    29
    +/*
    
    30
    + * Install an architecture-dependent breakpoint instruction at the
    
    31
    + * given PC address.  This also returns the bytes that were
    
    32
    + * overwritten by the breakpoint instruction so that the original
    
    33
    + * instruction can be restored once the breakpoint has been handled.
    
    34
    + */
    
    21 35
     extern unsigned long arch_install_breakpoint(void *pc);
    
    36
    +
    
    22 37
     extern void arch_remove_breakpoint(void *pc, unsigned long orig_inst);
    
    23 38
     extern void arch_install_interrupt_handlers(void);
    
    39
    +
    
    40
    +/*
    
    41
    + * This is called when we need to continue after a breakpoint.  The
    
    42
    + * original instruction in |orig_inst| is put back.  Then things are
    
    43
    + * set up so that we can run again and after this instruction is run,
    
    44
    + * we trap again so that the original breakpoint can be replaced.  How
    
    45
    + * this is done is architecture-dependent.
    
    46
    + */
    
    24 47
     extern void arch_do_displaced_inst(os_context_t * scp, unsigned long orig_inst);
    
    48
    +
    
    25 49
     extern lispobj funcall0(lispobj function);
    
    26 50
     extern lispobj funcall1(lispobj function, lispobj arg0);
    
    27 51
     extern lispobj funcall2(lispobj function, lispobj arg0, lispobj arg1);
    

  • src/lisp/breakpoint.c
    ... ... @@ -192,6 +192,8 @@ compute_offset(os_context_t * scp, lispobj code, boolean function_end)
    192 192
     static int
    
    193 193
     compute_offset(os_context_t * scp, lispobj code, boolean function_end)
    
    194 194
     {
    
    195
    +    DPRINTF(debug_handlers, (stderr, "compute_offset: code = 0x%lx\n", code));
    
    196
    +    
    
    195 197
         if (code == NIL)
    
    196 198
     	return 0;
    
    197 199
         else {
    
    ... ... @@ -206,11 +208,20 @@ compute_offset(os_context_t * scp, lispobj code, boolean function_end)
    206 208
     
    
    207 209
     	code_start = (unsigned long) codeptr
    
    208 210
     	    + HeaderValue(codeptr->header) * sizeof(lispobj);
    
    211
    +
    
    212
    +        DPRINTF(debug_handlers,
    
    213
    +                (stderr, "compute_offset: pc = 0x%lx, code_start = 0x%lx\n",
    
    214
    +                 pc, code_start));
    
    215
    +        
    
    209 216
     	if (pc < code_start)
    
    210 217
     	    return 0;
    
    211 218
     	else {
    
    212 219
     	    int offset = pc - code_start;
    
    213 220
     
    
    221
    +            DPRINTF(debug_handlers,
    
    222
    +                    (stderr, "compute_offset: offset %d, size = %ld\n",
    
    223
    +                     offset, codeptr->code_size));
    
    224
    +            
    
    214 225
     	    if (offset >= codeptr->code_size) {
    
    215 226
                     return 0;
    
    216 227
     	    } else {
    
    ... ... @@ -250,6 +261,10 @@ handle_breakpoint(int signal, int subcode, os_context_t * scp)
    250 261
     
    
    251 262
         code = find_code(scp);
    
    252 263
     
    
    264
    +    DPRINTF(debug_handlers,
    
    265
    +            (stderr, "handle breakpoint: offset %d\n",
    
    266
    +             compute_offset(scp, code, 0)));
    
    267
    +    
    
    253 268
         /*
    
    254 269
          * Don't disallow recursive breakpoint traps.  Otherwise, we can't
    
    255 270
          * use debugger breakpoints anywhere in here.
    

  • src/lisp/x86-arch.c
    ... ... @@ -23,7 +23,19 @@
    23 23
     
    
    24 24
     #define BREAKPOINT_INST 0xcc	/* INT3 */
    
    25 25
     
    
    26
    -unsigned long fast_random_state = 1;
    
    26
    +/*
    
    27
    + * The first two bytes of the UD1 instruction.  The mod r/m byte isn't
    
    28
    + * included here.
    
    29
    + */
    
    30
    +static const unsigned char ud1[] = {0x0f, 0xb9};
    
    31
    +      
    
    32
    +
    
    33
    +/*
    
    34
    + * Set to positive value to enabled debug prints related to the sigill
    
    35
    + * and sigtrap handlers.  Also enables prints related to handling of
    
    36
    + * breakpoints.
    
    37
    + */
    
    38
    +unsigned int debug_handlers = 0;
    
    27 39
     
    
    28 40
     #if defined(SOLARIS)
    
    29 41
     /*
    
    ... ... @@ -129,32 +141,42 @@ arch_init(fpu_mode_t mode)
    129 141
     
    
    130 142
     
    
    131 143
     /*
    
    132
    - * Assuming we get here via an INT3 xxx instruction, the PC now
    
    133
    - * points to the interrupt code (lisp value) so we just move past
    
    134
    - * it. Skip the code, then if the code is an error-trap or
    
    135
    - * Cerror-trap then skip the data bytes that follow.
    
    144
    + * Skip the UD1 instruction, and any data bytes associated with the
    
    145
    + * trap.
    
    136 146
      */
    
    137
    -
    
    138 147
     void
    
    139 148
     arch_skip_instruction(os_context_t * context)
    
    140 149
     {
    
    141 150
         int vlen, code;
    
    142 151
     
    
    143
    -    DPRINTF(0, (stderr, "[arch_skip_inst at %lx>]\n", SC_PC(context)));
    
    152
    +    DPRINTF(debug_handlers,
    
    153
    +            (stderr, "[arch_skip_inst at %lx>]\n", SC_PC(context)));
    
    154
    +
    
    155
    +    /* Get the address of the beginning of the UD1 instruction */
    
    156
    +    char* pc = (char *) SC_PC(context);
    
    157
    +    
    
    158
    +    /*
    
    159
    +     * Skip over the part of the UD1 inst (0x0f, 0xb9) so we can get to the mod r/m byte
    
    160
    +     */
    
    161
    +    pc += sizeof(ud1);
    
    162
    +
    
    163
    +    code = *pc++;
    
    164
    +    SC_PC(context) = (unsigned long) pc;
    
    144 165
     
    
    145
    -    /* Get and skip the lisp error code. */
    
    146
    -    code = *(char *) SC_PC(context)++;
    
    147 166
         switch (code) {
    
    148 167
           case trap_Error:
    
    149 168
           case trap_Cerror:
    
    150 169
     	  /* Lisp error arg vector length */
    
    151
    -	  vlen = *(char *) SC_PC(context)++;
    
    170
    +          vlen = *pc++;
    
    171
    +          SC_PC(context) = (unsigned long) pc;
    
    172
    +          
    
    152 173
     	  /* Skip lisp error arg data bytes */
    
    153
    -	  while (vlen-- > 0)
    
    154
    -	      SC_PC(context)++;
    
    174
    +          SC_PC(context) = (unsigned long) (pc + vlen);
    
    155 175
     	  break;
    
    156 176
     
    
    157 177
           case trap_Breakpoint:
    
    178
    +          lose("Unexpected breakpoint trap in arch_skip_instruction\n");
    
    179
    +          break;
    
    158 180
           case trap_FunctionEndBreakpoint:
    
    159 181
     	  break;
    
    160 182
     
    
    ... ... @@ -168,7 +190,8 @@ arch_skip_instruction(os_context_t * context)
    168 190
     	  break;
    
    169 191
         }
    
    170 192
     
    
    171
    -    DPRINTF(0, (stderr, "[arch_skip_inst resuming at %lx>]\n", SC_PC(context)));
    
    193
    +    DPRINTF(debug_handlers,
    
    194
    +            (stderr, "[arch_skip_inst resuming at %lx>]\n", SC_PC(context)));
    
    172 195
     }
    
    173 196
     
    
    174 197
     unsigned char *
    
    ... ... @@ -191,13 +214,19 @@ arch_set_pseudo_atomic_interrupted(os_context_t * context)
    191 214
     
    
    192 215
     
    
    193 216
     
    
    217
    +/*
    
    218
    + * Installs a breakpoint (INT3) at |pc|.  We return the byte that was
    
    219
    + * replaced by the int3 instruction.
    
    220
    + */
    
    194 221
     unsigned long
    
    195 222
     arch_install_breakpoint(void *pc)
    
    196 223
     {
    
    197
    -    unsigned long result = *(unsigned long *) pc;
    
    224
    +    unsigned long result = *(unsigned char *) pc;
    
    225
    +    *(unsigned char *) pc = BREAKPOINT_INST;
    
    198 226
     
    
    199
    -    *(char *) pc = BREAKPOINT_INST;	/* x86 INT3       */
    
    200
    -    *((char *) pc + 1) = trap_Breakpoint;	/* Lisp trap code */
    
    227
    +    DPRINTF(debug_handlers,
    
    228
    +            (stderr, "arch_install_breakpoint at %p, old code = 0x%lx\n",
    
    229
    +             pc, result));
    
    201 230
     
    
    202 231
         return result;
    
    203 232
     }
    
    ... ... @@ -205,8 +234,14 @@ arch_install_breakpoint(void *pc)
    205 234
     void
    
    206 235
     arch_remove_breakpoint(void *pc, unsigned long orig_inst)
    
    207 236
     {
    
    208
    -    *((char *) pc) = orig_inst & 0xff;
    
    209
    -    *((char *) pc + 1) = (orig_inst & 0xff00) >> 8;
    
    237
    +    DPRINTF(debug_handlers,
    
    238
    +            (stderr, "arch_remove_breakpoint: %p orig %lx\n",
    
    239
    +             pc, orig_inst));
    
    240
    +
    
    241
    +    /*
    
    242
    +     * Just restore the byte from orig_inst.
    
    243
    +     */
    
    244
    +    *(unsigned char *) pc = orig_inst & 0xff;
    
    210 245
     }
    
    211 246
     
    
    212 247
     
    
    ... ... @@ -224,20 +259,44 @@ unsigned int single_step_save2;
    224 259
     unsigned int single_step_save3;
    
    225 260
     #endif
    
    226 261
     
    
    262
    +/*
    
    263
    + * This is called when we need to continue after a breakpoint.  This
    
    264
    + * works by putting the original byte back into the code, and then
    
    265
    + * enabling single-step mode to step one instruction.  When we return,
    
    266
    + * the instruction will get run and a sigtrap will get triggered when
    
    267
    + * the one instruction is done.
    
    268
    + *
    
    269
    + * TODO: Be more like other archs where the original inst is put back,
    
    270
    + * and the next inst is replaced with a afterBreakpoint trap.  When we
    
    271
    + * run, the afterBreakpoint trap is hit at the next instruction and
    
    272
    + * then we can put back the original breakpoint and replace the
    
    273
    + * afterBreakpoint trap with the original inst there too.
    
    274
    + *
    
    275
    + * For x86, this means computing how many bytes are used in the
    
    276
    + * current instruction, and then placing an int3 (or maybe ud1) after
    
    277
    + * it.
    
    278
    + */
    
    227 279
     void
    
    228 280
     arch_do_displaced_inst(os_context_t * context, unsigned long orig_inst)
    
    229 281
     {
    
    230
    -    unsigned int *pc = (unsigned int *) SC_PC(context);
    
    282
    +    unsigned char *pc = (unsigned char *) SC_PC(context);
    
    231 283
     
    
    284
    +    DPRINTF(debug_handlers,
    
    285
    +            (stderr, "arch_do_displaced_inst: pc %p orig_inst %lx\n",
    
    286
    +             pc, orig_inst));
    
    287
    +    
    
    232 288
         /*
    
    233 289
          * Put the original instruction back.
    
    234 290
          */
    
    235 291
     
    
    236
    -    *((char *) pc) = orig_inst & 0xff;
    
    237
    -    *((char *) pc + 1) = (orig_inst & 0xff00) >> 8;
    
    292
    +    *pc = orig_inst & 0xff;
    
    238 293
     
    
    294
    +    /*
    
    295
    +     * If we have the SC_EFLAGS macro, we can enable single-stepping
    
    296
    +     * by setting the bit.  Otherwise, we need a more complicated way
    
    297
    +     * of enabling single-stepping.
    
    298
    +     */
    
    239 299
     #ifdef SC_EFLAGS
    
    240
    -    /* Enable single-stepping */
    
    241 300
         SC_EFLAGS(context) |= 0x100;
    
    242 301
     #else
    
    243 302
     
    
    ... ... @@ -274,53 +333,31 @@ arch_do_displaced_inst(os_context_t * context, unsigned long orig_inst)
    274 333
     }
    
    275 334
     
    
    276 335
     
    
    336
    +/*
    
    337
    + * Handles the ud1 instruction from lisp that is used to signal
    
    338
    + * errors.  In particular, this does not handle the breakpoint traps.
    
    339
    + */
    
    277 340
     void
    
    278
    -sigtrap_handler(HANDLER_ARGS)
    
    341
    +sigill_handler(HANDLER_ARGS)
    
    279 342
     {
    
    280 343
         unsigned int trap;
    
    281 344
         os_context_t* os_context = (os_context_t *) context;
    
    282
    -#if 0
    
    283
    -    fprintf(stderr, "x86sigtrap: %8x %x\n",
    
    284
    -            SC_PC(os_os_context), *(unsigned char *) (SC_PC(os_context) - 1));
    
    285
    -    fprintf(stderr, "sigtrap(%d %d %x)\n", signal, CODE(code), os_context);
    
    286
    -#endif
    
    287 345
     
    
    288
    -    if (single_stepping && (signal == SIGTRAP)) {
    
    289
    -#if 0
    
    290
    -	fprintf(stderr, "* Single step trap %p\n", single_stepping);
    
    291
    -#endif
    
    292
    -
    
    293
    -#ifdef SC_EFLAGS
    
    294
    -	/* Disable single-stepping */
    
    295
    -	SC_EFLAGS(os_context) ^= 0x100;
    
    296
    -#else
    
    297
    -	/* Un-install single step helper instructions. */
    
    298
    -	*(single_stepping - 3) = single_step_save1;
    
    299
    -	*(single_stepping - 2) = single_step_save2;
    
    300
    -	*(single_stepping - 1) = single_step_save3;
    
    301
    -        DPRINTF(0, (stderr, "Uninstalling helper instructions\n"));
    
    302
    -#endif
    
    303
    -
    
    304
    -	/*
    
    305
    -	 * Re-install the breakpoint if possible.
    
    306
    -	 */
    
    307
    -	if ((int) SC_PC(os_context) == (int) single_stepping + 1)
    
    308
    -	    fprintf(stderr, "* Breakpoint not re-install\n");
    
    309
    -	else {
    
    310
    -	    char *ptr = (char *) single_stepping;
    
    311
    -
    
    312
    -	    ptr[0] = BREAKPOINT_INST;	/* x86 INT3 */
    
    313
    -	    ptr[1] = trap_Breakpoint;
    
    314
    -	}
    
    315
    -
    
    316
    -	single_stepping = NULL;
    
    317
    -	return;
    
    318
    -    }
    
    346
    +    DPRINTF(debug_handlers,
    
    347
    +            (stderr,"sigill: fp=%lx sp=%lx pc=%lx { %x, %x, %x, %x, %x }\n",
    
    348
    +             SC_REG(context, reg_FP),
    
    349
    +             SC_REG(context, reg_SP),
    
    350
    +             SC_PC(context),
    
    351
    +             *((unsigned char*)SC_PC(context) + 0), /* 0x0F */
    
    352
    +             *((unsigned char*)SC_PC(context) + 1), /* 0x0B */
    
    353
    +             *((unsigned char*)SC_PC(context) + 2),
    
    354
    +             *((unsigned char*)SC_PC(context) + 3),
    
    355
    +             *((unsigned char*)SC_PC(context) + 4)));
    
    319 356
     
    
    357
    +    
    
    320 358
         /* This is just for info in case monitor wants to print an approx */
    
    321 359
         current_control_stack_pointer = (unsigned long *) SC_SP(os_context);
    
    322 360
     
    
    323
    -
    
    324 361
         /*
    
    325 362
          * In many places in the switch below, we eventually throw instead
    
    326 363
          * of returning from the signal handler.  So, just in case, set
    
    ... ... @@ -329,86 +366,181 @@ sigtrap_handler(HANDLER_ARGS)
    329 366
         RESTORE_FPU(os_context);
    
    330 367
     
    
    331 368
         /*
    
    332
    -     * On entry %eip points just after the INT3 byte and aims at the
    
    333
    -     * 'kind' value (eg trap_Cerror). For error-trap and Cerror-trap a
    
    334
    -     * number of bytes will follow, the first is the length of the byte
    
    335
    -     * arguments to follow.
    
    369
    +     * On entry %eip points just to the beginning of the UD1
    
    370
    +     * instruction.  For error-trap and cerror-trap a number of bytes
    
    371
    +     * will follow, the first is the length of the byte arguments to
    
    372
    +     * follow.
    
    336 373
          */
    
    337 374
     
    
    338
    -    trap = *(unsigned char *) SC_PC(os_context);
    
    375
    +    DPRINTF(debug_handlers,
    
    376
    +            (stderr, "pc %x\n",  *(unsigned short *)SC_PC(context)));
    
    339 377
     
    
    340
    -    switch (trap) {
    
    378
    +    /*
    
    379
    +     * If the trapping instruction is UD1, assume it's a Lisp trap
    
    380
    +     * that we handle here.  Otherwise, just call interrupt_handle_now
    
    381
    +     * for other cases.
    
    382
    +     */
    
    383
    +    if (memcmp((void *)SC_PC(context), ud1, sizeof(ud1)) == 0) {
    
    384
    +      /*
    
    385
    +       * This must match what the lisp code is doing.  The trap
    
    386
    +       * number is placed in the low 6-bits of the 3rd byte of the
    
    387
    +       * instruction.
    
    388
    +       */
    
    389
    +      trap = *(((char *)SC_PC(context)) + 2) & 0x3f;
    
    390
    +
    
    391
    +      DPRINTF(debug_handlers, (stderr, "code = %x\n", trap));
    
    392
    +
    
    393
    +      switch (trap) {
    
    341 394
           case trap_PendingInterrupt:
    
    342
    -	  DPRINTF(0, (stderr, "<trap Pending Interrupt.>\n"));
    
    343
    -	  arch_skip_instruction(os_context);
    
    344
    -	  interrupt_handle_pending(os_context);
    
    345
    -	  break;
    
    395
    +        DPRINTF(debug_handlers, (stderr, "<trap Pending Interrupt.>\n"));
    
    396
    +        arch_skip_instruction(os_context);
    
    397
    +        interrupt_handle_pending(os_context);
    
    398
    +        break;
    
    346 399
     
    
    347 400
           case trap_Halt:
    
    348
    -	  {
    
    349
    -              FPU_STATE(fpu_state);
    
    350
    -              save_fpu_state(fpu_state);
    
    401
    +        {
    
    402
    +          FPU_STATE(fpu_state);
    
    403
    +          save_fpu_state(fpu_state);
    
    351 404
     
    
    352
    -	      fake_foreign_function_call(os_context);
    
    353
    -	      lose("%%primitive halt called; the party is over.\n");
    
    354
    -	      undo_fake_foreign_function_call(os_context);
    
    405
    +          fake_foreign_function_call(os_context);
    
    406
    +          lose("%%primitive halt called; the party is over.\n");
    
    407
    +          undo_fake_foreign_function_call(os_context);
    
    355 408
     
    
    356
    -              restore_fpu_state(fpu_state);
    
    357
    -	      arch_skip_instruction(os_context);
    
    358
    -	      break;
    
    359
    -	  }
    
    409
    +          restore_fpu_state(fpu_state);
    
    410
    +          arch_skip_instruction(os_context);
    
    411
    +          break;
    
    412
    +        }
    
    360 413
     
    
    361 414
           case trap_Error:
    
    362 415
           case trap_Cerror:
    
    363
    -	  DPRINTF(0, (stderr, "<trap Error %x>\n", CODE(code)));
    
    364
    -	  interrupt_internal_error(signal, code, os_context, CODE(code) == trap_Cerror);
    
    365
    -	  break;
    
    416
    +        DPRINTF(debug_handlers, (stderr, "<trap Error %x>\n", CODE(code)));
    
    417
    +        interrupt_internal_error(signal, code, os_context, CODE(code) == trap_Cerror);
    
    418
    +        break;
    
    366 419
     
    
    367 420
           case trap_Breakpoint:
    
    368
    -#if 0
    
    369
    -	  fprintf(stderr, "*C break\n");
    
    370
    -#endif
    
    371
    -	  SC_PC(os_context) -= 1;
    
    372
    -
    
    373
    -	  handle_breakpoint(signal, CODE(code), os_context);
    
    374
    -#if 0
    
    375
    -	  fprintf(stderr, "*C break return\n");
    
    376
    -#endif
    
    377
    -	  break;
    
    421
    +        lose("Unexpected breakpoint trap in sigill-hander.\n");
    
    422
    +        break;
    
    378 423
     
    
    379 424
           case trap_FunctionEndBreakpoint:
    
    380
    -	  SC_PC(os_context) -= 1;
    
    381
    -	  SC_PC(os_context) =
    
    382
    -	      (int) handle_function_end_breakpoint(signal, CODE(code), os_context);
    
    383
    -	  break;
    
    425
    +        SC_PC(os_context) =
    
    426
    +          (int) handle_function_end_breakpoint(signal, CODE(code), os_context);
    
    427
    +        break;
    
    384 428
     
    
    385 429
     #ifdef trap_DynamicSpaceOverflowWarning
    
    386 430
           case trap_DynamicSpaceOverflowWarning:
    
    387
    -	  interrupt_handle_space_overflow(SymbolFunction
    
    388
    -					  (DYNAMIC_SPACE_OVERFLOW_WARNING_HIT),
    
    389
    -					  os_context);
    
    390
    -	  break;
    
    431
    +        interrupt_handle_space_overflow(SymbolFunction
    
    432
    +                                        (DYNAMIC_SPACE_OVERFLOW_WARNING_HIT),
    
    433
    +                                        os_context);
    
    434
    +        break;
    
    391 435
     #endif
    
    392 436
     #ifdef trap_DynamicSpaceOverflowError
    
    393 437
           case trap_DynamicSpaceOverflowError:
    
    394
    -	  interrupt_handle_space_overflow(SymbolFunction
    
    395
    -					  (DYNAMIC_SPACE_OVERFLOW_ERROR_HIT),
    
    396
    -					  os_context);
    
    397
    -	  break;
    
    438
    +        interrupt_handle_space_overflow(SymbolFunction
    
    439
    +                                        (DYNAMIC_SPACE_OVERFLOW_ERROR_HIT),
    
    440
    +                                        os_context);
    
    441
    +        break;
    
    398 442
     #endif
    
    399 443
           default:
    
    400
    -	  DPRINTF(0,
    
    401
    -		  (stderr, "[C--trap default %d %d %p]\n", signal, CODE(code),
    
    402
    -		   os_context));
    
    403
    -	  interrupt_handle_now(signal, code, os_context);
    
    404
    -	  break;
    
    444
    +        DPRINTF(debug_handlers,
    
    445
    +                (stderr, "[C--trap default %d %d %p]\n", signal, CODE(code),
    
    446
    +                 os_context));
    
    447
    +        interrupt_handle_now(signal, code, os_context);
    
    448
    +        break;
    
    449
    +      }
    
    450
    +    } else {
    
    451
    +      interrupt_handle_now(signal, code, os_context);
    
    452
    +    }
    
    453
    +}
    
    454
    +
    
    455
    +/*
    
    456
    + * Handles the breakpoint trap (int3) and also single-stepping
    
    457
    + */
    
    458
    +void
    
    459
    +sigtrap_handler(HANDLER_ARGS) 
    
    460
    +{
    
    461
    +    os_context_t* os_context = (os_context_t *) context;
    
    462
    +
    
    463
    +    DPRINTF(debug_handlers,
    
    464
    +            (stderr,"sigtrap: fp=%lx sp=%lx pc=%lx { %x, %x, %x, %x, %x }\n",
    
    465
    +             SC_REG(context, reg_FP),
    
    466
    +             SC_REG(context, reg_SP),
    
    467
    +             SC_PC(context),
    
    468
    +             *((unsigned char*)SC_PC(context) + 0), /* 0x0F */
    
    469
    +             *((unsigned char*)SC_PC(context) + 1), /* 0x0B */
    
    470
    +             *((unsigned char*)SC_PC(context) + 2),
    
    471
    +             *((unsigned char*)SC_PC(context) + 3),
    
    472
    +             *(unsigned char*)(SC_PC(context) + 4)));
    
    473
    +
    
    474
    +    if (single_stepping) {
    
    475
    +        /*
    
    476
    +         * We were single-stepping so we now need to disable
    
    477
    +         * single-stepping.  We want to put back the breakpoint (int3)
    
    478
    +         * instruction so that the next time the breakpoint will be
    
    479
    +         * hit again as expected.
    
    480
    +         */
    
    481
    +	DPRINTF(debug_handlers, (stderr, "* Single step trap %p\n", single_stepping));
    
    482
    +
    
    483
    +#ifdef SC_EFLAGS
    
    484
    +	/* Disable single-stepping */
    
    485
    +	SC_EFLAGS(os_context) ^= 0x100;
    
    486
    +#else
    
    487
    +	/* Un-install single step helper instructions. */
    
    488
    +	*(single_stepping - 3) = single_step_save1;
    
    489
    +	*(single_stepping - 2) = single_step_save2;
    
    490
    +	*(single_stepping - 1) = single_step_save3;
    
    491
    +        DPRINTF(0, (stderr, "Uninstalling helper instructions\n"));
    
    492
    +#endif
    
    493
    +
    
    494
    +	/*
    
    495
    +	 * Re-install the breakpoint if possible.
    
    496
    +	 */
    
    497
    +        DPRINTF(debug_handlers,
    
    498
    +                (stderr, "* Maybe reinstall breakpoint for pc %p with single_stepping %p\n",
    
    499
    +                 (void*) SC_PC(os_context), single_stepping));
    
    500
    +        
    
    501
    +        /*
    
    502
    +         * Lose if single-stepping didn't move us past where the
    
    503
    +         * breakpoint instruction was inserted.
    
    504
    +         */
    
    505
    +        if ((unsigned long) SC_PC(os_context) <= (unsigned long) single_stepping) {
    
    506
    +            lose("Single-stepping did not advance past the breakpoint at %p\n",
    
    507
    +                 single_stepping);
    
    508
    +        }
    
    509
    +
    
    510
    +        /*
    
    511
    +         * Put back the breakpoint since we skipped over it.
    
    512
    +         */
    
    513
    +        char *ptr = (char *) single_stepping;
    
    514
    +        ptr[0] = BREAKPOINT_INST;	/* x86 INT3 */
    
    515
    +
    
    516
    +	single_stepping = NULL;
    
    517
    +	return;
    
    405 518
         }
    
    519
    +
    
    520
    +    /*
    
    521
    +     * We weren't single-stepping, so this we've just hit the breakpoint (int3).  Handle it.
    
    522
    +     */
    
    523
    +    DPRINTF(debug_handlers, (stderr, "*C break\n"));
    
    524
    +
    
    525
    +    /*
    
    526
    +     * The int3 instruction causes a trap that leaves us just after
    
    527
    +     * the instruction.  Backup one so we're at the beginning.  This
    
    528
    +     * is really important so that when we handle the breakpoint, the
    
    529
    +     * offset of the instruction matches where Lisp thinks the
    
    530
    +     * breakpoint was placed.
    
    531
    +     */
    
    532
    +    SC_PC(os_context) -= 1;
    
    533
    +
    
    534
    +    handle_breakpoint(signal, CODE(code), os_context);
    
    535
    +
    
    536
    +    DPRINTF(debug_handlers, (stderr, "*C break return\n"));
    
    406 537
     }
    
    407 538
     
    
    539
    +
    
    408 540
     void
    
    409 541
     arch_install_interrupt_handlers(void)
    
    410 542
     {
    
    411
    -    interrupt_install_low_level_handler(SIGILL, sigtrap_handler);
    
    543
    +    interrupt_install_low_level_handler(SIGILL, sigill_handler);
    
    412 544
         interrupt_install_low_level_handler(SIGTRAP, sigtrap_handler);
    
    413 545
     }
    
    414 546
     
    

  • src/lisp/x86-arch.h
    ... ... @@ -11,6 +11,13 @@
    11 11
     extern int arch_support_sse2(void);
    
    12 12
     extern boolean os_support_sse2(void);
    
    13 13
     
    
    14
    +/*
    
    15
    + * Set to non-zero to enable debug prints for debugging the sigill and
    
    16
    + * sigtrap handlers and for debugging breakpoints.
    
    17
    + */
    
    18
    +extern unsigned int debug_handlers;
    
    19
    +
    
    20
    +
    
    14 21
     /*
    
    15 22
      * Define macro to allocate a local array of the appropriate size
    
    16 23
      * where the fpu state can be stored.
    

  • src/lisp/x86-assem.S
    ... ... @@ -18,6 +18,21 @@
    18 18
     #include "internals.h"
    
    19 19
     #include "lispregs.h"
    
    20 20
     
    
    21
    +/*
    
    22
    + * Emit the appropriate instruction used for implementing traps.
    
    23
    + * Currently, this is the UD1 instruction.  However, it make it
    
    24
    + * easy to add the trap code, use a sequence of bytes.  The code
    
    25
    + * is smashed into the mod r/m byte with the mod bits set to
    
    26
    + * #b11.  This MUST be coordinated with the Lisp code and the C
    
    27
    + * code.
    
    28
    + *
    
    29
    + * Also, clang doesn't recognize the ud1 instruction.
    
    30
    + */
    
    31
    +#define UD1(code) \
    
    32
    +	.byte 0x0f		; \
    
    33
    +	.byte 0xb9		; \
    
    34
    +	.byte 0xc0 + code
    
    35
    +
    
    21 36
     /* Minimize conditionalization for different OS naming schemes */
    
    22 37
     #ifdef DARWIN	
    
    23 38
     #define GNAME(var) _##var
    
    ... ... @@ -244,8 +259,7 @@ ENDFUNC(sse_restore)
    244 259
      * The undefined-function trampoline.
    
    245 260
      */
    
    246 261
     FUNCDEF(undefined_tramp)
    
    247
    -	INT3
    
    248
    -	.byte	trap_Error
    
    262
    +	UD1(trap_Error)
    
    249 263
             /* Number of argument bytes */
    
    250 264
             .byte   2
    
    251 265
     	.byte	UNDEFINED_SYMBOL_ERROR
    
    ... ... @@ -286,32 +300,28 @@ multiple_value_return:
    286 300
     	
    
    287 301
     	.globl GNAME(function_end_breakpoint_trap)
    
    288 302
     GNAME(function_end_breakpoint_trap):
    
    289
    -	INT3
    
    290
    -	.byte 	trap_FunctionEndBreakpoint
    
    303
    +	UD1(trap_FunctionEndBreakpoint)
    
    291 304
     	hlt			# Should never return here.
    
    305
    +ENDFUNC(function_end_breakpoint_trap)
    
    292 306
     
    
    293 307
     	.globl GNAME(function_end_breakpoint_end)
    
    294 308
     GNAME(function_end_breakpoint_end):
    
    295 309
     
    
    296
    -
    
    297 310
     FUNCDEF(do_pending_interrupt)
    
    298
    -	INT3
    
    299
    -	.byte 	trap_PendingInterrupt
    
    311
    +	UD1(trap_PendingInterrupt)
    
    300 312
     	ret
    
    301 313
     ENDFUNC(do_pending_interrupt)
    
    302 314
     	
    
    303 315
     #ifdef trap_DynamicSpaceOverflowError
    
    304 316
     FUNCDEF(do_dynamic_space_overflow_error)
    
    305
    -	INT3
    
    306
    -	.byte 	trap_DynamicSpaceOverflowError
    
    317
    +	UD1(trap_DynamicSpaceOverflowError)
    
    307 318
     	ret
    
    308 319
     ENDFUNC(do_dynamic_space_overflow_error)
    
    309 320
     #endif				
    
    310 321
     	
    
    311 322
     #ifdef trap_DynamicSpaceOverflowWarning
    
    312 323
     FUNCDEF(do_dynamic_space_overflow_warning)
    
    313
    -	INT3
    
    314
    -	.byte 	trap_DynamicSpaceOverflowWarning
    
    324
    +	UD1(trap_DynamicSpaceOverflowWarning)
    
    315 325
     	ret
    
    316 326
     ENDFUNC(do_dynamic_space_overflow_warning)
    
    317 327
     #endif				
    
    ... ... @@ -493,8 +503,7 @@ FUNCDEF(undefined_foreign_symbol_trap)
    493 503
             movl 8(%ebp),%eax
    
    494 504
     
    
    495 505
     	/* Now trap to Lisp */
    
    496
    -	INT3
    
    497
    -	.byte	trap_Error
    
    506
    +	UD1(trap_Error)
    
    498 507
             /* Number of argument bytes */
    
    499 508
             .byte   2
    
    500 509
     	.byte	UNDEFINED_FOREIGN_SYMBOL_ERROR