Blob Blame History Raw
commit b4af1d9b48998186aef8cd9abc47c6d59e36114e
Author: Dave Anderson <anderson@redhat.com>
Date:   Tue Dec 2 17:26:40 2014 -0500

    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)

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
@@ -102,6 +102,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))