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_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;
+}
Russell King - ARM Linux
2010-01-03 16:03:13 UTC
Permalink
Post by Hui Zhu
Hello,
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
[<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.
If you have frame pointers enabled, the backtrace is _never_ wrong.
It only goes wrong if you disable frame pointers, at which point the
unwind tables have to be used.
Post by Hui Zhu
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,
Please don't invent yet another way of dumping stuff out of the kernel.
What we already have is sufficient for your needs - there's no reason
what so ever to change it to achieve your goals. We already dump the
registers and the stack, which seems to be all that you require.
Hui Zhu
2010-01-03 16:30:20 UTC
Permalink
Thanks Russell,

This S2C: message just for program s2c.
s2c can convert it to a core file. Then gdb can do a clear analyse
with this file.
Then you can get more message than current we can get.

=46or example:
(gdb) bt
#0 0xc0008470 in kernel_init (unused=3D<value optimized out>)
at /home/teawater/kernel/arm_versatile_926ejs.glibc_std.standard/bui=
ld/linux/init/main.c:916
#1 0xc0042660 in sys_waitid (which=3D<value optimized out>, upid=3D<va=
lue
optimized out>, infop=3D0x0, options=3D0, ru=3D0x14)
at /home/teawater/kernel/arm_versatile_926ejs.glibc_std.standard/bui=
ld/linux/kernel/exit.c:1798
Backtrace stopped: previous frame inner to this frame (corrupt stack?)

a more clear backtrace.

(gdb) frame 1
#1 0xc0042660 in sys_waitid (which=3D<value optimized out>, upid=3D<va=
lue
optimized out>, infop=3D0x0, options=3D0, ru=3D0x14)
at /home/teawater/kernel/arm_versatile_926ejs.glibc_std.standard/bui=
ld/linux/kernel/exit.c:1798
1798 pid =3D find_get_pid(upid);
(gdb) p pid
$1 =3D (struct pid *) 0x0

A value of a val in stack in the frame.


I think it will more helpful for user to deal with the kernel die.

Best regards,
Hui

On Mon, Jan 4, 2010 at 00:03, Russell King - ARM Linux
Post by Russell King - ARM Linux
Post by Hui Zhu
Hello,
PC is at kernel_init+0xd4/0x104
LR is at _atomic_dec_and_lock+0x48/0x6c
pc : [<c0008470>] =A0 =A0lr : [<c01911f8>] =A0 =A0psr: 60000013
sp : c7823fd8 =A0ip : c7823f48 =A0fp : c7823ff4
Stack: (0xc7823fd8 to 0xc7824000)
3fc0: =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 00000000 00000001
Post by Russell King - ARM Linux
Post by Hui Zhu
[<c000839c>] (kernel_init+0x0/0x104) from [<c0042660>] (do_exit+0x0/=
0x880)
Post by Russell King - ARM Linux
Post by Hui Zhu
This backtrace have some wrong message sometime and cannot get any
val. Of course, kdump can get more message. =A0But it need do some a=
lot
Post by Russell King - ARM Linux
Post by Hui Zhu
of other config.
If you have frame pointers enabled, the backtrace is _never_ wrong.
It only goes wrong if you disable frame pointers, at which point the
unwind tables have to be used.
Post by Hui Zhu
S2C:elf_class=3D1
S2C:elf_data=3D1
S2C:elf_arch=3D40
S2C:elf_osabi=3D0
S2C:r0=3D0x00000000;
S2C:r1=3D0xc7822000;
S2C:r2=3D0xc7823f48;
S2C:r3=3D0x00000003;
S2C:r4=3D0x00000000;
S2C:r5=3D0x00000000;
S2C:r6=3D0x00000000;
S2C:r7=3D0x00000000;
S2C:r8=3D0x00000000;
S2C:r9=3D0x00000000;
S2C:r10=3D0x00000000;
S2C:fp=3D0xc7823ff4;
S2C:ip=3D0xc7823f48;
S2C:sp=3D0xc7823fd8;
S2C:lr=3D0xc01911f8;
S2C:pc=3D0xc0008470;
S2C:cpsr=3D0x60000013;
S2C:ORIG_r0=3D0xffffffff;
S2C:stack=3D0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
S2C:stack=3D0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
S2C:stack=3D0x00, 0x00, 0x00, 0x00, 0xf8, 0x3f, 0x82, 0xc7,
S2C:stack=3D0x60, 0x26, 0x04, 0xc0, 0xa8, 0x83, 0x00, 0xc0,
S2C:stack=3D0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Please don't invent yet another way of dumping stuff out of the kerne=
l.
Post by Russell King - ARM Linux
What we already have is sufficient for your needs - there's no reason
what so ever to change it to achieve your goals. =A0We already dump t=
he
Post by Russell King - ARM Linux
registers and the stack, which seems to be all that you require.
Russell King - ARM Linux
2010-01-03 16:44:14 UTC
Permalink
Post by Hui Zhu
This S2C: message just for program s2c.
s2c can convert it to a core file. Then gdb can do a clear analyse
with this file.
Then you can get more message than current we can get.
I understand that. What I'm saying is that all the additional noise
you're causing the kernel to create is just a pure duplication of
what we already dump.

