Raymond Toy pushed to branch master at cmucl / cmucl
Commits:
-
138199bd
by Raymond Toy at 2021-05-31T17:13:13+00:00
-
94a45e3f
by Raymond Toy at 2021-05-31T17:13:13+00:00
9 changed files:
- src/code/x86-vm.lisp
- src/compiler/x86/insts.lisp
- src/compiler/x86/macros.lisp
- src/compiler/x86/system.lisp
- src/lisp/arch.h
- src/lisp/breakpoint.c
- src/lisp/x86-arch.c
- src/lisp/x86-arch.h
- src/lisp/x86-assem.S
Changes:
| ... | ... | @@ -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))
|
| ... | ... | @@ -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)))
|
| ... | ... | @@ -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 |
|
| ... | ... | @@ -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)
|
| ... | ... | @@ -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);
|
| ... | ... | @@ -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.
|
| ... | ... | @@ -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 |
|
| ... | ... | @@ -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.
|
| ... | ... | @@ -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
|