[Crash-utility] [PATCH] Use registers from LKCD header to getstarting ESP register

Dave Anderson anderson at redhat.com
Wed May 2 15:06:44 UTC 2007


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 at suse.de>
>
> ---
>  Makefile           |   31 +++++++++-
>  defs.h             |    2
>  kernel.c           |   63 +++++++++++---------
>  lkcd_dump_i386.c   |   32 ++++++++++
>  lkcd_dump_i386.h   |   71 +++++++++++++++++++++++
>  lkcd_dump_ia64.c   |   35 +++++++++++
>  lkcd_dump_ia64.h   |   81 ++++++++++++++++++++++++++
>  lkcd_dump_ppc.h    |   67 +++++++++++++++++++++
>  lkcd_dump_v7.h     |  163 ++---------------------------------------------------
>  lkcd_dump_v8.h     |   32 ++++++++++
>  lkcd_dump_x86_64.c |   32 ++++++++++
>  lkcd_dump_x86_64.h |   71 +++++++++++++++++++++++
>  lkcd_fix_mem.c     |   18 -----
>  lkcd_v8.c          |  140 ++++++++++++++++++++++++++++++++++++++++++++-
>  14 files changed, 633 insertions(+), 205 deletions(-)
>
> --- a/Makefile
> +++ b/Makefile
> @@ -97,6 +97,24 @@ OBJECT_FILES=main.o tools.o global_data.
>         xen_hyper.o xen_hyper_command.o xen_hyper_global_data.o \
>         xen_hyper_dump_tables.o
>
> +
> +# architecture specific LKCD files
> +
> +ifeq ($(ARCH), x86_64)
> +CFILES                 += lkcd_dump_x86_64.c
> +OBJECT_FILES   += lkcd_dump_x86_64.o
> +endif
> +
> +ifeq ($(ARCH), i386)
> +CFILES         += lkcd_dump_i386.c
> +OBJECT_FILES   += lkcd_dump_i386.o
> +endif
> +
> +ifeq ($(ARCH), ia64)
> +CFILES         += lkcd_dump_ia64.c
> +OBJECT_FILES   += lkcd_dump_ia64.o
> +endif
> +
>  # These are the current set of crash extensions sources.  They are not built
>  # by default unless the third command line of the "all:" stanza is uncommented.
>  # Alternatively, they can be built by entering "make extensions" from this
> @@ -334,6 +352,15 @@ lkcd_v7.o: ${GENERIC_HFILES} ${LKCD_DUMP
>  lkcd_v8.o: ${GENERIC_HFILES} ${LKCD_DUMP_HFILES} lkcd_v8.c
>         cc -c ${CFLAGS} -DMCLX lkcd_v8.c ${WARNING_OPTIONS} ${WARNING_ERROR}
>
> +lkcd_dump_x86_64.o: ${GENERIC_HFILES} ${LKCD_DUMP_HFILES} lkcd_dump_x86_64.c
> +       cc -c ${CFLAGS} -DMCLX lkcd_dump_x86_64.c ${WARNING_OPTIONS} ${WARNING_ERROR}
> +
> +lkcd_dump_i386.o: ${GENERIC_HFILES} ${LKCD_DUMP_HFILES} lkcd_dump_i386.c
> +       cc -c ${CFLAGS} -DMCLX lkcd_dump_i386.c ${WARNING_OPTIONS} ${WARNING_ERROR}
> +
> +lkcd_dump_ia64.o: ${GENERIC_HFILES} ${LKCD_DUMP_HFILES} lkcd_dump_ia64.c
> +       cc -c ${CFLAGS} -DMCLX lkcd_dump_ia64.c ${WARNING_OPTIONS} ${WARNING_ERROR}
> +
>  net.o: ${GENERIC_HFILES} net.c
>         cc -c ${CFLAGS} net.c ${WARNING_OPTIONS} ${WARNING_ERROR}
>
> --- a/defs.h
> +++ b/defs.h
> @@ -3790,7 +3790,7 @@ void ppc_dump_machdep_table(ulong);
>   */
>
>  ulong get_lkcd_switch_stack(ulong);
> -int fix_addr_v8(int);
> +int fix_addr_v8();
>  int fix_addr_v7(int);
>
>  /*
> --- a/kernel.c
> +++ b/kernel.c
> @@ -2089,6 +2089,11 @@ get_lkcd_regs(struct bt_info *bt, ulong
>                 return;
>         }
>
> +       /* try to get it from the header */
> +       if (get_lkcd_regs_for_cpu(bt, eip, esp) == 0)
> +               return;
> +
> +       /* if that fails: do guessing */
>         sysrq_eip = sysrq_esp = 0;
>
>         for (i = 0, up = (ulong *)bt->stackbuf; i < LONGS_PER_STACK; i++, up++){
> @@ -2098,48 +2103,48 @@ get_lkcd_regs(struct bt_info *bt, ulong
>                         *esp = *(up-1);
>                         return;
>                 }
> -                /* Begin 3PAR change -- required for our panic path */
> +               /* Begin 3PAR change -- required for our panic path */
>                 if (STREQ(sym, "dump_ipi") && INSTACK(*(up-1), bt)) {
>                         *eip = *up;
>                         *esp = *(up-1);
>                         return;
>                 }
>                 /* End 3PAR change */
> -                if (STREQ(sym, "panic") && INSTACK(*(up-1), bt)) {
> -                        *eip = *up;
> -                        *esp = *(up-1);
> -                        return;
> -                }
> +               if (STREQ(sym, "panic") && INSTACK(*(up-1), bt)) {
> +                       *eip = *up;
> +                       *esp = *(up-1);
> +                       return;
> +               }
>                 /* Egenera */
> -                if (STREQ(sym, "netdump_ipi")) {
> -                        *eip = *up;
> -                        *esp = bt->task +
> +               if (STREQ(sym, "netdump_ipi")) {
> +                       *eip = *up;
> +                       *esp = bt->task +
>                                 ((char *)(up-1) - bt->stackbuf);
> -                        return;
> -                }
> -                if (STREQ(sym, "smp_stop_cpu_interrupt")) {
> -                        *eip = *up;
> -                        *esp = bt->task +
> +                       return;
> +               }
> +               if (STREQ(sym, "smp_stop_cpu_interrupt")) {
> +                       *eip = *up;
> +                       *esp = bt->task +
>                                 ((char *)(up-1) - bt->stackbuf);
> -                        return;
> -                }
> -                if (STREQ(sym, "stop_this_cpu")) {
> -                        *eip = *up;
> -                        *esp = bt->task +
> +                       return;
> +               }
> +               if (STREQ(sym, "stop_this_cpu")) {
> +                       *eip = *up;
> +                       *esp = bt->task +
>                                 ((char *)(up-1) - bt->stackbuf);
> -                        return;
> -                }
> -                if (SYSRQ_TASK(bt->task) &&
> -                   STREQ(sym, "smp_call_function_interrupt")) {
> -                        sysrq_eip = *up;
> -                        sysrq_esp = bt->task +
> -                                ((char *)(up-1) - bt->stackbuf);
> -                }
> +                       return;
> +               }
> +               if (SYSRQ_TASK(bt->task) &&
> +                               STREQ(sym, "smp_call_function_interrupt")) {
> +                       sysrq_eip = *up;
> +                       sysrq_esp = bt->task +
> +                               ((char *)(up-1) - bt->stackbuf);
> +               }
>         }
>
>         if (sysrq_eip) {
> -               *eip = sysrq_eip;
> -               *esp = sysrq_esp;
> +               *eip = sysrq_eip;
> +               *esp = sysrq_esp;
>                 return;
>         }
>
> --- /dev/null
> +++ b/lkcd_dump_i386.c
> @@ -0,0 +1,32 @@
> +/* lkcd_dump_i386.c
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +#include <stdint.h>
> +#include <stddef.h>
> +#include <stdio.h>
> +
> +#define LKCD_COMMON
> +#include "defs.h"
> +#include "lkcd_dump_v8.h"
> +
> +
> +int
> +get_lkcd_regs_for_cpu_arch_i386(dump_header_asm_t *dha, int cpu, ulong *eip, ulong *esp)
> +{
> +       if (eip)
> +               *eip = dha->dha_smp_regs[cpu].eip;
> +       if (esp)
> +               *esp = dha->dha_smp_regs[cpu].esp;
> +
> +       return 0;
> +}
> +
> --- /dev/null
> +++ b/lkcd_dump_i386.h
> @@ -0,0 +1,71 @@
> +/* lkcd_dump_i386.h
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +#ifndef LKCD_DUMP_I386_H
> +#define LKCD_DUMP_I386_H
> +
> +#include <linux/ptrace.h>
> +
> +/* from kernel include/asm-i386/dump.h */
> +#define DUMP_ASM_MAGIC_NUMBER  0xdeaddeadULL   /* magic number            */
> +#define DUMP_ASM_VERSION_NUMBER        0x5     /* version number          */
> +
> +/*
> + * Structure: __dump_header_asm
> + *  Function: This is the header for architecture-specific stuff.  It
> + *            follows right after the dump header.
> + */
> +typedef struct __dump_header_asm_i386 {
> +       /* the dump magic number -- unique to verify dump is valid */
> +       uint64_t        dha_magic_number;
> +
> +       /* the version number of this dump */
> +       uint32_t        dha_version;
> +
> +       /* the size of this header (in case we can't read it) */
> +       uint32_t        dha_header_size;
> +
> +       /* the esp for i386 systems */
> +       uint32_t        dha_esp;
> +
> +       /* the eip for i386 systems */
> +       uint32_t        dha_eip;
> +
> +       /* the dump registers */
> +       struct pt_regs  dha_regs;
> +
> +       /* smp specific */
> +       uint32_t        dha_smp_num_cpus;
> +       uint32_t        dha_dumping_cpu;
> +       struct pt_regs  dha_smp_regs[NR_CPUS];
> +       uint32_t        dha_smp_current_task[NR_CPUS];
> +       uint32_t        dha_stack[NR_CPUS];
> +       uint32_t        dha_stack_ptr[NR_CPUS];
> +} __attribute__((packed)) dump_header_asm_i386_t;
> +
> +/*
> + * CPU specific part of dump_header_asm_t
> + */
> +typedef struct dump_CPU_info_i386 {
> +       struct pt_regs  dha_smp_regs;
> +       uint64_t        dha_smp_current_task;
> +       uint64_t        dha_stack;
> +       uint64_t        dha_stack_ptr;
> +} __attribute__ ((packed)) dump_CPU_info_i386_t;
> +
> +
> +typedef struct __dump_header_asm_i386 dump_header_asm_t;
> +typedef struct dump_CPU_info_i386 dump_CPU_info_t;
> +
> +
> +#endif /* LKCD_DUMP_I386_H */
> +
> --- /dev/null
> +++ b/lkcd_dump_ia64.c
> @@ -0,0 +1,35 @@
> +/* lkcd_dump_x86_64.c
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +#include <stdint.h>
> +#include <stddef.h>
> +#include <stdio.h>
> +
> +#define LKCD_COMMON
> +#include "defs.h"
> +#include "lkcd_dump_v8.h"
> +#include "lkcd_dump_ia64.h"
> +
> +
> +/* reads the load address value for IA64 */
> +
> +int lkcd_dump_init_v8_ia64(int fd, dump_header_asm_t *dha)
> +{
> +    int ret;
> +
> +    ret = read(fd, &dha->dha_kernel_addr, sizeof(dha->dha_kernel_addr));
> +    if (ret != sizeof(dha->dha_kernel_addr))
> +        return -1;
> +    else
> +        return 0;
> +}
> +
> --- /dev/null
> +++ b/lkcd_dump_ia64.h
> @@ -0,0 +1,81 @@
> +/* lkcd_dump_ia64.h
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +#ifndef LKCD_DUMP_IA64_H
> +#define LKCD_DUMP_IA64_H
> +
> +#define _ASM_IA64_FPU_H
> +#include <linux/ptrace.h>
> +
> +#define DUMP_ASM_MAGIC_NUMBER     0xdeaddeadULL  /* magic number */
> +#define DUMP_ASM_VERSION_NUMBER   0x5            /* version number          */
> +
> +/*
> + * Structure: dump_header_asm_t
> + *  Function: This is the header for architecture-specific stuff.  It
> + *            follows right after the dump header.
> + */
> +/*typedef struct _dump_header_asm {*/
> +
> +typedef struct __dump_header_asm_ia64 {
> +
> +        /* the dump magic number -- unique to verify dump is valid */
> +        uint64_t             dha_magic_number;
> +
> +        /* the version number of this dump */
> +        uint32_t             dha_version;
> +
> +        /* the size of this header (in case we can't read it) */
> +        uint32_t             dha_header_size;
> +
> +        /* pointer to pt_regs, (OLD: (struct pt_regs *, NEW: (uint64_t)) */
> +       uint64_t             dha_pt_regs;
> +
> +       /* the dump registers */
> +       struct pt_regs       dha_regs;
> +
> +        /* the rnat register saved after flushrs */
> +        uint64_t             dha_rnat;
> +
> +       /* the pfs register saved after flushrs */
> +       uint64_t             dha_pfs;
> +
> +       /* the bspstore register saved after flushrs */
> +       uint64_t             dha_bspstore;
> +
> +       /* smp specific */
> +       uint32_t             dha_smp_num_cpus;
> +       uint32_t             dha_dumping_cpu;
> +       struct pt_regs       dha_smp_regs[NR_CPUS];
> +       uint64_t             dha_smp_current_task[NR_CPUS];
> +       uint64_t             dha_stack[NR_CPUS];
> +       uint64_t             dha_stack_ptr[NR_CPUS];
> +
> +       /* load address of kernel */
> +        uint64_t             dha_kernel_addr;
> +
> +} __attribute__((packed)) dump_header_asm_ia64_t;
> +
> +
> +struct dump_CPU_info_ia64 {
> +       struct pt_regs       dha_smp_regs;
> +       uint64_t             dha_smp_current_task;
> +       uint64_t             dha_stack;
> +       uint64_t             dha_stack_ptr;
> +} __attribute__((packed)) dump_CPU_info_ia64_t;
> +
> +typedef struct dump_CPU_info_ia64 dump_CPU_info_t;
> +typedef struct __dump_header_asm_ia64 dump_header_asm_t;
> +
> +int lkcd_dump_init_v8_ia64(int fd, dump_header_asm_t *dha);
> +
> +#endif /* LKCD_DUMP_IA64_H */
> --- /dev/null
> +++ b/lkcd_dump_ppc.h
> @@ -0,0 +1,67 @@
> +/* lkcd_dump_ppc.h
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +#ifndef LKCD_DUMP_PPC_H
> +#define LKCD_DUMP_PPC_H
> +
> +#include <linux/ptrace.h>
> +
> +/* from kernel include/asm-i386/dump.h */
> +#define DUMP_ASM_MAGIC_NUMBER  0xdeaddeadULL   /* magic number            */
> +#define DUMP_ASM_VERSION_NUMBER        0x5     /* version number          */
> +
> +/*
> + * Structure: __dump_header_asm
> + *  Function: This is the header for architecture-specific stuff.  It
> + *            follows right after the dump header.
> + */
> +struct __dump_header_asm_ppc {
> +
> +        /* the dump magic number -- unique to verify dump is valid */
> +        uint64_t             dha_magic_number;
> +
> +        /* the version number of this dump */
> +        uint32_t             dha_version;
> +
> +        /* the size of this header (in case we can't read it) */
> +        uint32_t             dha_header_size;
> +
> +       /* the dump registers */
> +       struct pt_regs       dha_regs;
> +
> +       /* smp specific */
> +       uint32_t             dha_smp_num_cpus;
> +       int                  dha_dumping_cpu;
> +       struct pt_regs       dha_smp_regs[NR_CPUS];
> +       uint64_t             dha_smp_current_task[NR_CPUS];
> +       uint64_t             dha_stack[NR_CPUS];
> +       uint64_t             dha_stack_ptr[NR_CPUS];
> +} __attribute__((packed)) dump_header_asm_ppc_t;
> +
> +
> +/*
> + * CPU specific part of dump_header_asm_t
> + */
> +typedef struct dump_CPU_info_ppc {
> +       struct pt_regs  dha_smp_regs;
> +       uint64_t        dha_smp_current_task;
> +       uint64_t        dha_stack;
> +       uint64_t        dha_stack_ptr;
> +} __attribute__ ((packed)) dump_CPU_info_ppc_t;
> +
> +
> +typedef struct __dump_header_asm_ppc dump_header_asm_t;
> +typedef struct dump_CPU_info_ppc dump_CPU_info_t;
> +
> +
> +#endif /* LKCD_DUMP_PPC_H */
> +
> --- a/lkcd_dump_v7.h
> +++ b/lkcd_dump_v7.h
> @@ -228,165 +228,20 @@ typedef struct lkcdinfo_s {
>  } lkcdinfo_t;
>
>
> -#ifdef IA64
> -
> -#define DUMP_ASM_MAGIC_NUMBER     0xdeaddeadULL  /* magic number */
> -
> -struct pt_regs {
> -       /* The following registers are saved by SAVE_MIN: */
> -       unsigned long b6;               /* scratch */
> -       unsigned long b7;               /* scratch */
> -
> -       unsigned long ar_csd;           /* used by cmp8xchg16 (scratch) */
> -       unsigned long ar_ssd;           /* reserved for future use (scratch) */
> -
> -       unsigned long r8;               /* scratch (return value register 0) */
> -       unsigned long r9;               /* scratch (return value register 1) */
> -       unsigned long r10;              /* scratch (return value register 2) */
> -       unsigned long r11;              /* scratch (return value register 3) */
> -
> -       unsigned long cr_ipsr;          /* interrupted task's psr */
> -       unsigned long cr_iip;           /* interrupted task's instruction pointer */
> -       unsigned long cr_ifs;           /* interrupted task's function state */
> -
> -       unsigned long ar_unat;          /* interrupted task's NaT register (preserved) */
> -       unsigned long ar_pfs;           /* prev function state  */
> -       unsigned long ar_rsc;           /* RSE configuration */
> -       /* The following two are valid only if cr_ipsr.cpl > 0: */
> -       unsigned long ar_rnat;          /* RSE NaT */
> -       unsigned long ar_bspstore;      /* RSE bspstore */
> -
> -       unsigned long pr;               /* 64 predicate registers (1 bit each) */
> -       unsigned long b0;               /* return pointer (bp) */
> -       unsigned long loadrs;           /* size of dirty partition << 16 */
> -
> -       unsigned long r1;               /* the gp pointer */
> -       unsigned long r12;              /* interrupted task's memory stack pointer */
> -       unsigned long r13;              /* thread pointer */
> -
> -       unsigned long ar_fpsr;          /* floating point status (preserved) */
> -       unsigned long r15;              /* scratch */
> -
> -       /* The remaining registers are NOT saved for system calls.  */
> -
> -       unsigned long r14;              /* scratch */
> -       unsigned long r2;               /* scratch */
> -       unsigned long r3;               /* scratch */
> -
> -       /* The following registers are saved by SAVE_REST: */
> -       unsigned long r16;              /* scratch */
> -       unsigned long r17;              /* scratch */
> -       unsigned long r18;              /* scratch */
> -       unsigned long r19;              /* scratch */
> -       unsigned long r20;              /* scratch */
> -       unsigned long r21;              /* scratch */
> -       unsigned long r22;              /* scratch */
> -       unsigned long r23;              /* scratch */
> -       unsigned long r24;              /* scratch */
> -       unsigned long r25;              /* scratch */
> -       unsigned long r26;              /* scratch */
> -       unsigned long r27;              /* scratch */
> -       unsigned long r28;              /* scratch */
> -       unsigned long r29;              /* scratch */
> -       unsigned long r30;              /* scratch */
> -       unsigned long r31;              /* scratch */
> -
> -       unsigned long ar_ccv;           /* compare/exchange value (scratch) */
> -
> -       /*
> -        * Floating point registers that the kernel considers scratch:
> -        */
> -       struct ia64_fpreg f6;           /* scratch */
> -       struct ia64_fpreg f7;           /* scratch */
> -       struct ia64_fpreg f8;           /* scratch */
> -       struct ia64_fpreg f9;           /* scratch */
> -       struct ia64_fpreg f10;          /* scratch */
> -       struct ia64_fpreg f11;          /* scratch */
> -};
> -
>  /*
> - * Structure: dump_header_asm_t
> - *  Function: This is the header for architecture-specific stuff.  It
> - *            follows right after the dump header.
> + * architecture specific data structures
>   */
> -typedef struct _dump_header_asm_s {
> -
> -        /* the dump magic number -- unique to verify dump is valid */
> -        uint64_t             dha_magic_number;
> -
> -        /* the version number of this dump */
> -        uint32_t             dha_version;
> -
> -        /* the size of this header (in case we can't read it) */
> -        uint32_t             dha_header_size;
> -
> -        /* pointer to pt_regs */
> -       struct pt_regs      *dha_pt_regs;
> -
> -       /* the dump registers */
> -       struct pt_regs       dha_regs;
> -
> -        /* the rnat register saved after flushrs */
> -        uint64_t             dha_rnat;
> -
> -       /* the pfs register saved after flushrs */
> -       uint64_t             dha_pfs;
> -
> -       /* the bspstore register saved after flushrs */
> -       uint64_t             dha_bspstore;
> -
> -       /* smp specific */
> -       uint32_t             dha_smp_num_cpus;
> -       int                  dha_dumping_cpu;
> -       struct pt_regs       dha_smp_regs[NR_CPUS];
> -       void *               dha_smp_current_task[NR_CPUS];
> -       void *               dha_stack[NR_CPUS];
> -       void *               dha_switch_stack[NR_CPUS];
> -
> -} dump_header_asm_t;
> -
> -#define NR_CPUS 32
> -
> -typedef struct _dump_header_asm_smp_s {
> -
> -        /* the dump magic number -- unique to verify dump is valid */
> -        uint64_t             dha_magic_number;
> -
> -        /* the version number of this dump */
> -        uint32_t             dha_version;
> -
> -        /* the size of this header (in case we can't read it) */
> -        uint32_t             dha_header_size;
> -
> -        /* pointer to pt_regs */
> -       struct pt_regs      *dha_pt_regs;
> -
> -       /* the dump registers */
> -       struct pt_regs       dha_regs;
> -
> -        /* the rnat register saved after flushrs */
> -        uint64_t             dha_rnat;
> -
> -       /* the pfs register saved after flushrs */
> -       uint64_t             dha_pfs;
> -
> -       /* the bspstore register saved after flushrs */
> -       uint64_t             dha_bspstore;
> -
> -       /* smp specific */
> -       uint32_t             dha_smp_num_cpus;
> -       int                  dha_dumping_cpu;
> -       struct pt_regs       dha_smp_regs[NR_CPUS];
> -       void *               dha_smp_current_task[NR_CPUS];
> -       void *               dha_stack[NR_CPUS];
> -       void *               dha_switch_stack[NR_CPUS];
> -
> -} dump_header_asm_smp_t;
> -
>
> +#if defined(IA64)
> +#    include "lkcd_dump_ia64.h"
> +#elif defined(X86_64)
> +#    include "lkcd_dump_x86_64.h"
> +#elif defined(X86)
> +#    include "lkcd_dump_i386.h"
> +#else
> +#    error "Add support for your architecture here"
>  #endif
>
> -
>  #ifdef __KERNEL__
>
>  /*
> --- a/lkcd_dump_v8.h
> +++ b/lkcd_dump_v8.h
> @@ -235,4 +235,36 @@ typedef struct lkcdinfo_s {
>         int             stack_offset;
>  } lkcdinfo_t;
>
> +
> +#if defined(IA64)
> +
> +#   include "lkcd_dump_ia64.h"
> +#   define get_lkcd_regs_for_cpu_arch(dha, cpu, eip, esp) \
> +        -1
> +
> +#elif defined(X86_64)
> +
> +#   include "lkcd_dump_x86_64.h"
> +#   define get_lkcd_regs_for_cpu_arch(dha, cpu, eip, esp) \
> +       get_lkcd_regs_for_cpu_arch_x86_64(dha, cpu, eip, esp)
> +
> +#elif defined(X86)
> +
> +#   include "lkcd_dump_i386.h"
> +#   define get_lkcd_regs_for_cpu_arch(dha, cpu, eip, esp) \
> +       get_lkcd_regs_for_cpu_arch_i386(dha, cpu, eip, esp)
> +
> +#elif defined(PPC) || defined(PPC64)
> +
> +#   include "lkcd_dump_ppc.h"
> +#   define get_lkcd_regs_for_cpu_arch(dha, cpu, eip, esp) \
> +        -1
> +
> +#else
> +
> +#   define NO_LKCD_DUMP_ARCH 1
> +
> +#endif
> +
> +
>  #endif /* _DUMP_H */
> --- /dev/null
> +++ b/lkcd_dump_x86_64.c
> @@ -0,0 +1,32 @@
> +/* lkcd_dump_x86_64.c
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +#include <stdint.h>
> +#include <stddef.h>
> +#include <stdio.h>
> +
> +#define LKCD_COMMON
> +#include "defs.h"
> +#include "lkcd_dump_v8.h"
> +
> +
> +int
> +get_lkcd_regs_for_cpu_arch_x86_64(dump_header_asm_t *dha, int cpu, ulong *eip, ulong *esp)
> +{
> +       if (eip)
> +               *eip = dha->dha_smp_regs[cpu].rip;
> +       if (esp)
> +               *esp = dha->dha_smp_regs[cpu].rsp;
> +
> +       return 0;
> +}
> +
> --- /dev/null
> +++ b/lkcd_dump_x86_64.h
> @@ -0,0 +1,71 @@
> +/* lkcd_dump_x86_64.h
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +#ifndef LKCD_DUMP_X86_64_H
> +#define LKCD_DUMP_X86_64_H
> +
> +#include <linux/ptrace.h>
> +
> +#define DUMP_HEADER_SIZE 0x100000
> +
> +
> +/* from kernel include/asm-x86_64/dump.h */
> +
> +/* definitions */
> +#define DUMP_ASM_MAGIC_NUMBER     0xdeaddeadULL  /* magic number            */
> +#define DUMP_ASM_VERSION_NUMBER   0x2            /* version number          */
> +
> +
> +/*
> + * Structure: dump_header_asm_t
> + *  Function: This is the header for architecture-specific stuff.  It
> + *            follows right after the dump header.
> + */
> +typedef struct __dump_header_asm_x86_64 {
> +
> +        /* the dump magic number -- unique to verify dump is valid */
> +        uint64_t             dha_magic_number;
> +
> +        /* the version number of this dump */
> +        uint32_t             dha_version;
> +
> +        /* the size of this header (in case we can't read it) */
> +        uint32_t             dha_header_size;
> +
> +       /* the dump registers */
> +       struct pt_regs       dha_regs;
> +
> +       /* smp specific */
> +       uint32_t             dha_smp_num_cpus;
> +       int                  dha_dumping_cpu;
> +       struct pt_regs       dha_smp_regs[NR_CPUS];
> +       uint64_t             dha_smp_current_task[NR_CPUS];
> +       uint64_t             dha_stack[NR_CPUS];
> +       uint64_t             dha_stack_ptr[NR_CPUS];
> +} __attribute__((packed)) dump_header_asm_t_x86_64;
> +
> +
> +/*
> + * CPU specific part of dump_header_asm_t
> + */
> +typedef struct dump_CPU_info_x86_64 {
> +       struct pt_regs       dha_smp_regs;
> +       uint64_t             dha_smp_current_task;
> +       uint64_t             dha_stack;
> +       uint64_t             dha_stack_ptr;
> +} __attribute__ ((packed)) dump_CPU_info_x86_64_t;
> +
> +typedef struct dump_CPU_info_x86_64 dump_CPU_info_t;
> +typedef struct __dump_header_asm_x86_64 dump_header_asm_t;
> +
> +#endif /* LKCD_DUMP_X86_64_H */
> +
> --- a/lkcd_fix_mem.c
> +++ b/lkcd_fix_mem.c
> @@ -25,16 +25,8 @@
>  static int fix_addr(dump_header_asm_t *);
>
>  int
> -fix_addr_v8(int fd)
> +fix_addr_v8(dump_header_asm_t *dha)
>  {
> -    static dump_header_asm_t dump_header_asm_v8 = { 0 };
> -    dump_header_asm_t *dha;
> -    dha = &dump_header_asm_v8;
> -
> -    if (read(lkcd->fd, dha, sizeof(dump_header_asm_t)) !=
> -           sizeof(dump_header_asm_t))
> -       return -1;
> -
>      fix_addr(dha);
>
>      return 0;
> @@ -59,14 +51,6 @@ fix_addr_v7(int fd)
>  static int
>  fix_addr(dump_header_asm_t *dha)
>  {
> -
> -
> -    if (dha->dha_header_size != sizeof(dump_header_asm_t)) {
> -       error(INFO, "LKCD machine specific dump header doesn't match crash version\n");
> -       error(INFO, "traceback of currently executing threads may not work\n\n");
> -    }
> -
> -
>      lkcd->dump_header_asm = dha;
>
>
> --- a/lkcd_v8.c
> +++ b/lkcd_v8.c
> @@ -19,15 +19,120 @@
>   */
>
>  #define LKCD_COMMON
> +#include <stddef.h>
>  #include "defs.h"
>  #include "lkcd_dump_v8.h"                              /* REMIND */
>
>  static dump_header_t dump_header_v8 = { 0 };
> -// static dump_header_asm_t dump_header_asm_v8 = { 0 };
> +#ifndef NO_LKCD_DUMP_ARCH
> +static dump_header_asm_t dump_header_asm_v8 = { 0 };
> +#endif
>  static dump_page_t dump_page = { 0 };
>  static void mclx_cache_page_headers_v8(void);
>  static off_t lkcd_offset_to_first_page = LKCD_OFFSET_TO_FIRST_PAGE;
>
> +#define STR(x) #x
> +
> +#ifndef NO_LKCD_DUMP_ARCH
> +int
> +lkcd_dump_init_v8_arch(dump_header_t *dh, dump_header_asm_t *dha)
> +{
> +       off_t                   ret_of;
> +       ssize_t                 ret_sz;
> +       uint32_t                hdr_size, offset, nr_cpus;
> +       dump_header_asm_t       arch_hdr;
> +       char                    *hdr_buf = NULL;
> +
> +       ret_of = lseek(lkcd->fd, dh->dh_header_size +
> +                       offsetof(dump_header_asm_t, dha_header_size),
> +                       SEEK_SET);
> +       if (ret_of < 0) {
> +               perror("lseek failed in " __FILE__ ":" STR(__LINE__));
> +               goto err;
> +       }
> +
> +       ret_sz = read(lkcd->fd, (char *)&hdr_size, sizeof(hdr_size));
> +       if (ret_sz != sizeof(hdr_size)) {
> +               perror("Reading hdr_size failed in " __FILE__ ":" STR(__LINE__));
> +               goto err;
> +       }
> +
> +       ret_of = lseek(lkcd->fd, dh->dh_header_size, SEEK_SET);
> +       if (ret_of < 0) {
> +               perror("lseek failed in " __FILE__ ":" STR(__LINE__));
> +               goto err;
> +       }
> +
> +       hdr_buf = (char *)malloc(hdr_size);
> +       if (!hdr_buf) {
> +               perror("Could not allocate memory for dump header\n");
> +               goto err;
> +       }
> +
> +       ret_sz = read(lkcd->fd, (char *)hdr_buf, hdr_size);
> +       if (ret_sz != hdr_size) {
> +               perror("Could not read header " __FILE__ ":" STR(__LINE__));
> +               goto err;
> +       }
> +
> +
> +       /*
> +         * Though we have KL_NR_CPUS is 128, the header size is different
> +         * CONFIG_NR_CPUS might be different in the kernel. Hence, need
> +         * to find out how many CPUs are configured.
> +         */
> +        offset = offsetof(dump_header_asm_t, dha_smp_regs[0]);
> +        nr_cpus = (hdr_size - offset) / sizeof(dump_CPU_info_t);
> +
> +       /* check for CPU overflow */
> +       if (nr_cpus > NR_CPUS) {
> +               fprintf(stderr, "CPU number too high %d (%s:%s)\n",
> +                               nr_cpus, __FILE__, __LINE__);
> +               goto err;
> +       }
> +
> +       /* parts that don't depend on the number of CPUs */
> +       memcpy(&arch_hdr, (void *)hdr_buf, offset);
> +
> +       /* registers */
> +       memcpy(&arch_hdr.dha_smp_regs, (void *)&hdr_buf[offset],
> +                       nr_cpus * sizeof(struct pt_regs));
> +       offset += nr_cpus * sizeof(struct pt_regs);
> +
> +       /* current task */
> +       memcpy(&arch_hdr.dha_smp_current_task, (void *)&hdr_buf[offset],
> +                       nr_cpus * sizeof(&arch_hdr.dha_smp_current_task[0]));
> +       offset += nr_cpus * sizeof(&arch_hdr.dha_smp_current_task[0]);
> +
> +       /* stack */
> +       memcpy(&arch_hdr.dha_stack, (void *)&hdr_buf[offset],
> +                       nr_cpus * sizeof(&arch_hdr.dha_stack[0]));
> +       offset += nr_cpus * sizeof(&arch_hdr.dha_stack[0]);
> +
> +       /* stack_ptr */
> +       memcpy(&arch_hdr.dha_stack_ptr, (void *)&hdr_buf[offset],
> +                       nr_cpus * sizeof(&arch_hdr.dha_stack_ptr[0]));
> +       offset += nr_cpus * sizeof(&arch_hdr.dha_stack_ptr[0]);
> +
> +       if (arch_hdr.dha_magic_number != DUMP_ASM_MAGIC_NUMBER) {
> +               fprintf(stderr, "Invalid magic number for x86_64\n");
> +               goto err;
> +       }
> +
> +#ifdef IA64
> +       lkcd_dump_init_v8_ia64(lkcd->fd, &arch_hdr);
> +#endif
> +
> +       memcpy(dha, &arch_hdr, sizeof(dump_header_asm_t));
> +
> +       return 0;
> +
> +err:
> +       free(hdr_buf);
> +       return -1;
> +}
> +#endif
> +
>  /*
>   *  Verify and initialize the LKCD environment, storing the common data
>   *  in the global lkcd_environment structure.
> @@ -69,8 +174,16 @@ lkcd_dump_init_v8(FILE *fp, int fd, char
>          lkcd->dump_header = dh;
>         if (lkcd->debug)
>                 dump_lkcd_environment(LKCD_DUMP_HEADER_ONLY);
> +
> +#ifndef NO_LKCD_DUMP_ARCH
> +       if (lkcd_dump_init_v8_arch(dh, &dump_header_asm_v8) != 0) {
> +               fprintf(stderr, "Warning: Failed to initialise "
> +                               "arch specific dump code\n");
> +       }
> +#endif
> +
>  #ifdef IA64
> -       if ( (fix_addr_v8(fd) == -1) )
> +       if ( (fix_addr_v8(&dump_header_asm_v8) == -1) )
>             return FALSE;
>  #endif
>
> @@ -233,6 +346,29 @@ lkcd_dump_init_v8(FILE *fp, int fd, char
>         return TRUE;
>  }
>
> +int
> +get_lkcd_regs_for_cpu(struct bt_info *bt, ulong *eip, ulong *esp)
> +{
> +       int cpu;
> +
> +       if (!bt || !bt->tc) {
> +               fprintf(stderr, "get_lkcd_regs_for_cpu: invalid tc\n", cpu);
> +               return -EINVAL;
> +       }
> +
> +       cpu = bt->tc->processor;
> +
> +       if (cpu >= NR_CPUS) {
> +               fprintf(stderr, "get_lkcd_regs_for_cpu, cpu (%d) too high\n", cpu);
> +               return -EINVAL;
> +       }
> +
> +#ifndef NO_LKCD_DUMP_ARCH
> +       return get_lkcd_regs_for_cpu_arch(&dump_header_asm_v8, cpu, eip, esp);
> +#else
> +       return -ENOSYS;
> +#endif
> +}
>
>  /*
>   *  Return the current page's dp_size.
>
> --
> Crash-utility mailing list
> Crash-utility at redhat.com
> https://www.redhat.com/mailman/listinfo/crash-utility




More information about the Crash-utility mailing list