The patch introduces per-cpu overflow stacks for RISCV64 to let
"bt" do backtrace on it and the 'help -m' command dispalys the
addresss of each per-cpu overflow stack.

TEST: a lkdtm DIRECT EXHAUST_STACK vmcore

```
crash> bt
PID: 1        TASK: ff600000000d8000  CPU: 1    COMMAND: "sh"
 #0 [ff6000001fc501c0] riscv_crash_save_regs at ffffffff8000a1dc
 #1 [ff6000001fc50320] panic at ffffffff808773ec
 #2 [ff6000001fc50380] walk_stackframe at ffffffff800056da
     PC: ffffffff80876a34  [memset+96]
     RA: ffffffff80563dc0  [recursive_loop+68]
     SP: ff2000000000fd50  CAUSE: 000000000000000f
epc : ffffffff80876a34 ra : ffffffff80563dc0 sp : ff2000000000fd50
 gp : ffffffff81515d38 tp : 0000000000000000 t0 : ff2000000000fd58
 t1 : ff600000000d88c8 t2 : 6143203a6d74646b s0 : ff20000000010190
 s1 : 0000000000000012 a0 : ff2000000000fd58 a1 : 1212121212121212
 a2 : 0000000000000400 a3 : ff20000000010158 a4 : 0000000000000000
 a5 : 725bedba92260900 a6 : 000000000130e0f0 a7 : 0000000000000000
 s2 : ff2000000000fd58 s3 : ffffffff815170d8 s4 : ff20000000013e60
 s5 : 000000000000000e s6 : ff20000000013e60 s7 : 0000000000000000
 s8 : ff60000000861000 s9 : 00007fffc3641694 s10: 00007fffc3641690
 s11: 00005555796ed240 t3 : 0000000000010297 t4 : ffffffff80c17810
 t5 : ffffffff8195e7b8 t6 : ff20000000013b18
 status: 0000000200000120 badaddr: ff2000000000fd58
  cause: 000000000000000f orig_a0: 0000000000000000
--- <OVERFLOW stack> ---
 #3 [ff2000000000fd50] memset at ffffffff80876a34
 #4 [ff20000000010190] recursive_loop at ffffffff80563e16
 #5 [ff200000000105d0] recursive_loop at ffffffff80563e16
 < recursive_loop ...>
 #16 [ff20000000013490] recursive_loop at ffffffff80563e16
 #17 [ff200000000138d0] recursive_loop at ffffffff80563e16
 #18 [ff20000000013d10] lkdtm_EXHAUST_STACK at ffffffff8088005e
 #19 [ff20000000013d30] lkdtm_do_action at ffffffff80563292
 #20 [ff20000000013d40] direct_entry at ffffffff80563474
 #21 [ff20000000013d70] full_proxy_write at ffffffff8032fb3a
 #22 [ff20000000013db0] vfs_write at ffffffff801d6414
 #23 [ff20000000013e60] ksys_write at ffffffff801d67b8
 #24 [ff20000000013eb0] __riscv_sys_write at ffffffff801d6832
 #25 [ff20000000013ec0] do_trap_ecall_u at ffffffff80884a20
crash>

crash> help -m
<snip>
        irq_stack_size: 16384
         irq_stacks[0]: ff20000000000000
         irq_stacks[1]: ff20000000008000
        overflow_stack_size: 4096
         overflow_stacks[0]: ff6000001fa7a510
         overflow_stacks[1]: ff6000001fc4f510
crash>
```
Signed-off-by: Song Shuai <[email protected]>
---
 defs.h    |   6 +++
 riscv64.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 120 insertions(+), 3 deletions(-)

diff --git a/defs.h b/defs.h
index 7b9fcce..5369d57 100644
--- a/defs.h
+++ b/defs.h
@@ -3656,6 +3656,9 @@ typedef signed int s32;
 #define VM_L5_2M       (0x100)
 #define VM_L5_1G       (0x200)
 #define IRQ_STACKS     (0x400)
+#define OVERFLOW_STACKS     (0x800)
+
+#define RISCV64_OVERFLOW_STACK_SIZE (1 << 12)
 
 #define VM_FLAGS       (VM_L3_4K | VM_L3_2M | VM_L3_1G | \
                         VM_L4_4K | VM_L4_2M | VM_L4_1G | \
@@ -7048,6 +7051,9 @@ struct machine_specific {
        struct riscv64_register *crash_task_regs;
        ulong irq_stack_size;
        ulong *irq_stacks;
+
+       ulong overflow_stack_size;
+       ulong *overflow_stacks;
 };
 /* from arch/riscv/include/asm/pgtable-bits.h */
 #define _PAGE_PRESENT  (machdep->machspec->_page_present)
diff --git a/riscv64.c b/riscv64.c
index a69dfe5..c5a85e8 100644
--- a/riscv64.c
+++ b/riscv64.c
@@ -34,6 +34,7 @@ static int riscv64_kvtop(struct task_context *tc, ulong 
kvaddr,
                          physaddr_t *paddr, int verbose);
 static void riscv64_cmd_mach(void);
 static void riscv64_irq_stack_init(void);
+static void riscv64_overflow_stack_init(void);
 static void riscv64_stackframe_init(void);
 static void riscv64_back_trace_cmd(struct bt_info *bt);
 static int riscv64_eframe_search(struct bt_info *bt);
@@ -59,9 +60,13 @@ static int riscv64_on_irq_stack(int , ulong);
 static int riscv64_on_process_stack(struct bt_info *, ulong );
 static void riscv64_set_process_stack(struct bt_info *);
 static void riscv64_set_irq_stack(struct bt_info *);
+static int riscv64_on_overflow_stack(int, ulong);
+static void riscv64_set_overflow_stack(struct bt_info *);
 
 #define REG_FMT        "%016lx"
 #define SZ_2G          0x80000000
+#define USER_MODE      (0)
+#define KERNEL_MODE    (1)
 
 /*
  * Holds registers during the crash.
@@ -204,6 +209,8 @@ riscv64_dump_machdep_table(ulong arg)
                fprintf(fp, "%sKSYMS_START", others++ ? "|" : "");
        if (machdep->flags & IRQ_STACKS)
                fprintf(fp, "%sIRQ_STACKS", others++ ? "|" : "");
+       if (machdep->flags & OVERFLOW_STACKS)
+               fprintf(fp, "%sOVERFLOW_STACKS", others++ ? "|" : "");
        fprintf(fp, ")\n");
 
        fprintf(fp, "             kvbase: %lx\n", machdep->kvbase);
@@ -268,6 +275,15 @@ riscv64_dump_machdep_table(ulong arg)
                fprintf(fp, "        irq_stack_size: (unused)\n");
                fprintf(fp, "            irq_stacks: (unused)\n");
        }
+       if (machdep->flags & OVERFLOW_STACKS) {
+               fprintf(fp, "        overflow_stack_size: %ld\n", 
ms->overflow_stack_size);
+               for (i = 0; i < kt->cpus; i++)
+                       fprintf(fp, "         overflow_stacks[%d]: %lx\n", 
+                               i, ms->overflow_stacks[i]);
+       } else {
+               fprintf(fp, "        overflow_stack_size: (unused)\n");
+               fprintf(fp, "            overflow_stacks: (unused)\n");
+       }
 }
 
 static ulong
@@ -682,6 +698,48 @@ riscv64_display_full_frame(struct bt_info *bt, struct 
riscv64_unwind_frame *curr
        fprintf(fp, "\n");
 }
 
+
+/*
+ *  Gather Overflow stack values.
+ */
+static void
+riscv64_overflow_stack_init(void)
+{
+       int i;
+       struct syment *sp;
+       struct gnu_request request, *req;
+       struct machine_specific *ms = machdep->machspec;
+       req = &request;
+
+       if (symbol_exists("overflow_stack") &&
+           (sp = per_cpu_symbol_search("overflow_stack")) &&
+           get_symbol_type("overflow_stack", NULL, req)) {
+               if (CRASHDEBUG(1)) {
+                       fprintf(fp, "overflow_stack: \n");
+                       fprintf(fp, "  type: %x, %s\n",
+                               (int)req->typecode,
+                               (req->typecode == TYPE_CODE_ARRAY) ?
+                                               "TYPE_CODE_ARRAY" : "other");
+                       fprintf(fp, "  target_typecode: %x, %s\n",
+                               (int)req->target_typecode,
+                               req->target_typecode == TYPE_CODE_INT ?
+                                               "TYPE_CODE_INT" : "other");
+                       fprintf(fp, "  target_length: %ld\n",
+                                               req->target_length);
+                       fprintf(fp, "  length: %ld\n", req->length);
+               }
+
+               if (!(ms->overflow_stacks = (ulong *)malloc((size_t)(kt->cpus * 
sizeof(ulong)))))
+                       error(FATAL, "cannot malloc overflow_stack 
addresses\n");
+
+               ms->overflow_stack_size = RISCV64_OVERFLOW_STACK_SIZE;
+               machdep->flags |= OVERFLOW_STACKS;
+
+               for (i = 0; i < kt->cpus; i++)
+                       ms->overflow_stacks[i] = kt->__per_cpu_offset[i] + 
sp->value;
+       }
+}
+
 /*
  *  Gather IRQ stack values.
  */
@@ -755,6 +813,23 @@ riscv64_on_irq_stack(int cpu, ulong stkptr)
        return FALSE;
 }
 
+static int
+riscv64_on_overflow_stack(int cpu, ulong stkptr)
+{
+       struct machine_specific *ms = machdep->machspec;
+       ulong * stacks = ms->overflow_stacks;
+       ulong stack_size = ms->overflow_stack_size;
+
+       if ((cpu >= kt->cpus) || (stacks == NULL) || !stack_size)
+               return FALSE;
+
+       if ((stkptr >= stacks[cpu]) &&
+           (stkptr < (stacks[cpu] + stack_size)))
+               return TRUE;
+
+       return FALSE;
+}
+
 static int
 riscv64_on_process_stack(struct bt_info *bt, ulong stkptr)
 {
@@ -779,6 +854,16 @@ riscv64_set_irq_stack(struct bt_info *bt)
        alter_stackbuf(bt);
 }
 
+static void
+riscv64_set_overflow_stack(struct bt_info *bt)
+{
+       struct machine_specific *ms = machdep->machspec;
+
+       bt->stackbase = ms->overflow_stacks[bt->tc->processor];
+       bt->stacktop = bt->stackbase + ms->overflow_stack_size;
+       alter_stackbuf(bt);
+}
+
 static void
 riscv64_set_process_stack(struct bt_info *bt)
 {
@@ -873,7 +958,7 @@ riscv64_back_trace_cmd(struct bt_info *bt)
 {
        struct riscv64_unwind_frame current, previous;
        struct stackframe curr_frame;
-       struct riscv64_register *regs, *irq_regs;
+       struct riscv64_register *regs, *irq_regs, *overflow_regs;
        int level = 0;
 
        if (bt->flags & BT_REGS_NOT_FOUND)
@@ -885,6 +970,11 @@ riscv64_back_trace_cmd(struct bt_info *bt)
        if (riscv64_on_irq_stack(bt->tc->processor, bt->frameptr)) {
                riscv64_set_irq_stack(bt);
                bt->flags |= BT_IRQSTACK;
+       } 
+
+       if (riscv64_on_overflow_stack(bt->tc->processor, bt->frameptr)) {
+                       riscv64_set_overflow_stack(bt);
+                       bt->flags |= BT_OVERFLOW_STACK;
        }
 
        current.pc = bt->instptr;
@@ -970,6 +1060,28 @@ riscv64_back_trace_cmd(struct bt_info *bt)
                        }
                }
 
+                /* When backtracing to handle_kernel_stack_overflow()
+                 * use pt_regs saved in overflow stack to continue
+                 */
+
+               if ((bt->flags & BT_OVERFLOW_STACK) &&
+                   !riscv64_on_overflow_stack(bt->tc->processor, current.fp)) {
+
+                               overflow_regs = (struct riscv64_register *)
+                                       
&bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(current.sp))];
+
+                               riscv64_print_exception_frame(bt, current.sp, 
KERNEL_MODE);
+
+                               current.pc = 
overflow_regs->regs[RISCV64_REGS_EPC];
+                               current.fp = 
overflow_regs->regs[RISCV64_REGS_FP];
+                               current.sp = 
overflow_regs->regs[RISCV64_REGS_SP];
+
+                               riscv64_set_process_stack(bt);
+
+                               bt->flags &= ~BT_OVERFLOW_STACK;
+                               fprintf(fp, "--- <OVERFLOW stack> ---\n");
+               }
+
                if (CRASHDEBUG(8))
                        fprintf(fp, "next %d pc %#lx sp %#lx fp %lx\n",
                                level, current.pc, current.sp, current.fp);
@@ -1582,6 +1694,7 @@ riscv64_init(int when)
                machdep->max_physmem_bits = _MAX_PHYSMEM_BITS;
 
                riscv64_irq_stack_init();
+               riscv64_overflow_stack_init();
                riscv64_stackframe_init();
                riscv64_page_type_init();
 
@@ -1678,8 +1791,6 @@ riscv64_display_regs_from_elf_notes(int cpu, FILE *ofp)
        riscv64_dump_pt_regs(regs, ofp, 0);
 }
 
-#define USER_MODE      (0)
-#define KERNEL_MODE    (1)
 
 static void
 riscv64_print_exception_frame(struct bt_info *bt, ulong ptr, int mode)
-- 
2.20.1
--
Crash-utility mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://${domain_name}/admin/lists/devel.lists.crash-utility.osci.io/
Contribution Guidelines: https://github.com/crash-utility/crash/wiki

Reply via email to