2e409b
commit 5fe78861ea1589084f6a2956a6ff63677c9269e1
2e409b
Author: Dave Anderson <anderson@redhat.com>
2e409b
Date:   Fri Sep 7 16:05:52 2018 -0400
2e409b
2e409b
    Commit 3db3d3992d781c1e42587d2d2bf81e785408e0c2 in crash-7.1.8 was
2e409b
    aimed at making the PPC64 "bt" command work for dumpfiles saved
2e409b
    with the FADUMP facility, but it introduced a bit of unwarranted
2e409b
    complexity in "bt" command processing.  Reworked the "bt" command
2e409b
    processing for PPC64 arch to make it a little less compilated and
2e409b
    also to print symbols for NIP and LR registers in exception frames.
2e409b
    Without the patch, "bt" on non-panic active tasks may fail with
2e409b
    the message "bt: invalid kernel virtual address: <address>
2e409b
    type: Regs NIP value".
2e409b
    (hbathini@linux.ibm.com)
2e409b
2e409b
diff --git a/ppc64.c b/ppc64.c
2e409b
index f5d0dac..03fecd3 100644
2e409b
--- a/ppc64.c
2e409b
+++ b/ppc64.c
2e409b
@@ -2093,15 +2093,10 @@ ppc64_print_stack_entry(int frame,
2e409b
 					lr);
2e409b
 				return;
2e409b
 			}
2e409b
-			if (req->pc != lr) {
2e409b
-				fprintf(fp, "\n%s[Link Register] ", 
2e409b
-					frame < 10 ? " " : "");
2e409b
-				fprintf(fp, "[%lx] %s at %lx",
2e409b
-					req->sp, lrname, lr);
2e409b
-			}
2e409b
 			req->ra = lr;
2e409b
 		}
2e409b
-		if (!req->name || STREQ(req->name,lrname)) 
2e409b
+		if (!req->name || STREQ(req->name, lrname) ||
2e409b
+		    !is_kernel_text(req->pc))
2e409b
 			fprintf(fp, "  (unreliable)");
2e409b
 		
2e409b
 		fprintf(fp, "\n"); 
2e409b
@@ -2219,6 +2214,22 @@ ppc64_print_regs(struct ppc64_pt_regs *regs)
2e409b
         fprintf(fp, "    Syscall Result: %016lx\n", regs->result);
2e409b
 }
2e409b
 
2e409b
+static void ppc64_print_nip_lr(struct ppc64_pt_regs *regs, int print_lr)
2e409b
+{
2e409b
+	char buf[BUFSIZE];
2e409b
+	char *sym_buf;
2e409b
+
2e409b
+	sym_buf = value_to_symstr(regs->nip, buf, 0);
2e409b
+	if (sym_buf[0] != NULLCHAR)
2e409b
+		fprintf(fp, " [NIP  : %s]\n", sym_buf);
2e409b
+
2e409b
+	if (print_lr) {
2e409b
+		sym_buf = value_to_symstr(regs->link, buf, 0);
2e409b
+		if (sym_buf[0] != NULLCHAR)
2e409b
+			fprintf(fp, " [LR   : %s]\n", sym_buf);
2e409b
+	}
2e409b
+}
2e409b
+
2e409b
 /*
2e409b
  * Print the exception frame information
2e409b
  */
2e409b
@@ -2231,6 +2242,59 @@ ppc64_print_eframe(char *efrm_str, struct ppc64_pt_regs *regs,
2e409b
 
2e409b
 	fprintf(fp, " %s [%lx] exception frame:\n", efrm_str, regs->trap);
2e409b
 	ppc64_print_regs(regs);
2e409b
+	ppc64_print_nip_lr(regs, 1);
2e409b
+}
2e409b
+
2e409b
+/*
2e409b
+ * For vmcore typically saved with KDump or FADump, get SP and IP values
2e409b
+ * from the saved ptregs.
2e409b
+ */
2e409b
+static int
2e409b
+ppc64_vmcore_stack_frame(struct bt_info *bt_in, ulong *nip, ulong *ksp)
2e409b
+{
2e409b
+	struct ppc64_pt_regs *pt_regs;
2e409b
+	unsigned long unip;
2e409b
+
2e409b
+	pt_regs = (struct ppc64_pt_regs *)bt_in->machdep;
2e409b
+	if (!pt_regs || !pt_regs->gpr[1]) {
2e409b
+		/*
2e409b
+		 * Not collected regs. May be the corresponding CPU not
2e409b
+		 * responded to an IPI in case of KDump OR f/w has not
2e409b
+		 * not provided the register info in case of FADump.
2e409b
+		 */
2e409b
+		fprintf(fp, "%0lx: GPR1 register value (SP) was not saved\n",
2e409b
+			bt_in->task);
2e409b
+		return FALSE;
2e409b
+	}
2e409b
+	*ksp = pt_regs->gpr[1];
2e409b
+	if (IS_KVADDR(*ksp)) {
2e409b
+		readmem(*ksp+16, KVADDR, &unip, sizeof(ulong), "Regs NIP value",
2e409b
+			FAULT_ON_ERROR);
2e409b
+		*nip = unip;
2e409b
+	} else {
2e409b
+		if (IN_TASK_VMA(bt_in->task, *ksp))
2e409b
+			fprintf(fp, "%0lx: Task is running in user space\n",
2e409b
+				bt_in->task);
2e409b
+		else
2e409b
+			fprintf(fp, "%0lx: Invalid Stack Pointer %0lx\n",
2e409b
+				bt_in->task, *ksp);
2e409b
+		*nip = pt_regs->nip;
2e409b
+	}
2e409b
+
2e409b
+	if (bt_in->flags &&
2e409b
+	((BT_TEXT_SYMBOLS|BT_TEXT_SYMBOLS_PRINT|BT_TEXT_SYMBOLS_NOPRINT)))
2e409b
+		return TRUE;
2e409b
+
2e409b
+	/*
2e409b
+	 * Print the collected regs for the active task
2e409b
+	 */
2e409b
+	ppc64_print_regs(pt_regs);
2e409b
+	if (!IS_KVADDR(*ksp))
2e409b
+		return FALSE;
2e409b
+
2e409b
+	ppc64_print_nip_lr(pt_regs, (unip != pt_regs->link) ? 1 : 0);
2e409b
+
2e409b
+	return TRUE;
2e409b
 }
