-----Original Message-----
dumpfiles:
(1) If ELF notes are not available, read them from the kernel's
crash_notes.
This is reverse? i.e. If kernel's crash_notes are not available,
read them from ELF notes.
Thanks,
Kazu
(2) If an online CPUs did not save its ELF notes, then adjust
the mapping of each ELF note to its CPU accordingly.
E.g. With this patch:
crash> bt
PID: 4768 TASK: 9800000243bcf200 CPU: 3 COMMAND: "bash"
#0 [980000024291f930] __crash_kexec at ffffffff802fff84
#1 [980000024291faa0] panic at ffffffff80248cac
#2 [980000024291fb40] die at ffffffff8021b338
#3 [980000024291fb70] do_page_fault at ffffffff802315e0
#4 [980000024291fbd0] tlb_do_page_fault_1 at ffffffff80239388
#5 [980000024291fd00] sysrq_handle_crash at ffffffff8085d308
#6 [980000024291fd10] __handle_sysrq at ffffffff8085d9e0
#7 [980000024291fd60] write_sysrq_trigger at ffffffff8085e020
#8 [980000024291fd80] proc_reg_write at ffffffff804762f0
#9 [980000024291fda0] __vfs_write at ffffffff803f3138
Signed-off-by: Huacai Chen <chenhuacai(a)loongson.cn>
Signed-off-by: Youling Tang <tangyouling(a)loongson.cn>
---
mips64.c | 203 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 202 insertions(+), 1 deletion(-)
diff --git a/mips64.c b/mips64.c
index 57a7f41..d949af4 100644
--- a/mips64.c
+++ b/mips64.c
@@ -42,7 +42,9 @@ static void mips64_get_stack_frame(struct bt_info *bt, ulong *pcp,
ulong *spp);
static int mips64_get_dumpfile_stack_frame(struct bt_info *bt,
ulong *nip, ulong *ksp);
static int mips64_get_frame(struct bt_info *bt, ulong *pcp, ulong *spp);
-
+static int mips64_init_active_task_regs(void);
+static int mips64_get_crash_notes(void);
+static int mips64_get_elf_notes(void);
/*
* 3 Levels paging PAGE_SIZE=16KB
@@ -806,6 +808,192 @@ mips64_get_frame(struct bt_info *bt, ulong *pcp, ulong *spp)
return TRUE;
}
+static int
+mips64_init_active_task_regs(void)
+{
+ int retval;
+
+ retval = mips64_get_crash_notes();
+ if (retval == TRUE)
+ return retval;
+
+ return mips64_get_elf_notes();
+}
+
+/*
+ * Retrieve task registers for the time of the crash.
+ */
+static int
+mips64_get_crash_notes(void)
+{
+ struct machine_specific *ms = machdep->machspec;
+ ulong crash_notes;
+ Elf64_Nhdr *note;
+ ulong offset;
+ char *buf, *p;
+ ulong *notes_ptrs;
+ ulong i;
+
+ /*
+ * crash_notes contains per cpu memory for storing cpu states
+ * in case of system crash.
+ */
+ if (!symbol_exists("crash_notes"))
+ return FALSE;
+
+ crash_notes = symbol_value("crash_notes");
+
+ notes_ptrs = (ulong *)GETBUF(kt->cpus*sizeof(notes_ptrs[0]));
+
+ /*
+ * Read crash_notes for the first CPU. crash_notes are in standard ELF
+ * note format.
+ */
+ if (!readmem(crash_notes, KVADDR, ¬es_ptrs[kt->cpus-1],
+ sizeof(notes_ptrs[kt->cpus-1]), "crash_notes",
+ RETURN_ON_ERROR)) {
+ error(WARNING, "cannot read crash_notes\n");
+ FREEBUF(notes_ptrs);
+ return FALSE;
+ }
+
+ if (symbol_exists("__per_cpu_offset")) {
+
+ /*
+ * Add __per_cpu_offset for each cpu to form the pointer to the notes
+ */
+ for (i = 0; i < kt->cpus; i++)
+ notes_ptrs[i] = notes_ptrs[kt->cpus-1] + kt->__per_cpu_offset[i];
+ }
+
+ buf = GETBUF(SIZE(note_buf));
+
+ if (!(panic_task_regs = calloc((size_t)kt->cpus, sizeof(*panic_task_regs))))
+ error(FATAL, "cannot calloc panic_task_regs space\n");
+
+ for (i = 0; i < kt->cpus; i++) {
+
+ if (!readmem(notes_ptrs[i], KVADDR, buf, SIZE(note_buf), "note_buf_t",
+ RETURN_ON_ERROR)) {
+ error(WARNING,
+ "cannot find NT_PRSTATUS note for cpu: %d\n", i);
+ goto fail;
+ }
+
+ /*
+ * Do some sanity checks for this note before reading registers from it.
+ */
+ note = (Elf64_Nhdr *)buf;
+ p = buf + sizeof(Elf64_Nhdr);
+
+ /*
+ * dumpfiles created with qemu won't have crash_notes, but there will
+ * be elf notes; dumpfiles created by kdump do not create notes for
+ * offline cpus.
+ */
+ if (note->n_namesz == 0 && (DISKDUMP_DUMPFILE() || KDUMP_DUMPFILE())) {
+ if (DISKDUMP_DUMPFILE())
+ note = diskdump_get_prstatus_percpu(i);
+ else if (KDUMP_DUMPFILE())
+ note = netdump_get_prstatus_percpu(i);
+ if (note) {
+ /*
+ * SIZE(note_buf) accounts for a "final note", which is a
+ * trailing empty elf note header.
+ */
+ long notesz = SIZE(note_buf) - sizeof(Elf64_Nhdr);
+
+ if (sizeof(Elf64_Nhdr) + roundup(note->n_namesz, 4) +
+ note->n_descsz == notesz)
+ BCOPY((char *)note, buf, notesz);
+ } else {
+ error(WARNING,
+ "cannot find NT_PRSTATUS note for cpu: %d\n", i);
+ continue;
+ }
+ }
+
+ /*
+ * Check the sanity of NT_PRSTATUS note only for each online cpu.
+ */
+ if (note->n_type != NT_PRSTATUS) {
+ error(WARNING, "invalid NT_PRSTATUS note (n_type != NT_PRSTATUS)\n");
+ goto fail;
+ }
+ if (!STRNEQ(p, "CORE")) {
+ error(WARNING, "invalid NT_PRSTATUS note (name != \"CORE\"\n");
+ goto fail;
+ }
+
+ /*
+ * Find correct location of note data. This contains elf_prstatus
+ * structure which has registers etc. for the crashed task.
+ */
+ offset = sizeof(Elf64_Nhdr);
+ offset = roundup(offset + note->n_namesz, 4);
+ p = buf + offset; /* start of elf_prstatus */
+
+ BCOPY(p + OFFSET(elf_prstatus_pr_reg), &panic_task_regs[i],
+ sizeof(panic_task_regs[i]));
+ }
+
+ /*
+ * And finally we have the registers for the crashed task. This is
+ * used later on when dumping backtrace.
+ */
+ ms->crash_task_regs = panic_task_regs;
+
+ FREEBUF(buf);
+ FREEBUF(notes_ptrs);
+ return TRUE;
+
+fail:
+ FREEBUF(buf);
+ FREEBUF(notes_ptrs);
+ free(panic_task_regs);
+ return FALSE;
+}
+
+static int
+mips64_get_elf_notes(void)
+{
+ struct machine_specific *ms = machdep->machspec;
+ int i;
+
+ if (!DISKDUMP_DUMPFILE() && !KDUMP_DUMPFILE())
+ return FALSE;
+
+ panic_task_regs = calloc(kt->cpus, sizeof(*panic_task_regs));
+ if (!panic_task_regs)
+ error(FATAL, "cannot calloc panic_task_regs space\n");
+
+ for (i = 0; i < kt->cpus; i++) {
+ Elf64_Nhdr *note = NULL;
+ size_t len;
+
+ if (DISKDUMP_DUMPFILE())
+ note = diskdump_get_prstatus_percpu(i);
+ else if (KDUMP_DUMPFILE())
+ note = netdump_get_prstatus_percpu(i);
+
+ if (!note) {
+ error(WARNING,
+ "cannot find NT_PRSTATUS note for cpu: %d\n", i);
+ continue;
+ }
+
+ len = sizeof(Elf64_Nhdr);
+ len = roundup(len + note->n_namesz, 4);
+
+ BCOPY((char *)note + len + OFFSET(elf_prstatus_pr_reg),
+ &panic_task_regs[i], sizeof(panic_task_regs[i]));
+ }
+
+ ms->crash_task_regs = panic_task_regs;
+
+ return TRUE;
+}
+
/*
* Accept or reject a symbol from the kernel namelist.
*/
@@ -959,9 +1147,22 @@ mips64_init(int when)
mips64_stackframe_init();
if (!machdep->hz)
machdep->hz = 250;
+ MEMBER_OFFSET_INIT(elf_prstatus_pr_reg, "elf_prstatus",
+ "pr_reg");
+ STRUCT_SIZE_INIT(note_buf, "note_buf_t");
break;
case POST_VM:
+ /*
+ * crash_notes contains machine specific information about the
+ * crash. In particular, it contains CPU registers at the time
+ * of the crash. We need this information to extract correct
+ * backtraces from the panic task.
+ */
+ if (!ACTIVE() && !mips64_init_active_task_regs())
+ error(WARNING,
+ "cannot retrieve registers for active task%s\n\n",
+ kt->cpus > 1 ? "s" : "");
break;
}
}
--
2.1.0