From 3db3d3992d781c1e42587d2d2bf81e785408e0c2 Mon Sep 17 00:00:00 2001
From: Dave Anderson <anderson@redhat.com>
Date: Tue, 24 Jan 2017 14:37:03 -0500
Subject: [PATCH] Fix for the PPC64 "bt" command for non-panicking active tasks
 in FADUMP-generated dumpfiles (Firmware Assisted Dump facility). Without the
 patch, backtraces of those tasks may be of the form "#0 [c0000000700b3a90]
 (null) at c0000000700b3b50  (unreliable)". This patch uses and displays the
 ptregs register set saved in the dumpfile header for the non-panicking active
 tasks. (hbathini@linux.vnet.ibm.com)

---
 diskdump.c |   22 ++++++++++
 ppc64.c    |  133 ++++++++++++++++++++----------------------------------------
 2 files changed, 67 insertions(+), 88 deletions(-)

diff --git a/diskdump.c b/diskdump.c
index 31cd0d6..0385a9e 100644
--- a/diskdump.c
+++ b/diskdump.c
@@ -1266,8 +1266,30 @@ get_diskdump_regs_ppc(struct bt_info *bt, ulong *eip, ulong *esp)
 static void
 get_diskdump_regs_ppc64(struct bt_info *bt, ulong *eip, ulong *esp)
 {
+	int cpu;
+	Elf64_Nhdr *note;
+	size_t len;
+
 	if ((bt->task == tt->panic_task) && DISKDUMP_VALID())
 		bt->machdep = &dd->sub_header->elf_regs;
+	else if (KDUMP_CMPRS_VALID() &&
+		(bt->task == tt->panic_task ||
+		(is_task_active(bt->task) && dd->num_prstatus_notes > 1))) {
+		cpu = bt->tc->processor;
+		if (dd->nt_prstatus_percpu[cpu] == NULL) {
+			if(CRASHDEBUG(1))
+				error(INFO,
+				      "registers not collected for cpu %d\n",
+				      cpu);
+		} else {
+			note = (Elf64_Nhdr *)
+				dd->nt_prstatus_percpu[cpu];
+			len = sizeof(Elf64_Nhdr);
+			len = roundup(len + note->n_namesz, 4);
+			bt->machdep = (void *)((char *)note + len +
+				MEMBER_OFFSET("elf_prstatus", "pr_reg"));
+		}
+	}
 
 	machdep->get_stack_frame(bt, eip, esp);
 }
diff --git a/ppc64.c b/ppc64.c
index 2efa953..1d0a409 100755
--- a/ppc64.c
+++ b/ppc64.c
@@ -60,18 +60,6 @@ static int is_hugepage(ulong pte);
 static int is_hugepd(ulong pte);
 static ulong hugepage_dir(ulong pte);
 
