diff --git a/defs.h b/defs.h index a5a199fb..997ab458 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 | \ @@ -7062,6 +7065,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 a69dfe52..c5a85e82 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, "--- ---\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)