Oops dumps are already noisy enough - especially if they cause a panic
at the end (where you end up with two backtraces.) We do not need even
more noise caused by needless duplication.

You can get everything you need already from the kernel. On ARM, we
already dump out all the registers and the _full_ stack. There is no
need for you to implement your own register dumping code and full stack
dump on top of that again.

So, I'm not going to accept your patch for the ARM kernel. Please use
what's already provided - it's more than adequate. By doing so, you
don't penalise those of us who want to read the raw oopses.

Talking about noisy oopses, I'm getting one with 2.6.33-rc2 on 'poweroff'
shutdown. No idea what it is because most of it's scrolled off the top of
the screen and I can't scroll back. Not bothered about it at the moment.
What it does illustrate though is why making things too noisy when problems
occur makes it _more_ difficult to find out what went wrong.
Hui Zhu
2010-01-03 16:55:04 UTC
Permalink
I didn't give the user raw oopses.
I give him core file. When the kernel die, do we can get a core file no=
w?


(gdb) bt
#0 0xc0008470 in kernel_init (unused=3D<value optimized out>)
at /home/teawater/kernel/arm_versatile_926ejs.glibc_std.standard/buil=
d/linux/init/main.c:916
#1 0xc0042660 in sys_waitid (which=3D<value optimized out>, upid=3D<va=
lue
optimized out>, infop=3D0x0, options=3D0, ru=3D0x14)
at /home/teawater/kernel/arm_versatile_926ejs.glibc_std.standard/buil=
d/linux/kernel/exit.c:1798
Backtrace stopped: previous frame inner to this frame (corrupt stack?)

It show which line make kernel die.

Hui




On Mon, Jan 4, 2010 at 00:44, Russell King - ARM Linux
Post by Hui Zhu
This S2C: message just for program s2c.
s2c can convert it to a core file. =A0Then gdb can do a clear analys=
e
Post by Hui Zhu
with this file.
Then you can get more message than current we can get.
I understand that. =A0What I'm saying is that all the additional nois=
e
you're causing the kernel to create is just a pure duplication of
what we already dump.
Oops dumps are already noisy enough - especially if they cause a pani=
c
at the end (where you end up with two backtraces.) =A0We do not need =
even
more noise caused by needless duplication.
You can get everything you need already from the kernel. =A0On ARM, w=
e
already dump out all the registers and the _full_ stack. =A0There is =
no
need for you to implement your own register dumping code and full sta=
ck
dump on top of that again.
So, I'm not going to accept your patch for the ARM kernel. =A0Please =
use
what's already provided - it's more than adequate. =A0By doing so, yo=
u
don't penalise those of us who want to read the raw oopses.
Talking about noisy oopses, I'm getting one with 2.6.33-rc2 on 'power=
off'
shutdown. =A0No idea what it is because most of it's scrolled off the=
top of
the screen and I can't scroll back. =A0Not bothered about it at the m=
oment.
What it does illustrate though is why making things too noisy when pr=
oblems
occur makes it _more_ difficult to find out what went wrong.
Russell King - ARM Linux
2010-01-03 17:10:13 UTC
Permalink
Post by Hui Zhu
I didn't give the user raw oopses.
I give him core file. When the kernel die, do we can get a core file now?
I think there's a communication issue here... clearly you're not
understanding what I've been trying to tell you.

