Re: [Crash-utility] [PATCH] Add ELF core dump support for s390x
by Dave Anderson
----- "Michael Holzheu" <holzheu(a)linux.vnet.ibm.com> wrote:
> Dave,
>
> On Mon, 2010-02-15 at 16:56 -0500, Dave Anderson wrote:
> > ----- "Michael Holzheu" <holzheu(a)linux.vnet.ibm.com> wrote:
> > > Sorry, I did not read your note carefully. If you want to do that then
> > > my current implementation is wrong. The problem is that now I expect ELF
> > > note structures and will always do. It is not possible to support
> > > multiple dump formats with my current approach.
> >
> > Sure it's possible. In the (unlikely) case s390x ever needs to support anything
> > else, the first int argument can be made a uniquely-identifiable "command"
> > or some such.
>
> First of all: It is VERY likely that we will support a new dump format
> in the near future. Believe me.
I was talking about the ELF format specifically, and even if the ELF format needs
another tweak for s390x, it can be handled easily.
> Second, how should that work? The callback has an integer and a void
> pointer. The integer is currently used to specify the CPU number. The
> void pointer is used to hold the ELF note information. How the hell can
> I code the information for a new dump format. Or am I missing
> something?
Make the first command command -- in the unlikely event this feature
would ever be required -- start with a #define of NR_CPUS+1, or with the
high bits encoded, or whatever.
Dave
14 years, 9 months
Re: [Crash-utility] [PATCH] Add ELF core dump support for s390x
by Dave Anderson
----- "Michael Holzheu" <holzheu(a)linux.vnet.ibm.com> wrote:
> On Mon, 2010-02-15 at 17:06 +0100, Michael Holzheu wrote:
> > > No major changes other than to rename the machdep->elf_note_add() function
> > > to machdep->dumpfile_init(). The idea is that, in the future, if there is
> > > ever *anything* in *any* type of dumpfile header that should be transmitted
> > > to the architecture code during the dumpfile discovery phase, then that function
> > > can be used. (For example, I could collaborate all of those machdep->xen_xxx()
> > > functions into using it, but I'm not going to bother changing them all
> > > at this point...)
>
> Sorry, I did not read your note carefully. If you want to do that then
> my current implementation is wrong. The problem is that now I expect ELF
> note structures and will always do. It is not possible to support
> multiple dump formats with my current approach.
Sure it's possible. In the (unlikely) case s390x ever needs to support anything
else, the first int argument can be made a uniquely-identifiable "command"
or some such.
> My suggestion would be to have one callback per dump format.
No thanks. There's now over a dozen different supported dumpfile formats.
Your patch is fine. With an int and void * arguments, we can cover
all bases in the future. Typically an int would be a command of some
sort -- but doesn't have to be as in your case -- and the void * could
point to any kind of data structure. I don't want to define things any
more than that.
Dave
14 years, 9 months
Re: [Crash-utility] [PATCH] Add ELF core dump support for s390x
by Dave Anderson
OK, the patch as queued is attached.
No major changes other than to rename the machdep->elf_note_add() function
to machdep->dumpfile_init(). The idea is that, in the future, if there is
ever *anything* in *any* type of dumpfile header that should be transmitted
to the architecture code during the dumpfile discovery phase, then that function
can be used. (For example, I could collaborate all of those machdep->xen_xxx()
functions into using it, but I'm not going to bother changing them all
at this point...)
Thanks,
Dave
14 years, 9 months
Re: [Crash-utility] [PATCH] Add ELF core dump support for s390x
by Dave Anderson
----- "Dave Anderson" <anderson(a)redhat.com> wrote:
> If you're happy with the changes above, I can do it here, make sure
> it compiles, and queue it for the next release.
Here's my proposed patch, along with cleanups for these compiler warnings:
s390x.c: In function 's390x_cpu_get':
s390x.c:91: warning: unused variable 'nt_prefix'
s390x.c: In function 's390x_back_trace_cmd':
s390x.c:762: warning: unused variable 'cpu'
s390x.c: In function 's390x_cpu_get'
s390x.c:104: warning: control reaches end of non-void function
s390x.c:650: warning: ‘s390x_cpu_of_task’ defined but not used
BTW, the second stanza in the patch to s390x.c may require hand-patching --
your original didn't apply on my current tree.
Anyway, does this work for you?
Dave
14 years, 9 months
Re: [Crash-utility] [PATCH] Add ELF core dump support for s390x
by Dave Anderson
----- "Michael Holzheu" <holzheu(a)linux.vnet.ibm.com> wrote:
> Hi Dave,
>
> Next try... I think this one is better:
>
> I added a new machdep function "elf_note_add()" and moved almost all
> into s390x.c:
>
> Add ELF core dump support for s390x
>
> This patch enables crash for reading s390x (64 bit) ELF core dumps. The
> following new ELF note sections are added by this patch:
>
> * NT_FPREGSET: Floating point registers - all architectures
> * NT_S390_TIMER: S390 CPU timer
> * NT_S390_TODCMP: S390 TOD clock comparator
> * NT_S390_TODPREG: S390 TOD programmable register
> * NT_S390_CTRS: S390 control registers
> * NT_S390_PREFIX: S390 prefix register
>
> A new machdep member function "elf_note_add()" is added. In this function
> we setup the s390x CPU information.
OK, this looks good -- these are the changes I would make.
Since a new entry-point is being made in the machdep_table,
let's make it generic so that other arches in the future
may use it for their own purposes, and allow it to be called
from other locations with an int and a generic pointer argument.
So in defs.h, remove this:
+#include <elf.h>
and move it to s390x.c.
Then change this from:
+ void (*elf_note_add)(int, Elf64_Nhdr *);
to:
+ void (*elf_note_add)(int, void *);
And remove this -- it doesn't exist anymore:
+void get_netdump_regs_s390x(struct bt_info *, ulong *, ulong *);
In netdump.c, change this from:
+ if (store && machdep->elf_note_add)
+ machdep->elf_note_add(nd->num_prstatus_notes, note);
to:
+ if (store && machine_type("S390X") && machdep->elf_note_add)
+ machdep->elf_note_add(nd->num_prstatus_notes, (void *)note);
And in s390x.c, adjust for the generic pointer argument, changing this:
+static void s390x_elf_note_add(int elf_cpu_nr, Elf64_Nhdr *note)
+{
to:
+static void s390x_elf_note_add(int elf_cpu_nr, void *noteptr)
+{
+ Elf64_Nhdr *note = (Elf64_Nhdr *)noteptr;
void *desc = get_elf_note_desc(note);
and fix this typo:
+ fprintf(fp, " elf_not_add: s390x_elf_note_add()\n") ;
to:
+ fprintf(fp, " elf_note_add: s390x_elf_note_add()\n") ;
If you're happy with the changes above, I can do it here, make sure
it compiles, and queue it for the next release.
Dave
> ---
> defs.h | 83 ++++++++++++++++++++++++++++++++++
> netdump.c | 11 ++++
> s390x.c | 150
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
> 3 files changed, 236 insertions(+), 8 deletions(-)
>
> --- a/defs.h
> +++ b/defs.h
> @@ -41,6 +41,7 @@
> #include <dirent.h>
> #include <time.h>
> #include <zlib.h>
> +#include <elf.h>
> #include <sys/types.h>
> #include <sys/stat.h>
> #include <sys/param.h>
> @@ -792,6 +793,7 @@ struct machdep_table {
> void (*clear_machdep_cache)(void);
> int (*xen_kdump_p2m_create)(struct xen_kdump_data *);
> int (*in_alternate_stack)(int, ulong);
> + void (*elf_note_add)(int, Elf64_Nhdr *);
> };
>
> /*
> @@ -2747,6 +2749,86 @@ struct efi_memory_desc_t {
> #define _SECTION_SIZE_BITS 28
> #define _MAX_PHYSMEM_BITS 42
>
> +/*
> + * S390 CPU timer ELF note
> + */
> +#ifndef NT_S390_TIMER
> +#define NT_S390_TIMER 0x301
> +#endif
> +
> +/*
> + * S390 TOD clock comparator ELF note
> + */
> +#ifndef NT_S390_TODCMP
> +#define NT_S390_TODCMP 0x302
> +#endif
> +
> +/*
> + * S390 TOD programmable register ELF note
> + */
> +#ifndef NT_S390_TODPREG
> +#define NT_S390_TODPREG 0x303
> +#endif
> +
> +/*
> + * S390 control registers ELF note
> + */
> +#ifndef NT_S390_CTRS
> +#define NT_S390_CTRS 0x304
> +#endif
> +
> +/*
> + * S390 prefix ELF note
> + */
> +#ifndef NT_S390_PREFIX
> +#define NT_S390_PREFIX 0x305
> +#endif
> +
> +/*
> + * s390x prstatus ELF Note
> + */
> +struct s390x_nt_prstatus {
> + uint8_t pad1[32];
> + uint32_t pr_pid;
> + uint8_t pad2[76];
> + uint64_t psw[2];
> + uint64_t gprs[16];
> + uint32_t acrs[16];
> + uint64_t orig_gpr2;
> + uint32_t pr_fpvalid;
> + uint8_t pad3[4];
> +} __attribute__ ((packed));
> +
> +/*
> + * S390x floating point register ELF Note
> + */
> +#ifndef NT_FPREGSET
> +#define NT_FPREGSET 0x2
> +#endif
> +
> +struct s390x_nt_fpregset {
> + uint32_t fpc;
> + uint32_t pad;
> + uint64_t fprs[16];
> +} __attribute__ ((packed));
> +
> +/*
> + * s390x CPU info
> + */
> +struct s390x_cpu
> +{
> + uint64_t gprs[16];
> + uint64_t ctrs[16];
> + uint32_t acrs[16];
> + uint64_t fprs[16];
> + uint32_t fpc;
> + uint64_t psw[2];
> + uint32_t prefix;
> + uint64_t timer;
> + uint64_t todcmp;
> + uint32_t todpreg;
> +};
> +
> #endif /* S390X */
>
> #ifdef PLATFORM
> @@ -4196,6 +4278,7 @@ void get_netdump_regs(struct bt_info *,
> int is_partial_netdump(void);
> void get_netdump_regs_x86(struct bt_info *, ulong *, ulong *);
> void get_netdump_regs_x86_64(struct bt_info *, ulong *, ulong *);
> +void get_netdump_regs_s390x(struct bt_info *, ulong *, ulong *);
> struct vmcore_data;
> struct vmcore_data *get_kdump_vmcore_data(void);
> int read_kdump(int, void *, int, ulong, physaddr_t);
> --- a/netdump.c
> +++ b/netdump.c
> @@ -213,6 +213,11 @@ is_netdump(char *file, ulong source_quer
> goto bailout;
> break;
>
> + case EM_S390:
> + if (machine_type_mismatch(file, "S390X", NULL,
> + source_query))
> + goto bailout;
> + break;
> case EM_386:
> if (machine_type_mismatch(file, "X86", NULL,
> source_query))
> @@ -1989,7 +1994,8 @@ dump_Elf64_Nhdr(Elf64_Off offset, int st
> netdump_print("(XEN_ELFNOTE_CRASH_REGS)\n");
> break;
> }
> -
> + if (store && machdep->elf_note_add)
> + machdep->elf_note_add(nd->num_prstatus_notes, note);
> uptr = (ulonglong *)(ptr + note->n_namesz);
>
> /*
> @@ -2082,6 +2088,9 @@ get_netdump_regs(struct bt_info *bt, ulo
> return get_netdump_regs_x86_64(bt, eip, esp);
> break;
>
> + case EM_S390:
> + machdep->get_stack_frame(bt, eip, esp);
> + break;
> default:
> error(FATAL,
> "support for ELF machine type %d not available\n",
> --- a/s390x.c
> +++ b/s390x.c
> @@ -56,7 +56,6 @@ static ulong s390x_processor_speed(void)
> static int s390x_eframe_search(struct bt_info *);
> static void s390x_back_trace_cmd(struct bt_info *);
> static void s390x_dump_irq(int);
> -static void s390x_get_stack_frame(struct bt_info *, ulong *, ulong
> *);
> static int s390x_dis_filter(ulong, char *);
> static void s390x_cmd_mach(void);
> static int s390x_get_smp_cpus(void);
> @@ -64,7 +63,10 @@ static void s390x_display_machine_stats(
> static void s390x_dump_line_number(ulong);
> static struct line_number_hook s390x_line_number_hooks[];
> static int s390x_is_uvaddr(ulong, struct task_context *);
> +static void s390x_get_stack_frame(struct bt_info *, ulong *, ulong
> *);
>
> +static struct s390x_cpu *s390x_cpu_vec;
> +static int s390x_cpu_cnt;
>
> /*
> * Initialize member offsets
> @@ -79,6 +81,115 @@ static void s390x_offsets_init(void)
> "psw_save_area");
> }
>
> +/*
> + * Return s390x CPU data for backtrace
> + */
> +static struct s390x_cpu *s390x_cpu_get(struct bt_info *bt)
> +{
> + unsigned int cpu = bt->tc->processor;
> + unsigned long lowcore_ptr, prefix;
> + uint32_t *nt_prefix;
> + unsigned int i;
> +
> + lowcore_ptr = symbol_value("lowcore_ptr");
> + readmem(lowcore_ptr + cpu * sizeof(long), KVADDR,
> + &prefix, sizeof(long), "lowcore_ptr", FAULT_ON_ERROR);
> + for (i = 0; i < s390x_cpu_cnt; i++) {
> + if (s390x_cpu_vec[i].prefix == prefix) {
> + fprintf(fp, "GOT: %i\n", i);
> + return &s390x_cpu_vec[i];
> + }
> + }
> + error(FATAL, "cannot determine CPU for task: %lx\n", bt->task);
> +}
> +
> +/*
> + * ELF core dump fuctions for storing CPU data
> + */
> +static void s390x_elf_nt_prstatus_add(struct s390x_cpu *cpu,
> + struct s390x_nt_prstatus *prstatus)
> +{
> + memcpy(&cpu->psw, &prstatus->psw, sizeof(cpu->psw));
> + memcpy(&cpu->gprs, &prstatus->gprs, sizeof(cpu->gprs));
> + memcpy(&cpu->acrs, &prstatus->acrs, sizeof(cpu->acrs));
> +}
> +
> +static void s390x_elf_nt_fpregset_add(struct s390x_cpu *cpu,
> + struct s390x_nt_fpregset *fpregset)
> +{
> + memcpy(&cpu->fpc, &fpregset->fpc, sizeof(cpu->fpc));
> + memcpy(&cpu->fprs, &fpregset->fprs, sizeof(cpu->fprs));
> +}
> +
> +static void s390x_elf_nt_timer_add(struct s390x_cpu *cpu, void
> *desc)
> +{
> + memcpy(&cpu->timer, desc, sizeof(cpu->timer));
> +}
> +
> +static void s390x_elf_nt_todcmp_add(struct s390x_cpu *cpu, void
> *desc)
> +{
> + memcpy(&cpu->todcmp, desc, sizeof(cpu->todcmp));
> +}
> +
> +static void s390x_elf_nt_todpreg_add(struct s390x_cpu *cpu, void
> *desc)
> +{
> + memcpy(&cpu->todpreg, desc, sizeof(cpu->todpreg));
> +}
> +
> +static void s390x_elf_nt_ctrs_add(struct s390x_cpu *cpu, void *desc)
> +{
> + memcpy(&cpu->ctrs, desc, sizeof(cpu->ctrs));
> +}
> +
> +static void s390x_elf_nt_prefix_add(struct s390x_cpu *cpu, void
> *desc)
> +{
> + memcpy(&cpu->prefix, desc, sizeof(cpu->prefix));
> +}
> +
> +static void *get_elf_note_desc(Elf64_Nhdr *note)
> +{
> + void *ptr = note;
> +
> + return ptr + roundup(sizeof(*note) + note->n_namesz, 4);
> +}
> +
> +static void s390x_elf_note_add(int elf_cpu_nr, Elf64_Nhdr *note)
> +{
> + void *desc = get_elf_note_desc(note);
> + struct s390x_cpu *cpu;
> +
> + if (elf_cpu_nr != s390x_cpu_cnt) {
> + s390x_cpu_cnt++;
> + s390x_cpu_vec = realloc(s390x_cpu_vec,
> + s390x_cpu_cnt * sizeof(*s390x_cpu_vec));
> + if (!s390x_cpu_vec)
> + error(FATAL, "cannot malloc cpu space.");
> + }
> + cpu = &s390x_cpu_vec[s390x_cpu_cnt - 1];
> + switch (note->n_type) {
> + case NT_PRSTATUS:
> + s390x_elf_nt_prstatus_add(cpu, desc);
> + break;
> + case NT_FPREGSET:
> + s390x_elf_nt_fpregset_add(cpu, desc);
> + break;
> + case NT_S390_TIMER:
> + s390x_elf_nt_timer_add(cpu, desc);
> + break;
> + case NT_S390_TODCMP:
> + s390x_elf_nt_todcmp_add(cpu, desc);
> + break;
> + case NT_S390_TODPREG:
> + s390x_elf_nt_todpreg_add(cpu, desc);
> + break;
> + case NT_S390_CTRS:
> + s390x_elf_nt_ctrs_add(cpu, desc);
> + break;
> + case NT_S390_PREFIX:
> + s390x_elf_nt_prefix_add(cpu, desc);
> + break;
> + }
> +}
>
> /*
> * Do all necessary machine-specific setup here. This is called
> several
> @@ -89,6 +200,9 @@ s390x_init(int when)
> {
> switch (when)
> {
> + case SETUP_ENV:
> + machdep->elf_note_add = s390x_elf_note_add;
> + break;
> case PRE_SYMTAB:
> machdep->verify_symbol = s390x_verify_symbol;
> if (pc->flags & KERNEL_DEBUG_QUERY)
> @@ -203,6 +317,7 @@ s390x_dump_machdep_table(ulong arg)
> fprintf(fp, " verify_paddr: generic_verify_paddr()\n");
> fprintf(fp, " init_kernel_pgd: NULL\n");
> fprintf(fp, " value_to_symbol:
> generic_machdep_value_to_symbol()\n");
> + fprintf(fp, " elf_not_add: s390x_elf_note_add()\n");
> fprintf(fp, " line_number_hooks: s390x_line_number_hooks\n");
> fprintf(fp, " last_pgd_read: %lx\n", machdep->last_pgd_read);
> fprintf(fp, " last_pmd_read: %lx\n", machdep->last_pmd_read);
> @@ -571,15 +686,37 @@ s390x_has_cpu(struct bt_info *bt)
> * read lowcore for cpu
> */
> static void
> -s390x_get_lowcore(int cpu, char* lowcore)
> +s390x_get_lowcore(struct bt_info *bt, char* lowcore)
> {
> unsigned long lowcore_array,lowcore_ptr;
> + struct s390x_cpu *s390x_cpu;
> + int cpu = bt->tc->processor;
>
> lowcore_array = symbol_value("lowcore_ptr");
> readmem(lowcore_array + cpu * S390X_WORD_SIZE,KVADDR,
> - &lowcore_ptr, sizeof(long), "lowcore_ptr", FAULT_ON_ERROR);
> - readmem(lowcore_ptr, KVADDR, lowcore, LOWCORE_SIZE, "lowcore",
> + &lowcore_ptr, sizeof(long), "lowcore_ptr",
> FAULT_ON_ERROR);
> + readmem(lowcore_ptr, KVADDR, lowcore, LOWCORE_SIZE, "lowcore",
> FAULT_ON_ERROR);
> +
> + if (!s390x_cpu_vec)
> + return;
> +
> + /* Copy register information to defined places in lowcore */
> + s390x_cpu = s390x_cpu_get(bt);
> +
> + memcpy(lowcore + 4864, &s390x_cpu->psw, sizeof(s390x_cpu->psw));
> + memcpy(lowcore + 4736, &s390x_cpu->gprs, sizeof(s390x_cpu->gprs));
> + memcpy(lowcore + 4928, &s390x_cpu->acrs, sizeof(s390x_cpu->acrs));
> +
> + memcpy(lowcore + 4892, &s390x_cpu->fpc, sizeof(s390x_cpu->fpc));
> + memcpy(lowcore + 4608, &s390x_cpu->fprs, sizeof(s390x_cpu->fprs));
> +
> + memcpy(lowcore + 4888, &s390x_cpu->prefix,
> sizeof(s390x_cpu->prefix));
> + memcpy(lowcore + 4992, &s390x_cpu->ctrs, sizeof(s390x_cpu->ctrs));
> +
> + memcpy(lowcore + 4900, &s390x_cpu->todpreg,
> sizeof(s390x_cpu->todpreg));
> + memcpy(lowcore + 4904, &s390x_cpu->timer,
> sizeof(s390x_cpu->timer));
> + memcpy(lowcore + 4912, &s390x_cpu->todcmp,
> sizeof(s390x_cpu->todcmp));
> }
>
> /*
> @@ -627,7 +764,7 @@ s390x_back_trace_cmd(struct bt_info *bt)
> fprintf(fp,"(active)\n");
> return;
> }
> - s390x_get_lowcore(cpu,lowcore);
> + s390x_get_lowcore(bt, lowcore);
> psw_flags = ULONG(lowcore + OFFSET(s390_lowcore_psw_save_area));
>
> if(psw_flags & 0x1000000000000ULL){
> @@ -908,7 +1045,7 @@ s390x_get_stack_frame(struct bt_info *bt
> char lowcore[LOWCORE_SIZE];
>
> if(s390x_has_cpu(bt))
> - s390x_get_lowcore(s390x_cpu_of_task(bt->task),lowcore);
> + s390x_get_lowcore(bt, lowcore);
>
> /* get the stack pointer */
> if(esp){
> @@ -1139,5 +1276,4 @@ try_closest:
> }
> }
> }
> -
> #endif
14 years, 9 months
Re: [Crash-utility] [PATCH] Add ELF core dump support for s390x
by Dave Anderson
----- "Michael Holzheu" <holzheu(a)linux.vnet.ibm.com> wrote:
> Hi Dave,
>
> Next patch...
>
> We will have ELF core dumps on s390x in the near future:
>
> This patch enables crash for reading s390x (64 bit) ELF core dumps. The
> following new ELF note sections are added by this patch:
>
> * NT_FPREGSET: Floating point registers - all architectures
> * NT_S390_TIMER: S390 CPU timer
> * NT_S390_TODCMP: S390 TOD clock comparator
> * NT_S390_TODPREG: S390 TOD programmable register
> * NT_S390_CTRS: S390 control registers
> * NT_S390_PREFIX: S390 prefix register
>
> The mapping of a s390 CPU to the correct note number is done via the prefix
> register of the CPUs. This is implemented in s390x_get_note_nr(). The
> function gets the prefix register for the logical CPU number from the lowcore
> pointer array (global variable lowcore_ptr) and searches the matching prefix
> register note.
>
> If CPU information is found in the dump for a running task, it is converted
> into a generic s390x_cpu structure which is then attached to "bt->machdep".
> If "bt->machdep" is set, the s390x "machdep->get_stack_frame()" function uses
> that register information.
OK, first the simple stuff...
The change to is_shared_object() doesn't make sense to me.
That function is only used when loading extension modules.
You make the following change in the ELFCLASS32 section.
So if a 32-bit s390 crash session attempts to load a 32-bit
s390 extension module, your patch will cause it to fall
through and fail:
--- a/symbols.c
+++ b/symbols.c
@@ -2710,7 +2710,7 @@ is_shared_object(char *file)
break;
case EM_S390:
- if (machine_type("S390"))
+ if (machine_type("S390X"))
return TRUE;
break;
How can that work?
Anyway, on to the the bigger picture...
--- a/netdump.h
+++ b/netdump.h
@@ -68,6 +68,12 @@ struct vmcore_data {
ulong switch_stack;
uint num_prstatus_notes;
void *nt_prstatus_percpu[NR_CPUS];
+ void *nt_fpregset_percpu[NR_CPUS];
+ void *nt_s390_timer_percpu[NR_CPUS];
+ void *nt_s390_todcmp_percpu[NR_CPUS];
+ void *nt_s390_todpreg_percpu[NR_CPUS];
+ void *nt_s390_ctrs_percpu[NR_CPUS];
+ void *nt_s390_prefix_percpu[NR_CPUS];
struct xen_kdump_data *xen_kdump_data;
void *vmcoreinfo;
uint size_vmcoreinfo;
This is bit hard to swallow. A while back I went through and purged
several prior static declarations of data structures that used arrays
indexed with NR_CPUS -- replacing them with pointers that dynamically
allocated the arrays when the actual number of cpus was known.
I really don't want to ever *add* any new instances of static arrays
indexed with NR_CPUS. Now you could argue that the currently-existing
nt_prstatus_percpu[NR_CPUS] is there, but that should probably be changed
to malloc() NR_CPUS-worth during the dumpfile discovery phase, and then
do a realloc() later on when the actual number of cpus is determined.
Anyway, the x86_64 and ia64 arches are up to 4096 NR_CPUS, so your patch
adds ~200k of useless static data for those architectures. So I suggest
suggest that all of your new NR_CPU-indexed fields -- none of which are
of any interest to the other architectures -- should be moved into s390x.c,
and then just a single pointer to the collective data could be put into
the vmcore_data structure. (i.e., similar to the xen_kdump_data pointer).
Let's keep the vmcore_data structure as generic as possible.
Also BTW, there's a lot work d one reading/saving the new note data,
but once that's accomplished, I don't see where the data is ever
used? What's the point of saving it if it's not referred
to somewhere later on? You couldn't even look at it unless
you ran a gdb on the crash session. Or am I missing something?
I see the temporary bt->machdep reference to the static s390x_cpu
data structure in get_netdump_regs_s390x(). But I would think
that if you're going to the trouble to save all of that data,
that you might want to put the s390x_cpu structure in s390x,
and then maybe dump its data in s390x_dump_machdep_table()
via "help -m".
Now, the NT_S390_XXX defines -- were did they originate exactly?
If I google them -- all I get is a reference to your 2-hour old
crash-utility mailing list post! Anyway, I haven't tried compiling
it, but given that they are all #define'd in the "#ifdef S390X" section
of defs.h, then netdump.c couldn't possibly compile for any other arch.
Also, the NT_S390_XXX numerical values are probably safe and would never
be misconstrued, but the NT_FPREGSET note is the only new note section
that could conceivably show up in some other architecture, so that
should be restricted to s390x only.
What do you think?
Dave
>
> ---
> defs.h | 66 ++++++++++++++++++++++++
> netdump.c | 164
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> netdump.h | 6 ++
> s390x.c | 34 ++++++++++--
> symbols.c | 2
> 5 files changed, 264 insertions(+), 8 deletions(-)
>
> --- a/defs.h
> +++ b/defs.h
> @@ -2747,6 +2747,71 @@ struct efi_memory_desc_t {
> #define _SECTION_SIZE_BITS 28
> #define _MAX_PHYSMEM_BITS 42
>
> +/*
> + * S390 CPU timer ELF note
> + */
> +#ifndef NT_S390_TIMER
> +#define NT_S390_TIMER 0x301
> +#endif
> +
> +/*
> + * S390 TOD clock comparator ELF note
> + */
> +#ifndef NT_S390_TODCMP
> +#define NT_S390_TODCMP 0x302
> +#endif
> +
> +/*
> + * S390 TOD programmable register ELF note
> + */
> +#ifndef NT_S390_TODPREG
> +#define NT_S390_TODPREG 0x303
> +#endif
> +
> +/*
> + * S390 control registers ELF note
> + */
> +#ifndef NT_S390_CTRS
> +#define NT_S390_CTRS 0x304
> +#endif
> +
> +/*
> + * S390 prefix ELF note
> + */
> +#ifndef NT_S390_PREFIX
> +#define NT_S390_PREFIX 0x305
> +#endif
> +
> +/*
> + * S390 floating point register ELF Note
> + */
> +#ifndef NT_FPREGSET
> +#define NT_FPREGSET 0x2
> +#endif
> +
> +struct nt_s390_fpregset_64 {
> + uint32_t fpc;
> + uint32_t pad;
> + uint64_t fprs[16];
> +} __attribute__ ((packed));
> +
> +/*
> + * s390x CPU info
> + */
> +struct s390x_cpu
> +{
> + uint64_t gprs[16];
> + uint64_t ctrs[16];
> + uint32_t acrs[16];
> + uint64_t fprs[16];
> + uint32_t fpc;
> + uint64_t psw[2];
> + uint32_t prefix;
> + uint64_t timer;
> + uint64_t todcmp;
> + uint32_t todpreg;
> +};
> +
> #endif /* S390X */
>
> #ifdef PLATFORM
> @@ -4196,6 +4261,7 @@ void get_netdump_regs(struct bt_info *,
> int is_partial_netdump(void);
> void get_netdump_regs_x86(struct bt_info *, ulong *, ulong *);
> void get_netdump_regs_x86_64(struct bt_info *, ulong *, ulong *);
> +void get_netdump_regs_s390x(struct bt_info *, ulong *, ulong *);
> struct vmcore_data;
> struct vmcore_data *get_kdump_vmcore_data(void);
> int read_kdump(int, void *, int, ulong, physaddr_t);
> --- a/netdump.c
> +++ b/netdump.c
> @@ -213,6 +213,11 @@ is_netdump(char *file, ulong source_quer
> goto bailout;
> break;
>
> + case EM_S390:
> + if (machine_type_mismatch(file, "S390X", NULL,
> + source_query))
> + goto bailout;
> + break;
> case EM_386:
> if (machine_type_mismatch(file, "X86", NULL,
> source_query))
> @@ -1858,6 +1863,72 @@ dump_Elf64_Nhdr(Elf64_Off offset, int st
> }
> }
> break;
> + case NT_FPREGSET:
> + netdump_print("(NT_FPREGSET)");
> + if (store) {
> + for (i = 0; i < NR_CPUS; i++) {
> + if (nd->nt_fpregset_percpu[i])
> + continue;
> + nd->nt_fpregset_percpu[i] = (void *)note;
> + break;
> + }
> + }
> + break;
> + case NT_S390_TIMER:
> + netdump_print("(NT_S390_TIMER)\n");
> + if (store) {
> + for (i = 0; i < NR_CPUS; i++) {
> + if (nd->nt_s390_timer_percpu[i])
> + continue;
> + nd->nt_s390_timer_percpu[i] = (void *)note;
> + break;
> + }
> + }
> + break;
> + case NT_S390_TODCMP:
> + netdump_print("(NT_S390_TODCMP)\n");
> + if (store) {
> + for (i = 0; i < NR_CPUS; i++) {
> + if (nd->nt_s390_todcmp_percpu[i])
> + continue;
> + nd->nt_s390_todcmp_percpu[i] = (void *)note;
> + break;
> + }
> + }
> + break;
> + case NT_S390_TODPREG:
> + netdump_print("(NT_S390_TODPREG)\n");
> + if (store) {
> + for (i = 0; i < NR_CPUS; i++) {
> + if (nd->nt_s390_todpreg_percpu[i])
> + continue;
> + nd->nt_s390_todpreg_percpu[i] = (void *)note;
> + break;
> + }
> + }
> + break;
> + case NT_S390_CTRS:
> + netdump_print("(NT_S390_CTRS)\n");
> + if (store) {
> + for (i = 0; i < NR_CPUS; i++) {
> + if (nd->nt_s390_ctrs_percpu[i])
> + continue;
> + nd->nt_s390_ctrs_percpu[i] = (void *)note;
> + break;
> + }
> + }
> + break;
> + case NT_S390_PREFIX:
> + netdump_print("(NT_S390_PREFIX)\n");
> + if (store) {
> + for (i = 0; i < NR_CPUS; i++) {
> + if (nd->nt_s390_prefix_percpu[i])
> + continue;
> + nd->nt_s390_prefix_percpu[i] = (void *)note;
> + break;
> + }
> + }
> + break;
> case NT_PRPSINFO:
> netdump_print("(NT_PRPSINFO)\n");
> if (store)
> @@ -2082,6 +2153,9 @@ get_netdump_regs(struct bt_info *bt, ulo
> return get_netdump_regs_x86_64(bt, eip, esp);
> break;
>
> + case EM_S390:
> + get_netdump_regs_s390x(bt, eip, esp);
> + break;
> default:
> error(FATAL,
> "support for ELF machine type %d not available\n",
> @@ -2381,6 +2455,96 @@ get_netdump_regs_ppc64(struct bt_info *b
> machdep->get_stack_frame(bt, eip, esp);
> }
>
> +static void *
> +get_note_desc(Elf64_Nhdr *note)
> +{
> + void *ptr = note;
> +
> + return ptr + roundup(sizeof(*note) + note->n_namesz, 4);
> +}
> +
> +static int
> +s390x_get_note_nr(struct bt_info *bt)
> +{
> + unsigned int cpu = bt->tc->processor;
> + unsigned long lowcore_ptr, prefix;
> + uint32_t *nt_prefix;
> + unsigned int i;
> +
> + lowcore_ptr = symbol_value("lowcore_ptr");
> + readmem(lowcore_ptr + cpu * sizeof(long), KVADDR,
> + &prefix, sizeof(long), "lowcore_ptr", FAULT_ON_ERROR);
> + for (i = 0; i < nd->num_prstatus_notes; i++) {
> + nt_prefix = get_note_desc(nd->nt_s390_prefix_percpu[i]);
> + if (*nt_prefix == prefix)
> + return i;
> + }
> + error(FATAL, "cannot determine NT_PRSTATUS ELF note for task:
> %lx\n",
> + bt->task);
> +}
> +
> +static void
> +s390x_note_to_s390x_cpu(struct s390x_cpu *s390x_cpu, int note_nr)
> +{
> + struct nt_s390_fpregset_64 *nt_s390_fpregset;
> + Elf64_Nhdr *note;
> + char *ptr;
> +
> + /* Copy prstatus note */
> + note = (Elf64_Nhdr *) nd->nt_prstatus_percpu[note_nr];
> + ptr = get_note_desc(note) + MEMBER_OFFSET("elf_prstatus",
> "pr_reg");
> + memcpy(&s390x_cpu->psw, ptr, sizeof(s390x_cpu->psw));
> + memcpy(&s390x_cpu->gprs, ptr + 16, sizeof(s390x_cpu->gprs));
> + memcpy(&s390x_cpu->acrs, ptr + 16 + 16 * 8,
> sizeof(s390x_cpu->acrs));
> +
> + /* Copy s390 floating point register note */
> + nt_s390_fpregset = get_note_desc(nd->nt_fpregset_percpu[note_nr]);
> + memcpy(&s390x_cpu->fpc, &nt_s390_fpregset->fpc,
> + sizeof(s390x_cpu->fpc));
> + memcpy(&s390x_cpu->fprs, &nt_s390_fpregset->fprs,
> + sizeof(s390x_cpu->fprs));
> +
> + /* Copy s390 additional notes */
> + memcpy(&s390x_cpu->timer,
> + get_note_desc(nd->nt_s390_timer_percpu[note_nr]),
> + sizeof(s390x_cpu->timer));
> + memcpy(&s390x_cpu->todcmp,
> + get_note_desc(nd->nt_s390_todcmp_percpu[note_nr]),
> + sizeof(s390x_cpu->todcmp));
> + memcpy(&s390x_cpu->todpreg,
> + get_note_desc(nd->nt_s390_todpreg_percpu[note_nr]),
> + sizeof(s390x_cpu->todpreg));
> + memcpy(&s390x_cpu->ctrs,
> + get_note_desc(nd->nt_s390_ctrs_percpu[note_nr]),
> + sizeof(s390x_cpu->ctrs));
> + memcpy(&s390x_cpu->prefix,
> + get_note_desc(nd->nt_s390_prefix_percpu[note_nr]),
> + sizeof(s390x_cpu->prefix));
> +}
> +
> +void
> +get_netdump_regs_s390x(struct bt_info *bt, ulong *eip, ulong *esp)
> +{
> + static struct s390x_cpu s390x_cpu;
> + unsigned int note_nr;
> + Elf64_Nhdr *note;
> +
> + bt->machdep = NULL;
> + if (nd->num_prstatus_notes == 0)
> + goto out;
> + if (!(is_task_active(bt->task) &&
> + (kt->cpu_flags[bt->tc->processor] & ONLINE)))
> + goto out;
> + note_nr = s390x_get_note_nr(bt);
> + if (!nd->nt_prstatus_percpu[note_nr])
> + error(FATAL, "cannot determine NT_PRSTATUS ELF note for "
> + "task: %lx\n", bt->task);
> + s390x_note_to_s390x_cpu(&s390x_cpu, note_nr);
> + bt->machdep = &s390x_cpu;
> +out:
> + machdep->get_stack_frame(bt, eip, esp);
> +}
> +
> int
> is_partial_netdump(void)
> {
> --- a/netdump.h
> +++ b/netdump.h
> @@ -68,6 +68,12 @@ struct vmcore_data {
> ulong switch_stack;
> uint num_prstatus_notes;
> void *nt_prstatus_percpu[NR_CPUS];
> + void *nt_fpregset_percpu[NR_CPUS];
> + void *nt_s390_timer_percpu[NR_CPUS];
> + void *nt_s390_todcmp_percpu[NR_CPUS];
> + void *nt_s390_todpreg_percpu[NR_CPUS];
> + void *nt_s390_ctrs_percpu[NR_CPUS];
> + void *nt_s390_prefix_percpu[NR_CPUS];
> struct xen_kdump_data *xen_kdump_data;
> void *vmcoreinfo;
> uint size_vmcoreinfo;
> --- a/s390x.c
> +++ b/s390x.c
> @@ -56,7 +56,6 @@ static ulong s390x_processor_speed(void)
> static int s390x_eframe_search(struct bt_info *);
> static void s390x_back_trace_cmd(struct bt_info *);
> static void s390x_dump_irq(int);
> -static void s390x_get_stack_frame(struct bt_info *, ulong *, ulong
> *);
> static int s390x_dis_filter(ulong, char *);
> static void s390x_cmd_mach(void);
> static int s390x_get_smp_cpus(void);
> @@ -64,6 +63,7 @@ static void s390x_display_machine_stats(
> static void s390x_dump_line_number(ulong);
> static struct line_number_hook s390x_line_number_hooks[];
> static int s390x_is_uvaddr(ulong, struct task_context *);
> +static void s390x_get_stack_frame(struct bt_info *, ulong *, ulong
> *);
>
>
> /*
> @@ -571,15 +571,36 @@ s390x_has_cpu(struct bt_info *bt)
> * read lowcore for cpu
> */
> static void
> -s390x_get_lowcore(int cpu, char* lowcore)
> +s390x_get_lowcore(struct bt_info *bt, char* lowcore)
> {
> unsigned long lowcore_array,lowcore_ptr;
> + struct s390x_cpu *s390x_cpu;
> + int cpu = bt->tc->processor;
>
> lowcore_array = symbol_value("lowcore_ptr");
> readmem(lowcore_array + cpu * S390X_WORD_SIZE,KVADDR,
> - &lowcore_ptr, sizeof(long), "lowcore_ptr", FAULT_ON_ERROR);
> - readmem(lowcore_ptr, KVADDR, lowcore, LOWCORE_SIZE, "lowcore",
> + &lowcore_ptr, sizeof(long), "lowcore_ptr",
> FAULT_ON_ERROR);
> + readmem(lowcore_ptr, KVADDR, lowcore, LOWCORE_SIZE, "lowcore",
> FAULT_ON_ERROR);
> +
> + if (!bt->machdep)
> + return;
> +
> + s390x_cpu = bt->machdep;
> + /* Copy ELF register information to defined places in lowcore */
> + memcpy(lowcore + 4864, &s390x_cpu->psw, sizeof(s390x_cpu->psw));
> + memcpy(lowcore + 4736, &s390x_cpu->gprs, sizeof(s390x_cpu->gprs));
> + memcpy(lowcore + 4928, &s390x_cpu->acrs, sizeof(s390x_cpu->acrs));
> +
> + memcpy(lowcore + 4892, &s390x_cpu->fpc, sizeof(s390x_cpu->fpc));
> + memcpy(lowcore + 4608, &s390x_cpu->fprs, sizeof(s390x_cpu->fprs));
> +
> + memcpy(lowcore + 4888, &s390x_cpu->prefix,
> sizeof(s390x_cpu->prefix));
> + memcpy(lowcore + 4992, &s390x_cpu->ctrs, sizeof(s390x_cpu->ctrs));
> +
> + memcpy(lowcore + 4900, &s390x_cpu->todpreg,
> sizeof(s390x_cpu->todpreg));
> + memcpy(lowcore + 4904, &s390x_cpu->timer,
> sizeof(s390x_cpu->timer));
> + memcpy(lowcore + 4912, &s390x_cpu->todcmp,
> sizeof(s390x_cpu->todcmp));
> }
>
> /*
> @@ -627,7 +648,7 @@ s390x_back_trace_cmd(struct bt_info *bt)
> fprintf(fp,"(active)\n");
> return;
> }
> - s390x_get_lowcore(cpu,lowcore);
> + s390x_get_lowcore(bt, lowcore);
> psw_flags = ULONG(lowcore + OFFSET(s390_lowcore_psw_save_area));
>
> if(psw_flags & 0x1000000000000ULL){
> @@ -908,7 +929,7 @@ s390x_get_stack_frame(struct bt_info *bt
> char lowcore[LOWCORE_SIZE];
>
> if(s390x_has_cpu(bt))
> - s390x_get_lowcore(s390x_cpu_of_task(bt->task),lowcore);
> + s390x_get_lowcore(bt, lowcore);
>
> /* get the stack pointer */
> if(esp){
> @@ -1139,5 +1160,4 @@ try_closest:
> }
> }
> }
> -
> #endif
> --- a/symbols.c
> +++ b/symbols.c
> @@ -2710,7 +2710,7 @@ is_shared_object(char *file)
> break;
>
> case EM_S390:
> - if (machine_type("S390"))
> + if (machine_type("S390X"))
> return TRUE;
> break;
> }
>
>
> --
> Crash-utility mailing list
> Crash-utility(a)redhat.com
> https://www.redhat.com/mailman/listinfo/crash-utility
14 years, 9 months
[PATCH] Add ELF core dump support for s390x
by Michael Holzheu
Hi Dave,
Next patch...
We will have ELF core dumps on s390x in the near future:
This patch enables crash for reading s390x (64 bit) ELF core dumps. The
following new ELF note sections are added by this patch:
* NT_FPREGSET: Floating point registers - all architectures
* NT_S390_TIMER: S390 CPU timer
* NT_S390_TODCMP: S390 TOD clock comparator
* NT_S390_TODPREG: S390 TOD programmable register
* NT_S390_CTRS: S390 control registers
* NT_S390_PREFIX: S390 prefix register
The mapping of a s390 CPU to the correct note number is done via the prefix
register of the CPUs. This is implemented in s390x_get_note_nr(). The
function gets the prefix register for the logical CPU number from the lowcore
pointer array (global variable lowcore_ptr) and searches the matching prefix
register note.
If CPU information is found in the dump for a running task, it is converted
into a generic s390x_cpu structure which is then attached to "bt->machdep".
If "bt->machdep" is set, the s390x "machdep->get_stack_frame()" function uses
that register information.
---
defs.h | 66 ++++++++++++++++++++++++
netdump.c | 164 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
netdump.h | 6 ++
s390x.c | 34 ++++++++++--
symbols.c | 2
5 files changed, 264 insertions(+), 8 deletions(-)
--- a/defs.h
+++ b/defs.h
@@ -2747,6 +2747,71 @@ struct efi_memory_desc_t {
#define _SECTION_SIZE_BITS 28
#define _MAX_PHYSMEM_BITS 42
+/*
+ * S390 CPU timer ELF note
+ */
+#ifndef NT_S390_TIMER
+#define NT_S390_TIMER 0x301
+#endif
+
+/*
+ * S390 TOD clock comparator ELF note
+ */
+#ifndef NT_S390_TODCMP
+#define NT_S390_TODCMP 0x302
+#endif
+
+/*
+ * S390 TOD programmable register ELF note
+ */
+#ifndef NT_S390_TODPREG
+#define NT_S390_TODPREG 0x303
+#endif
+
+/*
+ * S390 control registers ELF note
+ */
+#ifndef NT_S390_CTRS
+#define NT_S390_CTRS 0x304
+#endif
+
+/*
+ * S390 prefix ELF note
+ */
+#ifndef NT_S390_PREFIX
+#define NT_S390_PREFIX 0x305
+#endif
+
+/*
+ * S390 floating point register ELF Note
+ */
+#ifndef NT_FPREGSET
+#define NT_FPREGSET 0x2
+#endif
+
+struct nt_s390_fpregset_64 {
+ uint32_t fpc;
+ uint32_t pad;
+ uint64_t fprs[16];
+} __attribute__ ((packed));
+
+/*
+ * s390x CPU info
+ */
+struct s390x_cpu
+{
+ uint64_t gprs[16];
+ uint64_t ctrs[16];
+ uint32_t acrs[16];
+ uint64_t fprs[16];
+ uint32_t fpc;
+ uint64_t psw[2];
+ uint32_t prefix;
+ uint64_t timer;
+ uint64_t todcmp;
+ uint32_t todpreg;
+};
+
#endif /* S390X */
#ifdef PLATFORM
@@ -4196,6 +4261,7 @@ void get_netdump_regs(struct bt_info *,
int is_partial_netdump(void);
void get_netdump_regs_x86(struct bt_info *, ulong *, ulong *);
void get_netdump_regs_x86_64(struct bt_info *, ulong *, ulong *);
+void get_netdump_regs_s390x(struct bt_info *, ulong *, ulong *);
struct vmcore_data;
struct vmcore_data *get_kdump_vmcore_data(void);
int read_kdump(int, void *, int, ulong, physaddr_t);
--- a/netdump.c
+++ b/netdump.c
@@ -213,6 +213,11 @@ is_netdump(char *file, ulong source_quer
goto bailout;
break;
+ case EM_S390:
+ if (machine_type_mismatch(file, "S390X", NULL,
+ source_query))
+ goto bailout;
+ break;
case EM_386:
if (machine_type_mismatch(file, "X86", NULL,
source_query))
@@ -1858,6 +1863,72 @@ dump_Elf64_Nhdr(Elf64_Off offset, int st
}
}
break;
+ case NT_FPREGSET:
+ netdump_print("(NT_FPREGSET)");
+ if (store) {
+ for (i = 0; i < NR_CPUS; i++) {
+ if (nd->nt_fpregset_percpu[i])
+ continue;
+ nd->nt_fpregset_percpu[i] = (void *)note;
+ break;
+ }
+ }
+ break;
+ case NT_S390_TIMER:
+ netdump_print("(NT_S390_TIMER)\n");
+ if (store) {
+ for (i = 0; i < NR_CPUS; i++) {
+ if (nd->nt_s390_timer_percpu[i])
+ continue;
+ nd->nt_s390_timer_percpu[i] = (void *)note;
+ break;
+ }
+ }
+ break;
+ case NT_S390_TODCMP:
+ netdump_print("(NT_S390_TODCMP)\n");
+ if (store) {
+ for (i = 0; i < NR_CPUS; i++) {
+ if (nd->nt_s390_todcmp_percpu[i])
+ continue;
+ nd->nt_s390_todcmp_percpu[i] = (void *)note;
+ break;
+ }
+ }
+ break;
+ case NT_S390_TODPREG:
+ netdump_print("(NT_S390_TODPREG)\n");
+ if (store) {
+ for (i = 0; i < NR_CPUS; i++) {
+ if (nd->nt_s390_todpreg_percpu[i])
+ continue;
+ nd->nt_s390_todpreg_percpu[i] = (void *)note;
+ break;
+ }
+ }
+ break;
+ case NT_S390_CTRS:
+ netdump_print("(NT_S390_CTRS)\n");
+ if (store) {
+ for (i = 0; i < NR_CPUS; i++) {
+ if (nd->nt_s390_ctrs_percpu[i])
+ continue;
+ nd->nt_s390_ctrs_percpu[i] = (void *)note;
+ break;
+ }
+ }
+ break;
+ case NT_S390_PREFIX:
+ netdump_print("(NT_S390_PREFIX)\n");
+ if (store) {
+ for (i = 0; i < NR_CPUS; i++) {
+ if (nd->nt_s390_prefix_percpu[i])
+ continue;
+ nd->nt_s390_prefix_percpu[i] = (void *)note;
+ break;
+ }
+ }
+ break;
case NT_PRPSINFO:
netdump_print("(NT_PRPSINFO)\n");
if (store)
@@ -2082,6 +2153,9 @@ get_netdump_regs(struct bt_info *bt, ulo
return get_netdump_regs_x86_64(bt, eip, esp);
break;
+ case EM_S390:
+ get_netdump_regs_s390x(bt, eip, esp);
+ break;
default:
error(FATAL,
"support for ELF machine type %d not available\n",
@@ -2381,6 +2455,96 @@ get_netdump_regs_ppc64(struct bt_info *b
machdep->get_stack_frame(bt, eip, esp);
}
+static void *
+get_note_desc(Elf64_Nhdr *note)
+{
+ void *ptr = note;
+
+ return ptr + roundup(sizeof(*note) + note->n_namesz, 4);
+}
+
+static int
+s390x_get_note_nr(struct bt_info *bt)
+{
+ unsigned int cpu = bt->tc->processor;
+ unsigned long lowcore_ptr, prefix;
+ uint32_t *nt_prefix;
+ unsigned int i;
+
+ lowcore_ptr = symbol_value("lowcore_ptr");
+ readmem(lowcore_ptr + cpu * sizeof(long), KVADDR,
+ &prefix, sizeof(long), "lowcore_ptr", FAULT_ON_ERROR);
+ for (i = 0; i < nd->num_prstatus_notes; i++) {
+ nt_prefix = get_note_desc(nd->nt_s390_prefix_percpu[i]);
+ if (*nt_prefix == prefix)
+ return i;
+ }
+ error(FATAL, "cannot determine NT_PRSTATUS ELF note for task: %lx\n",
+ bt->task);
+}
+
+static void
+s390x_note_to_s390x_cpu(struct s390x_cpu *s390x_cpu, int note_nr)
+{
+ struct nt_s390_fpregset_64 *nt_s390_fpregset;
+ Elf64_Nhdr *note;
+ char *ptr;
+
+ /* Copy prstatus note */
+ note = (Elf64_Nhdr *) nd->nt_prstatus_percpu[note_nr];
+ ptr = get_note_desc(note) + MEMBER_OFFSET("elf_prstatus", "pr_reg");
+ memcpy(&s390x_cpu->psw, ptr, sizeof(s390x_cpu->psw));
+ memcpy(&s390x_cpu->gprs, ptr + 16, sizeof(s390x_cpu->gprs));
+ memcpy(&s390x_cpu->acrs, ptr + 16 + 16 * 8, sizeof(s390x_cpu->acrs));
+
+ /* Copy s390 floating point register note */
+ nt_s390_fpregset = get_note_desc(nd->nt_fpregset_percpu[note_nr]);
+ memcpy(&s390x_cpu->fpc, &nt_s390_fpregset->fpc,
+ sizeof(s390x_cpu->fpc));
+ memcpy(&s390x_cpu->fprs, &nt_s390_fpregset->fprs,
+ sizeof(s390x_cpu->fprs));
+
+ /* Copy s390 additional notes */
+ memcpy(&s390x_cpu->timer,
+ get_note_desc(nd->nt_s390_timer_percpu[note_nr]),
+ sizeof(s390x_cpu->timer));
+ memcpy(&s390x_cpu->todcmp,
+ get_note_desc(nd->nt_s390_todcmp_percpu[note_nr]),
+ sizeof(s390x_cpu->todcmp));
+ memcpy(&s390x_cpu->todpreg,
+ get_note_desc(nd->nt_s390_todpreg_percpu[note_nr]),
+ sizeof(s390x_cpu->todpreg));
+ memcpy(&s390x_cpu->ctrs,
+ get_note_desc(nd->nt_s390_ctrs_percpu[note_nr]),
+ sizeof(s390x_cpu->ctrs));
+ memcpy(&s390x_cpu->prefix,
+ get_note_desc(nd->nt_s390_prefix_percpu[note_nr]),
+ sizeof(s390x_cpu->prefix));
+}
+
+void
+get_netdump_regs_s390x(struct bt_info *bt, ulong *eip, ulong *esp)
+{
+ static struct s390x_cpu s390x_cpu;
+ unsigned int note_nr;
+ Elf64_Nhdr *note;
+
+ bt->machdep = NULL;
+ if (nd->num_prstatus_notes == 0)
+ goto out;
+ if (!(is_task_active(bt->task) &&
+ (kt->cpu_flags[bt->tc->processor] & ONLINE)))
+ goto out;
+ note_nr = s390x_get_note_nr(bt);
+ if (!nd->nt_prstatus_percpu[note_nr])
+ error(FATAL, "cannot determine NT_PRSTATUS ELF note for "
+ "task: %lx\n", bt->task);
+ s390x_note_to_s390x_cpu(&s390x_cpu, note_nr);
+ bt->machdep = &s390x_cpu;
+out:
+ machdep->get_stack_frame(bt, eip, esp);
+}
+
int
is_partial_netdump(void)
{
--- a/netdump.h
+++ b/netdump.h
@@ -68,6 +68,12 @@ struct vmcore_data {
ulong switch_stack;
uint num_prstatus_notes;
void *nt_prstatus_percpu[NR_CPUS];
+ void *nt_fpregset_percpu[NR_CPUS];
+ void *nt_s390_timer_percpu[NR_CPUS];
+ void *nt_s390_todcmp_percpu[NR_CPUS];
+ void *nt_s390_todpreg_percpu[NR_CPUS];
+ void *nt_s390_ctrs_percpu[NR_CPUS];
+ void *nt_s390_prefix_percpu[NR_CPUS];
struct xen_kdump_data *xen_kdump_data;
void *vmcoreinfo;
uint size_vmcoreinfo;
--- a/s390x.c
+++ b/s390x.c
@@ -56,7 +56,6 @@ static ulong s390x_processor_speed(void)
static int s390x_eframe_search(struct bt_info *);
static void s390x_back_trace_cmd(struct bt_info *);
static void s390x_dump_irq(int);
-static void s390x_get_stack_frame(struct bt_info *, ulong *, ulong *);
static int s390x_dis_filter(ulong, char *);
static void s390x_cmd_mach(void);
static int s390x_get_smp_cpus(void);
@@ -64,6 +63,7 @@ static void s390x_display_machine_stats(
static void s390x_dump_line_number(ulong);
static struct line_number_hook s390x_line_number_hooks[];
static int s390x_is_uvaddr(ulong, struct task_context *);
+static void s390x_get_stack_frame(struct bt_info *, ulong *, ulong *);
/*
@@ -571,15 +571,36 @@ s390x_has_cpu(struct bt_info *bt)
* read lowcore for cpu
*/
static void
-s390x_get_lowcore(int cpu, char* lowcore)
+s390x_get_lowcore(struct bt_info *bt, char* lowcore)
{
unsigned long lowcore_array,lowcore_ptr;
+ struct s390x_cpu *s390x_cpu;
+ int cpu = bt->tc->processor;
lowcore_array = symbol_value("lowcore_ptr");
readmem(lowcore_array + cpu * S390X_WORD_SIZE,KVADDR,
- &lowcore_ptr, sizeof(long), "lowcore_ptr", FAULT_ON_ERROR);
- readmem(lowcore_ptr, KVADDR, lowcore, LOWCORE_SIZE, "lowcore",
+ &lowcore_ptr, sizeof(long), "lowcore_ptr",
FAULT_ON_ERROR);
+ readmem(lowcore_ptr, KVADDR, lowcore, LOWCORE_SIZE, "lowcore", FAULT_ON_ERROR);
+
+ if (!bt->machdep)
+ return;
+
+ s390x_cpu = bt->machdep;
+ /* Copy ELF register information to defined places in lowcore */
+ memcpy(lowcore + 4864, &s390x_cpu->psw, sizeof(s390x_cpu->psw));
+ memcpy(lowcore + 4736, &s390x_cpu->gprs, sizeof(s390x_cpu->gprs));
+ memcpy(lowcore + 4928, &s390x_cpu->acrs, sizeof(s390x_cpu->acrs));
+
+ memcpy(lowcore + 4892, &s390x_cpu->fpc, sizeof(s390x_cpu->fpc));
+ memcpy(lowcore + 4608, &s390x_cpu->fprs, sizeof(s390x_cpu->fprs));
+
+ memcpy(lowcore + 4888, &s390x_cpu->prefix, sizeof(s390x_cpu->prefix));
+ memcpy(lowcore + 4992, &s390x_cpu->ctrs, sizeof(s390x_cpu->ctrs));
+
+ memcpy(lowcore + 4900, &s390x_cpu->todpreg, sizeof(s390x_cpu->todpreg));
+ memcpy(lowcore + 4904, &s390x_cpu->timer, sizeof(s390x_cpu->timer));
+ memcpy(lowcore + 4912, &s390x_cpu->todcmp, sizeof(s390x_cpu->todcmp));
}
/*
@@ -627,7 +648,7 @@ s390x_back_trace_cmd(struct bt_info *bt)
fprintf(fp,"(active)\n");
return;
}
- s390x_get_lowcore(cpu,lowcore);
+ s390x_get_lowcore(bt, lowcore);
psw_flags = ULONG(lowcore + OFFSET(s390_lowcore_psw_save_area));
if(psw_flags & 0x1000000000000ULL){
@@ -908,7 +929,7 @@ s390x_get_stack_frame(struct bt_info *bt
char lowcore[LOWCORE_SIZE];
if(s390x_has_cpu(bt))
- s390x_get_lowcore(s390x_cpu_of_task(bt->task),lowcore);
+ s390x_get_lowcore(bt, lowcore);
/* get the stack pointer */
if(esp){
@@ -1139,5 +1160,4 @@ try_closest:
}
}
}
-
#endif
--- a/symbols.c
+++ b/symbols.c
@@ -2710,7 +2710,7 @@ is_shared_object(char *file)
break;
case EM_S390:
- if (machine_type("S390"))
+ if (machine_type("S390X"))
return TRUE;
break;
}
14 years, 9 months
Re: [Crash-utility] Running idle threads show wrong CPU numbers
by Dave Anderson
----- "Michael Holzheu" <holzheu(a)linux.vnet.ibm.com> wrote:
> The following shows the output of "bt -a" without the patch:
>
> PID: 0 TASK: 18d38340 CPU: 2 COMMAND: "swapper"
> bt: invalid kernel virtual address: ffffffffffffc000 type: "async_stack"
>
> PID: 0 TASK: 18d40440 CPU: 3 COMMAND: "swapper"
> bt: invalid kernel virtual address: ffffffffffffc000 type: "async_stack"
>
> We can't leave it like that. With my patch at least we get a correct
> stack backtrace:
>
> PID: 0 TASK: 18d38340 CPU: 2 COMMAND: "swapper"
> #0 [18d3feb8] ret_from_fork at 117e12
OK, fair enough.. ;-)
>
> How is the output of a backtrace of offline CPUs on other
> architectures?
Well, none of the other arches have anything like that "lowcore" business,
so they work like any other blocked task, although that may be somewhat
dumpfile-type-dependent. I did check an i386, and it actually showed
a backtrace that passed through cpu_exit_clear() called from cpu_idle(),
via the inlined play_dead():
cpu_idle (void)
{
...
if (cpu_is_offline(cpu))
play_dead();
}
}
Anyway, queued for the next release. Sorry for keeping you late!
Dave
14 years, 9 months
Re: [Crash-utility] Running idle threads show wrong CPU numbers
by Dave Anderson
On Wed, 2010-02-10 at 14:01 -0500, Dave Anderson wrote:
> ----- "Michael Holzheu" <holzheu(a)linux.vnet.ibm.com> wrote:
>
> > > > It shows all swapper tasks (online and offline), but I get errors for
> > > > the backtrace for the offline CPUs.
> > >
> > > What kind of errors?
> >
> > The problem is that for the offline swapper tasks
> > s390x_get_stack_frame() is called. In that function I check with
> > s390x_has_cpu() if the task is currently running on a CPU. Because of
> > the missing CPU online check, s390x_has_cpu() returns TRUE. Therefore I
> > try to read the CPU registers from the lowcore of that CPU. The lowcore
> > pointer is zero, because the CPU is offline. Therefore the read stack
> > pointer (register 15) is wrong and the backtrace fails.
> >
> > > >
> > > > The attached patch would solve the problem (and eliminate most of the
> > > > probably redundant s390(x)_has_cpu() function.
> > >
> > > I don't see what's being solved by the patch (not the s390x_get_smp_cpus
> > > parts) -- does the "old" s390x_has_cpu() fail?
> >
> > The old s390x_has_cpu() returns TRUE for the offline swapper tasks. And
> > I think that this is wrong.
>
> Hmmm... To me, it is TRUE, i.e., the existing-but-idle swapper task for
> an offline cpu actually *does* own that cpu.
>
> And that's why I was wondering about what error message gets shown.
>
> >
> > The new implementation of s390x_has_cpu() should return TRUE if the task
> > is running on a online CPU and FALSE otherwise:
> >
> > + if (is_task_active(bt->task) && (kt->cpu_flags[cpu] & ONLINE))
> > + return TRUE;
> > + else
> > + return FALSE;
>
> This is probably OK, although I am slightly hesitant about throwing out all
> of the old backwards-compatibility code in the s390[x]_has_cpu() functions.
Why? The "is_task_active()" function must also work on all supported
kernel levels. Otherwise crash would probably fail in other s390
independent functions, wouldn't it? Of course, we could also keep my old
code and add the online check to the old code.
> I thought maybe it would be safer to leave well enough alone, and not
> worry about any error messages from backtraces of offline cpus.
> It might be even more useful that there are error messages to alert
> the user that the cpu is not online?
The following shows the output of "bt -a" without the patch:
PID: 0 TASK: 18d38340 CPU: 2 COMMAND: "swapper"
bt: invalid kernel virtual address: ffffffffffffc000 type:
"async_stack"
PID: 0 TASK: 18d40440 CPU: 3 COMMAND: "swapper"
bt: invalid kernel virtual address: ffffffffffffc000 type:
"async_stack"
We can't leave it like that. With my patch at least we get a correct
stack backtrace:
PID: 0 TASK: 18d38340 CPU: 2 COMMAND: "swapper"
#0 [18d3feb8] ret_from_fork at 117e12
How is the output of a backtrace of offline CPUs on other architectures?
Michael
14 years, 9 months
Running idle threads show wrong CPU numbers
by Dave Anderson
----- Forwarded Message -----
From: "Dave Anderson" <anderson(a)redhat.com>
----- "Michael Holzheu" <holzheu(a)linux.vnet.ibm.com> wrote:
> On Wed, 2010-02-10 at 10:08 -0500, Dave Anderson wrote:
> > ----- "Michael Holzheu" <holzheu(a)linux.vnet.ibm.com> wrote:
> >
> > > Hi again,
> >
> > > > When I change get_smp_cpus() to return "get_highest_cpu_online() + 1" I
> > > > see five swapper idle tasks when using "ps". The problem I now have is
> > > > that I have to provide a backtrace for the offline cpus. But the offline
> > > > CPUs do not have any stack on s390. Is there a way to tell crash that
> > > > there is no backtrace available? Probably I overlooked something...
> > >
> > > Ok, I think I got it now. In case of an offline CPU, I will use
> > > "task_struct_thread_ksp" like I do it for non active tasks.
> > >
> > > When I do that I get for the swapper tasks with the offline CPUs:
> > >
> > > PID: 0 TASK: 18d38340 CPU: 2 COMMAND: "swapper"
> > > #0 [18d3feb8] ret_from_fork at 117e12
> > >
> > > PID: 0 TASK: 18d40440 CPU: 3 COMMAND: "swapper"
> > > #0 [18d47eb8] ret_from_fork at 117e12
> >
> > I'm not why you should do anything. The cpu is offline and for all
> > practical purposes it doesn't exist, so why bother?
>
> Because you can do a "bt" on the swapper task with the offline CPU.
> Then s390x_get_stack_frame() is called where I figure out the stack
> pointer and instruction address. In that function I check if the task is
> currently running on a CPU and in that case I get the information from
> the associated s390 lowcore, where the registers are stored in case of a
> dump. If the task is not running I get the information from the thread
> struct.
>
> > The patch I have queued just uses get_highest_cpu_online()+1 and
> > does nothing else. But I only tested it on a live system, and
> > any backtrace attempt on the offlined swapper task just shows
> > (active). What happens when you do a "bt -a" with a dumpfile?
>
> It shows all swapper tasks (online and offline), but I get errors for
> the backtrace for the offline CPUs.
What kind of errors?
>
> The attached patch would solve the problem (and eliminate most of the
> probably redundant s390(x)_has_cpu() function.
I don't see what's being solved by the patch (not the s390x_get_smp_cpus
parts) -- does the "old" s390x_has_cpu() fail?
Even though the task is offline, the runqueue will still show its percpu
swapper task as the current task on that cpu.
Dave
>
> With this patch "ps" shows:
>
> PID PPID CPU TASK ST %MEM VSZ RSS COMM
> > 0 0 0 800ef0 RU 0.0 0 0 [swapper]
> > 0 0 1 18d30240 RU 0.0 0 0 [swapper]
> > 0 0 2 18d38340 RU 0.0 0 0 [swapper]
> > 0 0 3 18d40440 RU 0.0 0 0 [swapper]
> > 0 0 4 18d48540 RU 0.0 0 0 [swapper]
> 1 0 1 18d18040 IN 0.2 2244 1020 init
> ...
>
> And "bt -a" shows:
>
> PID: 0 TASK: 800ef0 CPU: 0 COMMAND: "swapper"
> LOWCORE INFO:
> -psw : 0x0706000180000000 0x0000000000115564
> -function : vtime_stop_cpu at 115564
> -prefix : 0x18d28000
> -cpu timer: 0x7fff00c1 0x00c584ef
> ...
>
> PID: 0 TASK: 18d30240 CPU: 1 COMMAND: "swapper"
> LOWCORE INFO:
> -psw : 0x0706000180000000 0x0000000000115564
> -function : vtime_stop_cpu at 115564
> ...
>
> PID: 0 TASK: 18d38340 CPU: 2 COMMAND: "swapper"
> #0 [18d3feb8] ret_from_fork at 117e12
> ...
>
> PID: 0 TASK: 18d40440 CPU: 3 COMMAND: "swapper"
> #0 [18d47eb8] ret_from_fork at 117e12
> ...
>
> PID: 0 TASK: 18d48540 CPU: 4 COMMAND: "swapper"
> LOWCORE INFO:
> -psw : 0x0706000180000000 0x0000000000115564
> -function : vtime_stop_cpu at 115564
> -prefix : 0x1416a000
>
> Michael
14 years, 9 months