Bernhard Walle wrote:
* Bernhard Walle <bwalle(a)suse.de> [2007-10-19 17:24]:
>The solution for that problem is to calculate the number of CPUs for
>IA64 at runtime. The 2nd patch implements this, and also reads the
>registers from the LKCD dump header instead of guessing on the stack.
>This fixes a problem here -- unfortunately, I don't still have that
>dump to provide further details.
I forget to attach the 2nd patch ;)
Thanks,
Bernhard
At this point I've lost most insights into the LKCD code.
The ia64 pt_regs hardwiring bothers me, mainly because there have
been changes to its definition over the years. (There's a couple
different versions hardwired in unwind.h for example).
So my biggest worry would be if this somehow breaks
backwards-compatibility, but I'm presuming that you took
that into account. But anyway, I leave this all up
to Troy.
A couple nits...
Please build with "make warn" before submitting any patch
and clean up the complaints.
Also I'd prefer to not tinker with the netdump.c file.
There is no /usr/include/stddef.h in the RHEL and FC8
environments, and the /usr/include/linux/stddef.h has
removed offsetof() in FC8 for some reason? In any case,
I'd prefer leaving it alone.
Because of the builtin array sizes that I long ago
painted crash into a corner with, I'd also prefer keeping
NR_CPUS to its minimum. I have no problem updating it if
necessary later, so 4096 is preferable to overkilling
it with 16384 at this time. I don't see how that could
be a problem? If it is, you can always release the SUSE
version with the larger value -- I'm sure that you're
almost never in sync with the upstream version anyway,
right? (I can't even do that with RHEL errata...)
Thanks,
Dave
------------------------------------------------------------------------
---
Makefile | 4
defs.h | 9 +
kernel.c | 5
lkcd_dump_v8.h | 300 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lkcd_fix_mem.c | 22 ----
lkcd_fix_mem.h | 295 --------------------------------------------------------
lkcd_v8.c | 186 ++++++++++++++++++++++++++++++++++-
netdump.c | 1
8 files changed, 502 insertions(+), 320 deletions(-)
--- a/Makefile
+++ b/Makefile
@@ -66,7 +66,7 @@ GENERIC_HFILES=defs.h xen_hyper_defs.h
MCORE_HFILES=va_server.h vas_crash.h
REDHAT_HFILES=netdump.h diskdump.h xendump.h
LKCD_DUMP_HFILES=lkcd_vmdump_v1.h lkcd_vmdump_v2_v3.h lkcd_dump_v5.h \
- lkcd_dump_v7.h lkcd_dump_v8.h lkcd_fix_mem.h
+ lkcd_dump_v7.h lkcd_dump_v8.h
LKCD_TRACE_HFILES=lkcd_x86_trace.h
IBM_HFILES=ibm_common.h
UNWIND_HFILES=unwind.h unwind_i.h rse.h unwind_x86.h unwind_x86_64.h
@@ -406,7 +406,7 @@ unwind_v3.o: ${GENERIC_HFILES} ${UNWIND_
cc -c ${CFLAGS} -DREDHAT -DUNWIND_V3 unwind.c -o unwind_v3.o ${WARNING_OPTIONS}
${WARNING_ERROR}
lkcd_fix_mem.o: ${GENERIC_HFILES} ${LKCD_HFILES} lkcd_fix_mem.c
- cc -c ${CFLAGS} lkcd_fix_mem.c ${WARNING_OPTIONS} ${WARNING_ERROR}
+ cc -c ${CFLAGS} -DMCLX lkcd_fix_mem.c ${WARNING_OPTIONS} ${WARNING_ERROR}
xen_hyper.o: ${GENERIC_HFILES} xen_hyper.c
cc -c ${CFLAGS} xen_hyper.c ${WARNING_OPTIONS} ${WARNING_ERROR}
--- a/defs.h
+++ b/defs.h
@@ -19,6 +19,7 @@
#ifndef GDB_COMMON
#include <stdio.h>
+#include <stddef.h>
#include <stdarg.h>
#include <stdint.h>
#include <termios.h>
@@ -54,6 +55,7 @@
#define TRUE (1)
#define FALSE (0)
+#define STR(x) #x
#ifdef X86
#define NR_CPUS (256)
@@ -3826,10 +3828,15 @@ 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);
/*
+ * lkcd_v8.c
+ */
+int get_lkcd_regs_for_cpu(struct bt_info *bt, ulong *eip, ulong *esp);
+
+/*
* ia64.c
*/
#ifdef IA64
--- a/kernel.c
+++ b/kernel.c
@@ -2102,6 +2102,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++){
--- a/lkcd_dump_v8.h
+++ b/lkcd_dump_v8.h
@@ -235,4 +235,304 @@ typedef struct lkcdinfo_s {
int stack_offset;
} lkcdinfo_t;
+/*
+ *
+ * machine specific dump headers
+ *
+ */
+
+/*
+ * IA64 ---------------------------------------------------------
+ */
+
+#if defined(IA64)
+
+#define DUMP_ASM_MAGIC_NUMBER 0xdeaddeadULL /* magic number */
+#define DUMP_ASM_VERSION_NUMBER 0x5 /* version 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.
+ *
+ */
+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;
+
+#elif defined(X86)
+
+#define DUMP_ASM_MAGIC_NUMBER 0xdeaddeadULL /* magic number */
+#define DUMP_ASM_VERSION_NUMBER 0x5 /* version number */
+
+
+struct pt_regs {
+ long ebx;
+ long ecx;
+ long edx;
+ long esi;
+ long edi;
+ long ebp;
+ long eax;
+ int xds;
+ int xes;
+ long orig_eax;
+ long eip;
+ int xcs;
+ long eflags;
+ long esp;
+ int xss;
+};
+
+/*
+ * 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;
+
+#elif defined(X86_64)
+
+/* definitions */
+#define DUMP_ASM_MAGIC_NUMBER 0xdeaddeadULL /* magic number */
+#define DUMP_ASM_VERSION_NUMBER 0x2 /* version number */
+
+
+struct pt_regs {
+ unsigned long r15;
+ unsigned long r14;
+ unsigned long r13;
+ unsigned long r12;
+ unsigned long rbp;
+ unsigned long rbx;
+/* arguments: non interrupts/non tracing syscalls only save upto here*/
+ unsigned long r11;
+ unsigned long r10;
+ unsigned long r9;
+ unsigned long r8;
+ unsigned long rax;
+ unsigned long rcx;
+ unsigned long rdx;
+ unsigned long rsi;
+ unsigned long rdi;
+ unsigned long orig_rax;
+/* end of arguments */
+/* cpu exception frame or undefined */
+ unsigned long rip;
+ unsigned long cs;
+ unsigned long eflags;
+ unsigned long rsp;
+ unsigned long ss;
+/* top of stack page */
+};
+
+/*
+ * 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;
+
+
+#else
+
+#define HAVE_NO_DUMP_HEADER_ASM 1
+
+#endif
+
#endif /* _DUMP_H */
--- a/lkcd_fix_mem.c
+++ b/lkcd_fix_mem.c
@@ -20,21 +20,13 @@
#define LKCD_COMMON
#include "defs.h"
-#include "lkcd_fix_mem.h"
+#include "lkcd_dump_v8.h"
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;
@@ -83,7 +67,7 @@ fix_addr(dump_header_asm_t *dha)
if (dha->dha_stack[i] && dha->dha_smp_current_task[i]) {
lkcd->fix_addr[i].task = (ulong)dha->dha_smp_current_task[i];
lkcd->fix_addr[i].saddr = (ulong)dha->dha_stack[i];
- lkcd->fix_addr[i].sw = (ulong)dha->dha_switch_stack[i];
+ lkcd->fix_addr[i].sw = (ulong)dha->dha_stack_ptr[i];
/* remember the highest non-zero entry */
lkcd->fix_addr_num = i + 1;
} else {
--- a/lkcd_fix_mem.h
+++ /dev/null
@@ -1,295 +0,0 @@
-#ifdef IA64
-
-#define UTSNAME_ENTRY_SZ 65
-
-/* necessary header definitions in all cases */
-#define DUMP_KIOBUF_NUMBER 0xdeadbeef /* special number for kiobuf maps */
-
-/* size of a dump header page */
-#define DUMP_PAGE_SZ 64 * 1024 /* size of dump page buffer */
-
-/* header definitions for s390 dump */
-#define DUMP_MAGIC_S390 0xa8190173618f23fdULL /* s390 magic number */
-#define S390_DUMP_HEADER_SIZE 4096
-
-/* standard header definitions */
-#define DUMP_MAGIC_NUMBER 0xa8190173618f23edULL /* dump magic number */
-#define DUMP_MAGIC_LIVE 0xa8190173618f23cdULL /* live magic number */
-#define DUMP_VERSION_NUMBER 0x5 /* dump version number */
-#define DUMP_PANIC_LEN 0x100 /* dump panic string length */
-
-/* dump levels - type specific stuff added later -- add as necessary */
-#define DUMP_LEVEL_NONE 0x0 /* no dumping at all -- just bail */
-#define DUMP_LEVEL_HEADER 0x1 /* kernel dump header only */
-#define DUMP_LEVEL_KERN 0x2 /* dump header and kernel pages */
-#define DUMP_LEVEL_USED 0x4 /* dump header, kernel/user pages */
-#define DUMP_LEVEL_ALL 0x8 /* dump header, all memory pages */
-
-/* dump compression options -- add as necessary */
-#define DUMP_COMPRESS_NONE 0x0 /* don't compress this dump */
-#define DUMP_COMPRESS_RLE 0x1 /* use RLE compression */
-#define DUMP_COMPRESS_GZIP 0x2 /* use GZIP compression */
-
-/* dump flags - any dump-type specific flags -- add as necessary */
-#define DUMP_FLAGS_NONE 0x0 /* no flags are set for this dump */
-#define DUMP_FLAGS_NONDISRUPT 0x1 /* try to keep running after dump */
-
-/* dump header flags -- add as necessary */
-#define DUMP_DH_FLAGS_NONE 0x0 /* no flags set (error condition!) */
-#define DUMP_DH_RAW 0x1 /* raw page (no compression) */
-#define DUMP_DH_COMPRESSED 0x2 /* page is compressed */
-#define DUMP_DH_END 0x4 /* end marker on a full dump */
-
-/* names for various dump tunables (they are now all read-only) */
-#define DUMP_ROOT_NAME "sys/dump"
-#define DUMP_DEVICE_NAME "dump_device"
-#define DUMP_COMPRESS_NAME "dump_compress"
-#define DUMP_LEVEL_NAME "dump_level"
-#define DUMP_FLAGS_NAME "dump_flags"
-
-/* page size for gzip compression -- buffered beyond PAGE_SIZE slightly */
-#define DUMP_DPC_PAGE_SIZE (PAGE_SIZE + 512)
-
-/* dump ioctl() control options */
-#define DIOSDUMPDEV 1 /* set the dump device */
-#define DIOGDUMPDEV 2 /* get the dump device */
-#define DIOSDUMPLEVEL 3 /* set the dump level */
-#define DIOGDUMPLEVEL 4 /* get the dump level */
-#define DIOSDUMPFLAGS 5 /* set the dump flag parameters */
-#define DIOGDUMPFLAGS 6 /* get the dump flag parameters */
-#define DIOSDUMPCOMPRESS 7 /* set the dump compress level */
-#define DIOGDUMPCOMPRESS 8 /* get the dump compress level */
-
-/* the major number used for the dumping device */
-#ifndef DUMP_MAJOR
-#define DUMP_MAJOR 227
-#endif
-
-/*
- * Structure: dump_header_t
- * Function: This is the header dumped at the top of every valid crash
- * dump.
- * easy reassembly of each crash dump page. The address bits
- * are split to make things easier for 64-bit/32-bit system
- * conversions.
- */
-typedef struct _dump_header_s {
- /* the dump magic number -- unique to verify dump is valid */
- uint64_t dh_magic_number;
-
- /* the version number of this dump */
- uint32_t dh_version;
-
- /* the size of this header (in case we can't read it) */
- uint32_t dh_header_size;
-
- /* the level of this dump (just a header?) */
- uint32_t dh_dump_level;
-
- /* the size of a Linux memory page (4K, 8K, 16K, etc.) */
- uint32_t dh_page_size;
-
- /* the size of all physical memory */
- uint64_t dh_memory_size;
-
- /* the start of physical memory */
- uint64_t dh_memory_start;
-
- /* the end of physical memory */
- uint64_t dh_memory_end;
-
- /* the number of pages in this dump specifically */
- uint32_t dh_num_pages;
-
- /* the panic string, if available */
- char dh_panic_string[DUMP_PANIC_LEN];
-
- /* timeval depends on architecture, two long values */
- struct {
- uint64_t tv_sec;
- uint64_t tv_usec;
- } dh_time; /* the time of the system crash */
-
- /* the NEW utsname (uname) information -- in character form */
- /* we do this so we don't have to include utsname.h */
- /* plus it helps us be more architecture independent */
- /* now maybe one day soon they'll make the [65] a #define! */
- char dh_utsname_sysname[65];
- char dh_utsname_nodename[65];
- char dh_utsname_release[65];
- char dh_utsname_version[65];
- char dh_utsname_machine[65];
- char dh_utsname_domainname[65];
-
- /* the address of current task (OLD = task_struct *, NEW = void *) */
- uint64_t dh_current_task;
-
- /* what type of compression we're using in this dump (if any) */
- uint32_t dh_dump_compress;
-
- /* any additional flags */
- uint32_t dh_dump_flags;
-
- /* any additional flags */
- uint32_t dh_dump_device;
-
-} __attribute__((packed)) dump_header_t;
-
-/*
- * Structure: dump_page_t
- * Function: To act as the header associated to each physical page of
- * memory saved in the system crash dump. This allows for
- * easy reassembly of each crash dump page. The address bits
- * are split to make things easier for 64-bit/32-bit system
- * conversions.
- */
-typedef struct _dump_page_s {
-
- /* the address of this dump page */
- uint64_t dp_address;
-
- /* the size of this dump page */
- uint32_t dp_size;
-
- /* flags (currently DUMP_COMPRESSED, DUMP_RAW or DUMP_END) */
- uint32_t dp_flags;
-} __attribute__((packed)) dump_page_t;
-
-/*
- * This structure contains information needed for the lkcdutils
- * package (particularly lcrash) to determine what information is
- * associated to this kernel, specifically.
- */
-typedef struct lkcdinfo_s {
- int arch;
- int ptrsz;
- int byte_order;
- int linux_release;
- int page_shift;
- int page_size;
- uint64_t page_mask;
- uint64_t page_offset;
- int stack_offset;
-} lkcdinfo_t;
-
-#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.
- *
- */
-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; // version 4 changed this
- 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; // v4 changed this
- struct pt_regs dha_smp_regs[NR_CPUS];
- uint64_t dha_smp_current_task[NR_CPUS]; // v4 changed this
- uint64_t dha_stack[NR_CPUS]; // v4 changed this
- uint64_t dha_switch_stack[NR_CPUS]; // v4 changed this
-
-} __attribute__((packed)) dump_header_asm_t;
-
-#endif // IA64
--- a/lkcd_v8.c
+++ b/lkcd_v8.c
@@ -23,11 +23,187 @@
#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 HAVE_NO_DUMP_HEADER_ASM
+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;
+#if defined(X86_64)
+
+int
+get_lkcd_regs_for_cpu_arch(int cpu, ulong *eip, ulong *esp)
+{
+ if (eip)
+ *eip = dump_header_asm_v8.dha_smp_regs[cpu].rip;
+ if (esp)
+ *esp = dump_header_asm_v8.dha_smp_regs[cpu].rsp;
+
+ return 0;
+}
+
+#elif defined(X86)
+
+int
+get_lkcd_regs_for_cpu_arch(int cpu, ulong *eip, ulong *esp)
+{
+ if (eip)
+ *eip = dump_header_asm_v8.dha_smp_regs[cpu].eip;
+ if (esp)
+ *esp = dump_header_asm_v8.dha_smp_regs[cpu].esp;
+
+ return 0;
+}
+
+#else
+
+int
+get_lkcd_regs_for_cpu_arch(int cpu, ulong *eip, ulong *esp)
+{
+ return -1;
+}
+
+#endif
+
+
+
+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;
+ }
+
+ return get_lkcd_regs_for_cpu_arch(cpu, eip, esp);
+}
+
+
+#ifndef HAVE_NO_DUMP_HEADER_ASM
+int
+lkcd_dump_init_v8_arch(dump_header_t *dh)
+{
+ 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;
+ }
+
+ /*
+ * read the kernel load address on IA64 -- other architectures have
+ * no relocatable kernel at the lifetime of LKCD
+ */
+#ifdef IA64
+ memcpy(&arch_hdr.dha_kernel_addr, (void *)&hdr_buf[offset], sizeof(uint64_t));
+#endif
+
+ memcpy(&dump_header_asm_v8, &arch_hdr, sizeof(dump_header_asm_t));
+
+ return 0;
+
+err:
+ free(hdr_buf);
+ return -1;
+}
+
+#else /* architecture that has no lkcd_dump_init_v8 */
+
+int
+lkcd_dump_init_v8_arch(dump_header_t *dh)
+{
+ return 0;
+}
+
+#endif
+
+
+
/*
* Verify and initialize the LKCD environment, storing the common data
* in the global lkcd_environment structure.
@@ -69,8 +245,14 @@ lkcd_dump_init_v8(FILE *fp, int fd, char
lkcd->dump_header = dh;
if (lkcd->debug)
dump_lkcd_environment(LKCD_DUMP_HEADER_ONLY);
+
+ if (lkcd_dump_init_v8_arch(dh) != 0) {
+ fprintf(stderr, "Warning: Failed to initialise "
+ "arch specific dump code\n");
+ }
+
#ifdef IA64
- if ( (fix_addr_v8(fd) == -1) )
+ if ( (fix_addr_v8(&dump_header_asm_v8) == -1) )
return FALSE;
#endif
--- a/netdump.c
+++ b/netdump.c
@@ -1757,7 +1757,6 @@ struct x86_64_user_regs_struct {
unsigned long fs_base, gs_base;
unsigned long ds,es,fs,gs;
};
-#define offsetof(TYPE, MEMBER) ((ulong)&((TYPE *)0)->MEMBER)
void
get_netdump_regs_x86_64(struct bt_info *bt, ulong *ripp, ulong *rspp)