From 1a13dcc2ab127a947b3ef36eaa865655ef21b4c7 Mon Sep 17 00:00:00 2001
From: wlott <wlott>
Date: Mon, 8 Nov 1993 00:07:29 +0000
Subject: [PATCH] HP breakpoint support.

---
 lisp/breakpoint.c | 11 +++++-
 lisp/hppa-arch.c  | 94 +++++++++++++++++++++++++++++++++++------------
 lisp/hppa-assem.S | 33 +++++++++++++++++
 lisp/hppa-assem.s | 33 +++++++++++++++++
 4 files changed, 146 insertions(+), 25 deletions(-)

diff --git a/lisp/breakpoint.c b/lisp/breakpoint.c
index d57d80d98..1e3979ff4 100644
--- a/lisp/breakpoint.c
+++ b/lisp/breakpoint.c
@@ -37,7 +37,9 @@ void breakpoint_remove(lispobj code_obj, int pc_offset,
 void breakpoint_do_displaced_inst(struct sigcontext *scp,
 				  unsigned long orig_inst)
 {
+#ifndef hpux
     undo_fake_foreign_function_call(scp);
+#endif
     arch_do_displaced_inst(scp, orig_inst);
 }
 
@@ -67,13 +69,18 @@ static int compute_offset(struct sigcontext *scp, lispobj code)
     else {
 	unsigned long code_start;
 	struct code *codeptr = (struct code *)PTR(code);
+#ifdef parisc
+	unsigned long pc = SC_PC(scp) & ~3;
+#else
+	unsigned long pc = SC_PC(scp);
+#endif
 
 	code_start = (unsigned long)codeptr
 	    + HeaderValue(codeptr->header)*sizeof(lispobj);
-	if (SC_PC(scp) < code_start)
+	if (pc < code_start)
 	    return 0;
 	else {
-	    int offset = SC_PC(scp) - code_start;
+	    int offset = pc - code_start;
 	    if (offset >= codeptr->code_size)
 		return 0;
 	    else
diff --git a/lisp/hppa-arch.c b/lisp/hppa-arch.c
index 4937317c9..137fe0419 100644
--- a/lisp/hppa-arch.c
+++ b/lisp/hppa-arch.c
@@ -30,12 +30,12 @@ os_vm_address_t arch_get_bad_addr(int signal,
 	return NULL;
 
     /* Check the instruction address first. */
-    addr = scp->sc_pcoq_head & ~3;
-    if (addr < 0x1000)
+    addr = (os_vm_address_t)((unsigned long)scp->sc_pcoq_head & ~3);
+    if (addr < (os_vm_address_t)0x1000)
 	return addr;
 
     /* Otherwise, it must have been a data fault. */
-    return state->ss_cr21;
+    return (os_vm_address_t)state->ss_cr21;
 #else
     struct hp800_thread_state *state;
     os_vm_address_t addr;
@@ -99,6 +99,7 @@ unsigned long arch_install_breakpoint(void *pc)
     unsigned long orig_inst = *ulpc;
 
     *ulpc = trap_Breakpoint;
+    os_flush_icache((os_vm_address_t)pc, sizeof(*ulpc));
     return orig_inst;
 }
 
@@ -107,33 +108,79 @@ void arch_remove_breakpoint(void *pc, unsigned long orig_inst)
     unsigned long *ulpc = (unsigned long *)pc;
 
     *ulpc = orig_inst;
+    os_flush_icache((os_vm_address_t)pc, sizeof(*ulpc));
 }
 
+#ifdef hpux
+extern void SingleStepTraps();
+static unsigned long *BreakpointAddr = NULL;
+static unsigned long NextPc = NULL;
+#endif
+
 void arch_do_displaced_inst(struct sigcontext *scp, unsigned long orig_inst)
 {
+#ifdef hpux
+    /* We change the next-pc to point to a breakpoint instruction, restore */
+    /* the original instruction, and exit.  We would like to be able to */
+    /* sigreturn, but we can't, because this is hpux. */
+    unsigned long *pc = (unsigned long *)(SC_PC(scp) & ~3);
+
+    NextPc = SC_NPC(scp);
+    SC_NPC(scp) = (unsigned)SingleStepTraps | (SC_NPC(scp)&3);
+
+    BreakpointAddr = pc;
+    *pc = orig_inst;
+    os_flush_icache((os_vm_address_t)pc, sizeof(unsigned long));
+#else
     /* We set the recovery counter to cover one instruction, put the */
     /* original instruction back in, and then resume.  We will then trap */
     /* after executing that one instruction, at which time we can put */
     /* the breakpoint back in. */
 
-#ifdef hpux
-    scp->sc_sl.sl_ss.ss_cr0 = 1;
-    scp->sc_flags |= 0x10;
-#else
     ((struct hp800_thread_state *)scp->sc_ap)->cr0 = 1;
     scp->sc_ps |= 0x10;
-#endif
     *(unsigned long *)SC_PC(scp) = orig_inst;
 
-    undo_fake_foreign_function_call(scp);
-
-#ifdef hpux
-    printf("ERROR: arch_do_displaced_inst doesn't work because no sigreturn\n");
-#else
     sigreturn(scp);
 #endif
 }
 
+#ifdef hpux
+static void restore_breakpoint(struct sigcontext *scp)
+{
+    /* We just single-stepped over an instruction that we want to replace */
+    /* with a breakpoint.  So we put the breakpoint back in, and tweek the */
+    /* state so that we will continue as if nothing happened. */
+
+    if (NextPc == NULL)
+	lose("SingleStepBreakpoint trap at strange time.");
+
+    if ((SC_PC(scp)&~3) == (unsigned long)SingleStepTraps) {
+	/* The next instruction was not nullified. */
+	SC_PC(scp) = NextPc;
+	if ((SC_NPC(scp)&~3) == (unsigned long)SingleStepTraps + 4) {
+	    /* The instruction we just stepped over was not a branch, so */
+	    /* we need to fix it up.  If it was a branch, it will point to */
+	    /* the correct place. */
+	    SC_NPC(scp) = NextPc + 4;
+	}
+    }
+    else {
+	/* The next instruction was nullified, so we want to skip it. */
+	SC_PC(scp) = NextPc + 4;
+	SC_NPC(scp) = NextPc + 8;
+    }
+    NextPc = NULL;
+
+    if (BreakpointAddr) {
+	*BreakpointAddr = trap_Breakpoint;
+	os_flush_icache((os_vm_address_t)BreakpointAddr,
+			sizeof(unsigned long));
+	BreakpointAddr = NULL;
+    }
+}
+#endif
+
 static void sigtrap_handler(int signal, int code, struct sigcontext *scp)
 {
     unsigned long bad_inst;
@@ -173,26 +220,27 @@ static void sigtrap_handler(int signal, int code, struct sigcontext *scp)
 
 	  case trap_Breakpoint:
 	    sigsetmask(scp->sc_mask);
-	    fake_foreign_function_call(scp);
 	    handle_breakpoint(signal, code, scp);
-	    undo_fake_foreign_function_call(scp);
 	    break;
 
 	  case trap_FunctionEndBreakpoint:
 	    sigsetmask(scp->sc_mask);
-	    fake_foreign_function_call(scp);
 	    {
-		void *pc;
-		pc = handle_function_end_breakpoint(signal, code, scp);
+		unsigned long pc;
+		pc = (unsigned long)
+		    handle_function_end_breakpoint(signal, code, scp);
 #ifdef hpux
-		scp->sc_pcoq_head = (unsigned long)pc;
-		scp->sc_pcoq_tail = (unsigned long)pc + 4;
+		scp->sc_pcoq_head = pc;
+		scp->sc_pcoq_tail = pc + 4;
 #else
-		scp->sc_pcoqh = (unsigned long)pc;
-		scp->sc_pcoqt = (unsigned long)pc + 4;
+		scp->sc_pcoqh = pc;
+		scp->sc_pcoqt = pc + 4;
 #endif
 	    }
-	    undo_fake_foreign_function_call(scp);
+	    break;
+
+	  case trap_SingleStepBreakpoint:
+	    restore_breakpoint(scp);
 	    break;
 
 	  default:
diff --git a/lisp/hppa-assem.S b/lisp/hppa-assem.S
index b71977f2b..2770bc528 100644
--- a/lisp/hppa-assem.S
+++ b/lisp/hppa-assem.S
@@ -334,3 +334,36 @@ restore_state
 	b	_restore_state
 	copy	arg1,ret0
 	.procend
+
+
+
+	.export SingleStepTraps
+SingleStepTraps
+	break	trap_SingleStepBreakpoint,0
+	break	trap_SingleStepBreakpoint,0
+
+
+
+	.align	8
+	.export function_end_breakpoint_guts
+function_end_breakpoint_guts
+	.word	type_ReturnPcHeader
+	/* multiple value return point -- just jump to trap. */
+	b,n	function_end_breakpoint_trap
+	/* single value return point -- convert to multiple w/ n=1 */
+	copy	reg_CSP, reg_OCFP
+	addi	4, reg_CSP, reg_CSP
+	addi	4, r0, reg_NARGS
+	copy	reg_NULL, reg_A1
+	copy	reg_NULL, reg_A2
+	copy	reg_NULL, reg_A3
+	copy	reg_NULL, reg_A4
+	copy	reg_NULL, reg_A5
+
+	.export	function_end_breakpoint_trap
+function_end_breakpoint_trap
+	break	trap_FunctionEndBreakpoint,0
+	b,n	function_end_breakpoint_trap
+
+	.export	function_end_breakpoint_end
+function_end_breakpoint_end
diff --git a/lisp/hppa-assem.s b/lisp/hppa-assem.s
index b71977f2b..2770bc528 100644
--- a/lisp/hppa-assem.s
+++ b/lisp/hppa-assem.s
@@ -334,3 +334,36 @@ restore_state
 	b	_restore_state
 	copy	arg1,ret0
 	.procend
+
+
+
+	.export SingleStepTraps
+SingleStepTraps
+	break	trap_SingleStepBreakpoint,0
+	break	trap_SingleStepBreakpoint,0
+
+
+
+	.align	8
+	.export function_end_breakpoint_guts
+function_end_breakpoint_guts
+	.word	type_ReturnPcHeader
+	/* multiple value return point -- just jump to trap. */
+	b,n	function_end_breakpoint_trap
+	/* single value return point -- convert to multiple w/ n=1 */
+	copy	reg_CSP, reg_OCFP
+	addi	4, reg_CSP, reg_CSP
+	addi	4, r0, reg_NARGS
+	copy	reg_NULL, reg_A1
+	copy	reg_NULL, reg_A2
+	copy	reg_NULL, reg_A3
+	copy	reg_NULL, reg_A4
+	copy	reg_NULL, reg_A5
+
+	.export	function_end_breakpoint_trap
+function_end_breakpoint_trap
+	break	trap_FunctionEndBreakpoint,0
+	b,n	function_end_breakpoint_trap
+
+	.export	function_end_breakpoint_end
+function_end_breakpoint_end
-- 
GitLab