Raymond Toy pushed to branch issue-97-define-ud2-inst at cmucl / cmucl
Commits: 9a86d9f0 by Raymond Toy at 2021-04-10T08:42:04-07:00 Change disassembly note for trap codes
Minor tweak to print the trap number first before the description of the trap.
- - - - - 9b09c6d9 by Raymond Toy at 2021-04-10T08:50:17-07:00 Add comments
- - - - - 46620f56 by Raymond Toy at 2021-04-10T09:15:38-07:00 Address review comments and add more comments
Fixed up a few things mentioned in the review.
Add a more comments on how things work, and added a TODO on computing the instruction length and inserting a int3/ud1 after it, kind of like how other archs handle it.
- - - - -
2 changed files:
- src/compiler/x86/insts.lisp - src/lisp/x86-arch.c
Changes:
===================================== src/compiler/x86/insts.lisp ===================================== @@ -2110,32 +2110,39 @@ (defun ud1-control (chunk inst stream dstate) (declare (ignore inst)) (flet ((nt (x) (if stream (disassem:note x dstate)))) - (case (ldb (byte 6 16) chunk) - (#.vm:error-trap - (nt #.(format nil "Error trap: ~D" vm:error-trap)) - (disassem:handle-break-args #'snarf-error-junk stream dstate)) - (#.vm:cerror-trap - (nt #.(format nil "Cerror trap: ~D" vm:cerror-trap)) - (disassem:handle-break-args #'snarf-error-junk stream dstate)) - (#.vm:breakpoint-trap - (nt #.(format nil "Breakpoint trap: ~D" vm:breakpoint-trap))) - (#.vm:pending-interrupt-trap - (nt #.(format nil "Pending interrupt trap: ~D" vm:pending-interrupt-trap))) - (#.vm:halt-trap - (nt #.(format nil "Halt trap: ~D" vm:halt-trap))) - (#.vm:function-end-breakpoint-trap - (nt #.(format nil "Function end breakpoint trap: ~D" vm:function-end-breakpoint-trap))) - ))) + (let ((code (ldb (byte 6 16) chunk))) + (case code + (#.vm:error-trap + (nt #.(format nil "Trap ~D: Error trap" vm:error-trap)) + (disassem:handle-break-args #'snarf-error-junk stream dstate)) + (#.vm:cerror-trap + (nt #.(format nil "Trap ~D: Cerror trap" vm:cerror-trap)) + (disassem:handle-break-args #'snarf-error-junk stream dstate)) + (#.vm:pending-interrupt-trap + (nt #.(format nil "Trap ~D: Pending interrupt trap" vm:pending-interrupt-trap))) + (#.vm:halt-trap + (nt #.(format nil "Trap ~D: Halt trap" vm:halt-trap))) + (#.vm:function-end-breakpoint-trap + (nt #.(format nil "Trap ~D: Function end breakpoint trap" + vm:function-end-breakpoint-trap))) + (t + (nt #.(format nil "Trap ~D: Unexpected trap type!!!!" )))))))
;; The ud1 instruction where we smash the code (trap type) into the -;; mod r/m byte. We don't care about what that actually encodes to. -;; We just want the trap code in the third byte of the instruction. +;; low 6 bits of the mod r/m byte. The mod bits are set to #b11 to +;; make sure the reg/mem part is interpreted to be a register and not +;; memory. (define-instruction ud1 (segment code) (:declare (type (unsigned-byte 8) code)) (:printer ud1 ((op #b10111001) (reg nil :type 'word-reg)) :default :control #'ud1-control) (:emitter + ;; We should not be using the breakpoint trap with UD1 anymore. + ;; Breakpoint traps are handled in C now, using plain int3. + (assert (/= code vm:breakpoint-trap)) + + ;; Emit the bytes of the instruction. (emit-byte segment #x0f) (emit-byte segment #xb9) (emit-mod-reg-r/m-byte segment
===================================== src/lisp/x86-arch.c ===================================== @@ -260,6 +260,23 @@ unsigned int single_step_save2; unsigned int single_step_save3; #endif
+/* + * This is called when we need to continue after a breakpoint. This + * works by putting the original byte back into the code, and then + * enabling single-step mode to step one instruction. When we return, + * the instruction will get run and a sigtrap will get triggered when + * the one instruction is done. + * + * TODO: Be more like other archs where the original inst is put back, + * and the next inst is replaced with a afterBreakpoint trap. When we + * run, the afterBreakpoint trap is hit at the next instruction and + * then we can put back the original breakpoint and replace the + * afterBreakpoint trap with the original inst there too. + * + * For x86, this means computing how many bytes are used in the + * current instruction, and then placing an int3 (or maybe ud1) after + * it. + */ void arch_do_displaced_inst(os_context_t * context, unsigned long orig_inst) { @@ -273,7 +290,7 @@ arch_do_displaced_inst(os_context_t * context, unsigned long orig_inst) * Put the original instruction back. */
- *((char *) pc) = orig_inst & 0xff; + *pc = orig_inst & 0xff;
/* * If we have the SC_EFLAGS macro, we can enable single-stepping @@ -318,9 +335,8 @@ arch_do_displaced_inst(os_context_t * context, unsigned long orig_inst)
/* - * Handles the break instruction from lisp, which is now UD2 followed - * by the trap code. In particular, this does not handle the - * breakpoint traps. + * Handles the ud1 instruction from lisp that is used to signal + * errors. In particular, this does not handle the breakpoint traps. */ void sigill_handler(HANDLER_ARGS) @@ -351,10 +367,10 @@ sigill_handler(HANDLER_ARGS) RESTORE_FPU(os_context);
/* - * On entry %eip points just after the INT3 byte and aims at the - * 'kind' value (eg trap_Cerror). For error-trap and Cerror-trap a - * number of bytes will follow, the first is the length of the byte - * arguments to follow. + * On entry %eip points just to the beginning of the UD1 + * instruction. For error-trap and cerror-trap a number of bytes + * will follow, the first is the length of the byte arguments to + * follow. */
DPRINTF(debug_handlers, @@ -459,7 +475,13 @@ sigtrap_handler(HANDLER_ARGS) *((unsigned char*)SC_PC(context) + 3), *(unsigned char*)(SC_PC(context) + 4)));
- if (single_stepping && (signal == SIGTRAP)) { + if (single_stepping) { + /* + * We were single-stepping so we now need to disable + * single-stepping. We want to put back the breakpoint (int3) + * instruction so that the next time the breakpoint will be + * hit again as expected. + */ DPRINTF(debug_handlers, (stderr, "* Single step trap %p\n", single_stepping));
#ifdef SC_EFLAGS @@ -492,6 +514,9 @@ sigtrap_handler(HANDLER_ARGS) return; }
+ /* + * We weren't single-stepping, so this we've just hit the breakpoint (int3). Handle it. + */ DPRINTF(debug_handlers, (stderr, "*C break\n"));
/*
View it on GitLab: https://gitlab.common-lisp.net/cmucl/cmucl/-/compare/cfb35624edee9113a81d900...