public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] stack2core: show stack message and convert it to core file  when kernel die
@ 2010-01-03 15:05 Hui Zhu
  2010-01-03 16:03 ` Russell King - ARM Linux
  2010-01-03 22:49 ` Tejun Heo
  0 siblings, 2 replies; 22+ messages in thread
From: Hui Zhu @ 2010-01-03 15:05 UTC (permalink / raw)
  To: Russell King, saeed bishara, Catalin Marinas, Nicolas Pitre,
	Ralf Baechle, David Daney, Tomaso Paoletti, Chris Dearman,
	Paul Gortmaker, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, x86,
	Frederic Weisbecker, Alexey Dobriyan, Brian Gerst, Tejun Heo,
	Rusty Russell, Andrew Morton, Steven Rostedt, Greg Kroah-Hartman,
	Paul E. McKenney, linux-arm-kernel, linux-kernel, linux-mips
  Cc: Coly Li

Hello,

For, when the kernel die, the user will get some message like:
PC is at kernel_init+0xd4/0x104
LR is at _atomic_dec_and_lock+0x48/0x6c
pc : [<c0008470>]    lr : [<c01911f8>]    psr: 60000013
sp : c7823fd8  ip : c7823f48  fp : c7823ff4
Stack: (0xc7823fd8 to 0xc7824000)
3fc0:                                                       00000000 00000001
Backtrace:
[<c000839c>] (kernel_init+0x0/0x104) from [<c0042660>] (do_exit+0x0/0x880)
This backtrace have some wrong message sometime and cannot get any
val. Of course, kdump can get more message.  But it need do some a lot
of other config.

The stack2core function, can let kernel show stack message when kernel
die.  This stack message can be convert to core file by program s2c
(tools/s2c).  Then gdb can show the message in this core file.
For example:
When kernel die, show some message:
S2C:elf_class=1
S2C:elf_data=1
S2C:elf_arch=40
S2C:elf_osabi=0
S2C:r0=0x00000000;
S2C:r1=0xc7822000;
S2C:r2=0xc7823f48;
S2C:r3=0x00000003;
S2C:r4=0x00000000;
S2C:r5=0x00000000;
S2C:r6=0x00000000;
S2C:r7=0x00000000;
S2C:r8=0x00000000;
S2C:r9=0x00000000;
S2C:r10=0x00000000;
S2C:fp=0xc7823ff4;
S2C:ip=0xc7823f48;
S2C:sp=0xc7823fd8;
S2C:lr=0xc01911f8;
S2C:pc=0xc0008470;
S2C:cpsr=0x60000013;
S2C:ORIG_r0=0xffffffff;

S2C:stack=0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
S2C:stack=0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
S2C:stack=0x00, 0x00, 0x00, 0x00, 0xf8, 0x3f, 0x82, 0xc7,
S2C:stack=0x60, 0x26, 0x04, 0xc0, 0xa8, 0x83, 0x00, 0xc0,
S2C:stack=0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
S2C:commandline=console=ttyAMA0,115200 ip=dhcp root=/dev/nfs
nfsroot=10.0.2.2:/home/teawater/kernel/arm_versatile_926ejs.glibc_std.standard/export/dist,nfsvers=2,mountprog=21111,nfsprog=11111,udp
rw highres=off UMA=1

Save it to file t.txt.  This is the reg message and stack message.

Get the s2c program.
cd linux-2.6/tools/s2c
sudo make install

Get the core file.
s2c < t.txt >core

