I come at this from an architectural understanding of micro-controllers and processors. College level texts probably have this well covered these days. Perhaps Patterson/Hennessy ARM Architecture type thing, or some of Furber's original works.
You probably want to start by understanding how the micro-controller stacks context for interrupts and exceptions, for this a more generalized coverage might be found in books on the Cortex-Mx by Joseph Yiu, and the ST Programming Manuals for the M3/M4
ARM also has Technical Reference Manuals (TRM) explaining how the cores function.
If you understand how the context is saved, you can fish around in there, see where the program counter (PC), what instuction is there, and modify the PC and other registers, or emulate instructions, or retry them. The try/catch type stuff takes a narrow range of potential PC values in a region of interest, and then diverts execution, at the same stack scope/depth, to some code that handles the "what to do if that just failed" scenario. How polished or crude this is depends on your desire to do system level coding, in the simplest case you could handle one particular instruction you know might fail, and then just step beyond it replacing R0 (or whatever) with the content you want, or that flags failure, perhaps in a variable that you can check later.
https://www.st.com/resource/en/programming_manual/dm00046982-stm32-cortex-m4-mcus-and-mpus-programming-manual-stmicroelectronics.pdf
See also the hard fault routines I published in the past for outputting useful diagnostic information. Imagine how you can modify the PC, or other registers, in that context and return();