From: Nicholas Nethercote Date: Mon, 19 May 2003 15:04:06 +0000 (+0000) Subject: This commit fixes up the handling of shadow registers quite a bit. X-Git-Tag: svn/VALGRIND_2_0_0~142 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=136a5e69d5a57075218eccde7093ec41741c8e13;p=thirdparty%2Fvalgrind.git This commit fixes up the handling of shadow registers quite a bit. Removed the SK_(written_shadow_regs_values)() function. Instead, skins that use shadow regs can track the `post_regs_write_init' event, and set the shadow regs from within it. This is much more flexible, since it allows each shadow register to be set to a separate value if necessary. It also matches the new shadow-reg-change events described below. In the core, there were some places where the shadow regs were changed, and skins had no way of knowing about it, which was a problem for some skins. So I added a bunch of new events to notify skins about these: post_reg_write_syscall_return post_reg_write_deliver_signal post_reg_write_pthread_return post_reg_write_clientreq_return post_reg_write_clientcall_return Any skin that uses shadow regs should almost certainly track these events. The post_reg_write_clientcall_return allows a skin to tailor the shadow reg of the return value of a CLIENTCALL'd function appropriately; this is especially useful when replacing malloc() et al. Defined some macros that should be used *whenever the core changes the value of a shadow register* : SET_SYSCALL_RETVAL SET_SIGNAL_EDX (maybe should be SET_SIGNAL_RETVAL? ... not sure) SET_SIGNAL_ESP SET_CLREQ_RETVAL SET_CLCALL_RETVAL SET_PTHREQ_ESP SET_PTHREQ_RETVAL These replace all the old SET_EAX and SET_EDX macros, and are added in a few places where the shadow-reg update was missing. Added shadow registers to the machine state saved/restored when signal handlers are pushed/popped (they were missing). Added skin-callable functions VG_(set_return_from_syscall_shadow)() and VG_(get_exit_status_shadow)() which are useful and abstract away from which registers the results are in. Also, poll() changes %ebx (it's first argument) sometimes, I don't know why. So we notify skins about that too (with the `post_reg_write_syscall_return' event, which isn't ideal I guess...) git-svn-id: svn://svn.valgrind.org/valgrind/trunk@1642 --- diff --git a/coregrind/vg_default.c b/coregrind/vg_default.c index 6aea85e25d..b74c74076e 100644 --- a/coregrind/vg_default.c +++ b/coregrind/vg_default.c @@ -158,17 +158,6 @@ void SK_(discard_basic_block_info)(Addr a, UInt size) } -/* --------------------------------------------------------------------- - For throwing out basic block level info when code is invalidated - ------------------------------------------------------------------ */ - -__attribute__ ((weak)) -void SK_(written_shadow_regs_values)(UInt* gen_reg, UInt* eflags) -{ - non_fund_panic("SK_(written_shadow_regs_values)"); -} - - /* --------------------------------------------------------------------- Command line arg template function ------------------------------------------------------------------ */ diff --git a/coregrind/vg_from_ucode.c b/coregrind/vg_from_ucode.c index b285e1db0c..2236a47d27 100644 --- a/coregrind/vg_from_ucode.c +++ b/coregrind/vg_from_ucode.c @@ -2952,6 +2952,11 @@ void VG_(set_shadow_archreg) ( UInt archreg, UInt val ) VG_(baseBlock)[ shadow_reg_index(archreg) ] = val; } +void VG_(set_shadow_eflags) ( UInt val ) +{ + VG_(baseBlock)[ VGOFF_(sh_eflags) ] = val; +} + UInt VG_(get_thread_shadow_archreg) ( ThreadId tid, UInt archreg ) { ThreadState* tst; diff --git a/coregrind/vg_include.h b/coregrind/vg_include.h index 206c6d845d..f6cc1a5d88 100644 --- a/coregrind/vg_include.h +++ b/coregrind/vg_include.h @@ -353,6 +353,16 @@ typedef void (*post_mem_write) ( Addr a, UInt size ); + /* Register events */ + void (*post_regs_write_init) ( void ); + void (*post_reg_write_syscall_return) ( ThreadId tid, UInt reg ); + void (*post_reg_write_deliver_signal) ( ThreadId tid, UInt reg ); + void (*post_reg_write_pthread_return) ( ThreadId tid, UInt reg ); + void (*post_reg_write_clientreq_return) ( ThreadId tid, UInt reg ); + void (*post_reg_write_clientcall_return) ( ThreadId tid, UInt reg, + Addr f ); + + /* Scheduler events (not exhaustive) */ void (*thread_run) ( ThreadId tid ); @@ -923,24 +933,38 @@ extern Int VG_(longjmpd_on_signal); (VG_AR_CLIENT_STACKBASE_REDZONE_SZW * VKI_BYTES_PER_WORD) /* Junk to fill up a thread's shadow regs with when shadow regs aren't - * being used. */ + being used. */ #define VG_UNUSED_SHADOW_REG_VALUE 0x27182818 +/* For sanity checking: if this ends up in a thread's shadow regs when + shadow regs aren't being used, something went wrong. */ +#define VG_USED_SHADOW_REG_VALUE 0x31415927 + +/* Write a value to a client's thread register, and shadow (if necessary) */ +#define SET_THREAD_REG( zztid, zzval, zzreg, zzREG, zzevent, zzargs... ) \ + do { VG_(threads)[zztid].m_##zzreg = (zzval); \ + VG_TRACK( zzevent, zztid, R_##zzREG, ##zzargs ); \ + } while (0) -/* What we set a shadow register to when written by SET_EAX and similar - * things. */ -extern UInt VG_(written_shadow_reg); +#define SET_SYSCALL_RETVAL(zztid, zzval) \ + SET_THREAD_REG(zztid, zzval, eax, EAX, post_reg_write_syscall_return) -/* Write a value to the client's %EDX (request return value register) - and set the shadow to indicate it is defined. */ -#define SET_EDX(zztid, zzval) \ - do { VG_(threads)[zztid].m_edx = (zzval); \ - VG_(threads)[zztid].sh_edx = VG_(written_shadow_reg); \ - } while (0) +#define SET_SIGNAL_EDX(zztid, zzval) \ + SET_THREAD_REG(zztid, zzval, edx, EDX, post_reg_write_deliver_signal) -#define SET_EAX(zztid, zzval) \ - do { VG_(threads)[zztid].m_eax = (zzval); \ - VG_(threads)[zztid].sh_eax = VG_(written_shadow_reg); \ - } while (0) +#define SET_SIGNAL_ESP(zztid, zzval) \ + SET_THREAD_REG(zztid, zzval, esp, ESP, post_reg_write_deliver_signal) + +#define SET_CLREQ_RETVAL(zztid, zzval) \ + SET_THREAD_REG(zztid, zzval, edx, EDX, post_reg_write_clientreq_return) + +#define SET_CLCALL_RETVAL(zztid, zzval, f) \ + SET_THREAD_REG(zztid, zzval, edx, EDX, post_reg_write_clientcall_return, f) + +#define SET_PTHREQ_ESP(zztid, zzval) \ + SET_THREAD_REG(zztid, zzval, esp, ESP, post_reg_write_pthread_return) + +#define SET_PTHREQ_RETVAL(zztid, zzval) \ + SET_THREAD_REG(zztid, zzval, edx, EDX, post_reg_write_pthread_return) /* This is or'd into a pthread mutex's __m_kind field if it is used @@ -1435,14 +1459,14 @@ extern void VG_(post_known_blocking_syscall)( ThreadId tid, Int syscallno, extern Bool VG_(is_kerror) ( Int res ); -#define KERNEL_DO_SYSCALL(thread_id, result_lvalue) \ - VG_(load_thread_state)(thread_id); \ - VG_(copy_baseBlock_to_m_state_static)(); \ - VG_(do_syscall)(); \ - VG_(copy_m_state_static_to_baseBlock)(); \ - VG_(save_thread_state)(thread_id); \ - VG_(threads)[thread_id].sh_eax = VG_(written_shadow_reg);\ - result_lvalue = VG_(threads)[thread_id].m_eax; +#define KERNEL_DO_SYSCALL(thread_id, result_lvalue) \ + VG_(load_thread_state)(thread_id); \ + VG_(copy_baseBlock_to_m_state_static)(); \ + VG_(do_syscall)(); \ + VG_(copy_m_state_static_to_baseBlock)(); \ + VG_(save_thread_state)(thread_id); \ + result_lvalue = VG_(threads)[thread_id].m_eax; \ + VG_TRACK( post_reg_write_syscall_return, thread_id, R_EAX ); /* --------------------------------------------------------------------- diff --git a/coregrind/vg_intercept.c b/coregrind/vg_intercept.c index 1f810e822d..d0f5724d4c 100644 --- a/coregrind/vg_intercept.c +++ b/coregrind/vg_intercept.c @@ -279,6 +279,7 @@ int VGR_(poll) (struct pollfd *__fds, nfds_t __nfds, int __timeout) VG_USERREQ__READ_MILLISECOND_TIMER, 0, 0, 0, 0); + /* CHECK SIZES FOR struct pollfd */ my_assert(sizeof(struct timeval) == sizeof(struct vki_timeval)); @@ -357,7 +358,6 @@ int VGR_(poll) (struct pollfd *__fds, nfds_t __nfds, int __timeout) return 0; } } - } } diff --git a/coregrind/vg_main.c b/coregrind/vg_main.c index 960fa75730..2390cd724d 100644 --- a/coregrind/vg_main.c +++ b/coregrind/vg_main.c @@ -390,9 +390,6 @@ static void vg_init_baseBlock ( void ) /* Initialise shadow regs */ if (VG_(needs).shadow_regs) { - UInt eflags; - - SK_(written_shadow_regs_values) ( & VG_(written_shadow_reg), & eflags ); VG_(baseBlock)[VGOFF_(sh_esp)] = VG_(baseBlock)[VGOFF_(sh_ebp)] = VG_(baseBlock)[VGOFF_(sh_eax)] = @@ -400,11 +397,9 @@ static void vg_init_baseBlock ( void ) VG_(baseBlock)[VGOFF_(sh_edx)] = VG_(baseBlock)[VGOFF_(sh_ebx)] = VG_(baseBlock)[VGOFF_(sh_esi)] = - VG_(baseBlock)[VGOFF_(sh_edi)] = VG_(written_shadow_reg); - VG_(baseBlock)[VGOFF_(sh_eflags)] = eflags; - - } else { - VG_(written_shadow_reg) = VG_UNUSED_SHADOW_REG_VALUE; + VG_(baseBlock)[VGOFF_(sh_edi)] = 0; + VG_(baseBlock)[VGOFF_(sh_eflags)] = 0; + VG_TRACK( post_regs_write_init ); } } diff --git a/coregrind/vg_needs.c b/coregrind/vg_needs.c index c5cb35746e..259e15ea58 100644 --- a/coregrind/vg_needs.c +++ b/coregrind/vg_needs.c @@ -95,6 +95,14 @@ VgTrackEvents VG_(track_events) = { .pre_mem_write = NULL, .post_mem_write = NULL, + /* Register events */ + .post_regs_write_init = NULL, + .post_reg_write_syscall_return = NULL, + .post_reg_write_deliver_signal = NULL, + .post_reg_write_pthread_return = NULL, + .post_reg_write_clientreq_return = NULL, + .post_reg_write_clientcall_return = NULL, + /* Scheduler events */ .thread_run = NULL, @@ -129,7 +137,8 @@ void VG_(sanity_check_needs) ( void) VG_(track_events).new_mem_stack_12 || VG_(track_events).new_mem_stack_16 || VG_(track_events).new_mem_stack_32) && - ! VG_(track_events).new_mem_stack) { + ! VG_(track_events).new_mem_stack) + { VG_(printf)("\nSkin error: one of the specialised `new_mem_stack_n'\n" "events tracked, but not the generic `new_mem_stack' one.\n"); VG_(skin_panic)("`new_mem_stack' should be defined\n"); @@ -140,12 +149,25 @@ void VG_(sanity_check_needs) ( void) VG_(track_events).die_mem_stack_12 || VG_(track_events).die_mem_stack_16 || VG_(track_events).die_mem_stack_32) && - ! VG_(track_events).die_mem_stack) { + ! VG_(track_events).die_mem_stack) + { VG_(printf)("\nSkin error: one of the specialised `die_mem_stack_n'\n" "events tracked, but not the generic `die_mem_stack' one.\n"); VG_(skin_panic)("`die_mem_stack' should be defined\n"); } + if ( (VG_(track_events).post_reg_write_syscall_return || + VG_(track_events).post_reg_write_deliver_signal || + VG_(track_events).post_reg_write_pthread_return || + VG_(track_events).post_reg_write_clientreq_return || + VG_(track_events).post_reg_write_clientcall_return) && + ! VG_(needs).shadow_regs) + { + VG_(printf)("\nSkin error: one of the `post_reg_write'\n" + "events tracked, but `shadow_regs' need not set.\n"); + VG_(skin_panic)("`shadow_regs' should be set\n"); + } + #undef CHECK_NOT #undef INVALID_Bool } @@ -232,6 +254,13 @@ TRACK(pre_mem_write, CorePart part, ThreadState* tst, Char* s, Addr a, UInt size) TRACK(post_mem_write, Addr a, UInt size) +TRACK(post_regs_write_init, void ); +TRACK(post_reg_write_syscall_return, ThreadId tid, UInt reg ); +TRACK(post_reg_write_deliver_signal, ThreadId tid, UInt reg ); +TRACK(post_reg_write_pthread_return, ThreadId tid, UInt reg ); +TRACK(post_reg_write_clientreq_return, ThreadId tid, UInt reg ); +TRACK(post_reg_write_clientcall_return, ThreadId tid, UInt reg, Addr f ); + TRACK(thread_run, ThreadId tid) TRACK(post_thread_create, ThreadId tid, ThreadId child) diff --git a/coregrind/vg_scheduler.c b/coregrind/vg_scheduler.c index ed4fcba83e..92c951baeb 100644 --- a/coregrind/vg_scheduler.c +++ b/coregrind/vg_scheduler.c @@ -160,7 +160,10 @@ static ThreadKeyState vg_thread_keys[VG_N_THREAD_KEYS]; typedef UInt ThreadKey; -UInt VG_(written_shadow_reg); +UInt VG_(syscall_altered_shadow_reg); +UInt VG_(signal_delivery_altered_shadow_reg); +UInt VG_(pthread_op_altered_shadow_reg); +UInt VG_(client_request_altered_shadow_reg); /* Forwards */ static void do_client_request ( ThreadId tid ); @@ -441,8 +444,6 @@ void VG_(load_thread_state) ( ThreadId tid ) VG_(baseBlock)[VGOFF_(sh_eflags)] = VG_(threads)[tid].sh_eflags; } else { /* Fields shouldn't be used -- check their values haven't changed. */ - /* Nb: they are written to by some macros like SET_EDX, but they - * should just write VG_UNUSED_SHADOW_REG_VALUE. */ vg_assert( VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_eax && VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_ebx && @@ -788,8 +789,7 @@ void handle_signal_return ( ThreadId tid ) vg_assert(VG_(is_valid_tid)(tid)); - /* Increment signal-returned counter. Used only to implement - pause(). */ + /* Increment signal-returned counter. Used only to implement pause(). */ VG_(threads)[tid].n_signals_returned++; restart_blocked_syscalls = VG_(signal_returns)(tid); @@ -803,9 +803,8 @@ void handle_signal_return ( ThreadId tid ) || VG_(threads)[tid].m_eax == __NR_write)) { /* read() or write() interrupted. Force a return with EINTR. */ cleanup_waiting_fd_table(tid); - VG_(threads)[tid].m_eax = -VKI_EINTR; + SET_SYSCALL_RETVAL(tid, -VKI_EINTR); VG_(threads)[tid].status = VgTs_Runnable; - if (VG_(clo_trace_sched)) { VG_(sprintf)(msg_buf, "read() / write() interrupted by signal; return EINTR" ); @@ -825,7 +824,7 @@ void handle_signal_return ( ThreadId tid ) rem->tv_sec = 0; rem->tv_nsec = 1; } - SET_EAX(tid, -VKI_EINTR); + SET_SYSCALL_RETVAL(tid, -VKI_EINTR); VG_(threads)[tid].status = VgTs_Runnable; return; } @@ -841,7 +840,7 @@ void handle_signal_return ( ThreadId tid ) static void sched_do_syscall ( ThreadId tid ) { - UInt saved_eax; + UInt saved_meax, saved_sheax; Int res, syscall_no; UInt fd; void* pre_res; @@ -908,7 +907,8 @@ void sched_do_syscall ( ThreadId tid ) pre_res = VG_(pre_known_blocking_syscall)(tid, syscall_no); /* This trashes the thread's %eax; we have to preserve it. */ - saved_eax = VG_(threads)[tid].m_eax; + saved_meax = VG_(threads)[tid].m_eax; + saved_sheax = VG_(threads)[tid].sh_eax; KERNEL_DO_SYSCALL(tid,res); /* Restore original blockfulness of the fd. */ @@ -936,11 +936,13 @@ void sched_do_syscall ( ThreadId tid ) /* It would have blocked. First, restore %EAX to what it was before our speculative call. */ - VG_(threads)[tid].m_eax = saved_eax; + saved_meax = VG_(threads)[tid].m_eax = saved_meax; + saved_sheax = VG_(threads)[tid].sh_eax = saved_sheax; + /* Put this fd in a table of fds on which we are waiting for completion. The arguments for select() later are constructed from this table. */ - add_waiting_fd(tid, fd, saved_eax /* which holds the syscall # */, + add_waiting_fd(tid, fd, saved_meax /* which holds the syscall # */, pre_res); /* Deschedule thread until an I/O completion happens. */ VG_(threads)[tid].status = VgTs_WaitFD; @@ -948,7 +950,6 @@ void sched_do_syscall ( ThreadId tid ) VG_(sprintf)(msg_buf,"block until I/O ready on fd %d", fd); print_sched_event(tid, msg_buf); } - } } @@ -1010,7 +1011,8 @@ void poll_for_ready_fds ( void ) rem->tv_nsec = 0; } /* Make the syscall return 0 (success). */ - VG_(threads)[tid].m_eax = 0; + SET_SYSCALL_RETVAL(tid, 0); + /* Reschedule this thread. */ VG_(threads)[tid].status = VgTs_Runnable; if (VG_(clo_trace_sched)) { @@ -1526,7 +1528,7 @@ VgSchedReturnCode VG_(scheduler) ( void ) thread yield instead. Not essential, just an optimisation. */ if (VG_(threads)[tid].m_eax == __NR_sched_yield) { - SET_EAX(tid, 0); /* syscall returns with success */ + SET_SYSCALL_RETVAL(tid, 0); /* syscall returns with success */ goto stage1; /* find a new thread to run */ } @@ -1670,7 +1672,7 @@ void make_thread_jump_to_cancelhdlr ( ThreadId tid ) vg_assert(VG_(threads)[tid].cancel_pend != NULL); /* Push a suitable arg, and mark it as readable. */ - VG_(threads)[tid].m_esp -= 4; + SET_PTHREQ_ESP(tid, VG_(threads)[tid].m_esp - 4); * (UInt*)(VG_(threads)[tid].m_esp) = (UInt)PTHREAD_CANCELED; VG_TRACK( post_mem_write, VG_(threads)[tid].m_esp, sizeof(void*) ); @@ -1678,7 +1680,7 @@ void make_thread_jump_to_cancelhdlr ( ThreadId tid ) need to have it so that the arg is at the correct stack offset. Don't mark as readable; any attempt to read this is and internal valgrind bug since thread_exit_wrapper should not return. */ - VG_(threads)[tid].m_esp -= 4; + SET_PTHREQ_ESP(tid, VG_(threads)[tid].m_esp - 4); * (UInt*)(VG_(threads)[tid].m_esp) = 0xBEADDEEF; /* .cancel_pend will hold &thread_exit_wrapper */ @@ -1790,7 +1792,7 @@ void maybe_rendezvous_joiners_and_joinees ( void ) /* joiner returns with success */ VG_(threads)[jnr].status = VgTs_Runnable; - SET_EDX(jnr, 0); + SET_PTHREQ_RETVAL(jnr, 0); } } @@ -1838,7 +1840,7 @@ void do__cleanup_push ( ThreadId tid, CleanupEntry* cu ) VG_(threads)[tid].custack[sp] = *cu; sp++; VG_(threads)[tid].custack_used = sp; - SET_EDX(tid, 0); + SET_PTHREQ_RETVAL(tid, 0); } @@ -1855,7 +1857,7 @@ void do__cleanup_pop ( ThreadId tid, CleanupEntry* cu ) } vg_assert(sp >= 0 && sp <= VG_N_CLEANUPSTACK); if (sp == 0) { - SET_EDX(tid, -1); + SET_PTHREQ_RETVAL(tid, -1); return; } sp--; @@ -1864,7 +1866,7 @@ void do__cleanup_pop ( ThreadId tid, CleanupEntry* cu ) *cu = VG_(threads)[tid].custack[sp]; VG_TRACK( post_mem_write, (Addr)cu, sizeof(CleanupEntry) ); VG_(threads)[tid].custack_used = sp; - SET_EDX(tid, 0); + SET_PTHREQ_RETVAL(tid, 0); } @@ -1877,7 +1879,7 @@ void do_pthread_yield ( ThreadId tid ) VG_(sprintf)(msg_buf, "yield"); print_sched_event(tid, msg_buf); } - SET_EDX(tid, 0); + SET_PTHREQ_RETVAL(tid, 0); } @@ -1898,7 +1900,7 @@ void do__testcancel ( ThreadId tid ) make_thread_jump_to_cancelhdlr ( tid ); } else { /* No, we keep going. */ - SET_EDX(tid, 0); + SET_PTHREQ_RETVAL(tid, 0); } } @@ -1925,8 +1927,8 @@ void do__set_cancelstate ( ThreadId tid, Int state ) } else { VG_(core_panic)("do__set_cancelstate"); } - SET_EDX(tid, old_st ? PTHREAD_CANCEL_ENABLE - : PTHREAD_CANCEL_DISABLE); + SET_PTHREQ_RETVAL(tid, old_st ? PTHREAD_CANCEL_ENABLE + : PTHREAD_CANCEL_DISABLE); } @@ -1952,7 +1954,7 @@ void do__set_canceltype ( ThreadId tid, Int type ) } else { VG_(core_panic)("do__set_canceltype"); } - SET_EDX(tid, old_ty ? PTHREAD_CANCEL_DEFERRED + SET_PTHREQ_RETVAL(tid, old_ty ? PTHREAD_CANCEL_DEFERRED : PTHREAD_CANCEL_ASYNCHRONOUS); } @@ -1977,20 +1979,20 @@ void do__set_or_get_detach ( ThreadId tid, } if (!VG_(is_valid_tid)(det)) { - SET_EDX(tid, -1); + SET_PTHREQ_RETVAL(tid, -1); return; } switch (what) { case 2: /* get */ - SET_EDX(tid, VG_(threads)[det].detached ? 1 : 0); + SET_PTHREQ_RETVAL(tid, VG_(threads)[det].detached ? 1 : 0); return; case 1: /* set detached. If someone is in a join-wait for det, do not detach. */ for (i = 1; i < VG_N_THREADS; i++) { if (VG_(threads)[i].status == VgTs_WaitJoinee && VG_(threads)[i].joiner_jee_tid == det) { - SET_EDX(tid, 0); + SET_PTHREQ_RETVAL(tid, 0); if (VG_(clo_trace_sched)) { VG_(sprintf)(msg_buf, "tid %d not detached because %d in join-wait for it", @@ -2001,11 +2003,11 @@ void do__set_or_get_detach ( ThreadId tid, } } VG_(threads)[det].detached = True; - SET_EDX(tid, 0); + SET_PTHREQ_RETVAL(tid, 0); return; case 0: /* set not detached */ VG_(threads)[det].detached = False; - SET_EDX(tid, 0); + SET_PTHREQ_RETVAL(tid, 0); return; default: VG_(core_panic)("do__set_or_get_detach"); @@ -2031,7 +2033,7 @@ void do__set_cancelpend ( ThreadId tid, } VG_(record_pthread_error)( tid, "pthread_cancel: target thread does not exist, or invalid"); - SET_EDX(tid, -VKI_ESRCH); + SET_PTHREQ_RETVAL(tid, -VKI_ESRCH); return; } @@ -2045,7 +2047,7 @@ void do__set_cancelpend ( ThreadId tid, } /* Thread doing the cancelling returns with success. */ - SET_EDX(tid, 0); + SET_PTHREQ_RETVAL(tid, 0); /* Perhaps we can nuke the cancellee right now? */ do__testcancel(cee); @@ -2066,7 +2068,7 @@ void do_pthread_join ( ThreadId tid, if (jee == tid) { VG_(record_pthread_error)( tid, "pthread_join: attempt to join to self"); - SET_EDX(tid, EDEADLK); /* libc constant, not a kernel one */ + SET_PTHREQ_RETVAL(tid, EDEADLK); /* libc constant, not a kernel one */ VG_(threads)[tid].status = VgTs_Runnable; return; } @@ -2082,7 +2084,7 @@ void do_pthread_join ( ThreadId tid, /* Invalid thread to join to. */ VG_(record_pthread_error)( tid, "pthread_join: target thread does not exist, or invalid"); - SET_EDX(tid, EINVAL); + SET_PTHREQ_RETVAL(tid, EINVAL); VG_(threads)[tid].status = VgTs_Runnable; return; } @@ -2096,7 +2098,7 @@ void do_pthread_join ( ThreadId tid, VG_(record_pthread_error)( tid, "pthread_join: another thread already " "in join-wait for target thread"); - SET_EDX(tid, EINVAL); + SET_PTHREQ_RETVAL(tid, EINVAL); VG_(threads)[tid].status = VgTs_Runnable; return; } @@ -2246,9 +2248,9 @@ void do__apply_in_new_thread ( ThreadId parent_tid, - mark everything below %esp inaccessible - mark redzone at stack end inaccessible */ - VG_(threads)[tid].m_esp = VG_(threads)[tid].stack_base - + VG_(threads)[tid].stack_size - - VG_AR_CLIENT_STACKBASE_REDZONE_SZB; + SET_PTHREQ_ESP(tid, VG_(threads)[tid].stack_base + + VG_(threads)[tid].stack_size + - VG_AR_CLIENT_STACKBASE_REDZONE_SZB); VG_TRACK ( die_mem_stack, VG_(threads)[tid].stack_base, + new_stk_szb - VG_AR_CLIENT_STACKBASE_REDZONE_SZB); @@ -2256,7 +2258,8 @@ void do__apply_in_new_thread ( ThreadId parent_tid, VG_AR_CLIENT_STACKBASE_REDZONE_SZB ); /* push two args */ - VG_(threads)[tid].m_esp -= 8; + SET_PTHREQ_ESP(tid, VG_(threads)[tid].m_esp - 8); + VG_TRACK ( new_mem_stack, (Addr)VG_(threads)[tid].m_esp, 2 * 4 ); VG_TRACK ( pre_mem_write, Vg_CorePThread, & VG_(threads)[tid], "new thread: stack", @@ -2282,7 +2285,7 @@ void do__apply_in_new_thread ( ThreadId parent_tid, VG_(ksigemptyset)(&VG_(threads)[tid].sigs_waited_for); /* return child's tid to parent */ - SET_EDX(parent_tid, tid); /* success */ + SET_PTHREQ_RETVAL(parent_tid, tid); /* success */ } @@ -2403,7 +2406,7 @@ void do_pthread_mutex_lock( ThreadId tid, if (mutex == NULL) { VG_(record_pthread_error)( tid, "pthread_mutex_lock/trylock: mutex is NULL"); - SET_EDX(tid, EINVAL); + SET_PTHREQ_RETVAL(tid, EINVAL); return; } @@ -2423,7 +2426,7 @@ void do_pthread_mutex_lock( ThreadId tid, default: VG_(record_pthread_error)( tid, "pthread_mutex_lock/trylock: mutex is invalid"); - SET_EDX(tid, EINVAL); + SET_PTHREQ_RETVAL(tid, EINVAL); return; } @@ -2437,16 +2440,16 @@ void do_pthread_mutex_lock( ThreadId tid, if (mutex->__m_kind == PTHREAD_MUTEX_RECURSIVE_NP) { /* return 0 (success). */ mutex->__m_count++; - SET_EDX(tid, 0); + SET_PTHREQ_RETVAL(tid, 0); if (0) VG_(printf)("!!!!!! tid %d, mx %p -> locked %d\n", tid, mutex, mutex->__m_count); return; } else { if (is_trylock) - SET_EDX(tid, EBUSY); + SET_PTHREQ_RETVAL(tid, EBUSY); else - SET_EDX(tid, EDEADLK); + SET_PTHREQ_RETVAL(tid, EDEADLK); return; } } else { @@ -2455,13 +2458,13 @@ void do_pthread_mutex_lock( ThreadId tid, /* GUARD: __m_count > 0 && __m_owner is valid */ if (is_trylock) { /* caller is polling; so return immediately. */ - SET_EDX(tid, EBUSY); + SET_PTHREQ_RETVAL(tid, EBUSY); } else { VG_TRACK ( pre_mutex_lock, tid, mutex ); VG_(threads)[tid].status = VgTs_WaitMX; VG_(threads)[tid].associated_mx = mutex; - SET_EDX(tid, 0); /* pth_mx_lock success value */ + SET_PTHREQ_RETVAL(tid, 0); /* pth_mx_lock success value */ if (VG_(clo_trace_pthread_level) >= 1) { VG_(sprintf)(msg_buf, "%s mx %p: BLOCK", caller, mutex ); @@ -2481,12 +2484,11 @@ void do_pthread_mutex_lock( ThreadId tid, mutex->__m_count = 1; mutex->__m_owner = (_pthread_descr)tid; - VG_TRACK( post_mutex_lock, tid, mutex); - /* return 0 (success). */ - SET_EDX(tid, 0); - } + SET_PTHREQ_RETVAL(tid, 0); + VG_TRACK( post_mutex_lock, tid, mutex); + } } @@ -2508,7 +2510,7 @@ void do_pthread_mutex_unlock ( ThreadId tid, if (mutex == NULL) { VG_(record_pthread_error)( tid, "pthread_mutex_unlock: mutex is NULL"); - SET_EDX(tid, EINVAL); + SET_PTHREQ_RETVAL(tid, EINVAL); return; } @@ -2536,7 +2538,7 @@ void do_pthread_mutex_unlock ( ThreadId tid, default: VG_(record_pthread_error)( tid, "pthread_mutex_unlock: mutex is invalid"); - SET_EDX(tid, EINVAL); + SET_PTHREQ_RETVAL(tid, EINVAL); return; } @@ -2545,7 +2547,7 @@ void do_pthread_mutex_unlock ( ThreadId tid, /* nobody holds it */ VG_(record_pthread_error)( tid, "pthread_mutex_unlock: mutex is not locked"); - SET_EDX(tid, EPERM); + SET_PTHREQ_RETVAL(tid, EPERM); return; } @@ -2553,7 +2555,7 @@ void do_pthread_mutex_unlock ( ThreadId tid, /* we don't hold it */ VG_(record_pthread_error)( tid, "pthread_mutex_unlock: mutex is locked by a different thread"); - SET_EDX(tid, EPERM); + SET_PTHREQ_RETVAL(tid, EPERM); return; } @@ -2562,7 +2564,7 @@ void do_pthread_mutex_unlock ( ThreadId tid, if (mutex->__m_count > 1) { vg_assert(mutex->__m_kind == PTHREAD_MUTEX_RECURSIVE_NP); mutex->__m_count --; - SET_EDX(tid, 0); /* success */ + SET_PTHREQ_RETVAL(tid, 0); /* success */ return; } @@ -2575,7 +2577,7 @@ void do_pthread_mutex_unlock ( ThreadId tid, release_one_thread_waiting_on_mutex ( mutex, "pthread_mutex_lock" ); /* Our (tid's) pth_unlock() returns with 0 (success). */ - SET_EDX(tid, 0); /* Success. */ + SET_PTHREQ_RETVAL(tid, 0); /* Success. */ } @@ -2627,7 +2629,7 @@ void do_pthread_cond_timedwait_TIMEOUT ( ThreadId tid ) /* Currently unheld; hand it out to thread tid. */ vg_assert(mx->__m_count == 0); VG_(threads)[tid].status = VgTs_Runnable; - SET_EDX(tid, ETIMEDOUT); /* pthread_cond_wait return value */ + SET_PTHREQ_RETVAL(tid, ETIMEDOUT); /* pthread_cond_wait return value */ VG_(threads)[tid].associated_cv = NULL; VG_(threads)[tid].associated_mx = NULL; mx->__m_owner = (_pthread_descr)tid; @@ -2647,7 +2649,7 @@ void do_pthread_cond_timedwait_TIMEOUT ( ThreadId tid ) VG_TRACK( pre_mutex_lock, tid, mx ); VG_(threads)[tid].status = VgTs_WaitMX; - SET_EDX(tid, ETIMEDOUT); /* pthread_cond_wait return value */ + SET_PTHREQ_RETVAL(tid, ETIMEDOUT); /* pthread_cond_wait return value */ VG_(threads)[tid].associated_cv = NULL; VG_(threads)[tid].associated_mx = mx; if (VG_(clo_trace_pthread_level) >= 1) { @@ -2718,7 +2720,7 @@ void release_N_threads_waiting_on_cond ( pthread_cond_t* cond, VG_(threads)[i].status = VgTs_WaitMX; VG_(threads)[i].associated_cv = NULL; VG_(threads)[i].associated_mx = mx; - SET_EDX(i, 0); /* pth_cond_wait success value */ + SET_PTHREQ_RETVAL(i, 0); /* pth_cond_wait success value */ if (VG_(clo_trace_pthread_level) >= 1) { VG_(sprintf)(msg_buf, "%s cv %p: BLOCK for mx %p", @@ -2758,7 +2760,7 @@ void do_pthread_cond_wait ( ThreadId tid, if (mutex == NULL || cond == NULL) { VG_(record_pthread_error)( tid, "pthread_cond_wait/timedwait: cond or mutex is NULL"); - SET_EDX(tid, EINVAL); + SET_PTHREQ_RETVAL(tid, EINVAL); return; } @@ -2778,7 +2780,7 @@ void do_pthread_cond_wait ( ThreadId tid, default: VG_(record_pthread_error)( tid, "pthread_cond_wait/timedwait: mutex is invalid"); - SET_EDX(tid, EINVAL); + SET_PTHREQ_RETVAL(tid, EINVAL); return; } @@ -2788,7 +2790,7 @@ void do_pthread_cond_wait ( ThreadId tid, VG_(record_pthread_error)( tid, "pthread_cond_wait/timedwait: mutex is unlocked " "or is locked but not owned by thread"); - SET_EDX(tid, EINVAL); + SET_PTHREQ_RETVAL(tid, EINVAL); return; } @@ -2833,7 +2835,7 @@ void do_pthread_cond_signal_or_broadcast ( ThreadId tid, if (cond == NULL) { VG_(record_pthread_error)( tid, "pthread_cond_signal/broadcast: cond is NULL"); - SET_EDX(tid, EINVAL); + SET_PTHREQ_RETVAL(tid, EINVAL); return; } @@ -2843,7 +2845,7 @@ void do_pthread_cond_signal_or_broadcast ( ThreadId tid, caller ); - SET_EDX(tid, 0); /* success */ + SET_PTHREQ_RETVAL(tid, 0); /* success */ } @@ -2879,9 +2881,9 @@ void do_pthread_key_validate ( ThreadId tid, && VG_(threads)[tid].status == VgTs_Runnable); if (is_valid_key((ThreadKey)key)) { - SET_EDX(tid, 1); + SET_PTHREQ_RETVAL(tid, 1); } else { - SET_EDX(tid, 0); + SET_PTHREQ_RETVAL(tid, 0); } } @@ -2909,7 +2911,7 @@ void do_pthread_key_create ( ThreadId tid, break; if (i == VG_N_THREAD_KEYS) { - /* SET_EDX(tid, EAGAIN); + /* SET_PTHREQ_RETVAL(tid, EAGAIN); return; */ VG_(core_panic)("pthread_key_create: VG_N_THREAD_KEYS is too low;" @@ -2926,7 +2928,7 @@ void do_pthread_key_create ( ThreadId tid, *key = i; VG_TRACK( post_mem_write, (Addr)key, sizeof(pthread_key_t) ); - SET_EDX(tid, 0); + SET_PTHREQ_RETVAL(tid, 0); } @@ -2946,13 +2948,13 @@ void do_pthread_key_delete ( ThreadId tid, pthread_key_t key ) if (!is_valid_key(key)) { VG_(record_pthread_error)( tid, "pthread_key_delete: key is invalid"); - SET_EDX(tid, EINVAL); + SET_PTHREQ_RETVAL(tid, EINVAL); return; } vg_thread_keys[key].inuse = False; vg_thread_keys[key].destructor = NULL; - SET_EDX(tid, 0); + SET_PTHREQ_RETVAL(tid, 0); } @@ -2974,7 +2976,7 @@ void do_pthread_getspecific_ptr ( ThreadId tid ) vg_assert(VG_(is_valid_or_empty_tid)(tid)); if (VG_(threads)[tid].status == VgTs_Empty) { - SET_EDX(tid, 1); + SET_PTHREQ_RETVAL(tid, 1); return; } @@ -2982,7 +2984,7 @@ void do_pthread_getspecific_ptr ( ThreadId tid ) vg_assert(specifics_ptr == NULL || IS_ALIGNED4_ADDR(specifics_ptr)); - SET_EDX(tid, (UInt)specifics_ptr); + SET_PTHREQ_RETVAL(tid, (UInt)specifics_ptr); } @@ -3000,7 +3002,7 @@ void do_pthread_setspecific_ptr ( ThreadId tid, void** ptr ) && VG_(threads)[tid].status == VgTs_Runnable); VG_(threads)[tid].specifics_ptr = ptr; - SET_EDX(tid, 0); + SET_PTHREQ_RETVAL(tid, 0); } @@ -3023,7 +3025,7 @@ void do__get_key_destr_and_spec ( ThreadId tid, vg_assert(key >= 0 && key < VG_N_THREAD_KEYS); if (!vg_thread_keys[key].inuse) { - SET_EDX(tid, -1); + SET_PTHREQ_RETVAL(tid, -1); return; } VG_TRACK( pre_mem_write, Vg_CorePThread, & VG_(threads)[tid], @@ -3042,7 +3044,7 @@ void do__get_key_destr_and_spec ( ThreadId tid, } VG_TRACK( post_mem_write, (Addr)cu, sizeof(CleanupEntry) ); - SET_EDX(tid, 0); + SET_PTHREQ_RETVAL(tid, 0); } @@ -3087,7 +3089,7 @@ void do_pthread_sigmask ( ThreadId tid, VG_TRACK( post_mem_write, (Addr)oldmask, sizeof(vki_ksigset_t) ); /* Success. */ - SET_EDX(tid, 0); + SET_PTHREQ_RETVAL(tid, 0); } @@ -3138,17 +3140,17 @@ void do_pthread_kill ( ThreadId tid, /* me */ if (!VG_(is_valid_tid)(thread)) { VG_(record_pthread_error)( tid, "pthread_kill: invalid target thread"); - SET_EDX(tid, -VKI_ESRCH); + SET_PTHREQ_RETVAL(tid, -VKI_ESRCH); return; } if (sig < 1 || sig > VKI_KNSIG) { - SET_EDX(tid, -VKI_EINVAL); + SET_PTHREQ_RETVAL(tid, -VKI_EINVAL); return; } VG_(send_signal_to_thread)( thread, sig ); - SET_EDX(tid, 0); + SET_PTHREQ_RETVAL(tid, 0); } @@ -3170,9 +3172,9 @@ void do__set_fhstack_used ( ThreadId tid, Int n ) if (n >= 0 && n < VG_N_FORKHANDLERSTACK) { vg_fhstack_used = n; - SET_EDX(tid, 0); + SET_PTHREQ_RETVAL(tid, 0); } else { - SET_EDX(tid, -1); + SET_PTHREQ_RETVAL(tid, -1); } } @@ -3192,7 +3194,7 @@ void do__get_fhstack_used ( ThreadId tid ) n = vg_fhstack_used; vg_assert(n >= 0 && n < VG_N_FORKHANDLERSTACK); - SET_EDX(tid, n); + SET_PTHREQ_RETVAL(tid, n); } static @@ -3211,12 +3213,12 @@ void do__set_fhstack_entry ( ThreadId tid, Int n, ForkHandlerEntry* fh ) (Addr)fh, sizeof(ForkHandlerEntry)); if (n < 0 || n >= VG_N_FORKHANDLERSTACK) { - SET_EDX(tid, -1); + SET_PTHREQ_RETVAL(tid, -1); return; } vg_fhstack[n] = *fh; - SET_EDX(tid, 0); + SET_PTHREQ_RETVAL(tid, 0); } @@ -3237,16 +3239,30 @@ void do__get_fhstack_entry ( ThreadId tid, Int n, /*OUT*/ (Addr)fh, sizeof(ForkHandlerEntry)); if (n < 0 || n >= VG_N_FORKHANDLERSTACK) { - SET_EDX(tid, -1); + SET_PTHREQ_RETVAL(tid, -1); return; } *fh = vg_fhstack[n]; - SET_EDX(tid, 0); + SET_PTHREQ_RETVAL(tid, 0); VG_TRACK( post_mem_write, (Addr)fh, sizeof(ForkHandlerEntry) ); } +/* --------------------------------------------------------------------- + Specifying shadow register values + ------------------------------------------------------------------ */ + +void VG_(set_return_from_syscall_shadow) ( ThreadId tid, UInt ret_shadow ) +{ + VG_(set_thread_shadow_archreg)(tid, R_EAX, ret_shadow); +} + +UInt VG_(get_exit_status_shadow) ( void ) +{ + return VG_(get_shadow_archreg)(R_EBX); +} + /* --------------------------------------------------------------------- Handle client requests. @@ -3259,11 +3275,6 @@ void do__get_fhstack_entry ( ThreadId tid, Int n, /*OUT*/ static void do_client_request ( ThreadId tid ) { -# define RETURN_WITH(vvv) \ - { tst->m_edx = (vvv); \ - tst->sh_edx = VG_(written_shadow_reg); \ - } - ThreadState* tst = &VG_(threads)[tid]; UInt* arg = (UInt*)(VG_(threads)[tid].m_eax); UInt req_no = arg[0]; @@ -3271,63 +3282,45 @@ void do_client_request ( ThreadId tid ) /* VG_(printf)("req no = 0x%x\n", req_no); */ switch (req_no) { - /* For the CLIENT_{,tst}CALL[0123] ones, have to do some nasty casting - to make gcc believe it's a function. */ case VG_USERREQ__CLIENT_CALL0: { UInt (*f)(void) = (void*)arg[1]; - RETURN_WITH( - f ( ) - ); + SET_CLCALL_RETVAL(tid, f ( ), (Addr)f); break; } case VG_USERREQ__CLIENT_CALL1: { UInt (*f)(UInt) = (void*)arg[1]; - RETURN_WITH( - f ( arg[2] ) - ); + SET_CLCALL_RETVAL(tid, f ( arg[2] ), (Addr)f ); break; } case VG_USERREQ__CLIENT_CALL2: { UInt (*f)(UInt, UInt) = (void*)arg[1]; - RETURN_WITH( - f ( arg[2], arg[3] ) - ); + SET_CLCALL_RETVAL(tid, f ( arg[2], arg[3] ), (Addr)f ); break; } case VG_USERREQ__CLIENT_CALL3: { UInt (*f)(UInt, UInt, UInt) = (void*)arg[1]; - RETURN_WITH( - f ( arg[2], arg[3], arg[4] ) - ); + SET_CLCALL_RETVAL(tid, f ( arg[2], arg[3], arg[4] ), (Addr)f ); break; } case VG_USERREQ__CLIENT_tstCALL0: { UInt (*f)(ThreadState*) = (void*)arg[1]; - RETURN_WITH( - f ( tst ) - ); + SET_CLCALL_RETVAL(tid, f ( tst ), (Addr)f ); break; } case VG_USERREQ__CLIENT_tstCALL1: { UInt (*f)(ThreadState*, UInt) = (void*)arg[1]; - RETURN_WITH( - f ( tst, arg[2] ) - ); + SET_CLCALL_RETVAL(tid, f ( tst, arg[2] ), (Addr)f ); break; } case VG_USERREQ__CLIENT_tstCALL2: { UInt (*f)(ThreadState*, UInt, UInt) = (void*)arg[1]; - RETURN_WITH( - f ( tst, arg[2], arg[3] ) - ); + SET_CLCALL_RETVAL(tid, f ( tst, arg[2], arg[3] ), (Addr)f ); break; } case VG_USERREQ__CLIENT_tstCALL3: { UInt (*f)(ThreadState*, UInt, UInt, UInt) = (void*)arg[1]; - RETURN_WITH( - f ( tst, arg[2], arg[3], arg[4] ) - ); + SET_CLCALL_RETVAL(tid, f ( tst, arg[2], arg[3], arg[4] ), (Addr)f ); break; } @@ -3341,8 +3334,8 @@ void do_client_request ( ThreadId tid ) the comment in vg_defaults.c/SK_(malloc)() for why. */ case VG_USERREQ__MALLOC: VG_(sk_malloc_called_by_scheduler) = True; - RETURN_WITH( - (UInt)SK_(malloc) ( tst, arg[1] ) + SET_PTHREQ_RETVAL( + tid, (UInt)SK_(malloc) ( tst, arg[1] ) ); VG_(sk_malloc_called_by_scheduler) = False; break; @@ -3351,23 +3344,23 @@ void do_client_request ( ThreadId tid ) VG_(sk_malloc_called_by_scheduler) = True; SK_(free) ( tst, (void*)arg[1] ); VG_(sk_malloc_called_by_scheduler) = False; - RETURN_WITH(0); /* irrelevant */ + SET_PTHREQ_RETVAL(tid, 0); /* irrelevant */ break; case VG_USERREQ__PTHREAD_GET_THREADID: - RETURN_WITH(tid); + SET_PTHREQ_RETVAL(tid, tid); break; case VG_USERREQ__RUNNING_ON_VALGRIND: - RETURN_WITH(1); + SET_CLREQ_RETVAL(tid, 1); break; case VG_USERREQ__GET_PTHREAD_TRACE_LEVEL: - RETURN_WITH(VG_(clo_trace_pthread_level)); + SET_PTHREQ_RETVAL(tid, VG_(clo_trace_pthread_level)); break; case VG_USERREQ__READ_MILLISECOND_TIMER: - RETURN_WITH(VG_(read_millisecond_timer)()); + SET_PTHREQ_RETVAL(tid, VG_(read_millisecond_timer)()); break; /* Some of these may make thread tid non-runnable, but the @@ -3405,7 +3398,7 @@ void do_client_request ( ThreadId tid ) break; case VG_USERREQ__GET_N_SIGS_RETURNED: - RETURN_WITH(VG_(threads)[tid].n_signals_returned); + SET_PTHREQ_RETVAL(tid, VG_(threads)[tid].n_signals_returned); break; case VG_USERREQ__PTHREAD_JOIN: @@ -3517,12 +3510,12 @@ void do_client_request ( ThreadId tid ) case VG_USERREQ__NUKE_OTHER_THREADS: VG_(nuke_all_threads_except) ( tid ); - SET_EDX(tid, 0); + SET_PTHREQ_RETVAL(tid, 0); break; case VG_USERREQ__PTHREAD_ERROR: VG_(record_pthread_error)( tid, (Char*)(arg[1]) ); - SET_EDX(tid, 0); + SET_PTHREQ_RETVAL(tid, 0); break; case VG_USERREQ__SET_FHSTACK_USED: @@ -3557,11 +3550,11 @@ void do_client_request ( ThreadId tid ) VG_(invalidate_translations)( arg[1], arg[2], True ); - SET_EDX( tid, 0 ); /* return value is meaningless */ + SET_CLREQ_RETVAL( tid, 0 ); /* return value is meaningless */ break; case VG_USERREQ__COUNT_ERRORS: - SET_EDX( tid, VG_(n_errs_found) ); + SET_CLREQ_RETVAL( tid, VG_(n_errs_found) ); break; default: @@ -3573,7 +3566,7 @@ void do_client_request ( ThreadId tid ) arg[0], (void*)arg[1], arg[2] ); if (SK_(handle_client_request) ( &VG_(threads)[tid], arg, &ret )) - SET_EDX(tid, ret); + SET_CLREQ_RETVAL(tid, ret); } else { static Bool whined = False; @@ -3588,8 +3581,6 @@ void do_client_request ( ThreadId tid ) } break; } - -# undef RETURN_WITH } diff --git a/coregrind/vg_signals.c b/coregrind/vg_signals.c index 4cafe38640..1123ee9fa9 100644 --- a/coregrind/vg_signals.c +++ b/coregrind/vg_signals.c @@ -518,13 +518,13 @@ void VG_(do__NR_sigaltstack) ( ThreadId tid ) if (ss != NULL) { if (on_sig_stack(VG_(threads)[tid].m_esp)) { - SET_EAX(tid, -VKI_EPERM); + SET_SYSCALL_RETVAL(tid, -VKI_EPERM); return; } if (ss->ss_flags != VKI_SS_DISABLE && ss->ss_flags != VKI_SS_ONSTACK && ss->ss_flags != 0) { - SET_EAX(tid, -VKI_EINVAL); + SET_SYSCALL_RETVAL(tid, -VKI_EINVAL); return; } if (ss->ss_flags == VKI_SS_DISABLE) { @@ -532,14 +532,14 @@ void VG_(do__NR_sigaltstack) ( ThreadId tid ) vg_scss.altstack.ss_sp = NULL; } else { if (ss->ss_size < VKI_MINSIGSTKSZ) { - SET_EAX(tid, -VKI_ENOMEM); + SET_SYSCALL_RETVAL(tid, -VKI_ENOMEM); return; } } vg_scss.altstack.ss_sp = ss->ss_sp; vg_scss.altstack.ss_size = ss->ss_size; } - SET_EAX(tid, 0); + SET_SYSCALL_RETVAL(tid, 0); } @@ -597,7 +597,7 @@ void VG_(do__NR_sigaction) ( ThreadId tid ) VG_(block_all_host_signals)( &irrelevant_sigmask ); VG_(handle_SCSS_change)( False /* lazy update */ ); } - SET_EAX(tid, 0); + SET_SYSCALL_RETVAL(tid, 0); return; bad_signo: @@ -605,7 +605,7 @@ void VG_(do__NR_sigaction) ( ThreadId tid ) VG_(message)(Vg_UserMsg, "Warning: bad signal number %d in __NR_sigaction.", signo); - SET_EAX(tid, -VKI_EINVAL); + SET_SYSCALL_RETVAL(tid, -VKI_EINVAL); return; bad_sigkill_or_sigstop: @@ -614,7 +614,7 @@ void VG_(do__NR_sigaction) ( ThreadId tid ) "Warning: attempt to set %s handler in __NR_sigaction.", signo == VKI_SIGKILL ? "SIGKILL" : "SIGSTOP" ); - SET_EAX(tid, -VKI_EINVAL); + SET_SYSCALL_RETVAL(tid, -VKI_EINVAL); return; } @@ -713,11 +713,11 @@ void VG_(do__NR_sigprocmask) ( ThreadId tid, vg_assert(VG_(is_valid_tid)(tid)); do_setmask ( VG_INVALID_THREADID, how, set, oldset ); /* Syscall returns 0 (success) to its thread. */ - SET_EAX(tid, 0); + SET_SYSCALL_RETVAL(tid, 0); } else { VG_(message)(Vg_DebugMsg, "sigprocmask: unknown `how' field %d", how); - SET_EAX(tid, -VKI_EINVAL); + SET_SYSCALL_RETVAL(tid, -VKI_EINVAL); } } @@ -904,17 +904,29 @@ typedef /* Safely-saved version of sigNo, as described above. */ Int sigNo_private; /* Saved processor state. */ - UInt ssestate[VG_SIZE_OF_SSESTATE_W]; - UInt eax; - UInt ecx; - UInt edx; - UInt ebx; - UInt ebp; - UInt esp; - UInt esi; - UInt edi; - Addr eip; - UInt eflags; + UInt m_sse[VG_SIZE_OF_SSESTATE_W]; + + UInt m_eax; + UInt m_ecx; + UInt m_edx; + UInt m_ebx; + UInt m_ebp; + UInt m_esp; + UInt m_esi; + UInt m_edi; + UInt m_eflags; + Addr m_eip; + + UInt sh_eax; + UInt sh_ebx; + UInt sh_ecx; + UInt sh_edx; + UInt sh_esi; + UInt sh_edi; + UInt sh_ebp; + UInt sh_esp; + UInt sh_eflags; + /* Scheduler-private stuff: what was the thread's status prior to delivering this signal? */ ThreadStatus status; @@ -989,25 +1001,41 @@ void vg_push_signal_frame ( ThreadId tid, int sigNo ) frame->magicPI = 0x31415927; for (i = 0; i < VG_SIZE_OF_SSESTATE_W; i++) - frame->ssestate[i] = tst->m_sse[i]; - - frame->eax = tst->m_eax; - frame->ecx = tst->m_ecx; - frame->edx = tst->m_edx; - frame->ebx = tst->m_ebx; - frame->ebp = tst->m_ebp; - frame->esp = tst->m_esp; - frame->esi = tst->m_esi; - frame->edi = tst->m_edi; - frame->eip = tst->m_eip; - frame->eflags = tst->m_eflags; + frame->m_sse[i] = tst->m_sse[i]; + + frame->m_eax = tst->m_eax; + frame->m_ecx = tst->m_ecx; + frame->m_edx = tst->m_edx; + frame->m_ebx = tst->m_ebx; + frame->m_ebp = tst->m_ebp; + frame->m_esp = tst->m_esp; + frame->m_esi = tst->m_esi; + frame->m_edi = tst->m_edi; + frame->m_eflags = tst->m_eflags; + frame->m_eip = tst->m_eip; + + if (VG_(needs).shadow_regs) { + frame->sh_eax = tst->sh_eax; + frame->sh_ecx = tst->sh_ecx; + frame->sh_edx = tst->sh_edx; + frame->sh_ebx = tst->sh_ebx; + frame->sh_ebp = tst->sh_ebp; + frame->sh_esp = tst->sh_esp; + frame->sh_esi = tst->sh_esi; + frame->sh_edi = tst->sh_edi; + frame->sh_eflags = tst->sh_eflags; + } frame->status = tst->status; frame->magicE = 0x27182818; + /* Ensure 'tid' and 'tst' correspond */ + vg_assert(& VG_(threads)[tid] == tst); /* Set the thread so it will next run the handler. */ - tst->m_esp = esp; + /* tst->m_esp = esp; */ + SET_SIGNAL_ESP(tid, esp); + tst->m_eip = (Addr)vg_scss.scss_per_sig[sigNo].scss_handler; /* This thread needs to be marked runnable, but we leave that the caller to do. */ @@ -1022,7 +1050,6 @@ void vg_push_signal_frame ( ThreadId tid, int sigNo ) */ } - /* Clear the signal frame created by vg_push_signal_frame, restore the simulated machine state, and return the signal number that the frame was for. */ @@ -1049,25 +1076,36 @@ Int vg_pop_signal_frame ( ThreadId tid ) VG_(message)(Vg_DebugMsg, "vg_pop_signal_frame (thread %d): valid magic", tid); - /* restore machine state */ - for (i = 0; i < VG_SIZE_OF_SSESTATE_W; i++) - tst->m_sse[i] = frame->ssestate[i]; - /* Mark the frame structure as nonaccessible. */ VG_TRACK( die_mem_stack_signal, (Addr)frame, sizeof(VgSigFrame) ); - /* Restore machine state from the saved context. */ - tst->m_eax = frame->eax; - tst->m_ecx = frame->ecx; - tst->m_edx = frame->edx; - tst->m_ebx = frame->ebx; - tst->m_ebp = frame->ebp; - tst->m_esp = frame->esp; - tst->m_esi = frame->esi; - tst->m_edi = frame->edi; - tst->m_eflags = frame->eflags; - tst->m_eip = frame->eip; - + /* restore machine state */ + for (i = 0; i < VG_SIZE_OF_SSESTATE_W; i++) + tst->m_sse[i] = frame->m_sse[i]; + + tst->m_eax = frame->m_eax; + tst->m_ecx = frame->m_ecx; + tst->m_edx = frame->m_edx; + tst->m_ebx = frame->m_ebx; + tst->m_ebp = frame->m_ebp; + tst->m_esp = frame->m_esp; + tst->m_esi = frame->m_esi; + tst->m_edi = frame->m_edi; + tst->m_eflags = frame->m_eflags; + tst->m_eip = frame->m_eip; + + if (VG_(needs).shadow_regs) { + tst->sh_eax = frame->sh_eax; + tst->sh_ecx = frame->sh_ecx; + tst->sh_edx = frame->sh_edx; + tst->sh_ebx = frame->sh_ebx; + tst->sh_ebp = frame->sh_ebp; + tst->sh_esp = frame->sh_esp; + tst->sh_esi = frame->sh_esi; + tst->sh_edi = frame->sh_edi; + tst->sh_eflags = frame->sh_eflags; + } + /* don't use the copy exposed to the handler; it might have changed it. */ sigNo = frame->sigNo_private; @@ -1180,7 +1218,7 @@ Bool VG_(deliver_signals) ( void ) *(Int*)(sigwait_args[2]) = sigNo; VG_TRACK( post_mem_write, (Addr)sigwait_args[2], sizeof(UInt)); } - SET_EDX(tid, 0); + SET_SIGNAL_EDX(tid, 0); tst->status = VgTs_Runnable; VG_(ksigemptyset)(&tst->sigs_waited_for); scss_changed = True; diff --git a/coregrind/vg_syscalls.c b/coregrind/vg_syscalls.c index 57ef09ed77..6e6dcac9df 100644 --- a/coregrind/vg_syscalls.c +++ b/coregrind/vg_syscalls.c @@ -616,7 +616,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid ) } /* "do" the syscall ourselves; the kernel never sees it */ res = VG_(sys_modify_ldt)( tid, arg1, (void*)arg2, arg3 ); - SET_EAX(tid, res); + SET_SYSCALL_RETVAL(tid, res); if (arg1 == 0 && !VG_(is_kerror)(res) && res > 0) { VG_TRACK( post_mem_write, arg2, res ); } @@ -1373,7 +1373,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid ) "alternative logfile fd." ); /* Pretend the close succeeded, regardless. (0 == success) */ res = 0; - SET_EAX(tid, res); + SET_SYSCALL_RETVAL(tid, res); } else { KERNEL_DO_SYSCALL(tid,res); } @@ -2661,6 +2661,12 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid ) VG_TRACK( post_mem_write, (Addr)(&arr[i].revents), sizeof(Short) ); } + /* For some unknown reason, %ebx sometimes gets changed by poll... + let the skin know (using the `post_reg_write_syscall_return' + event isn't ideal... */ + if (arg1 != tst->m_ebx) { + VG_TRACK( post_reg_write_syscall_return, tid, R_EBX ); + } break; case __NR_readlink: /* syscall 85 */ @@ -3398,7 +3404,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid ) # if SIGNAL_SIMULATION VG_(do_sigpending)( tid, (vki_ksigset_t*)arg1 ); res = 0; - SET_EAX(tid, res); + SET_SYSCALL_RETVAL(tid, res); # else KERNEL_DO_SYSCALL(tid, res); # endif diff --git a/include/vg_skin.h b/include/vg_skin.h index 8a1ee914ea..6dd05ccb8c 100644 --- a/include/vg_skin.h +++ b/include/vg_skin.h @@ -987,6 +987,7 @@ extern UInt VG_(get_thread_archreg) ( ThreadId tid, UInt archreg ); extern UInt VG_(get_shadow_archreg) ( UInt archreg ); extern void VG_(set_shadow_archreg) ( UInt archreg, UInt val ); +extern void VG_(set_shadow_eflags) ( UInt val ); extern Addr VG_(shadow_archreg_address) ( UInt archreg ); extern UInt VG_(get_thread_shadow_archreg) ( ThreadId tid, UInt archreg ); @@ -1207,7 +1208,8 @@ extern void VG_(pp_ExeContext) ( ExeContext* ); extern ExeContext* VG_(get_ExeContext) ( ThreadState *tst ); /* Just grab the client's EIP, as a much smaller and cheaper - indication of where they are. */ + indication of where they are. ThreadState should be NULL if it's called + from within generated code. */ extern Addr VG_(get_EIP)( ThreadState *tst ); @@ -1469,6 +1471,23 @@ extern void VG_(HT_apply_to_all_nodes)( VgHashTable t, void (*f)(VgHashNode*) ); extern void VG_(HT_destruct) ( VgHashTable t ); +/*====================================================================*/ +/*=== Functions for shadow registers ===*/ +/*====================================================================*/ + +/* Nb: make sure the shadow_regs 'need' is set before using these! */ + +/* This one lets you override the shadow of the return value register for a + syscall. Call it from SK_(post_syscall)() (not SK_(pre_syscall)()!) to + override the default shadow register value. */ +extern void VG_(set_return_from_syscall_shadow) ( ThreadId tid, + UInt ret_shadow ); + +/* This can be called from SK_(fini)() to find the shadow of the argument + to exit(), ie. the shadow of the program's return value. */ +extern UInt VG_(get_exit_status_shadow) ( void ); + + /*====================================================================*/ /*=== General stuff for replacing functions ===*/ /*====================================================================*/ @@ -1499,9 +1518,6 @@ extern Bool VG_(is_running_on_simd_CPU) ( void ); /*=== Specific stuff for replacing malloc() and friends ===*/ /*====================================================================*/ -/* ------------------------------------------------------------------ */ -/* Replacing malloc() and friends */ - /* If a skin replaces malloc() et al, the easiest way to do so is to link with coregrind/vg_replace_malloc.c, and follow the following instructions. You can do it from scratch, though, if you enjoy that sort of thing. */ @@ -1536,8 +1552,8 @@ extern Bool VG_(addr_is_in_block)( Addr a, Addr start, UInt size ); /* ------------------------------------------------------------------ */ /* Some options that can be used by a skin if malloc() et al are replaced. - The skin should use the VG_(process...)() and VG_(print...)() functions - to give control over these aspects of Valgrind's version of malloc(). */ + The skin should call the functions in the appropriate places to give + control over these aspects of Valgrind's version of malloc(). */ /* Round malloc sizes upwards to integral number of words? default: NO */ extern Bool VG_(clo_sloppy_malloc); @@ -1711,6 +1727,30 @@ EV VG_(track_pre_mem_write) ( void (*f)(CorePart part, ThreadState* tst, EV VG_(track_post_mem_write) ( void (*f)(Addr a, UInt size) ); +/* Register events -- if `shadow_regs' need is set, all should probably be + used. Use VG_(set_thread_shadow_archreg)() to set the shadow of the + changed register. */ + +/* Use VG_(set_shadow_archreg)() to set the eight general purpose regs, + and use VG_(set_shadow_eflags)() to set eflags. */ +EV VG_(track_post_regs_write_init) ( void (*f)() ); + +/* Use VG_(set_thread_shadow_archreg)() to set the shadow regs for these + events. */ +EV VG_(track_post_reg_write_syscall_return) + ( void (*f)(ThreadId tid, UInt reg) ); +EV VG_(track_post_reg_write_deliver_signal) + ( void (*f)(ThreadId tid, UInt reg) ); +EV VG_(track_post_reg_write_pthread_return) + ( void (*f)(ThreadId tid, UInt reg) ); +EV VG_(track_post_reg_write_clientreq_return) + ( void (*f)(ThreadId tid, UInt reg) ); + /* This one is called for malloc() et al if they are replaced by a skin. */ +EV VG_(track_post_reg_write_clientcall_return) + ( void (*f)(ThreadId tid, UInt reg, + Addr called_function) ); + + /* Scheduler events (not exhaustive) */ EV VG_(track_thread_run) ( void (*f)(ThreadId tid) ); @@ -1865,10 +1905,8 @@ extern void SK_(discard_basic_block_info) ( Addr a, UInt size ); /* ------------------------------------------------------------------ */ /* VG_(needs).shadow_regs */ -/* Valid values for general registers and EFLAGS register, for initialising - and updating registers when written in certain places in core. */ -extern void SK_(written_shadow_regs_values) ( UInt* gen_reg, UInt* eflags ); - +/* No functions must be defined, but the post_reg[s]_write_* events should + be tracked. */ /* ------------------------------------------------------------------ */ /* VG_(needs).command_line_options */ @@ -1886,7 +1924,19 @@ extern void SK_(print_debug_usage) ( void ); /* ------------------------------------------------------------------ */ /* VG_(needs).client_requests */ -extern Bool SK_(handle_client_request) ( ThreadState* tst, UInt* arg_block, UInt *ret ); +/* If using client requests, the number of the first request should be equal + to VG_USERREQ_SKIN_BASE('X','Y'), where 'X' and 'Y' form a suitable two + character identification for the string. The second and subsequent + requests should follow. */ + +/* This function should use the VG_IS_SKIN_USERREQ macro (in + include/valgrind.h) to first check if it's a request for this skin. Then + should handle it if it's recognised (and return True), or return False if + not recognised. arg_block[0] holds the request number, any further args + from the request are in arg_block[1..]. 'ret' is for the return value... + it should probably be filled, if only with 0. */ +extern Bool SK_(handle_client_request) ( ThreadState* tst, UInt* arg_block, + UInt *ret ); /* ------------------------------------------------------------------ */ diff --git a/memcheck/mc_main.c b/memcheck/mc_main.c index 149bb23815..9bbe74936b 100644 --- a/memcheck/mc_main.c +++ b/memcheck/mc_main.c @@ -685,6 +685,29 @@ void mc_set_perms (Addr a, UInt len, Bool rr, Bool ww, Bool xx) } +/*------------------------------------------------------------*/ +/*--- Register event handlers ---*/ +/*------------------------------------------------------------*/ + +static void mc_post_regs_write_init ( void ) +{ + UInt i; + for (i = R_EAX; i <= R_EDI; i++) + VG_(set_shadow_archreg)( i, VGM_WORD_VALID ); + VG_(set_shadow_eflags)( VGM_EFLAGS_VALID ); +} + +static void mc_post_reg_write(ThreadId tid, UInt reg) +{ + VG_(set_thread_shadow_archreg)( tid, reg, VGM_WORD_VALID ); +} + +static void mc_post_reg_write_clientcall(ThreadId tid, UInt reg, Addr f ) +{ + VG_(set_thread_shadow_archreg)( tid, reg, VGM_WORD_VALID ); +} + + /*------------------------------------------------------------*/ /*--- Functions called directly from generated code. ---*/ /*------------------------------------------------------------*/ @@ -1473,15 +1496,9 @@ void show_bb ( Addr eip_next ) /*------------------------------------------------------------*/ -/*--- Setup ---*/ +/*--- Command line args ---*/ /*------------------------------------------------------------*/ -void SK_(written_shadow_regs_values)( UInt* gen_reg_value, UInt* eflags_value ) -{ - *gen_reg_value = VGM_WORD_VALID; - *eflags_value = VGM_EFLAGS_VALID; -} - Bool MC_(clo_avoid_strlen_errors) = True; Bool MC_(clo_cleanup) = True; @@ -1582,6 +1599,13 @@ void SK_(pre_clo_init)(void) VG_(track_pre_mem_write) ( & mc_check_is_writable ); VG_(track_post_mem_write) ( & MC_(make_readable) ); + VG_(track_post_regs_write_init) ( & mc_post_regs_write_init ); + VG_(track_post_reg_write_syscall_return) ( & mc_post_reg_write ); + VG_(track_post_reg_write_deliver_signal) ( & mc_post_reg_write ); + VG_(track_post_reg_write_pthread_return) ( & mc_post_reg_write ); + VG_(track_post_reg_write_clientreq_return) ( & mc_post_reg_write ); + VG_(track_post_reg_write_clientcall_return) ( & mc_post_reg_write_clientcall ); + /* Three compact slots taken up by stack memory helpers */ VG_(register_compact_helper)((Addr) & MC_(helper_value_check4_fail)); VG_(register_compact_helper)((Addr) & MC_(helper_value_check0_fail));