git: aacf448007f7 - main - loader.efi: panic() should show stack trace

From: Toomas Soome <tsoome_at_FreeBSD.org>
Date: Thu, 09 Apr 2026 13:30:05 UTC
The branch main has been updated by tsoome:

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

commit aacf448007f7adbcdb528556cabcd120c9e8cb75
Author:     Toomas Soome <tsoome@FreeBSD.org>
AuthorDate: 2026-04-09 11:36:12 +0000
Commit:     Toomas Soome <tsoome@FreeBSD.org>
CommitDate: 2026-04-09 13:29:12 +0000

    loader.efi: panic() should show stack trace
    
    Because panic() does provide mechanism to have architecture specific
    panic call, we can instruct it to print out stack trace too
    (in hope we actually can print). While there, also implement simple
    check to detect loop in trace.
    
    illumos issue: https://www.illumos.org/issues/17887
---
 stand/efi/loader/arch/amd64/trap.c | 88 +++++++++++++++++++++++++-------------
 1 file changed, 59 insertions(+), 29 deletions(-)

diff --git a/stand/efi/loader/arch/amd64/trap.c b/stand/efi/loader/arch/amd64/trap.c
index 3fe86f7b1924..ff7190d214ad 100644
--- a/stand/efi/loader/arch/amd64/trap.c
+++ b/stand/efi/loader/arch/amd64/trap.c
@@ -82,14 +82,68 @@ struct frame {
 };
 
 void report_exc(struct trapframe *tf);
-void
-report_exc(struct trapframe *tf)
+
+static void
+stack_trace(struct frame *fp, uintptr_t pc)
 {
-	struct frame *fp;
-	uintptr_t pc, base;
+	uintptr_t base;
 	char buf[80];
 
 	base = (uintptr_t)boot_img->ImageBase;
+
+	printf("Stack trace:\n");
+	pager_open();
+	while (fp != NULL || pc != 0) {
+		struct frame *nfp;
+		char *source = "PC";
+
+		if (pc >= base && pc < base + boot_img->ImageSize) {
+			pc -= base;
+			source = "loader PC";
+		}
+		(void) snprintf(buf, sizeof (buf), "FP %016lx: %s 0x%016lx\n",
+		    (uintptr_t)fp, source, pc);
+		if (pager_output(buf))
+			break;
+
+		if (fp == NULL)
+			break;
+
+		nfp = fp->fr_savfp;
+		if (nfp != NULL && nfp <= fp) {
+			printf("FP %016lx: loop detected, stopping trace\n",
+			    (uintptr_t)nfp);
+			break;
+		}
+		fp = nfp;
+
+		if (fp != NULL)
+			pc = fp->fr_savpc;
+		else
+			pc = 0;
+	}
+	pager_close();
+}
+
+void
+panic_action(void)
+{
+	struct frame *fp;
+	uintptr_t rip;
+
+	__asm __volatile("movq %%rbp,%0" : "=r" (fp));
+	rip = fp->fr_savpc;
+
+	stack_trace(fp, rip);
+	printf("--> Press a key on the console to reboot <--\n");
+	getchar();
+	printf("Rebooting...\n");
+	exit(1);
+}
+
+void
+report_exc(struct trapframe *tf)
+{
 	/*
 	 * printf() depends on loader runtime and UEFI firmware health
 	 * to produce the console output, in case of exception, the
@@ -116,32 +170,8 @@ report_exc(struct trapframe *tf)
 	    tf->tf_r9, tf->tf_rax, tf->tf_rbx, tf->tf_rbp, tf->tf_r10,
 	    tf->tf_r11, tf->tf_r12, tf->tf_r13, tf->tf_r14, tf->tf_r15);
 
-	fp = (struct frame *)tf->tf_rbp;
-	pc = tf->tf_rip;
-
-	printf("Stack trace:\n");
-	pager_open();
-	while (fp != NULL || pc != 0) {
-		char *source = "PC";
-
-		if (pc >= base && pc < base + boot_img->ImageSize) {
-			pc -= base;
-			source = "loader PC";
-		}
-		(void) snprintf(buf, sizeof (buf), "FP %016lx: %s 0x%016lx\n",
-		    (uintptr_t)fp, source, pc);
-		if (pager_output(buf))
-			break;
+	stack_trace((struct frame *)tf->tf_rbp, tf->tf_rip);
 
-		if (fp != NULL)
-			fp = fp->fr_savfp;
-
-		if (fp != NULL)
-			pc = fp->fr_savpc;
-		else
-			pc = 0;
-	}
-	pager_close();
 	printf("Machine stopped.\n");
 }