From 3f013a6227117476e2659d6bef16b838666f75d4 Mon Sep 17 00:00:00 2001
From: Dave Anderson <anderson@redhat.com>
Date: Wed, 21 Jan 2015 15:03:10 -0500
Subject: [PATCH 3/5] Additional output for the "help [-D|-n]" options for the
 PPC64 architecture.  For compressed kdump and ELF kdump dumpfiles, the
 elf_prstatus structure in each per-cpu NT_PRSTATUS note will be translated.
 (anderson@redhat.com)

The "help -r" option has been extended to dump the PPC64 registers
stored in each per-cpu NT_PRSTATUS note in compressed kdump and
ELF kdump dumpfiles.
(anderson@redhat.com)
---
 defs.h     |  31 +++++++++++++--
 diskdump.c |  60 ++++++++++++++++++++++++++++-
 netdump.c  | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 ppc64.c    |   4 ++
 4 files changed, 215 insertions(+), 6 deletions(-)

diff --git a/defs.h b/defs.h
index 8a7b582..50c95cd 100644
--- a/defs.h
+++ b/defs.h
@@ -1,8 +1,8 @@
 /* defs.h - core analysis suite
  *
  * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc.
- * Copyright (C) 2002-2014 David Anderson
- * Copyright (C) 2002-2014 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2002-2015 David Anderson
+ * Copyright (C) 2002-2015 Red Hat, Inc. All rights reserved.
  * Copyright (C) 2002 Silicon Graphics, Inc.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -5252,7 +5252,7 @@ int dwarf_print_stack_entry(struct bt_info *, int);
 /*
  * ppc64.c
  */
-#ifdef PPC64
+
 /*
  *  This structure was copied from kernel source
  *  in include/asm-ppc/ptrace.h
@@ -5274,6 +5274,31 @@ struct ppc64_pt_regs {
         long result;         /* Result of a system call */
 };
 
