Discussion:
[PATCH] stack2core: show stack message and convert it to core file when kernel die
Hui Zhu
2010-01-03 15:05:05 UTC
Permalink
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