Lots of changes to future-proof the core/skin interface, making it less likely
that changes will cause binary incompatibilities.  Mostly done by hiding naked
structs with function calls.

Structs hidden in this way were: UCodeBlock, SkinSupp and SkinError (which were
merged back with CoreSupp and CoreError into single types Supp and Error),
ShadowChunk, VgDetails, VgNeeds and VgTrackEvents.  The last three are the most
important ones, as they are (I think) the most likely to change.

Suitable get()/set() methods were defined for each one.  The way UCodeBlocks
are copied for instrumentation by skins is a little different now, using
setup_UCodeBlock.  Had to add a few other functions here n there.  Changed
how SK_(complete_shadow_chunk) works a bit.

Added a file coregrind/vg_needs.c which contains all the get/set functions.
It's pretty simple.

The changes are not totally ideal -- eg. ShadowChunks has get()/set() methods
for its `next' field which arguably shouldn't be exposed (betraying the fact
that it's a linked list), and the get()/set() methods are a bit cumbersome at
times, esp. for `Error' because the fields are accessed quite a few times, and
the treatment of Supps and Errors is a bit inconsistent (but they are used in
different ways), and sizeof_shadow_blocks is still a hack.  But still better
than naked structs.  And one advantage is that a bit of sanity checking can be
performed by the get()/set() methods, as is done for VG_({get,set}_sc_extra)()
to make sure no reading/writing occurs outside the allowed area.

I didn't do it for UInstr, because its fields are accessed directly in lots and
lots of spots, which would have been a great big pain and I was a little
worried about overhead of calling lots of extra functions, although in practice
translation times are small enough that it probably doesn't matter.

Updated the example skin and the docs, too, hurrah.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@1314 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/Makefile.am b/coregrind/Makefile.am
index 7ad845e..fd11306 100644
--- a/coregrind/Makefile.am
+++ b/coregrind/Makefile.am
@@ -51,6 +51,7 @@
 	vg_memory.c \
 	vg_messages.c \
 	vg_mylibc.c \
+	vg_needs.c \
 	vg_procselfmaps.c \
 	vg_dummy_profile.c \
 	vg_signals.c \
diff --git a/coregrind/docs/coregrind_skins.html b/coregrind/docs/coregrind_skins.html
index a173971..ab958d7 100644
--- a/coregrind/docs/coregrind_skins.html
+++ b/coregrind/docs/coregrind_skins.html
@@ -369,18 +369,18 @@
 options and must do some initialisation after option processing takes place
 (``<code>clo</code>'' stands for ``command line options'').<p>
 
-The first argument to <code>SK_(pre_clo_init)()</code> must be initialised with
-various ``details'' for a skin.  These are all compulsory except for
+First of all, various ``details'' need to be set for a skin, using the
+functions <code>VG_(details_*)()</code>.  These are all compulsory except for
 <code>version</code>.  They are used when constructing the startup message,
 except for <code></code> which is used if <code>VG_(skin_panic)()</code> is
 ever called, or a skin assertion fails.<p>
 
-The second argument to <code>SK_(pre_clo_init)()</code> must be initialised with
-the ``needs'' for a skin.  They are mostly booleans, and can be left untouched
-(they default to <code>False</code>).  They determine whether a skin can do
-various things such as:  record, report and suppress errors; process command
-line options;  wrap system calls;  record extra information about malloc'd
-blocks, etc.<p>
+Second, various ``needs'' can be set for a skin, using the functions
+<code>VG_(needs_*)()</code>.  They are mostly booleans, and can be left
+untouched (they default to <code>False</code>).  They determine whether a skin
+can do various things such as:  record, report and suppress errors; process
+command line options;  wrap system calls;  record extra information about
+malloc'd blocks, etc.<p>
 
 For example, if a skin wants the core's help in recording and reporting errors,
 it must set the <code>skin_errors</code> need to <code>True</code>, and then
@@ -391,18 +391,20 @@
 <code>VgNeeds</code> in <code>include/vg_skin.h</code> for full details of all
 the needs.<p>
 
-The third argument to <code>SK_(pre_clo_init)()</code> must be initialised to
-indicate which events in core the skin wants to be notified about.  These
-include things such as blocks of memory being malloc'd, the stack pointer
-changing, a mutex being locked, etc.  If a skin wants to know about this,
-it should set the relevant pointer in the structure to point to a function,
-which will be called when that event happens.<p>
+Third, the skin can indicate which events in core it wants to be notified
+about, using the functions <code>VG_(track_*)()</code>.  These include things
+such as blocks of memory being malloc'd, the stack pointer changing, a mutex
+being locked, etc.  If a skin wants to know about this, it should set the
+relevant pointer in the structure to point to a function, which will be called
+when that event happens.<p>
 
 For example, if the skin want to be notified when a new block of memory is
-malloc'd, it should set the <code>new_mem_heap</code> function pointer, and the
-assigned function will be called each time this happens.  See the type
-<code>VgTrackEvents</code> in <code>include/vg_skin.h</code> for full details
-of all the trackable events.<p>
+malloc'd, it should call <code>VG_(track_new_mem_heap)()</code> with an
+appropriate function pointer, and the assigned function will be called each
+time this happens.<p>
+
+More information about ``details'', ``needs'' and ``trackable events'' can be
+found in <code>include/vg_skin.h</code>.<p>
 
 <a name="instr"></a>
 <h3>2.7&nbsp; Instrumentation</h3>
@@ -675,9 +677,8 @@
   <li>If you write a skin</li><p>
   <li>If you have suggestions for new features, needs, trackable events,
       functions</li><p>
-  <li>If you have suggestions for making skins easier to write
-  </li><p>
-  <li>If you have suggestions for improving this documentation  </li><p>
+  <li>If you have suggestions for making skins easier to write</li><p>
+  <li>If you have suggestions for improving this documentation</li><p>
   <li>If you don't understand something</li><p>
 </ul>
 
diff --git a/coregrind/vg_default.c b/coregrind/vg_default.c
index 83008d4..8778b84 100644
--- a/coregrind/vg_default.c
+++ b/coregrind/vg_default.c
@@ -71,7 +71,7 @@
    ------------------------------------------------------------------ */
 
 __attribute__ ((weak))
-void SK_(pre_clo_init)(VgDetails* details, VgNeeds* needs, VgTrackEvents* track)
+void SK_(pre_clo_init)( void )
 {
    fund_panic("SK_(pre_clo_init)");
 }
@@ -99,38 +99,37 @@
    ------------------------------------------------------------------ */
 
 __attribute__ ((weak))
-Bool SK_(eq_SkinError)(VgRes res, SkinError* e1, SkinError* e2)
+Bool SK_(eq_SkinError)(VgRes res, Error* e1, Error* e2)
 {
    non_fund_panic("SK_(eq_SkinError)");
 }
 
 __attribute__ ((weak))
-void SK_(pp_SkinError)(SkinError* ec, void (*pp_ExeContext)(void))
+void SK_(pp_SkinError)(Error* err, void (*pp_ExeContext)(void))
 {
    non_fund_panic("SK_(pp_SkinError)");
 }
 
 __attribute__ ((weak))
-void SK_(dup_extra_and_update)(SkinError* ec)
+void* SK_(dup_extra_and_update)(Error* err)
 {
    non_fund_panic("SK_(dup_extra_and_update)");
 }
 
 __attribute__ ((weak))
-Bool SK_(recognised_suppression)(Char* name, SuppKind* skind)
+Bool SK_(recognised_suppression)(Char* name, Supp* su)
 {
    non_fund_panic("SK_(recognised_suppression)");
 }
 
 __attribute__ ((weak))