+struct ppc64_elf_siginfo {
+    int si_signo;
+    int si_code;
+    int si_errno;
+};
+
+struct ppc64_elf_prstatus {
+    struct ppc64_elf_siginfo pr_info;
+    short pr_cursig;
+    unsigned long pr_sigpend;
+    unsigned long pr_sighold;
+    pid_t pr_pid;
+    pid_t pr_ppid;
+    pid_t pr_pgrp;
+    pid_t pr_sid;
+    struct timeval pr_utime;
+    struct timeval pr_stime;
+    struct timeval pr_cutime;
+    struct timeval pr_cstime;
+    struct ppc64_pt_regs pr_reg;
+    int pr_fpvalid;
+};
+
+#ifdef PPC64
+
 struct ppc64_vmemmap {
         unsigned long phys;
         unsigned long virt;
diff --git a/diskdump.c b/diskdump.c
index 17fba1b..a5c4588 100644
--- a/diskdump.c
+++ b/diskdump.c
@@ -1474,7 +1474,7 @@ dump_nt_prstatus_offset(FILE *fp)
 		fprintf(fp, "  NT_PRSTATUS_offset: ");
 		for (tot = cnt = 0; tot < size; tot += len) {
 			if (machine_type("X86_64") || machine_type("S390X") ||
-			    machine_type("ARM64")) {
+			    machine_type("ARM64") || machine_type("PPC64")) {
 				note64 = (void *)dd->notes_buf + tot;
 				len = sizeof(Elf64_Nhdr);
 				len = roundup(len + note64->n_namesz, 4);
@@ -2066,6 +2066,61 @@ diskdump_display_regs(int cpu, FILE *ofp)
 		);
 	}
 
+	if (machine_type("PPC64")) {
+		struct ppc64_elf_prstatus *prs;
+		struct ppc64_pt_regs *pr;
+
+		note64 = dd->nt_prstatus_percpu[cpu];
+		len = sizeof(Elf64_Nhdr);
+		len = roundup(len + note64->n_namesz, 4);
+		len = roundup(len + note64->n_descsz, 4);
+		if (!valid_note_address((unsigned char *)note64 + len)) {
+			error(INFO, "invalid NT_PRSTATUS note for cpu %d\n", cpu);
+			return;
+		}
+
+		prs = (struct ppc64_elf_prstatus *)
+			((char *)note64 + sizeof(Elf64_Nhdr) + note64->n_namesz);
+		prs = (struct ppc64_elf_prstatus *)roundup((ulong)prs, 4);
+		pr = &prs->pr_reg;
+
+		fprintf(ofp, 
+			"     R0: %016lx   R1: %016lx   R2: %016lx\n"
+			"     R3: %016lx   R4: %016lx   R5: %016lx\n"
+			"     R6: %016lx   R7: %016lx   R8: %016lx\n"
+			"     R9: %016lx  R10: %016lx  R11: %016lx\n"
+			"    R12: %016lx  R13: %016lx  R14: %016lx\n"
+			"    R15: %016lx  R16: %016lx  R16: %016lx\n"
+			"    R18: %016lx  R19: %016lx  R20: %016lx\n"
+			"    R21: %016lx  R22: %016lx  R23: %016lx\n"
+			"    R24: %016lx  R25: %016lx  R26: %016lx\n"
+			"    R27: %016lx  R28: %016lx  R29: %016lx\n"
+			"    R30: %016lx  R31: %016lx\n"
+			"      NIP: %016lx     MSR: %016lx\n"
+			"    OGPR3: %016lx     CTR: %016lx\n"  
+			"     LINK: %016lx     XER: %016lx\n"
+			"      CCR: %016lx      MQ: %016lx\n"
+			"     TRAP: %016lx     DAR: %016lx\n"
+			"    DSISR: %016lx  RESULT: %016lx\n",
+			pr->gpr[0], pr->gpr[1], pr->gpr[2],
+			pr->gpr[3], pr->gpr[4], pr->gpr[5],
+			pr->gpr[6], pr->gpr[7], pr->gpr[8],
+			pr->gpr[9], pr->gpr[10], pr->gpr[11],
+			pr->gpr[12], pr->gpr[13], pr->gpr[14],
+			pr->gpr[15], pr->gpr[16], pr->gpr[17],
+			pr->gpr[18], pr->gpr[19], pr->gpr[20],
+			pr->gpr[21], pr->gpr[22], pr->gpr[23],
+			pr->gpr[24], pr->gpr[25], pr->gpr[26],
+			pr->gpr[27], pr->gpr[28], pr->gpr[29],
+			pr->gpr[30], pr->gpr[31],
+			pr->nip, pr->msr, 
+			pr->orig_gpr3, pr->ctr,
+			pr->link, pr->xer,
+			pr->ccr, pr->mq,
+			pr->trap,  pr->dar, 
+			pr->dsisr, pr->result);
+	}
+
 	if (machine_type("ARM64")) {
 		note64 = dd->nt_prstatus_percpu[cpu];
 		len = sizeof(Elf64_Nhdr);
@@ -2121,7 +2176,8 @@ dump_registers_for_compressed_kdump(void)
 	int c;
 
 	if (!KDUMP_CMPRS_VALID() || (dd->header->header_version < 4) ||
-	    !(machine_type("X86") || machine_type("X86_64") || machine_type("ARM64")))
+	    !(machine_type("X86") || machine_type("X86_64") || 
+	      machine_type("ARM64") || machine_type("PPC64")))
 		error(FATAL, "-r option not supported for this dumpfile\n");
 
 	for (c = 0; c < kt->cpus; c++) {
diff --git a/netdump.c b/netdump.c
index 426efe4..812b0d2 100644
--- a/netdump.c
+++ b/netdump.c
@@ -2302,6 +2302,8 @@ dump_Elf64_Nhdr(Elf64_Off offset, int store)
 				else if (qemuinfo)
 					display_ELF_note(EM_X86_64, QEMU_NOTE, note, nd->ofp);
 			}
+			if (machine_type("PPC64") && (note->n_type == NT_PRSTATUS))
+				display_ELF_note(EM_PPC64, PRSTATUS_NOTE, note, nd->ofp);
 		}
 		for (i = lf = 0; i < note->n_descsz/sizeof(ulonglong); i++) {
 			if (((i%2)==0)) {
@@ -2523,6 +2525,55 @@ display_regs_from_elf_notes(int cpu, FILE *ofp)
 		    UINT(user_regs + OFFSET(user_regs_struct_ebp)),
 		    UINT(user_regs + OFFSET(user_regs_struct_eflags))
 		);
+	} else if (machine_type("PPC64")) {
+		struct ppc64_elf_prstatus *prs;
+		struct ppc64_pt_regs *pr;
+
+		if (nd->num_prstatus_notes > 1)
+			note64 = (Elf64_Nhdr *)nd->nt_prstatus_percpu[cpu];
+		else
+			note64 = (Elf64_Nhdr *)nd->nt_prstatus;
+
+		prs = (struct ppc64_elf_prstatus *)
+			((char *)note64 + sizeof(Elf64_Nhdr) + note64->n_namesz);
+		prs = (struct ppc64_elf_prstatus *)roundup((ulong)prs, 4);
+		pr = &prs->pr_reg;
+
+		fprintf(ofp, 
+			"     R0: %016lx   R1: %016lx   R2: %016lx\n"
+			"     R3: %016lx   R4: %016lx   R5: %016lx\n"
+			"     R6: %016lx   R7: %016lx   R8: %016lx\n"
+			"     R9: %016lx  R10: %016lx  R11: %016lx\n"
+			"    R12: %016lx  R13: %016lx  R14: %016lx\n"
+			"    R15: %016lx  R16: %016lx  R16: %016lx\n"
+			"    R18: %016lx  R19: %016lx  R20: %016lx\n"
+			"    R21: %016lx  R22: %016lx  R23: %016lx\n"
+			"    R24: %016lx  R25: %016lx  R26: %016lx\n"
+			"    R27: %016lx  R28: %016lx  R29: %016lx\n"
+			"    R30: %016lx  R31: %016lx\n"
+			"      NIP: %016lx     MSR: %016lx\n"
+			"    OGPR3: %016lx     CTR: %016lx\n"  
+			"     LINK: %016lx     XER: %016lx\n"
+			"      CCR: %016lx      MQ: %016lx\n"
+			"     TRAP: %016lx     DAR: %016lx\n"
+			"    DSISR: %016lx  RESULT: %016lx\n",
+			pr->gpr[0], pr->gpr[1], pr->gpr[2],
+			pr->gpr[3], pr->gpr[4], pr->gpr[5],
+			pr->gpr[6], pr->gpr[7], pr->gpr[8],
+			pr->gpr[9], pr->gpr[10], pr->gpr[11],
+			pr->gpr[12], pr->gpr[13], pr->gpr[14],
+			pr->gpr[15], pr->gpr[16], pr->gpr[17],
+			pr->gpr[18], pr->gpr[19], pr->gpr[20],
+			pr->gpr[21], pr->gpr[22], pr->gpr[23],
+			pr->gpr[24], pr->gpr[25], pr->gpr[26],
+			pr->gpr[27], pr->gpr[28], pr->gpr[29],
+			pr->gpr[30], pr->gpr[31],
+			pr->nip, pr->msr, 
+			pr->orig_gpr3, pr->ctr,
+			pr->link, pr->xer,
+			pr->ccr, pr->mq,
+			pr->trap,  pr->dar, 
+			pr->dsisr, pr->result);
 	} else if (machine_type("ARM64")) {
 		if (nd->num_prstatus_notes > 1)
                 	note64 = (Elf64_Nhdr *)
@@ -2542,7 +2593,8 @@ dump_registers_for_elf_dumpfiles(void)
 {
         int c;
 
-        if (!(machine_type("X86") || machine_type("X86_64") || machine_type("ARM64")))
+        if (!(machine_type("X86") || machine_type("X86_64") || 
+	    machine_type("ARM64") || machine_type("PPC64")))
                 error(FATAL, "-r option not supported for this dumpfile\n");
 
 	if (NETDUMP_DUMPFILE()) {
@@ -2824,6 +2876,69 @@ display_qemu_x86(void *note_ptr, FILE *ofp)
 		space(sp), (ulonglong)ptr->cr[3], (ulonglong)ptr->cr[4]);
 }
 
+static void
+display_prstatus_ppc64(void *note_ptr, FILE *ofp)
+{
+	struct ppc64_elf_prstatus *pr;
+	Elf64_Nhdr *note;
+	int sp;
+
+	note = (Elf64_Nhdr *)note_ptr;
+	pr = (struct ppc64_elf_prstatus *)(
+		(char *)note + sizeof(Elf64_Nhdr) + note->n_namesz);
+	pr = (struct ppc64_elf_prstatus *)roundup((ulong)pr, 4);
+	sp = nd->num_prstatus_notes ? 25 : 22;
+
+	fprintf(ofp,
+		"%ssi.signo: %d  si.code: %d  si.errno: %d\n"
+		"%scursig: %d  sigpend: %lx  sighold: %lx\n"
+		"%spid: %d  ppid: %d  pgrp: %d  sid:%d\n"
+		"%sutime: %01lld.%06d  stime: %01lld.%06d\n"
+		"%scutime: %01lld.%06d  cstime: %01lld.%06d\n"
+		"%s R0: %016lx   R1: %016lx   R2: %016lx\n"
+		"%s R3: %016lx   R4: %016lx   R5: %016lx\n"
+		"%s R6: %016lx   R7: %016lx   R8: %016lx\n"
+		"%s R9: %016lx  R10: %016lx  R11: %016lx\n"
+		"%sR12: %016lx  R13: %016lx  R14: %016lx\n"
+		"%sR15: %016lx  R16: %016lx  R16: %016lx\n"
+		"%sR18: %016lx  R19: %016lx  R20: %016lx\n"
+		"%sR21: %016lx  R22: %016lx  R23: %016lx\n"
+		"%sR24: %016lx  R25: %016lx  R26: %016lx\n"
+		"%sR27: %016lx  R28: %016lx  R29: %016lx\n"
+		"%sR30: %016lx  R31: %016lx\n"
+		"%s  NIP: %016lx     MSR: %016lx\n"
+		"%sOGPR3: %016lx     CTR: %016lx\n"  
+		"%s LINK: %016lx     XER: %016lx\n"
+		"%s  CCR: %016lx      MQ: %016lx\n"
+		"%s TRAP: %016lx     DAR: %016lx\n"
+		"%sDSISR: %016lx  RESULT: %016lx\n",
+		space(sp), pr->pr_info.si_signo, pr->pr_info.si_code, pr->pr_info.si_errno,
+		space(sp), pr->pr_cursig, pr->pr_sigpend, pr->pr_sighold,
+		space(sp), pr->pr_pid, pr->pr_ppid, pr->pr_pgrp, pr->pr_sid,
+		space(sp), (long long)pr->pr_utime.tv_sec, (int)pr->pr_utime.tv_usec,
+		(long long)pr->pr_stime.tv_sec, (int)pr->pr_stime.tv_usec,
+		space(sp), (long long)pr->pr_cutime.tv_sec, (int)pr->pr_cutime.tv_usec,
+		(long long)pr->pr_cstime.tv_sec, (int)pr->pr_cstime.tv_usec,
+		space(sp), pr->pr_reg.gpr[0], pr->pr_reg.gpr[1], pr->pr_reg.gpr[2],
+		space(sp), pr->pr_reg.gpr[3], pr->pr_reg.gpr[4], pr->pr_reg.gpr[5],
+		space(sp), pr->pr_reg.gpr[6], pr->pr_reg.gpr[7], pr->pr_reg.gpr[8],
+		space(sp), pr->pr_reg.gpr[9], pr->pr_reg.gpr[10], pr->pr_reg.gpr[11],
+		space(sp), pr->pr_reg.gpr[12], pr->pr_reg.gpr[13], pr->pr_reg.gpr[14],
+		space(sp), pr->pr_reg.gpr[15], pr->pr_reg.gpr[16], pr->pr_reg.gpr[17],
+		space(sp), pr->pr_reg.gpr[18], pr->pr_reg.gpr[19], pr->pr_reg.gpr[20],
+		space(sp), pr->pr_reg.gpr[21], pr->pr_reg.gpr[22], pr->pr_reg.gpr[23],
+		space(sp), pr->pr_reg.gpr[24], pr->pr_reg.gpr[25], pr->pr_reg.gpr[26],
+		space(sp), pr->pr_reg.gpr[27], pr->pr_reg.gpr[28], pr->pr_reg.gpr[29],
+		space(sp), pr->pr_reg.gpr[30], pr->pr_reg.gpr[31],
+		space(sp), pr->pr_reg.nip, pr->pr_reg.msr, 
+		space(sp), pr->pr_reg.orig_gpr3, pr->pr_reg.ctr,
+		space(sp), pr->pr_reg.link, pr->pr_reg.xer,
+		space(sp), pr->pr_reg.ccr, pr->pr_reg.mq,
+		space(sp), pr->pr_reg.trap,  pr->pr_reg.dar, 
+		space(sp), pr->pr_reg.dsisr, pr->pr_reg.result);
+}
+
+
 void
 display_ELF_note(int machine, int type, void *note, FILE *ofp)
 {
@@ -2853,6 +2968,15 @@ display_ELF_note(int machine, int type, void *note, FILE *ofp)
 		}
 		break;
 
+	case EM_PPC64:
+		switch (type)
+		{
+		case PRSTATUS_NOTE:
+			display_prstatus_ppc64(note, ofp);
+			break;
+		}
+		break;
+
 	default:
 		return;
 	}
diff --git a/ppc64.c b/ppc64.c
index 2cd9f02..e758728 100644
--- a/ppc64.c
+++ b/ppc64.c
@@ -164,6 +164,10 @@ ppc64_init(int when)
 {
 	switch (when)
 	{
+	case SETUP_ENV:
+		machdep->process_elf_notes = process_elf64_notes;
+		break;
+
 	case PRE_SYMTAB:
 		machdep->machspec = &ppc64_machine_specific;
 		machdep->verify_symbol = ppc64_verify_symbol;
-- 
2.10.2

