The VEX code for PUT(pc, <variable>) should specialize these cases in order to help debugging: 1) return from subroutine 2) multi-way branch inside a subroutine (C-language 'switch') 3) subroutine call indirect through a pointer-to-function 4) any other write to pc of a non-constant value. [There is no change for PUT(pc, <constant>).] Just allocate 4 more pseudo-registers in the thread state, and assign the **current** pc (not the destination) to the appropriate slot. And check that the value is sane: not zero in any case, and if extra debugging is requested then the destination should be mapped and executable, etc. The emulator doesn't have to be as dumb as the hardware. Instead, the emulator can tell you exactly where the problem was triggered. Here's an example of how this is helpful. ===== stomp.S for ARM(32-bit) _start: .globl _start // execution starts here mov r0,#0 // value to overwrite return address bl sub // call subroutine mov r7,#248 // NR_exit svc #0 sub: // IN: r0: value to clobber pc stmdb sp!,{lr} // save return address str r0,[sp] // clobber the return address ldmia sp!,{pc} // try to return ===== $ gcc -o stomp -nostartfiles -nostdlib stomp.S $ valgrind ./stomp ==19579== Memcheck, a memory error detector ==19579== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==19579== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info ==19579== Command: ./stomp ==19579== ==19579== Jump to the invalid address stated on the next line ==19579== at 0x0: ??? ==19579== Address 0x0 is not stack'd, malloc'd or (recently) free'd ==19579== ==== SB 1 (evchecks 1) [tid 1] 0x0 UNKNOWN_FUNCTION UNKNOWN_OBJECT+0x0 ==19579== ==19579== Process terminating with default action of signal 11 (SIGSEGV): dumping core ==19579== Bad permissions for mapped region at address 0x0 ==19579== at 0x0: ??? ==19579== ==19579== HEAP SUMMARY: ==19579== in use at exit: 0 bytes in 0 blocks ==19579== total heap usage: 0 allocs, 0 frees, 0 bytes allocated ==19579== ==19579== All heap blocks were freed -- no leaks are possible ==19579== ==19579== For counts of detected and suppressed errors, rerun with: -v ==19579== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0) Segmentation fault (core dumped) $ ===== All that output, but no useful information: no hint of the pc just before it became 0. Instead, VEX should recognize "ldmia sp!,{pc}" as return-from-subroutine, and save the address of the ldmia in the new pseduo-register for "address of most recent RETURN". Then when extra debugging is requested a helper can check the new value of pc; and in any case the error diagnostic for "bad pc" can print the most recent locations that wrote a variable value into pc. This can save hours of debugging time.