From 9cca9773c6dd9a3623fe1a201e0f4cee89faf8e5 Mon Sep 17 00:00:00 2001 From: Douglas Katzman Date: Fri, 13 Oct 2017 14:56:05 -0400 Subject: [PATCH] x86-64: Allow choice of 0xCC or 0xCE as the interrupt instruction If you've ever needed to run under 'gdb' and have it pass Lisp interrupts to Lisp while still being able to set debugger breakpoints, you can change our interrupt opcode to INTO (0xCE) which is illegal in 64-bit mode. The feature is named :INT4-BREAKPOINTS, because :into-breakpoints sounds weird. At the CPU level, it's interrupt vector number 4 that is taken. --- src/code/early-fasl.lisp | 4 +++- src/compiler/x86-64/insts.lisp | 8 ++++---- src/compiler/x86-64/macros.lisp | 2 +- src/runtime/x86-64-arch.c | 19 ++++++++++++++----- src/runtime/x86-64-assem.S | 2 ++ 5 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/code/early-fasl.lisp b/src/code/early-fasl.lisp index d5f88c9e1..5312a3784 100644 --- a/src/code/early-fasl.lisp +++ b/src/code/early-fasl.lisp @@ -35,7 +35,9 @@ (macrolet ((define-fasl-format-features () (let (;; master value for *F-P-A-F-F* - (fpaff '(:sb-thread :sb-package-locks :sb-unicode :gencgc :ud2-breakpoints))) + (fpaff (append '(:sb-thread :sb-package-locks :sb-unicode :gencgc) + #!+(or x86 x86-64) '(:int4-breakpoints + :ud2-breakpoints)))) `(progn ;; a list of *(SHEBANG-)FEATURES* flags which affect ;; binary compatibility, i.e. which must be the same diff --git a/src/compiler/x86-64/insts.lisp b/src/compiler/x86-64/insts.lisp index 6e589464e..1c44e1704 100644 --- a/src/compiler/x86-64/insts.lisp +++ b/src/compiler/x86-64/insts.lisp @@ -2502,12 +2502,12 @@ (define-instruction break (segment code) (:declare (type (unsigned-byte 8) code)) - #!-ud2-breakpoints (:printer byte-imm ((op #b11001100)) + #!-ud2-breakpoints (:printer byte-imm ((op (or #!+int4-breakpoints #xCE #xCC))) '(:name :tab code) :control #'break-control) #!+ud2-breakpoints (:printer word-imm ((op #b0000101100001111)) '(:name :tab code) :control #'break-control) (:emitter - #!-ud2-breakpoints (emit-byte segment #b11001100) + #!-ud2-breakpoints (emit-byte segment (or #!+int4-breakpoints #xCE #xCC)) ;; On darwin, trap handling via SIGTRAP is unreliable, therefore we ;; throw a sigill with 0x0b0f instead and check for this in the ;; SIGILL handler and pass it on to the sigtrap handler if @@ -2520,8 +2520,8 @@ (:printer byte-imm ((op #b11001101))) (:emitter (etypecase number - ((member 3) - (emit-byte segment #b11001100)) + ((member 3 4) + (emit-byte segment (if (eql number 4) #xCE #xCC))) ((unsigned-byte 8) (emit-byte segment #b11001101) (emit-byte segment number))))) diff --git a/src/compiler/x86-64/macros.lisp b/src/compiler/x86-64/macros.lisp index 8b95f6a9c..080110751 100644 --- a/src/compiler/x86-64/macros.lisp +++ b/src/compiler/x86-64/macros.lisp @@ -282,7 +282,7 @@ (defun emit-error-break (vop kind code values) (assemble () #!-ud2-breakpoints - (inst int 3) ; i386 breakpoint instruction + (inst int #!+int4-breakpoints 4 #!-int4-breakpoints 3) ;; On Darwin, we need to use #x0b0f instead of int3 in order ;; to generate a SIGILL instead of a SIGTRAP as darwin/x86 ;; doesn't seem to be reliably firing SIGTRAP diff --git a/src/runtime/x86-64-arch.c b/src/runtime/x86-64-arch.c index e382a2400..3a938085f 100644 --- a/src/runtime/x86-64-arch.c +++ b/src/runtime/x86-64-arch.c @@ -30,13 +30,17 @@ #include "genesis/static-symbols.h" #include "genesis/symbol.h" -#define BREAKPOINT_INST 0xcc /* INT3 */ -#define UD2_INST 0x0b0f /* UD2 */ -#ifndef LISP_FEATURE_UD2_BREAKPOINTS -#define BREAKPOINT_WIDTH 1 -#else +#ifdef LISP_FEATURE_UD2_BREAKPOINTS +#define UD2_INST 0x0b0f /* UD2 */ #define BREAKPOINT_WIDTH 2 +#else +#ifdef LISP_FEATURE_INT4_BREAKPOINTS +# define BREAKPOINT_INST 0xce /* INTO */ +#else +# define BREAKPOINT_INST 0xcc /* INT3 */ +#endif +#define BREAKPOINT_WIDTH 1 #endif unsigned int cpuid_fn1_ecx; @@ -377,6 +381,11 @@ sigill_handler(int signal, siginfo_t *siginfo, os_context_t *context) { *os_context_pc_addr(context) += 2; return sigtrap_handler(signal, siginfo, context); } +#elif defined(LISP_FEATURE_INT4_BREAKPOINTS) && !defined(LISP_FEATURE_MACH_EXCEPTION_HANDLER) + if (*((unsigned char *)*os_context_pc_addr(context)) == BREAKPOINT_INST) { + *os_context_pc_addr(context) += BREAKPOINT_WIDTH; + return sigtrap_handler(signal, siginfo, context); + } #endif fake_foreign_function_call(context); diff --git a/src/runtime/x86-64-assem.S b/src/runtime/x86-64-assem.S index a726f0f8b..6c7a37247 100644 --- a/src/runtime/x86-64-assem.S +++ b/src/runtime/x86-64-assem.S @@ -82,6 +82,8 @@ * call sigtrap_handler. */ #if defined(LISP_FEATURE_UD2_BREAKPOINTS) #define TRAP ud2 +#elif defined(LISP_FEATURE_INT4_BREAKPOINTS) +#define TRAP .byte 0xCE /* due to illegality, assembler won't emit "into" */ #else #define TRAP int3 #endif -- 2.11.4.GIT