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
|