I don't think I can help you any further.
Hui Zhu
2010-01-03 17:18:25 UTC
Permalink
Sorry I make a mistake, I sent the mail before I complete it. Maybe
some hotkey or something.

The s2c can get the message from the current panic message is better.
I am not get them for now, maybe it need open some options or
something.

Thanks,
Hui

On Mon, Jan 4, 2010 at 01:10, Russell King - ARM Linux
Post by Russell King - ARM Linux
Post by Hui Zhu
I didn't give the user raw oopses.
I give him core file. When the kernel die, do we can get a core file now?
I think there's a communication issue here... clearly you're not
understanding what I've been trying to tell you.
I don't think I can help you any further.
Hui Zhu
2010-01-03 17:37:40 UTC
Permalink
And gdb need a message that seems panic doesn't show:
LKM address message. like:
S2C:add-symbol-file e.ko 0xffffffffa0000000

Thanks,
Hui
Sorry I make a mistake, I sent the mail before I complete it. =A0Mayb=
e
some hotkey or something.
The s2c can get the message from the current panic message is better.
I am not get them for now, maybe it need open some options or
something.
Thanks,
Hui
On Mon, Jan 4, 2010 at 01:10, Russell King - ARM Linux
Post by Russell King - ARM Linux
Post by Hui Zhu
I didn't give the user raw oopses.
I give him core file. When the kernel die, do we can get a core fil=
e now?
Post by Russell King - ARM Linux
I think there's a communication issue here... clearly you're not
understanding what I've been trying to tell you.
I don't think I can help you any further.
Arjan van de Ven
2010-01-03 17:26:08 UTC
Permalink
On Mon, 4 Jan 2010 00:55:04 +0800
Post by Hui Zhu
It show which line make kernel die.
similar to scripts/markup_oops.pl already does ?
--
Arjan van de Ven Intel Open Source Technology Centre
For development, discussion and tips for power savings,
visit http://www.lesswatts.org
Hui Zhu
2010-01-03 17:39:44 UTC
Permalink
scripts/markup_oops.pl just support x86?
s2c support x86, x8664, arm, mips, mips64.

