[Crash-utility] [PATCH] Add ELF core dump support for s390x
Dave Anderson
anderson at redhat.com
Fri Feb 12 16:03:37 UTC 2010
Sorry -- our paths are crossing -- my proposed patch went out
before I received this one.
Anyway...
> Why the check for s390x? All architectures that do not define
> "elf_note_add" will not be affected.
But if they *do* define it in the future, they might *not* want to call it
from here. I wanted to make the new function as flexibly-usable as possible.
> I attached a new patch (without the s390x check in netdump.c). I also
> moved all the definitions from defs.h into s390x.c. No need to have them
> in the header file.
Good -- I had moved the "#include <elf.h>" down into the "#ifdef S390X"
section, but I like the wholesale movement too. Doing it that way will
make this patch absolutely incapable of changing any other architecture's
behavior.
The only other patch mis-matches would be for the compiler warnings...
Thanks,
Dave
>
> Thanks!
>
> Michael
> ---
>
> 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.
> ---
> defs.h | 1
> netdump.c | 11 ++
> s390x.c | 230
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
> 3 files changed, 235 insertions(+), 7 deletions(-)
>
> --- a/defs.h
> +++ b/defs.h
> @@ -792,6 +792,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, void *);
> };
>
> /*
> --- 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
> @@ -16,6 +16,7 @@
> * GNU General Public License for more details.
> */
> #ifdef S390X
> +#include <elf.h>
> #include "defs.h"
>
> #define S390X_WORD_SIZE 8
> @@ -41,6 +42,86 @@
> #define LOWCORE_SIZE 8192
>
> /*
> + * 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;
> +};
> +
> +/*
> * declarations of static functions
> */
> static void s390x_print_lowcore(char*, struct bt_info*,int);
> @@ -65,6 +146,8 @@ 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 struct s390x_cpu *s390x_cpu_vec;
> +static int s390x_cpu_cnt;
>
> /*
> * Initialize member offsets
> @@ -79,6 +162,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)
> + 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, void *note_ptr)
> +{
> + Elf64_Nhdr *note = note_ptr;
> + struct s390x_cpu *cpu;
> + void *desc;
> +
> + desc = get_elf_note_desc(note);
> + 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 +281,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 +398,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_note_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 +767,38 @@ 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 +846,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 +1127,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 +1358,4 @@ try_closest:
> }
> }
> }
> -
> #endif
More information about the Crash-utility
mailing list