The attached testcase crashes when I run it under valgrind on i386 (on FreeBSD 8.2):
The crash is here (which happens when pthread_cancel tries to signal the second thread to exit):
vex x86->IR: unhandled instruction bytes: 0xF 0xB 0x90 0x55 ==30076== valgrind: Unrecognised instruction at address 0x38044a3d. ==30076== at 0x38044A3D: ??? (m_trampoline.S:698) ==30076== by 0x69A29: ??? (in /lib/libthr.so.3) ==30076== by 0x69B3B: pthread_cond_wait (in /lib/libthr.so.3) ==30076== by 0x8048695: thread_start (sigreturn.c:12) ==30076== by 0x616E4: ??? (in /lib/libthr.so.3)
VG_(x86_freebsd_SUBST_FOR_sigreturn): lea 0x14(%esp), %eax /* args to sigreturn(ucontext_t *) */ pushl %eax pushl %eax /* fake return addr */ /* movl 0x44(%eax), %gs ; restore %gs, not done by sigreturn */ movl $__NR_fake_sigreturn, %eax int $0x80 ud2 /* line 698 */
I've done some digging and put some printfs in, and it appears that x86_freebsd_SUBST_FOR_sigreturn is using the wrong offset from %esp to find the ucontext_t*. I put one printf in build_sigframe just after synth_ucontext is called, and another two in PRE(sys_fake_sigreturn). The printfs demonstrate that fake_sigreturn is called with the wrong pointer (it's always off by 8 bytes for me).
synthesized ucontext 0x9F9FE590 (len=640) sys_fake_sigreturn ( 0x9f9fe588 ) sys_fake_sigreturn (len=-1616908584 expected=640)
I can fix the crash by changing to:
lea 0x1c(%esp), %eax
But this sigreturn stuff looks like pure magic to me so I have no confidence that is actually the right fix.