[PATCH] stack2core: show stack message and convert it to core file when kernel die

Hui Zhu teawater at gmail.com
Sun Jan 3 10:05:05 EST 2010


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;
+}



More information about the linux-arm-kernel mailing list