Visitar URL original
arch/arm64: Report a recovered user fault as a segmentation fault. by casaroli · Pull Request #20510 · apache/nuttx · GitHub
Skip to content

arch/arm64: Report a recovered user fault as a segmentation fault. - #20510

Merged
acassis merged 2 commits into
apache:masterfrom
casaroli:arm64-user-fault-report
Oct 8, 2026
Merged

acassis merged 2 commits into
apache:masterfrom
casaroli:arm64-user-fault-report

Conversation

@casaroli

@casaroli casaroli commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

Summary

On arm64, a user fault that the kernel recovers from looks like a kernel failure. arm64_fatal_handler() prints "PANIC: Unhandled user exception" and a full register dump, but it then only kills the offending task with SIGSEGV. This change prints "Segmentation fault in (PID n: )", the same message as risc-v, and keeps the register dump for the fatal path.

arm64_el1_undef() also reads the words around ELR. For an exception from EL0 these are user addresses that can be in an unmapped page. A fault there is a nested exception that trips the DEBUGASSERT in arm64_fatal_handler(). This change skips the dump for EL0 and keeps it for EL1.

The first commit fixes an older nxstyle error in arm64_fatal.c, because CI checks every file that a change touches. It changes whitespace only.

Impact

Only the console output changes, for faults from EL0, which happen in kernel builds. Recovery behaviour does not change. Kernel faults still panic with the register dump.

Testing

QEMU, qemu-armv8a:knsh with apps examples/sandbox and ostest, Arm GNU Toolchain 14.2.rel1 (aarch64-none-elf).

Before (master), sandbox 0x40000000:

arm64_exception_handler: ESR_ELn: 0x9200000e
arm64_fatal_handler: PANIC: Unhandled user exception in PID 10: sandbox
arm64_fatal_handler: Reason: DABT (lower EL) - Data Abort from a lower Exception level, that might be using AArch32 or AArch64
up_dump_register: stack = 0x402dfcc0
up_dump_register: x0:   0x0                 x1:   0x7ffffffe
...
sandbox: the offender exited with status 2816

After:

arm64_exception_handler: ESR_ELn: 0x9200000e
arm64_fatal_handler: Segmentation fault in sandbox (PID 10: sandbox)
arm64_fatal_handler: Reason: DABT (lower EL) - Data Abort from a lower Exception level, that might be using AArch32 or AArch64
sandbox: the offender exited with status 2816
sandbox: CONTAINED - 1 target(s), every check passed

An undefined instruction at EL0 (a local test probe, not part of this PR) now prints the following, and the shell survives:

arm64_el1_undef: Undefined instruction at 0xc00023bc
arm64_fatal_handler: Segmentation fault in sandbox (PID 21: sandbox)

On today's master I could not make the dump read an unmapped page: the word before the start of the text was mapped. The skip for EL0 prevents that case.

ostest exits with status 0 before and after this change.

tools/checkpatch.sh -c -u -m -g passes.

nxstyle reports "Bad right brace alignment" for the closing brace of the
switch in arm64_el1_exception_handler().  Indent it like the switch,
because CI checks every file that a change touches.

No functional change.  The change is whitespace only.

Assisted-by: Claude Code:claude-opus-5-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
Two problems in the same path make a contained user fault look like a
kernel failure.

arm64_el1_undef() dumps the words around ELR.  For an exception taken
from EL0, ELR is a user address, and the words around it can be in a
page that is not mapped.  Then the memcpy faults inside the fatal
handler.  That nested exception trips the DEBUGASSERT in
arm64_fatal_handler(), and the fault that the user took is not reported.
The ESR that tells what happened is lost.  Skip the dump when the
exception came from EL0.  At EL1 the address is kernel code that was
just fetched, so keep the dump there.

arm64_fatal_handler() then reports the fault that it recovers from as
"PANIC: Unhandled user exception", followed by a full register dump.
But there is no panic: it sets TCB_FLAG_FORCED_CANCEL, changes ELR to
_exit(SIGSEGV), and the system continues without the offending task.
Print "Segmentation fault in <process> (PID n: <thread>)" instead, the
same message as risc-v, and keep the register dump for the
PANIC_WITH_REGS() path, which is fatal.

Tested on QEMU qemu-armv8a:knsh with examples/sandbox and ostest.  A
user read or write of kernel memory (0x40000000) now prints:

  arm64_exception_handler: ESR_ELn: 0x9200000e
  arm64_fatal_handler: Segmentation fault in sandbox (PID 10: sandbox)
  arm64_fatal_handler: Reason: DABT (lower EL) - Data Abort from a ...
  sandbox: the offender exited with status 2816

Before this change it printed "PANIC: Unhandled user exception" and a
register dump for the same recovered fault.  An undefined instruction
at EL0 now prints "Undefined instruction at <ELR>" without the dump,
then the same segmentation fault message.  The shell survives in all
cases, and ostest exits with status 0 before and after this change.

Assisted-by: Claude Code:claude-opus-5-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
@github-actions github-actions Bot added Arch: arm64 Issues related to ARM64 (64-bit) architecture Size: S The size of the change in this PR is small labels Oct 8, 2026
@github-actions

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown

MemBrowse Memory Report

qemu-armv8a

@acassis
acassis merged commit f17c74c into apache:master Oct 8, 2026
25 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Arch: arm64 Issues related to ARM64 (64-bit) architecture Size: S The size of the change in this PR is small

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants