I see the standard way of exiting risc-v exception handler is update mepc to mepc+4 before mret.
These are not serious exception handlers; they are illustrative only — to show catching of exceptions at all, and returning back to the interrupted code without having done the actual exception processing needed for the given situation. Thus, the easiest thing to do to prevent an infinite loop is to simply skip past the offending instruction.
One of the few places where we advance the pc in order to return to the code that cause the exception is in handling an ecall
. As far as I know there is no compressed (16-bit) ecall
instruction.
Many resumable exceptions need to rerun the instruction that caused the exception — loads & stores that cause page faults (available in both 32-bit and 16-bit form), for example, need to re-execute once the page tables have been fixed (the page read in from disc and mapped into the user's address space).
Many other exceptions are not generally resumable.
However, emulation of an instruction requires knowing its size, as is the case with ecall
. if you choose to emulate, for example, misaligned memory accesses, you will indeed have to make a decision as to the size of the instruction, as emulating it means resuming past it. Also note that RISC V supports 16-bit, 32-bit, 48-bit, 64-bit and longer instructions, so an exception handler that is going to emulate instructions will need to be able to decode their length (only the instructions chosen for emulation, though).
The other thing to add is that the sample exception handlers you may be looking at are designed to work without the compressed instruction set, and since RVC is optional that is a reasonable design choice (though ideally, of course, would be clearly stated).