[Crash-utility] [PATCH] bug on get_be_long() and improvement of bt

Hu Tao hutao at cn.fujitsu.com
Mon Oct 18 07:22:57 UTC 2010


Hi Dave,

   There is a bug on get_be_long() that causes high 32 bits truncated.
   As a result, we get wrong registers values from dump file. Patch 1
   fixes this.

   Once we can get right cpu registers values, it's better to use the
   sp/ip for backtracing the active task. This can show a more accurate
   backtrace, not including those invalid frames beyond sp. pathes 2 and
   3 do this on kvmdump case(virsh dump).

   To verify: run that km_probe.c test module on a x86_64 system, then
   `echo q > /proc/sysrq-trigger' to trigger the kprobe which does
   looping in post_handler. Then vrish dump then crash. 

-- 
Thanks,
Hu Tao
-------------- next part --------------
diff --git a/qemu-load.c b/qemu-load.c
index 998b6d4..95eaf97 100644
--- a/qemu-load.c
+++ b/qemu-load.c
@@ -408,7 +408,7 @@ cpu_common_init_load (struct qemu_device_list *dl,
 

 /* CPU loader.  */
 
-static inline int
+static inline uint64_t
 get_be_long (FILE *fp, int size)
 {
 	uint32_t a = size == 32 ? 0 : get_be32 (fp);
-------------- next part --------------
diff --git a/qemu-load.h b/qemu-load.h
index 578fedd..0d8db4e 100644
--- a/qemu-load.h
+++ b/qemu-load.h
@@ -140,6 +140,18 @@ struct qemu_x86_mce {
 	uint64_t		mce_banks[10 * 4];
 };
 
+enum CPU_REG {
+	R_EAX,
+	R_ECX,
+	R_EDX,
+	R_EBX,
+	R_ESP,
+	R_EBP,
+	R_ESI,
+	R_EDI,
+	R_GP_MAX,
+};
+
 struct qemu_device_x86 {
 	struct qemu_device	dev_base;
 
-------------- next part --------------
diff --git a/kernel.c b/kernel.c
index e399099..2627020 100755
--- a/kernel.c
+++ b/kernel.c
@@ -16,6 +16,7 @@
  */
 
 #include "defs.h"
+#include "qemu-load.h"
 #include "xen_hyper_defs.h"
 #include <elf.h>
 
diff --git a/kvmdump.c b/kvmdump.c
index 1bf0d9e..557d329 100644
--- a/kvmdump.c
+++ b/kvmdump.c
@@ -17,6 +17,7 @@
 
 #include "defs.h"
 #include "kvmdump.h"
+#include "qemu-load.h"
 
 static struct kvmdump_data kvmdump_data = { 0 };  
 struct kvmdump_data *kvm = &kvmdump_data;
@@ -310,7 +311,11 @@ kvmdump_memory_dump(FILE *ofp)
 void 
 get_kvmdump_regs(struct bt_info *bt, ulong *pc, ulong *sp)
 {
-	machdep->get_stack_frame(bt, pc, sp);
+	if (is_task_active(bt->task)) {
+		*sp = device_list->dx86->regs[R_ESP];
+		*pc = device_list->dx86->eip;
+	} else
+		machdep->get_stack_frame(bt, pc, sp);
 }
 
 ulong
diff --git a/main.c b/main.c
index 925de2f..ecab83c 100755
--- a/main.c
+++ b/main.c
@@ -16,6 +16,7 @@
  */
 
 #include "defs.h"
+#include "qemu-load.h"
 #include "xen_hyper_defs.h"
 #include <curses.h>
 #include <getopt.h>
@@ -1445,6 +1446,8 @@ clean_exit(int status)
 	if (pc->flags & MEMMOD)
 		cleanup_memory_driver();
 
+	device_list_free (device_list);
+
 	exit(status);
 }
 
diff --git a/qemu-load.c b/qemu-load.c
index 95eaf97..c807c49 100644
--- a/qemu-load.c
+++ b/qemu-load.c
@@ -18,6 +18,7 @@
  */
 
 #define _GNU_SOURCE
+#include "defs.h"
 #include "qemu-load.h"
 #include <stdlib.h>
 #include <string.h>
@@ -881,6 +882,7 @@ qemu_load (const struct qemu_device_loader *devices, uint32_t required_features,
 	dprintf("\n");
 
 	result = calloc (1, sizeof (struct qemu_device_list));
+	result->dx86 = NULL;
 	for (;;) {
 		struct qemu_device *d;
 		uint32_t features;
@@ -904,6 +906,9 @@ qemu_load (const struct qemu_device_loader *devices, uint32_t required_features,
 		if (feof (fp) || ferror (fp))
 			break;
 
+		if (STREQ(d->vtbl->name, "cpu"))
+			result->dx86 = d;
+
 		if (sec == QEMU_VM_SECTION_END || sec == QEMU_VM_SECTION_FULL)
 			result->features |= features;
 	}
@@ -924,7 +929,6 @@ fail:
  *  crash utility adaptation.
  */
 
-#include "defs.h"
 
 int
 is_qemu_vm_file(char *filename)
diff --git a/qemu-load.h b/qemu-load.h
index 0d8db4e..3872899 100644
--- a/qemu-load.h
+++ b/qemu-load.h
@@ -40,6 +40,7 @@ enum qemu_features {
 
 struct qemu_device_list {
 	struct qemu_device	*head, *tail;
+	struct qemu_device_x86	*dx86;
 	uint32_t		features;
 };
 
@@ -232,4 +233,6 @@ extern const struct qemu_device_loader devices_x86_32[];
 /* For a 64-bit KVM host.  */
 extern const struct qemu_device_loader devices_x86_64[];
 
+extern struct qemu_device_list *device_list;
+
 #endif
diff --git a/qemu.c b/qemu.c
index 84b6f96..a355c4f 100644
--- a/qemu.c
+++ b/qemu.c
@@ -280,10 +280,11 @@ int main (int argc, char **argv)
 
 #include "defs.h"
 
+struct qemu_device_list *device_list = NULL;
+
 int 
 qemu_init(char *filename)
 {
-	struct qemu_device_list *dl;
 	struct qemu_device_ram *dram;
 	uint64_t idt = 0;
 
@@ -298,24 +299,24 @@ qemu_init(char *filename)
 	please_wait("scanning KVM dumpfile");
 
 	if (machine_type("X86"))
-		dl = qemu_load(devices_x86_32, 
+		device_list = qemu_load(devices_x86_32,
 			QEMU_FEATURE_CPU|QEMU_FEATURE_RAM, kvm->vmp);
 	else if (machine_type("X86_64"))
-		dl = qemu_load(devices_x86_64, 
+		device_list = qemu_load(devices_x86_64,
 			QEMU_FEATURE_CPU|QEMU_FEATURE_RAM, kvm->vmp);
 	else
-		dl = NULL;
+		device_list = NULL;
 
 	please_wait_done();
 
-	if (dl) {
+	if (device_list) {
 		if (machine_type("X86_64")) {
-			idt = get_idt_base(dl);
-			kvm->mapinfo.phys_base = get_kernel_base(dl);
+			idt = get_idt_base(device_list);
+			kvm->mapinfo.phys_base = get_kernel_base(device_list);
 		}
 
 		dram = (struct qemu_device_ram *) 
-			device_find_instance (dl, "ram", 0);
+			device_find_instance (device_list, "ram", 0);
 
 		if (CRASHDEBUG(1)) {
 			if (machine_type("X86_64")) {
@@ -327,10 +328,8 @@ qemu_init(char *filename)
 			fprintf(kvm->ofp, "last RAM offset: %llx\n", 
 				(ulonglong)dram->last_ram_offset); 
 		}
-
-		device_list_free (dl);
 	} else
 		fclose(kvm->vmp);
 
-	return dl ? TRUE : FALSE;
+	return device_list ? TRUE : FALSE;
 }


More information about the Crash-utility mailing list