On Fri, 2010-02-12 at 09:53 -0500, Dave Anderson wrote:
> 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 *);
Makes sense!
And remove this -- it doesn't exist anymore:
+void get_netdump_regs_s390x(struct bt_info *, ulong *, ulong *);
Yes, I already removed that in my local patch.
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);
Why the check for s390x? All architectures that do not define
"elf_note_add" will not be affected.
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);
ok
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") ;
ok
If you're happy with the changes above, I can do it here, make
sure
it compiles, and queue it for the next release.
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.
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