Bernhard Walle wrote: > 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. > Hi Bernhard, I've taken a quick look at this patch and there are a few issues. I cannot #include any header files that are part of the kernel-headers package. That's a Red Hat specific build issue, and for that reason I had to remove #include's of page.h, segment.h, and list.h -- and ptrace.h is part of our kernel-headers package. Also, for example, the ia64 pt_regs definition has changed at least 3 times over the years, and that's why it gets declared locally 3 different ways in unwind.h, resulting in the three unwind_v[123].o objects created from the single unwind.c file. So, depending upon the version of the host build system, it seems that there could be a fatal mismatch. Also, if I recall correctly, there was also an Ubuntu issue where the system doesn't have kernel header files installed, or perhaps had stub files replacing them? Also, the CFILES+ addition to defs.h shouldn't be done because CFILES is used as part of the SOURCE_FILES list, which is needed for packaging, cscope, file listing, etc. And adding a bunch of new LKCD files at this point in its life-time is not all that appealing if it can be avoided. In any case, I don't do any LKCD "vetting" anymore. Troy Heber (cc'd) is the crash/LKCD gate-keeper, and especially w/respect to ia64 LKCD. Thanks, Dave > > Signed-off-by: Bernhard Walle <bwalle@xxxxxxx> > > --- > 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. > > -- > Crash-utility mailing list > Crash-utility@xxxxxxxxxx > https://www.redhat.com/mailman/listinfo/crash-utility -- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility