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)