git: fcd94047f33b - releng/13.2 - dtrace/powerpc: "Fix" stack traces across trap frames

From: Justin Hibbits <jhibbits_at_FreeBSD.org>
Date: Wed, 15 Mar 2023 20:47:03 UTC
The branch releng/13.2 has been updated by jhibbits:

URL: https://cgit.FreeBSD.org/src/commit/?id=fcd94047f33beb98f1eee4d09e29d6c8de31c4a6

commit fcd94047f33beb98f1eee4d09e29d6c8de31c4a6
Author:     Justin Hibbits <jhibbits@FreeBSD.org>
AuthorDate: 2023-03-11 16:30:00 +0000
Commit:     Justin Hibbits <jhibbits@FreeBSD.org>
CommitDate: 2023-03-15 20:27:37 +0000

    dtrace/powerpc: "Fix" stack traces across trap frames
    
    In function boundary tracing the link register is not yet saved to the
    save stack location, so the save point contains whatever the previous
    'lr' save was, or even garbage, at the time the trap is taken.  Address
    this by explicitly loading the link register from the trap frame instead
    of the stack, and propagate that out.
    
    Approved by:    re (cperciva)
    
    (cherry picked from commit 3e1155ade1baab51458374efd0295bdf6db455fc)
    (cherry picked from commit e620e088cbd1c062655eee825aaf4f80bd255e1f)
    (cherry picked from commit 0a21a6659e5dfe503da587fb0460ae19bd765859)
---
 sys/cddl/dev/dtrace/powerpc/dtrace_isa.c | 20 ++++++++++++++------
 1 file changed, 14 insertions(+), 6 deletions(-)

diff --git a/sys/cddl/dev/dtrace/powerpc/dtrace_isa.c b/sys/cddl/dev/dtrace/powerpc/dtrace_isa.c
index cce1c907b5d8..1fca72e5b7fd 100644
--- a/sys/cddl/dev/dtrace/powerpc/dtrace_isa.c
+++ b/sys/cddl/dev/dtrace/powerpc/dtrace_isa.c
@@ -97,15 +97,18 @@ dtrace_sp_inkernel(uintptr_t sp)
 }
 
 static __inline void
-dtrace_next_sp_pc(uintptr_t sp, uintptr_t *nsp, uintptr_t *pc)
+dtrace_next_sp_pc(uintptr_t sp, uintptr_t *nsp, uintptr_t *pc, uintptr_t *lr)
 {
 	vm_offset_t callpc;
 	struct trapframe *frame;
 
+	if (lr != 0 && *lr != 0)
+		callpc = *lr;
+	else
 #ifdef __powerpc64__
-	callpc = *(vm_offset_t *)(sp + RETURN_OFFSET64);
+		callpc = *(vm_offset_t *)(sp + RETURN_OFFSET64);
 #else
-	callpc = *(vm_offset_t *)(sp + RETURN_OFFSET);
+		callpc = *(vm_offset_t *)(sp + RETURN_OFFSET);
 #endif
 
 	/*
@@ -121,6 +124,8 @@ dtrace_next_sp_pc(uintptr_t sp, uintptr_t *nsp, uintptr_t *pc)
 			*nsp = frame->fixreg[1];
 		if (pc != NULL)
 			*pc = frame->srr0;
+		if (lr != NULL)
+			*lr = frame->lr;
 		return;
 	}
 
@@ -128,6 +133,9 @@ dtrace_next_sp_pc(uintptr_t sp, uintptr_t *nsp, uintptr_t *pc)
 		*nsp = *(uintptr_t *)sp;
 	if (pc != NULL)
 		*pc = callpc;
+	/* lr is only valid for trap frames */
+	if (lr != NULL)
+		*lr = 0;
 }
 
 void
@@ -135,7 +143,7 @@ dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
     uint32_t *intrpc)
 {
 	int depth = 0;
-	uintptr_t osp, sp;
+	uintptr_t osp, sp, lr = 0;
 	vm_offset_t callpc;
 	pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller;
 
@@ -154,7 +162,7 @@ dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
 		if (!dtrace_sp_inkernel(sp))
 			break;
 		osp = sp;
-		dtrace_next_sp_pc(osp, &sp, &callpc);
+		dtrace_next_sp_pc(osp, &sp, &callpc, &lr);
 
 		if (aframes > 0) {
 			aframes--;
@@ -513,7 +521,7 @@ dtrace_getstackdepth(int aframes)
 
 		depth++;
 		osp = sp;
-		dtrace_next_sp_pc(sp, &sp, NULL);
+		dtrace_next_sp_pc(sp, &sp, NULL, NULL);
 	}
 	if (depth < aframes)
 		return (0);