From 2e5061dd1802a9fae89007839530f71736bbe4bc Mon Sep 17 00:00:00 2001
From: Dave Anderson <anderson@redhat.com>
Date: Tue, 2 Dec 2014 17:26:40 -0500
Subject: [PATCH 1/5] Fix for finding the starting stack and instruction
 pointer hooks for the active tasks in x86_64 ELF or compressed dumpfiles
 created by the KVM "virsh dump --memory-only" facility.  Without the patch,
 the backtraces of active tasks may show an invalid starting frame that
 indicates "__schedule".  The fix displays the exception RIP and dumps the
 register contents that are stored in the dumpfile header.  If the active task
 was operating in the kernel, the backtrace continues from there; if the task
 was operating in user-space, the backtrace is complete at that point.
 (anderson@redhat.com)

---
 defs.h     |  1 +
 diskdump.c |  3 +++
 netdump.c  | 35 +++++++++++++++++++++--------------
 task.c     |  2 +-
 x86_64.c   | 13 +++++++++----
 5 files changed, 35 insertions(+), 19 deletions(-)

diff --git a/defs.h b/defs.h
index 2e52bc4..dc2d65a 100644
--- a/defs.h
+++ b/defs.h
@@ -5547,6 +5547,7 @@ int write_proc_kcore(int, void *, int, ulong, physaddr_t);
 int kcore_memory_dump(FILE *);
 void dump_registers_for_qemu_mem_dump(void);
 void kdump_backup_region_init(void);
+void display_regs_from_elf_notes(int, FILE *);
 
 /*
  * ramdump.c
diff --git a/diskdump.c b/diskdump.c
index 3d33fdc..6b2aab5 100644
--- a/diskdump.c
+++ b/diskdump.c
@@ -100,6 +100,9 @@ map_cpus_to_prstatus_kdump_cmprs(void)
 	int online, i, j, nrcpus;
 	size_t size;
 
+	if (pc->flags2 & QEMU_MEM_DUMP_COMPRESSED)  /* notes exist for all cpus */
+		return;
+
 	if (!(online = get_cpus_online()) || (online == kt->cpus))
 		return;
 
diff --git a/netdump.c b/netdump.c
index 903faa0..6029a54 100644
--- a/netdump.c
+++ b/netdump.c
@@ -72,6 +72,9 @@ map_cpus_to_prstatus(void)
 	int online, i, j, nrcpus;
 	size_t size;
 
+	if (pc->flags2 & QEMU_MEM_DUMP_ELF)  /* notes exist for all cpus */
+		return;
+
 	if (!(online = get_cpus_online()) || (online == kt->cpus))
 		return;
 
@@ -2398,8 +2401,8 @@ get_regs_from_note(char *note, ulong *ip, ulong *sp)
 	return user_regs;
 }
 
