Skip to contentSkip to conversation

implement dump_execution_state() on ia64

PATCH In review Akio Takebe 2 participants 8 messages Mar 27, 2008

lore
Share & tools
lore
#0 lore raw

cover implement dump_execution_state() on ia64

Hi,

This patch can show Calltraces at BUG_ON() on ia64.
And this supports xm debug-key d on ia64.
This patch needs to modify some common codes for supporting them.

[1/2] x86 side: implement_dump_execution_state.x86.patch [2/2] ia64 side: implement_dump_execution_state.ia64.patch

Best Regards,

Akio Takebe

#1 lore raw

PATCH 1/2 implement dump_execution_state() on ia64

Hi,

This patch is x86 side.

Best Regards,

Akio Takebe

xen/arch/x86/traps.c +27 -0
diff -r edfb58ca4d96 xen/arch/x86/traps.c
@@ -329,6 +329,33 @@ void show_execution_state(struct cpu_use
 {
     show_registers(regs);
     show_stack(regs);
+}
+
+void __dump_execstate(void *unused)
+{
+    dump_execution_state();
+    printk("*** Dumping CPU%d guest state: ***\n", smp_processor_id());
+    if ( is_idle_vcpu(current) )
+        printk("No guest context (CPU is idle).\n");
+    else
+        show_execution_state(guest_cpu_user_regs());
+}
+
+void _dump_registers(struct cpu_user_regs *regs)
+{
+    unsigned int cpu;
+
+    /* Get local execution state out immediately, in case we get stuck. */
+    printk("\n*** Dumping CPU%d host state: ***\n", smp_processor_id());
+    __dump_execstate(NULL);
+
+    for_each_online_cpu ( cpu )
+    {
+        if ( cpu == smp_processor_id() )
+            continue;
+        printk("\n*** Dumping CPU%d host state: ***\n", cpu);
+        on_selected_cpus(cpumask_of_cpu(cpu), __dump_execstate, NULL, 1, 1);
+    }
 }
 
 char *trapstr(int trapnr)
xen/common/keyhandler.c +1 -25
diff -r edfb58ca4d96 xen/common/keyhandler.c
@@ -89,34 +89,10 @@ static void show_handlers(unsigned char 
                    key_table[i].desc);
 }
 
-static void __dump_execstate(void *unused)
-{
-    dump_execution_state();
-    printk("*** Dumping CPU%d guest state: ***\n", smp_processor_id());
-    if ( is_idle_vcpu(current) )
-        printk("No guest context (CPU is idle).\n");
-    else
-        show_execution_state(guest_cpu_user_regs());
-}
-
 static void dump_registers(unsigned char key, struct cpu_user_regs *regs)
 {
-    unsigned int cpu;
-
     printk("'%c' pressed -> dumping registers\n", key);
-
-    /* Get local execution state out immediately, in case we get stuck. */
-    printk("\n*** Dumping CPU%d host state: ***\n", smp_processor_id());
-    __dump_execstate(NULL);
-
-    for_each_online_cpu ( cpu )
-    {
-        if ( cpu == smp_processor_id() )
-            continue;
-        printk("\n*** Dumping CPU%d host state: ***\n", cpu);
-        on_selected_cpus(cpumask_of_cpu(cpu), __dump_execstate, NULL, 1, 1);
-    }
-
+    _dump_registers(regs);
     printk("\n");
 }
 
xen/drivers/char/console.c +2 -2
diff -r edfb58ca4d96 xen/drivers/char/console.c
@@ -946,7 +946,7 @@ void __bug(char *file, int line)
 {
     console_start_sync();
     printk("Xen BUG at %s:%d\n", file, line);
-    dump_execution_state();
+    dump_execution_state(NULL);
     panic("Xen BUG at %s:%d\n", file, line);
     for ( ; ; ) ;
 }
@@ -954,7 +954,7 @@ void __warn(char *file, int line)
 void __warn(char *file, int line)
 {
     printk("Xen WARN at %s:%d\n", file, line);
-    dump_execution_state();
+    dump_execution_state(NULL);
 }
 
 
