nuttx icon indicating copy to clipboard operation
nuttx copied to clipboard

Adding signal handing for SEGV/BUS/...

Open nealef opened this issue 2 years ago • 4 comments

I have been investigating signal handling in NuttX for SEGV/BUS/… for armv7-m. I have got some PoC code written (for a backlevel NuttX) that, while I’m in the interrupt handler, will schedule a signal handler. However, when it returns from the interrupt in exception_common and the next instruction is executed:

343		bx		r14						/* And return */
(gdb) p $r14
$1 = 0xfffffffd
(gdb) stepi
up_sigdeliver () at armv7-m/up_sigdeliver.c:74
74	  struct tcb_s  *rtcb = this_task();
(gdb) bt
#0  up_sigdeliver () at armv7-m/up_sigdeliver.c:74
#1  <signal handler called>

I get a hardfault with a cfault of 0x1 (instruction access violation) and an hfault of 0x40000000 (“FORCED”):

[    9.439000] [12] up_hardfault:   IRQ: 3 regs: 0xc0327078
[    9.439000] [12] up_hardfault:   BASEPRI: 00000080 PRIMASK: 00000000 IPSR: 00000003 CONTROL: 00000001
[    9.439000] [12] up_hardfault:   CFAULTS: 00000001 HFAULTS: 40000000 DFAULTS: 0000000b BFAULTADDR: 00000000 AFAULTS: 00000000

The registers at the time of the fault:

lr             0xfffffff9          0xfffffff9
pc             0x8161ef0           0x8161ef0 <up_sigdeliver>
xPSR           0x1000000           0x1000000
fpscr          0x80000010          0x80000010
msp            0xc03275e8          0xc03275e8
psp            0xc03276b8          0xc03276b8
primask        0x0                 0x0
basepri        0x80                0x80
faultmask      0x0                 0x0
control        0x3                 0x3

In the interrupt handler I thought I was clearing/acknowledging the interrupt in the correct way in up_memfault:

  uint32_t cfsr = getreg32(NVIC_CFAULTS);
  uint32_t *mfsr = (uintptr_t) NVIC_CFAULTS;
:
          *mfsr |= cfsr;        /* Acknowledge interrupt */

I have looked through the ARM-7M Architecture Reference but I can’t work out what the proper way of exiting the handler is (assuming this is the root cause of the problem).

nealef avatar Oct 11 '23 17:10 nealef

@masayuki2009 @pkarashchenko @xiaoxiang781216 any idea why issue is happening?

acassis avatar Oct 12 '23 21:10 acassis

@nealef do you want to continue after memfault? the default memfault handler doesn't support this feature yet, I think you may need skip the broken instruction before return.

xiaoxiang781216 avatar Oct 18 '23 18:10 xiaoxiang781216

@xiaoxiang781216 I've scheduled a signal handler (if one exists for that tid). If not we panic as before. It's when we leave exception_common that there's a problem.

nealef avatar Oct 19 '23 03:10 nealef

@nealef do you want to continue after memfault? the default memfault handler doesn't support this feature yet, I think you may need skip the broken instruction before return.

I suppose I should ask a more fundamental question: when a userland program issues a signal() what is the mechanism of returning from that syscall after the kernel has scheduled a signal handler? That is, the syscall is handled by checking if there is a corresponding signal handler and if so using nxsig_tcbdispatch() to schedule the handler it then returns from the syscall. What is the mechanism used to return from that call?

As you can see in my case when I leave exception_common the up_sigdeliver() function is what gets branched to. I am assuming this guy is supposed to run (in my configuration) in protected mode but is in userland mode instead (for wont of a better term). up_sigdeliver (or arm_sigdeliver as it is now) appears to do the returning to userland. So should my code set up the return register to be 0xfffffff[1|9] so that the signal deliver is invoked in the correct mode?

nealef avatar Dec 22 '23 06:12 nealef