grab their return values.
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@58
/* Assembly code stubs make these requests ... */
#define VG_USERREQ__SIGNAL_RETURNS 0x4001
-#define VG_USERREQ__SHUTDOWN_VALGRIND 0x4002
+#define VG_USERREQ__PTHREAD_RETURNS 0x4002
+#define VG_USERREQ__SHUTDOWN_VALGRIND 0x4003
#endif /* ndef __VG_INCLUDE_H */
.text
+
+.global VG_(pthreadreturn_bogusRA)
+VG_(pthreadreturn_bogusRA):
+ subl $20, %esp # allocate arg block
+ movl %esp, %edx # %edx == &_zzq_args[0]
+ movl $VG_USERREQ__PTHREAD_RETURNS, 0(%edx) # request
+ movl %eax, 4(%edx) # arg1 == thread return value
+ movl $0, 8(%edx) # arg2
+ movl $0, 12(%edx) # arg3
+ movl $0, 16(%edx) # arg4
+ movl %edx, %eax
+ # and now the magic sequence itself:
+ roll $29, %eax
+ roll $3, %eax
+ rorl $27, %eax
+ rorl $5, %eax
+ roll $13, %eax
+ roll $19, %eax
+ # should never get here
+ pushl $pthreadreturn_bogusRA_panic_msg
+ call VG_(panic)
+
+.data
+pthreadreturn_bogusRA_panic_msg:
+.ascii "vg_pthreadreturn_bogusRA: VG_USERREQ__PTHREAD_RETURNS was missed"
+.byte 0
+.text
+
+
+
+
/* ------------------ REAL CPU HELPERS ------------------ */
/* The rest of this lot run on the real CPU. */
#define VG_USERREQ__PTHREAD_CREATE 0x3001
-#define VG_USERREQ__PTHREAD_CREATE_BOGUSRA 0x3002
-#define VG_USERREQ__PTHREAD_JOIN 0x3003
-#define VG_USERREQ__PTHREAD_GET_THREADID 0x3004
-#define VG_USERREQ__PTHREAD_MUTEX_INIT 0x3005
-#define VG_USERREQ__PTHREAD_MUTEX_LOCK 0x3006
-#define VG_USERREQ__PTHREAD_MUTEX_UNLOCK 0x3007
-#define VG_USERREQ__PTHREAD_MUTEX_DESTROY 0x3008
-#define VG_USERREQ__PTHREAD_CANCEL 0x3009
+#define VG_USERREQ__PTHREAD_JOIN 0x3002
+#define VG_USERREQ__PTHREAD_GET_THREADID 0x3003
+#define VG_USERREQ__PTHREAD_MUTEX_INIT 0x3004
+#define VG_USERREQ__PTHREAD_MUTEX_LOCK 0x3005
+#define VG_USERREQ__PTHREAD_MUTEX_UNLOCK 0x3006
+#define VG_USERREQ__PTHREAD_MUTEX_DESTROY 0x3007
+#define VG_USERREQ__PTHREAD_CANCEL 0x3008
/*
In vg_constants.h:
#define VG_USERREQ__SIGNAL_RETURNS 0x4001
-#define VG_USERREQ__SHUTDOWN_VALGRIND 0x4002
+#define VG_USERREQ__PTHREAD_RETURNS 0x4002
+#define VG_USERREQ__SHUTDOWN_VALGRIND 0x4003
*/
extern void VG_(helper_value_check1_fail);
extern void VG_(helper_value_check0_fail);
-/* NOT A FUNCTION; a bogus RETURN ADDRESS. */
+/* NOT FUNCTIONS; these are bogus RETURN ADDRESS. */
extern void VG_(signalreturn_bogusRA)( void );
+extern void VG_(pthreadreturn_bogusRA)( void );
/* ---------------------------------------------------------------------
- signals interrupting read/write and nanosleep, and take notice
of SA_RESTART or not
-- return bogus RA: %EAX trashed, so pthread_joiner gets nonsense
- exit codes
-
- when a thread is done mark its stack as noaccess
- make signal return and .fini call be detected via request mechanism
typedef unsigned long int pthread_t;
*/
-/* RUNS ON SIMD CPU!
- This is the return address that pthread_create uses.
-*/
-static
-void do_pthread_create_bogusRA ( void )
-{
- /* Tell the scheduler that this thread has returned. */
- Int res;
- VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
- VG_USERREQ__PTHREAD_CREATE_BOGUSRA,
- 0, 0, 0, 0);
- VG_(panic)("do_pthread_create_bogusRA: shouldn't be still alive!");
-}
-
static
void do_pthread_cancel ( ThreadId tid_canceller,
print_sched_event(tid_cancellee, msg_buf);
}
vg_threads[tid_cancellee].m_eax = (UInt)PTHREAD_CANCELED;
- vg_threads[tid_cancellee].m_eip = (UInt)&do_pthread_create_bogusRA;
+ vg_threads[tid_cancellee].m_eip = (UInt)&VG_(pthreadreturn_bogusRA);
vg_threads[tid_cancellee].status = VgTs_Runnable;
}
/* Thread tid is exiting, by returning from the function it was
- created with. The main complication here is to resume any thread
- waiting to join with this one. */
+ created with. Or possibly due to pthread_exit or cancellation.
+ The main complication here is to resume any thread waiting to join
+ with this one. */
static
-void do_pthread_create_exit_by_returning ( ThreadId tid )
+void handle_pthread_return ( ThreadId tid, void* retval )
{
ThreadId jnr; /* joiner, the thread calling pthread_join. */
UInt* jnr_args;
vg_assert(tid >= 0 && tid < VG_N_THREADS);
vg_assert(vg_threads[tid].status != VgTs_Empty);
- vg_threads[tid].retval = (void*)vg_threads[tid].m_eax;
+ vg_threads[tid].retval = retval;
if (vg_threads[tid].joiner == VG_INVALID_THREADID) {
/* No one has yet done a join on me */
/* push (magical) return address */
vg_threads[tid].m_esp -= 4;
- * (UInt*)(vg_threads[tid].m_esp) = (UInt)do_pthread_create_bogusRA;
+ * (UInt*)(vg_threads[tid].m_esp) = (UInt)VG_(pthreadreturn_bogusRA);
if (VG_(clo_instrument))
VGM_(make_readable)( vg_threads[tid].m_esp, 2 * 4 );
(void*)arg[4] );
break;
- case VG_USERREQ__PTHREAD_CREATE_BOGUSRA:
- do_pthread_create_exit_by_returning( tid );
+ case VG_USERREQ__PTHREAD_RETURNS:
+ handle_pthread_return( tid, (void*)arg[1] );
break;
case VG_USERREQ__PTHREAD_JOIN:
/* Assembly code stubs make these requests ... */
#define VG_USERREQ__SIGNAL_RETURNS 0x4001
-#define VG_USERREQ__SHUTDOWN_VALGRIND 0x4002
+#define VG_USERREQ__PTHREAD_RETURNS 0x4002
+#define VG_USERREQ__SHUTDOWN_VALGRIND 0x4003
#endif /* ndef __VG_INCLUDE_H */
.text
+
+.global VG_(pthreadreturn_bogusRA)
+VG_(pthreadreturn_bogusRA):
+ subl $20, %esp # allocate arg block
+ movl %esp, %edx # %edx == &_zzq_args[0]
+ movl $VG_USERREQ__PTHREAD_RETURNS, 0(%edx) # request
+ movl %eax, 4(%edx) # arg1 == thread return value
+ movl $0, 8(%edx) # arg2
+ movl $0, 12(%edx) # arg3
+ movl $0, 16(%edx) # arg4
+ movl %edx, %eax
+ # and now the magic sequence itself:
+ roll $29, %eax
+ roll $3, %eax
+ rorl $27, %eax
+ rorl $5, %eax
+ roll $13, %eax
+ roll $19, %eax
+ # should never get here
+ pushl $pthreadreturn_bogusRA_panic_msg
+ call VG_(panic)
+
+.data
+pthreadreturn_bogusRA_panic_msg:
+.ascii "vg_pthreadreturn_bogusRA: VG_USERREQ__PTHREAD_RETURNS was missed"
+.byte 0
+.text
+
+
+
+
/* ------------------ REAL CPU HELPERS ------------------ */
/* The rest of this lot run on the real CPU. */
#define VG_USERREQ__PTHREAD_CREATE 0x3001
-#define VG_USERREQ__PTHREAD_CREATE_BOGUSRA 0x3002
-#define VG_USERREQ__PTHREAD_JOIN 0x3003
-#define VG_USERREQ__PTHREAD_GET_THREADID 0x3004
-#define VG_USERREQ__PTHREAD_MUTEX_INIT 0x3005
-#define VG_USERREQ__PTHREAD_MUTEX_LOCK 0x3006
-#define VG_USERREQ__PTHREAD_MUTEX_UNLOCK 0x3007
-#define VG_USERREQ__PTHREAD_MUTEX_DESTROY 0x3008
-#define VG_USERREQ__PTHREAD_CANCEL 0x3009
+#define VG_USERREQ__PTHREAD_JOIN 0x3002
+#define VG_USERREQ__PTHREAD_GET_THREADID 0x3003
+#define VG_USERREQ__PTHREAD_MUTEX_INIT 0x3004
+#define VG_USERREQ__PTHREAD_MUTEX_LOCK 0x3005
+#define VG_USERREQ__PTHREAD_MUTEX_UNLOCK 0x3006
+#define VG_USERREQ__PTHREAD_MUTEX_DESTROY 0x3007
+#define VG_USERREQ__PTHREAD_CANCEL 0x3008
/*
In vg_constants.h:
#define VG_USERREQ__SIGNAL_RETURNS 0x4001
-#define VG_USERREQ__SHUTDOWN_VALGRIND 0x4002
+#define VG_USERREQ__PTHREAD_RETURNS 0x4002
+#define VG_USERREQ__SHUTDOWN_VALGRIND 0x4003
*/
extern void VG_(helper_value_check1_fail);
extern void VG_(helper_value_check0_fail);
-/* NOT A FUNCTION; a bogus RETURN ADDRESS. */
+/* NOT FUNCTIONS; these are bogus RETURN ADDRESS. */
extern void VG_(signalreturn_bogusRA)( void );
+extern void VG_(pthreadreturn_bogusRA)( void );
/* ---------------------------------------------------------------------
- signals interrupting read/write and nanosleep, and take notice
of SA_RESTART or not
-- return bogus RA: %EAX trashed, so pthread_joiner gets nonsense
- exit codes
-
- when a thread is done mark its stack as noaccess
- make signal return and .fini call be detected via request mechanism
typedef unsigned long int pthread_t;
*/
-/* RUNS ON SIMD CPU!
- This is the return address that pthread_create uses.
-*/
-static
-void do_pthread_create_bogusRA ( void )
-{
- /* Tell the scheduler that this thread has returned. */
- Int res;
- VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
- VG_USERREQ__PTHREAD_CREATE_BOGUSRA,
- 0, 0, 0, 0);
- VG_(panic)("do_pthread_create_bogusRA: shouldn't be still alive!");
-}
-
static
void do_pthread_cancel ( ThreadId tid_canceller,
print_sched_event(tid_cancellee, msg_buf);
}
vg_threads[tid_cancellee].m_eax = (UInt)PTHREAD_CANCELED;
- vg_threads[tid_cancellee].m_eip = (UInt)&do_pthread_create_bogusRA;
+ vg_threads[tid_cancellee].m_eip = (UInt)&VG_(pthreadreturn_bogusRA);
vg_threads[tid_cancellee].status = VgTs_Runnable;
}
/* Thread tid is exiting, by returning from the function it was
- created with. The main complication here is to resume any thread
- waiting to join with this one. */
+ created with. Or possibly due to pthread_exit or cancellation.
+ The main complication here is to resume any thread waiting to join
+ with this one. */
static
-void do_pthread_create_exit_by_returning ( ThreadId tid )
+void handle_pthread_return ( ThreadId tid, void* retval )
{
ThreadId jnr; /* joiner, the thread calling pthread_join. */
UInt* jnr_args;
vg_assert(tid >= 0 && tid < VG_N_THREADS);
vg_assert(vg_threads[tid].status != VgTs_Empty);
- vg_threads[tid].retval = (void*)vg_threads[tid].m_eax;
+ vg_threads[tid].retval = retval;
if (vg_threads[tid].joiner == VG_INVALID_THREADID) {
/* No one has yet done a join on me */
/* push (magical) return address */
vg_threads[tid].m_esp -= 4;
- * (UInt*)(vg_threads[tid].m_esp) = (UInt)do_pthread_create_bogusRA;
+ * (UInt*)(vg_threads[tid].m_esp) = (UInt)VG_(pthreadreturn_bogusRA);
if (VG_(clo_instrument))
VGM_(make_readable)( vg_threads[tid].m_esp, 2 * 4 );
(void*)arg[4] );
break;
- case VG_USERREQ__PTHREAD_CREATE_BOGUSRA:
- do_pthread_create_exit_by_returning( tid );
+ case VG_USERREQ__PTHREAD_RETURNS:
+ handle_pthread_return( tid, (void*)arg[1] );
break;
case VG_USERREQ__PTHREAD_JOIN: