|
|
821d228 |
From 87f031ada9dfac6003658d2d89ede2886d92f83e Mon Sep 17 00:00:00 2001
|
|
|
821d228 |
From: Ming Wang <wangming01@loongson.cn>
|
|
|
821d228 |
Date: Thu, 28 Dec 2023 19:46:29 +0800
|
|
|
821d228 |
Subject: [PATCH 05/12] LoongArch64: Add 'bt' command support
|
|
|
821d228 |
|
|
|
821d228 |
- Add basic support for the 'bt' command.
|
|
|
821d228 |
- LooongArch64: Add 'bt -f' command support
|
|
|
821d228 |
- LoongArch64: Add 'bt -l' command support
|
|
|
821d228 |
|
|
|
821d228 |
E.g. With this patch:
|
|
|
821d228 |
crash> bt
|
|
|
821d228 |
PID: 1832 TASK: 900000009a552100 CPU: 11 COMMAND: "bash"
|
|
|
821d228 |
#0 [900000009beffb60] __cpu_possible_mask at 90000000014168f0
|
|
|
821d228 |
#1 [900000009beffb60] __crash_kexec at 90000000002e7660
|
|
|
821d228 |
#2 [900000009beffcd0] panic at 9000000000f0ec28
|
|
|
821d228 |
#3 [900000009beffd60] sysrq_handle_crash at 9000000000a2c188
|
|
|
821d228 |
#4 [900000009beffd70] __handle_sysrq at 9000000000a2c85c
|
|
|
821d228 |
#5 [900000009beffdc0] write_sysrq_trigger at 9000000000a2ce10
|
|
|
821d228 |
#6 [900000009beffde0] proc_reg_write at 90000000004ce454
|
|
|
821d228 |
#7 [900000009beffe00] vfs_write at 900000000043e838
|
|
|
821d228 |
#8 [900000009beffe40] ksys_write at 900000000043eb58
|
|
|
821d228 |
#9 [900000009beffe80] do_syscall at 9000000000f2da54
|
|
|
821d228 |
#10 [900000009beffea0] handle_syscall at 9000000000221440
|
|
|
821d228 |
crash>
|
|
|
821d228 |
...
|
|
|
821d228 |
|
|
|
821d228 |
Co-developed-by: Youling Tang <tangyouling@loongson.cn>
|
|
|
821d228 |
Signed-off-by: Youling Tang <tangyouling@loongson.cn>
|
|
|
821d228 |
Signed-off-by: Ming Wang <wangming01@loongson.cn>
|
|
|
821d228 |
Signed-off-by: Lianbo Jiang <lijiang@redhat.com>
|
|
|
821d228 |
---
|
|
|
821d228 |
defs.h | 2 +
|
|
|
821d228 |
loongarch64.c | 668 +++++++++++++++++++++++++++++++++++++++++++++++++-
|
|
|
821d228 |
symbols.c | 4 +
|
|
|
821d228 |
3 files changed, 673 insertions(+), 1 deletion(-)
|
|
|
821d228 |
|
|
|
821d228 |
diff --git a/defs.h b/defs.h
|
|
|
821d228 |
index fa25ecca272b..d1edce9893d1 100644
|
|
|
821d228 |
--- a/defs.h
|
|
|
821d228 |
+++ b/defs.h
|
|
|
821d228 |
@@ -2234,6 +2234,8 @@ struct offset_table { /* stash of commonly-used offsets */
|
|
|
821d228 |
long irq_data_irq;
|
|
|
821d228 |
long zspage_huge;
|
|
|
821d228 |
long zram_comp_algs;
|
|
|
821d228 |
+ long task_struct_thread_reg01;
|
|
|
821d228 |
+ long task_struct_thread_reg03;
|
|
|
821d228 |
};
|
|
|
821d228 |
|
|
|
821d228 |
struct size_table { /* stash of commonly-used sizes */
|
|
|
821d228 |
diff --git a/loongarch64.c b/loongarch64.c
|
|
|
821d228 |
index 20c889288d0c..fd056953083a 100644
|
|
|
821d228 |
--- a/loongarch64.c
|
|
|
821d228 |
+++ b/loongarch64.c
|
|
|
821d228 |
@@ -51,6 +51,28 @@ static int loongarch64_translate_pte(ulong pte, void *physaddr,
|
|
|
821d228 |
|
|
|
821d228 |
static void loongarch64_cmd_mach(void);
|
|
|
821d228 |
static void loongarch64_display_machine_stats(void);
|
|
|
821d228 |
+
|
|
|
821d228 |
+static void loongarch64_back_trace_cmd(struct bt_info *bt);
|
|
|
821d228 |
+static void loongarch64_analyze_function(ulong start, ulong offset,
|
|
|
821d228 |
+ struct loongarch64_unwind_frame *current,
|
|
|
821d228 |
+ struct loongarch64_unwind_frame *previous);
|
|
|
821d228 |
+static void loongarch64_dump_backtrace_entry(struct bt_info *bt,
|
|
|
821d228 |
+ struct syment *sym, struct loongarch64_unwind_frame *current,
|
|
|
821d228 |
+ struct loongarch64_unwind_frame *previous, int level);
|
|
|
821d228 |
+static void loongarch64_dump_exception_stack(struct bt_info *bt, char *pt_regs);
|
|
|
821d228 |
+static int loongarch64_is_exception_entry(struct syment *sym);
|
|
|
821d228 |
+static void loongarch64_display_full_frame(struct bt_info *bt,
|
|
|
821d228 |
+ struct loongarch64_unwind_frame *current,
|
|
|
821d228 |
+ struct loongarch64_unwind_frame *previous);
|
|
|
821d228 |
+static void loongarch64_stackframe_init(void);
|
|
|
821d228 |
+static void loongarch64_get_stack_frame(struct bt_info *bt, ulong *pcp, ulong *spp);
|
|
|
821d228 |
+static int loongarch64_get_dumpfile_stack_frame(struct bt_info *bt,
|
|
|
821d228 |
+ ulong *nip, ulong *ksp);
|
|
|
821d228 |
+static int loongarch64_get_frame(struct bt_info *bt, ulong *pcp, ulong *spp);
|
|
|
821d228 |
+static int loongarch64_init_active_task_regs(void);
|
|
|
821d228 |
+static int loongarch64_get_crash_notes(void);
|
|
|
821d228 |
+static int loongarch64_get_elf_notes(void);
|
|
|
821d228 |
+
|
|
|
821d228 |
/*
|
|
|
821d228 |
* 3 Levels paging PAGE_SIZE=16KB
|
|
|
821d228 |
* PGD | PMD | PTE | OFFSET |
|
|
|
821d228 |
@@ -82,8 +104,25 @@ typedef struct { ulong pte; } pte_t;
|
|
|
821d228 |
|
|
|
821d228 |
#define LOONGARCH64_CPU_RIXI (1UL << 23) /* CPU has TLB Read/eXec Inhibit */
|
|
|
821d228 |
|
|
|
821d228 |
+#define LOONGARCH64_EF_R0 0
|
|
|
821d228 |
+#define LOONGARCH64_EF_RA 1
|
|
|
821d228 |
+#define LOONGARCH64_EF_SP 3
|
|
|
821d228 |
+#define LOONGARCH64_EF_FP 22
|
|
|
821d228 |
+#define LOONGARCH64_EF_CSR_EPC 32
|
|
|
821d228 |
+#define LOONGARCH64_EF_CSR_BADVADDR 33
|
|
|
821d228 |
+#define LOONGARCH64_EF_CSR_CRMD 34
|
|
|
821d228 |
+#define LOONGARCH64_EF_CSR_PRMD 35
|
|
|
821d228 |
+#define LOONGARCH64_EF_CSR_EUEN 36
|
|
|
821d228 |
+#define LOONGARCH64_EF_CSR_ECFG 37
|
|
|
821d228 |
+#define LOONGARCH64_EF_CSR_ESTAT 38
|
|
|
821d228 |
+
|
|
|
821d228 |
static struct machine_specific loongarch64_machine_specific = { 0 };
|
|
|
821d228 |
|
|
|
821d228 |
+/*
|
|
|
821d228 |
+ * Holds registers during the crash.
|
|
|
821d228 |
+ */
|
|
|
821d228 |
+static struct loongarch64_pt_regs *panic_task_regs;
|
|
|
821d228 |
+
|
|
|
821d228 |
/*
|
|
|
821d228 |
* Check and print the flags on the page
|
|
|
821d228 |
*/
|
|
|
821d228 |
@@ -389,6 +428,621 @@ loongarch64_display_machine_stats(void)
|
|
|
821d228 |
|
|
|
821d228 |
}
|
|
|
821d228 |
|
|
|
821d228 |
+/*
|
|
|
821d228 |
+ * Unroll a kernel stack.
|
|
|
821d228 |
+ */
|
|
|
821d228 |
+static void
|
|
|
821d228 |
+loongarch64_back_trace_cmd(struct bt_info *bt)
|
|
|
821d228 |
+{
|
|
|
821d228 |
+ struct loongarch64_unwind_frame current, previous;
|
|
|
821d228 |
+ struct loongarch64_pt_regs *regs;
|
|
|
821d228 |
+ char pt_regs[SIZE(pt_regs)];
|
|
|
821d228 |
+ int level = 0;
|
|
|
821d228 |
+ int invalid_ok = 1;
|
|
|
821d228 |
+
|
|
|
821d228 |
+ if (bt->flags & BT_REGS_NOT_FOUND)
|
|
|
821d228 |
+ return;
|
|
|
821d228 |
+
|
|
|
821d228 |
+ previous.sp = previous.pc = previous.ra = 0;
|
|
|
821d228 |
+
|
|
|
821d228 |
+ current.pc = bt->instptr;
|
|
|
821d228 |
+ current.sp = bt->stkptr;
|
|
|
821d228 |
+ current.ra = 0;
|
|
|
821d228 |
+
|
|
|
821d228 |
+ if (!INSTACK(current.sp, bt))
|
|
|
821d228 |
+ return;
|
|
|
821d228 |
+
|
|
|
821d228 |
+ if (bt->machdep) {
|
|
|
821d228 |
+ regs = (struct loongarch64_pt_regs *)bt->machdep;
|
|
|
821d228 |
+ previous.pc = current.ra = regs->regs[LOONGARCH64_EF_RA];
|
|
|
821d228 |
+ }
|
|
|
821d228 |
+
|
|
|
821d228 |
+ while (current.sp <= bt->stacktop - 32 - SIZE(pt_regs)) {
|
|
|
821d228 |
+ struct syment *symbol = NULL;
|
|
|
821d228 |
+ ulong offset;
|
|
|
821d228 |
+
|
|
|
821d228 |
+ if (CRASHDEBUG(8))
|
|
|
821d228 |
+ fprintf(fp, "level %d pc %#lx ra %#lx sp %lx\n",
|
|
|
821d228 |
+ level, current.pc, current.ra, current.sp);
|
|
|
821d228 |
+
|
|
|
821d228 |
+ if (!IS_KVADDR(current.pc) && !invalid_ok)
|
|
|
821d228 |
+ return;
|
|
|
821d228 |
+
|
|
|
821d228 |
+ symbol = value_search(current.pc, &offset);
|
|
|
821d228 |
+ if (!symbol && !invalid_ok) {
|
|
|
821d228 |
+ error(FATAL, "PC is unknown symbol (%lx)", current.pc);
|
|
|
821d228 |
+ return;
|
|
|
821d228 |
+ }
|
|
|
821d228 |
+ invalid_ok = 0;
|
|
|
821d228 |
+
|
|
|
821d228 |
+ /*
|
|
|
821d228 |
+ * If we get an address which points to the start of a
|
|
|
821d228 |
+ * function, then it could one of the following:
|
|
|
821d228 |
+ *
|
|
|
821d228 |
+ * - we are dealing with a noreturn function. The last call
|
|
|
821d228 |
+ * from a noreturn function has an ra which points to the
|
|
|
821d228 |
+ * start of the function after it. This is common in the
|
|
|
821d228 |
+ * oops callchain because of die() which is annotated as
|
|
|
821d228 |
+ * noreturn.
|
|
|
821d228 |
+ *
|
|
|
821d228 |
+ * - we have taken an exception at the start of this function.
|
|
|
821d228 |
+ * In this case we already have the RA in current.ra.
|
|
|
821d228 |
+ *
|
|
|
821d228 |
+ * - we are in one of these routines which appear with zero
|
|
|
821d228 |
+ * offset in manually-constructed stack frames:
|
|
|
821d228 |
+ *
|
|
|
821d228 |
+ * * ret_from_exception
|
|
|
821d228 |
+ * * ret_from_irq
|
|
|
821d228 |
+ * * ret_from_fork
|
|
|
821d228 |
+ * * ret_from_kernel_thread
|
|
|
821d228 |
+ */
|
|
|
821d228 |
+ if (symbol && !STRNEQ(symbol->name, "ret_from") && !offset &&
|
|
|
821d228 |
+ !current.ra && current.sp < bt->stacktop - 32 - SIZE(pt_regs)) {
|
|
|
821d228 |
+ if (CRASHDEBUG(8))
|
|
|
821d228 |
+ fprintf(fp, "zero offset at %s, try previous symbol\n",
|
|
|
821d228 |
+ symbol->name);
|
|
|
821d228 |
+
|
|
|
821d228 |
+ symbol = value_search(current.pc - 4, &offset);
|
|
|
821d228 |
+ if (!symbol) {
|
|
|
821d228 |
+ error(FATAL, "PC is unknown symbol (%lx)", current.pc);
|
|
|
821d228 |
+ return;
|
|
|
821d228 |
+ }
|
|
|
821d228 |
+ }
|
|
|
821d228 |
+
|
|
|
821d228 |
+ if (symbol && loongarch64_is_exception_entry(symbol)) {
|
|
|
821d228 |
+
|
|
|
821d228 |
+ GET_STACK_DATA(current.sp, pt_regs, sizeof(pt_regs));
|
|
|
821d228 |
+ regs = (struct loongarch64_pt_regs *) (pt_regs + OFFSET(pt_regs_regs));
|
|
|
821d228 |
+ previous.ra = regs->regs[LOONGARCH64_EF_RA];
|
|
|
821d228 |
+ previous.sp = regs->regs[LOONGARCH64_EF_SP];
|
|
|
821d228 |
+ current.ra = regs->csr_epc;
|
|
|
821d228 |
+
|
|
|
821d228 |
+ if (CRASHDEBUG(8))
|
|
|
821d228 |
+ fprintf(fp, "exception pc %#lx ra %#lx sp %lx\n",
|
|
|
821d228 |
+ previous.pc, previous.ra, previous.sp);
|
|
|
821d228 |
+
|
|
|
821d228 |
+ /* The PC causing the exception may have been invalid */
|
|
|
821d228 |
+ invalid_ok = 1;
|
|
|
821d228 |
+ } else if (symbol) {
|
|
|
821d228 |
+ loongarch64_analyze_function(symbol->value, offset, ¤t, &previous);
|
|
|
821d228 |
+ } else {
|
|
|
821d228 |
+ /*
|
|
|
821d228 |
+ * The current PC is invalid. Assume that the code
|
|
|
821d228 |
+ * jumped through a invalid pointer and that the SP has
|
|
|
821d228 |
+ * not been adjusted.
|
|
|
821d228 |
+ */
|
|
|
821d228 |
+ previous.sp = current.sp;
|
|
|
821d228 |
+ }
|
|
|
821d228 |
+
|
|
|
821d228 |
+ if (symbol)
|
|
|
821d228 |
+ loongarch64_dump_backtrace_entry(bt, symbol, ¤t, &previous, level++);
|
|
|
821d228 |
+
|
|
|
821d228 |
+ current.pc = current.ra;
|
|
|
821d228 |
+ current.sp = previous.sp;
|
|
|
821d228 |
+ current.ra = previous.ra;
|
|
|
821d228 |
+
|
|
|
821d228 |
+ if (CRASHDEBUG(8))
|
|
|
821d228 |
+ fprintf(fp, "next %d pc %#lx ra %#lx sp %lx\n",
|
|
|
821d228 |
+ level, current.pc, current.ra, current.sp);
|
|
|
821d228 |
+
|
|
|
821d228 |
+ previous.sp = previous.pc = previous.ra = 0;
|
|
|
821d228 |
+ }
|
|
|
821d228 |
+}
|
|
|
821d228 |
+
|
|
|
821d228 |
+static void
|
|
|
821d228 |
+loongarch64_analyze_function(ulong start, ulong offset,
|
|
|
821d228 |
+ struct loongarch64_unwind_frame *current,
|
|
|
821d228 |
+ struct loongarch64_unwind_frame *previous)
|
|
|
821d228 |
+{
|
|
|
821d228 |
+ ulong i;
|
|
|
821d228 |
+ ulong rapos = 0;
|
|
|
821d228 |
+ ulong spadjust = 0;
|
|
|
821d228 |
+ uint32_t *funcbuf, *ip;
|
|
|
821d228 |
+
|
|
|
821d228 |
+ if (CRASHDEBUG(8))
|
|
|
821d228 |
+ fprintf(fp, "%s: start %#lx offset %#lx\n",
|
|
|
821d228 |
+ __func__, start, offset);
|
|
|
821d228 |
+
|
|
|
821d228 |
+ if (!offset) {
|
|
|
821d228 |
+ previous->sp = current->sp;
|
|
|
821d228 |
+ return;
|
|
|
821d228 |
+ }
|
|
|
821d228 |
+
|
|
|
821d228 |
+ ip = funcbuf = (uint32_t *)GETBUF(offset);
|
|
|
821d228 |
+ if (!readmem(start, KVADDR, funcbuf, offset,
|
|
|
821d228 |
+ "loongarch64_analyze_function", RETURN_ON_ERROR)) {
|
|
|
821d228 |
+ FREEBUF(funcbuf);
|
|
|
821d228 |
+ error(WARNING, "Cannot read function at %16lx\n", start);
|
|
|
821d228 |
+ return;
|
|
|
821d228 |
+ }
|
|
|
821d228 |
+
|
|
|
821d228 |
+ for (i = 0; i < offset; i += 4) {
|
|
|
821d228 |
+ ulong insn = *ip & 0xffffffff;
|
|
|
821d228 |
+ ulong si12 = (insn >> 10) & 0xfff; /* bit[10:21] */
|
|
|
821d228 |
+
|
|
|
821d228 |
+ if (CRASHDEBUG(8))
|
|
|
821d228 |
+ fprintf(fp, "insn @ %#lx = %#lx\n", start + i, insn);
|
|
|
821d228 |
+
|
|
|
821d228 |
+ if ((insn & 0xffc003ff) == 0x02800063 || /* addi.w sp,sp,si12 */
|
|
|
821d228 |
+ (insn & 0xffc003ff) == 0x02c00063) { /* addi.d sp,sp,si12 */
|
|
|
821d228 |
+ if (!(si12 & 0x800)) /* si12 < 0 */
|
|
|
821d228 |
+ break;
|
|
|
821d228 |
+ spadjust += 0x1000 - si12;
|
|
|
821d228 |
+ if (CRASHDEBUG(8))
|
|
|
821d228 |
+ fprintf(fp, "si12 =%lu ,spadjust = %lu\n", si12, spadjust);
|
|
|
821d228 |
+ } else if ((insn & 0xffc003ff) == 0x29800061 || /* st.w ra,sp,si12 */
|
|
|
821d228 |
+ (insn & 0xffc003ff) == 0x29c00061) { /* st.d ra,sp,si12 */
|
|
|
821d228 |
+ rapos = current->sp + si12;
|
|
|
821d228 |
+ if (CRASHDEBUG(8))
|
|
|
821d228 |
+ fprintf(fp, "rapos %lx\n", rapos);
|
|
|
821d228 |
+ break;
|
|
|
821d228 |
+ }
|
|
|
821d228 |
+
|
|
|
821d228 |
+ ip++;
|
|
|
821d228 |
+ }
|
|
|
821d228 |
+
|
|
|
821d228 |
+ FREEBUF(funcbuf);
|
|
|
821d228 |
+
|
|
|
821d228 |
+ previous->sp = current->sp + spadjust;
|
|
|
821d228 |
+
|
|
|
821d228 |
+ if (rapos && !readmem(rapos, KVADDR, ¤t->ra,
|
|
|
821d228 |
+ sizeof(current->ra), "RA from stack",
|
|
|
821d228 |
+ RETURN_ON_ERROR)) {
|
|
|
821d228 |
+ error(FATAL, "Cannot read RA from stack %lx", rapos);
|
|
|
821d228 |
+ return;
|
|
|
821d228 |
+ }
|
|
|
821d228 |
+}
|
|
|
821d228 |
+
|
|
|
821d228 |
+static void
|
|
|
821d228 |
+loongarch64_dump_backtrace_entry(struct bt_info *bt, struct syment *sym,
|
|
|
821d228 |
+ struct loongarch64_unwind_frame *current,
|
|
|
821d228 |
+ struct loongarch64_unwind_frame *previous, int level)
|
|
|
821d228 |
+{
|
|
|
821d228 |
+ const char *name = sym ? sym->name : "(invalid)";
|
|
|
821d228 |
+ struct load_module *lm;
|
|
|
821d228 |
+ char *name_plus_offset = NULL;
|
|
|
821d228 |
+ struct syment *symp;
|
|
|
821d228 |
+ ulong symbol_offset;
|
|
|
821d228 |
+ char buf[BUFSIZE];
|
|
|
821d228 |
+ char pt_regs[SIZE(pt_regs)];
|
|
|
821d228 |
+
|
|
|
821d228 |
+ if (bt->flags & BT_SYMBOL_OFFSET) {
|
|
|
821d228 |
+ symp = value_search(current->pc, &symbol_offset);
|
|
|
821d228 |
+
|
|
|
821d228 |
+ if (symp && symbol_offset)
|
|
|
821d228 |
+ name_plus_offset =
|
|
|
821d228 |
+ value_to_symstr(current->pc, buf, bt->radix);
|
|
|
821d228 |
+ }
|
|
|
821d228 |
+
|
|
|
821d228 |
+ fprintf(fp, "%s#%d [%016lx] %s at %016lx", level < 10 ? " " : "", level,
|
|
|
821d228 |
+ current->sp, name_plus_offset ? name_plus_offset : name,
|
|
|
821d228 |
+ current->pc);
|
|
|
821d228 |
+
|
|
|
821d228 |
+ if (module_symbol(current->pc, NULL, &lm, NULL, 0))
|
|
|
821d228 |
+ fprintf(fp, " [%s]", lm->mod_name);
|
|
|
821d228 |
+
|
|
|
821d228 |
+ fprintf(fp, "\n");
|
|
|
821d228 |
+
|
|
|
821d228 |
+ /*
|
|
|
821d228 |
+ * 'bt -l', get a line number associated with a current pc address.
|
|
|
821d228 |
+ */
|
|
|
821d228 |
+ if (bt->flags & BT_LINE_NUMBERS) {
|
|
|
821d228 |
+ get_line_number(current->pc, buf, FALSE);
|
|
|
821d228 |
+ if (strlen(buf))
|
|
|
821d228 |
+ fprintf(fp, " %s\n", buf);
|
|
|
821d228 |
+ }
|
|
|
821d228 |
+
|
|
|
821d228 |
+ if (sym && loongarch64_is_exception_entry(sym)) {
|
|
|
821d228 |
+ GET_STACK_DATA(current->sp, &pt_regs, SIZE(pt_regs));
|
|
|
821d228 |
+ loongarch64_dump_exception_stack(bt, pt_regs);
|
|
|
821d228 |
+ }
|
|
|
821d228 |
+
|
|
|
821d228 |
+ /* bt -f */
|
|
|
821d228 |
+ if (bt->flags & BT_FULL) {
|
|
|
821d228 |
+ fprintf(fp, " "
|
|
|
821d228 |
+ "[PC: %016lx RA: %016lx SP: %016lx SIZE: %ld]\n",
|
|
|
821d228 |
+ current->pc, current->ra, current->sp,
|
|
|
821d228 |
+ previous->sp - current->sp);
|
|
|
821d228 |
+ loongarch64_display_full_frame(bt, current, previous);
|
|
|
821d228 |
+ }
|
|
|
821d228 |
+}
|
|
|
821d228 |
+
|
|
|
821d228 |
+static void
|
|
|
821d228 |
+loongarch64_dump_exception_stack(struct bt_info *bt, char *pt_regs)
|
|
|
821d228 |
+{
|
|
|
821d228 |
+ struct loongarch64_pt_regs *regs;
|
|
|
821d228 |
+ int i;
|
|
|
821d228 |
+ char buf[BUFSIZE];
|
|
|
821d228 |
+
|
|
|
821d228 |
+ regs = (struct loongarch64_pt_regs *) (pt_regs + OFFSET(pt_regs_regs));
|
|
|
821d228 |
+
|
|
|
821d228 |
+ for (i = 0; i < 32; i += 4) {
|
|
|
821d228 |
+ fprintf(fp, " $%2d : %016lx %016lx %016lx %016lx\n",
|
|
|
821d228 |
+ i, regs->regs[i], regs->regs[i+1],
|
|
|
821d228 |
+ regs->regs[i+2], regs->regs[i+3]);
|
|
|
821d228 |
+ }
|
|
|
821d228 |
+
|
|
|
821d228 |
+ value_to_symstr(regs->csr_epc, buf, 16);
|
|
|
821d228 |
+ fprintf(fp, " epc : %016lx %s\n", regs->csr_epc, buf);
|
|
|
821d228 |
+
|
|
|
821d228 |
+ value_to_symstr(regs->regs[LOONGARCH64_EF_RA], buf, 16);
|
|
|
821d228 |
+ fprintf(fp, " ra : %016lx %s\n", regs->regs[LOONGARCH64_EF_RA], buf);
|
|
|
821d228 |
+
|
|
|
821d228 |
+ fprintf(fp, " CSR crmd : %016lx\n", regs->csr_crmd);
|
|
|
821d228 |
+ fprintf(fp, " CSR prmd : %016lx\n", regs->csr_prmd);
|
|
|
821d228 |
+ fprintf(fp, " CSR ecfg : %016lx\n", regs->csr_ecfg);
|
|
|
821d228 |
+ fprintf(fp, " CSR estat: %016lx\n", regs->csr_estat);
|
|
|
821d228 |
+ fprintf(fp, " CSR euen : %016lx\n", regs->csr_euen);
|
|
|
821d228 |
+
|
|
|
821d228 |
+ fprintf(fp, " BadVA : %016lx\n", regs->csr_badvaddr);
|
|
|
821d228 |
+}
|
|
|
821d228 |
+
|
|
|
821d228 |
+static int
|
|
|
821d228 |
+loongarch64_is_exception_entry(struct syment *sym)
|
|
|
821d228 |
+{
|
|
|
821d228 |
+ return STREQ(sym->name, "ret_from_exception") ||
|
|
|
821d228 |
+ STREQ(sym->name, "ret_from_irq") ||
|
|
|
821d228 |
+ STREQ(sym->name, "work_resched") ||
|
|
|
821d228 |
+ STREQ(sym->name, "handle_sys");
|
|
|
821d228 |
+}
|
|
|
821d228 |
+
|
|
|
821d228 |
+/*
|
|
|
821d228 |
+ * 'bt -f' commend output
|
|
|
821d228 |
+ * Display all stack data contained in a frame
|
|
|
821d228 |
+ */
|
|
|
821d228 |
+static void
|
|
|
821d228 |
+loongarch64_display_full_frame(struct bt_info *bt, struct loongarch64_unwind_frame *current,
|
|
|
821d228 |
+ struct loongarch64_unwind_frame *previous)
|
|
|
821d228 |
+{
|
|
|
821d228 |
+ int i, u_idx;
|
|
|
821d228 |
+ ulong *up;
|
|
|
821d228 |
+ ulong words, addr;
|
|
|
821d228 |
+ char buf[BUFSIZE];
|
|
|
821d228 |
+
|
|
|
821d228 |
+ if (previous->sp < current->sp)
|
|
|
821d228 |
+ return;
|
|
|
821d228 |
+
|
|
|
821d228 |
+ if (!(INSTACK(previous->sp, bt) && INSTACK(current->sp, bt)))
|
|
|
821d228 |
+ return;
|
|
|
821d228 |
+
|
|
|
821d228 |
+ words = (previous->sp - current->sp) / sizeof(ulong) + 1;
|
|
|
821d228 |
+ addr = current->sp;
|
|
|
821d228 |
+ u_idx = (current->sp - bt->stackbase) / sizeof(ulong);
|
|
|
821d228 |
+
|
|
|
821d228 |
+ for (i = 0; i < words; i++, u_idx++) {
|
|
|
821d228 |
+ if (!(i & 1))
|
|
|
821d228 |
+ fprintf(fp, "%s %lx: ", i ? "\n" : "", addr);
|
|
|
821d228 |
+
|
|
|
821d228 |
+ up = (ulong *)(&bt->stackbuf[u_idx*sizeof(ulong)]);
|
|
|
821d228 |
+ fprintf(fp, "%s ", format_stack_entry(bt, buf, *up, 0));
|
|
|
821d228 |
+ addr += sizeof(ulong);
|
|
|
821d228 |
+ }
|
|
|
821d228 |
+ fprintf(fp, "\n");
|
|
|
821d228 |
+}
|
|
|
821d228 |
+
|
|
|
821d228 |
+static void
|
|
|
821d228 |
+loongarch64_stackframe_init(void)
|
|
|
821d228 |
+{
|
|
|
821d228 |
+ long task_struct_thread = MEMBER_OFFSET("task_struct", "thread");
|
|
|
821d228 |
+ long thread_reg03_sp = MEMBER_OFFSET("thread_struct", "reg03");
|
|
|
821d228 |
+ long thread_reg01_ra = MEMBER_OFFSET("thread_struct", "reg01");
|
|
|
821d228 |
+
|
|
|
821d228 |
+ if ((task_struct_thread == INVALID_OFFSET) ||
|
|
|
821d228 |
+ (thread_reg03_sp == INVALID_OFFSET) ||
|
|
|
821d228 |
+ (thread_reg01_ra == INVALID_OFFSET)) {
|
|
|
821d228 |
+ error(FATAL,
|
|
|
821d228 |
+ "cannot determine thread_struct offsets\n");
|
|
|
821d228 |
+ return;
|
|
|
821d228 |
+ }
|
|
|
821d228 |
+
|
|
|
821d228 |
+ ASSIGN_OFFSET(task_struct_thread_reg03) =
|
|
|
821d228 |
+ task_struct_thread + thread_reg03_sp;
|
|
|
821d228 |
+ ASSIGN_OFFSET(task_struct_thread_reg01) =
|
|
|
821d228 |
+ task_struct_thread + thread_reg01_ra;
|
|
|
821d228 |
+
|
|
|
821d228 |
+ MEMBER_OFFSET_INIT(elf_prstatus_pr_reg, "elf_prstatus", "pr_reg");
|
|
|
821d228 |
+ STRUCT_SIZE_INIT(note_buf, "note_buf_t");
|
|
|
821d228 |
+}
|
|
|
821d228 |
+
|
|
|
821d228 |
+/*
|
|
|
821d228 |
+ * Get a stack frame combination of pc and ra from the most relevant spot.
|
|
|
821d228 |
+ */
|
|
|
821d228 |
+static void
|
|
|
821d228 |
+loongarch64_get_stack_frame(struct bt_info *bt, ulong *pcp, ulong *spp)
|
|
|
821d228 |
+{
|
|
|
821d228 |
+ ulong ksp, nip;
|
|
|
821d228 |
+ int ret = 0;
|
|
|
821d228 |
+
|
|
|
821d228 |
+ nip = ksp = 0;
|
|
|
821d228 |
+ bt->machdep = NULL;
|
|
|
821d228 |
+
|
|
|
821d228 |
+ if (DUMPFILE() && is_task_active(bt->task)) {
|
|
|
821d228 |
+ ret = loongarch64_get_dumpfile_stack_frame(bt, &nip, &ksp;;
|
|
|
821d228 |
+ }
|
|
|
821d228 |
+ else {
|
|
|
821d228 |
+ ret = loongarch64_get_frame(bt, &nip, &ksp;;
|
|
|
821d228 |
+ }
|
|
|
821d228 |
+
|
|
|
821d228 |
+ if (!ret)
|
|
|
821d228 |
+ error(WARNING, "cannot determine starting stack frame for task %lx\n",
|
|
|
821d228 |
+ bt->task);
|
|
|
821d228 |
+
|
|
|
821d228 |
+ if (pcp)
|
|
|
821d228 |
+ *pcp = nip;
|
|
|
821d228 |
+ if (spp)
|
|
|
821d228 |
+ *spp = ksp;
|
|
|
821d228 |
+}
|
|
|
821d228 |
+
|
|
|
821d228 |
+/*
|
|
|
821d228 |
+ * Get the starting point for the active cpu in a diskdump.
|
|
|
821d228 |
+ */
|
|
|
821d228 |
+static int
|
|
|
821d228 |
+loongarch64_get_dumpfile_stack_frame(struct bt_info *bt, ulong *nip, ulong *ksp)
|
|
|
821d228 |
+{
|
|
|
821d228 |
+ const struct machine_specific *ms = machdep->machspec;
|
|
|
821d228 |
+ struct loongarch64_pt_regs *regs;
|
|
|
821d228 |
+ ulong epc, sp;
|
|
|
821d228 |
+
|
|
|
821d228 |
+ if (!ms->crash_task_regs) {
|
|
|
821d228 |
+ bt->flags |= BT_REGS_NOT_FOUND;
|
|
|
821d228 |
+ return FALSE;
|
|
|
821d228 |
+ }
|
|
|
821d228 |
+
|
|
|
821d228 |
+ /*
|
|
|
821d228 |
+ * We got registers for panic task from crash_notes. Just return them.
|
|
|
821d228 |
+ */
|
|
|
821d228 |
+ regs = &ms->crash_task_regs[bt->tc->processor];
|
|
|
821d228 |
+ epc = regs->csr_epc;
|
|
|
821d228 |
+ sp = regs->regs[LOONGARCH64_EF_SP];
|
|
|
821d228 |
+
|
|
|
821d228 |
+ if (!epc && !sp) {
|
|
|
821d228 |
+ bt->flags |= BT_REGS_NOT_FOUND;
|
|
|
821d228 |
+ return FALSE;
|
|
|
821d228 |
+ }
|
|
|
821d228 |
+
|
|
|
821d228 |
+ if (nip)
|
|
|
821d228 |
+ *nip = epc;
|
|
|
821d228 |
+ if (ksp)
|
|
|
821d228 |
+ *ksp = sp;
|
|
|
821d228 |
+
|
|
|
821d228 |
+ bt->machdep = regs;
|
|
|
821d228 |
+
|
|
|
821d228 |
+ return TRUE;
|
|
|
821d228 |
+}
|
|
|
821d228 |
+
|
|
|
821d228 |
+/*
|
|
|
821d228 |
+ * Do the work for loongarch64_get_stack_frame() for non-active tasks.
|
|
|
821d228 |
+ * Get SP and PC values for idle tasks.
|
|
|
821d228 |
+ */
|
|
|
821d228 |
+static int
|
|
|
821d228 |
+loongarch64_get_frame(struct bt_info *bt, ulong *pcp, ulong *spp)
|
|
|
821d228 |
+{
|
|
|
821d228 |
+ if (!bt->tc || !(tt->flags & THREAD_INFO))
|
|
|
821d228 |
+ return FALSE;
|
|
|
821d228 |
+
|
|
|
821d228 |
+ if (!readmem(bt->task + OFFSET(task_struct_thread_reg01),
|
|
|
821d228 |
+ KVADDR, pcp, sizeof(*pcp),
|
|
|
821d228 |
+ "thread_struct.regs01",
|
|
|
821d228 |
+ RETURN_ON_ERROR)) {
|
|
|
821d228 |
+ return FALSE;
|
|
|
821d228 |
+ }
|
|
|
821d228 |
+
|
|
|
821d228 |
+ if (!readmem(bt->task + OFFSET(task_struct_thread_reg03),
|
|
|
821d228 |
+ KVADDR, spp, sizeof(*spp),
|
|
|
821d228 |
+ "thread_struct.regs03",
|
|
|
821d228 |
+ RETURN_ON_ERROR)) {
|
|
|
821d228 |
+ return FALSE;
|
|
|
821d228 |
+ }
|
|
|
821d228 |
+
|
|
|
821d228 |
+ return TRUE;
|
|
|
821d228 |
+}
|
|
|
821d228 |
+
|
|
|
821d228 |
+static int
|
|
|
821d228 |
+loongarch64_init_active_task_regs(void)
|
|
|
821d228 |
+{
|
|
|
821d228 |
+ int retval;
|
|
|
821d228 |
+
|
|
|
821d228 |
+ retval = loongarch64_get_crash_notes();
|
|
|
821d228 |
+ if (retval == TRUE)
|
|
|
821d228 |
+ return retval;
|
|
|
821d228 |
+
|
|
|
821d228 |
+ return loongarch64_get_elf_notes();
|
|
|
821d228 |
+}
|
|
|
821d228 |
+
|
|
|
821d228 |
+/*
|
|
|
821d228 |
+ * Retrieve task registers for the time of the crash.
|
|
|
821d228 |
+ */
|
|
|
821d228 |
+static int
|
|
|
821d228 |
+loongarch64_get_crash_notes(void)
|
|
|
821d228 |
+{
|
|
|
821d228 |
+ struct machine_specific *ms = machdep->machspec;
|
|
|
821d228 |
+ ulong crash_notes;
|
|
|
821d228 |
+ Elf64_Nhdr *note;
|
|
|
821d228 |
+ ulong offset;
|
|
|
821d228 |
+ char *buf, *p;
|
|
|
821d228 |
+ ulong *notes_ptrs;
|
|
|
821d228 |
+ ulong i;
|
|
|
821d228 |
+
|
|
|
821d228 |
+ /*
|
|
|
821d228 |
+ * crash_notes contains per cpu memory for storing cpu states
|
|
|
821d228 |
+ * in case of system crash.
|
|
|
821d228 |
+ */
|
|
|
821d228 |
+ if (!symbol_exists("crash_notes"))
|
|
|
821d228 |
+ return FALSE;
|
|
|
821d228 |
+
|
|
|
821d228 |
+ crash_notes = symbol_value("crash_notes");
|
|
|
821d228 |
+
|
|
|
821d228 |
+ notes_ptrs = (ulong *)GETBUF(kt->cpus*sizeof(notes_ptrs[0]));
|
|
|
821d228 |
+
|
|
|
821d228 |
+ /*
|
|
|
821d228 |
+ * Read crash_notes for the first CPU. crash_notes are in standard ELF
|
|
|
821d228 |
+ * note format.
|
|
|
821d228 |
+ */
|
|
|
821d228 |
+ if (!readmem(crash_notes, KVADDR, ¬es_ptrs[kt->cpus-1],
|
|
|
821d228 |
+ sizeof(notes_ptrs[kt->cpus-1]), "crash_notes",
|
|
|
821d228 |
+ RETURN_ON_ERROR)) {
|
|
|
821d228 |
+ error(WARNING, "cannot read crash_notes\n");
|
|
|
821d228 |
+ FREEBUF(notes_ptrs);
|
|
|
821d228 |
+ return FALSE;
|
|
|
821d228 |
+ }
|
|
|
821d228 |
+
|
|
|
821d228 |
+ if (symbol_exists("__per_cpu_offset")) {
|
|
|
821d228 |
+
|
|
|
821d228 |
+ /*
|
|
|
821d228 |
+ * Add __per_cpu_offset for each cpu to form the pointer to the notes
|
|
|
821d228 |
+ */
|
|
|
821d228 |
+ for (i = 0; i < kt->cpus; i++)
|
|
|
821d228 |
+ notes_ptrs[i] = notes_ptrs[kt->cpus-1] + kt->__per_cpu_offset[i];
|
|
|
821d228 |
+ }
|
|
|
821d228 |
+
|
|
|
821d228 |
+ buf = GETBUF(SIZE(note_buf));
|
|
|
821d228 |
+
|
|
|
821d228 |
+ if (!(panic_task_regs = calloc((size_t)kt->cpus, sizeof(*panic_task_regs))))
|
|
|
821d228 |
+ error(FATAL, "cannot calloc panic_task_regs space\n");
|
|
|
821d228 |
+
|
|
|
821d228 |
+ for (i = 0; i < kt->cpus; i++) {
|
|
|
821d228 |
+
|
|
|
821d228 |
+ if (!readmem(notes_ptrs[i], KVADDR, buf, SIZE(note_buf), "note_buf_t",
|
|
|
821d228 |
+ RETURN_ON_ERROR)) {
|
|
|
821d228 |
+ error(WARNING,
|
|
|
821d228 |
+ "cannot find NT_PRSTATUS note for cpu: %d\n", i);
|
|
|
821d228 |
+ goto fail;
|
|
|
821d228 |
+ }
|
|
|
821d228 |
+
|
|
|
821d228 |
+ /*
|
|
|
821d228 |
+ * Do some sanity checks for this note before reading registers from it.
|
|
|
821d228 |
+ */
|
|
|
821d228 |
+ note = (Elf64_Nhdr *)buf;
|
|
|
821d228 |
+ p = buf + sizeof(Elf64_Nhdr);
|
|
|
821d228 |
+
|
|
|
821d228 |
+ /*
|
|
|
821d228 |
+ * dumpfiles created with qemu won't have crash_notes, but there will
|
|
|
821d228 |
+ * be elf notes; dumpfiles created by kdump do not create notes for
|
|
|
821d228 |
+ * offline cpus.
|
|
|
821d228 |
+ */
|
|
|
821d228 |
+ if (note->n_namesz == 0 && (DISKDUMP_DUMPFILE() || KDUMP_DUMPFILE())) {
|
|
|
821d228 |
+ if (DISKDUMP_DUMPFILE())
|
|
|
821d228 |
+ note = diskdump_get_prstatus_percpu(i);
|
|
|
821d228 |
+ else if (KDUMP_DUMPFILE())
|
|
|
821d228 |
+ note = netdump_get_prstatus_percpu(i);
|
|
|
821d228 |
+ if (note) {
|
|
|
821d228 |
+ /*
|
|
|
821d228 |
+ * SIZE(note_buf) accounts for a "final note", which is a
|
|
|
821d228 |
+ * trailing empty elf note header.
|
|
|
821d228 |
+ */
|
|
|
821d228 |
+ long notesz = SIZE(note_buf) - sizeof(Elf64_Nhdr);
|
|
|
821d228 |
+
|
|
|
821d228 |
+ if (sizeof(Elf64_Nhdr) + roundup(note->n_namesz, 4) +
|
|
|
821d228 |
+ note->n_descsz == notesz)
|
|
|
821d228 |
+ BCOPY((char *)note, buf, notesz);
|
|
|
821d228 |
+ } else {
|
|
|
821d228 |
+ error(WARNING,
|
|
|
821d228 |
+ "cannot find NT_PRSTATUS note for cpu: %d\n", i);
|
|
|
821d228 |
+ continue;
|
|
|
821d228 |
+ }
|
|
|
821d228 |
+ }
|
|
|
821d228 |
+
|
|
|
821d228 |
+ /*
|
|
|
821d228 |
+ * Check the sanity of NT_PRSTATUS note only for each online cpu.
|
|
|
821d228 |
+ */
|
|
|
821d228 |
+ if (note->n_type != NT_PRSTATUS) {
|
|
|
821d228 |
+ error(WARNING, "invalid NT_PRSTATUS note (n_type != NT_PRSTATUS)\n");
|
|
|
821d228 |
+ goto fail;
|
|
|
821d228 |
+ }
|
|
|
821d228 |
+ if (!STRNEQ(p, "CORE")) {
|
|
|
821d228 |
+ error(WARNING, "invalid NT_PRSTATUS note (name != \"CORE\"\n");
|
|
|
821d228 |
+ goto fail;
|
|
|
821d228 |
+ }
|
|
|
821d228 |
+
|
|
|
821d228 |
+ /*
|
|
|
821d228 |
+ * Find correct location of note data. This contains elf_prstatus
|
|
|
821d228 |
+ * structure which has registers etc. for the crashed task.
|
|
|
821d228 |
+ */
|
|
|
821d228 |
+ offset = sizeof(Elf64_Nhdr);
|
|
|
821d228 |
+ offset = roundup(offset + note->n_namesz, 4);
|
|
|
821d228 |
+ p = buf + offset; /* start of elf_prstatus */
|
|
|
821d228 |
+
|
|
|
821d228 |
+ BCOPY(p + OFFSET(elf_prstatus_pr_reg), &panic_task_regs[i],
|
|
|
821d228 |
+ sizeof(panic_task_regs[i]));
|
|
|
821d228 |
+ }
|
|
|
821d228 |
+
|
|
|
821d228 |
+ /*
|
|
|
821d228 |
+ * And finally we have the registers for the crashed task. This is
|
|
|
821d228 |
+ * used later on when dumping backtrace.
|
|
|
821d228 |
+ */
|
|
|
821d228 |
+ ms->crash_task_regs = panic_task_regs;
|
|
|
821d228 |
+
|
|
|
821d228 |
+ FREEBUF(buf);
|
|
|
821d228 |
+ FREEBUF(notes_ptrs);
|
|
|
821d228 |
+ return TRUE;
|
|
|
821d228 |
+
|
|
|
821d228 |
+fail:
|
|
|
821d228 |
+ FREEBUF(buf);
|
|
|
821d228 |
+ FREEBUF(notes_ptrs);
|
|
|
821d228 |
+ free(panic_task_regs);
|
|
|
821d228 |
+ return FALSE;
|
|
|
821d228 |
+}
|
|
|
821d228 |
+
|
|
|
821d228 |
+static int
|
|
|
821d228 |
+loongarch64_get_elf_notes(void)
|
|
|
821d228 |
+{
|
|
|
821d228 |
+ struct machine_specific *ms = machdep->machspec;
|
|
|
821d228 |
+ int i;
|
|
|
821d228 |
+
|
|
|
821d228 |
+ if (!DISKDUMP_DUMPFILE() && !KDUMP_DUMPFILE())
|
|
|
821d228 |
+ return FALSE;
|
|
|
821d228 |
+
|
|
|
821d228 |
+ panic_task_regs = calloc(kt->cpus, sizeof(*panic_task_regs));
|
|
|
821d228 |
+ if (!panic_task_regs)
|
|
|
821d228 |
+ error(FATAL, "cannot calloc panic_task_regs space\n");
|
|
|
821d228 |
+
|
|
|
821d228 |
+ for (i = 0; i < kt->cpus; i++) {
|
|
|
821d228 |
+ Elf64_Nhdr *note = NULL;
|
|
|
821d228 |
+ size_t len;
|
|
|
821d228 |
+
|
|
|
821d228 |
+ if (DISKDUMP_DUMPFILE())
|
|
|
821d228 |
+ note = diskdump_get_prstatus_percpu(i);
|
|
|
821d228 |
+ else if (KDUMP_DUMPFILE())
|
|
|
821d228 |
+ note = netdump_get_prstatus_percpu(i);
|
|
|
821d228 |
+
|
|
|
821d228 |
+ if (!note) {
|
|
|
821d228 |
+ error(WARNING,
|
|
|
821d228 |
+ "cannot find NT_PRSTATUS note for cpu: %d\n", i);
|
|
|
821d228 |
+ continue;
|
|
|
821d228 |
+ }
|
|
|
821d228 |
+
|
|
|
821d228 |
+ len = sizeof(Elf64_Nhdr);
|
|
|
821d228 |
+ len = roundup(len + note->n_namesz, 4);
|
|
|
821d228 |
+
|
|
|
821d228 |
+ BCOPY((char *)note + len + OFFSET(elf_prstatus_pr_reg),
|
|
|
821d228 |
+ &panic_task_regs[i], sizeof(panic_task_regs[i]));
|
|
|
821d228 |
+ }
|
|
|
821d228 |
+
|
|
|
821d228 |
+ ms->crash_task_regs = panic_task_regs;
|
|
|
821d228 |
+
|
|
|
821d228 |
+ return TRUE;
|
|
|
821d228 |
+}
|
|
|
821d228 |
+
|
|
|
821d228 |
/*
|
|
|
821d228 |
* Accept or reject a symbol from the kernel namelist.
|
|
|
821d228 |
*/
|
|
|
821d228 |
@@ -429,7 +1083,7 @@ loongarch64_get_page_size(void)
|
|
|
821d228 |
static ulong
|
|
|
821d228 |
loongarch64_vmalloc_start(void)
|
|
|
821d228 |
{
|
|
|
821d228 |
- return 0;
|
|
|
821d228 |
+ return first_vmalloc_address();
|
|
|
821d228 |
}
|
|
|
821d228 |
|
|
|
821d228 |
/*
|
|
|
821d228 |
@@ -520,6 +1174,8 @@ loongarch64_init(int when)
|
|
|
821d228 |
machdep->uvtop = loongarch64_uvtop;
|
|
|
821d228 |
machdep->kvtop = loongarch64_kvtop;
|
|
|
821d228 |
machdep->cmd_mach = loongarch64_cmd_mach;
|
|
|
821d228 |
+ machdep->back_trace = loongarch64_back_trace_cmd;
|
|
|
821d228 |
+ machdep->get_stack_frame = loongarch64_get_stack_frame;
|
|
|
821d228 |
machdep->vmalloc_start = loongarch64_vmalloc_start;
|
|
|
821d228 |
machdep->processor_speed = loongarch64_processor_speed;
|
|
|
821d228 |
machdep->get_stackbase = generic_get_stackbase;
|
|
|
821d228 |
@@ -536,11 +1192,21 @@ loongarch64_init(int when)
|
|
|
821d228 |
case POST_GDB:
|
|
|
821d228 |
machdep->section_size_bits = _SECTION_SIZE_BITS;
|
|
|
821d228 |
machdep->max_physmem_bits = _MAX_PHYSMEM_BITS;
|
|
|
821d228 |
+ loongarch64_stackframe_init();
|
|
|
821d228 |
if (!machdep->hz)
|
|
|
821d228 |
machdep->hz = 250;
|
|
|
821d228 |
break;
|
|
|
821d228 |
|
|
|
821d228 |
case POST_VM:
|
|
|
821d228 |
+ /*
|
|
|
821d228 |
+ * crash_notes contains machine specific information about the
|
|
|
821d228 |
+ * crash. In particular, it contains CPU registers at the time
|
|
|
821d228 |
+ * of the crash. We need this information to extract correct
|
|
|
821d228 |
+ * backtraces from the panic task.
|
|
|
821d228 |
+ */
|
|
|
821d228 |
+ if (!ACTIVE() && !loongarch64_init_active_task_regs())
|
|
|
821d228 |
+ error(WARNING,"cannot retrieve registers for active task%s\n\n",
|
|
|
821d228 |
+ kt->cpus > 1 ? "s" : "");
|
|
|
821d228 |
break;
|
|
|
821d228 |
}
|
|
|
821d228 |
}
|
|
|
821d228 |
diff --git a/symbols.c b/symbols.c
|
|
|
821d228 |
index 6a2dad03dc61..cf25e9da9e8f 100644
|
|
|
821d228 |
--- a/symbols.c
|
|
|
821d228 |
+++ b/symbols.c
|
|
|
821d228 |
@@ -9815,6 +9815,10 @@ dump_offset_table(char *spec, ulong makestruct)
|
|
|
821d228 |
OFFSET(task_struct_thread_esp));
|
|
|
821d228 |
fprintf(fp, " task_struct_thread_ksp: %ld\n",
|
|
|
821d228 |
OFFSET(task_struct_thread_ksp));
|
|
|
821d228 |
+ fprintf(fp, " task_struct_thread_reg01: %ld\n",
|
|
|
821d228 |
+ OFFSET(task_struct_thread_reg01));
|
|
|
821d228 |
+ fprintf(fp, " task_struct_thread_reg03: %ld\n",
|
|
|
821d228 |
+ OFFSET(task_struct_thread_reg03));
|
|
|
821d228 |
fprintf(fp, " task_struct_thread_reg29: %ld\n",
|
|
|
821d228 |
OFFSET(task_struct_thread_reg29));
|
|
|
821d228 |
fprintf(fp, " task_struct_thread_reg31: %ld\n",
|
|
|
821d228 |
--
|
|
|
821d228 |
2.41.0
|
|
|
821d228 |
|