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 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/vg_include.h b/coregrind/vg_include.h
index 206c6d8..f6cc1a5 100644
--- a/coregrind/vg_include.h
+++ b/coregrind/vg_include.h
@@ -353,6 +353,16 @@
       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 @@
    (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
 
-/* What we set a shadow register to when written by SET_EAX and similar
- * things. */
-extern UInt VG_(written_shadow_reg);
-
-/* 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);  \
+/* 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)
 
-#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_SYSCALL_RETVAL(zztid, zzval) \
+   SET_THREAD_REG(zztid, zzval, eax, EAX, post_reg_write_syscall_return)
+
+#define SET_SIGNAL_EDX(zztid, zzval) \
+   SET_THREAD_REG(zztid, zzval, edx, EDX, post_reg_write_deliver_signal)
+
+#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 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 );
 
 
 /* ---------------------------------------------------------------------