Thanks,
Hui
Post by Arjan van de Ven
On Mon, 4 Jan 2010 00:55:04 +0800
Post by Hui Zhu
It show which line make kernel die.
similar to scripts/markup_oops.pl already does ?
--
Arjan van de Ven =A0 =A0 =A0 =A0Intel Open Source Technology Centre
For development, discussion and tips for power savings,
visit http://www.lesswatts.org
Russell King - ARM Linux
2010-01-03 17:47:37 UTC
Permalink
Post by Hui Zhu
scripts/markup_oops.pl just support x86?
s2c support x86, x8664, arm, mips, mips64.
I'm sure there's patches around to make it work on ARM, or if not,
there soon will be. There's certainly patches around at the moment
to make scripts/decodecode work on ARM.
Marek Vasut
2010-01-03 18:32:11 UTC
Permalink
Post by Russell King - ARM Linux
Post by Hui Zhu
scripts/markup_oops.pl just support x86?
s2c support x86, x8664, arm, mips, mips64.
I'm sure there's patches around to make it work on ARM, or if not,
there soon will be.
And if there are not, that's the place you should focus yourself on rather than
duplicating work ...
Post by Russell King - ARM Linux
There's certainly patches around at the moment
to make scripts/decodecode work on ARM.
_______________________________________________
linux-arm-kernel mailing list
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Tejun Heo
2010-01-03 22:49:56 UTC
Permalink
Post by Hui Zhu
Hello,
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
[<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.
FWIW, I love it. I used to have to match the assembly to the source
code manually to find out which register and stack space meant what.
This will be very helpful in decoding oops message, but I think that
it would be far more useful if it uses the existing oops messages
instead of adding extra messages. The new messages don't add any new
information and the oops message is already quite long and scrolls off
the screen on certain configurations. Adding new configuration option
and making oops message longer will make acquiring the information
quite more difficult.

If implementing parsing of oops message in C is too awkward
(unsurprising at all), maybe implementing a converter in perl or
python is the easiest way so that it takes the oops message and puts
out well formatted input for the s2c program?

thanks.
--
tejun
Arjan van de Ven
2010-01-03 23:01:34 UTC
Permalink
On Mon, 04 Jan 2010 07:49:56 +0900
Post by Tejun Heo
If implementing parsing of oops message in C is too awkward
(unsurprising at all), maybe implementing a converter in perl or
python is the easiest way so that it takes the oops message and puts
out well formatted input for the s2c program?
you mean like scripts/markup_oops.pl ?
--
Arjan van de Ven Intel Open Source Technology Centre
For development, discussion and tips for power savings,
visit http://www.lesswatts.org
Tejun Heo
2010-01-03 23:07:45 UTC
Permalink
Post by Arjan van de Ven
On Mon, 04 Jan 2010 07:49:56 +0900
Post by Tejun Heo
If implementing parsing of oops message in C is too awkward
(unsurprising at all), maybe implementing a converter in perl or
python is the easiest way so that it takes the oops message and puts
out well formatted input for the s2c program?
you mean like scripts/markup_oops.pl ?
Whichever one works but s2c wouldn't require symbol decoding. Maybe
we can simply add an option to tell it to just parse the oops and
output it in machine friendly format. Oh, also, the patch does add
new information the module load addresses. We should be able to add
those to the oops message in a compact form.

Thanks.
--
tejun
Arjan van de Ven
2010-01-03 23:14:06 UTC
Permalink
On Mon, 04 Jan 2010 08:07:45 +0900
Post by Tejun Heo
Post by Arjan van de Ven
On Mon, 04 Jan 2010 07:49:56 +0900
Post by Tejun Heo
If implementing parsing of oops message in C is too awkward
(unsurprising at all), maybe implementing a converter in perl or
python is the easiest way so that it takes the oops message and
puts out well formatted input for the s2c program?
you mean like scripts/markup_oops.pl ?
Whichever one works but s2c wouldn't require symbol decoding. Maybe
we can simply add an option to tell it to just parse the oops and
output it in machine friendly format. Oh, also, the patch does add
new information the module load addresses. We should be able to add
those to the oops message in a compact form.
actually one does not need those; you know the start address of the
function already from the current oops output, and since you know the
address of the function within the module as well, you know the start
address of the module.
--
Arjan van de Ven Intel Open Source Technology Centre
For development, discussion and tips for power savings,
visit http://www.lesswatts.org
Tejun Heo
2010-01-03 23:24:53 UTC
Permalink
Post by Arjan van de Ven
Post by Tejun Heo
Whichever one works but s2c wouldn't require symbol decoding. Maybe
we can simply add an option to tell it to just parse the oops and
output it in machine friendly format. Oh, also, the patch does add
new information the module load addresses. We should be able to add
those to the oops message in a compact form.
actually one does not need those; you know the start address of the
function already from the current oops output, and since you know the
address of the function within the module as well, you know the start
address of the module.
Right. Thanks for the explanation.
--
tejun
Hui Zhu
2010-01-04 16:22:02 UTC
Permalink
Thanks for your mail.

I am not sure s2c is not a duplicating work with with others or not.

The main work of it is give user a coredump when kernel die like a
user level program die.
The user can very easy use it with gdb.
Now, it support x86/x8664/mips/arm. It's very easy to extend. To
support a new arch is not a very hard work. (I use half a day make it
support mips and mips64 include the test work.)

And the s2c convert program can run on every environment. I try it in
x86, x8664, mipsn32 . It didn't depend on any special lib. User can
compile it with "gcc s2c.c" to get it. And run it in a small board
that didn't have some script support.

markup_oops.pl sames still not support cross compile environment. It
get module message with modinfo,right? And use some objdump and so
on.
So even if it support cross compile environment, user use it will need
set which objdump he want use. Which mod dir he want use. Right?

=46or the s2c, user just "s2c < message >core" It did everything with i=
tself.
After that, gdb vmlinux core.

Best regards,
Hui
Post by Arjan van de Ven
On Mon, 04 Jan 2010 08:07:45 +0900
Post by Arjan van de Ven
On Mon, 04 Jan 2010 07:49:56 +0900
Post by Tejun Heo
If implementing parsing of oops message in C is too awkward
(unsurprising at all), maybe implementing a converter in perl or
python is the easiest way so that it takes the oops message and
puts out well formatted input for the s2c program?
you mean like scripts/markup_oops.pl ?
Whichever one works but s2c wouldn't require symbol decoding. =A0May=
be
Post by Arjan van de Ven
we can simply add an option to tell it to just parse the oops and
output it in machine friendly format. =A0Oh, also, the patch does ad=
d
Post by Arjan van de Ven
new information the module load addresses. =A0We should be able to a=
dd
Post by Arjan van de Ven
those to the oops message in a compact form.
actually one does not need those; you know the start address of the
function already from the current oops output, and since you know the
address of the function within the module as well, you know the start
address of the module.
--
Arjan van de Ven =A0 =A0 =A0 =A0Intel Open Source Technology Centre
For development, discussion and tips for power savings,
visit http://www.lesswatts.org
Tejun Heo
2010-01-04 23:03:50 UTC
Permalink
Hello,
For the s2c, user just "s2c < message >core" It did everything with itself.
After that, gdb vmlinux core.
It is true that by making the kernel oops message more verbose, s2c
can be made way simpler. However, dependence on standard object tools
or perl is already assumed and avoiding it doesn't really buy
anything. I really like the idea but unfortunately I'm doubtful that
it will be able to go upstream in the current form. The suggested
solution (extending markup_oops.pl) won't be too much work, most of
functionality will remain the same and will have much higher chance of
getting included.

Thanks.
--
tejun
Hui Zhu
2010-01-05 09:04:07 UTC
Permalink
Hi,

I agree with read the current stack message is better.

About the extending, I have some question with it:
1. markup_oops.pl have itself idea, it try use dmesg| markup_oops.pl
show what happen to usr. This is different with s2c.
I am not sure people like it have other function with it. Too much
part of this file need to be change. It need rewrite, just the oops
message parse part can be keep.

2. I use perl to work in a long time before, I know it good at parse
the text, but I am not sure it good at handle struct like:
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)));
Even if what happen, I will keep a c s2c with myself. :)

