Hi Dave,
This patch is an attempt to get the ball rolling on SMP support for ARM.
Regards,
Per
Aside from a few minor issues when compiling arm.c with "make warn",
this patch looks fine to me, and runs OK on a sample UP vmlinux/vmcore
pair that Mika made available for me.
For a sanity check, though, can I get an ACK from the ARM maintainers
(Mika, Jan, and/or Thomas) prior to merging it?
Also, it would be helpful to me if you could make an ARM SMP vmlinux/vmcore
pair for me to have around as a reference. If you can do it, please make
the dumpfile as small in memory-size as possible, and put it somewhere that
I can download from. (you can send me the details off-list).
Thanks,
Dave
diff --git a/arm.c b/arm.c
index 06b2f1c..bf346df 100644
--- a/arm.c
+++ b/arm.c
@@ -73,7 +73,7 @@ struct arm_cpu_context_save {
/*
* Holds registers during the crash.
*/
-static struct arm_pt_regs panic_task_regs;
+static struct arm_pt_regs *panic_task_regs;
#define PGDIR_SIZE() (4 * PAGESIZE())
#define PGDIR_OFFSET(X) (((ulong)(X)) & (PGDIR_SIZE() - 1))
@@ -484,71 +484,103 @@ arm_get_crash_notes(void)
Elf32_Nhdr *note;
ulong ptr, offset;
char *buf, *p;
+ ulong *notes_ptrs;
+ ulong per_cpu_offsets_addr;
+ ulong *per_cpu_offsets;
+ ulong i;
if (!symbol_exists("crash_notes"))
return FALSE;
crash_notes = symbol_value("crash_notes");
- if (kt->cpus > 1)
- error(WARNING, "only one CPU is currently supported\n");
+ notes_ptrs = 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, &ptr, sizeof(ptr), "crash_notes",
+ 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");
+ error(WARNING, "cannot read crash_notes\n");
+ return FALSE;
+ }
+
+
+ if (symbol_exists("__per_cpu_offset")) {
+
+ /* Get the __per_cpu_offset array */
+ per_cpu_offsets_addr = symbol_value("__per_cpu_offset");
+
+ per_cpu_offsets = GETBUF(kt->cpus*sizeof(*per_cpu_offsets));
+
+ if (!readmem(per_cpu_offsets_addr, KVADDR, per_cpu_offsets,
kt->cpus*sizeof(*per_cpu_offsets), "per_cpu_offsets",
+ RETURN_ON_ERROR)) {
+ error(WARNING, "cannot read per_cpu_offsets\n");
return FALSE;
+ }
+
+ /* 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] + per_cpu_offsets[i];
+ }
+ FREEBUF(per_cpu_offsets);
}
buf = GETBUF(SIZE(note_buf));
+ panic_task_regs = GETBUF(kt->cpus*sizeof(*panic_task_regs));
+
+ for (i=0;i<kt->cpus;i++) {
- if (!readmem(ptr, KVADDR, buf, SIZE(note_buf), "note_buf_t",
- RETURN_ON_ERROR)) {
+ if (!readmem(notes_ptrs[i], KVADDR, buf, SIZE(note_buf),
"note_buf_t",
+ RETURN_ON_ERROR)) {
error(WARNING, "failed to read note_buf_t\n");
goto fail;
- }
+ }
- /*
- * Do some sanity checks for this note before reading registers from
it.
- */
- note = (Elf32_Nhdr *)buf;
- p = buf + sizeof(Elf32_Nhdr);
+ /*
+ * Do some sanity checks for this note before reading registers
from it.
+ */
+ note = (Elf32_Nhdr *)buf;
+ p = buf + sizeof(Elf32_Nhdr);
- if (note->n_type != NT_PRSTATUS) {
+ if (note->n_type != NT_PRSTATUS) {
error(WARNING, "invalid note (n_type != NT_PRSTATUS)\n");
goto fail;
- }
- if (p[0] != 'C' || p[1] != 'O' || p[2] != 'R' || p[3] !=
'E') {
+ }
+ if (p[0] != 'C' || p[1] != 'O' || p[2] != 'R' || p[3] !=
'E') {
error(WARNING, "invalid 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(Elf32_Nhdr);
- offset = roundup(offset + note->n_namesz, 4);
- p = buf + offset; /* start of elf_prstatus */
+ /*
+ * Find correct location of note data. This contains
elf_prstatus
+ * structure which has registers etc. for the crashed task.
+ */
+ offset = sizeof(Elf32_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,
- sizeof(panic_task_regs));
+ BCOPY(p + OFFSET(elf_prstatus_pr_reg), &panic_task_regs[i],
+ sizeof(panic_task_regs[i]));
+
+ }
/*
* And finally we have pid and registers for the crashed task. This
is
* used later on when dumping backtrace.
*/
ms->crash_task_pid = *(ulong *)(p + OFFSET(elf_prstatus_pr_pid));
- ms->crash_task_regs = &panic_task_regs;
+ ms->crash_task_regs = panic_task_regs;
FREEBUF(buf);
+ FREEBUF(notes_ptrs);
return TRUE;
fail:
FREEBUF(buf);
+ FREEBUF(notes_ptrs);
+ FREEBUF(panic_task_regs);
return FALSE;
}
@@ -996,20 +1028,20 @@ arm_get_dumpfile_stack_frame(struct bt_info
*bt, ulong *nip, ulong *ksp)
if (!ms->crash_task_regs)
return FALSE;
- if (tt->panic_task != bt->task || bt->tc->pid !=
ms->crash_task_pid)
- return FALSE;
-
+ if (!is_task_active(bt->task))
+ return FALSE;
+
/*
* We got registers for panic task from crash_notes. Just return
them.
*/
- *nip = ms->crash_task_regs->ARM_pc;
- *ksp = ms->crash_task_regs->ARM_sp;
+ *nip = ms->crash_task_regs[bt->tc->processor].ARM_pc;
+ *ksp = ms->crash_task_regs[bt->tc->processor].ARM_sp;
/*
* Also store pointer to all registers in case unwinding code needs
* to access LR.
*/
- bt->machdep = ms->crash_task_regs;
+ bt->machdep = &(ms->crash_task_regs[bt->tc->processor]);
return TRUE;
}
diff --git a/defs.h b/defs.h
index d431d6e..8a2291a 100755
--- a/defs.h
+++ b/defs.h
@@ -85,7 +85,7 @@
#define NR_CPUS (64)
#endif
#ifdef ARM
-#define NR_CPUS (1)
+#define NR_CPUS (4)
#endif
#define BUFSIZE (1500)
--
Crash-utility mailing list
Crash-utility(a)redhat.com
https://www.redhat.com/mailman/listinfo/crash-utility