-static inline uint get_ptetype(ulong pte)
-{
-	uint pte_type = 0; /* 0: regular entry; 1: huge pte; 2: huge pd */
-
-	if (is_hugepage(pte))
-		pte_type = 1;
-	else if (is_hugepd(pte))
-		pte_type = 2;
-
-	return pte_type;
-}
-
 static int is_hugepage(ulong pte)
 {
 	/*
@@ -93,6 +81,18 @@ static inline int is_hugepd(ulong pte)
 		return ((pte & PD_HUGE) == 0x0);
 }
 
+static inline uint get_ptetype(ulong pte)
+{
+	uint pte_type = 0; /* 0: regular entry; 1: huge pte; 2: huge pd */
+
+	if (is_hugepage(pte))
+		pte_type = 1;
+	else if (is_hugepd(pte))
+		pte_type = 2;
+
+	return pte_type;
+}
+
 static inline ulong hugepage_dir(ulong pte)
 {
 	if (THIS_KERNEL_VERSION >= LINUX(3,10,0))
@@ -1949,66 +1949,11 @@ ppc64_print_eframe(char *efrm_str, struct ppc64_pt_regs *regs,
 }
 
 /*
- * get SP and IP from the saved ptregs.
- */
-static int
-ppc64_kdump_stack_frame(struct bt_info *bt_in, ulong *nip, ulong *ksp)
-{
-	struct ppc64_pt_regs *pt_regs;
-	unsigned long unip;
-
-	pt_regs = (struct ppc64_pt_regs *)bt_in->machdep;
-	if (!pt_regs || !pt_regs->gpr[1]) {
-		/*
-		 * Not collected regs. May be the corresponding CPU not
-		 * responded to an IPI.
-		 */
-		fprintf(fp, "%0lx: GPR1 register value (SP) was not saved\n",
-			bt_in->task);
-		return FALSE;
-	}
-	*ksp = pt_regs->gpr[1];
-	if (IS_KVADDR(*ksp)) {
-		readmem(*ksp+16, KVADDR, &unip, sizeof(ulong), "Regs NIP value",
-			FAULT_ON_ERROR);
-		*nip = unip;
-	} else {
-		if (IN_TASK_VMA(bt_in->task, *ksp))
-			fprintf(fp, "%0lx: Task is running in user space\n",
-				bt_in->task);
-		else 
-			fprintf(fp, "%0lx: Invalid Stack Pointer %0lx\n",
-				bt_in->task, *ksp);
-		*nip = pt_regs->nip;
-	}
-
-	if (bt_in->flags && 
-	((BT_TEXT_SYMBOLS|BT_TEXT_SYMBOLS_PRINT|BT_TEXT_SYMBOLS_NOPRINT))) 
-		return TRUE;
-
-	/*
-	 * Print the collected regs for the active task
-	 */
-	ppc64_print_regs(pt_regs);
-	if (!IS_KVADDR(*ksp)) 
-		return FALSE;
-	
-	fprintf(fp, " NIP [%016lx] %s\n", pt_regs->nip,
-		closest_symbol(pt_regs->nip));
-	if (unip != pt_regs->link)
-		fprintf(fp, " LR  [%016lx] %s\n", pt_regs->link,
-			closest_symbol(pt_regs->link));
-
-	return TRUE;
-}
-
-/*
  *  Get the starting point for the active cpus in a diskdump/netdump.
  */
 static int
 ppc64_get_dumpfile_stack_frame(struct bt_info *bt_in, ulong *nip, ulong *ksp)
 {
-	int panic_task;
 	int i;
 	char *sym;
 	ulong *up;
@@ -2021,25 +1966,13 @@ ppc64_get_dumpfile_stack_frame(struct bt_info *bt_in, ulong *nip, ulong *ksp)
 	struct ppc64_pt_regs *pt_regs;
 	struct syment *sp;
 
-	/* 
-	 * For the kdump vmcore, Use SP and IP values that are saved in ptregs.
-	 */ 
-	if (pc->flags & KDUMP)
-		return ppc64_kdump_stack_frame(bt_in, nip, ksp);
-
         bt = &bt_local;
         BCOPY(bt_in, bt, sizeof(struct bt_info));
         ms = machdep->machspec;
-        ur_nip = ur_ksp = 0;
-	
-	panic_task = tt->panic_task == bt->task ? TRUE : FALSE;
 
 	check_hardirq = check_softirq = tt->flags & IRQSTACKS ? TRUE : FALSE;
-	if (panic_task && bt->machdep) {
-		pt_regs = (struct ppc64_pt_regs *)bt->machdep;
-		ur_nip = pt_regs->nip;
-		ur_ksp = pt_regs->gpr[1];
-	} else if (bt->task != tt->panic_task) {
+
+	if (bt->task != tt->panic_task) {
 		char cpu_frozen = FALSE;
 		/*
 		 * Determine whether the CPU responded to an IPI.
@@ -2158,15 +2091,39 @@ retry:
 		alter_stackbuf(bt);
 		check_intrstack = FALSE;
 		goto retry;
-	} 
+	}
+
 	/*
-	 *  We didn't find what we were looking for, so just use what was
-	 *  passed in the ELF header.
+	 * We didn't find what we were looking for, so try to use
+	 * the SP and IP values saved in ptregs.
 	 */
-	if (ur_nip && ur_ksp) {
-        	*nip = ur_nip;
-		*ksp = ur_ksp;
-		return TRUE;
+	pt_regs = (struct ppc64_pt_regs *)bt_in->machdep;
+	if (!pt_regs || !pt_regs->gpr[1]) {
+		/*
+		 * Not collected regs. May be the corresponding CPU did not
+		 * respond to an IPI.
+		 */
+		if (CRASHDEBUG(1))
+			fprintf(fp, "%0lx: GPR1(SP) register value not saved\n",
+				bt_in->task);
+	} else {
+		*ksp = pt_regs->gpr[1];
+		if (IS_KVADDR(*ksp)) {
+			readmem(*ksp+16, KVADDR, nip, sizeof(ulong),
+				"Regs NIP value", FAULT_ON_ERROR);
+			ppc64_print_regs(pt_regs);
+			return TRUE;
+		} else {
+			if (IN_TASK_VMA(bt_in->task, *ksp))
+				fprintf(fp, "%0lx: Task is running in user space\n",
+					bt_in->task);
+			else
+				fprintf(fp, "%0lx: Invalid Stack Pointer %0lx\n",
+					bt_in->task, *ksp);
+			*nip = pt_regs->nip;
+			ppc64_print_regs(pt_regs);
+			return FALSE;
+		}
 	}
 
         console("ppc64_get_dumpfile_stack_frame: cannot find SP for panic task\n");
