-----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@xxxxxxxxxxx> > Signed-off-by: Youling Tang <tangyouling@xxxxxxxxxxx> > --- > 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 -- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://listman.redhat.com/mailman/listinfo/crash-utility