diff --git a/arch/arm64/src/common/arm64_fatal.c b/arch/arm64/src/common/arm64_fatal.c index cd310ba11cf..aabeafc1fed 100644 --- a/arch/arm64/src/common/arm64_fatal.c +++ b/arch/arm64/src/common/arm64_fatal.c @@ -357,20 +357,30 @@ static int arm64_el1_bti(uint64_t *regs, uint64_t esr) static int arm64_el1_undef(uint64_t *regs, uint64_t esr) { - uint32_t insn; uint64_t elr = regs[REG_ELR]; + uint32_t insn; + int i; - serr("Undefined instruction at 0x%" PRIx64 ", dump:\n", elr); - memcpy(&insn, (void *)(elr - 8), 4); - serr("0x%" PRIx64 " : 0x%" PRIx32 "\n", elr - 8, insn); - memcpy(&insn, (void *)(elr - 4), 4); - serr("0x%" PRIx64 " : 0x%" PRIx32 "\n", elr - 4, insn); - memcpy(&insn, (void *)(elr), 4); - serr("0x%" PRIx64 " : 0x%" PRIx32 "\n", elr, insn); - memcpy(&insn, (void *)(elr + 4), 4); - serr("0x%" PRIx64 " : 0x%" PRIx32 "\n", elr + 4, insn); - memcpy(&insn, (void *)(elr + 8), 4); - serr("0x%" PRIx64 " : 0x%" PRIx32 "\n", elr + 8, insn); + serr("Undefined instruction at 0x%" PRIx64 "\n", elr); + + /* Only dump the surrounding words for an exception taken at EL1, where + * ELR is kernel code that was just fetched. From EL0, ELR is a user + * address and the words around it can be in a page that is not mapped. + * A fault here is a nested exception, which trips the DEBUGASSERT in + * arm64_fatal_handler() before the user fault is reported. + */ + + if ((regs[REG_SPSR] & SPSR_MODE_MASK) == SPSR_MODE_EL0T) + { + return -1; + } + + serr("dump:\n"); + for (i = -8; i <= 8; i += 4) + { + memcpy(&insn, (FAR void *)(elr + i), sizeof(insn)); + serr("0x%" PRIx64 " : 0x%" PRIx32 "\n", elr + i, insn); + } return -1; } @@ -640,6 +650,7 @@ uint64_t *arm64_fatal_handler(uint64_t *regs) ((tcb->flags & TCB_FLAG_SYSCALL) == 0) && ((regs[REG_SPSR] & SPSR_MODE_MASK) == SPSR_MODE_EL0T)) { + struct tcb_s *ptcb; uint64_t esr; const char *reason; const char *desc; @@ -659,10 +670,17 @@ uint64_t *arm64_fatal_handler(uint64_t *regs) desc = ""; } - _alert("PANIC: Unhandled user exception in PID %d: %s\n", + /* This is not a panic: the offending task is terminated and the + * system continues. Say so in the same words as risc-v, and leave + * the register dump to the paths that are fatal. + */ + + ptcb = nxsched_get_tcb(tcb->group->tg_pid); + + _alert("Segmentation fault in %s (PID %d: %s)\n", + ptcb != NULL ? get_task_name(ptcb) : "", tcb->pid, get_task_name(tcb)); _alert("Reason: %s - %s\n", reason, desc); - up_dump_register(regs); tcb->flags |= TCB_FLAG_FORCED_CANCEL;