dumpfiles:
 (1) If ELF notes are not available, read them from the kernel's
     crash_notes.
 (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 <[email protected]>
Signed-off-by: Youling Tang <[email protected]>
---
v1 -> v2:
 - No change.

 mips64.c | 203 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 202 insertions(+), 1 deletion(-)

diff --git a/mips64.c b/mips64.c
index c038ea9..b5e2df6 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
@@ -799,6 +801,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, &notes_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.
  */
@@ -952,9 +1140,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
[email protected]
https://listman.redhat.com/mailman/listinfo/crash-utility

Reply via email to