Best regards,
Hui
Post by Hui Zhu
Hello,
For the s2c, user just "s2c < message >core" It did everything with =
itself.
Post by Hui Zhu
After that, gdb vmlinux core.
It is true that by making the kernel oops message more verbose, s2c
can be made way simpler. =A0However, dependence on standard object to=
ols
Post by Hui Zhu
or perl is already assumed and avoiding it doesn't really buy
anything. =A0I really like the idea but unfortunately I'm doubtful th=
at
Post by Hui Zhu
it will be able to go upstream in the current form. =A0The suggested
solution (extending markup_oops.pl) won't be too much work, most of
functionality will remain the same and will have much higher chance o=
f
Post by Hui Zhu
getting included.
Thanks.
--
tejun
Tejun Heo
2010-01-05 09:20:23 UTC
Permalink
Hello,
Post by Hui Zhu
I agree with read the current stack message is better.
1. markup_oops.pl have itself idea, it try use dmesg| markup_oops.pl
show what happen to usr. This is different with s2c.
I am not sure people like it have other function with it. Too much
part of this file need to be change. It need rewrite, just the oops
message parse part can be keep.
Yeah, I think you'll need to refactor it and share only the parsing
frontend. Just adding a switch (-m or whatever) which puts it into
machine-friendly translator mode should do the trick.
Post by Hui Zhu
2. I use perl to work in a long time before, I know it good at parse
You don't need to handle the data structure at all. Just make it
parse the dmesg and output machine-friendly formatted output which can
be processed by s2c. ie. just make it do the reformatting.
Post by Hui Zhu
Even if what happen, I will keep a c s2c with myself. :)
That will be sad. I really want it too. :-)

Thanks.
--
tejun
Loading...