-Bool SK_(read_extra_suppression_info)(Int fd, Char* buf, 
-                                       Int nBuf, SkinSupp *s)
+Bool SK_(read_extra_suppression_info)(Int fd, Char* buf, Int nBuf, Supp* su)
 {
    non_fund_panic("SK_(read_extra_suppression_info)");
 }
 
 __attribute__ ((weak))
-Bool SK_(error_matches_suppression)(SkinError* ec, SkinSupp* su)
+Bool SK_(error_matches_suppression)(Error* err, Supp* su)
 {
    non_fund_panic("SK_(error_matches_suppression)");
 }
@@ -213,7 +212,7 @@
 }
 
 __attribute__ ((weak))
-Int SK_(get_Xreg_usage)(UInstr* u, Tag tag, RegUse* arr)
+Int SK_(get_Xreg_usage)(UInstr* u, Tag tag, Int* regs, Bool* isWrites)
 {
    non_fund_panic("SK_(get_Xreg_usage)");
 }
diff --git a/coregrind/vg_errcontext.c b/coregrind/vg_errcontext.c
index b01ca57..4d82b50 100644
--- a/coregrind/vg_errcontext.c
+++ b/coregrind/vg_errcontext.c
@@ -36,11 +36,11 @@
 
 /* The list of error contexts found, both suppressed and unsuppressed.
    Initially empty, and grows as errors are detected. */
-static CoreError* vg_errors = NULL;
+static Error* vg_errors = NULL;
 
 /* The list of suppression directives, as read from the specified
    suppressions file. */
-static CoreSupp* vg_suppressions = NULL;
+static Supp* vg_suppressions = NULL;
 
 /* Running count of unsuppressed errors detected. */
 static UInt vg_n_errs_found = 0;
@@ -49,7 +49,7 @@
 static UInt vg_n_errs_suppressed = 0;
 
 /* forwards ... */
-static CoreSupp* is_suppressible_error ( CoreError* err );
+static Supp* is_suppressible_error ( Error* err );
 
 
 /*------------------------------------------------------------*/
@@ -59,34 +59,34 @@
 /* Compare error contexts, to detect duplicates.  Note that if they
    are otherwise the same, the faulting addrs and associated rwoffsets
    are allowed to be different.  */
-static Bool eq_CoreError ( VgRes res, CoreError* e1, CoreError* e2 )
+static Bool eq_Error ( VgRes res, Error* e1, Error* e2 )
 {
-   if (e1->skin_err.ekind != e2->skin_err.ekind) 
+   if (e1->ekind != e2->ekind) 
       return False;
    if (!VG_(eq_ExeContext)(res, e1->where, e2->where))
       return False;
 
-   switch (e1->skin_err.ekind) {
+   switch (e1->ekind) {
       case PThreadErr:
          vg_assert(VG_(needs).core_errors);
-         if (e1->skin_err.string == e2->skin_err.string) 
+         if (e1->string == e2->string) 
             return True;
-         if (0 == VG_(strcmp)(e1->skin_err.string, e2->skin_err.string))
+         if (0 == VG_(strcmp)(e1->string, e2->string))
             return True;
          return False;
       default: 
          if (VG_(needs).skin_errors)
-            return SK_(eq_SkinError)(res, &e1->skin_err, &e2->skin_err);
+            return SK_(eq_SkinError)(res, e1, e2);
          else {
             VG_(printf)("\nUnhandled error type: %u. VG_(needs).skin_errors\n"
                         "probably needs to be set.\n",
-                        e1->skin_err.ekind);
+                        e1->ekind);
             VG_(skin_panic)("unhandled error type");
          }
    }
 }
 
