On 03/10/2021 09:19 AM, HAGIO KAZUHITO(萩尾 一仁) wrote:
-----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.
Yes, If crash_notes is available, crash_notes will be
used first, otherwise
it will be read from ELF notes.
Thanks,
Youling
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