xen/include/asm-x86/processor.h +2 -0
diff -r edfb58ca4d96 xen/include/asm-x86/processor.h
@@ -561,6 +561,8 @@ void show_stack_overflow(unsigned int cp
 void show_stack_overflow(unsigned int cpu, unsigned long esp);
 void show_registers(struct cpu_user_regs *regs);
 void show_execution_state(struct cpu_user_regs *regs);
+void __dump_execstate(void *unused);
+void _dump_registers(struct cpu_user_regs *regs);
 void show_page_walk(unsigned long addr);
 asmlinkage void fatal_trap(int trapnr, struct cpu_user_regs *regs);
 
xen/include/asm-x86/x86_32/bug.h +3 -1
diff -r edfb58ca4d96 xen/include/asm-x86/x86_32/bug.h
@@ -7,7 +7,9 @@ struct bug_frame_str {
 } __attribute__((packed));
 #define BUG_MOV_STR "\xbc"
 
-#define dump_execution_state()                          \
+#define dump_execution_state(i) _dump_execution_state()
+
+#define _dump_execution_state()                         \
     asm volatile (                                      \
         "ud2 ; ret $%c0"                                \
         : : "i" (BUGFRAME_dump) )
xen/include/asm-x86/x86_64/bug.h +2 -1
diff -r edfb58ca4d96 xen/include/asm-x86/x86_64/bug.h
@@ -7,7 +7,8 @@ struct bug_frame_str {
 } __attribute__((packed));
 #define BUG_MOV_STR "\x48\xbc"
 
-#define dump_execution_state()                          \
+#define dump_execution_state(i) _dump_execution_state()
+#define _dump_execution_state()                         \
     asm volatile (                                      \
         "ud2 ; ret $%c0"                                \
         : : "i" (BUGFRAME_dump) )
xen/include/xen/smp.h +7 -0
diff -r edfb58ca4d96 xen/include/xen/smp.h
@@ -47,6 +47,13 @@ extern int on_selected_cpus(
     int retry,
     int wait);
 
+/* this is only for ia64. */
+extern int on_selected_cpus_regs(
+    cpumask_t selected,
+    void (*func) (void *info, struct cpu_user_regs *),
+    void *info,
+    int retry,
+    int wait);
 /*
  * Mark the boot cpu "online" so that it can call console drivers in
  * printk() and can access its per-cpu storage.

_______________________________________________
Xen-ia64-devel mailing list
[email protected]
http://lists.xensource.com/xen-ia64-devel

#2 lore raw

PATCH 2/2 implement dump_execution_state() on ia64

In reply to Akio Takebe

Hi,

This patch is ia64 side.

Best Regards,

Akio Takebe

xen/arch/ia64/linux-xen/smp.c +74 -1
diff -r edfb58ca4d96 xen/arch/ia64/linux-xen/smp.c
@@ -91,10 +91,20 @@ struct call_data_struct {
 	atomic_t finished;
 };
 
+struct call_data_regs_struct {
+	void (*func) (void *info, struct cpu_user_regs *);
+	void *info;
+	long wait;
+	atomic_t started;
+	atomic_t finished;
+};
+
 static volatile struct call_data_struct *call_data;
+static volatile struct call_data_regs_struct *call_data_regs;
 
 #define IPI_CALL_FUNC		0
 #define IPI_CPU_STOP		1
+#define IPI_CALL_FUNC_REGS	2
 
 /* This needs to be cacheline aligned because it is written to by *other* CPUs.  */
 static DEFINE_PER_CPU(u64, ipi_operation) ____cacheline_aligned;
@@ -183,7 +193,35 @@ handle_IPI (int irq, void *dev_id, struc
 					      atomic_inc(&data->finished);
 			      }
 			      break;
-
+#ifdef XEN
+			      case IPI_CALL_FUNC_REGS:
+			      {
+				      struct call_data_regs_struct *data;
+				      void (*func)(void *info, struct cpu_user_regs *);
+				      void *info;
+				      int wait;
+
+				      /* release the 'pointer lock' */
+				      data = (struct call_data_regs_struct *) call_data_regs;
+				      func = data->func;
+				      info = data->info;
+				      wait = data->wait;
+
+				      mb();
+				      atomic_inc(&data->started);
+				      /*
+				       * At this point the structure may be gone unless
+				       * wait is true.
+				       */
+				      (*func)(info, regs);
+
+				      /* Notify the sending CPU that the task is done.  */
+				      mb();
+				      if (wait)
+					      atomic_inc(&data->finished);
+			      }
+			      break;
+#endif
 			      case IPI_CPU_STOP:
 				stop_this_cpu();
 				break;
@@ -455,6 +493,41 @@ on_selected_cpus(cpumask_t selected, voi
 
 	return 0;
 }
+
+int
+on_selected_cpus_regs(cpumask_t selected, 
+		void (*func) (void *info, struct cpu_user_regs *), void *info,
+                 int retry, int wait)
+{
+	struct call_data_regs_struct data;
+	unsigned int cpu, nr_cpus = cpus_weight(selected);
+
+	ASSERT(local_irq_is_enabled());
+
+	if (!nr_cpus)
+		return 0;
+
+	data.func = func;
+	data.info = info;
+	data.wait = wait;
+	atomic_set(&data.started, 0);
+	atomic_set(&data.finished, 0);
+
+	spin_lock(&call_lock);
+
+	call_data_regs = &data;
+	wmb();
+
+	for_each_cpu_mask(cpu, selected)
+		send_IPI_single(cpu, IPI_CALL_FUNC_REGS);
+
+	while (atomic_read(wait ? &data.finished : &data.started) != nr_cpus)
+		cpu_relax();
+
+	spin_unlock(&call_lock);
+
+	return 0;
+}
 #endif
 
 /*
xen/arch/ia64/xen/xenmisc.c +44 -0

50 lines not on this page · raw message

xen/include/asm-ia64/xenprocessor.h +3 -1
diff -r edfb58ca4d96 xen/include/asm-ia64/xenprocessor.h
@@ -250,6 +250,8 @@ typedef union {
 	};
 } ia64_pkr_t;
 
-#define dump_execution_state() printk("FIXME: implement ia64 dump_execution_state()\n");
+extern inline void dump_execution_state(struct cpu_user_regs *);
+extern inline void __dump_execstate(void *, struct cpu_user_regs *);
+extern inline void _dump_registers(struct cpu_user_regs *);
 
 #endif // _ASM_IA64_XENPROCESSOR_H

_______________________________________________
Xen-ia64-devel mailing list
[email protected]
http://lists.xensource.com/xen-ia64-devel

#3 lore raw
In reply to Akio Takebe
Quoted 3 lines · Akio Takebe

This patch can show Calltraces at BUG_ON() on ia64.
And this supports xm debug-key d on ia64.
This patch needs to modify some common codes for supporting them.

Can you carefully explain why the interface changes are required?

-- Keir

#4 lore raw

Hi, Keir

Quoted 8 lines · Akio Takebe
Quoted 4 lines

This patch can show Calltraces at BUG_ON() on ia64.
And this supports xm debug-key d on ia64.
This patch needs to modify some common codes for supporting them.

Can you carefully explain why the interface changes are required?

IA64 needs unwind infomation to show the Calltrace.
To make the unwind infomation, we needs switch stack and pt_regs. So if possible, I want to use pt_regs at geting a interrupt.

I make many interface change because debug-key use IPI. But I just want to use pt_regs.

Best Regards,

Akio Takebe

#5 lore raw
Quoted 8 lines · Akio Takebe
Quoted 2 lines

Can you carefully explain why the interface changes are required?

IA64 needs unwind infomation to show the Calltrace.
To make the unwind infomation, we needs switch stack and pt_regs. So if possible, I want to use pt_regs at geting a interrupt.

I make many interface change because debug-key use IPI. But I just want to use pt_regs.

There is already a function which does what you want (i.e., takes a cpu_user_regs pointer) -- it's called show_execution_state().

On x86 we implement dump_execution_state() by forcing an exception (by executing an invalid opcode) and dumping the calltrace from within the exception handler. This works because the exception handler has a cpu_user_regs pointer and hence can call show_execution_state(). We use the same trick for handling BUG() and ASSERT(). The code concerned is in arch/x86/traps.c:do_invalid_op().

Can a similar thing be done on ia64?

-- Keir

#6 lore raw

Hi,

Quoted 14 lines · Akio Takebe
Quoted 9 lines
Quoted 3 lines

Can you carefully explain why the interface changes are required?

IA64 needs unwind infomation to show the Calltrace.
To make the unwind infomation, we needs switch stack and pt_regs. So if possible, I want to use pt_regs at geting a interrupt.

I make many interface change because debug-key use IPI. But I just want to use pt_regs.

There is already a function which does what you want (i.e., takes a cpu_user_regs pointer) -- it's called show_execution_state().

Quoted 6 lines

On x86 we implement dump_execution_state() by forcing an exception (by executing an invalid opcode) and dumping the calltrace from within the exception handler. This works because the exception handler has a cpu_user_regs pointer and hence can call show_execution_state(). We use the same trick for handling BUG() and ASSERT(). The code concerned is in arch/x86/traps.c:do_invalid_op().

On x86, does "xm debug-key d" make system hang? Or it just uses the exception handler, not hangup?

Best Regards,

Akio Takebe

#7 lore raw
Quoted 11 lines · Akio Takebe
Quoted 9 lines

There is already a function which does what you want (i.e., takes a cpu_user_regs pointer) -- it's called show_execution_state().

On x86 we implement dump_execution_state() by forcing an exception (by executing an invalid opcode) and dumping the calltrace from within the exception handler. This works because the exception handler has a cpu_user_regs pointer and hence can call show_execution_state(). We use the same trick for handling BUG() and ASSERT(). The code concerned is in arch/x86/traps.c:do_invalid_op().

On x86, does "xm debug-key d" make system hang? Or it just uses the exception handler, not hangup?

It works fine. It uses dump_execution_state(), as you have seen when you modified it, and hence it does indeed force an exception on each CPU in turn, and the exception handler dumps the cpu_user_regs (also known as 'pt_regs' in ia64) pointer that it receives.

-- Keir