-static void pp_CoreError ( CoreError* err, Bool printCount )
+static void pp_Error ( Error* err, Bool printCount )
 {
    /* Closure for printing where the error occurred.  Abstracts details
       about the `where' field away from the skin. */
@@ -100,19 +100,19 @@
    if (err->tid > 1)
       VG_(message)(Vg_UserMsg, "Thread %d:", err->tid );
 
-   switch (err->skin_err.ekind) {
+   switch (err->ekind) {
       case PThreadErr:
          vg_assert(VG_(needs).core_errors);
-         VG_(message)(Vg_UserMsg, "%s", err->skin_err.string );
+         VG_(message)(Vg_UserMsg, "%s", err->string );
          VG_(pp_ExeContext)(err->where);
          break;
       default: 
          if (VG_(needs).skin_errors)
-            SK_(pp_SkinError)( &err->skin_err, &pp_ExeContextClosure );
+            SK_(pp_SkinError)( err, &pp_ExeContextClosure );
          else {
             VG_(printf)("\nUnhandled error type: %u.  VG_(needs).skin_errors\n"
                         "probably needs to be set?\n",
-                        err->skin_err.ekind);
+                        err->ekind);
             VG_(skin_panic)("unhandled error type");
          }
    }
@@ -175,10 +175,10 @@
      stored thread state, not from VG_(baseBlock).  
 */
 static __inline__
-void construct_error ( CoreError* err, ThreadState* tst, 
+void construct_error ( Error* err, ThreadState* tst, 
                        ErrorKind ekind, Addr a, Char* s, void* extra )
 {
-   /* CoreError parts */
+   /* Core-only parts */
    err->next     = NULL;
    err->supp     = NULL;
    err->count    = 1;
@@ -200,11 +200,11 @@
       err->m_ebp = tst->m_ebp;
    }
 
-   /* SkinError parts */
-   err->skin_err.ekind  = ekind;
-   err->skin_err.addr   = a;
-   err->skin_err.string = s;
-   err->skin_err.extra  = extra;
+   /* Skin-relevant parts */
+   err->ekind  = ekind;
+   err->addr   = a;
+   err->string = s;
+   err->extra  = extra;
 
    /* sanity... */
    vg_assert(err->tid >= 0 && err->tid < VG_N_THREADS);
@@ -216,14 +216,14 @@
 void VG_(maybe_record_error) ( ThreadState* tst, 
                                ErrorKind ekind, Addr a, Char* s, void* extra )
 {
-   CoreError   err;
-   CoreError*  p;
-   CoreError*  p_prev;
-   VgRes       exe_res                = Vg_MedRes;
-   static Bool is_first_shown_context = True;
-   static Bool stopping_message       = False;
-   static Bool slowdown_message       = False;
-   static Int  vg_n_errs_shown        = 0;
+          Error  err;
+          Error* p;
+          Error* p_prev;
+          VgRes  exe_res                = Vg_MedRes;
+   static Bool   is_first_shown_context = True;
+   static Bool   stopping_message       = False;
+   static Bool   slowdown_message       = False;
+   static Int    vg_n_errs_shown        = 0;
 
    /* After M_VG_COLLECT_NO_ERRORS_AFTER_SHOWN different errors have
       been found, or M_VG_COLLECT_NO_ERRORS_AFTER_FOUND total errors
@@ -286,7 +286,7 @@
    p      = vg_errors;
    p_prev = NULL;
    while (p != NULL) {
-      if (eq_CoreError(exe_res, p, &err)) {
+      if (eq_Error(exe_res, p, &err)) {
          /* Found it. */
          p->count++;
 	 if (p->supp != NULL) {
@@ -316,19 +316,19 @@
    /* OK, we're really going to collect it.  First make a copy,
       because the error context is on the stack and will disappear shortly.
       We can duplicate the main part ourselves, but use
-      SK_(dup_extra_and_update) to duplicate the 'extra' part (unless it's
+      SK_(dup_extra_and_update) to duplicate the `extra' part (unless it's
       NULL).
      
-      SK_(dup_extra_and_update) can also update the SkinError.  This is
+      SK_(dup_extra_and_update) can also update the `extra' part.  This is
       for when there are more details to fill in which take time to work out
       but don't affect our earlier decision to include the error -- by
       postponing those details until now, we avoid the extra work in the
-      case where we ignore the error.
+      case where we ignore the error.  Ugly.
     */
-   p = VG_(arena_malloc)(VG_AR_ERRORS, sizeof(CoreError));
+   p = VG_(arena_malloc)(VG_AR_ERRORS, sizeof(Error));
    *p = err;
-   if (NULL != err.skin_err.extra)
-      SK_(dup_extra_and_update)(&p->skin_err);
+   if (NULL != err.extra)
+      p->extra = SK_(dup_extra_and_update)(p);
 
    p->next = vg_errors;
    p->supp = is_suppressible_error(&err);
@@ -337,7 +337,7 @@
       vg_n_errs_found++;
       if (!is_first_shown_context)
          VG_(message)(Vg_UserMsg, "");
-      pp_CoreError(p, False);      
+      pp_Error(p, False);      
       is_first_shown_context = False;
       vg_n_errs_shown++;
       /* Perhaps we want a GDB attach at this point? */
@@ -369,11 +369,11 @@
 
 void VG_(show_all_errors) ( void )
 {
-   Int        i, n_min;
-   Int        n_err_contexts, n_supp_contexts;
-   CoreError *p, *p_min;
-   CoreSupp   *su;
-   Bool       any_supp;
+   Int    i, n_min;
+   Int    n_err_contexts, n_supp_contexts;
+   Error *p, *p_min;
+   Supp  *su;
+   Bool   any_supp;
 
    if (VG_(clo_verbosity) == 0)
       return;
@@ -416,7 +416,7 @@
       VG_(message)(Vg_UserMsg, "%d errors in context %d of %d:",
                    p_min->count,
                    i+1, n_err_contexts);
-      pp_CoreError( p_min, False );
+      pp_Error( p_min, False );
 
       if ((i+1 == VG_(clo_dump_error))) {
 	VG_(translate) ( 0 /* dummy ThreadId; irrelevant due to below NULLs */,
@@ -558,11 +558,11 @@
 
    while (True) {
       /* Assign and initialise the two suppression halves (core and skin) */
-      CoreSupp* supp;
-      supp        = VG_(arena_malloc)(VG_AR_CORE, sizeof(CoreSupp));
+      Supp* supp;
+      supp        = VG_(arena_malloc)(VG_AR_CORE, sizeof(Supp));
       supp->count = 0;
       for (i = 0; i < VG_N_SUPP_CALLERS; i++) supp->caller[i] = NULL;
-      supp->skin_supp.string = supp->skin_supp.extra = NULL;
+      supp->string = supp->extra = NULL;
 
       eof = VG_(get_line) ( fd, buf, N_BUF );
       if (eof) break;
@@ -593,7 +593,7 @@
       if (VG_(needs).core_errors && skin_name_present("core", skin_names))
       {
          if (STREQ(supp_name, "PThread"))
-            supp->skin_supp.skind = PThreadSupp;
+            supp->skind = PThreadSupp;
          else
             goto syntax_error;
       }
@@ -602,9 +602,9 @@
       else if (VG_(needs).skin_errors && 
                skin_name_present(VG_(details).name, skin_names))
       {
-         if (SK_(recognised_suppression)(supp_name, & supp->skin_supp.skind)) 
+         if (SK_(recognised_suppression)(supp_name, supp)) 
          {
-            /* Do nothing, function fills in supp->skin_supp.skind */
+            /* Do nothing, function fills in supp->skind */
          } else
             goto syntax_error;
       }
@@ -621,7 +621,7 @@
       }
 
       if (VG_(needs).skin_errors && 
-          !SK_(read_extra_suppression_info)(fd, buf, N_BUF, &supp->skin_supp)) 
+          !SK_(read_extra_suppression_info)(fd, buf, N_BUF, supp)) 
          goto syntax_error;
 
       /* "i > 0" ensures at least one caller read. */
@@ -687,28 +687,27 @@
 }     
 
 static __inline__
-Bool supp_matches_error(CoreSupp* su, CoreError* err)
+Bool supp_matches_error(Supp* su, Error* err)
 {
-   switch (su->skin_supp.skind) {
+   switch (su->skind) {
       case PThreadSupp:
-         return (err->skin_err.ekind == PThreadErr);
+         return (err->ekind == PThreadErr);
       default:
          if (VG_(needs).skin_errors) {
-            return (SK_(error_matches_suppression)(&err->skin_err, 
-                                                    &su->skin_supp));
+            return SK_(error_matches_suppression)(err, su);
          } else {
             VG_(printf)(
                "\nUnhandled suppression type: %u.  VG_(needs).skin_errors\n"
                "probably needs to be set.\n",
-               err->skin_err.ekind);
+               err->ekind);
             VG_(skin_panic)("unhandled suppression type");
          }
    }
 }
 
 static __inline__
-Bool supp_matches_callers(CoreSupp* su, Char caller_obj[][M_VG_ERRTXT], 
-                                        Char caller_fun[][M_VG_ERRTXT])
+Bool supp_matches_callers(Supp* su, Char caller_obj[][M_VG_ERRTXT], 
+                                    Char caller_fun[][M_VG_ERRTXT])
 {
    Int i;
 
@@ -728,19 +727,18 @@
    return True;
 }
 
-/* Does an error context match a suppression?  ie is this a
-   suppressible error?  If so, return a pointer to the CoreSupp
-   record, otherwise NULL.
+/* Does an error context match a suppression?  ie is this a suppressible
+   error?  If so, return a pointer to the Supp record, otherwise NULL.
    Tries to minimise the number of symbol searches since they are expensive.  
 */
-static CoreSupp* is_suppressible_error ( CoreError* err )
+static Supp* is_suppressible_error ( Error* err )
 {
    Int i;
 
    Char caller_obj[VG_N_SUPP_CALLERS][M_VG_ERRTXT];
    Char caller_fun[VG_N_SUPP_CALLERS][M_VG_ERRTXT];
 
-   CoreSupp* su;
+   Supp* su;
 
    /* get_objname_fnname() writes the function name and object name if
       it finds them in the debug info.  so the strings in the suppression
diff --git a/coregrind/vg_include.h b/coregrind/vg_include.h
index 0db3c65..8b559f1 100644
--- a/coregrind/vg_include.h
+++ b/coregrind/vg_include.h
@@ -279,6 +279,129 @@
 
 
 /* ---------------------------------------------------------------------
+   Skin-related types
+   ------------------------------------------------------------------ */
+/* These structs are not exposed to skins to mitigate possibility of
+   binary-incompatibilities when the core/skin interface changes.  Instead,
+   set functions are provided (see include/vg_skin.h). */
+typedef
+   struct {
+      Char* name;
+      Char* version;
+      Char* description;
+      Char* copyright_author;
+      Char* bug_reports_to;
+   }
+   VgDetails;
+
+extern VgDetails VG_(details);
+
+/* If new fields are added to this type, update:
+ *  - vg_main.c:initialisation of VG_(needs)
+ *  - vg_main.c:sanity_check_needs()
+ *
+ * If the name of this type or any of its fields change, update:
+ *  - dependent comments (just search for "VG_(needs)"). 
+ */
+typedef
+   struct {
+      Bool libc_freeres;
+      Bool core_errors;
+
+      Bool skin_errors;
+      Bool basic_block_discards;
+      Bool shadow_regs;
+      Bool command_line_options;
+      Bool client_requests;
+      Bool extended_UCode;
+      Bool syscall_wrapper;
+      UInt sizeof_shadow_block;
+      Bool alternative_free;
+      Bool sanity_checks;
+      Bool data_syms;
+   } 
+   VgNeeds;
+
+extern VgNeeds VG_(needs);
+
+/* Events happening in core to track.  To be notified, assign a function
+   to the function pointer.  To ignore an event, don't do anything
+   (default assignment is to NULL in which case the call is skipped). */
+typedef
+   struct {
+      /* Memory events */
+      void (*new_mem_startup)( Addr a, UInt len, Bool rr, Bool ww, Bool xx );
+      void (*new_mem_heap)   ( Addr a, UInt len, Bool is_inited );
+      void (*new_mem_stack)  ( Addr a, UInt len );
+      void (*new_mem_stack_aligned) ( Addr a, UInt len );
+      void (*new_mem_stack_signal)  ( Addr a, UInt len );
+      void (*new_mem_brk)    ( Addr a, UInt len );
+      void (*new_mem_mmap)   ( Addr a, UInt len, Bool rr, Bool ww, Bool xx );
+
+      void (*copy_mem_heap)  ( Addr from, Addr to, UInt len );
+      void (*copy_mem_remap) ( Addr from, Addr to, UInt len );
+      void (*change_mem_mprotect) ( Addr a, UInt len, Bool rr, Bool ww, Bool xx );
+      
+      /* Used on redzones around malloc'd blocks and at end of stack */
+      void (*ban_mem_heap)   ( Addr a, UInt len );
+      void (*ban_mem_stack)  ( Addr a, UInt len );
+
+      void (*die_mem_heap)   ( Addr a, UInt len );
+      void (*die_mem_stack)  ( Addr a, UInt len );
+      void (*die_mem_stack_aligned) ( Addr a, UInt len );
+      void (*die_mem_stack_signal)  ( Addr a, UInt len );
+      void (*die_mem_brk)    ( Addr a, UInt len );
+      void (*die_mem_munmap) ( Addr a, UInt len );
+
+      void (*bad_free)        ( ThreadState* tst, Addr a );
+      void (*mismatched_free) ( ThreadState* tst, Addr a );
+
+      void (*pre_mem_read)   ( CorePart part, ThreadState* tst,
+                               Char* s, Addr a, UInt size );
+      void (*pre_mem_read_asciiz) ( CorePart part, ThreadState* tst,
+                                    Char* s, Addr a );
+      void (*pre_mem_write)  ( CorePart part, ThreadState* tst,
+                               Char* s, Addr a, UInt size );
+      /* Not implemented yet -- have to add in lots of places, which is a
+         pain.  Won't bother unless/until there's a need. */
+      /* void (*post_mem_read)  ( ThreadState* tst, Char* s, 
+                                  Addr a, UInt size ); */
+      void (*post_mem_write) ( Addr a, UInt size );
+
+
+      /* Scheduler events (not exhaustive) */
+      void (*thread_run) ( ThreadId tid );
+
+
+      /* Thread events (not exhaustive) */
+      void (*post_thread_create) ( ThreadId tid, ThreadId child );
+      void (*post_thread_join)   ( ThreadId joiner, ThreadId joinee );
+
+
+      /* Mutex events (not exhaustive) */
+      void (*pre_mutex_lock)    ( ThreadId tid, 
+                                  void* /*pthread_mutex_t* */ mutex );
+      void (*post_mutex_lock)   ( ThreadId tid, 
+                                  void* /*pthread_mutex_t* */ mutex );
+      void (*post_mutex_unlock) ( ThreadId tid, 
+                                  void* /*pthread_mutex_t* */ mutex );
+
+      
+      /* Others... condition variable, signal events... */
+      /* ... */
+   }
+   VgTrackEvents;
+
+extern VgTrackEvents VG_(track_events);
+
+
+/* ---------------------------------------------------------------------
+   Exports of vg_needs.c
+   ------------------------------------------------------------------ */
+
+void VG_(sanity_check_needs)(void);
+
+/* ---------------------------------------------------------------------
    Exports of vg_malloc2.c
    ------------------------------------------------------------------ */
 
@@ -936,6 +1059,16 @@
    Exports of vg_translate.c
    ------------------------------------------------------------------ */
 
+/* Expandable arrays of uinstrs. */
+struct _UCodeBlock { 
+   Int     used; 
+   Int     size; 
+   UInstr* instrs;
+   Int     nextTemp;
+};
+
+extern UCodeBlock* VG_(alloc_UCodeBlock) ( void );
+
 extern void  VG_(translate)  ( ThreadState* tst,
                                Addr  orig_addr,
                                UInt* orig_size,
@@ -998,23 +1131,29 @@
    }
    SuppLocTy;
 
-/* Suppressions.  Skin part `SkinSupp' (which is all skins have to deal
-   with) is in vg_skin.h */
-typedef
-   struct _CoreSupp {
-      struct _CoreSupp* next;
-      /* The number of times this error has been suppressed. */
-      Int count;
-      /* The name by which the suppression is referred to. */
-      Char* sname;
-      /* First two (name of fn where err occurs, and immediate caller)
-       * are mandatory;  extra two are optional. */
-      SuppLocTy caller_ty[VG_N_SUPP_CALLERS];
-      Char*     caller   [VG_N_SUPP_CALLERS];
-      /* The skin-specific part */
-      SkinSupp  skin_supp;
-   } 
-   CoreSupp;
+/* Suppressions.  Skins can get/set skin-relevant parts with functions
+   declared in include/vg_skin.h.  Extensible via the 'extra' field. 
+   Skins can use a normal enum (with element values in the normal range
+   (0..)) for `skind'. */
+struct _Supp {
+   struct _Supp* next;
+   /* The number of times this error has been suppressed. */
+   Int count;
+   /* The name by which the suppression is referred to. */
+   Char* sname;
+   /* First two (name of fn where err occurs, and immediate caller)
+    * are mandatory;  extra two are optional. */
+   SuppLocTy caller_ty[VG_N_SUPP_CALLERS];
+   Char*     caller   [VG_N_SUPP_CALLERS];
+
+   /* The skin-specific part */
+   /* What kind of suppression.  Must use the range (0..) */
+   SuppKind skind;
+   /* String -- use is optional.  NULL by default. */
+   Char* string;
+   /* Anything else -- use is optional.  NULL by default. */
+   void* extra;
+};
 
 /* Note: it is imperative this doesn't overlap with (0..) at all, as skins
  * effectively extend it by defining their own enums in the (0..) range. */
@@ -1024,27 +1163,40 @@
    }
    CoreErrorKind;
 
-/* Errors.  Skin part `SkinError' (which is all skins have to deal
-   with) is in vg_skin.h */
-typedef
-   struct _CoreErrContext {
-      struct _CoreErrContext* next;
-      /* NULL if unsuppressed; or ptr to suppression record. */
-      CoreSupp* supp;
-      Int count;
-      ExeContext* where;
-      ThreadId tid;
-      /* These record %EIP, %ESP and %EBP at the error point.  They
-         are only used to make GDB-attaching convenient; there is no
-         other purpose; specifically they are not used to do
-         comparisons between errors. */
-      UInt m_eip;
-      UInt m_esp;
-      UInt m_ebp;
-      /* The skin-specific part */
-      SkinError skin_err;
-   } 
-   CoreError;
+/* Errors.  Extensible (via the 'extra' field).  Skins can use a normal
+   enum (with element values in the normal range (0..)) for `ekind'. 
+   Functions for getting/setting the skin-relevant fields are in
+   include/vg_skin.h.
+
+   When errors are found and recorded with VG_(maybe_record_error)(), all
+   the skin must do is pass in the four parameters;  core will
+   allocate/initialise the error record.
+*/
+struct _Error {
+   struct _Error* next;
+   /* NULL if unsuppressed; or ptr to suppression record. */
+   Supp* supp;
+   Int count;
+   ExeContext* where;
+   ThreadId tid;
+   /* These record %EIP, %ESP and %EBP at the error point.  They
+      are only used to make GDB-attaching convenient; there is no
+      other purpose; specifically they are not used to do
+      comparisons between errors. */
+   UInt m_eip;
+   UInt m_esp;
+   UInt m_ebp;
+
+   /* The skin-specific part */
+   /* Used by ALL.  Must be in the range (0..) */
+   Int ekind;
+   /* Used frequently */
+   Addr addr;
+   /* Used frequently */
+   Char* string;
+   /* For any skin-specific extras */
+   void* extra;
+};
 
 
 extern void VG_(load_suppressions)    ( void );
@@ -1087,6 +1239,26 @@
    Exports of vg_clientmalloc.c
    ------------------------------------------------------------------ */
 
+typedef
+   enum { 
+      Vg_AllocMalloc = 0,
+      Vg_AllocNew    = 1,
+      Vg_AllocNewVec = 2 
+   }
+   VgAllocKind;
+
+/* Description of a malloc'd chunk.  Functions for extracting skin-relevant
+   parts are in include/vg_skin.h Size of skin_extra array is given by
+   VG_(needs).sizeof_shadow_chunk. */
+struct _ShadowChunk {
+   struct _ShadowChunk* next;
+   UInt          size : 30;      /* size requested                   */
+   VgAllocKind   allockind : 2;  /* which wrapper did the allocation */
+   Addr          data;           /* ptr to actual block              */
+   UInt          extra[0];       /* extra skin-specific info         */
+};
+
+
 extern void  VG_(client_malloc_init)();
 
 /* These are called from the scheduler, when it intercepts a user
diff --git a/coregrind/vg_main.c b/coregrind/vg_main.c
index 900d3e1..163b64b 100644
--- a/coregrind/vg_main.c
+++ b/coregrind/vg_main.c
@@ -444,94 +444,6 @@
 
 
 /* ---------------------------------------------------------------------
-   Skin data structure initialisation
-   ------------------------------------------------------------------ */
-
-/* Init with default values. */
-VgDetails VG_(details) = {
-   .name             = NULL,
-   .version          = NULL,
-   .description      = NULL,
-   .copyright_author = NULL,
-   .bug_reports_to   = NULL,
-};
-
-VgNeeds VG_(needs) = {
-   .core_errors          = False,
-   .skin_errors          = False,
-   .libc_freeres         = False,
-   .sizeof_shadow_block  = 0,
-   .basic_block_discards = False,
-   .shadow_regs          = False,
-   .command_line_options = False,
-   .client_requests      = False,
-   .extended_UCode       = False,
-   .syscall_wrapper      = False,
-   .alternative_free     = False,
-   .sanity_checks        = False,
-   .data_syms	         = False,
-};
-
-VgTrackEvents VG_(track_events) = {
-   /* Memory events */
-   .new_mem_startup       = NULL,
-   .new_mem_heap          = NULL,
-   .new_mem_stack         = NULL,
-   .new_mem_stack_aligned = NULL,
-   .new_mem_stack_signal  = NULL,
-   .new_mem_brk           = NULL,
-   .new_mem_mmap          = NULL,
-
-   .copy_mem_heap         = NULL,
-   .copy_mem_remap        = NULL,
-   .change_mem_mprotect   = NULL,
-
-   .ban_mem_heap          = NULL,
-   .ban_mem_stack         = NULL,
-
-   .die_mem_heap          = NULL,
-   .die_mem_stack         = NULL,
-   .die_mem_stack_aligned = NULL,
-   .die_mem_stack_signal  = NULL,
-   .die_mem_brk           = NULL,
-   .die_mem_munmap        = NULL,
-
-   .bad_free              = NULL,
-   .mismatched_free       = NULL,
-
-   .pre_mem_read          = NULL,
-   .pre_mem_read_asciiz   = NULL,
-   .pre_mem_write         = NULL,
-   .post_mem_write        = NULL,
-
-   /* Scheduler events */
-   .thread_run            = NULL,
-
-   /* Mutex events */
-   .post_mutex_lock       = NULL,
-   .post_mutex_unlock     = NULL,
-};
-
-static void sanity_check_needs ( void )
-{
-#define CHECK_NOT(var, value)                               \
-   if ((var)==(value)) {                                    \
-      VG_(printf)("\nSkin error: `%s' not initialised\n",   \
-                  VG__STRING(var));                         \
-      VG_(skin_panic)("Uninitialised needs field\n");       \
-   }
-   
-   CHECK_NOT(VG_(details).name,             NULL);
-   /* Nb: .version can be NULL */
-   CHECK_NOT(VG_(details).description,      NULL);
-   CHECK_NOT(VG_(details).copyright_author, NULL);
-   CHECK_NOT(VG_(details).bug_reports_to,   NULL);
-
-#undef CHECK_NOT
-#undef INVALID_Bool
-}
-
-/* ---------------------------------------------------------------------
    Values derived from command-line options.
    ------------------------------------------------------------------ */
 
@@ -1350,8 +1262,8 @@
         and turn on/off 'command_line_options' need
       - init_memory() (to setup memory event trackers).
     */
-   SK_(pre_clo_init) ( & VG_(details), & VG_(needs), & VG_(track_events) );
-   sanity_check_needs();
+   SK_(pre_clo_init)();
+   VG_(sanity_check_needs)();
 
    /* Process Valgrind's command-line opts (from env var VG_ARGS). */
    process_cmd_line_options();
diff --git a/coregrind/vg_needs.c b/coregrind/vg_needs.c
new file mode 100644
index 0000000..5abeffd
--- /dev/null
+++ b/coregrind/vg_needs.c
@@ -0,0 +1,337 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Stuff relating to skin data structures.                      ---*/
+/*---                                                   vg_needs.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, an extensible x86 protected-mode
+   emulator for monitoring program execution on x86-Unixes.
+
+   Copyright (C) 2000-2002 Nicholas Nethercote
+      jseward@acm.org
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307, USA.
+
+   The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "vg_include.h"
+
+
+/* ---------------------------------------------------------------------
+   Skin data structure initialisation
+   ------------------------------------------------------------------ */
+
+/* Init with default values. */
+VgDetails VG_(details) = {
+   .name             = NULL,
+   .version          = NULL,
+   .description      = NULL,
+   .copyright_author = NULL,
+   .bug_reports_to   = NULL,
+};
+
+VgNeeds VG_(needs) = {
+   .core_errors          = False,
+   .skin_errors          = False,
+   .libc_freeres         = False,
+   .sizeof_shadow_block  = 0,
+   .basic_block_discards = False,
+   .shadow_regs          = False,
+   .command_line_options = False,
+   .client_requests      = False,
+   .extended_UCode       = False,
+   .syscall_wrapper      = False,
+   .alternative_free     = False,
+   .sanity_checks        = False,
+   .data_syms	         = False,
+};
+
+VgTrackEvents VG_(track_events) = {
+   /* Memory events */
+   .new_mem_startup       = NULL,
+   .new_mem_heap          = NULL,
+   .new_mem_stack         = NULL,
+   .new_mem_stack_aligned = NULL,
+   .new_mem_stack_signal  = NULL,
+   .new_mem_brk           = NULL,
+   .new_mem_mmap          = NULL,
+
+   .copy_mem_heap         = NULL,
+   .copy_mem_remap        = NULL,
+   .change_mem_mprotect   = NULL,
+
+   .ban_mem_heap          = NULL,
+   .ban_mem_stack         = NULL,
+
+   .die_mem_heap          = NULL,
+   .die_mem_stack         = NULL,
+   .die_mem_stack_aligned = NULL,
+   .die_mem_stack_signal  = NULL,
+   .die_mem_brk           = NULL,
+   .die_mem_munmap        = NULL,
+
+   .bad_free              = NULL,
+   .mismatched_free       = NULL,
+
+   .pre_mem_read          = NULL,
+   .pre_mem_read_asciiz   = NULL,
+   .pre_mem_write         = NULL,
+   .post_mem_write        = NULL,
+
+   /* Scheduler events */
+   .thread_run            = NULL,
+
+   /* Mutex events */
+   .post_mutex_lock       = NULL,
+   .post_mutex_unlock     = NULL,
+};
+
+/* static */
+void VG_(sanity_check_needs) ( void)
+{
+#define CHECK_NOT(var, value)                               \
+   if ((var)==(value)) {                                    \
+      VG_(printf)("\nSkin error: `%s' not initialised\n",   \
+                  VG__STRING(var));                         \
+      VG_(skin_panic)("Uninitialised needs field\n");       \
+   }
+   
+   CHECK_NOT(VG_(details).name,             NULL);
+   /* Nb: .version can be NULL */
+   CHECK_NOT(VG_(details).description,      NULL);
+   CHECK_NOT(VG_(details).copyright_author, NULL);
+   CHECK_NOT(VG_(details).bug_reports_to,   NULL);
+
+#undef CHECK_NOT
+#undef INVALID_Bool
+}
+
+/*--------------------------------------------------------------------*/
+/* Setting details */
+
+/* Use macro because they're so repetitive */
+#define DETAILS(detail)  \
+   extern void VG_(details_##detail)(Char* detail) \
+   {                                   \
+      VG_(details).detail = detail;          \
+   }
+
+DETAILS(name)
+DETAILS(version)
+DETAILS(description)
+DETAILS(copyright_author)
+DETAILS(bug_reports_to)
+
+/*--------------------------------------------------------------------*/
+/* Setting needs */
+
+/* Use macro because they're so repetitive */
+#define NEEDS(need)  \
+   extern void VG_(needs_##need)(void) \
+   {                                   \
+      VG_(needs).need = True;          \
+   }
+
+NEEDS(libc_freeres)
+NEEDS(core_errors)
+NEEDS(skin_errors)
+NEEDS(basic_block_discards)
+NEEDS(shadow_regs)
+NEEDS(command_line_options)
+NEEDS(client_requests)
+NEEDS(extended_UCode)
+NEEDS(syscall_wrapper)
+
+extern void VG_(needs_sizeof_shadow_block)(Int size)
+{
+   VG_(needs).sizeof_shadow_block = size;
+}
+
+NEEDS(alternative_free)
+NEEDS(sanity_checks)
+NEEDS(data_syms)
+
+/*--------------------------------------------------------------------*/
+#define TRACK(event, args...)  \
+   void VG_(track_##event)(void (*f)(args)) \
+   {                                      \
+      VG_(track_events).event = f;        \
+   }
+
+TRACK(new_mem_startup,       Addr a, UInt len, Bool rr, Bool ww, Bool xx)
+TRACK(new_mem_heap,          Addr a, UInt len, Bool is_inited)
+TRACK(new_mem_stack,         Addr a, UInt len)
+TRACK(new_mem_stack_aligned, Addr a, UInt len)
+TRACK(new_mem_stack_signal,  Addr a, UInt len)
+TRACK(new_mem_brk,           Addr a, UInt len)
+TRACK(new_mem_mmap,          Addr a, UInt len, Bool rr, Bool ww, Bool xx)
+
+TRACK(copy_mem_heap,       Addr from, Addr to, UInt len)
+TRACK(copy_mem_remap,      Addr from, Addr to, UInt len)
+TRACK(change_mem_mprotect, Addr a, UInt len, Bool rr, Bool ww, Bool xx)
+
+TRACK(ban_mem_heap,  Addr a, UInt len)
+TRACK(ban_mem_stack, Addr a, UInt len)
+
+TRACK(die_mem_heap,          Addr a, UInt len)
+TRACK(die_mem_stack,         Addr a, UInt len)
+TRACK(die_mem_stack_aligned, Addr a, UInt len)
+TRACK(die_mem_stack_signal,  Addr a, UInt len)
+TRACK(die_mem_brk,           Addr a, UInt len)
+TRACK(die_mem_munmap,        Addr a, UInt len)
+
+TRACK(bad_free,        ThreadState* tst, Addr a)
+TRACK(mismatched_free, ThreadState* tst, Addr a)
+
+TRACK(pre_mem_read,        CorePart part, ThreadState* tst, Char* s, Addr a,
+                           UInt size)
+TRACK(pre_mem_read_asciiz, CorePart part, ThreadState* tst, Char* s, Addr a)
+TRACK(pre_mem_write,       CorePart part, ThreadState* tst, Char* s, Addr a,
+                           UInt size)
+TRACK(post_mem_write,      Addr a, UInt size)
+
+TRACK(thread_run, ThreadId tid)
+
+TRACK(post_thread_create, ThreadId tid, ThreadId child)
+TRACK(post_thread_join,   ThreadId joiner, ThreadId joinee)
+
+TRACK( pre_mutex_lock,   ThreadId tid, void* /*pthread_mutex_t* */ mutex)
+TRACK(post_mutex_lock,   ThreadId tid, void* /*pthread_mutex_t* */ mutex)
+TRACK(post_mutex_unlock, ThreadId tid, void* /*pthread_mutex_t* */ mutex)
+
+/*--------------------------------------------------------------------*/
+/* UCodeBlocks */
+
+Int VG_(get_num_instrs) ( UCodeBlock* cb )
+{
+   return cb->used;
+}
+
+Int VG_(get_num_temps) ( UCodeBlock* cb )
+{
+   return cb->nextTemp;
+}
+
+UInstr* VG_(get_instr) ( UCodeBlock* cb, Int i )
+{
+   return & cb->instrs[i];
+}
+
+UInstr* VG_(get_last_instr) ( UCodeBlock* cb )
+{
+   return & cb->instrs[cb->used-1];
+}
+   
+/*--------------------------------------------------------------------*/
+/* Suppressions */
+
+SuppKind VG_(get_supp_kind) ( Supp* su )
+{
+   return su->skind;
+}
+
+Char* VG_(get_supp_string) ( Supp* su )
+{
+   return su->string;
+}
+
+void* VG_(get_supp_extra)  ( Supp* su )
+{
+   return su->extra;
+}
+
+
+void VG_(set_supp_kind)   ( Supp* su, SuppKind skind )
+{
+   su->skind = skind;
+}
+
+void VG_(set_supp_string) ( Supp* su, Char* string )
+{
+   su->string = string;
+}
+
+void VG_(set_supp_extra)  ( Supp* su, void* extra )
+{
+   su->extra = extra;
+}
+
+/*--------------------------------------------------------------------*/
+/* Errors */
+
+ErrorKind VG_(get_error_kind) ( Error* err )
+{
+   return err->ekind;
+}
+
+Addr VG_(get_error_address) ( Error* err )
+{
+   return err->addr;
+}
+
+Char* VG_(get_error_string) ( Error* err )
+{
+   return err->string;
+}
+
+void* VG_(get_error_extra)  ( Error* err )
+{
+   return err->extra;
+}
+
+/*--------------------------------------------------------------------*/
+/* ShadowChunks */
+
+UInt VG_(get_sc_size)  ( ShadowChunk* sc )
+{
+   return sc->size;
+}
+
+Addr VG_(get_sc_data)  ( ShadowChunk* sc )
+{
+   return sc->data;
+}
+
+UInt VG_(get_sc_extra) ( ShadowChunk* sc, UInt i )
+{
+   vg_assert(i < VG_(needs).sizeof_shadow_block);
+   return sc->extra[i];
+}
+
+ShadowChunk* VG_(get_sc_next)  ( ShadowChunk* sc )
+{
+   return sc->next;
+}
+
+void VG_(set_sc_extra) ( ShadowChunk* sc, UInt i, UInt word )
+{
+   vg_assert(i < VG_(needs).sizeof_shadow_block);
+   sc->extra[i] = word;
+}
+
+void VG_(set_sc_next)  ( ShadowChunk* sc, ShadowChunk* next )
+{
+   sc->next = next;
+}
+
+
+/*--------------------------------------------------------------------*/
+/*--- end                                               vg_needs.c ---*/
+/*--------------------------------------------------------------------*/
+
+
diff --git a/coregrind/vg_to_ucode.c b/coregrind/vg_to_ucode.c
index 99bf7b1..601b2ee 100644
--- a/coregrind/vg_to_ucode.c
+++ b/coregrind/vg_to_ucode.c
@@ -236,19 +236,6 @@
 /*--- Flag-related helpers.                                ---*/
 /*------------------------------------------------------------*/
 
-/* For the last uinsn inserted into cb, set the read, written and
-   undefined flags.  Undefined flags are counted as written, but it
-   seems worthwhile to distinguish them. 
-*/
-static __inline__ void uFlagsRWU ( UCodeBlock* cb,
-                                   FlagSet rr, FlagSet ww, FlagSet uu )
-{
-   VG_(set_flag_RW)(
-      &LAST_UINSTR(cb), rr, VG_UNION_FLAG_SETS(ww,uu)
-   );
-}
-
-
 static void setFlagsFromUOpcode ( UCodeBlock* cb, Int uopc )
 {
    switch (uopc) {
@@ -275,7 +262,8 @@
    }
 }
 
-static __inline__ void uCond ( UCodeBlock* cb, Condcode cond )
+__inline__
+void VG_(set_cond_field) ( UCodeBlock* cb, Condcode cond )
 {
    LAST_UINSTR(cb).cond = cond;
 }
diff --git a/coregrind/vg_translate.c b/coregrind/vg_translate.c
index 0b6175a..8f5ac3d 100644
--- a/coregrind/vg_translate.c
+++ b/coregrind/vg_translate.c
@@ -42,6 +42,7 @@
 /*--- Basics                                               ---*/
 /*------------------------------------------------------------*/
 
+/* This one is called by the core */
 UCodeBlock* VG_(alloc_UCodeBlock) ( void )
 {
    UCodeBlock* cb = VG_(arena_malloc)(VG_AR_CORE, sizeof(UCodeBlock));
@@ -50,6 +51,15 @@
    return cb;
 }
 
+/* This one is called by skins */
+UCodeBlock* VG_(setup_UCodeBlock) ( UCodeBlock* cb_in )
+{
+   UCodeBlock* cb = VG_(arena_malloc)(VG_AR_CORE, sizeof(UCodeBlock));
+   cb->used = cb->size = 0;
+   cb->nextTemp = cb_in->nextTemp;
+   cb->instrs = NULL;
+   return cb;
+}
 
 void VG_(free_UCodeBlock) ( UCodeBlock* cb )
 {
@@ -205,17 +215,6 @@
 }
 
 
-/* Set the flag R/W sets on a uinstr. */
-void VG_(set_flag_RW) ( UInstr* u, FlagSet fr, FlagSet fw )
-{
-   /* VG_(pp_UInstr)(-1,u); */
-   vg_assert(fr == (fr & FlagsALL));
-   vg_assert(fw == (fw & FlagsALL));
-   u->flags_r = fr;
-   u->flags_w = fw;
-}
-
-
 /* Set the lit32 field of the most recent uinsn. */
 void VG_(set_lit_field) ( UCodeBlock* cb, UInt lit32 )
 {
@@ -235,6 +234,23 @@
    LAST_UINSTR(cb).has_ret_val = has_ret_val;
 }
 
+/* For the last uinsn inserted into cb, set the read, written and
+   undefined flags.  Undefined flags are counted as written, but it
+   seems worthwhile to distinguish them. 
+*/
+__inline__
+void VG_(set_flag_fields) ( UCodeBlock* cb,
+                             FlagSet rr, FlagSet ww, FlagSet uu )
+{
+   FlagSet uw = VG_UNION_FLAG_SETS(ww,uu);
+   
+   vg_assert(rr == (rr & FlagsALL));
+   vg_assert(uw == (uw & FlagsALL));
+   LAST_UINSTR(cb).flags_r = rr;
+   LAST_UINSTR(cb).flags_w = uw;
+}
+
+
 Bool VG_(any_flag_use) ( UInstr* u )
 {
    return (u->flags_r != FlagsEmpty 
@@ -1075,18 +1091,18 @@
 /*------------------------------------------------------------*/
 
 /* Get the temp/reg use of a uinstr, parking them in an array supplied by
-   the caller, which is assumed to be big enough.  Return the number
-   of entries.  Insns which read _and_ write a register wind up
-   mentioning it twice.  Entries are placed in the array in program
-   order, so that if a reg is read-modified-written, it appears first
-   as a read and then as a write.  'tag' indicates whether we are looking at
-   TempRegs or RealRegs.
+   the caller (regs), which is assumed to be big enough.  Return the number
+   of entries.  Written regs are indicated in parallel array isWrites.
+   Insns which read _and_ write a register wind up mentioning it twice.
+   Entries are placed in the array in program order, so that if a reg is
+   read-modified-written, it appears first as a read and then as a write.
+   'tag' indicates whether we are looking at TempRegs or RealRegs.
 */
 __inline__
-Int VG_(get_reg_usage) ( UInstr* u, Tag tag, RegUse* arr )
+Int VG_(get_reg_usage) ( UInstr* u, Tag tag, Int* regs, Bool* isWrites )
 {
-#  define RD(ono)    VG_UINSTR_READS_REG(ono)
-#  define WR(ono)    VG_UINSTR_WRITES_REG(ono)
+#  define RD(ono)    VG_UINSTR_READS_REG(ono, regs, isWrites)
+#  define WR(ono)    VG_UINSTR_WRITES_REG(ono, regs, isWrites)
 
    Int n = 0;
    switch (u->opcode) {
@@ -1142,7 +1158,7 @@
 
       default:
          if (VG_(needs).extended_UCode)
-            return SK_(get_Xreg_usage)(u, tag, arr);
+            return SK_(get_Xreg_usage)(u, tag, regs, isWrites);
          else {
             VG_(printf)("unhandled opcode: %u.  Perhaps " 
                         "VG_(needs).extended_UCode should be set?",
@@ -1160,26 +1176,26 @@
 /* Change temp regs in u into real regs, as directed by the
  * temps[i]-->reals[i] mapping. */
 static __inline__
-void patchUInstr ( UInstr* u, RegUse temps[], UInt reals[], Int n_tmap )
+void patchUInstr ( UInstr* u, Int temps[], UInt reals[], Int n_tmap )
 {
    Int i;
    if (u->tag1 == TempReg) {
       for (i = 0; i < n_tmap; i++)
-         if (temps[i].num == u->val1) break;
+         if (temps[i] == u->val1) break;
       if (i == n_tmap) VG_(core_panic)("patchUInstr(1)");
       u->tag1 = RealReg;
       u->val1 = reals[i];
    }
    if (u->tag2 == TempReg) {
       for (i = 0; i < n_tmap; i++)
-         if (temps[i].num == u->val2) break;
+         if (temps[i] == u->val2) break;
       if (i == n_tmap) VG_(core_panic)("patchUInstr(2)");
       u->tag2 = RealReg;
       u->val2 = reals[i];
    }
    if (u->tag3 == TempReg) {
       for (i = 0; i < n_tmap; i++)
-         if (temps[i].num == u->val3) break;
+         if (temps[i] == u->val3) break;
       if (i == n_tmap) VG_(core_panic)("patchUInstr(3)");
       u->tag3 = RealReg;
       u->val3 = reals[i];
@@ -1255,10 +1271,12 @@
 Bool uInstrMentionsTempReg ( UInstr* u, Int tempreg )
 {
    Int i, k;
-   RegUse tempUse[3];
-   k = VG_(get_reg_usage) ( u, TempReg, &tempUse[0] );
+   Int tempUse[3];
+   Bool notUsed[3];
+
+   k = VG_(get_reg_usage) ( u, TempReg, &tempUse[0], &notUsed[0] );
    for (i = 0; i < k; i++)
-      if (tempUse[i].num == tempreg)
+      if (tempUse[i] == tempreg)
          return True;
    return False;
 }
@@ -1280,7 +1298,8 @@
    Int     i, j, k, m, n, ar, tr, told, actual_areg;
    Int     areg_map[8];
    Bool    annul_put[8];
-   RegUse  tempUse[3];
+   Int     tempUse[3];
+   Bool    isWrites[3];
    UInstr* u;
    Bool    wr;
    Int*    last_live_before;
@@ -1307,12 +1326,12 @@
    for (i = cb->used-1; i >= 0; i--) {
       u = &cb->instrs[i];
 
-      k = VG_(get_reg_usage)(u, TempReg, &tempUse[0]);
+      k = VG_(get_reg_usage)(u, TempReg, &tempUse[0], &isWrites[0]);
 
       /* For each temp usage ... bwds in program order. */
       for (j = k-1; j >= 0; j--) {
-         tr = tempUse[j].num;
-         wr = tempUse[j].isWrite;
+         tr = tempUse[j];
+         wr = isWrites[j];
          if (last_live_before[tr] == -1) {
             vg_assert(tr >= 0 && tr < cb->nextTemp);
             last_live_before[tr] = wr ? (i+1) : i;
@@ -1413,12 +1432,12 @@
          }
 
          /* boring insn; invalidate any mappings to temps it writes */
-         k = VG_(get_reg_usage)(u, TempReg, &tempUse[0]);
+         k = VG_(get_reg_usage)(u, TempReg, &tempUse[0], &isWrites[0]);
 
          for (j = 0; j < k; j++) {
-            wr  = tempUse[j].isWrite;
+            wr  = isWrites[j];
             if (!wr) continue;
-            tr = tempUse[j].num;
+            tr = tempUse[j];
             for (m = 0; m < 8; m++)
                if (areg_map[m] == tr) areg_map[m] = -1;
          }
@@ -1621,7 +1640,8 @@
    Int          i, j, k, m, r, tno, max_ss_no;
    Bool         wr, defer, isRead, spill_reqd;
    UInt         realUse[3];
-   RegUse       tempUse[3];
+   Int          tempUse[3];
+   Bool         isWrites[3];
    UCodeBlock*  c2;
 
    /* Used to denote ... well, "no value" in this fn. */
@@ -1646,13 +1666,14 @@
    /* Scan fwds to establish live ranges. */
 
    for (i = 0; i < c1->used; i++) {
-      k = VG_(get_reg_usage)(&c1->instrs[i], TempReg, &tempUse[0]);
+      k = VG_(get_reg_usage)(&c1->instrs[i], TempReg, &tempUse[0],
+                             &isWrites[0]);
       vg_assert(k >= 0 && k <= 3);
 
       /* For each temp usage ... fwds in program order */
       for (j = 0; j < k; j++) {
-         tno = tempUse[j].num;
-         wr  = tempUse[j].isWrite;
+         tno = tempUse[j];
+         wr  = isWrites[j];
          if (wr) {
             /* Writes hold a reg live until after this insn. */
             if (temp_info[tno].live_after == VG_NOTHING)
@@ -1781,7 +1802,8 @@
          generate spill stores since we may have to evict some TempRegs
          currently in real regs.  Also generates spill loads. */
 
-      k = VG_(get_reg_usage)(&c1->instrs[i], TempReg, &tempUse[0]);
+      k = VG_(get_reg_usage)(&c1->instrs[i], TempReg, &tempUse[0],
+                             &isWrites[0]);
       vg_assert(k >= 0 && k <= 3);
 
       /* For each ***different*** temp mentioned in the insn .... */
@@ -1792,14 +1814,14 @@
             used by the insn once, even if it is mentioned more than
             once. */
          defer = False;
-         tno = tempUse[j].num;
+         tno = tempUse[j];
          for (m = j+1; m < k; m++)
-            if (tempUse[m].num == tno) 
+            if (tempUse[m] == tno) 
                defer = True;
          if (defer) 
             continue;
 
-         /* Now we're trying to find a register for tempUse[j].num.
+         /* Now we're trying to find a register for tempUse[j].
             First of all, if it already has a register assigned, we
             don't need to do anything more. */
          if (temp_info[tno].real_no != VG_NOTHING)
@@ -1825,7 +1847,7 @@
 
             Select r in 0 .. VG_MAX_REALREGS-1 such that
             real_to_temp[r] is not mentioned in 
-            tempUse[0 .. k-1].num, since it would be just plain 
+            tempUse[0 .. k-1], since it would be just plain 
             wrong to eject some other TempReg which we need to use in 
             this insn.
 
@@ -1836,7 +1858,7 @@
          for (r = 0; r < VG_MAX_REALREGS; r++) {
             is_spill_cand[r] = True;
             for (m = 0; m < k; m++) {
-               if (real_to_temp[r] == tempUse[m].num) {
+               if (real_to_temp[r] == tempUse[m]) {
                   is_spill_cand[r] = False;
                   break;
                }
@@ -1898,7 +1920,7 @@
          /* Decide if tno is read. */
          isRead = False;
          for (m = 0; m < k; m++)
-            if (tempUse[m].num == tno && !tempUse[m].isWrite) 
+            if (tempUse[m] == tno && !isWrites[m]) 
                isRead = True;
 
          /* If so, generate a spill load. */
@@ -1922,7 +1944,7 @@
          and use patchUInstr to convert its rTempRegs into
          realregs. */
       for (j = 0; j < k; j++)
-         realUse[j] = VG_(rank_to_realreg)(temp_info[tempUse[j].num].real_no);
+         realUse[j] = VG_(rank_to_realreg)(temp_info[tempUse[j]].real_no);
       VG_(copy_UInstr)(c2, &c1->instrs[i]);
       patchUInstr(&LAST_UINSTR(c2), &tempUse[0], &realUse[0], k);
 
@@ -1951,7 +1973,8 @@
 {        
    Int      i, j, k;
    RRegSet  rregs_live;
-   RegUse   regUse[3];
+   Int      regUse[3];
+   Bool     isWrites[3];
    UInstr*  u;
 
    /* All regs are dead at the end of the block */
@@ -1962,16 +1985,16 @@
 
       u->regs_live_after = rregs_live;
 
-      k = VG_(get_reg_usage)(u, RealReg, regUse);
+      k = VG_(get_reg_usage)(u, RealReg, &regUse[0], &isWrites[0]);
 
       /* For each reg usage ... bwds in program order.  Variable is live
          before this UInstr if it is read by this UInstr.
-         Note that regUse[j].num holds the Intel reg number, so we must
+         Note that regUse[j] holds the Intel reg number, so we must
          convert it to our rank number.  */
       for (j = k-1; j >= 0; j--) {
-         SET_RREG_LIVENESS ( VG_(realreg_to_rank)(regUse[j].num),
+         SET_RREG_LIVENESS ( VG_(realreg_to_rank)(regUse[j]),
                              rregs_live,
-                             !regUse[j].isWrite );
+                             !isWrites[j] );
       }
    }
 }