-static void
-display_regs_from_elf_notes(int cpu)
+void
+display_regs_from_elf_notes(int cpu, FILE *ofp)
 {
 	Elf32_Nhdr *note32;
 	Elf64_Nhdr *note64;
@@ -2408,13 +2411,16 @@ display_regs_from_elf_notes(int cpu)
 	int c, skipped_count;
 
 	/*
-	 * NT_PRSTATUS notes are only related to online cpus, offline cpus
-	 * should be skipped.
+	 * Kdump NT_PRSTATUS notes are only related to online cpus, 
+	 * so offline cpus should be skipped.
 	 */
-	skipped_count = 0;
-	for (c = 0; c < cpu; c++) {
-		if (check_offline_cpu(c))
-			skipped_count++;
+	if (pc->flags2 & QEMU_MEM_DUMP_ELF)
+		skipped_count = 0;
+	else {
+		for (c = skipped_count = 0; c < cpu; c++) {
+			if (check_offline_cpu(c))
+				skipped_count++;
+		}
 	}
 
 	if ((cpu - skipped_count) >= nd->num_prstatus_notes) {
@@ -2433,7 +2439,7 @@ display_regs_from_elf_notes(int cpu)
 		len = roundup(len + note64->n_descsz, 4);
 		user_regs = ((char *)note64) + len - SIZE(user_regs_struct) - sizeof(long);
 
-		fprintf(fp,
+		fprintf(ofp,
 		    "    RIP: %016llx  RSP: %016llx  RFLAGS: %08llx\n"
 		    "    RAX: %016llx  RBX: %016llx  RCX: %016llx\n"
 		    "    RDX: %016llx  RSI: %016llx  RDI: %016llx\n"
@@ -2473,7 +2479,7 @@ display_regs_from_elf_notes(int cpu)
 		len = roundup(len + note32->n_descsz, 4);
 		user_regs = ((char *)note32) + len - SIZE(user_regs_struct) - sizeof(long);
 
-		fprintf(fp,
+		fprintf(ofp,
 		    "    EAX: %08x  EBX: %08x  ECX: %08x  EDX: %08x\n"
 		    "    ESP: %08x  EIP: %08x  ESI: %08x  EDI: %08x\n"
 		    "    CS: %04x       DS: %04x       ES: %04x       FS: %04x\n"
@@ -2506,7 +2512,7 @@ display_regs_from_elf_notes(int cpu)
 		len = roundup(len + note64->n_namesz, 4);
 		len = roundup(len + note64->n_descsz, 4);
 //		user_regs = ((char *)note64) + len - SIZE(user_regs_struct) - sizeof(long);
-		fprintf(fp, "display_regs_from_elf_notes: ARM64 register dump TBD\n");
+		fprintf(ofp, "display_regs_from_elf_notes: ARM64 register dump TBD\n");
 	}
 }
 
@@ -2519,7 +2525,7 @@ dump_registers_for_elf_dumpfiles(void)
                 error(FATAL, "-r option not supported for this dumpfile\n");
 
 	if (NETDUMP_DUMPFILE()) {
-                display_regs_from_elf_notes(0);
+                display_regs_from_elf_notes(0, fp);
 		return;
 	}
 
@@ -2530,7 +2536,7 @@ dump_registers_for_elf_dumpfiles(void)
 		}
 
                 fprintf(fp, "%sCPU %d:\n", c ? "\n" : "", c);
-                display_regs_from_elf_notes(c);
+                display_regs_from_elf_notes(c, fp);
         }
 }
 
@@ -2556,7 +2562,8 @@ get_netdump_regs_x86_64(struct bt_info *bt, ulong *ripp, ulong *rspp)
                 bt->flags |= BT_DUMPFILE_SEARCH;
 
 	if (((NETDUMP_DUMPFILE() || KDUMP_DUMPFILE()) &&
-   	      VALID_STRUCT(user_regs_struct) && (bt->task == tt->panic_task)) ||
+   	      VALID_STRUCT(user_regs_struct) && 
+	      ((bt->task == tt->panic_task) || (pc->flags2 & QEMU_MEM_DUMP_ELF))) ||
 	      (KDUMP_DUMPFILE() && (kt->flags & DWARF_UNWIND) && 
 	      (bt->flags & BT_DUMPFILE_SEARCH))) {
 		if (nd->num_prstatus_notes > 1)
diff --git a/task.c b/task.c
index f5bbe64..147ff5c 100644
--- a/task.c
+++ b/task.c
@@ -483,7 +483,7 @@ task_init(void)
 		tt->this_task = pid_to_task(active_pid);
 	}
 	else {
-		if (KDUMP_DUMPFILE() && !(pc->flags2 & QEMU_MEM_DUMP_ELF))
+		if (KDUMP_DUMPFILE())
 			map_cpus_to_prstatus();
 		else if (ELF_NOTES_VALID() && DISKDUMP_DUMPFILE())
 			map_cpus_to_prstatus_kdump_cmprs();
diff --git a/x86_64.c b/x86_64.c
index bbf1326..df6c561 100644
--- a/x86_64.c
+++ b/x86_64.c
@@ -2963,11 +2963,13 @@ x86_64_low_budget_back_trace_cmd(struct bt_info *bt_in)
 			diskdump_display_regs(bt->tc->processor, ofp);
 		else if (SADUMP_DUMPFILE())
 			sadump_display_regs(bt->tc->processor, ofp);
+		else if (pc->flags2 & QEMU_MEM_DUMP_ELF)
+			display_regs_from_elf_notes(bt->tc->processor, ofp);
 		return;
 	} else if ((bt->flags & BT_KERNEL_SPACE) &&
 		   (KVMDUMP_DUMPFILE() ||
 		    (ELF_NOTES_VALID() && DISKDUMP_DUMPFILE()) ||
-		    SADUMP_DUMPFILE())) {
+		    SADUMP_DUMPFILE() || (pc->flags2 & QEMU_MEM_DUMP_ELF))) {
 		fprintf(ofp, "    [exception RIP: ");
 		if ((sp = value_search(bt->instptr, &offset))) {
 			fprintf(ofp, "%s", sp->name);
@@ -2983,6 +2985,9 @@ x86_64_low_budget_back_trace_cmd(struct bt_info *bt_in)
 			diskdump_display_regs(bt->tc->processor, ofp);
 		else if (SADUMP_DUMPFILE())
 			sadump_display_regs(bt->tc->processor, ofp);
+		else if (pc->flags2 & QEMU_MEM_DUMP_ELF)
+			display_regs_from_elf_notes(bt->tc->processor, ofp);
+
         } else if (bt->flags & BT_START) {
                 x86_64_print_stack_entry(bt, ofp, level,
                         0, bt->instptr);
@@ -4565,7 +4570,7 @@ skip_stage:
         	*rip = ur_rip;
 		*rsp = ur_rsp;
 		if (is_kernel_text(ur_rip) &&
-		    (INSTACK(ur_rsp, bt) ||
+		    (INSTACK(ur_rsp, bt_in) ||
 		     in_alternate_stack(bt->tc->processor, ur_rsp)))
 			bt_in->flags |= BT_KERNEL_SPACE;
 		if (!is_kernel_text(ur_rip) && in_user_stack(bt->tc->task, ur_rsp))
@@ -4596,14 +4601,14 @@ skip_stage:
 		ur_rip = ULONG(user_regs + OFFSET(user_regs_struct_rip));
 		ur_rsp = ULONG(user_regs + OFFSET(user_regs_struct_rsp));
 		if (!in_alternate_stack(bt->tc->processor, ur_rsp) && 
-		    !stkptr_to_task(bt->task)) {
+		    !stkptr_to_task(ur_rsp)) {
 			if (CRASHDEBUG(1))
 				error(INFO, 
 				    "x86_64_get_dumpfile_stack_frame: "
 				    "ELF mismatch: RSP: %lx task: %lx\n",
 					ur_rsp, bt->task);
 		} else {
-			if (is_kernel_text(ur_rip) && (INSTACK(ur_rsp, bt) || 
+			if (is_kernel_text(ur_rip) && (INSTACK(ur_rsp, bt_in) || 
 			    in_alternate_stack(bt->tc->processor, ur_rsp)))
 				bt_in->flags |= BT_KERNEL_SPACE;
 			if (!is_kernel_text(ur_rip) && in_user_stack(bt->tc->task, ur_rsp))
-- 
2.10.2

