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)®s->sp); + printk(S2CMARK"ss=0x%08x;\n", (unsigned int)regs->ss); + + stack2core_tail((uint8_t *)(®s->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; +}