2e409b
 
2e409b
 /*
2e409b
@@ -2239,7 +2303,7 @@ ppc64_print_eframe(char *efrm_str, struct ppc64_pt_regs *regs,
2e409b
 static int
2e409b
 ppc64_get_dumpfile_stack_frame(struct bt_info *bt_in, ulong *nip, ulong *ksp)
2e409b
 {
2e409b
-	int i;
2e409b
+	int i, ret, panic_task;
2e409b
 	char *sym;
2e409b
 	ulong *up;
2e409b
 	struct bt_info bt_local, *bt;
2e409b
@@ -2251,11 +2315,29 @@ ppc64_get_dumpfile_stack_frame(struct bt_info *bt_in, ulong *nip, ulong *ksp)
2e409b
 	struct ppc64_pt_regs *pt_regs;
2e409b
 	struct syment *sp;
2e409b
 
2e409b
-        bt = &bt_local;
2e409b
-        BCOPY(bt_in, bt, sizeof(struct bt_info));
2e409b
-        ms = machdep->machspec;
2e409b
+	bt = &bt_local;
2e409b
+	BCOPY(bt_in, bt, sizeof(struct bt_info));
2e409b
+	ms = machdep->machspec;
2e409b
+	ur_nip = ur_ksp = 0;
2e409b
+
2e409b
+	panic_task = tt->panic_task == bt->task ? TRUE : FALSE;
2e409b
 
2e409b
 	check_hardirq = check_softirq = tt->flags & IRQSTACKS ? TRUE : FALSE;
2e409b
+	if (panic_task && bt->machdep) {
2e409b
+		pt_regs = (struct ppc64_pt_regs *)bt->machdep;
2e409b
+		ur_nip = pt_regs->nip;
2e409b
+		ur_ksp = pt_regs->gpr[1];
2e409b
+	} else if ((pc->flags & KDUMP) ||
2e409b
+		   ((pc->flags & DISKDUMP) &&
2e409b
+		    (*diskdump_flags & KDUMP_CMPRS_LOCAL))) {
2e409b
+		/*
2e409b
+		 * For the KDump or FADump vmcore, use SP and IP values
2e409b
+		 * that are saved in ptregs.
2e409b
+		 */
2e409b
+		ret = ppc64_vmcore_stack_frame(bt_in, nip, ksp);
2e409b
+		if (ret)
2e409b
+			return TRUE;
2e409b
+	}
2e409b
 
2e409b
 	if (bt->task != tt->panic_task) {
2e409b
 		char cpu_frozen = FALSE;
2e409b
@@ -2385,38 +2467,14 @@ retry:
2e409b
 		check_intrstack = FALSE;
2e409b
 		goto retry;
2e409b
 	}
2e409b
-
2e409b
 	/*
2e409b
-	 * We didn't find what we were looking for, so try to use
2e409b
-	 * the SP and IP values saved in ptregs.
2e409b
+	 *  We didn't find what we were looking for, so just use what was
2e409b
+	 *  passed in the ELF header.
2e409b
 	 */
2e409b
-	pt_regs = (struct ppc64_pt_regs *)bt_in->machdep;
2e409b
-	if (!pt_regs || !pt_regs->gpr[1]) {
2e409b
-		/*
2e409b
-		 * Not collected regs. May be the corresponding CPU did not
2e409b
-		 * respond to an IPI.
2e409b
-		 */
2e409b
-		if (CRASHDEBUG(1))
2e409b
-			fprintf(fp, "%0lx: GPR1(SP) register value not saved\n",
2e409b
-				bt_in->task);
2e409b
-	} else {
2e409b
-		*ksp = pt_regs->gpr[1];
2e409b
-		if (IS_KVADDR(*ksp)) {
2e409b
-			readmem(*ksp+16, KVADDR, nip, sizeof(ulong),
2e409b
-				"Regs NIP value", FAULT_ON_ERROR);
2e409b
-			ppc64_print_regs(pt_regs);
2e409b
-			return TRUE;
2e409b
-		} else {
2e409b
-			if (IN_TASK_VMA(bt_in->task, *ksp))
2e409b
-				fprintf(fp, "%0lx: Task is running in user space\n",
2e409b
-					bt_in->task);
2e409b
-			else
2e409b
-				fprintf(fp, "%0lx: Invalid Stack Pointer %0lx\n",
2e409b
-					bt_in->task, *ksp);
2e409b
-			*nip = pt_regs->nip;
2e409b
-			ppc64_print_regs(pt_regs);
2e409b
-			return FALSE;
2e409b
-		}
2e409b
+	if (ur_nip && ur_ksp) {
2e409b
+		*nip = ur_nip;
2e409b
+		*ksp = ur_ksp;
2e409b
+		return TRUE;
2e409b
 	}
2e409b
 
2e409b
         console("ppc64_get_dumpfile_stack_frame: cannot find SP for panic task\n");