* Dave Anderson <anderson@xxxxxxxxxx> [2007-10-22 15:32]: > Troy Heber wrote: >> On 10/19/07 12:23, Dave Anderson wrote: >>> 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. >> I just did a quick sanity check on a couple of old IA64 LKCD dumps and >> everything seems to work, so I'm happy. >> Troy Troy, thanks for checking this! > Bernhard, can you post a cleaned-up patch for queueing? Here it is (attached). I didn't see any warnings in the crash code with 'make warn' now. I have used your own definition of offsetof() but moved it into the header file. Thanks, Bernhard
--- Makefile | 4 defs.h | 15 ++ kernel.c | 5 lkcd_dump_v8.h | 300 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lkcd_fix_mem.c | 22 ---- lkcd_fix_mem.h | 295 -------------------------------------------------------- lkcd_v8.c | 187 +++++++++++++++++++++++++++++++++++ netdump.c | 1 8 files changed, 509 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 @@ -437,7 +437,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 @@ -54,6 +54,10 @@ #define TRUE (1) #define FALSE (0) +#define STR(x) #x +#ifndef offsetof +# define offsetof(TYPE, MEMBER) ((ulong)&((TYPE *)0)->MEMBER) +#endif #ifdef X86 #define NR_CPUS (256) @@ -3830,9 +3834,18 @@ void ppc_dump_machdep_table(ulong); * lkcd_fix_mem.c */ +struct _dump_header_asm_s; +struct _dump_header_s; ulong get_lkcd_switch_stack(ulong); -int fix_addr_v8(int); +int fix_addr_v8(struct _dump_header_asm_s *); +int lkcd_dump_init_v8_arch(struct _dump_header_s *dh); int fix_addr_v7(int); +int get_lkcd_regs_for_cpu_arch(int cpu, ulong *eip, ulong *esp); + +/* + * lkcd_v8.c + */ +int get_lkcd_regs_for_cpu(struct bt_info *bt, ulong *eip, ulong *esp); /* * ia64.c --- 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_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, (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_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; + +/* + * i386 --------------------------------------------------------- + */ + +#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_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; + + /* 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_t; + +/* + * CPU specific part of dump_header_asm_t + */ +typedef struct dump_CPU_info_s { + 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_t; + + +/* + * x86-64 --------------------------------------------------------- + */ + +#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_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; + + /* 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; + + +/* + * CPU specific part of dump_header_asm_t + */ +typedef struct dump_CPU_info_s { + 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_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,188 @@ #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 " + "(CPU=%d)\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:%d)\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 +246,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)
-- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility