Scripting infrastructure in crash
by Sachin P. Sant
Dave, i came across one of the Crash TODO list items about having
a scripting infrastructure in crash.
I was trying to evaluate the Alicia utility [mentioned in todo list].
Here are some of my observations about Alicia.
1] It is a wrapper on top of crash.
2] One can write perl based scripts to extract infromation from dumps.
3] It has a nice report generation functionality which presents
the data in text as well as html format.
4] Provides functions which could be used to read data from crash
dumps.
5] It is easy to use and effective too.
Attached here is a sample script which i tried using Alicia to
display block and character devices. [ I know dev command already
does this stuff .. but for the sake of trying out the Alicia i chose
to write such a script ].
Also encountered few problems while trying out Alicia.
1] On PPC64 arch came across data type overflow problem while
executing the attached script.
2] On s390/s390x architecture class function provided by Alicia
seems broken.
3] Alicia is a wrapper on top of crash.
Other dump solutions [ lkcd ] has sial scripting which is c like
and very effective. Not sure how difficult it will be to implement
something like sial in crash.
Do you have any plans of having scripting infrastructure in
crash ? If yes your thoughts on Alicia / sial / < any other stuff >
Regards
-Sachin
sub pdevices {
my ($name, $value, $maxdev, $i);
my (@chrdevlist, @sortedlist);
$maxdev = 255; # same as MAX_CHARDEV
$value = get_addr 'chrdevs';
@chrdevlist = get_mem $value,$maxdev;
@sortedlist = sort @chrdevlist;
print "Character devices:\n";
for ($i=0; $i < $maxdev; $i++) {
if ($sortedlist[$i] ne "0x00000000") {
$val = kernel($sortedlist[$i], 'char_device_struct', 'name', 'char *' );
print "$i\t\t$val\n";
};
};
}
1;
17 years, 6 months
[PATCH] Use registers from LKCD header to get starting ESP register
by Bernhard Walle
On i386/x86_64, crash uses the ESP register to start its backtrace when
analysing LKCD dumps. It does this by guessing in get_lkcd_regs(). This patch
uses another approach vor v8 dumps: It uses the registers saved by LKCD in the
arch-specific dump header.
It fixed a problem here where I head a crash dump from a customer
using LKCD that showed a totally wrong backtrace in crash but lcrash
worked fine.
To implement this, the patch fetches the headers for all architectures and not
only to IA64. We need the arch-specific header, this is done by copying the
declaraction from the kernel patch (2.6.17, the latest) and using a separate
header file for each architecture.
Signed-off-by: Bernhard Walle <bwalle(a)suse.de>
---
Makefile | 31 +++++++++-
defs.h | 2
kernel.c | 63 +++++++++++---------
lkcd_dump_i386.c | 32 ++++++++++
lkcd_dump_i386.h | 71 +++++++++++++++++++++++
lkcd_dump_ia64.c | 35 +++++++++++
lkcd_dump_ia64.h | 81 ++++++++++++++++++++++++++
lkcd_dump_ppc.h | 67 +++++++++++++++++++++
lkcd_dump_v7.h | 163 ++---------------------------------------------------
lkcd_dump_v8.h | 32 ++++++++++
lkcd_dump_x86_64.c | 32 ++++++++++
lkcd_dump_x86_64.h | 71 +++++++++++++++++++++++
lkcd_fix_mem.c | 18 -----
lkcd_v8.c | 140 ++++++++++++++++++++++++++++++++++++++++++++-
14 files changed, 633 insertions(+), 205 deletions(-)
--- a/Makefile
+++ b/Makefile
@@ -97,6 +97,24 @@ OBJECT_FILES=main.o tools.o global_data.
xen_hyper.o xen_hyper_command.o xen_hyper_global_data.o \
xen_hyper_dump_tables.o
+
+# architecture specific LKCD files
+
+ifeq ($(ARCH), x86_64)
+CFILES += lkcd_dump_x86_64.c
+OBJECT_FILES += lkcd_dump_x86_64.o
+endif
+
+ifeq ($(ARCH), i386)
+CFILES += lkcd_dump_i386.c
+OBJECT_FILES += lkcd_dump_i386.o
+endif
+
+ifeq ($(ARCH), ia64)
+CFILES += lkcd_dump_ia64.c
+OBJECT_FILES += lkcd_dump_ia64.o
+endif
+
# These are the current set of crash extensions sources. They are not built
# by default unless the third command line of the "all:" stanza is uncommented.
# Alternatively, they can be built by entering "make extensions" from this
@@ -334,6 +352,15 @@ lkcd_v7.o: ${GENERIC_HFILES} ${LKCD_DUMP
lkcd_v8.o: ${GENERIC_HFILES} ${LKCD_DUMP_HFILES} lkcd_v8.c
cc -c ${CFLAGS} -DMCLX lkcd_v8.c ${WARNING_OPTIONS} ${WARNING_ERROR}
+lkcd_dump_x86_64.o: ${GENERIC_HFILES} ${LKCD_DUMP_HFILES} lkcd_dump_x86_64.c
+ cc -c ${CFLAGS} -DMCLX lkcd_dump_x86_64.c ${WARNING_OPTIONS} ${WARNING_ERROR}
+
+lkcd_dump_i386.o: ${GENERIC_HFILES} ${LKCD_DUMP_HFILES} lkcd_dump_i386.c
+ cc -c ${CFLAGS} -DMCLX lkcd_dump_i386.c ${WARNING_OPTIONS} ${WARNING_ERROR}
+
+lkcd_dump_ia64.o: ${GENERIC_HFILES} ${LKCD_DUMP_HFILES} lkcd_dump_ia64.c
+ cc -c ${CFLAGS} -DMCLX lkcd_dump_ia64.c ${WARNING_OPTIONS} ${WARNING_ERROR}
+
net.o: ${GENERIC_HFILES} net.c
cc -c ${CFLAGS} net.c ${WARNING_OPTIONS} ${WARNING_ERROR}
--- a/defs.h
+++ b/defs.h
@@ -3790,7 +3790,7 @@ void ppc_dump_machdep_table(ulong);
*/
ulong get_lkcd_switch_stack(ulong);
-int fix_addr_v8(int);
+int fix_addr_v8();
int fix_addr_v7(int);
/*
--- a/kernel.c
+++ b/kernel.c
@@ -2089,6 +2089,11 @@ get_lkcd_regs(struct bt_info *bt, ulong
return;
}
+ /* try to get it from the header */
+ if (get_lkcd_regs_for_cpu(bt, eip, esp) == 0)
+ return;
+
+ /* if that fails: do guessing */
sysrq_eip = sysrq_esp = 0;
for (i = 0, up = (ulong *)bt->stackbuf; i < LONGS_PER_STACK; i++, up++){
@@ -2098,48 +2103,48 @@ get_lkcd_regs(struct bt_info *bt, ulong
*esp = *(up-1);
return;
}
- /* Begin 3PAR change -- required for our panic path */
+ /* Begin 3PAR change -- required for our panic path */
if (STREQ(sym, "dump_ipi") && INSTACK(*(up-1), bt)) {
*eip = *up;
*esp = *(up-1);
return;
}
/* End 3PAR change */
- if (STREQ(sym, "panic") && INSTACK(*(up-1), bt)) {
- *eip = *up;
- *esp = *(up-1);
- return;
- }
+ if (STREQ(sym, "panic") && INSTACK(*(up-1), bt)) {
+ *eip = *up;
+ *esp = *(up-1);
+ return;
+ }
/* Egenera */
- if (STREQ(sym, "netdump_ipi")) {
- *eip = *up;
- *esp = bt->task +
+ if (STREQ(sym, "netdump_ipi")) {
+ *eip = *up;
+ *esp = bt->task +
((char *)(up-1) - bt->stackbuf);
- return;
- }
- if (STREQ(sym, "smp_stop_cpu_interrupt")) {
- *eip = *up;
- *esp = bt->task +
+ return;
+ }
+ if (STREQ(sym, "smp_stop_cpu_interrupt")) {
+ *eip = *up;
+ *esp = bt->task +
((char *)(up-1) - bt->stackbuf);
- return;
- }
- if (STREQ(sym, "stop_this_cpu")) {
- *eip = *up;
- *esp = bt->task +
+ return;
+ }
+ if (STREQ(sym, "stop_this_cpu")) {
+ *eip = *up;
+ *esp = bt->task +
((char *)(up-1) - bt->stackbuf);
- return;
- }
- if (SYSRQ_TASK(bt->task) &&
- STREQ(sym, "smp_call_function_interrupt")) {
- sysrq_eip = *up;
- sysrq_esp = bt->task +
- ((char *)(up-1) - bt->stackbuf);
- }
+ return;
+ }
+ if (SYSRQ_TASK(bt->task) &&
+ STREQ(sym, "smp_call_function_interrupt")) {
+ sysrq_eip = *up;
+ sysrq_esp = bt->task +
+ ((char *)(up-1) - bt->stackbuf);
+ }
}
if (sysrq_eip) {
- *eip = sysrq_eip;
- *esp = sysrq_esp;
+ *eip = sysrq_eip;
+ *esp = sysrq_esp;
return;
}
--- /dev/null
+++ b/lkcd_dump_i386.c
@@ -0,0 +1,32 @@
+/* lkcd_dump_i386.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <stdint.h>
+#include <stddef.h>
+#include <stdio.h>
+
+#define LKCD_COMMON
+#include "defs.h"
+#include "lkcd_dump_v8.h"
+
+
+int
+get_lkcd_regs_for_cpu_arch_i386(dump_header_asm_t *dha, int cpu, ulong *eip, ulong *esp)
+{
+ if (eip)
+ *eip = dha->dha_smp_regs[cpu].eip;
+ if (esp)
+ *esp = dha->dha_smp_regs[cpu].esp;
+
+ return 0;
+}
+
--- /dev/null
+++ b/lkcd_dump_i386.h
@@ -0,0 +1,71 @@
+/* lkcd_dump_i386.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef LKCD_DUMP_I386_H
+#define LKCD_DUMP_I386_H
+
+#include <linux/ptrace.h>
+
+/* from kernel include/asm-i386/dump.h */
+#define DUMP_ASM_MAGIC_NUMBER 0xdeaddeadULL /* magic number */
+#define DUMP_ASM_VERSION_NUMBER 0x5 /* version number */
+
+/*
+ * Structure: __dump_header_asm
+ * Function: This is the header for architecture-specific stuff. It
+ * follows right after the dump header.
+ */
+typedef struct __dump_header_asm_i386 {
+ /* the dump magic number -- unique to verify dump is valid */
+ uint64_t dha_magic_number;
+
+ /* the version number of this dump */
+ uint32_t dha_version;
+
+ /* the size of this header (in case we can't read it) */
+ uint32_t dha_header_size;
+
+ /* the esp for i386 systems */
+ uint32_t dha_esp;
+
+ /* the eip for i386 systems */
+ uint32_t dha_eip;
+
+ /* the dump registers */
+ struct pt_regs dha_regs;
+
+ /* smp specific */
+ uint32_t dha_smp_num_cpus;
+ uint32_t dha_dumping_cpu;
+ struct pt_regs dha_smp_regs[NR_CPUS];
+ uint32_t dha_smp_current_task[NR_CPUS];
+ uint32_t dha_stack[NR_CPUS];
+ uint32_t dha_stack_ptr[NR_CPUS];
+} __attribute__((packed)) dump_header_asm_i386_t;
+
+/*
+ * CPU specific part of dump_header_asm_t
+ */
+typedef struct dump_CPU_info_i386 {
+ struct pt_regs dha_smp_regs;
+ uint64_t dha_smp_current_task;
+ uint64_t dha_stack;
+ uint64_t dha_stack_ptr;
+} __attribute__ ((packed)) dump_CPU_info_i386_t;
+
+
+typedef struct __dump_header_asm_i386 dump_header_asm_t;
+typedef struct dump_CPU_info_i386 dump_CPU_info_t;
+
+
+#endif /* LKCD_DUMP_I386_H */
+
--- /dev/null
+++ b/lkcd_dump_ia64.c
@@ -0,0 +1,35 @@
+/* lkcd_dump_x86_64.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <stdint.h>
+#include <stddef.h>
+#include <stdio.h>
+
+#define LKCD_COMMON
+#include "defs.h"
+#include "lkcd_dump_v8.h"
+#include "lkcd_dump_ia64.h"
+
+
+/* reads the load address value for IA64 */
+
+int lkcd_dump_init_v8_ia64(int fd, dump_header_asm_t *dha)
+{
+ int ret;
+
+ ret = read(fd, &dha->dha_kernel_addr, sizeof(dha->dha_kernel_addr));
+ if (ret != sizeof(dha->dha_kernel_addr))
+ return -1;
+ else
+ return 0;
+}
+
--- /dev/null
+++ b/lkcd_dump_ia64.h
@@ -0,0 +1,81 @@
+/* lkcd_dump_ia64.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef LKCD_DUMP_IA64_H
+#define LKCD_DUMP_IA64_H
+
+#define _ASM_IA64_FPU_H
+#include <linux/ptrace.h>
+
+#define DUMP_ASM_MAGIC_NUMBER 0xdeaddeadULL /* magic number */
+#define DUMP_ASM_VERSION_NUMBER 0x5 /* version number */
+
+/*
+ * Structure: dump_header_asm_t
+ * Function: This is the header for architecture-specific stuff. It
+ * follows right after the dump header.
+ */
+/*typedef struct _dump_header_asm {*/
+
+typedef struct __dump_header_asm_ia64 {
+
+ /* the dump magic number -- unique to verify dump is valid */
+ uint64_t dha_magic_number;
+
+ /* the version number of this dump */
+ uint32_t dha_version;
+
+ /* the size of this header (in case we can't read it) */
+ uint32_t dha_header_size;
+
+ /* pointer to pt_regs, (OLD: (struct pt_regs *, NEW: (uint64_t)) */
+ uint64_t dha_pt_regs;
+
+ /* the dump registers */
+ struct pt_regs dha_regs;
+
+ /* the rnat register saved after flushrs */
+ uint64_t dha_rnat;
+
+ /* the pfs register saved after flushrs */
+ uint64_t dha_pfs;
+
+ /* the bspstore register saved after flushrs */
+ uint64_t dha_bspstore;
+
+ /* smp specific */
+ uint32_t dha_smp_num_cpus;
+ uint32_t dha_dumping_cpu;
+ struct pt_regs dha_smp_regs[NR_CPUS];
+ uint64_t dha_smp_current_task[NR_CPUS];
+ uint64_t dha_stack[NR_CPUS];
+ uint64_t dha_stack_ptr[NR_CPUS];
+
+ /* load address of kernel */
+ uint64_t dha_kernel_addr;
+
+} __attribute__((packed)) dump_header_asm_ia64_t;
+
+
+struct dump_CPU_info_ia64 {
+ struct pt_regs dha_smp_regs;
+ uint64_t dha_smp_current_task;
+ uint64_t dha_stack;
+ uint64_t dha_stack_ptr;
+} __attribute__((packed)) dump_CPU_info_ia64_t;
+
+typedef struct dump_CPU_info_ia64 dump_CPU_info_t;
+typedef struct __dump_header_asm_ia64 dump_header_asm_t;
+
+int lkcd_dump_init_v8_ia64(int fd, dump_header_asm_t *dha);
+
+#endif /* LKCD_DUMP_IA64_H */
--- /dev/null
+++ b/lkcd_dump_ppc.h
@@ -0,0 +1,67 @@
+/* lkcd_dump_ppc.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef LKCD_DUMP_PPC_H
+#define LKCD_DUMP_PPC_H
+
+#include <linux/ptrace.h>
+
+/* from kernel include/asm-i386/dump.h */
+#define DUMP_ASM_MAGIC_NUMBER 0xdeaddeadULL /* magic number */
+#define DUMP_ASM_VERSION_NUMBER 0x5 /* version number */
+
+/*
+ * Structure: __dump_header_asm
+ * Function: This is the header for architecture-specific stuff. It
+ * follows right after the dump header.
+ */
+struct __dump_header_asm_ppc {
+
+ /* the dump magic number -- unique to verify dump is valid */
+ uint64_t dha_magic_number;
+
+ /* the version number of this dump */
+ uint32_t dha_version;
+
+ /* the size of this header (in case we can't read it) */
+ uint32_t dha_header_size;
+
+ /* the dump registers */
+ struct pt_regs dha_regs;
+
+ /* smp specific */
+ uint32_t dha_smp_num_cpus;
+ int dha_dumping_cpu;
+ struct pt_regs dha_smp_regs[NR_CPUS];
+ uint64_t dha_smp_current_task[NR_CPUS];
+ uint64_t dha_stack[NR_CPUS];
+ uint64_t dha_stack_ptr[NR_CPUS];
+} __attribute__((packed)) dump_header_asm_ppc_t;
+
+
+/*
+ * CPU specific part of dump_header_asm_t
+ */
+typedef struct dump_CPU_info_ppc {
+ struct pt_regs dha_smp_regs;
+ uint64_t dha_smp_current_task;
+ uint64_t dha_stack;
+ uint64_t dha_stack_ptr;
+} __attribute__ ((packed)) dump_CPU_info_ppc_t;
+
+
+typedef struct __dump_header_asm_ppc dump_header_asm_t;
+typedef struct dump_CPU_info_ppc dump_CPU_info_t;
+
+
+#endif /* LKCD_DUMP_PPC_H */
+
--- a/lkcd_dump_v7.h
+++ b/lkcd_dump_v7.h
@@ -228,165 +228,20 @@ typedef struct lkcdinfo_s {
} lkcdinfo_t;
-#ifdef IA64
-
-#define DUMP_ASM_MAGIC_NUMBER 0xdeaddeadULL /* magic number */
-
-struct pt_regs {
- /* The following registers are saved by SAVE_MIN: */
- unsigned long b6; /* scratch */
- unsigned long b7; /* scratch */
-
- unsigned long ar_csd; /* used by cmp8xchg16 (scratch) */
- unsigned long ar_ssd; /* reserved for future use (scratch) */
-
- unsigned long r8; /* scratch (return value register 0) */
- unsigned long r9; /* scratch (return value register 1) */
- unsigned long r10; /* scratch (return value register 2) */
- unsigned long r11; /* scratch (return value register 3) */
-
- unsigned long cr_ipsr; /* interrupted task's psr */
- unsigned long cr_iip; /* interrupted task's instruction pointer */
- unsigned long cr_ifs; /* interrupted task's function state */
-
- unsigned long ar_unat; /* interrupted task's NaT register (preserved) */
- unsigned long ar_pfs; /* prev function state */
- unsigned long ar_rsc; /* RSE configuration */
- /* The following two are valid only if cr_ipsr.cpl > 0: */
- unsigned long ar_rnat; /* RSE NaT */
- unsigned long ar_bspstore; /* RSE bspstore */
-
- unsigned long pr; /* 64 predicate registers (1 bit each) */
- unsigned long b0; /* return pointer (bp) */
- unsigned long loadrs; /* size of dirty partition << 16 */
-
- unsigned long r1; /* the gp pointer */
- unsigned long r12; /* interrupted task's memory stack pointer */
- unsigned long r13; /* thread pointer */
-
- unsigned long ar_fpsr; /* floating point status (preserved) */
- unsigned long r15; /* scratch */
-
- /* The remaining registers are NOT saved for system calls. */
-
- unsigned long r14; /* scratch */
- unsigned long r2; /* scratch */
- unsigned long r3; /* scratch */
-
- /* The following registers are saved by SAVE_REST: */
- unsigned long r16; /* scratch */
- unsigned long r17; /* scratch */
- unsigned long r18; /* scratch */
- unsigned long r19; /* scratch */
- unsigned long r20; /* scratch */
- unsigned long r21; /* scratch */
- unsigned long r22; /* scratch */
- unsigned long r23; /* scratch */
- unsigned long r24; /* scratch */
- unsigned long r25; /* scratch */
- unsigned long r26; /* scratch */
- unsigned long r27; /* scratch */
- unsigned long r28; /* scratch */
- unsigned long r29; /* scratch */
- unsigned long r30; /* scratch */
- unsigned long r31; /* scratch */
-
- unsigned long ar_ccv; /* compare/exchange value (scratch) */
-
- /*
- * Floating point registers that the kernel considers scratch:
- */
- struct ia64_fpreg f6; /* scratch */
- struct ia64_fpreg f7; /* scratch */
- struct ia64_fpreg f8; /* scratch */
- struct ia64_fpreg f9; /* scratch */
- struct ia64_fpreg f10; /* scratch */
- struct ia64_fpreg f11; /* scratch */
-};
-
/*
- * Structure: dump_header_asm_t
- * Function: This is the header for architecture-specific stuff. It
- * follows right after the dump header.
+ * architecture specific data structures
*/
-typedef struct _dump_header_asm_s {
-
- /* the dump magic number -- unique to verify dump is valid */
- uint64_t dha_magic_number;
-
- /* the version number of this dump */
- uint32_t dha_version;
-
- /* the size of this header (in case we can't read it) */
- uint32_t dha_header_size;
-
- /* pointer to pt_regs */
- struct pt_regs *dha_pt_regs;
-
- /* the dump registers */
- struct pt_regs dha_regs;
-
- /* the rnat register saved after flushrs */
- uint64_t dha_rnat;
-
- /* the pfs register saved after flushrs */
- uint64_t dha_pfs;
-
- /* the bspstore register saved after flushrs */
- uint64_t dha_bspstore;
-
- /* smp specific */
- uint32_t dha_smp_num_cpus;
- int dha_dumping_cpu;
- struct pt_regs dha_smp_regs[NR_CPUS];
- void * dha_smp_current_task[NR_CPUS];
- void * dha_stack[NR_CPUS];
- void * dha_switch_stack[NR_CPUS];
-
-} dump_header_asm_t;
-
-#define NR_CPUS 32
-
-typedef struct _dump_header_asm_smp_s {
-
- /* the dump magic number -- unique to verify dump is valid */
- uint64_t dha_magic_number;
-
- /* the version number of this dump */
- uint32_t dha_version;
-
- /* the size of this header (in case we can't read it) */
- uint32_t dha_header_size;
-
- /* pointer to pt_regs */
- struct pt_regs *dha_pt_regs;
-
- /* the dump registers */
- struct pt_regs dha_regs;
-
- /* the rnat register saved after flushrs */
- uint64_t dha_rnat;
-
- /* the pfs register saved after flushrs */
- uint64_t dha_pfs;
-
- /* the bspstore register saved after flushrs */
- uint64_t dha_bspstore;
-
- /* smp specific */
- uint32_t dha_smp_num_cpus;
- int dha_dumping_cpu;
- struct pt_regs dha_smp_regs[NR_CPUS];
- void * dha_smp_current_task[NR_CPUS];
- void * dha_stack[NR_CPUS];
- void * dha_switch_stack[NR_CPUS];
-
-} dump_header_asm_smp_t;
-
+#if defined(IA64)
+# include "lkcd_dump_ia64.h"
+#elif defined(X86_64)
+# include "lkcd_dump_x86_64.h"
+#elif defined(X86)
+# include "lkcd_dump_i386.h"
+#else
+# error "Add support for your architecture here"
#endif
-
#ifdef __KERNEL__
/*
--- a/lkcd_dump_v8.h
+++ b/lkcd_dump_v8.h
@@ -235,4 +235,36 @@ typedef struct lkcdinfo_s {
int stack_offset;
} lkcdinfo_t;
+
+#if defined(IA64)
+
+# include "lkcd_dump_ia64.h"
+# define get_lkcd_regs_for_cpu_arch(dha, cpu, eip, esp) \
+ -1
+
+#elif defined(X86_64)
+
+# include "lkcd_dump_x86_64.h"
+# define get_lkcd_regs_for_cpu_arch(dha, cpu, eip, esp) \
+ get_lkcd_regs_for_cpu_arch_x86_64(dha, cpu, eip, esp)
+
+#elif defined(X86)
+
+# include "lkcd_dump_i386.h"
+# define get_lkcd_regs_for_cpu_arch(dha, cpu, eip, esp) \
+ get_lkcd_regs_for_cpu_arch_i386(dha, cpu, eip, esp)
+
+#elif defined(PPC) || defined(PPC64)
+
+# include "lkcd_dump_ppc.h"
+# define get_lkcd_regs_for_cpu_arch(dha, cpu, eip, esp) \
+ -1
+
+#else
+
+# define NO_LKCD_DUMP_ARCH 1
+
+#endif
+
+
#endif /* _DUMP_H */
--- /dev/null
+++ b/lkcd_dump_x86_64.c
@@ -0,0 +1,32 @@
+/* lkcd_dump_x86_64.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <stdint.h>
+#include <stddef.h>
+#include <stdio.h>
+
+#define LKCD_COMMON
+#include "defs.h"
+#include "lkcd_dump_v8.h"
+
+
+int
+get_lkcd_regs_for_cpu_arch_x86_64(dump_header_asm_t *dha, int cpu, ulong *eip, ulong *esp)
+{
+ if (eip)
+ *eip = dha->dha_smp_regs[cpu].rip;
+ if (esp)
+ *esp = dha->dha_smp_regs[cpu].rsp;
+
+ return 0;
+}
+
--- /dev/null
+++ b/lkcd_dump_x86_64.h
@@ -0,0 +1,71 @@
+/* lkcd_dump_x86_64.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef LKCD_DUMP_X86_64_H
+#define LKCD_DUMP_X86_64_H
+
+#include <linux/ptrace.h>
+
+#define DUMP_HEADER_SIZE 0x100000
+
+
+/* from kernel include/asm-x86_64/dump.h */
+
+/* definitions */
+#define DUMP_ASM_MAGIC_NUMBER 0xdeaddeadULL /* magic number */
+#define DUMP_ASM_VERSION_NUMBER 0x2 /* version number */
+
+
+/*
+ * Structure: dump_header_asm_t
+ * Function: This is the header for architecture-specific stuff. It
+ * follows right after the dump header.
+ */
+typedef struct __dump_header_asm_x86_64 {
+
+ /* the dump magic number -- unique to verify dump is valid */
+ uint64_t dha_magic_number;
+
+ /* the version number of this dump */
+ uint32_t dha_version;
+
+ /* the size of this header (in case we can't read it) */
+ uint32_t dha_header_size;
+
+ /* the dump registers */
+ struct pt_regs dha_regs;
+
+ /* smp specific */
+ uint32_t dha_smp_num_cpus;
+ int dha_dumping_cpu;
+ struct pt_regs dha_smp_regs[NR_CPUS];
+ uint64_t dha_smp_current_task[NR_CPUS];
+ uint64_t dha_stack[NR_CPUS];
+ uint64_t dha_stack_ptr[NR_CPUS];
+} __attribute__((packed)) dump_header_asm_t_x86_64;
+
+
+/*
+ * CPU specific part of dump_header_asm_t
+ */
+typedef struct dump_CPU_info_x86_64 {
+ struct pt_regs dha_smp_regs;
+ uint64_t dha_smp_current_task;
+ uint64_t dha_stack;
+ uint64_t dha_stack_ptr;
+} __attribute__ ((packed)) dump_CPU_info_x86_64_t;
+
+typedef struct dump_CPU_info_x86_64 dump_CPU_info_t;
+typedef struct __dump_header_asm_x86_64 dump_header_asm_t;
+
+#endif /* LKCD_DUMP_X86_64_H */
+
--- a/lkcd_fix_mem.c
+++ b/lkcd_fix_mem.c
@@ -25,16 +25,8 @@
static int fix_addr(dump_header_asm_t *);
int
-fix_addr_v8(int fd)
+fix_addr_v8(dump_header_asm_t *dha)
{
- static dump_header_asm_t dump_header_asm_v8 = { 0 };
- dump_header_asm_t *dha;
- dha = &dump_header_asm_v8;
-
- if (read(lkcd->fd, dha, sizeof(dump_header_asm_t)) !=
- sizeof(dump_header_asm_t))
- return -1;
-
fix_addr(dha);
return 0;
@@ -59,14 +51,6 @@ fix_addr_v7(int fd)
static int
fix_addr(dump_header_asm_t *dha)
{
-
-
- if (dha->dha_header_size != sizeof(dump_header_asm_t)) {
- error(INFO, "LKCD machine specific dump header doesn't match crash version\n");
- error(INFO, "traceback of currently executing threads may not work\n\n");
- }
-
-
lkcd->dump_header_asm = dha;
--- a/lkcd_v8.c
+++ b/lkcd_v8.c
@@ -19,15 +19,120 @@
*/
#define LKCD_COMMON
+#include <stddef.h>
#include "defs.h"
#include "lkcd_dump_v8.h" /* REMIND */
static dump_header_t dump_header_v8 = { 0 };
-// static dump_header_asm_t dump_header_asm_v8 = { 0 };
+#ifndef NO_LKCD_DUMP_ARCH
+static dump_header_asm_t dump_header_asm_v8 = { 0 };
+#endif
static dump_page_t dump_page = { 0 };
static void mclx_cache_page_headers_v8(void);
static off_t lkcd_offset_to_first_page = LKCD_OFFSET_TO_FIRST_PAGE;
+#define STR(x) #x
+
+#ifndef NO_LKCD_DUMP_ARCH
+int
+lkcd_dump_init_v8_arch(dump_header_t *dh, dump_header_asm_t *dha)
+{
+ off_t ret_of;
+ ssize_t ret_sz;
+ uint32_t hdr_size, offset, nr_cpus;
+ dump_header_asm_t arch_hdr;
+ char *hdr_buf = NULL;
+
+ ret_of = lseek(lkcd->fd, dh->dh_header_size +
+ offsetof(dump_header_asm_t, dha_header_size),
+ SEEK_SET);
+ if (ret_of < 0) {
+ perror("lseek failed in " __FILE__ ":" STR(__LINE__));
+ goto err;
+ }
+
+ ret_sz = read(lkcd->fd, (char *)&hdr_size, sizeof(hdr_size));
+ if (ret_sz != sizeof(hdr_size)) {
+ perror("Reading hdr_size failed in " __FILE__ ":" STR(__LINE__));
+ goto err;
+ }
+
+ ret_of = lseek(lkcd->fd, dh->dh_header_size, SEEK_SET);
+ if (ret_of < 0) {
+ perror("lseek failed in " __FILE__ ":" STR(__LINE__));
+ goto err;
+ }
+
+ hdr_buf = (char *)malloc(hdr_size);
+ if (!hdr_buf) {
+ perror("Could not allocate memory for dump header\n");
+ goto err;
+ }
+
+ ret_sz = read(lkcd->fd, (char *)hdr_buf, hdr_size);
+ if (ret_sz != hdr_size) {
+ perror("Could not read header " __FILE__ ":" STR(__LINE__));
+ goto err;
+ }
+
+
+ /*
+ * Though we have KL_NR_CPUS is 128, the header size is different
+ * CONFIG_NR_CPUS might be different in the kernel. Hence, need
+ * to find out how many CPUs are configured.
+ */
+ offset = offsetof(dump_header_asm_t, dha_smp_regs[0]);
+ nr_cpus = (hdr_size - offset) / sizeof(dump_CPU_info_t);
+
+ /* check for CPU overflow */
+ if (nr_cpus > NR_CPUS) {
+ fprintf(stderr, "CPU number too high %d (%s:%s)\n",
+ nr_cpus, __FILE__, __LINE__);
+ goto err;
+ }
+
+ /* parts that don't depend on the number of CPUs */
+ memcpy(&arch_hdr, (void *)hdr_buf, offset);
+
+ /* registers */
+ memcpy(&arch_hdr.dha_smp_regs, (void *)&hdr_buf[offset],
+ nr_cpus * sizeof(struct pt_regs));
+ offset += nr_cpus * sizeof(struct pt_regs);
+
+ /* current task */
+ memcpy(&arch_hdr.dha_smp_current_task, (void *)&hdr_buf[offset],
+ nr_cpus * sizeof(&arch_hdr.dha_smp_current_task[0]));
+ offset += nr_cpus * sizeof(&arch_hdr.dha_smp_current_task[0]);
+
+ /* stack */
+ memcpy(&arch_hdr.dha_stack, (void *)&hdr_buf[offset],
+ nr_cpus * sizeof(&arch_hdr.dha_stack[0]));
+ offset += nr_cpus * sizeof(&arch_hdr.dha_stack[0]);
+
+ /* stack_ptr */
+ memcpy(&arch_hdr.dha_stack_ptr, (void *)&hdr_buf[offset],
+ nr_cpus * sizeof(&arch_hdr.dha_stack_ptr[0]));
+ offset += nr_cpus * sizeof(&arch_hdr.dha_stack_ptr[0]);
+
+ if (arch_hdr.dha_magic_number != DUMP_ASM_MAGIC_NUMBER) {
+ fprintf(stderr, "Invalid magic number for x86_64\n");
+ goto err;
+ }
+
+#ifdef IA64
+ lkcd_dump_init_v8_ia64(lkcd->fd, &arch_hdr);
+#endif
+
+ memcpy(dha, &arch_hdr, sizeof(dump_header_asm_t));
+
+ return 0;
+
+err:
+ free(hdr_buf);
+ return -1;
+}
+#endif
+
/*
* Verify and initialize the LKCD environment, storing the common data
* in the global lkcd_environment structure.
@@ -69,8 +174,16 @@ lkcd_dump_init_v8(FILE *fp, int fd, char
lkcd->dump_header = dh;
if (lkcd->debug)
dump_lkcd_environment(LKCD_DUMP_HEADER_ONLY);
+
+#ifndef NO_LKCD_DUMP_ARCH
+ if (lkcd_dump_init_v8_arch(dh, &dump_header_asm_v8) != 0) {
+ fprintf(stderr, "Warning: Failed to initialise "
+ "arch specific dump code\n");
+ }
+#endif
+
#ifdef IA64
- if ( (fix_addr_v8(fd) == -1) )
+ if ( (fix_addr_v8(&dump_header_asm_v8) == -1) )
return FALSE;
#endif
@@ -233,6 +346,29 @@ lkcd_dump_init_v8(FILE *fp, int fd, char
return TRUE;
}
+int
+get_lkcd_regs_for_cpu(struct bt_info *bt, ulong *eip, ulong *esp)
+{
+ int cpu;
+
+ if (!bt || !bt->tc) {
+ fprintf(stderr, "get_lkcd_regs_for_cpu: invalid tc\n", cpu);
+ return -EINVAL;
+ }
+
+ cpu = bt->tc->processor;
+
+ if (cpu >= NR_CPUS) {
+ fprintf(stderr, "get_lkcd_regs_for_cpu, cpu (%d) too high\n", cpu);
+ return -EINVAL;
+ }
+
+#ifndef NO_LKCD_DUMP_ARCH
+ return get_lkcd_regs_for_cpu_arch(&dump_header_asm_v8, cpu, eip, esp);
+#else
+ return -ENOSYS;
+#endif
+}
/*
* Return the current page's dp_size.
17 years, 7 months
4.0-3.21 cross crash support.
by Maxim Syrchin
Good news everyone,
cross-crash patch for crash-4.0.3.21 is available now on
http://sourceforge.net/projects/crosscrash/.
Current version allows the analysis of linux kernel core dumps by Linux
Kernel Crash Dump (LKCD) up to version 9 LKCD format.
The arch support matrix is below:
host arch | dump arch | test results
i386 | i386 | OK
i386 | x86_64 | OK
i386 | PPC32 | OK
i386 | PPC64 | not tested
x86_64 | all | not tested*
PPC32 | all | not tested*
PPC64 | all | not tested
* - non-cross usage is available and works
IA64, alpha, s390(x) architectures are not fixed for cross analyse
Any comments are welcome.
Thanks,
Maxim Syrchin,
17 years, 7 months
crash version 4.0-4.1 is available
by Dave Anderson
- Implemented dependable backtraces for the x86_64 architecture. (!!!)
This feature builds upon the current "low_budget" backtrace function,
and also required the fix for the BUG()/ud2a disassembly problem
addressed in 4.0-3.22. It does not require kernel unwind support,
but rather it calculates function framesizes by disassembling the
code from the beginning of the function to the point where it calls
the next function, parsing for add or sub instructions on the rsp,
and for push and pop instructions, thereby determining the framesize
of the function at the point of the call. This is similar to what is
done for x86, but requires far less hackery. You will notice a slight
hitch the first time a "bt" is done on a task, but for each text
return address in any backtrace, its framesize is cached for all
subsequent instances. It also accounts for backtrace text return
addresses from the .text.lock section, by appending "(via function)"
to the end of the frame line. Also, because it layers on top of the
current backtrace code, it does not compromise the capability of
switching between the process, IRQ, and exception stacks. That all
being said, 100% accuracy cannot be guaranteed. But for the ~30
sample dumpfiles I keep around for x86_64 testing, I cannot find any
obviously invalid backtraces. However, if there is any doubt, the
"bt -o" option will perform backtraces using the "old" manner; and
"bt -O" will force the old manner to always be used. Of course the
"bt -t" and "bt -T" options are still available. It's interesting to
redirect the output of "foreach bt" to a file using this version, and
then compare it with the output from an older version.
(anderson(a)redhat.com)
- Fix for s390 and s390x backtrace commands to recognize the kernel
structure name change from "runqueue" to "rq".
(holzheu(a)linux.vnet.ibm.com)
- Merged fourth round of "xencrash" patches, which allows a crash
session to alternatively be brought up against the xen-syms
binary instead of a vmlinux kernel. This patch enhances the
"doms" command display contents, and adds support to access the
ia64 frame table virtual address space so that the page_info table
can be accessed. (oda(a)valinux.co.jp)
Download from: http://people.redhat.com/anderson
17 years, 7 months