[Crash-utility] [PATCH] Add ELF core dump support for s390x

Dave Anderson anderson at redhat.com
Fri Feb 12 14:53:25 UTC 2010


----- "Michael Holzheu" <holzheu at 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




More information about the Crash-utility mailing list