Use core file.
gdb ./vmlinux core
Core was generated by `console=ttyAMA0,115200 ip=dhcp root=/dev/nfs
nfsroot=10.0.2.2:/home/teawater/ke'.
[New process 0]
#0  0xc0008470 in kernel_init (unused=<value optimized out>)
    at /home/teawater/kernel/arm_versatile_926ejs.glibc_std.standard/build/linux/init/main.c:916
916		buf[0] = 3;
(gdb) bt
#0  0xc0008470 in kernel_init (unused=<value optimized out>)
    at /home/teawater/kernel/arm_versatile_926ejs.glibc_std.standard/build/linux/init/main.c:916
#1  0xc0042660 in sys_waitid (which=<value optimized out>, upid=<value
optimized out>, infop=0x0, options=0, ru=0x14)
    at /home/teawater/kernel/arm_versatile_926ejs.glibc_std.standard/build/linux/kernel/exit.c:1798
Backtrace stopped: previous frame inner to this frame (corrupt stack?)
(gdb) frame 1
#1  0xc0042660 in sys_waitid (which=<value optimized out>, upid=<value
optimized out>, infop=0x0, options=0, ru=0x14)
    at /home/teawater/kernel/arm_versatile_926ejs.glibc_std.standard/build/linux/kernel/exit.c:1798
1798			pid = find_get_pid(upid);
(gdb) p pid
$1 = (struct pid *) 0x0

It can support lkm:
The stack message will include:
S2C:add-symbol-file e.ko 0xffffffffa0000000
In gdb, use command "add-symbol-file e.ko 0xffffffffa0000000" let gdb
load the symbol of this lkm.


Now, stack2core support x86, x8664, arm, mips.

Thanks,
Hui

---
 arch/arm/kernel/traps.c        |   27 +
 arch/mips/kernel/traps.c       |   20
 arch/x86/kernel/dumpstack_32.c |   27 +
 arch/x86/kernel/dumpstack_64.c |   31 +
 include/linux/module.h         |    4
 include/linux/stack2core.h     |   49 +
 kernel/module.c                |   13
 lib/Kconfig.debug              |    9
 tools/s2c/Makefile             |   15
 tools/s2c/s2c.c                | 1009 +++++++++++++++++++++++++++++++++++++++++
 10 files changed, 1204 insertions(+)

--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -28,6 +28,7 @@
 #include <asm/unistd.h>
 #include <asm/traps.h>
 #include <asm/unwind.h>
+#include <linux/stack2core.h>

 #include "ptrace.h"
 #include "signal.h"
@@ -242,6 +243,32 @@ static void __die(const char *str, int e
 			 THREAD_SIZE + (unsigned long)task_stack_page(tsk));
 		dump_backtrace(regs, tsk);
 		dump_instr(KERN_EMERG, regs);
+
+#ifdef CONFIG_STACK2CORE
+		stack2core_header();
+
+		/* Show the registers */
+		printk(S2CMARK"r0=0x%08x;\n", (unsigned int)regs->ARM_r0);
+		printk(S2CMARK"r1=0x%08x;\n", (unsigned int)regs->ARM_r1);
+		printk(S2CMARK"r2=0x%08x;\n", (unsigned int)regs->ARM_r2);
+		printk(S2CMARK"r3=0x%08x;\n", (unsigned int)regs->ARM_r3);
+		printk(S2CMARK"r4=0x%08x;\n", (unsigned int)regs->ARM_r4);
+		printk(S2CMARK"r5=0x%08x;\n", (unsigned int)regs->ARM_r5);
+		printk(S2CMARK"r6=0x%08x;\n", (unsigned int)regs->ARM_r6);
+		printk(S2CMARK"r7=0x%08x;\n", (unsigned int)regs->ARM_r7);
+		printk(S2CMARK"r8=0x%08x;\n", (unsigned int)regs->ARM_r8);
+		printk(S2CMARK"r9=0x%08x;\n", (unsigned int)regs->ARM_r9);
+		printk(S2CMARK"r10=0x%08x;\n", (unsigned int)regs->ARM_r10);
+		printk(S2CMARK"fp=0x%08x;\n", (unsigned int)regs->ARM_fp);
+		printk(S2CMARK"ip=0x%08x;\n", (unsigned int)regs->ARM_ip);
+		printk(S2CMARK"sp=0x%08x;\n", (unsigned int)regs->ARM_sp);
+		printk(S2CMARK"lr=0x%08x;\n", (unsigned int)regs->ARM_lr);
+		printk(S2CMARK"pc=0x%08x;\n", (unsigned int)regs->ARM_pc);
+		printk(S2CMARK"cpsr=0x%08x;\n", (unsigned int)regs->ARM_cpsr);
+		printk(S2CMARK"ORIG_r0=0x%08x;\n", (unsigned int)regs->ARM_ORIG_r0);
+
+		stack2core_tail((uint8_t *)(regs->ARM_sp));
+#endif	/* CONFIG_STACK2CORE */
 	}
 }

--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -347,6 +347,26 @@ void show_registers(const struct pt_regs
 	show_stacktrace(current, regs);
 	show_code((unsigned int __user *) regs->cp0_epc);
 	printk("\n");
+#ifdef CONFIG_STACK2CORE
+	stack2core_header();
+
+	/* Show the registers */
+	{
+		int	i;
+
+		for (i = 0; i < 32; i++)
+			printk(S2CMARK"r%d=0x%lx;\n", i, regs->regs[i]);
+
+		printk(S2CMARK"cp0_status=0x%lx;\n", regs->cp0_status);
+		printk(S2CMARK"hi=0x%lx;\n", regs->hi);
+		printk(S2CMARK"lo=0x%lx;\n", regs->lo);
+		printk(S2CMARK"cp0_badvaddr=0x%lx;\n", regs->cp0_badvaddr);
+		printk(S2CMARK"cp0_cause=0x%lx;\n", regs->cp0_cause);
+		printk(S2CMARK"cp0_epc=0x%lx;\n", regs->cp0_epc);
+	}
+
+	stack2core_tail((uint8_t *)(regs->regs[29]));
+#endif	/* CONFIG_STACK2CORE */
 }

 static DEFINE_SPINLOCK(die_lock);
--- a/arch/x86/kernel/dumpstack_32.c
+++ b/arch/x86/kernel/dumpstack_32.c
@@ -13,6 +13,7 @@
 #include <linux/sysfs.h>
 #include <linux/bug.h>
 #include <linux/nmi.h>
+#include <linux/stack2core.h>

 #include <asm/stacktrace.h>

@@ -141,6 +142,32 @@ void show_registers(struct pt_regs *regs
 			else
 				printk("%02x ", c);
 		}
+
+#ifdef CONFIG_STACK2CORE
+		printk("\n");
+		stack2core_header();
+
+		/* Show the registers */
+		printk(S2CMARK"bx=0x%08x;\n", (unsigned int)regs->bx);
+		printk(S2CMARK"cx=0x%08x;\n", (unsigned int)regs->cx);
+		printk(S2CMARK"dx=0x%08x;\n", (unsigned int)regs->dx);
+		printk(S2CMARK"si=0x%08x;\n", (unsigned int)regs->si);
+		printk(S2CMARK"di=0x%08x;\n", (unsigned int)regs->di);
+		printk(S2CMARK"bp=0x%08x;\n", (unsigned int)regs->bp);
+		printk(S2CMARK"ax=0x%08x;\n", (unsigned int)regs->ax);
+		printk(S2CMARK"ds=0x%08x;\n", (unsigned int)regs->ds);
+		printk(S2CMARK"es=0x%08x;\n", (unsigned int)regs->es);
+		printk(S2CMARK"fs=0x%08x;\n", (unsigned int)regs->fs);
+		printk(S2CMARK"gs=0x%08x;\n", (unsigned int)regs->gs);
+		printk(S2CMARK"orig_ax=0x%08x;\n", (unsigned int)regs->orig_ax);
+		printk(S2CMARK"ip=0x%08x;\n", (unsigned int)regs->ip);
+		printk(S2CMARK"cs=0x%08x;\n", (unsigned int)regs->cs);
+		printk(S2CMARK"flags=0x%08x;\n", (unsigned int)regs->flags);
+		printk(S2CMARK"sp=0x%08x;\n", (unsigned int)&regs->sp);
+		printk(S2CMARK"ss=0x%08x;\n", (unsigned int)regs->ss);
+
+		stack2core_tail((uint8_t *)(&regs->sp));
+#endif	/* CONFIG_STACK2CORE */
 	}
 	printk("\n");
 }
--- a/arch/x86/kernel/dumpstack_64.c
+++ b/arch/x86/kernel/dumpstack_64.c
@@ -13,6 +13,7 @@
 #include <linux/sysfs.h>
 #include <linux/bug.h>
 #include <linux/nmi.h>
+#include <linux/stack2core.h>

 #include <asm/stacktrace.h>

@@ -328,6 +329,36 @@ void show_registers(struct pt_regs *regs
 			else
 				printk("%02x ", c);
 		}
+
+#ifdef CONFIG_STACK2CORE
+		printk("\n");
+		stack2core_header();
+
+		/* Show the registers */
+		printk(S2CMARK"r15=0x%016x;\n", (unsigned long)regs->r15);
+		printk(S2CMARK"r14=0x%016x;\n", (unsigned long)regs->r14);
+		printk(S2CMARK"r13=0x%016x;\n", (unsigned long)regs->r13);
+		printk(S2CMARK"r12=0x%016x;\n", (unsigned long)regs->r12);
+		printk(S2CMARK"bp=0x%016x;\n", (unsigned long)regs->bp);
+		printk(S2CMARK"bx=0x%016x;\n", (unsigned long)regs->bx);
+		printk(S2CMARK"r11=0x%016x;\n", (unsigned long)regs->r11);
+		printk(S2CMARK"r10=0x%016x;\n", (unsigned long)regs->r10);
+		printk(S2CMARK"r9=0x%016x;\n", (unsigned long)regs->r9);
+ 		printk(S2CMARK"r8=0x%016x;\n", (unsigned long)regs->r8);
+		printk(S2CMARK"ax=0x%016x;\n", (unsigned long)regs->ax);
+		printk(S2CMARK"cx=0x%016x;\n", (unsigned long)regs->cx);
+		printk(S2CMARK"dx=0x%016x;\n", (unsigned long)regs->dx);
+		printk(S2CMARK"si=0x%016x;\n", (unsigned long)regs->si);
+		printk(S2CMARK"di=0x%016x;\n", (unsigned long)regs->di);
+		printk(S2CMARK"orig_ax=0x%016x;\n", (unsigned long)regs->orig_ax);
+		printk(S2CMARK"ip=0x%016x;\n", (unsigned long)regs->ip);
+		printk(S2CMARK"cs=0x%016x;\n", (unsigned long)regs->cs);
+		printk(S2CMARK"flags=0x%016x;\n", (unsigned long)regs->flags);
+		printk(S2CMARK"sp=0x%016x;\n", (unsigned long)regs->sp);
+		printk(S2CMARK"ss=0x%016x;\n", (unsigned long)regs->ss);
+
+		stack2core_tail((uint8_t *)(regs->sp));
+#endif	/* CONFIG_STACK2CORE */
 	}
 	printk("\n");
 }
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -726,4 +726,8 @@ static inline int  module_bug_finalize(c
 static inline void module_bug_cleanup(struct module *mod) {}
 #endif	/* CONFIG_GENERIC_BUG */

+#ifdef CONFIG_STACK2CORE
+extern void module_print_address_for_s2c (void);
+#endif	/* CONFIG_STACK2CORE */
+
 #endif /* _LINUX_MODULE_H */
--- /dev/null
+++ b/include/linux/stack2core.h
@@ -0,0 +1,49 @@
+/*
+ *  Copyright (C) 2009, 2010, Hui Zhu
+ */
+#ifndef _STACK2CORE_H_
+#define _STACK2CORE_H_
+
+#ifdef CONFIG_STACK2CORE
+
+#define S2CMARK	KERN_EMERG "S2C:"
+
+static inline void
+stack2core_header(void)
+{
+	printk(S2CMARK"elf_class=%d\n", ELF_CLASS);
+	printk(S2CMARK"elf_data=%d\n", ELF_DATA);
+	printk(S2CMARK"elf_arch=%d\n", ELF_ARCH);
+	printk(S2CMARK"elf_osabi=%d\n", ELF_OSABI);
+}
+
+static inline void
+stack2core_tail(uint8_t *stack)
+{
+	int	i = 7;
+	uint8_t	*stack_end = (uint8_t *)(((unsigned long)stack &
(~(THREAD_SIZE - 1))) + THREAD_SIZE);
+
+	/* Show stack.  */
+	for (; stack < stack_end; stack++) {
+		if (i > 6) {
+			printk("\n");
+			printk(S2CMARK"stack=0x%02x,", stack[0]);
+			i = 0;
+		}
+		else {
+			printk(" 0x%02x,", stack[0]);
+			i ++;
+		}
+	}
+	printk("\n");
+
+	/* Show the modules.  */
+	module_print_address_for_s2c ();
+
+	/* Show command line.  */
+	printk(S2CMARK"commandline=%s\n", saved_command_line);
+}
+
+#endif	/* CONFIG_STACK2CORE */
+
+#endif /* _STACK2CORE_H_ */
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -55,6 +55,7 @@
 #include <linux/async.h>
 #include <linux/percpu.h>
 #include <linux/kmemleak.h>
+#include <linux/stack2core.h>

 #define CREATE_TRACE_POINTS
 #include <trace/events/module.h>
@@ -3014,3 +3015,15 @@ int module_get_iter_tracepoints(struct t
 	return found;
 }
 #endif
+
+#ifdef CONFIG_STACK2CORE
+void
+module_print_address_for_s2c (void)
+{
+	struct module *mod;
+
+	list_for_each_entry(mod, &modules, list)
+		printk(S2CMARK"add-symbol-file %s.ko 0x%p\n",
+			mod->name, mod->module_core);
+}
+#endif	/* CONFIG_STACK2CORE */
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -322,6 +322,15 @@ config DEBUG_SLAB
 	  allocation as well as poisoning memory on free to catch use of freed
 	  memory. This can make kmalloc/kfree-intensive workloads much slower.

+config STACK2CORE
+	bool "Output stack data when kernel die."
+	depends on DEBUG_KERNEL && (X86 || MIPS || ARM)
+	default y
+	help
+	  If say Y here, kernel will output stack data when it die.  This data
+	  can be convert to core file through program stack2core.  Then GDB can
+	  do clear backtrace with this core file.
+
 config DEBUG_SLAB_LEAK
 	bool "Memory leak debugging"
 	depends on DEBUG_SLAB
--- /dev/null
+++ b/tools/s2c/Makefile
@@ -0,0 +1,15 @@
+TARGET = s2c
+CC = gcc
+CFLAGS = -g
+
+
+all: $(TARGET)
+
+$(TARGET): $(TARGET).c
+	$(CC) $(CFLAGS) $(TARGET).c -o $(TARGET)
+
+clean:
+	rm -rf $(TARGET)
+
+install: $(TARGET)
+	cp $(TARGET) /bin/
--- /dev/null
+++ b/tools/s2c/s2c.c
@@ -0,0 +1,1009 @@
+/*
+ *  Copyright (C) 2009, 2010, Hui Zhu
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <ctype.h>
+#include <byteswap.h>
+
+#define S2CMARK		"S2C:"
+
+#define S2C_ELFCLASS32	1
+#define S2C_ELFCLASS64	2
+
+#define S2C_ELFDATA2LSB	1	/* little endian */
+#define S2C_ELFDATA2MSB	2	/* big endian */
+
+#define S2C_EM_386	3
+#define S2C_EM_X86_64	62
+#define S2C_EM_ARM	40
+#define S2C_EM_MIPS	8
+
+#define NEEDSWAP	((BYTE_ORDER == LITTLE_ENDIAN \
+                          && elf_data == S2C_ELFDATA2MSB) \
+		         || (BYTE_ORDER == BIG_ENDIAN \
+                             && elf_data == S2C_ELFDATA2LSB))
+#define SWAP16(a)	(NEEDSWAP ? bswap_16 (a) : a)
+#define SWAP32(a)	(NEEDSWAP ? bswap_32 (a) : a)
+#define SWAP64(a)	(NEEDSWAP ? bswap_64 (a) : a)
+
+#define GETU32(ul, str) \
+	if (strncmp (line, str, strlen (str)) == 0) { \
+		ul = strtoul (line + strlen (str), NULL, 0); \
+		return 0; \
+	}
+
+#define GETU64(ul, str) \
+	if (strncmp (line, str, strlen (str)) == 0) { \
+		ul = strtoull (line + strlen (str), NULL, 0); \
+		return 0; \
+	}
+
+/* Parse and save the input.  */
+
+uint8_t	elf_class = 0;
+uint8_t	elf_data = 0;
+uint8_t	elf_arch = 0;
+uint8_t	elf_osabi = 0;
+
+#define S2C_ELF_PRARGSZ	(80)
+uint8_t	commandline[S2C_ELF_PRARGSZ];
+
+#define S2C_THREAD_SIZE	8192
+uint8_t	stack[S2C_THREAD_SIZE];
+int stack_len = 0;
+
+uint32_t	sp_32 = 0;
+uint64_t	sp_64 = 0;
+
+/* I386 */
+
+uint32_t	i386_bx = 0;
+uint32_t	i386_cx = 0;
+uint32_t	i386_dx = 0;
+uint32_t	i386_si = 0;
+uint32_t	i386_di = 0;
+uint32_t	i386_bp = 0;
+uint32_t	i386_ax = 0;
+uint32_t	i386_ds = 0;
+uint32_t	i386_es = 0;
+uint32_t	i386_fs = 0;
+uint32_t	i386_gs = 0;
+uint32_t	i386_orig_ax = 0;
+uint32_t	i386_ip = 0;
+uint32_t	i386_cs = 0;
+uint32_t	i386_flags = 0;
+uint32_t	i386_sp = 0;
+uint32_t	i386_ss = 0;
+
+int
+parse_line_i386 (char *line)
+{
+	GETU32 (i386_bx, "bx=");
+	GETU32 (i386_cx, "cx=");
+	GETU32 (i386_dx, "dx=");
+	GETU32 (i386_si, "si=");
+	GETU32 (i386_di, "di=");
+	GETU32 (i386_bp, "bp=");
+	GETU32 (i386_ax, "ax=");
+	GETU32 (i386_ds, "ds=");
+	GETU32 (i386_es, "es=");
+	GETU32 (i386_fs, "fs=");
+	GETU32 (i386_gs, "gs=");
+	GETU32 (i386_orig_ax, "orig_ax=");
+	GETU32 (i386_ip, "ip=");
+	GETU32 (i386_cs, "cs=");
+	GETU32 (i386_flags, "flags=");
+	GETU32 (i386_sp, "sp=");
+	GETU32 (i386_ss, "ss=");
+
+	return 0;
+}
+
+/* x86_64 */
+
+uint64_t	x86_64_r15 = 0;
+uint64_t	x86_64_r14 = 0;
+uint64_t	x86_64_r13 = 0;
+uint64_t	x86_64_r12 = 0;
+uint64_t	x86_64_bp = 0;
+uint64_t	x86_64_bx = 0;
+uint64_t	x86_64_r11 = 0;
+uint64_t	x86_64_r10 = 0;
+uint64_t	x86_64_r9 = 0;
+uint64_t	x86_64_r8 = 0;
+uint64_t	x86_64_ax = 0;
+uint64_t	x86_64_cx = 0;
+uint64_t	x86_64_dx = 0;
+uint64_t	x86_64_si = 0;
+uint64_t	x86_64_di = 0;
+uint64_t	x86_64_orig_ax = 0;
+uint64_t	x86_64_ip = 0;
+uint64_t	x86_64_cs = 0;
+uint64_t	x86_64_flags = 0;
+uint64_t	x86_64_sp = 0;
+uint64_t	x86_64_ss = 0;
+
+int
+parse_line_x86_64 (char *line)
+{
+	GETU64 (x86_64_r15, "r15=");
+	GETU64 (x86_64_r14, "r14=");
+	GETU64 (x86_64_r13, "r13=");
+	GETU64 (x86_64_r12, "r12=");
+	GETU64 (x86_64_bp, "bp=");
+	GETU64 (x86_64_bx, "bx=");
+	GETU64 (x86_64_r11, "r11=");
+	GETU64 (x86_64_r10, "r10=");
+	GETU64 (x86_64_r9, "r9=");
+	GETU64 (x86_64_r8, "r8=");
+	GETU64 (x86_64_ax, "ax=");
+	GETU64 (x86_64_cx, "cx=");
+	GETU64 (x86_64_dx, "dx=");
+	GETU64 (x86_64_si, "si=");
+	GETU64 (x86_64_di, "di=");
+	GETU64 (x86_64_orig_ax, "orig_ax=");
+	GETU64 (x86_64_ip, "ip=");
+	GETU64 (x86_64_cs, "cs=");
+	GETU64 (x86_64_flags, "flags=");
+	GETU64 (x86_64_sp, "sp=");
+	GETU64 (x86_64_ss, "ss=");
+
+	return 0;
+}
+
+/* arm */
+
+uint32_t	arm_r0 = 0;
+uint32_t	arm_r1 = 0;
+uint32_t	arm_r2 = 0;
+uint32_t	arm_r3 = 0;
+uint32_t	arm_r4 = 0;
+uint32_t	arm_r5 = 0;
+uint32_t	arm_r6 = 0;
+uint32_t	arm_r7 = 0;
+uint32_t	arm_r8 = 0;
+uint32_t	arm_r9 = 0;
+uint32_t	arm_r10 = 0;
+uint32_t	arm_fp = 0;
+uint32_t	arm_ip = 0;
+uint32_t	arm_sp = 0;
+uint32_t	arm_lr = 0;
+uint32_t	arm_pc = 0;
+uint32_t	arm_cpsr = 0;
+uint32_t	arm_ORIG_r0 = 0;
+
+int
+parse_line_arm (char *line)
+{
+	GETU32 (arm_r0, "r0=");
+	GETU32 (arm_r1, "r1=");
+	GETU32 (arm_r2, "r2=");
+	GETU32 (arm_r3, "r3=");
+	GETU32 (arm_r4, "r4=");
+	GETU32 (arm_r5, "r5=");
+	GETU32 (arm_r6, "r6=");
+	GETU32 (arm_r7, "r7=");
+	GETU32 (arm_r8, "r8=");
+	GETU32 (arm_r9, "r9=");
+	GETU32 (arm_r10, "r10=");
+	GETU32 (arm_fp, "fp=");
+	GETU32 (arm_ip, "ip=");
+	GETU32 (arm_sp, "sp=");
+	GETU32 (arm_lr, "lr=");
+	GETU32 (arm_pc, "pc=");
+	GETU32 (arm_cpsr, "cpsr=");
+	GETU32 (arm_ORIG_r0, "ORIG_r0=");
+
+	return 0;
+}
+
+/* mips */
+
+uint32_t	mips32_r[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+				0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+				0, 0};
+uint32_t	mips32_hi = 0;
+uint32_t	mips32_lo = 0;
+uint32_t	mips32_cp0_epc = 0;
+uint32_t	mips32_cp0_badvaddr = 0;
+uint32_t	mips32_cp0_status = 0;
+uint32_t	mips32_cp0_cause = 0;
+
+
+uint64_t	mips64_r[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+				0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+				0, 0};
+uint64_t	mips64_hi = 0;
+uint64_t	mips64_lo = 0;
+uint64_t	mips64_cp0_epc = 0;
+uint64_t	mips64_cp0_badvaddr = 0;
+uint64_t	mips64_cp0_status = 0;
+uint64_t	mips64_cp0_cause = 0;
+
+int
+parse_line_mips (char *line)
+{
+	int	i;
+	char	str[10];
+
+	if (elf_class == S2C_ELFCLASS32) {
+		for (i = 0; i < 32; i++) {
+			snprintf (str, 10, "r%d=", i);
+			GETU32 (mips32_r[i], str);
+		}
+		GETU32 (mips32_cp0_status, "cp0_status=");
+		GETU32 (mips32_hi, "hi=");
+		GETU32 (mips32_lo, "lo=");
+		GETU32 (mips32_cp0_badvaddr, "cp0_badvaddr=");
+		GETU32 (mips32_cp0_cause, "cp0_cause=");
+		GETU32 (mips32_cp0_epc, "cp0_epc=");
+	}
+	else {
+		for (i = 0; i < 32; i++) {
+			snprintf (str, 10, "r%d=", i);
+			GETU64 (mips64_r[i], str);
+		}
+		GETU64 (mips64_cp0_status, "cp0_status=");
+		GETU64 (mips64_hi, "hi=");
+		GETU64 (mips64_lo, "lo=");
+		GETU64 (mips64_cp0_badvaddr, "cp0_badvaddr=");
+		GETU64 (mips64_cp0_cause, "cp0_cause=");
+		GETU64 (mips64_cp0_epc, "cp0_epc=");
+	}
+
+	return 0;
+}
+
+int
+parse_line (char *line)
+{
+	GETU32 (elf_class, "elf_class=");
+	GETU32 (elf_data, "elf_data=");
+	GETU32 (elf_arch, "elf_arch=");
+	GETU32 (elf_osabi, "elf_osabi=");
+
+	if (strncmp (line, "stack=", sizeof ("stack=") - 1) == 0) {
+		line += sizeof ("stack=") - 1;
+
+		while (stack_len < S2C_THREAD_SIZE && line[0]) {
+			if (isdigit (line[0]))
+				stack[stack_len++] = strtoul (line, &line, 0);
+			else
+				line++;
+		}
+		return 0;
+	}
+
+	if (strncmp (line, "commandline=", sizeof ("commandline=") - 1) == 0) {
+		snprintf ((char *)commandline, S2C_ELF_PRARGSZ, "%s",
+			  line + sizeof ("commandline=") - 1);
+		return 0;
+	}
+
+	switch (elf_arch) {
+		case S2C_EM_386:
+			return parse_line_i386 (line);
+			break;
+		case S2C_EM_X86_64:
+			return parse_line_x86_64 (line);
+			break;
+		case S2C_EM_ARM:
+			return parse_line_arm (line);
+			break;
+		case S2C_EM_MIPS:
+			return parse_line_mips (line);
+			break;
+	}
+
+	return 0;
+}
+
+void
+iterate_over_lines (FILE *fp)
+{
+	char	line[256], *linep;
+
+	if (!fp) {
+		fprintf(stderr, "Parse input error.\n");
+		exit (-1);
+	}
+
+	while(fgets(line, 256, fp) != NULL) {
+		linep = line;
+                linep = strstr (linep, S2CMARK);
+		if (linep) {
+			linep += sizeof (S2CMARK) - 1;
+			if (parse_line (linep)) {
+				fprintf(stderr, "Failied with parse line %s\n", line);
+				exit (-1);
+			}
+		}
+	}
+	if (ferror (fp)) {
+		fprintf(stderr, "Parse input error.\n");
+		exit (-1);
+	}
+}
+
+/* Convert and save to core_buf.  */
+
+uint8_t	core_buf[81920];
+int	core_buf_size = 0;
+
+#define S2C_EI_NIDENT	16
+
+typedef struct s2c_elf32_hdr_s {
+	uint8_t		e_ident[S2C_EI_NIDENT];
+	uint16_t	e_type;
+	uint16_t	e_machine;
+	uint32_t	e_version;
+	uint32_t	e_entry;
+	uint32_t	e_phoff;
+	uint32_t	e_shoff;
+	uint32_t	e_flags;
+	uint16_t	e_ehsize;
+	uint16_t	e_phentsize;
+	uint16_t	e_phnum;
+	uint16_t	e_shentsize;
+	uint16_t	e_shnum;
+	uint16_t	e_shstrndx;
+} s2c_elf32_hdr_t;
+
+typedef struct s2c_elf64_hdr_s {
+	uint8_t		e_ident[S2C_EI_NIDENT];
+	uint16_t	e_type;
+	uint16_t	e_machine;
+	uint32_t	e_version;
+	uint64_t	e_entry;
+	uint64_t	e_phoff;
+	uint64_t	e_shoff;
+	uint32_t	e_flags;
+	uint16_t	e_ehsize;
+	uint16_t	e_phentsize;
+	uint16_t	e_phnum;
+	uint16_t	e_shentsize;
+	uint16_t	e_shnum;
+	uint16_t	e_shstrndx;
+} s2c_elf64_hdr_t;
+
+#define	S2C_ELFMAG	"\177ELF"
+#define S2C_SELFMAG	4
+#define S2C_EI_CLASS	4
+#define S2C_EI_DATA	5
+#define	S2C_EI_VERSION	6
+#define S2C_EV_CURRENT	1
+#define	S2C_EI_OSABI	7
+#define S2C_ET_CORE	4
+
+typedef struct s2c_elf32_phdr_s {
+	uint32_t	p_type;
+	uint32_t	p_offset;
+	uint32_t	p_vaddr;
+	uint32_t	p_paddr;
+	uint32_t	p_filesz;
+	uint32_t	p_memsz;
+	uint32_t	p_flags;
+	uint32_t	p_align;
+} s2c_elf32_phdr_t;
+
+typedef struct s2c_elf64_phdr_s {
+	uint32_t	p_type;
+	uint32_t	p_flags;
+	uint64_t	p_offset;
+	uint64_t	p_vaddr;
+	uint64_t	p_paddr;
+	uint64_t	p_filesz;
+	uint64_t	p_memsz;
+	uint64_t	p_align;
+} s2c_elf64_phdr_t;
+
+#define S2C_PT_NOTE	4
+#define S2C_PT_LOAD	1
+#define S2C_PF_R		0x4
+
+uint8_t	*nhdr;
+uint8_t	*phdr;
+
+void
+elfhdr_32 (void)
+{
+	s2c_elf32_hdr_t	*elf;
+	s2c_elf32_phdr_t	*nhdrp;
+	s2c_elf32_phdr_t	*phdrp;
+
+	elf = (s2c_elf32_hdr_t *)(core_buf + core_buf_size);
+	core_buf_size += sizeof (s2c_elf32_hdr_t);
+	memset(elf, 0, sizeof(*elf));
+	memcpy(elf->e_ident, S2C_ELFMAG, S2C_SELFMAG);
+	elf->e_ident[S2C_EI_CLASS] = elf_class;
+	elf->e_ident[S2C_EI_DATA] = elf_data;
+	elf->e_ident[S2C_EI_VERSION] = S2C_EV_CURRENT;
+	elf->e_ident[S2C_EI_OSABI] = elf_osabi;
+	elf->e_type = SWAP16 (S2C_ET_CORE);
+	elf->e_machine = SWAP16 (elf_arch);
+	elf->e_version = SWAP32 (S2C_EV_CURRENT);
+	elf->e_phoff = SWAP32 (sizeof (s2c_elf32_hdr_t));
+	elf->e_flags = 0;
+	elf->e_ehsize = SWAP16 (sizeof (s2c_elf32_hdr_t));
+	elf->e_phentsize = SWAP16 (sizeof (s2c_elf32_phdr_t));
+	/* segs including notes section (vma + 1) */
+	elf->e_phnum = SWAP16 (1 + 1);
+
+	nhdr = core_buf + core_buf_size;
+	core_buf_size += sizeof (s2c_elf32_phdr_t);
+	nhdrp = (s2c_elf32_phdr_t *) nhdr;
+	nhdrp->p_type = SWAP32 (S2C_PT_NOTE);
+	nhdrp->p_offset = sizeof(s2c_elf32_hdr_t) + sizeof(s2c_elf32_phdr_t) * 2;
+	nhdrp->p_vaddr = 0;
+	nhdrp->p_paddr = 0;
+	nhdrp->p_filesz = 0;
+	nhdrp->p_memsz = 0;
+	nhdrp->p_flags = 0;
+	nhdrp->p_align = 0;
+
+	phdr = core_buf + core_buf_size;
+	core_buf_size += sizeof (s2c_elf32_phdr_t);
+	phdrp = (s2c_elf32_phdr_t *) phdr;
+	phdrp->p_type = SWAP32 (S2C_PT_LOAD);
+	phdrp->p_flags = SWAP32 (S2C_PF_R);
+	phdrp->p_offset = nhdrp->p_offset;
+	phdrp->p_vaddr = sp_32 & ~63;
+	phdrp->p_paddr = 0;
+	phdrp->p_filesz = phdrp->p_memsz = stack_len + (sp_32 - phdrp->p_vaddr);
+	phdrp->p_align = SWAP32 (1);
+}
+
+void
+elfhdr_64 (void)
+{
+	s2c_elf64_hdr_t	*elf;
+	s2c_elf64_phdr_t	*nhdrp;
+	s2c_elf64_phdr_t	*phdrp;
+
+	elf = (s2c_elf64_hdr_t *)(core_buf + core_buf_size);
+	core_buf_size += sizeof (s2c_elf64_hdr_t);
+	memset(elf, 0, sizeof(*elf));
+	memcpy(elf->e_ident, S2C_ELFMAG, S2C_SELFMAG);
+	elf->e_ident[S2C_EI_CLASS] = elf_class;
+	elf->e_ident[S2C_EI_DATA] = elf_data;
+	elf->e_ident[S2C_EI_VERSION] = S2C_EV_CURRENT;
+	elf->e_ident[S2C_EI_OSABI] = elf_osabi;
+	elf->e_type = SWAP16 (S2C_ET_CORE);
+	elf->e_machine = SWAP16 (elf_arch);
+	elf->e_version = SWAP32 (S2C_EV_CURRENT);
+	elf->e_phoff = SWAP64 (sizeof (s2c_elf64_hdr_t));
+	elf->e_flags = 0;
+	elf->e_ehsize = SWAP16 (sizeof (s2c_elf64_hdr_t));
+	elf->e_phentsize = SWAP16 (sizeof (s2c_elf64_phdr_t));
+	/* segs including notes section (vma + 1) */
+	elf->e_phnum = SWAP16 (1 + 1);
+
+	nhdr = core_buf + core_buf_size;
+	core_buf_size += sizeof (s2c_elf64_phdr_t);
+	nhdrp = (s2c_elf64_phdr_t *) nhdr;
+	nhdrp->p_type = SWAP32 (S2C_PT_NOTE);
+	nhdrp->p_offset = sizeof(s2c_elf64_hdr_t) + sizeof(s2c_elf64_phdr_t) * 2;
+	nhdrp->p_vaddr = 0;
+	nhdrp->p_paddr = 0;
+	nhdrp->p_filesz = 0;
+	nhdrp->p_memsz = 0;
+	nhdrp->p_flags = 0;
+	nhdrp->p_align = 0;
+
+	phdr = core_buf + core_buf_size;
+	core_buf_size += sizeof (s2c_elf64_phdr_t);
+	phdrp = (s2c_elf64_phdr_t *) phdr;
+	phdrp->p_type = SWAP32 (S2C_PT_LOAD);
+	phdrp->p_flags = SWAP32 (S2C_PF_R);
+	phdrp->p_offset = nhdrp->p_offset;
+	phdrp->p_vaddr = sp_64 & ~63;
+	phdrp->p_paddr = 0;
+	phdrp->p_filesz = phdrp->p_memsz = stack_len + (sp_64 - phdrp->p_vaddr);
+	phdrp->p_align = 1;
+}
+
+typedef struct elf_note_s {
+	uint32_t	n_namesz;
+	uint32_t	n_descsz;
+	uint32_t	n_type;
+} elf_note_t;
+
+#define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
+
+int
+fill_elf_note (uint8_t *p, const char *name,
+		int type, void **data, int data_len)
+{
+	int		ret = 0;
+	elf_note_t	*en = (elf_note_t *) p;
+
+	p += sizeof(elf_note_t);
+	ret += sizeof(elf_note_t);
+	en->n_namesz = strlen(name) + 1;
+	en->n_type = SWAP32 (type);
+	en->n_descsz = SWAP32 (data_len);
+
+	memcpy (p, name, en->n_namesz);
+	p += en->n_namesz;
+	p = (uint8_t *) roundup((unsigned long) p, 4);
+	ret += roundup((en->n_namesz), 4);
+
+	*data = p;
+	p += data_len;
+	p = (uint8_t *) roundup((unsigned long) p, 4);
+	ret += roundup(data_len, 4);
+
+	en->n_namesz = SWAP32 (en->n_namesz);
+
+	return ret;
+}
+
+#define S2C_NT_PRSTATUS	1
+
+struct s2c_elf_siginfo
+{
+	uint32_t	si_signo;
+	uint32_t	si_code;
+	uint32_t	si_errno;
+};
+
+struct s2c_timeval_32 {
+	uint32_t	tv_sec;
+	uint32_t	tv_usec;
+};
+
+struct s2c_timeval_64 {
+	uint64_t	tv_sec;
+	uint64_t	tv_usec;
+};
+
+/* i386 */
+
+struct i386_elf_prstatus
+{
+	struct s2c_elf_siginfo	pr_info;
+	uint16_t		pr_cursig;
+	uint32_t		pr_sigpend;
+	uint32_t		pr_sighold;
+	uint32_t		pr_pid;
+	uint32_t		pr_ppid;
+	uint32_t		pr_pgrp;
+	uint32_t		pr_sid;
+	struct s2c_timeval_32	pr_utime;
+	struct s2c_timeval_32	pr_stime;
+	struct s2c_timeval_32	pr_cutime;
+	struct s2c_timeval_32	pr_cstime;
+
+	uint32_t		pr_reg[17];
+
+	uint32_t		pr_fpvalid;
+} __attribute__ ((aligned(4)));
+
+void
+i386_elf_prstatus (void)
+{
+	int				offset;
+	struct i386_elf_prstatus	*pstat;
+
+	offset = fill_elf_note (core_buf + core_buf_size, "CORE",
+				S2C_NT_PRSTATUS,
+				((void **)&pstat),
+				sizeof(struct i386_elf_prstatus));
+	core_buf_size += offset;
+	((s2c_elf32_phdr_t *) nhdr)->p_filesz += offset;
+	memset (pstat, 0, sizeof(struct i386_elf_prstatus));
+	pstat->pr_reg[0] = SWAP32 (i386_bx);
+	pstat->pr_reg[1] = SWAP32 (i386_cx);
+	pstat->pr_reg[2] = SWAP32 (i386_dx);
+	pstat->pr_reg[3] = SWAP32 (i386_si);
+	pstat->pr_reg[4] = SWAP32 (i386_di);
+	pstat->pr_reg[5] = SWAP32 (i386_bp);
+	pstat->pr_reg[6] = SWAP32 (i386_ax);
+	pstat->pr_reg[7] = SWAP32 (i386_ds);
+	pstat->pr_reg[8] = SWAP32 (i386_es);
+	pstat->pr_reg[9] = SWAP32 (i386_fs);
+	pstat->pr_reg[10] = SWAP32 (i386_gs);
+	pstat->pr_reg[11] = SWAP32 (i386_orig_ax);
+	pstat->pr_reg[12] = SWAP32 (i386_ip);
+	pstat->pr_reg[13] = SWAP32 (i386_cs);
+	pstat->pr_reg[14] = SWAP32 (i386_flags);
+	pstat->pr_reg[15] = SWAP32 (i386_sp);
+	pstat->pr_reg[16] = SWAP32 (i386_ss);
+}
+
+/* x86_64 */
+
+struct x86_64_elf_prstatus
+{
+	struct s2c_elf_siginfo	pr_info;
+	uint16_t		pr_cursig;
+	uint64_t		pr_sigpend;
+	uint64_t		pr_sighold;
+	uint32_t		pr_pid;
+	uint32_t		pr_ppid;
+	uint32_t		pr_pgrp;
+	uint32_t		pr_sid;
+	struct s2c_timeval_64	pr_utime;
+	struct s2c_timeval_64	pr_stime;
+	struct s2c_timeval_64	pr_cutime;
+	struct s2c_timeval_64	pr_cstime;
+
+	uint64_t		pr_reg[27];
+
+	uint32_t		pr_fpvalid;
+} __attribute__ ((aligned(8)));
+
+void
+x86_64_elf_prstatus (void)
+{
+	int				offset;
+	struct x86_64_elf_prstatus	*pstat;
+
+	offset = fill_elf_note (core_buf + core_buf_size, "CORE",
+				S2C_NT_PRSTATUS,
+				((void **)&pstat),
+				sizeof(struct x86_64_elf_prstatus));
+	core_buf_size += offset;
+	((s2c_elf64_phdr_t *) nhdr)->p_filesz += offset;
+	memset (pstat, 0, sizeof(struct x86_64_elf_prstatus));
+	pstat->pr_reg[0] = SWAP64 (x86_64_r15);
+	pstat->pr_reg[1] = SWAP64 (x86_64_r14);
+	pstat->pr_reg[2] = SWAP64 (x86_64_r13);
+	pstat->pr_reg[3] = SWAP64 (x86_64_r12);
+	pstat->pr_reg[4] = SWAP64 (x86_64_bp);
+	pstat->pr_reg[5] = SWAP64 (x86_64_bx);
+	pstat->pr_reg[6] = SWAP64 (x86_64_r11);
+	pstat->pr_reg[7] = SWAP64 (x86_64_r10);
+	pstat->pr_reg[8] = SWAP64 (x86_64_r9);
+	pstat->pr_reg[9] = SWAP64 (x86_64_r8);
+	pstat->pr_reg[10] = SWAP64 (x86_64_ax);
+	pstat->pr_reg[11] = SWAP64 (x86_64_cx);
+	pstat->pr_reg[12] = SWAP64 (x86_64_dx);
+	pstat->pr_reg[13] = SWAP64 (x86_64_si);
+	pstat->pr_reg[14] = SWAP64 (x86_64_di);
+	pstat->pr_reg[15] = SWAP64 (x86_64_orig_ax);
+	pstat->pr_reg[16] = SWAP64 (x86_64_ip);
+	pstat->pr_reg[17] = SWAP64 (x86_64_cs);
+	pstat->pr_reg[18] = SWAP64 (x86_64_flags);
+	pstat->pr_reg[19] = SWAP64 (x86_64_sp);
+ 	pstat->pr_reg[20] = SWAP64 (x86_64_ss);
+}
+
+/* arm */
+
+struct arm_elf_prstatus
+{
+	struct s2c_elf_siginfo	pr_info;
+	uint16_t		pr_cursig;
+	uint32_t		pr_sigpend;
+	uint32_t		pr_sighold;
+	uint32_t		pr_pid;
+	uint32_t		pr_ppid;
+	uint32_t		pr_pgrp;
+	uint32_t		pr_sid;
+	struct s2c_timeval_32	pr_utime;
+	struct s2c_timeval_32	pr_stime;
+	struct s2c_timeval_32	pr_cutime;
+	struct s2c_timeval_32	pr_cstime;
+
+	uint32_t		pr_reg[18];
+
+	uint32_t		pr_fpvalid;
+} __attribute__ ((aligned(4)));
+
+void
+arm_elf_prstatus (void)
+{
+	int				offset;
+	struct arm_elf_prstatus		*pstat;
+
+	offset = fill_elf_note (core_buf + core_buf_size, "CORE",
+				S2C_NT_PRSTATUS,
+				((void **)&pstat),
+				sizeof(struct arm_elf_prstatus));
+	core_buf_size += offset;
+	((s2c_elf32_phdr_t *) nhdr)->p_filesz += offset;
+	memset (pstat, 0, sizeof(struct arm_elf_prstatus));
+	pstat->pr_reg[0] = SWAP32 (arm_r0);
+	pstat->pr_reg[1] = SWAP32 (arm_r1);
+	pstat->pr_reg[2] = SWAP32 (arm_r2);
+	pstat->pr_reg[3] = SWAP32 (arm_r3);
+	pstat->pr_reg[4] = SWAP32 (arm_r4);
+	pstat->pr_reg[5] = SWAP32 (arm_r5);
+	pstat->pr_reg[6] = SWAP32 (arm_r6);
+	pstat->pr_reg[7] = SWAP32 (arm_r7);
+	pstat->pr_reg[8] = SWAP32 (arm_r8);
+	pstat->pr_reg[9] = SWAP32 (arm_r9);
+	pstat->pr_reg[10] = SWAP32 (arm_r10);
+	pstat->pr_reg[11] = SWAP32 (arm_fp);
+	pstat->pr_reg[12] = SWAP32 (arm_ip);
+	pstat->pr_reg[13] = SWAP32 (arm_sp);
+	pstat->pr_reg[14] = SWAP32 (arm_lr);
+	pstat->pr_reg[15] = SWAP32 (arm_pc);
+	pstat->pr_reg[16] = SWAP32 (arm_cpsr);
+	pstat->pr_reg[17] = SWAP32 (arm_ORIG_r0);
+}
+
+/* mips */
+
+struct mips32_elf_prstatus
+{
+	struct s2c_elf_siginfo	pr_info;
+	uint16_t		pr_cursig;
+	uint32_t		pr_sigpend;
+	uint32_t		pr_sighold;
+	uint32_t		pr_pid;
+	uint32_t		pr_ppid;
+	uint32_t		pr_pgrp;
+	uint32_t		pr_sid;
+	struct s2c_timeval_32	pr_utime;
+	struct s2c_timeval_32	pr_stime;
+	struct s2c_timeval_32	pr_cutime;
+	struct s2c_timeval_32	pr_cstime;
+
+	uint32_t		pr_reg[45];
+
+	uint32_t		pr_fpvalid;
+} __attribute__ ((aligned(4)));
+
+struct mips64_elf_prstatus
+{
+	struct s2c_elf_siginfo	pr_info;
+	uint16_t		pr_cursig;
+	uint64_t		pr_sigpend;
+	uint64_t		pr_sighold;
+	uint32_t		pr_pid;
+	uint32_t		pr_ppid;
+	uint32_t		pr_pgrp;
+	uint32_t		pr_sid;
+	struct s2c_timeval_64	pr_utime;
+	struct s2c_timeval_64	pr_stime;
+	struct s2c_timeval_64	pr_cutime;
+	struct s2c_timeval_64	pr_cstime;
+
+	uint64_t		pr_reg[45];
+
+	uint32_t		pr_fpvalid;
+} __attribute__ ((aligned(8)));
+
+#define MIPS32_EF_R0		6
+#define MIPS32_EF_LO		38
+#define MIPS32_EF_HI		39
+#define MIPS32_EF_CP0_EPC	40
+#define MIPS32_EF_CP0_BADVADDR	41
+#define MIPS32_EF_CP0_STATUS	42
+#define MIPS32_EF_CP0_CAUSE	43
+
+#define MIPS64_EF_R0		0
+#define MIPS64_EF_LO		32
+#define MIPS64_EF_HI		33
+#define MIPS64_EF_CP0_EPC	34
+#define MIPS64_EF_CP0_BADVADDR	35
+#define MIPS64_EF_CP0_STATUS	36
+#define MIPS64_EF_CP0_CAUSE	37
+
+void
+mips_elf_prstatus (void)
+{
+	int	offset;
+
+	if (elf_class == S2C_ELFCLASS32) {
+		struct mips32_elf_prstatus	*pstat;
+
+		offset = fill_elf_note (core_buf + core_buf_size, "CORE",
+					S2C_NT_PRSTATUS,
+					((void **)&pstat),
+					sizeof(struct mips32_elf_prstatus));
+		core_buf_size += offset;
+		((s2c_elf32_phdr_t *) nhdr)->p_filesz += offset;
+		memset (pstat, 0, sizeof(struct mips32_elf_prstatus));
+
+		for (offset = 0; offset < 32; offset ++)
+			pstat->pr_reg[MIPS32_EF_R0 + offset] = SWAP32 (mips32_r[offset]);
+		pstat->pr_reg[MIPS32_EF_LO] = SWAP32 (mips32_lo);
+		pstat->pr_reg[MIPS32_EF_HI] = SWAP32 (mips32_hi);
+		pstat->pr_reg[MIPS32_EF_CP0_EPC] = SWAP32 (mips32_cp0_epc);
+		pstat->pr_reg[MIPS32_EF_CP0_BADVADDR] = SWAP32 (mips32_cp0_badvaddr);
+		pstat->pr_reg[MIPS32_EF_CP0_STATUS] = SWAP32 (mips32_cp0_status);
+		pstat->pr_reg[MIPS32_EF_CP0_CAUSE] = SWAP32 (mips32_cp0_cause);
+
+	}
+	else {
+		struct mips64_elf_prstatus	*pstat;
+
+		offset = fill_elf_note (core_buf + core_buf_size, "CORE",
+					S2C_NT_PRSTATUS,
+					((void **)&pstat),
+					sizeof(struct mips64_elf_prstatus));
+		core_buf_size += offset;
+		((s2c_elf64_phdr_t *) nhdr)->p_filesz += offset;
+		memset (pstat, 0, sizeof(struct mips64_elf_prstatus));
+
+		for (offset = 0; offset < 32; offset ++)
+			pstat->pr_reg[MIPS64_EF_R0 + offset] = SWAP64 (mips64_r[offset]);
+		pstat->pr_reg[MIPS64_EF_LO] = SWAP64 (mips64_lo);
+		pstat->pr_reg[MIPS64_EF_HI] = SWAP64 (mips64_hi);
+		pstat->pr_reg[MIPS64_EF_CP0_EPC] = SWAP64 (mips64_cp0_epc);
+		pstat->pr_reg[MIPS64_EF_CP0_BADVADDR] = SWAP64 (mips64_cp0_badvaddr);
+		pstat->pr_reg[MIPS64_EF_CP0_STATUS] = SWAP64 (mips64_cp0_status);
+		pstat->pr_reg[MIPS64_EF_CP0_CAUSE] = SWAP64 (mips64_cp0_cause);
+	}
+}
+
+struct s2c_elf_prpsinfo_32
+{
+	uint8_t		pr_state;
+	uint8_t		pr_sname;
+	uint8_t		pr_zomb;
+	uint8_t		pr_nice;
+	uint32_t	pr_flag;
+	uint16_t	pr_uid;
+	uint16_t	pr_gid;
+	uint32_t	pr_pid, pr_ppid, pr_pgrp, pr_sid;
+	uint8_t		pr_fname[16];
+	uint8_t		pr_psargs[S2C_ELF_PRARGSZ];
+};
+
+struct s2c_elf_prpsinfo_64
+{
+	uint8_t		pr_state;
+	uint8_t		pr_sname;
+	uint8_t		pr_zomb;
+	uint8_t		pr_nice;
+	uint64_t	pr_flag;
+	uint32_t	pr_uid;
+	uint32_t	pr_gid;
+	uint32_t	pr_pid, pr_ppid, pr_pgrp, pr_sid;
+	uint8_t		pr_fname[16];
+	uint8_t		pr_psargs[S2C_ELF_PRARGSZ];
+};
+
+#define S2C_NT_PRPSINFO	3
+
+void
+save_pinfo_32 (void)
+{
+	int				offset;
+	struct s2c_elf_prpsinfo_32	*pinfo;
+
+	offset = fill_elf_note (core_buf + core_buf_size, "CORE",
+				S2C_NT_PRPSINFO,
+				((void **)&pinfo),
+				sizeof(struct s2c_elf_prpsinfo_32));
+	core_buf_size += offset;
+	memset (pinfo, 0, sizeof(struct s2c_elf_prpsinfo_32));
+	pinfo->pr_state = 0;
+	pinfo->pr_sname = 'R';
+	pinfo->pr_zomb = 0;
+	strcpy((char *)pinfo->pr_fname, "vmlinux");
+	snprintf((char *)pinfo->pr_psargs, S2C_ELF_PRARGSZ, "%s", commandline);
+	((s2c_elf32_phdr_t *) nhdr)->p_filesz += offset;
+}
+
+void
+save_pinfo_64 (void)
+{
+	int				offset;
+	struct s2c_elf_prpsinfo_64	*pinfo;
+
+	offset = fill_elf_note (core_buf + core_buf_size, "CORE",
+				S2C_NT_PRPSINFO,
+				((void **)&pinfo),
+				sizeof(struct s2c_elf_prpsinfo_64));
+	core_buf_size += offset;
+	memset (pinfo, 0, sizeof(struct s2c_elf_prpsinfo_64));
+	pinfo->pr_state = 0;
+	pinfo->pr_sname = 'R';
+	pinfo->pr_zomb = 0;
+	strcpy((char *)pinfo->pr_fname, "vmlinux");
+	snprintf((char *)pinfo->pr_psargs, S2C_ELF_PRARGSZ, "%s", commandline);
+	((s2c_elf64_phdr_t *) nhdr)->p_filesz += offset;
+}
+
+void
+stack_32 (void)
+{
+	((s2c_elf32_phdr_t *) phdr)->p_offset += ((s2c_elf32_phdr_t *)
nhdr)->p_filesz;
+	memset (core_buf + core_buf_size, 0, (sp_32 - ((s2c_elf32_phdr_t *)
phdr)->p_vaddr));
+	core_buf_size += sp_32 - ((s2c_elf32_phdr_t *) phdr)->p_vaddr;
+	memcpy (core_buf + core_buf_size, stack, stack_len);
+	core_buf_size += stack_len;
+
+	if (NEEDSWAP) {
+		((s2c_elf32_phdr_t *) nhdr)->p_offset = bswap_32(((s2c_elf32_phdr_t
*) nhdr)->p_offset);
+		((s2c_elf32_phdr_t *) nhdr)->p_filesz = bswap_32(((s2c_elf32_phdr_t
*) nhdr)->p_filesz);
+		((s2c_elf32_phdr_t *) phdr)->p_offset = bswap_32(((s2c_elf32_phdr_t
*) phdr)->p_offset);
+		((s2c_elf32_phdr_t *) phdr)->p_vaddr = bswap_32(((s2c_elf32_phdr_t
*) phdr)->p_vaddr);
+		((s2c_elf32_phdr_t *) phdr)->p_filesz = bswap_32(((s2c_elf32_phdr_t
*) phdr)->p_filesz);
+		((s2c_elf32_phdr_t *) phdr)->p_memsz = bswap_32(((s2c_elf32_phdr_t
*) phdr)->p_memsz);
+	}
+}
+
+void
+stack_64 (void)
+{
+	((s2c_elf64_phdr_t *) phdr)->p_offset += ((s2c_elf64_phdr_t *)
nhdr)->p_filesz;
+	memset (core_buf + core_buf_size, 0, (sp_64 - ((s2c_elf64_phdr_t *)
phdr)->p_vaddr));
+	core_buf_size += sp_64 - ((s2c_elf64_phdr_t *) phdr)->p_vaddr;
+	memcpy (core_buf + core_buf_size, stack, stack_len);
+	core_buf_size += stack_len;
+
+	if (NEEDSWAP) {
+		((s2c_elf64_phdr_t *) nhdr)->p_offset = bswap_64(((s2c_elf64_phdr_t
*) nhdr)->p_offset);
+		((s2c_elf64_phdr_t *) nhdr)->p_filesz = bswap_64(((s2c_elf64_phdr_t
*) nhdr)->p_filesz);
+		((s2c_elf64_phdr_t *) phdr)->p_offset = bswap_64(((s2c_elf64_phdr_t
*) phdr)->p_offset);
+		((s2c_elf64_phdr_t *) phdr)->p_vaddr = bswap_64(((s2c_elf64_phdr_t
*) phdr)->p_vaddr);
+		((s2c_elf64_phdr_t *) phdr)->p_filesz = bswap_64(((s2c_elf64_phdr_t
*) phdr)->p_filesz);
+		((s2c_elf64_phdr_t *) phdr)->p_memsz = bswap_64(((s2c_elf64_phdr_t
*) phdr)->p_memsz);
+	}
+}
+
+int
+main(int argc,char *argv[],char *envp[])
+{
+	/* Parse and save the input.  */
+	iterate_over_lines (stdin);
+	/* Set sp.  */
+	switch (elf_arch) {
+		case S2C_EM_386:
+			sp_32 = i386_sp;
+			break;
+		case S2C_EM_X86_64:
+			sp_64 = x86_64_sp;
+			break;
+		case S2C_EM_ARM:
+			sp_32 = arm_sp;
+			break;
+		case S2C_EM_MIPS:
+			if (elf_class == S2C_ELFCLASS32)
+				sp_32 = mips32_r[29];
+			else
+				sp_64 = mips64_r[29];
+			break;
+	}
+
+	/* Convert and save to core_buf.  */
+	/* Elf header */
+	if (elf_class == S2C_ELFCLASS32)
+		elfhdr_32 ();
+	else
+		elfhdr_64 ();
+	/* note0 pstat */
+	switch (elf_arch) {
+		case S2C_EM_386:
+			i386_elf_prstatus ();
+			break;
+		case S2C_EM_X86_64:
+			x86_64_elf_prstatus ();
+			break;
+		case S2C_EM_ARM:
+			arm_elf_prstatus ();
+			break;
+		case S2C_EM_MIPS:
+			mips_elf_prstatus ();
+			break;
+	}
+	/* note1 pinfo */
+	if (elf_class == S2C_ELFCLASS32)
+		save_pinfo_32 ();
+	else
+		save_pinfo_64 ();
+
+	/* stack */
+	if (elf_class == S2C_ELFCLASS32)
+		stack_32 ();
+	else
+		stack_64 ();
+
+	if (write (STDOUT_FILENO, core_buf, core_buf_size) != core_buf_size) {
+		fprintf(stderr, "Output core error.\n");
+		exit (-1);
+	}
+
+	return 0;
+}

^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2010-01-06  7:07 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-01-03 15:05 [PATCH] stack2core: show stack message and convert it to core file when kernel die Hui Zhu
2010-01-03 16:03 ` Russell King - ARM Linux
2010-01-03 16:30   ` Hui Zhu
2010-01-03 16:44     ` Russell King - ARM Linux
2010-01-03 16:55       ` Hui Zhu
2010-01-03 17:10         ` Russell King - ARM Linux
2010-01-03 17:18           ` Hui Zhu
2010-01-03 17:37             ` Hui Zhu
2010-01-03 17:26         ` Arjan van de Ven
2010-01-03 17:39           ` Hui Zhu
2010-01-03 17:47             ` Russell King - ARM Linux
2010-01-03 18:32               ` Marek Vasut
2010-01-03 22:49 ` Tejun Heo
2010-01-03 23:01   ` Arjan van de Ven
2010-01-03 23:07     ` Tejun Heo
2010-01-03 23:14       ` Arjan van de Ven
2010-01-03 23:24         ` Tejun Heo
2010-01-04 16:22         ` Hui Zhu
2010-01-04 23:03           ` Tejun Heo
2010-01-05  9:04             ` Hui Zhu
2010-01-05  9:20               ` Tejun Heo
2010-01-06  7:07                 ` Hui Zhu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox