]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Plumb the right %EIP and %EBP values through to VG_(get_ExeContext)
authorJulian Seward <jseward@acm.org>
Sun, 14 Apr 2002 04:16:48 +0000 (04:16 +0000)
committerJulian Seward <jseward@acm.org>
Sun, 14 Apr 2002 04:16:48 +0000 (04:16 +0000)
now that we have the additional complication of multiple threads.

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@64

14 files changed:
coregrind/vg_clientmalloc.c
coregrind/vg_errcontext.c
coregrind/vg_execontext.c
coregrind/vg_include.h
coregrind/vg_memory.c
coregrind/vg_scheduler.c
vg_clientmalloc.c
vg_clientperms.c
vg_errcontext.c
vg_execontext.c
vg_include.h
vg_memory.c
vg_scheduler.c
vg_syscall_mem.c

index d59a029a197f6c922c86ab5c31ae0d3c4759784a..eb450dfe16c4984e6fc29758e2a116a92bcd1614 100644 (file)
@@ -209,7 +209,8 @@ static void add_to_freed_queue ( ShadowChunk* sc )
    shadow chunk on the appropriate list, and set all memory
    protections correctly. */
 
-static ShadowChunk* client_malloc_shadow ( UInt align, UInt size, 
+static ShadowChunk* client_malloc_shadow ( ThreadState* tst,
+                                           UInt align, UInt size, 
                                            VgAllocKind kind )
 {
    ShadowChunk* sc;
@@ -229,7 +230,7 @@ static ShadowChunk* client_malloc_shadow ( UInt align, UInt size,
       p = (Addr)VG_(malloc_aligned)(VG_AR_CLIENT, align, size);
 
    sc        = VG_(malloc)(VG_AR_PRIVATE, sizeof(ShadowChunk));
-   sc->where = VG_(get_ExeContext)(True);
+   sc->where = VG_(get_ExeContext)(True, tst->m_eip, tst->m_ebp);
    sc->size  = size;
    sc->allockind = kind;
    sc->data  = p;
@@ -250,7 +251,7 @@ static ShadowChunk* client_malloc_shadow ( UInt align, UInt size,
 /* Allocate memory, noticing whether or not we are doing the full
    instrumentation thing. */
 
-void* VG_(client_malloc) ( UInt size, VgAllocKind kind )
+void* VG_(client_malloc) ( ThreadState* tst, UInt size, VgAllocKind kind )
 {
    ShadowChunk* sc;
 
@@ -271,13 +272,13 @@ void* VG_(client_malloc) ( UInt size, VgAllocKind kind )
       return VG_(malloc) ( VG_AR_CLIENT, size );
    }
 
-   sc = client_malloc_shadow ( 0, size, kind );
+   sc = client_malloc_shadow ( tst, 0, size, kind );
    VGP_POPCC;
    return (void*)(sc->data);
 }
 
 
-void* VG_(client_memalign) ( UInt align, UInt size )
+void* VG_(client_memalign) ( ThreadState* tst, UInt align, UInt size )
 {
    ShadowChunk* sc;
    VGP_PUSHCC(VgpCliMalloc);
@@ -296,13 +297,13 @@ void* VG_(client_memalign) ( UInt align, UInt size )
       VGP_POPCC;
       return VG_(malloc_aligned) ( VG_AR_CLIENT, align, size );
    }
-   sc = client_malloc_shadow ( align, size, Vg_AllocMalloc );
+   sc = client_malloc_shadow ( tst, align, size, Vg_AllocMalloc );
    VGP_POPCC;
    return (void*)(sc->data);
 }
 
 
-void VG_(client_free) ( void* ptrV, VgAllocKind kind )
+void VG_(client_free) ( ThreadState* tst, void* ptrV, VgAllocKind kind )
 {
    ShadowChunk* sc;
    UInt         ml_no;
@@ -350,7 +351,7 @@ void VG_(client_free) ( void* ptrV, VgAllocKind kind )
    VGM_(make_noaccess) ( sc->data - VG_AR_CLIENT_REDZONE_SZB, 
                          sc->size + 2*VG_AR_CLIENT_REDZONE_SZB );
    VGM_(make_noaccess) ( (Addr)sc, sizeof(ShadowChunk) );
-   sc->where = VG_(get_ExeContext)(True);
+   sc->where = VG_(get_ExeContext)(True, tst->m_eip, tst->m_ebp);
 
    /* Put it out of harm's way for a while. */
    add_to_freed_queue ( sc );
@@ -359,7 +360,7 @@ void VG_(client_free) ( void* ptrV, VgAllocKind kind )
 
 
 
-void* VG_(client_calloc) ( UInt nmemb, UInt size1 )
+void* VG_(client_calloc) ( ThreadState* tst, UInt nmemb, UInt size1 )
 {
    ShadowChunk* sc;
    Addr         p;
@@ -386,7 +387,7 @@ void* VG_(client_calloc) ( UInt nmemb, UInt size1 )
    size      = nmemb * size1;
    p         = (Addr)VG_(malloc)(VG_AR_CLIENT, size);
    sc        = VG_(malloc)(VG_AR_PRIVATE, sizeof(ShadowChunk));
-   sc->where = VG_(get_ExeContext)(True);
+   sc->where = VG_(get_ExeContext)(True, tst->m_eip, tst->m_ebp);
    sc->size  = size;
    sc->allockind = Vg_AllocMalloc; /* its a lie - but true. eat this :) */
    sc->data  = p;
@@ -407,7 +408,7 @@ void* VG_(client_calloc) ( UInt nmemb, UInt size1 )
 }
 
 
-void* VG_(client_realloc) ( void* ptrV, UInt size_new )
+void* VG_(client_realloc) ( ThreadState* tst, void* ptrV, UInt size_new )
 {
    ShadowChunk *sc, *sc_new;
    UInt         i, ml_no;
@@ -466,7 +467,7 @@ void* VG_(client_realloc) ( void* ptrV, UInt size_new )
       return ptrV;
    } else {
       /* new size is bigger */
-      sc_new = client_malloc_shadow ( 0, size_new, Vg_AllocMalloc );
+      sc_new = client_malloc_shadow ( tst, 0, size_new, Vg_AllocMalloc );
       for (i = 0; i < sc->size; i++)
          ((UChar*)(sc_new->data))[i] = ((UChar*)(sc->data))[i];
       VGM_(copy_address_range_perms) ( 
index 178594ce52e864faef11999bf02e19a588b7f336..29d8b2c9de3c20ae5d84cae6966a89192ed556f2 100644 (file)
@@ -537,13 +537,19 @@ static void VG_(maybe_add_context) ( ErrContext* ec )
 /*--- Exported fns                                         ---*/
 /*------------------------------------------------------------*/
 
+/* These are all called from generated code, so that the %EIP/%EBP
+   values that we need in order to create proper error messages are
+   picked up out of VG_(baseBlock) rather than from the thread table
+   (vg_threads in vg_scheduler.c). */
+
 void VG_(record_value_error) ( Int size )
 {
    ErrContext ec;
    clear_ErrContext( &ec );
    ec.count = 1;
    ec.next  = NULL;
-   ec.where = VG_(get_ExeContext)( False );
+   ec.where = VG_(get_ExeContext)( False, VG_(baseBlock)[VGOFF_(m_eip)], 
+                                          VG_(baseBlock)[VGOFF_(m_ebp)] );
    ec.ekind = ValueErr;
    ec.size  = size;
    VG_(maybe_add_context) ( &ec );
@@ -555,13 +561,15 @@ void VG_(record_address_error) ( Addr a, Int size, Bool isWrite )
 
    /* If this is caused by an access immediately below %ESP, and the
       user asks nicely, we just ignore it. */
-   if (VG_(clo_workaround_gcc296_bugs) && VG_(is_just_below_ESP)(a))
+   if (VG_(clo_workaround_gcc296_bugs) 
+       && VG_(is_just_below_ESP)( VG_(baseBlock)[VGOFF_(m_esp)], a ))
       return;
 
    clear_ErrContext( &ec );
    ec.count   = 1;
    ec.next    = NULL;
-   ec.where   = VG_(get_ExeContext)( False );
+   ec.where   = VG_(get_ExeContext)( False, VG_(baseBlock)[VGOFF_(m_eip)], 
+                                            VG_(baseBlock)[VGOFF_(m_ebp)] );
    ec.ekind   = AddrErr;
    ec.axskind = isWrite ? WriteAxs : ReadAxs;
    ec.size    = size;
@@ -576,7 +584,8 @@ void VG_(record_jump_error) ( Addr a )
    clear_ErrContext( &ec );
    ec.count   = 1;
    ec.next    = NULL;
-   ec.where   = VG_(get_ExeContext)( False );
+   ec.where   = VG_(get_ExeContext)( False, VG_(baseBlock)[VGOFF_(m_eip)], 
+                                            VG_(baseBlock)[VGOFF_(m_ebp)] );
    ec.ekind   = AddrErr;
    ec.axskind = ExecAxs;
    ec.addr    = a;
@@ -590,7 +599,8 @@ void VG_(record_free_error) ( Addr a )
    clear_ErrContext( &ec );
    ec.count   = 1;
    ec.next    = NULL;
-   ec.where   = VG_(get_ExeContext)( True );
+   ec.where   = VG_(get_ExeContext)( True, VG_(baseBlock)[VGOFF_(m_eip)], 
+                                           VG_(baseBlock)[VGOFF_(m_ebp)] );
    ec.ekind   = FreeErr;
    ec.addr    = a;
    VG_(describe_addr) ( a, &ec.addrinfo );
@@ -603,20 +613,26 @@ void VG_(record_freemismatch_error) ( Addr a )
    clear_ErrContext( &ec );
    ec.count   = 1;
    ec.next    = NULL;
-   ec.where   = VG_(get_ExeContext)( True );
+   ec.where   = VG_(get_ExeContext)( True, VG_(baseBlock)[VGOFF_(m_eip)], 
+                                           VG_(baseBlock)[VGOFF_(m_ebp)] );
    ec.ekind   = FreeMismatchErr;
    ec.addr    = a;
    VG_(describe_addr) ( a, &ec.addrinfo );
    VG_(maybe_add_context) ( &ec );
 }
 
-void VG_(record_param_err) ( Addr a, Bool isWriteLack, Char* msg )
+/* These two are called not from generated code but in response to
+   requests passed back to the scheduler.  So we pick up %EIP/%EBP
+   values from the stored thread state, not from VG_(baseBlock).  */
+
+void VG_(record_param_err) ( ThreadState* tst, Addr a, Bool isWriteLack, 
+                             Char* msg )
 {
    ErrContext ec;
    clear_ErrContext( &ec );
    ec.count   = 1;
    ec.next    = NULL;
-   ec.where   = VG_(get_ExeContext)( False );
+   ec.where   = VG_(get_ExeContext)( False, tst->m_eip, tst->m_ebp );
    ec.ekind   = ParamErr;
    ec.addr    = a;
    VG_(describe_addr) ( a, &ec.addrinfo );
@@ -626,13 +642,13 @@ void VG_(record_param_err) ( Addr a, Bool isWriteLack, Char* msg )
 }
 
 
-void VG_(record_user_err) ( Addr a, Bool isWriteLack )
+void VG_(record_user_err) ( ThreadState* tst, Addr a, Bool isWriteLack )
 {
    ErrContext ec;
    clear_ErrContext( &ec );
    ec.count   = 1;
    ec.next    = NULL;
-   ec.where   = VG_(get_ExeContext)( False );
+   ec.where   = VG_(get_ExeContext)( False, tst->m_eip, tst->m_ebp );
    ec.ekind   = UserErr;
    ec.addr    = a;
    VG_(describe_addr) ( a, &ec.addrinfo );
@@ -641,6 +657,8 @@ void VG_(record_user_err) ( Addr a, Bool isWriteLack )
 }
 
 
+/*------------------------------*/
+
 void VG_(show_all_errors) ( void )
 {
    Int         i, n_min;
index 759345b7a849715574d8d18c2f5ea174485d50fa..dfdb58555fcbaaec74a2a0a8cc6b384ea3b71f99 100644 (file)
@@ -154,11 +154,13 @@ Bool VG_(eq_ExeContext_top4) ( ExeContext* e1, ExeContext* e2 )
    duplicates, and so exact equality can be quickly done as equality
    on the returned ExeContext* values themselves.  Inspired by Hugs's
    Text type.  
+
+   In order to be thread-safe, we pass in the thread's %EIP and %EBP.
 */
-ExeContext* VG_(get_ExeContext) ( Bool skip_top_frame )
+ExeContext* VG_(get_ExeContext) ( Bool skip_top_frame,
+                                  Addr eip, Addr ebp )
 {
    Int         i;
-   UInt        ebp;
    Addr        eips[VG_DEEPEST_BACKTRACE];
    Bool        same;
    UInt        hash;
@@ -185,13 +187,11 @@ ExeContext* VG_(get_ExeContext) ( Bool skip_top_frame )
       lval = ebp = 0;                                             \
    }
 
-   ebp = VG_(baseBlock)[VGOFF_(m_ebp)];
-
    if (skip_top_frame) {
       for (i = 0; i < VG_(clo_backtrace_size); i++)
          GET_CALLER(eips[i]);
    } else {
-      eips[0] = VG_(baseBlock)[VGOFF_(m_eip)];
+      eips[0] = eip;
       for (i = 1; i < VG_(clo_backtrace_size); i++)
          GET_CALLER(eips[i]);
    }
index 5735b1c009545b7fc38cc9bd0ffbc3cfcf8b9203..6d7c4c3dedaafec1d87c10fc6a0bc55a95d0dc8e 100644 (file)
@@ -1024,7 +1024,8 @@ extern void VG_(show_ExeContext_stats) ( void );
 /* Take a snapshot of the client's stack.  Search our collection of
    ExeContexts to see if we already have it, and if not, allocate a
    new one.  Either way, return a pointer to the context. */
-extern ExeContext* VG_(get_ExeContext) ( Bool skip_top_frame );
+extern ExeContext* VG_(get_ExeContext) ( Bool skip_top_frame,
+                                         Addr eip, Addr ebp );
 
 /* Print an ExeContext. */
 extern void VG_(pp_ExeContext) ( ExeContext* );
@@ -1052,10 +1053,13 @@ extern void VG_(record_freemismatch_error)    ( Addr a );
 extern void VG_(record_address_error) ( Addr a, Int size, 
                                         Bool isWrite );
 extern void VG_(record_jump_error) ( Addr a );
-extern void VG_(record_param_err) ( Addr a, 
+
+extern void VG_(record_param_err) ( ThreadState* tst,
+                                    Addr a, 
                                     Bool isWriteLack, 
                                     Char* msg );
-extern void VG_(record_user_err) ( Addr a, Bool isWriteLack );
+extern void VG_(record_user_err) ( ThreadState* tst,
+                                   Addr a, Bool isWriteLack );
 
 
 /* The classification of a faulting address. */
@@ -1084,7 +1088,7 @@ typedef
 
 extern Bool VG_(client_perm_maybe_describe)( Addr a, AddrInfo* ai );
 
-extern UInt VG_(handle_client_request) ( UInt* arg_block );
+extern UInt VG_(handle_client_request) ( ThreadState* tst, UInt* arg_block );
 
 extern void VG_(delete_client_stack_blocks_following_ESP_change) ( void );
 
@@ -1150,11 +1154,16 @@ extern ShadowChunk** VG_(get_malloc_shadows) ( /*OUT*/ UInt* n_shadows );
 
 /* These are called from the scheduler, when it intercepts a user
    request. */
-extern void* VG_(client_malloc)   ( UInt size, VgAllocKind kind );
-extern void* VG_(client_memalign) ( UInt align, UInt size );
-extern void  VG_(client_free)     ( void* ptrV, VgAllocKind  kind );
-extern void* VG_(client_calloc)   ( UInt nmemb, UInt size1 );
-extern void* VG_(client_realloc)  ( void* ptrV, UInt size_new );
+extern void* VG_(client_malloc)   ( ThreadState* tst, 
+                                    UInt size, VgAllocKind kind );
+extern void* VG_(client_memalign) ( ThreadState* tst, 
+                                    UInt align, UInt size );
+extern void  VG_(client_free)     ( ThreadState* tst, 
+                                    void* ptrV, VgAllocKind  kind );
+extern void* VG_(client_calloc)   ( ThreadState* tst, 
+                                    UInt nmemb, UInt size1 );
+extern void* VG_(client_realloc)  ( ThreadState* tst, 
+                                    void* ptrV, UInt size_new );
 
 
 /* ---------------------------------------------------------------------
@@ -1342,7 +1351,7 @@ UInt VG_(scan_all_valid_memory) ( void (*notify_word)( Addr, UInt ) );
 
 /* Is this address within some small distance below %ESP?  Used only
    for the --workaround-gcc296-bugs kludge. */
-extern Bool VG_(is_just_below_ESP)( Addr aa );
+extern Bool VG_(is_just_below_ESP)( Addr esp, Addr aa );
 
 /* Nasty kludgery to deal with applications which switch stacks,
    like netscape. */
index b219a3a07fe22ecbd7ad64a68798cf6fae9cf559..5e932fbcdd970f2c9ad94709d84e99a14698c95b 100644 (file)
@@ -1331,11 +1331,10 @@ Bool VG_(is_plausible_stack_addr) ( Addr aa )
 
 /* Is this address within some small distance below %ESP?  Used only
    for the --workaround-gcc296-bugs kludge. */
-Bool VG_(is_just_below_ESP)( Addr aa )
+Bool VG_(is_just_below_ESP)( Addr esp, Addr aa )
 {
-   UInt esp = VG_(baseBlock)[VGOFF_(m_esp)];
-   if (esp > (UInt)aa
-       && (esp - (UInt)aa) <= VG_GCC296_BUG_STACK_SLOP)
+   if ((UInt)esp > (UInt)aa
+       && ((UInt)esp - (UInt)aa) <= VG_GCC296_BUG_STACK_SLOP)
       return True;
    else
       return False;
index 695f086efff3ef56d64d0bdf21661393569d3162..dc3024e5a7e985b9a1333360598822e90692098d 100644 (file)
@@ -57,8 +57,6 @@ suitable for use by anyone at all!
 - Read/write syscall starts: don't crap out when the initial
   nonblocking read/write returns an error.
 
-- 0xDEADBEEF syscall errors ... fix.
-
 */
 
 
@@ -507,45 +505,47 @@ static
 Bool maybe_do_trivial_clientreq ( ThreadId tid )
 {
 #  define SIMPLE_RETURN(vvv)                      \
-       { vg_threads[tid].m_edx = (vvv);           \
+       { tst->m_edx = (vvv);                      \
          return True;                             \
        }
 
-   UInt* arg    = (UInt*)(vg_threads[tid].m_eax);
-   UInt  req_no = arg[0];
+   ThreadState* tst    = &vg_threads[tid];
+   UInt*        arg    = (UInt*)(tst->m_eax);
+   UInt         req_no = arg[0];
+
    switch (req_no) {
       case VG_USERREQ__MALLOC:
          SIMPLE_RETURN(
-            (UInt)VG_(client_malloc) ( arg[1], Vg_AllocMalloc ) 
+            (UInt)VG_(client_malloc) ( tst, arg[1], Vg_AllocMalloc ) 
          );
       case VG_USERREQ__BUILTIN_NEW:
          SIMPLE_RETURN(
-            (UInt)VG_(client_malloc) ( arg[1], Vg_AllocNew )
+            (UInt)VG_(client_malloc) ( tst, arg[1], Vg_AllocNew )
          );
       case VG_USERREQ__BUILTIN_VEC_NEW:
          SIMPLE_RETURN(
-            (UInt)VG_(client_malloc) ( arg[1], Vg_AllocNewVec )
+            (UInt)VG_(client_malloc) ( tst, arg[1], Vg_AllocNewVec )
          );
       case VG_USERREQ__FREE:
-         VG_(client_free) ( (void*)arg[1], Vg_AllocMalloc );
+         VG_(client_free) ( tst, (void*)arg[1], Vg_AllocMalloc );
         SIMPLE_RETURN(0); /* irrelevant */
       case VG_USERREQ__BUILTIN_DELETE:
-         VG_(client_free) ( (void*)arg[1], Vg_AllocNew );
+         VG_(client_free) ( tst, (void*)arg[1], Vg_AllocNew );
         SIMPLE_RETURN(0); /* irrelevant */
       case VG_USERREQ__BUILTIN_VEC_DELETE:
-         VG_(client_free) ( (void*)arg[1], Vg_AllocNewVec );
+         VG_(client_free) ( tst, (void*)arg[1], Vg_AllocNewVec );
         SIMPLE_RETURN(0); /* irrelevant */
       case VG_USERREQ__CALLOC:
          SIMPLE_RETURN(
-            (UInt)VG_(client_calloc) ( arg[1], arg[2] )
+            (UInt)VG_(client_calloc) ( tst, arg[1], arg[2] )
          );
       case VG_USERREQ__REALLOC:
          SIMPLE_RETURN(
-            (UInt)VG_(client_realloc) ( (void*)arg[1], arg[2] )
+            (UInt)VG_(client_realloc) ( tst, (void*)arg[1], arg[2] )
          );
       case VG_USERREQ__MEMALIGN:
          SIMPLE_RETURN(
-            (UInt)VG_(client_memalign) ( arg[1], arg[2] )
+            (UInt)VG_(client_memalign) ( tst, arg[1], arg[2] )
          );
       default:
          /* Too hard; wimp out. */
@@ -1777,7 +1777,8 @@ void do_nontrivial_clientreq ( ThreadId tid )
       case VG_USERREQ__MAKE_NOACCESS_STACK:
       case VG_USERREQ__RUNNING_ON_VALGRIND:
       case VG_USERREQ__DO_LEAK_CHECK:
-         vg_threads[tid].m_edx = VG_(handle_client_request) ( arg );
+         vg_threads[tid].m_edx 
+            = VG_(handle_client_request) ( &vg_threads[tid], arg );
         break;
 
       case VG_USERREQ__SIGNAL_RETURNS: 
index d59a029a197f6c922c86ab5c31ae0d3c4759784a..eb450dfe16c4984e6fc29758e2a116a92bcd1614 100644 (file)
@@ -209,7 +209,8 @@ static void add_to_freed_queue ( ShadowChunk* sc )
    shadow chunk on the appropriate list, and set all memory
    protections correctly. */
 
-static ShadowChunk* client_malloc_shadow ( UInt align, UInt size, 
+static ShadowChunk* client_malloc_shadow ( ThreadState* tst,
+                                           UInt align, UInt size, 
                                            VgAllocKind kind )
 {
    ShadowChunk* sc;
@@ -229,7 +230,7 @@ static ShadowChunk* client_malloc_shadow ( UInt align, UInt size,
       p = (Addr)VG_(malloc_aligned)(VG_AR_CLIENT, align, size);
 
    sc        = VG_(malloc)(VG_AR_PRIVATE, sizeof(ShadowChunk));
-   sc->where = VG_(get_ExeContext)(True);
+   sc->where = VG_(get_ExeContext)(True, tst->m_eip, tst->m_ebp);
    sc->size  = size;
    sc->allockind = kind;
    sc->data  = p;
@@ -250,7 +251,7 @@ static ShadowChunk* client_malloc_shadow ( UInt align, UInt size,
 /* Allocate memory, noticing whether or not we are doing the full
    instrumentation thing. */
 
-void* VG_(client_malloc) ( UInt size, VgAllocKind kind )
+void* VG_(client_malloc) ( ThreadState* tst, UInt size, VgAllocKind kind )
 {
    ShadowChunk* sc;
 
@@ -271,13 +272,13 @@ void* VG_(client_malloc) ( UInt size, VgAllocKind kind )
       return VG_(malloc) ( VG_AR_CLIENT, size );
    }
 
-   sc = client_malloc_shadow ( 0, size, kind );
+   sc = client_malloc_shadow ( tst, 0, size, kind );
    VGP_POPCC;
    return (void*)(sc->data);
 }
 
 
-void* VG_(client_memalign) ( UInt align, UInt size )
+void* VG_(client_memalign) ( ThreadState* tst, UInt align, UInt size )
 {
    ShadowChunk* sc;
    VGP_PUSHCC(VgpCliMalloc);
@@ -296,13 +297,13 @@ void* VG_(client_memalign) ( UInt align, UInt size )
       VGP_POPCC;
       return VG_(malloc_aligned) ( VG_AR_CLIENT, align, size );
    }
-   sc = client_malloc_shadow ( align, size, Vg_AllocMalloc );
+   sc = client_malloc_shadow ( tst, align, size, Vg_AllocMalloc );
    VGP_POPCC;
    return (void*)(sc->data);
 }
 
 
-void VG_(client_free) ( void* ptrV, VgAllocKind kind )
+void VG_(client_free) ( ThreadState* tst, void* ptrV, VgAllocKind kind )
 {
    ShadowChunk* sc;
    UInt         ml_no;
@@ -350,7 +351,7 @@ void VG_(client_free) ( void* ptrV, VgAllocKind kind )
    VGM_(make_noaccess) ( sc->data - VG_AR_CLIENT_REDZONE_SZB, 
                          sc->size + 2*VG_AR_CLIENT_REDZONE_SZB );
    VGM_(make_noaccess) ( (Addr)sc, sizeof(ShadowChunk) );
-   sc->where = VG_(get_ExeContext)(True);
+   sc->where = VG_(get_ExeContext)(True, tst->m_eip, tst->m_ebp);
 
    /* Put it out of harm's way for a while. */
    add_to_freed_queue ( sc );
@@ -359,7 +360,7 @@ void VG_(client_free) ( void* ptrV, VgAllocKind kind )
 
 
 
-void* VG_(client_calloc) ( UInt nmemb, UInt size1 )
+void* VG_(client_calloc) ( ThreadState* tst, UInt nmemb, UInt size1 )
 {
    ShadowChunk* sc;
    Addr         p;
@@ -386,7 +387,7 @@ void* VG_(client_calloc) ( UInt nmemb, UInt size1 )
    size      = nmemb * size1;
    p         = (Addr)VG_(malloc)(VG_AR_CLIENT, size);
    sc        = VG_(malloc)(VG_AR_PRIVATE, sizeof(ShadowChunk));
-   sc->where = VG_(get_ExeContext)(True);
+   sc->where = VG_(get_ExeContext)(True, tst->m_eip, tst->m_ebp);
    sc->size  = size;
    sc->allockind = Vg_AllocMalloc; /* its a lie - but true. eat this :) */
    sc->data  = p;
@@ -407,7 +408,7 @@ void* VG_(client_calloc) ( UInt nmemb, UInt size1 )
 }
 
 
-void* VG_(client_realloc) ( void* ptrV, UInt size_new )
+void* VG_(client_realloc) ( ThreadState* tst, void* ptrV, UInt size_new )
 {
    ShadowChunk *sc, *sc_new;
    UInt         i, ml_no;
@@ -466,7 +467,7 @@ void* VG_(client_realloc) ( void* ptrV, UInt size_new )
       return ptrV;
    } else {
       /* new size is bigger */
-      sc_new = client_malloc_shadow ( 0, size_new, Vg_AllocMalloc );
+      sc_new = client_malloc_shadow ( tst, 0, size_new, Vg_AllocMalloc );
       for (i = 0; i < sc->size; i++)
          ((UChar*)(sc_new->data))[i] = ((UChar*)(sc->data))[i];
       VGM_(copy_address_range_perms) ( 
index f6351d371494f08e0535c98bdfa7741b23f5cabf..8594a3eee58f374a15961cd47657fcae95621082 100644 (file)
@@ -151,7 +151,7 @@ static UInt vg_csb_discards = 0;   /* Number of discards. */
 static UInt vg_csb_swaps    = 0;   /* Number of searches. */
 
 static
-void vg_add_client_stack_block ( Addr aa, UInt sz )
+void vg_add_client_stack_block ( ThreadState* tst, Addr aa, UInt sz )
 {
    UInt i, sz_new;
    CStackBlock* csbs_new;
@@ -180,7 +180,9 @@ void vg_add_client_stack_block ( Addr aa, UInt sz )
    /* Ok, we can use [vg_csb_used]. */
    vg_csbs[vg_csb_used].start = aa;
    vg_csbs[vg_csb_used].size  = sz;
-   vg_csbs[vg_csb_used].where = VG_(get_ExeContext) ( False );   
+   /* Actually running a thread at this point. */
+   vg_csbs[vg_csb_used].where 
+      = VG_(get_ExeContext) ( False, tst->m_eip, tst->m_ebp );
    vg_csb_used++;
 
    if (vg_csb_used > vg_csb_used_MAX)
@@ -289,7 +291,7 @@ void VG_(delete_client_stack_blocks_following_ESP_change) ( void )
 }
 
 
-UInt VG_(handle_client_request) ( UInt* arg_block )
+UInt VG_(handle_client_request) ( ThreadState* tst, UInt* arg_block )
 {
    Int   i;
    Bool  ok;
@@ -310,7 +312,8 @@ UInt VG_(handle_client_request) ( UInt* arg_block )
          vg_cgbs[i].kind  = CG_NoAccess;
          vg_cgbs[i].start = arg[1];
          vg_cgbs[i].size  = arg[2];
-         vg_cgbs[i].where = VG_(get_ExeContext) ( False );
+         vg_cgbs[i].where 
+            = VG_(get_ExeContext) ( False, tst->m_eip, tst->m_ebp );
          VGM_(make_noaccess) ( arg[1], arg[2] );
          return i;
       case VG_USERREQ__MAKE_WRITABLE: /* make writable */
@@ -318,7 +321,8 @@ UInt VG_(handle_client_request) ( UInt* arg_block )
          vg_cgbs[i].kind  = CG_Writable;
          vg_cgbs[i].start = arg[1];
          vg_cgbs[i].size  = arg[2];
-         vg_cgbs[i].where = VG_(get_ExeContext) ( False );
+         vg_cgbs[i].where 
+            = VG_(get_ExeContext) ( False, tst->m_eip, tst->m_ebp );
          VGM_(make_writable) ( arg[1], arg[2] );
          return i;
       case VG_USERREQ__MAKE_READABLE: /* make readable */
@@ -326,19 +330,20 @@ UInt VG_(handle_client_request) ( UInt* arg_block )
          vg_cgbs[i].kind  = CG_Readable;
          vg_cgbs[i].start = arg[1];
          vg_cgbs[i].size  = arg[2];
-         vg_cgbs[i].where = VG_(get_ExeContext) ( False );
+         vg_cgbs[i].where 
+            = VG_(get_ExeContext) ( False, tst->m_eip, tst->m_ebp );
          VGM_(make_readable) ( arg[1], arg[2] );
          return i;
 
       case VG_USERREQ__CHECK_WRITABLE: /* check writable */
          ok = VGM_(check_writable) ( arg[1], arg[2], &bad_addr );
          if (!ok)
-            VG_(record_user_err) ( bad_addr, True );
+            VG_(record_user_err) ( tst, bad_addr, True );
          return ok ? (UInt)NULL : bad_addr;
       case VG_USERREQ__CHECK_READABLE: /* check readable */
          ok = VGM_(check_readable) ( arg[1], arg[2], &bad_addr );
          if (!ok)
-            VG_(record_user_err) ( bad_addr, False );
+            VG_(record_user_err) ( tst, bad_addr, False );
          return ok ? (UInt)NULL : bad_addr;
 
       case VG_USERREQ__DISCARD: /* discard */
@@ -351,7 +356,7 @@ UInt VG_(handle_client_request) ( UInt* arg_block )
          return 0;
 
       case VG_USERREQ__MAKE_NOACCESS_STACK: /* make noaccess stack block */
-         vg_add_client_stack_block ( arg[1], arg[2] );
+         vg_add_client_stack_block ( tst, arg[1], arg[2] );
          return 0;
 
       case VG_USERREQ__RUNNING_ON_VALGRIND:
index 178594ce52e864faef11999bf02e19a588b7f336..29d8b2c9de3c20ae5d84cae6966a89192ed556f2 100644 (file)
@@ -537,13 +537,19 @@ static void VG_(maybe_add_context) ( ErrContext* ec )
 /*--- Exported fns                                         ---*/
 /*------------------------------------------------------------*/
 
+/* These are all called from generated code, so that the %EIP/%EBP
+   values that we need in order to create proper error messages are
+   picked up out of VG_(baseBlock) rather than from the thread table
+   (vg_threads in vg_scheduler.c). */
+
 void VG_(record_value_error) ( Int size )
 {
    ErrContext ec;
    clear_ErrContext( &ec );
    ec.count = 1;
    ec.next  = NULL;
-   ec.where = VG_(get_ExeContext)( False );
+   ec.where = VG_(get_ExeContext)( False, VG_(baseBlock)[VGOFF_(m_eip)], 
+                                          VG_(baseBlock)[VGOFF_(m_ebp)] );
    ec.ekind = ValueErr;
    ec.size  = size;
    VG_(maybe_add_context) ( &ec );
@@ -555,13 +561,15 @@ void VG_(record_address_error) ( Addr a, Int size, Bool isWrite )
 
    /* If this is caused by an access immediately below %ESP, and the
       user asks nicely, we just ignore it. */
-   if (VG_(clo_workaround_gcc296_bugs) && VG_(is_just_below_ESP)(a))
+   if (VG_(clo_workaround_gcc296_bugs) 
+       && VG_(is_just_below_ESP)( VG_(baseBlock)[VGOFF_(m_esp)], a ))
       return;
 
    clear_ErrContext( &ec );
    ec.count   = 1;
    ec.next    = NULL;
-   ec.where   = VG_(get_ExeContext)( False );
+   ec.where   = VG_(get_ExeContext)( False, VG_(baseBlock)[VGOFF_(m_eip)], 
+                                            VG_(baseBlock)[VGOFF_(m_ebp)] );
    ec.ekind   = AddrErr;
    ec.axskind = isWrite ? WriteAxs : ReadAxs;
    ec.size    = size;
@@ -576,7 +584,8 @@ void VG_(record_jump_error) ( Addr a )
    clear_ErrContext( &ec );
    ec.count   = 1;
    ec.next    = NULL;
-   ec.where   = VG_(get_ExeContext)( False );
+   ec.where   = VG_(get_ExeContext)( False, VG_(baseBlock)[VGOFF_(m_eip)], 
+                                            VG_(baseBlock)[VGOFF_(m_ebp)] );
    ec.ekind   = AddrErr;
    ec.axskind = ExecAxs;
    ec.addr    = a;
@@ -590,7 +599,8 @@ void VG_(record_free_error) ( Addr a )
    clear_ErrContext( &ec );
    ec.count   = 1;
    ec.next    = NULL;
-   ec.where   = VG_(get_ExeContext)( True );
+   ec.where   = VG_(get_ExeContext)( True, VG_(baseBlock)[VGOFF_(m_eip)], 
+                                           VG_(baseBlock)[VGOFF_(m_ebp)] );
    ec.ekind   = FreeErr;
    ec.addr    = a;
    VG_(describe_addr) ( a, &ec.addrinfo );
@@ -603,20 +613,26 @@ void VG_(record_freemismatch_error) ( Addr a )
    clear_ErrContext( &ec );
    ec.count   = 1;
    ec.next    = NULL;
-   ec.where   = VG_(get_ExeContext)( True );
+   ec.where   = VG_(get_ExeContext)( True, VG_(baseBlock)[VGOFF_(m_eip)], 
+                                           VG_(baseBlock)[VGOFF_(m_ebp)] );
    ec.ekind   = FreeMismatchErr;
    ec.addr    = a;
    VG_(describe_addr) ( a, &ec.addrinfo );
    VG_(maybe_add_context) ( &ec );
 }
 
-void VG_(record_param_err) ( Addr a, Bool isWriteLack, Char* msg )
+/* These two are called not from generated code but in response to
+   requests passed back to the scheduler.  So we pick up %EIP/%EBP
+   values from the stored thread state, not from VG_(baseBlock).  */
+
+void VG_(record_param_err) ( ThreadState* tst, Addr a, Bool isWriteLack, 
+                             Char* msg )
 {
    ErrContext ec;
    clear_ErrContext( &ec );
    ec.count   = 1;
    ec.next    = NULL;
-   ec.where   = VG_(get_ExeContext)( False );
+   ec.where   = VG_(get_ExeContext)( False, tst->m_eip, tst->m_ebp );
    ec.ekind   = ParamErr;
    ec.addr    = a;
    VG_(describe_addr) ( a, &ec.addrinfo );
@@ -626,13 +642,13 @@ void VG_(record_param_err) ( Addr a, Bool isWriteLack, Char* msg )
 }
 
 
-void VG_(record_user_err) ( Addr a, Bool isWriteLack )
+void VG_(record_user_err) ( ThreadState* tst, Addr a, Bool isWriteLack )
 {
    ErrContext ec;
    clear_ErrContext( &ec );
    ec.count   = 1;
    ec.next    = NULL;
-   ec.where   = VG_(get_ExeContext)( False );
+   ec.where   = VG_(get_ExeContext)( False, tst->m_eip, tst->m_ebp );
    ec.ekind   = UserErr;
    ec.addr    = a;
    VG_(describe_addr) ( a, &ec.addrinfo );
@@ -641,6 +657,8 @@ void VG_(record_user_err) ( Addr a, Bool isWriteLack )
 }
 
 
+/*------------------------------*/
+
 void VG_(show_all_errors) ( void )
 {
    Int         i, n_min;
index 759345b7a849715574d8d18c2f5ea174485d50fa..dfdb58555fcbaaec74a2a0a8cc6b384ea3b71f99 100644 (file)
@@ -154,11 +154,13 @@ Bool VG_(eq_ExeContext_top4) ( ExeContext* e1, ExeContext* e2 )
    duplicates, and so exact equality can be quickly done as equality
    on the returned ExeContext* values themselves.  Inspired by Hugs's
    Text type.  
+
+   In order to be thread-safe, we pass in the thread's %EIP and %EBP.
 */
-ExeContext* VG_(get_ExeContext) ( Bool skip_top_frame )
+ExeContext* VG_(get_ExeContext) ( Bool skip_top_frame,
+                                  Addr eip, Addr ebp )
 {
    Int         i;
-   UInt        ebp;
    Addr        eips[VG_DEEPEST_BACKTRACE];
    Bool        same;
    UInt        hash;
@@ -185,13 +187,11 @@ ExeContext* VG_(get_ExeContext) ( Bool skip_top_frame )
       lval = ebp = 0;                                             \
    }
 
-   ebp = VG_(baseBlock)[VGOFF_(m_ebp)];
-
    if (skip_top_frame) {
       for (i = 0; i < VG_(clo_backtrace_size); i++)
          GET_CALLER(eips[i]);
    } else {
-      eips[0] = VG_(baseBlock)[VGOFF_(m_eip)];
+      eips[0] = eip;
       for (i = 1; i < VG_(clo_backtrace_size); i++)
          GET_CALLER(eips[i]);
    }
index 5735b1c009545b7fc38cc9bd0ffbc3cfcf8b9203..6d7c4c3dedaafec1d87c10fc6a0bc55a95d0dc8e 100644 (file)
@@ -1024,7 +1024,8 @@ extern void VG_(show_ExeContext_stats) ( void );
 /* Take a snapshot of the client's stack.  Search our collection of
    ExeContexts to see if we already have it, and if not, allocate a
    new one.  Either way, return a pointer to the context. */
-extern ExeContext* VG_(get_ExeContext) ( Bool skip_top_frame );
+extern ExeContext* VG_(get_ExeContext) ( Bool skip_top_frame,
+                                         Addr eip, Addr ebp );
 
 /* Print an ExeContext. */
 extern void VG_(pp_ExeContext) ( ExeContext* );
@@ -1052,10 +1053,13 @@ extern void VG_(record_freemismatch_error)    ( Addr a );
 extern void VG_(record_address_error) ( Addr a, Int size, 
                                         Bool isWrite );
 extern void VG_(record_jump_error) ( Addr a );
-extern void VG_(record_param_err) ( Addr a, 
+
+extern void VG_(record_param_err) ( ThreadState* tst,
+                                    Addr a, 
                                     Bool isWriteLack, 
                                     Char* msg );
-extern void VG_(record_user_err) ( Addr a, Bool isWriteLack );
+extern void VG_(record_user_err) ( ThreadState* tst,
+                                   Addr a, Bool isWriteLack );
 
 
 /* The classification of a faulting address. */
@@ -1084,7 +1088,7 @@ typedef
 
 extern Bool VG_(client_perm_maybe_describe)( Addr a, AddrInfo* ai );
 
-extern UInt VG_(handle_client_request) ( UInt* arg_block );
+extern UInt VG_(handle_client_request) ( ThreadState* tst, UInt* arg_block );
 
 extern void VG_(delete_client_stack_blocks_following_ESP_change) ( void );
 
@@ -1150,11 +1154,16 @@ extern ShadowChunk** VG_(get_malloc_shadows) ( /*OUT*/ UInt* n_shadows );
 
 /* These are called from the scheduler, when it intercepts a user
    request. */
-extern void* VG_(client_malloc)   ( UInt size, VgAllocKind kind );
-extern void* VG_(client_memalign) ( UInt align, UInt size );
-extern void  VG_(client_free)     ( void* ptrV, VgAllocKind  kind );
-extern void* VG_(client_calloc)   ( UInt nmemb, UInt size1 );
-extern void* VG_(client_realloc)  ( void* ptrV, UInt size_new );
+extern void* VG_(client_malloc)   ( ThreadState* tst, 
+                                    UInt size, VgAllocKind kind );
+extern void* VG_(client_memalign) ( ThreadState* tst, 
+                                    UInt align, UInt size );
+extern void  VG_(client_free)     ( ThreadState* tst, 
+                                    void* ptrV, VgAllocKind  kind );
+extern void* VG_(client_calloc)   ( ThreadState* tst, 
+                                    UInt nmemb, UInt size1 );
+extern void* VG_(client_realloc)  ( ThreadState* tst, 
+                                    void* ptrV, UInt size_new );
 
 
 /* ---------------------------------------------------------------------
@@ -1342,7 +1351,7 @@ UInt VG_(scan_all_valid_memory) ( void (*notify_word)( Addr, UInt ) );
 
 /* Is this address within some small distance below %ESP?  Used only
    for the --workaround-gcc296-bugs kludge. */
-extern Bool VG_(is_just_below_ESP)( Addr aa );
+extern Bool VG_(is_just_below_ESP)( Addr esp, Addr aa );
 
 /* Nasty kludgery to deal with applications which switch stacks,
    like netscape. */
index b219a3a07fe22ecbd7ad64a68798cf6fae9cf559..5e932fbcdd970f2c9ad94709d84e99a14698c95b 100644 (file)
@@ -1331,11 +1331,10 @@ Bool VG_(is_plausible_stack_addr) ( Addr aa )
 
 /* Is this address within some small distance below %ESP?  Used only
    for the --workaround-gcc296-bugs kludge. */
-Bool VG_(is_just_below_ESP)( Addr aa )
+Bool VG_(is_just_below_ESP)( Addr esp, Addr aa )
 {
-   UInt esp = VG_(baseBlock)[VGOFF_(m_esp)];
-   if (esp > (UInt)aa
-       && (esp - (UInt)aa) <= VG_GCC296_BUG_STACK_SLOP)
+   if ((UInt)esp > (UInt)aa
+       && ((UInt)esp - (UInt)aa) <= VG_GCC296_BUG_STACK_SLOP)
       return True;
    else
       return False;
index 695f086efff3ef56d64d0bdf21661393569d3162..dc3024e5a7e985b9a1333360598822e90692098d 100644 (file)
@@ -57,8 +57,6 @@ suitable for use by anyone at all!
 - Read/write syscall starts: don't crap out when the initial
   nonblocking read/write returns an error.
 
-- 0xDEADBEEF syscall errors ... fix.
-
 */
 
 
@@ -507,45 +505,47 @@ static
 Bool maybe_do_trivial_clientreq ( ThreadId tid )
 {
 #  define SIMPLE_RETURN(vvv)                      \
-       { vg_threads[tid].m_edx = (vvv);           \
+       { tst->m_edx = (vvv);                      \
          return True;                             \
        }
 
-   UInt* arg    = (UInt*)(vg_threads[tid].m_eax);
-   UInt  req_no = arg[0];
+   ThreadState* tst    = &vg_threads[tid];
+   UInt*        arg    = (UInt*)(tst->m_eax);
+   UInt         req_no = arg[0];
+
    switch (req_no) {
       case VG_USERREQ__MALLOC:
          SIMPLE_RETURN(
-            (UInt)VG_(client_malloc) ( arg[1], Vg_AllocMalloc ) 
+            (UInt)VG_(client_malloc) ( tst, arg[1], Vg_AllocMalloc ) 
          );
       case VG_USERREQ__BUILTIN_NEW:
          SIMPLE_RETURN(
-            (UInt)VG_(client_malloc) ( arg[1], Vg_AllocNew )
+            (UInt)VG_(client_malloc) ( tst, arg[1], Vg_AllocNew )
          );
       case VG_USERREQ__BUILTIN_VEC_NEW:
          SIMPLE_RETURN(
-            (UInt)VG_(client_malloc) ( arg[1], Vg_AllocNewVec )
+            (UInt)VG_(client_malloc) ( tst, arg[1], Vg_AllocNewVec )
          );
       case VG_USERREQ__FREE:
-         VG_(client_free) ( (void*)arg[1], Vg_AllocMalloc );
+         VG_(client_free) ( tst, (void*)arg[1], Vg_AllocMalloc );
         SIMPLE_RETURN(0); /* irrelevant */
       case VG_USERREQ__BUILTIN_DELETE:
-         VG_(client_free) ( (void*)arg[1], Vg_AllocNew );
+         VG_(client_free) ( tst, (void*)arg[1], Vg_AllocNew );
         SIMPLE_RETURN(0); /* irrelevant */
       case VG_USERREQ__BUILTIN_VEC_DELETE:
-         VG_(client_free) ( (void*)arg[1], Vg_AllocNewVec );
+         VG_(client_free) ( tst, (void*)arg[1], Vg_AllocNewVec );
         SIMPLE_RETURN(0); /* irrelevant */
       case VG_USERREQ__CALLOC:
          SIMPLE_RETURN(
-            (UInt)VG_(client_calloc) ( arg[1], arg[2] )
+            (UInt)VG_(client_calloc) ( tst, arg[1], arg[2] )
          );
       case VG_USERREQ__REALLOC:
          SIMPLE_RETURN(
-            (UInt)VG_(client_realloc) ( (void*)arg[1], arg[2] )
+            (UInt)VG_(client_realloc) ( tst, (void*)arg[1], arg[2] )
          );
       case VG_USERREQ__MEMALIGN:
          SIMPLE_RETURN(
-            (UInt)VG_(client_memalign) ( arg[1], arg[2] )
+            (UInt)VG_(client_memalign) ( tst, arg[1], arg[2] )
          );
       default:
          /* Too hard; wimp out. */
@@ -1777,7 +1777,8 @@ void do_nontrivial_clientreq ( ThreadId tid )
       case VG_USERREQ__MAKE_NOACCESS_STACK:
       case VG_USERREQ__RUNNING_ON_VALGRIND:
       case VG_USERREQ__DO_LEAK_CHECK:
-         vg_threads[tid].m_edx = VG_(handle_client_request) ( arg );
+         vg_threads[tid].m_edx 
+            = VG_(handle_client_request) ( &vg_threads[tid], arg );
         break;
 
       case VG_USERREQ__SIGNAL_RETURNS: 
index 7578a7bbf0ec2dc6a766ca0c1936d52dc8941a39..5e8e6dd4ed9da417513f216de1ef386ad22364cf 100644 (file)
@@ -79,7 +79,8 @@ static void make_readwritable ( Addr a, UInt len )
 }
 
 static
-void must_be_writable ( Char* syscall_name, UInt base, UInt size )
+void must_be_writable ( ThreadState* tst, 
+                        Char* syscall_name, UInt base, UInt size )
 {
    Bool ok;
    Addr bad_addr;
@@ -89,11 +90,12 @@ void must_be_writable ( Char* syscall_name, UInt base, UInt size )
       return;
    ok = VGM_(check_writable) ( base, size, &bad_addr );
    if (!ok)
-      VG_(record_param_err) ( bad_addr, True, syscall_name );
+      VG_(record_param_err) ( tst, bad_addr, True, syscall_name );
 }
 
 static
-void must_be_readable ( Char* syscall_name, UInt base, UInt size )
+void must_be_readable ( ThreadState* tst, 
+                        Char* syscall_name, UInt base, UInt size )
 {
    Bool ok;
    Addr bad_addr;
@@ -103,11 +105,12 @@ void must_be_readable ( Char* syscall_name, UInt base, UInt size )
       return;
    ok = VGM_(check_readable) ( base, size, &bad_addr );
    if (!ok)
-      VG_(record_param_err) ( bad_addr, False, syscall_name );
+      VG_(record_param_err) ( tst, bad_addr, False, syscall_name );
 }
 
 static
-void must_be_readable_asciiz ( Char* syscall_name, UInt str )
+void must_be_readable_asciiz ( ThreadState* tst, 
+                               Char* syscall_name, UInt str )
 {
    Bool ok = True;
    Addr bad_addr;
@@ -116,7 +119,7 @@ void must_be_readable_asciiz ( Char* syscall_name, UInt str )
       return;
    ok = VGM_(check_readable_asciiz) ( (Addr)str, &bad_addr );
    if (!ok)
-      VG_(record_param_err) ( bad_addr, False, syscall_name );
+      VG_(record_param_err) ( tst, bad_addr, False, syscall_name );
 }
 
 
@@ -205,7 +208,7 @@ UInt get_shm_size ( Int shmid )
 }
  
 static
-Char *strdupcat( const Char *s1, const Char *s2, ArenaId aid )
+Char *strdupcat ( const Char *s1, const Char *s2, ArenaId aid )
 {
    UInt len = VG_(strlen) ( s1 ) + VG_(strlen) ( s2 ) + 1;
    Char *result = VG_(malloc) ( aid, len );
@@ -215,54 +218,64 @@ Char *strdupcat( const Char *s1, const Char *s2, ArenaId aid )
 }
 
 static 
-void must_be_readable_sendmsg( Char *msg, UInt base, UInt size )
+void must_be_readable_sendmsg ( ThreadState* tst, 
+                                Char *msg, UInt base, UInt size )
 {
    Char *outmsg = strdupcat ( "socketcall.sendmsg", msg, VG_AR_TRANSIENT );
-   must_be_readable ( outmsg, base, size );
+   must_be_readable ( tst, outmsg, base, size );
    VG_(free) ( VG_AR_TRANSIENT, outmsg );
 }
 
 static 
-void must_be_writable_recvmsg( Char *msg, UInt base, UInt size )
+void must_be_writable_recvmsg ( ThreadState* tst, 
+                                Char *msg, UInt base, UInt size )
 {
    Char *outmsg = strdupcat ( "socketcall.recvmsg", msg, VG_AR_TRANSIENT );
-   must_be_writable ( outmsg, base, size );
+   must_be_writable ( tst, outmsg, base, size );
    VG_(free) ( VG_AR_TRANSIENT, outmsg );
 }
 
 static
-void make_readable_recvmsg( Char *fieldName, UInt base, UInt size )
+void make_readable_recvmsg ( ThreadState* tst,
+                             Char *fieldName, UInt base, UInt size )
 {
    make_readable( base, size );
 }
  
 static
-void msghdr_foreachfield ( struct msghdr *msg, 
-                           void (*foreach_func)( Char *, UInt, UInt ) )
+void msghdr_foreachfield ( 
+        ThreadState* tst, 
+        struct msghdr *msg, 
+        void (*foreach_func)( ThreadState*, Char *, UInt, UInt ) 
+     )
 {
    if ( !msg )
       return;
 
-   foreach_func ( "(msg)", (Addr)msg, sizeof( struct msghdr ) );
+   foreach_func ( tst, "(msg)", (Addr)msg, sizeof( struct msghdr ) );
 
    if ( msg->msg_name )
-      foreach_func ( "(msg.msg_name)", 
+      foreach_func ( tst, 
+                     "(msg.msg_name)", 
                      (Addr)msg->msg_name, msg->msg_namelen );
 
    if ( msg->msg_iov ) {
       struct iovec *iov = msg->msg_iov;
       UInt i;
 
-      foreach_func ( "(msg.msg_iov)", 
+      foreach_func ( tst, 
+                     "(msg.msg_iov)", 
                      (Addr)iov, msg->msg_iovlen * sizeof( struct iovec ) );
 
       for ( i = 0; i < msg->msg_iovlen; ++i, ++iov )
-         foreach_func ( "(msg.msg_iov[i]", 
+         foreach_func ( tst, 
+                        "(msg.msg_iov[i]", 
                         (Addr)iov->iov_base, iov->iov_len );
    }
 
    if ( msg->msg_control )
-      foreach_func ( "(msg.msg_control)", 
+      foreach_func ( tst, 
+                     "(msg.msg_control)", 
                      (Addr)msg->msg_control, msg->msg_controllen );
 }
 
@@ -371,7 +384,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
       /* int _sysctl(struct __sysctl_args *args); */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("_sysctl ( %p )\n", arg1 );
-         must_be_writable ( "_sysctl(args)", arg1, 
+         must_be_writable ( tst, "_sysctl(args)", arg1, 
                             sizeof(struct __sysctl_args) );
          KERNEL_DO_SYSCALL(tid,res);
          if (!VG_(is_kerror)(res))
@@ -395,7 +408,8 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          if (VG_(clo_trace_syscalls))
             VG_(printf)("sched_setscheduler ( %d, %d, %p )\n",arg1,arg2,arg3);
          if (arg3 != (UInt)NULL)
-            must_be_readable( "sched_setscheduler(struct sched_param *p)", 
+            must_be_readable( tst,
+                              "sched_setscheduler(struct sched_param *p)", 
                               arg3, sizeof(struct sched_param));
          KERNEL_DO_SYSCALL(tid,res);
          break;
@@ -472,7 +486,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
                              size_t count) */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("sendfile ( %d, %d, %p, %d )\n",arg1,arg2,arg3,arg4);
-         must_be_writable( "sendfile(offset)", arg3, sizeof(off_t) );
+         must_be_writable( tst, "sendfile(offset)", arg3, sizeof(off_t) );
          KERNEL_DO_SYSCALL(tid,res);
          if (!VG_(is_kerror)(res)) {
             make_readable( arg3, sizeof( off_t ) );
@@ -488,7 +502,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
                             off_t offset); */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("pwrite ( %d, %p, %d, %d )\n", arg1, arg2, arg3, arg4);
-         must_be_readable( "pwrite(buf)", arg2, arg3 );
+         must_be_readable( tst, "pwrite(buf)", arg2, arg3 );
          KERNEL_DO_SYSCALL(tid,res);
          break;
 #     endif
@@ -506,7 +520,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          /* int fstatfs(int fd, struct statfs *buf); */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("fstatfs ( %d, %p )\n",arg1,arg2);
-         must_be_writable( "stat(buf)", arg2, sizeof(struct statfs) );
+         must_be_writable( tst, "stat(buf)", arg2, sizeof(struct statfs) );
          KERNEL_DO_SYSCALL(tid,res);
          if (!VG_(is_kerror)(res))
             make_readable( arg2, sizeof(struct statfs) );
@@ -533,7 +547,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          /* ssize_t pread(int fd, void *buf, size_t count, off_t offset); */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("pread ( %d, %p, %d, %d ) ...\n",arg1,arg2,arg3,arg4);
-         must_be_writable( "pread(buf)", arg2, arg3 );
+         must_be_writable( tst, "pread(buf)", arg2, arg3 );
          KERNEL_DO_SYSCALL(tid,res);
          if (VG_(clo_trace_syscalls))
             VG_(printf)("SYSCALL[%d]       pread ( %d, %p, %d, %d ) --> %d\n",
@@ -551,7 +565,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          /* int mknod(const char *pathname, mode_t mode, dev_t dev); */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("mknod ( %p, 0x%x, 0x%x )\n", arg1, arg2, arg3 );
-         must_be_readable_asciiz( "mknod(pathname)", arg1 );
+         must_be_readable_asciiz( tst, "mknod(pathname)", arg1 );
          KERNEL_DO_SYSCALL(tid,res);
          break;
 
@@ -571,7 +585,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
             VG_(printf)("sigsuspend ( %p )\n", arg1 );
          if (arg1 != (Addr)NULL) {
             /* above NULL test is paranoia */
-            must_be_readable( "sigsuspend(mask)", arg1, 
+            must_be_readable( tst, "sigsuspend(mask)", arg1, 
                               sizeof(vki_ksigset_t) );
          }
          KERNEL_DO_SYSCALL(tid,res);
@@ -582,8 +596,8 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          /* int init_module(const char *name, struct module *image); */
          if (VG_(clo_trace_syscalls)) 
             VG_(printf)("init_module ( %p, %p )\n", arg1, arg2 );
-         must_be_readable_asciiz( "init_module(name)", arg1 );
-         must_be_readable( "init_module(image)", arg2, 
+         must_be_readable_asciiz( tst, "init_module(name)", arg1 );
+         must_be_readable( tst, "init_module(image)", arg2, 
                            sizeof(struct module) );
          KERNEL_DO_SYSCALL(tid,res);
          break;
@@ -599,9 +613,9 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          /* int capget(cap_user_header_t header, cap_user_data_t data); */
          if (VG_(clo_trace_syscalls)) 
             VG_(printf)("capget ( %p, %p )\n", arg1, arg2 );
-         must_be_readable( "capget(header)", arg1, 
+         must_be_readable( tst, "capget(header)", arg1, 
                                              sizeof(vki_cap_user_header_t) );
-         must_be_writable( "capget(data)", arg2, 
+         must_be_writable( tst, "capget(data)", arg2, 
                                            sizeof( vki_cap_user_data_t) );
          KERNEL_DO_SYSCALL(tid,res);
          if (!VG_(is_kerror)(res) && arg2 != (Addr)NULL)
@@ -654,7 +668,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          /* int access(const char *pathname, int mode); */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("access ( %p, %d )\n", arg1,arg2);
-         must_be_readable_asciiz( "access(pathname)", arg1 );
+         must_be_readable_asciiz( tst, "access(pathname)", arg1 );
          KERNEL_DO_SYSCALL(tid,res);
          break;
 
@@ -702,7 +716,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          /* int chdir(const char *path); */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("chdir ( %p )\n", arg1);
-         must_be_readable_asciiz( "chdir(path)", arg1 );
+         must_be_readable_asciiz( tst, "chdir(path)", arg1 );
          KERNEL_DO_SYSCALL(tid,res);
          break;
 
@@ -710,7 +724,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          /* int chmod(const char *path, mode_t mode); */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("chmod ( %p, %d )\n", arg1,arg2);
-         must_be_readable_asciiz( "chmod(path)", arg1 );
+         must_be_readable_asciiz( tst, "chmod(path)", arg1 );
          KERNEL_DO_SYSCALL(tid,res);
          break;
 
@@ -724,7 +738,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          /* int chown(const char *path, uid_t owner, gid_t group); */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("chown ( %p, 0x%x, 0x%x )\n", arg1,arg2,arg3);
-         must_be_readable_asciiz( "chown(path)", arg1 );
+         must_be_readable_asciiz( tst, "chown(path)", arg1 );
          KERNEL_DO_SYSCALL(tid,res);
          break;
 
@@ -812,7 +826,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          /* int fstat(int filedes, struct stat *buf); */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("fstat ( %d, %p )\n",arg1,arg2);
-         must_be_writable( "fstat", arg2, sizeof(struct stat) );
+         must_be_writable( tst, "fstat", arg2, sizeof(struct stat) );
          KERNEL_DO_SYSCALL(tid,res);
          if (!VG_(is_kerror)(res))
             make_readable( arg2, sizeof(struct stat) );
@@ -863,7 +877,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
                          unsigned int count); */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("getdents ( %d, %p, %d )\n",arg1,arg2,arg3);
-         must_be_writable( "getdents(dirp)", arg2, arg3 );
+         must_be_writable( tst, "getdents(dirp)", arg2, arg3 );
          KERNEL_DO_SYSCALL(tid,res);
          if (!VG_(is_kerror)(res) && res > 0)
             make_readable( arg2, res );
@@ -875,7 +889,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
                          unsigned int count); */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("getdents64 ( %d, %p, %d )\n",arg1,arg2,arg3);
-         must_be_writable( "getdents64(dirp)", arg2, arg3 );
+         must_be_writable( tst, "getdents64(dirp)", arg2, arg3 );
          KERNEL_DO_SYSCALL(tid,res);
          if (!VG_(is_kerror)(res) && res > 0)
             make_readable( arg2, res );
@@ -890,7 +904,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          if (VG_(clo_trace_syscalls))
             VG_(printf)("getgroups ( %d, %p )\n", arg1, arg2);
          if (arg1 > 0)
-            must_be_writable ( "getgroups(list)", arg2, 
+            must_be_writable ( tst, "getgroups(list)", arg2, 
                                arg1 * sizeof(gid_t) );
          KERNEL_DO_SYSCALL(tid,res);
          if (arg1 > 0 && !VG_(is_kerror)(res) && res > 0)
@@ -901,7 +915,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          /* char *getcwd(char *buf, size_t size); */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("getcwd ( %p, %d )\n",arg1,arg2);
-         must_be_writable( "getcwd(buf)", arg1, arg2 );
+         must_be_writable( tst, "getcwd(buf)", arg1, arg2 );
          KERNEL_DO_SYSCALL(tid,res);
          if (!VG_(is_kerror)(res) && res != (Addr)NULL)
             make_readable ( arg1, arg2 );
@@ -990,9 +1004,9 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          /* int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("getresgid ( %p, %p, %p )\n", arg1,arg2,arg3);
-         must_be_writable ( "getresgid(rgid)", arg1, sizeof(gid_t) );
-         must_be_writable ( "getresgid(egid)", arg2, sizeof(gid_t) );
-         must_be_writable ( "getresgid(sgid)", arg3, sizeof(gid_t) );
+         must_be_writable ( tst, "getresgid(rgid)", arg1, sizeof(gid_t) );
+         must_be_writable ( tst, "getresgid(egid)", arg2, sizeof(gid_t) );
+         must_be_writable ( tst, "getresgid(sgid)", arg3, sizeof(gid_t) );
          KERNEL_DO_SYSCALL(tid,res);
          if (!VG_(is_kerror)(res) && res == 0) {
             make_readable ( arg1, sizeof(gid_t) );
@@ -1006,9 +1020,9 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          /* int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("getresgid32 ( %p, %p, %p )\n", arg1,arg2,arg3);
-         must_be_writable ( "getresgid32(rgid)", arg1, sizeof(gid_t) );
-         must_be_writable ( "getresgid32(egid)", arg2, sizeof(gid_t) );
-         must_be_writable ( "getresgid32(sgid)", arg3, sizeof(gid_t) );
+         must_be_writable ( tst, "getresgid32(rgid)", arg1, sizeof(gid_t) );
+         must_be_writable ( tst, "getresgid32(egid)", arg2, sizeof(gid_t) );
+         must_be_writable ( tst, "getresgid32(sgid)", arg3, sizeof(gid_t) );
          KERNEL_DO_SYSCALL(tid,res);
          if (!VG_(is_kerror)(res) && res == 0) {
             make_readable ( arg1, sizeof(gid_t) );
@@ -1022,9 +1036,9 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          /* int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("getresuid ( %p, %p, %p )\n", arg1,arg2,arg3);
-         must_be_writable ( "getresuid(ruid)", arg1, sizeof(uid_t) );
-         must_be_writable ( "getresuid(euid)", arg2, sizeof(uid_t) );
-         must_be_writable ( "getresuid(suid)", arg3, sizeof(uid_t) );
+         must_be_writable ( tst, "getresuid(ruid)", arg1, sizeof(uid_t) );
+         must_be_writable ( tst, "getresuid(euid)", arg2, sizeof(uid_t) );
+         must_be_writable ( tst, "getresuid(suid)", arg3, sizeof(uid_t) );
          KERNEL_DO_SYSCALL(tid,res);
          if (!VG_(is_kerror)(res) && res == 0) {
             make_readable ( arg1, sizeof(uid_t) );
@@ -1038,9 +1052,9 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          /* int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("getresuid32 ( %p, %p, %p )\n", arg1,arg2,arg3);
-         must_be_writable ( "getresuid32(ruid)", arg1, sizeof(uid_t) );
-         must_be_writable ( "getresuid32(euid)", arg2, sizeof(uid_t) );
-         must_be_writable ( "getresuid32(suid)", arg3, sizeof(uid_t) );
+         must_be_writable ( tst, "getresuid32(ruid)", arg1, sizeof(uid_t) );
+         must_be_writable ( tst, "getresuid32(euid)", arg2, sizeof(uid_t) );
+         must_be_writable ( tst, "getresuid32(suid)", arg3, sizeof(uid_t) );
          KERNEL_DO_SYSCALL(tid,res);
          if (!VG_(is_kerror)(res) && res == 0) {
             make_readable ( arg1, sizeof(uid_t) );
@@ -1057,7 +1071,8 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          /* int getrlimit (int resource, struct rlimit *rlim); */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("getrlimit ( %d, %p )\n", arg1,arg2);
-         must_be_writable( "getrlimit(rlim)", arg2, sizeof(struct rlimit) );
+         must_be_writable( tst, "getrlimit(rlim)", arg2, 
+                           sizeof(struct rlimit) );
          KERNEL_DO_SYSCALL(tid,res);
          if (!VG_(is_kerror)(res) && res == 0)
             make_readable( arg2, sizeof(struct rlimit) );
@@ -1067,7 +1082,8 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          /* int getrusage (int who, struct rusage *usage); */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("getrusage ( %d, %p )\n", arg1,arg2);
-         must_be_writable( "getrusage(usage)", arg2, sizeof(struct rusage) );
+         must_be_writable( tst, "getrusage(usage)", arg2, 
+                           sizeof(struct rusage) );
          KERNEL_DO_SYSCALL(tid,res);
          if (!VG_(is_kerror)(res) && res == 0)
             make_readable(arg2, sizeof(struct rusage) );
@@ -1077,9 +1093,10 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          /* int gettimeofday(struct timeval *tv, struct timezone *tz); */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("gettimeofday ( %p, %p )\n",arg1,arg2);
-         must_be_writable( "gettimeofday(tv)", arg1, sizeof(struct timeval) );
+         must_be_writable( tst, "gettimeofday(tv)", arg1, 
+                           sizeof(struct timeval) );
          if (arg2 != 0)
-            must_be_writable( "gettimeofday(tz)", arg2, 
+            must_be_writable( tst, "gettimeofday(tz)", arg2, 
                               sizeof(struct timezone) );
          KERNEL_DO_SYSCALL(tid,res);
          if (!VG_(is_kerror)(res) && res == 0) {
@@ -1116,7 +1133,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
                         arg1,arg2,arg3,arg4,arg5,arg6);
          switch (arg1 /* call */) {
             case 1: /* IPCOP_semop */
-               must_be_readable ( "semop(sops)", arg5, 
+               must_be_readable ( tst, "semop(sops)", arg5, 
                                   arg3 * sizeof(struct sembuf) );
                KERNEL_DO_SYSCALL(tid,res);
                break;
@@ -1129,9 +1146,9 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
                   struct msgbuf *msgp = (struct msgbuf *)arg5;
                   Int msgsz = arg3;
 
-                  must_be_readable ( "msgsnd(msgp->mtype)", 
+                  must_be_readable ( tst, "msgsnd(msgp->mtype)", 
                                      (UInt)&msgp->mtype, sizeof(msgp->mtype) );
-                  must_be_readable ( "msgsnd(msgp->mtext)", 
+                  must_be_readable ( tst, "msgsnd(msgp->mtext)", 
                                      (UInt)msgp->mtext, msgsz );
 
                   KERNEL_DO_SYSCALL(tid,res);
@@ -1142,9 +1159,9 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
                   struct msgbuf *msgp = ((struct ipc_kludge *)arg5)->msgp;
                   Int msgsz = arg3;
 
-                  must_be_writable ( "msgsnd(msgp->mtype)", 
+                  must_be_writable ( tst, "msgsnd(msgp->mtype)", 
                                      (UInt)&msgp->mtype, sizeof(msgp->mtype) );
-                  must_be_writable ( "msgsnd(msgp->mtext)", 
+                  must_be_writable ( tst, "msgsnd(msgp->mtext)", 
                                      (UInt)msgp->mtext, msgsz );
 
                   KERNEL_DO_SYSCALL(tid,res);
@@ -1162,7 +1179,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
                {
                   switch (arg3 /* cmd */) {
                      case IPC_STAT:
-                        must_be_writable ( "msgctl(buf)", arg5, 
+                        must_be_writable ( tst, "msgctl(buf)", arg5, 
                                            sizeof(struct msqid_ds) );
                         KERNEL_DO_SYSCALL(tid,res);
                         if ( !VG_(is_kerror)(res) && res > 0 ) {
@@ -1170,12 +1187,12 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
                         }
                         break;
                      case IPC_SET:
-                        must_be_readable ( "msgctl(buf)", arg5, 
+                        must_be_readable ( tst, "msgctl(buf)", arg5, 
                                            sizeof(struct msqid_ds) );
                         KERNEL_DO_SYSCALL(tid,res);
                         break;
                      case IPC_STAT|IPC_64:
-                        must_be_writable ( "msgctl(buf)", arg5, 
+                        must_be_writable ( tst, "msgctl(buf)", arg5, 
                                            sizeof(struct msqid64_ds) );
                         KERNEL_DO_SYSCALL(tid,res);
                         if ( !VG_(is_kerror)(res) && res > 0 ) {
@@ -1183,7 +1200,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
                         }
                         break;
                      case IPC_SET|IPC_64:
-                        must_be_readable ( "msgctl(buf)", arg5, 
+                        must_be_readable ( tst, "msgctl(buf)", arg5, 
                                            sizeof(struct msqid64_ds) );
                         KERNEL_DO_SYSCALL(tid,res);
                         break;
@@ -1235,11 +1252,11 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
             case 24: /* IPCOP_shmctl */
                {
                   if ( arg3 > 0 ) {
-                     must_be_readable ( "shmctl(buf)", arg3, 
+                     must_be_readable ( tst, "shmctl(buf)", arg3, 
                                         sizeof( struct shmid_ds ) ); 
 
                      if ( arg2 == SHM_STAT )
-                        must_be_writable( "shmctl(IPC_STAT,buf)", arg3, 
+                        must_be_writable( tst, "shmctl(IPC_STAT,buf)", arg3, 
                                           sizeof( struct shmid_ds ) );
                   }
 
@@ -1273,24 +1290,24 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
             case TCSETS:
             case TCSETSW:
             case TCSETSF:
-               must_be_readable( "ioctl(TCSETSW)", arg3, 
+               must_be_readable( tst, "ioctl(TCSETSW)", arg3, 
                                  VKI_SIZEOF_STRUCT_TERMIOS );
                KERNEL_DO_SYSCALL(tid,res);
                break; 
             case TCGETS:
-               must_be_writable( "ioctl(TCGETS)", arg3, 
+               must_be_writable( tst, "ioctl(TCGETS)", arg3, 
                                  VKI_SIZEOF_STRUCT_TERMIOS );
                KERNEL_DO_SYSCALL(tid,res);
                if (!VG_(is_kerror)(res) && res == 0)
                   make_readable ( arg3, VKI_SIZEOF_STRUCT_TERMIOS );
                break;
             case TCSETA:
-               must_be_readable( "ioctl(TCSETA)", arg3,
+               must_be_readable( tst, "ioctl(TCSETA)", arg3,
                                  VKI_SIZEOF_STRUCT_TERMIO );
                KERNEL_DO_SYSCALL(tid,res);
                break;
             case TCGETA:
-               must_be_writable( "ioctl(TCGETA)", arg3,
+               must_be_writable( tst, "ioctl(TCGETA)", arg3,
                                  VKI_SIZEOF_STRUCT_TERMIO );
                KERNEL_DO_SYSCALL(tid,res);
                if (!VG_(is_kerror)(res) && res == 0)
@@ -1303,26 +1320,26 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
                KERNEL_DO_SYSCALL(tid,res);
                break;
             case TIOCGWINSZ:
-               must_be_writable( "ioctl(TIOCGWINSZ)", arg3, 
+               must_be_writable( tst, "ioctl(TIOCGWINSZ)", arg3, 
                                  sizeof(struct winsize) );
                KERNEL_DO_SYSCALL(tid,res);
                if (!VG_(is_kerror)(res) && res == 0)
                   make_readable ( arg3, sizeof(struct winsize) );
                break;
             case TIOCSWINSZ:
-               must_be_readable( "ioctl(TIOCSWINSZ)", arg3, 
+               must_be_readable( tst, "ioctl(TIOCSWINSZ)", arg3, 
                                  sizeof(struct winsize) );
                KERNEL_DO_SYSCALL(tid,res);
                break;
             case TIOCGPGRP:
                /* Get process group ID for foreground processing group. */
-               must_be_writable( "ioctl(TIOCGPGRP)", arg3,
+               must_be_writable( tst, "ioctl(TIOCGPGRP)", arg3,
                                  sizeof(pid_t) );
                KERNEL_DO_SYSCALL(tid,res);
                if (!VG_(is_kerror)(res) && res == 0)
                   make_readable ( arg3, sizeof(pid_t) );
             case TIOCGPTN: /* Get Pty Number (of pty-mux device) */
-               must_be_writable("ioctl(TIOCGPTN)", arg3, sizeof(int) );
+               must_be_writable(tst, "ioctl(TIOCGPTN)", arg3, sizeof(int) );
                KERNEL_DO_SYSCALL(tid,res);
                if (!VG_(is_kerror)(res) && res == 0)
                    make_readable ( arg3, sizeof(int));
@@ -1332,19 +1349,19 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
                KERNEL_DO_SYSCALL(tid,res);
                break;
             case TIOCSPTLCK: /* Lock/unlock Pty */
-               must_be_readable( "ioctl(TIOCSPTLCK)", arg3, sizeof(int) );
+               must_be_readable( tst, "ioctl(TIOCSPTLCK)", arg3, sizeof(int) );
                KERNEL_DO_SYSCALL(tid,res);
                break;
             case FIONBIO:
-               must_be_readable( "ioctl(FIONBIO)", arg3, sizeof(int) );
+               must_be_readable( tst, "ioctl(FIONBIO)", arg3, sizeof(int) );
                KERNEL_DO_SYSCALL(tid,res);
                break;
             case FIOASYNC:
-               must_be_readable( "ioctl(FIOASYNC)", arg3, sizeof(int) );
+               must_be_readable( tst, "ioctl(FIOASYNC)", arg3, sizeof(int) );
                KERNEL_DO_SYSCALL(tid,res);
                break;
             case FIONREAD:
-               must_be_writable( "ioctl(FIONREAD)", arg3, sizeof(int) );
+               must_be_writable( tst, "ioctl(FIONREAD)", arg3, sizeof(int) );
                KERNEL_DO_SYSCALL(tid,res);
                if (!VG_(is_kerror)(res) && res == 0)
                   make_readable( arg3, sizeof(int) );
@@ -1355,12 +1372,13 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
                vg_unsafe.h. */
 #       if 1
             case SG_SET_COMMAND_Q:
-               must_be_readable( "ioctl(SG_SET_COMMAND_Q)", arg3, sizeof(int) );
+               must_be_readable( tst, "ioctl(SG_SET_COMMAND_Q)", 
+                                 arg3, sizeof(int) );
                KERNEL_DO_SYSCALL(tid,res);
                break;
 #           if defined(SG_IO)
             case SG_IO:
-               must_be_writable( "ioctl(SG_IO)", arg3, 
+               must_be_writable( tst, "ioctl(SG_IO)", arg3, 
                                  sizeof(struct sg_io_hdr) );
                KERNEL_DO_SYSCALL(tid,res);
                if (!VG_(is_kerror)(res) && res == 0)
@@ -1369,36 +1387,38 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
 #           endif /* SG_IO */
             case SG_GET_SCSI_ID:
                /* Note: sometimes sg_scsi_id is called sg_scsi_id_t */
-               must_be_writable( "ioctl(SG_GET_SCSI_ID)", arg3, 
+               must_be_writable( tst, "ioctl(SG_GET_SCSI_ID)", arg3, 
                                  sizeof(struct sg_scsi_id) );
                KERNEL_DO_SYSCALL(tid,res);
                if (!VG_(is_kerror)(res) && res == 0)
                   make_readable (arg3, sizeof(struct sg_scsi_id));
                break;
             case SG_SET_RESERVED_SIZE:
-               must_be_readable( "ioctl(SG_SET_RESERVED_SIZE)", 
+               must_be_readable( tst, "ioctl(SG_SET_RESERVED_SIZE)", 
                                  arg3, sizeof(int) );
                KERNEL_DO_SYSCALL(tid,res);
                break;
             case SG_SET_TIMEOUT:
-               must_be_readable( "ioctl(SG_SET_TIMEOUT)", arg3, sizeof(int) );
+               must_be_readable( tst, "ioctl(SG_SET_TIMEOUT)", arg3, 
+                                 sizeof(int) );
                KERNEL_DO_SYSCALL(tid,res);
                break;
             case SG_GET_RESERVED_SIZE:
-               must_be_writable( "ioctl(SG_GET_RESERVED_SIZE)", arg3, 
+               must_be_writable( tst, "ioctl(SG_GET_RESERVED_SIZE)", arg3, 
                                  sizeof(int) );
                KERNEL_DO_SYSCALL(tid,res);
                if (!VG_(is_kerror)(res) && res == 0)
                   make_readable (arg3, sizeof(int));
                break;
             case SG_GET_TIMEOUT:
-               must_be_writable( "ioctl(SG_GET_TIMEOUT)", arg3, sizeof(int) );
+               must_be_writable( tst, "ioctl(SG_GET_TIMEOUT)", arg3, 
+                                 sizeof(int) );
                KERNEL_DO_SYSCALL(tid,res);
                if (!VG_(is_kerror)(res) && res == 0)
                   make_readable (arg3, sizeof(int));
                break;
             case SG_GET_VERSION_NUM:
-               must_be_readable( "ioctl(SG_GET_VERSION_NUM)", 
+               must_be_readable( tst, "ioctl(SG_GET_VERSION_NUM)", 
                                  arg3, sizeof(int) );
                KERNEL_DO_SYSCALL(tid,res);
                break;
@@ -1410,7 +1430,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
 #              ifndef ISDN_MAX_CHANNELS
 #              define ISDN_MAX_CHANNELS 64
 #              endif
-               must_be_writable( "ioctl(IIOCGETCPS)", arg3,
+               must_be_writable( tst, "ioctl(IIOCGETCPS)", arg3,
                                  ISDN_MAX_CHANNELS 
                                  * 2 * sizeof(unsigned long) );
                KERNEL_DO_SYSCALL(tid,res);
@@ -1419,10 +1439,10 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
                                         * 2 * sizeof(unsigned long) );
                break;
             case IIOCNETGPN:
-               must_be_readable( "ioctl(IIOCNETGPN)",
+               must_be_readable( tst, "ioctl(IIOCNETGPN)",
                                  (UInt)&((isdn_net_ioctl_phone *)arg3)->name,
                                  sizeof(((isdn_net_ioctl_phone *)arg3)->name) );
-               must_be_writable( "ioctl(IIOCNETGPN)", arg3,
+               must_be_writable( tst, "ioctl(IIOCNETGPN)", arg3,
                                  sizeof(isdn_net_ioctl_phone) );
                KERNEL_DO_SYSCALL(tid,res);
                if (!VG_(is_kerror)(res) && res == 0)
@@ -1442,7 +1462,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
             case SIOCGIFDSTADDR:      /* get remote PA address        */
             case SIOCGIFBRDADDR:      /* get broadcast PA address     */
             case SIOCGIFNAME:         /* get iface name               */
-               must_be_writable("ioctl(SIOCGIFINDEX)", arg3, 
+               must_be_writable(tst, "ioctl(SIOCGIFINDEX)", arg3, 
                                 sizeof(struct ifreq));
                KERNEL_DO_SYSCALL(tid,res);
                if (!VG_(is_kerror)(res) && res == 0)
@@ -1456,13 +1476,13 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
                if (!VG_(is_kerror)(res) && res == 0)
                   make_readable (arg3, sizeof(struct ifconf));
                */
-               must_be_readable("ioctl(SIOCGIFCONF)", arg3, 
+               must_be_readable(tst, "ioctl(SIOCGIFCONF)", arg3, 
                                 sizeof(struct ifconf));
                if ( arg3 ) {
                   // TODO len must be readable and writable
                   // buf pointer only needs to be readable
                   struct ifconf *ifc = (struct ifconf *) arg3;
-                  must_be_writable("ioctl(SIOCGIFCONF).ifc_buf",
+                  must_be_writable(tst, "ioctl(SIOCGIFCONF).ifc_buf",
                                    (Addr)(ifc->ifc_buf), (UInt)(ifc->ifc_len) );
                }
                KERNEL_DO_SYSCALL(tid,res);
@@ -1472,7 +1492,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
                }
                break;
             case SIOCGSTAMP:
-               must_be_writable("ioctl(SIOCGSTAMP)", arg3, 
+               must_be_writable(tst, "ioctl(SIOCGSTAMP)", arg3, 
                                 sizeof(struct timeval));
                KERNEL_DO_SYSCALL(tid,res);
                if (!VG_(is_kerror)(res) && res == 0)
@@ -1480,7 +1500,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
                break;
             case SIOCGRARP:           /* get RARP table entry         */
             case SIOCGARP:            /* get ARP table entry          */
-               must_be_writable("ioctl(SIOCGARP)", arg3, 
+               must_be_writable(tst, "ioctl(SIOCGARP)", arg3, 
                                 sizeof(struct arpreq));
                KERNEL_DO_SYSCALL(tid,res);
                if (!VG_(is_kerror)(res) && res == 0)
@@ -1497,14 +1517,14 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
             case SIOCSIFADDR:         /* set PA address               */
             case SIOCSIFMTU:          /* set MTU size                 */
             case SIOCSIFHWADDR:       /* set hardware address         */
-               must_be_readable("ioctl(SIOCSIFFLAGS)", arg3, 
+               must_be_readable(tst,"ioctl(SIOCSIFFLAGS)", arg3, 
                                 sizeof(struct ifreq));
                KERNEL_DO_SYSCALL(tid,res);
                break;
             /* Routing table calls.  */
             case SIOCADDRT:           /* add routing table entry      */
             case SIOCDELRT:           /* delete routing table entry   */
-               must_be_readable("ioctl(SIOCADDRT/DELRT)", arg3, 
+               must_be_readable(tst,"ioctl(SIOCADDRT/DELRT)", arg3, 
                                 sizeof(struct rtentry));
                KERNEL_DO_SYSCALL(tid,res);
                break;
@@ -1515,13 +1535,13 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
             /* ARP cache control calls. */
             case SIOCSARP:            /* set ARP table entry          */
             case SIOCDARP:            /* delete ARP table entry       */
-               must_be_readable("ioctl(SIOCSIFFLAGS)", arg3, 
+               must_be_readable(tst, "ioctl(SIOCSIFFLAGS)", arg3, 
                                 sizeof(struct ifreq));
                KERNEL_DO_SYSCALL(tid,res);
                break;
 
             case SIOCSPGRP:
-               must_be_readable( "ioctl(SIOCSPGRP)", arg3, sizeof(int) );
+               must_be_readable( tst, "ioctl(SIOCSPGRP)", arg3, sizeof(int) );
                KERNEL_DO_SYSCALL(tid,res);
                break;
 
@@ -1546,7 +1566,8 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
             case SOUND_PCM_READ_BITS:
             case (SOUND_PCM_READ_BITS|0x40000000): /* what the fuck ? */
             case SOUND_PCM_READ_FILTER:
-               must_be_writable("ioctl(SNDCTL_XXX|SOUND_XXX (SIOR, int))", arg3,
+               must_be_writable(tst,"ioctl(SNDCTL_XXX|SOUND_XXX (SIOR, int))", 
+                                arg3,
                                 sizeof(int));
                KERNEL_DO_SYSCALL(tid,res);
                if (!VG_(is_kerror)(res) && res == 0)
@@ -1571,15 +1592,18 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
             case SNDCTL_TMR_SOURCE:
             case SNDCTL_MIDI_PRETIME:
             case SNDCTL_MIDI_MPUMODE:
-               must_be_readable("ioctl(SNDCTL_XXX|SOUND_XXX (SIOWR, int))", 
+               must_be_readable(tst, "ioctl(SNDCTL_XXX|SOUND_XXX "
+                                     "(SIOWR, int))", 
                                 arg3, sizeof(int));
-               must_be_writable("ioctl(SNDCTL_XXX|SOUND_XXX (SIOWR, int))", 
+               must_be_writable(tst, "ioctl(SNDCTL_XXX|SOUND_XXX "
+                                     "(SIOWR, int))", 
                                 arg3, sizeof(int));
                KERNEL_DO_SYSCALL(tid,res);
                break;
             case SNDCTL_DSP_GETOSPACE:
             case SNDCTL_DSP_GETISPACE:
-               must_be_writable("ioctl(SNDCTL_XXX|SOUND_XXX "
+               must_be_writable(tst, 
+                                "ioctl(SNDCTL_XXX|SOUND_XXX "
                                 "(SIOR, audio_buf_info))", arg3,
                                 sizeof(audio_buf_info));
                KERNEL_DO_SYSCALL(tid,res);
@@ -1587,7 +1611,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
                   make_readable (arg3, sizeof(audio_buf_info));
                break;
             case SNDCTL_DSP_SETTRIGGER:
-               must_be_readable("ioctl(SNDCTL_XXX|SOUND_XXX (SIOW, int))", 
+               must_be_readable(tst, "ioctl(SNDCTL_XXX|SOUND_XXX (SIOW, int))", 
                                 arg3, sizeof(int));
                KERNEL_DO_SYSCALL(tid,res);
                break;
@@ -1612,9 +1636,9 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
                      " writing a proper wrapper." );
                } else {
                   if ((dir & _IOC_READ) && size > 0)
-                     must_be_readable("ioctl(generic)", arg3, size);
+                     must_be_readable(tst, "ioctl(generic)", arg3, size);
                   if ((dir & _IOC_WRITE) && size > 0)
-                     must_be_writable("ioctl(generic)", arg3, size);
+                     must_be_writable(tst, "ioctl(generic)", arg3, size);
                }
                KERNEL_DO_SYSCALL(tid,res);
                if (size > 0 && (dir & _IOC_WRITE)
@@ -1636,8 +1660,8 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          /* int link(const char *oldpath, const char *newpath); */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("link ( %p, %p)\n", arg1, arg2);
-         must_be_readable_asciiz( "link(oldpath)", arg1);
-         must_be_readable_asciiz( "link(newpath)", arg2);
+         must_be_readable_asciiz( tst, "link(oldpath)", arg1);
+         must_be_readable_asciiz( tst, "link(newpath)", arg2);
          KERNEL_DO_SYSCALL(tid,res);
          break;
 
@@ -1655,7 +1679,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          if (VG_(clo_trace_syscalls))
             VG_(printf)("llseek ( %d, 0x%x, 0x%x, %p, %d )\n",
                         arg1,arg2,arg3,arg4,arg5);
-         must_be_writable( "llseek(result)", arg4, sizeof(loff_t));
+         must_be_writable( tst, "llseek(result)", arg4, sizeof(loff_t));
          KERNEL_DO_SYSCALL(tid,res);
          if (!VG_(is_kerror)(res) && res == 0)
             make_readable( arg4, sizeof(loff_t) );
@@ -1665,8 +1689,8 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          /* int lstat(const char *file_name, struct stat *buf); */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("lstat ( %p, %p )\n",arg1,arg2);
-         must_be_readable_asciiz( "lstat(file_name)", arg1 );
-         must_be_writable( "lstat(buf)", arg2, sizeof(struct stat) );
+         must_be_readable_asciiz( tst, "lstat(file_name)", arg1 );
+         must_be_writable( tst, "lstat(buf)", arg2, sizeof(struct stat) );
          KERNEL_DO_SYSCALL(tid,res);
          if (!VG_(is_kerror)(res) && res == 0) {
             make_readable( arg2, sizeof(struct stat) );
@@ -1678,8 +1702,8 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          /* int lstat64(const char *file_name, struct stat64 *buf); */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("lstat64 ( %p, %p )\n",arg1,arg2);
-         must_be_readable_asciiz( "lstat64(file_name)", arg1 );
-         must_be_writable( "lstat64(buf)", arg2, sizeof(struct stat64) );
+         must_be_readable_asciiz( tst, "lstat64(file_name)", arg1 );
+         must_be_writable( tst, "lstat64(buf)", arg2, sizeof(struct stat64) );
          KERNEL_DO_SYSCALL(tid,res);
          if (!VG_(is_kerror)(res) && res == 0) {
             make_readable( arg2, sizeof(struct stat64) );
@@ -1691,7 +1715,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          /* int mkdir(const char *pathname, mode_t mode); */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("mkdir ( %p, %d )\n", arg1,arg2);
-         must_be_readable_asciiz( "mkdir(pathname)", arg1 );
+         must_be_readable_asciiz( tst, "mkdir(pathname)", arg1 );
          KERNEL_DO_SYSCALL(tid,res);
          break;
 
@@ -1726,7 +1750,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
                  = VG_(clo_instrument)
                  ? VGM_(check_readable)(arg1, 6*sizeof(UInt), NULL)
                  : True;
-         must_be_readable( "mmap(args)", arg1, 6*sizeof(UInt) );
+         must_be_readable( tst, "mmap(args)", arg1, 6*sizeof(UInt) );
          if (arg_block_readable) {
             UInt* arg_block = (UInt*)arg1;
             UInt arg6;
@@ -1799,10 +1823,10 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          /* int nanosleep(const struct timespec *req, struct timespec *rem); */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("nanosleep ( %p, %p )\n", arg1,arg2);
-         must_be_readable ( "nanosleep(req)", arg1, 
+         must_be_readable ( tst, "nanosleep(req)", arg1, 
                                               sizeof(struct timespec) );
          if (arg2 != (UInt)NULL)
-            must_be_writable ( "nanosleep(rem)", arg2, 
+            must_be_writable ( tst, "nanosleep(rem)", arg2, 
                                sizeof(struct timespec) );
          KERNEL_DO_SYSCALL(tid,res);
          /* Somewhat bogus ... is only written by the kernel if
@@ -1820,16 +1844,16 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
             VG_(printf)("newselect ( %d, %p, %p, %p, %p )\n",
                         arg1,arg2,arg3,arg4,arg5);
          if (arg2 != 0)
-            must_be_readable( "newselect(readfds)",   
+            must_be_readable( tst, "newselect(readfds)",   
                               arg2, arg1/8 /* __FD_SETSIZE/8 */ );
          if (arg3 != 0)
-            must_be_readable( "newselect(writefds)",  
+            must_be_readable( tst, "newselect(writefds)",  
                               arg3, arg1/8 /* __FD_SETSIZE/8 */ );
          if (arg4 != 0)
-            must_be_readable( "newselect(exceptfds)", 
+            must_be_readable( tst, "newselect(exceptfds)", 
                               arg4, arg1/8 /* __FD_SETSIZE/8 */ );
          if (arg5 != 0)
-            must_be_readable( "newselect(timeout)", arg5, 
+            must_be_readable( tst, "newselect(timeout)", arg5, 
                               sizeof(struct timeval) );
          KERNEL_DO_SYSCALL(tid,res);
          break;
@@ -1838,7 +1862,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          /* int open(const char *pathname, int flags); */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("open ( %p(%s), %d ) --> ",arg1,arg1,arg2);
-         must_be_readable_asciiz( "open(pathname)", arg1 );
+         must_be_readable_asciiz( tst, "open(pathname)", arg1 );
          KERNEL_DO_SYSCALL(tid,res);
          if (VG_(clo_trace_syscalls))
             VG_(printf)("%d\n",res);
@@ -1848,7 +1872,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          /* int pipe(int filedes[2]); */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("pipe ( %p ) ...\n", arg1);
-         must_be_writable( "pipe(filedes)", arg1, 2*sizeof(int) );
+         must_be_writable( tst, "pipe(filedes)", arg1, 2*sizeof(int) );
          KERNEL_DO_SYSCALL(tid,res);
          if (!VG_(is_kerror)(res))
             make_readable ( arg1, 2*sizeof(int) );
@@ -1871,7 +1895,8 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
             VG_(printf)("poll ( %d, %d, %d )\n",arg1,arg2,arg3);
          /* In fact some parts of this struct should be readable too.
             This should be fixed properly. */
-         must_be_writable( "poll(ufds)", arg1, arg2 * sizeof(struct pollfd) );
+         must_be_writable( tst, "poll(ufds)", 
+                           arg1, arg2 * sizeof(struct pollfd) );
          KERNEL_DO_SYSCALL(tid,res);
          if (!VG_(is_kerror)(res) && res > 0) {
             Int i;
@@ -1885,8 +1910,8 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          /* int readlink(const char *path, char *buf, size_t bufsiz); */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("readlink ( %p, %p, %d )\n", arg1,arg2,arg3);
-         must_be_readable_asciiz( "readlink(path)", arg1 );
-         must_be_writable ( "readlink(buf)", arg2,arg3 );
+         must_be_readable_asciiz( tst, "readlink(path)", arg1 );
+         must_be_writable ( tst, "readlink(buf)", arg2,arg3 );
          KERNEL_DO_SYSCALL(tid,res);
          if (!VG_(is_kerror)(res) && res > 0) {
             make_readable ( arg2, res );
@@ -1899,12 +1924,12 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          struct iovec * vec;
          if (VG_(clo_trace_syscalls))
             VG_(printf)("readv ( %d, %p, %d )\n",arg1,arg2,arg3);
-         must_be_readable( "readv(vector)", 
+         must_be_readable( tst, "readv(vector)", 
                            arg2, arg3 * sizeof(struct iovec) );
          /* ToDo: don't do any of the following if the vector is invalid */
          vec = (struct iovec *)arg2;
          for (i = 0; i < arg3; i++)
-            must_be_writable( "readv(vector[...])",
+            must_be_writable( tst, "readv(vector[...])",
                               (UInt)vec[i].iov_base,vec[i].iov_len );
          KERNEL_DO_SYSCALL(tid,res);
          if (!VG_(is_kerror)(res) && res > 0) {
@@ -1924,8 +1949,8 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          /* int rename(const char *oldpath, const char *newpath); */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("rename ( %p, %p )\n", arg1, arg2 );
-         must_be_readable_asciiz( "rename(oldpath)", arg1 );
-         must_be_readable_asciiz( "rename(newpath)", arg2 );
+         must_be_readable_asciiz( tst, "rename(oldpath)", arg1 );
+         must_be_readable_asciiz( tst, "rename(newpath)", arg2 );
          KERNEL_DO_SYSCALL(tid,res);
          break;
 
@@ -1933,7 +1958,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          /* int rmdir(const char *pathname); */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("rmdir ( %p )\n", arg1);
-         must_be_readable_asciiz( "rmdir(pathname)", arg1 );
+         must_be_readable_asciiz( tst, "rmdir(pathname)", arg1 );
          KERNEL_DO_SYSCALL(tid,res);
          break;
 
@@ -1965,7 +1990,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
                  = VG_(clo_instrument)
                  ? VGM_(check_readable)(arg1, 5*sizeof(UInt), NULL)
                  : True;
-         must_be_readable ( "select(args)", arg1, 5*sizeof(UInt) );
+         must_be_readable ( tst, "select(args)", arg1, 5*sizeof(UInt) );
          if (arg_block_readable) {
             UInt* arg_struct = (UInt*)arg1;
             arg1 = arg_struct[0];
@@ -1978,16 +2003,16 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
                VG_(printf)("select ( %d, %p, %p, %p, %p )\n", 
                            arg1,arg2,arg3,arg4,arg5);
             if (arg2 != (Addr)NULL)
-               must_be_readable("select(readfds)", arg2, 
+               must_be_readable(tst, "select(readfds)", arg2, 
                                 arg1/8 /* __FD_SETSIZE/8 */ );
             if (arg3 != (Addr)NULL)
-               must_be_readable("select(writefds)", arg3, 
+               must_be_readable(tst, "select(writefds)", arg3, 
                                 arg1/8 /* __FD_SETSIZE/8 */ );
             if (arg4 != (Addr)NULL)
-               must_be_readable("select(exceptfds)", arg4, 
+               must_be_readable(tst, "select(exceptfds)", arg4, 
                                 arg1/8 /* __FD_SETSIZE/8 */ );
             if (arg5 != (Addr)NULL)
-               must_be_readable("select(timeout)", arg5, 
+               must_be_readable(tst, "select(timeout)", arg5, 
                                 sizeof(struct timeval) );
          }
          }
@@ -1999,10 +2024,10 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
                                  struct itimerval *ovalue); */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("setitimer ( %d, %p, %p )\n", arg1,arg2,arg3);
-         must_be_readable("setitimer(value)", 
+         must_be_readable(tst, "setitimer(value)", 
                           arg2, sizeof(struct itimerval) );
          if (arg3 != (Addr)NULL)
-            must_be_writable("setitimer(ovalue)", 
+            must_be_writable(tst, "setitimer(ovalue)", 
                              arg3, sizeof(struct itimerval));
          KERNEL_DO_SYSCALL(tid,res);
          if (!VG_(is_kerror)(res) && arg3 != (Addr)NULL) {
@@ -2044,7 +2069,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          if (VG_(clo_trace_syscalls))
             VG_(printf)("setgroups ( %d, %p )\n", arg1, arg2);
          if (arg1 > 0)
-            must_be_readable ( "setgroups(list)", arg2, 
+            must_be_readable ( tst, "setgroups(list)", arg2, 
                                arg1 * sizeof(gid_t) );
          KERNEL_DO_SYSCALL(tid,res);
          break;
@@ -2088,7 +2113,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          /* int setrlimit (int resource, const struct rlimit *rlim); */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("setrlimit ( %d, %p )\n", arg1,arg2);
-         must_be_readable( "setrlimit(rlim)", arg2, sizeof(struct rlimit) );
+         must_be_readable( tst, "setrlimit(rlim)", arg2, sizeof(struct rlimit) );
          KERNEL_DO_SYSCALL(tid,res);
          break;
 
@@ -2110,9 +2135,9 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
 
             case SYS_SOCKETPAIR:
                /* int socketpair(int d, int type, int protocol, int sv[2]); */
-               must_be_readable( "socketcall.socketpair(args)", 
+               must_be_readable( tst, "socketcall.socketpair(args)", 
                                  arg2, 4*sizeof(Addr) );
-               must_be_writable( "socketcall.socketpair(sv)", 
+               must_be_writable( tst, "socketcall.socketpair(sv)", 
                                  ((UInt*)arg2)[3], 2*sizeof(int) );
                KERNEL_DO_SYSCALL(tid,res);
                if (!VG_(is_kerror)(res))
@@ -2121,7 +2146,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
 
             case SYS_SOCKET:
                /* int socket(int domain, int type, int protocol); */
-               must_be_readable( "socketcall.socket(args)", 
+               must_be_readable( tst, "socketcall.socket(args)", 
                                  arg2, 3*sizeof(Addr) );
                KERNEL_DO_SYSCALL(tid,res);
                break;
@@ -2129,16 +2154,16 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
             case SYS_BIND:
                /* int bind(int sockfd, struct sockaddr *my_addr, 
                            int addrlen); */
-               must_be_readable( "socketcall.bind(args)", 
+               must_be_readable( tst, "socketcall.bind(args)", 
                                  arg2, 3*sizeof(Addr) );
-               must_be_readable( "socketcall.bind(my_addr)", 
+               must_be_readable( tst, "socketcall.bind(my_addr)", 
                                  ((UInt*)arg2)[1], ((UInt*)arg2)[2] );
                KERNEL_DO_SYSCALL(tid,res);
                break;
 
             case SYS_LISTEN:
                /* int listen(int s, int backlog); */
-               must_be_readable( "socketcall.listen(args)", 
+               must_be_readable( tst, "socketcall.listen(args)", 
                                  arg2, 2*sizeof(Addr) );
                KERNEL_DO_SYSCALL(tid,res);
                break;
@@ -2148,15 +2173,15 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
                Addr addr;
                Addr p_addrlen;
                UInt addrlen_in, addrlen_out;
-               must_be_readable( "socketcall.accept(args)", 
+               must_be_readable( tst, "socketcall.accept(args)", 
                                  arg2, 3*sizeof(Addr) );
                addr      = ((UInt*)arg2)[1];
                p_addrlen = ((UInt*)arg2)[2];
                if (p_addrlen != (Addr)NULL) {
-                  must_be_readable ( "socketcall.accept(addrlen)", 
+                  must_be_readable ( tst, "socketcall.accept(addrlen)", 
                                      p_addrlen, sizeof(int) );
                   addrlen_in = safe_dereference( p_addrlen, 0 );
-                  must_be_writable ( "socketcall.accept(addr)", 
+                  must_be_writable ( tst, "socketcall.accept(addr)", 
                                      addr, addrlen_in );
                }
                KERNEL_DO_SYSCALL(tid,res);
@@ -2172,12 +2197,12 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
                /* int sendto(int s, const void *msg, int len, 
                              unsigned int flags, 
                              const struct sockaddr *to, int tolen); */
-               must_be_readable( "socketcall.sendto(args)", arg2, 
+               must_be_readable( tst, "socketcall.sendto(args)", arg2, 
                                  6*sizeof(Addr) );
-               must_be_readable( "socketcall.sendto(msg)",
+               must_be_readable( tst, "socketcall.sendto(msg)",
                                  ((UInt*)arg2)[1], /* msg */
                                  ((UInt*)arg2)[2]  /* len */ );
-               must_be_readable( "socketcall.sendto(to)",
+               must_be_readable( tst, "socketcall.sendto(to)",
                                  ((UInt*)arg2)[4], /* to */
                                  ((UInt*)arg2)[5]  /* tolen */ );
                KERNEL_DO_SYSCALL(tid,res);
@@ -2185,9 +2210,9 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
 
             case SYS_SEND:
                /* int send(int s, const void *msg, size_t len, int flags); */
-               must_be_readable( "socketcall.send(args)", arg2,
+               must_be_readable( tst, "socketcall.send(args)", arg2,
                                  4*sizeof(Addr) );
-               must_be_readable( "socketcall.send(msg)",
+               must_be_readable( tst, "socketcall.send(msg)",
                                  ((UInt*)arg2)[1], /* msg */
                                   ((UInt*)arg2)[2]  /* len */ );
                KERNEL_DO_SYSCALL(tid,res);
@@ -2196,18 +2221,18 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
             case SYS_RECVFROM:
                /* int recvfrom(int s, void *buf, int len, unsigned int flags,
                                struct sockaddr *from, int *fromlen); */
-               must_be_readable( "socketcall.recvfrom(args)", 
+               must_be_readable( tst, "socketcall.recvfrom(args)", 
                                  arg2, 6*sizeof(Addr) );
                if ( ((UInt*)arg2)[4] /* from */ != 0) {
-                  must_be_readable( "socketcall.recvfrom(fromlen)",
+                  must_be_readable( tst, "socketcall.recvfrom(fromlen)",
                                     ((UInt*)arg2)[5] /* fromlen */, 
                                     sizeof(int) );
-                  must_be_writable( "socketcall.recvfrom(from)",
+                  must_be_writable( tst, "socketcall.recvfrom(from)",
                                     ((UInt*)arg2)[4], /*from*/
                                     safe_dereference( (Addr)
                                                       ((UInt*)arg2)[5], 0 ) );
                }
-               must_be_writable( "socketcall.recvfrom(buf)", 
+               must_be_writable( tst, "socketcall.recvfrom(buf)", 
                                  ((UInt*)arg2)[1], /* buf */
                                  ((UInt*)arg2)[2]  /* len */ );
                KERNEL_DO_SYSCALL(tid,res);
@@ -2230,9 +2255,9 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
                (see connect(2)) and is identical to recvfrom with a  NULL
                from parameter.
                */
-               must_be_readable( "socketcall.recv(args)", 
+               must_be_readable( tst, "socketcall.recv(args)", 
                                  arg2, 4*sizeof(Addr) );
-               must_be_writable( "socketcall.recv(buf)", 
+               must_be_writable( tst, "socketcall.recv(buf)", 
                                  ((UInt*)arg2)[1], /* buf */
                                  ((UInt*)arg2)[2]  /* len */ );
                KERNEL_DO_SYSCALL(tid,res);
@@ -2247,21 +2272,21 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
                struct sockaddr *sa;
                /* int connect(int sockfd, 
                               struct sockaddr *serv_addr, int addrlen ); */
-               must_be_readable( "socketcall.connect(args)", 
+               must_be_readable( tst, "socketcall.connect(args)", 
                                  arg2, 3*sizeof(Addr) );
-               must_be_readable( "socketcall.connect(serv_addr.sa_family)",
+               must_be_readable( tst, "socketcall.connect(serv_addr.sa_family)",
                                  ((UInt*)arg2)[1], /* serv_addr */
                                  sizeof (sa_family_t));
                sa = (struct sockaddr *) (((UInt*)arg2)[1]);
                if (sa->sa_family == AF_UNIX)
-                  must_be_readable_asciiz( 
+                  must_be_readable_asciiz( tst, 
                      "socketcall.connect(serv_addr.sun_path)",
                      (UInt) ((struct sockaddr_un *) sa)->sun_path);
                /* XXX There probably should be more cases here since not
                   all of the struct sockaddr_XXX must be initialized.  But
                   wait until something pops up.  */
                else
-                  must_be_readable( "socketcall.connect(serv_addr)",
+                  must_be_readable( tst, "socketcall.connect(serv_addr)",
                                     ((UInt*)arg2)[1], /* serv_addr */
                                     ((UInt*)arg2)[2]  /* addrlen */ );
                KERNEL_DO_SYSCALL(tid,res);
@@ -2271,9 +2296,9 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
             case SYS_SETSOCKOPT:
                /* int setsockopt(int s, int level, int optname, 
                                  const void *optval, int optlen); */
-               must_be_readable( "socketcall.setsockopt(args)", 
+               must_be_readable( tst, "socketcall.setsockopt(args)", 
                                  arg2, 5*sizeof(Addr) );
-               must_be_readable( "socketcall.setsockopt(optval)",
+               must_be_readable( tst, "socketcall.setsockopt(optval)",
                                  ((UInt*)arg2)[3], /* optval */
                                  ((UInt*)arg2)[4]  /* optlen */ );
                KERNEL_DO_SYSCALL(tid,res);
@@ -2282,16 +2307,16 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
             case SYS_GETSOCKOPT:
                /* int setsockopt(int s, int level, int optname, 
                                  void *optval, socklen_t *optlen); */
-               must_be_readable( "socketcall.getsockopt(args)", 
+               must_be_readable( tst, "socketcall.getsockopt(args)", 
                                  arg2, 5*sizeof(Addr) );
                {
                Addr optval_p = ((UInt*)arg2)[3];
                Addr optlen_p = ((UInt*)arg2)[4];
-               //vg_assert(sizeof(socklen_t) == sizeof(UInt));
+               /* vg_assert(sizeof(socklen_t) == sizeof(UInt)); */
                UInt optlen_after;
                UInt optlen = safe_dereference ( optlen_p, 0 );
                if (optlen > 0) 
-                  must_be_writable( "socketcall.getsockopt(optval)", 
+                  must_be_writable( tst, "socketcall.getsockopt(optval)", 
                                     optval_p, optlen );
                KERNEL_DO_SYSCALL(tid,res);
                optlen_after = safe_dereference ( optlen_p, 0 );
@@ -2303,12 +2328,12 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
             case SYS_GETSOCKNAME:
                /* int getsockname(int s, struct sockaddr* name, 
                                   int* namelen) */
-               must_be_readable( "socketcall.getsockname(args)", 
+               must_be_readable( tst, "socketcall.getsockname(args)", 
                                  arg2, 3*sizeof(Addr) );
                {
                UInt namelen = safe_dereference( (Addr) ((UInt*)arg2)[2], 0);
                if (namelen > 0)
-                  must_be_writable( "socketcall.getsockname(name)", 
+                  must_be_writable( tst, "socketcall.getsockname(name)", 
                                     ((UInt*)arg2)[1], namelen );
                KERNEL_DO_SYSCALL(tid,res);
                if (!VG_(is_kerror)(res)) {
@@ -2323,12 +2348,12 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
             case SYS_GETPEERNAME:
                /* int getpeername(int s, struct sockaddr* name, 
                                   int* namelen) */
-               must_be_readable( "socketcall.getpeername(args)", 
+               must_be_readable( tst, "socketcall.getpeername(args)", 
                                  arg2, 3*sizeof(Addr) );
                {
                UInt namelen = safe_dereference( (Addr) ((UInt*)arg2)[2], 0);
                if (namelen > 0)
-                  must_be_writable( "socketcall.getpeername(name)", 
+                  must_be_writable( tst, "socketcall.getpeername(name)", 
                                     ((UInt*)arg2)[1], namelen );
                KERNEL_DO_SYSCALL(tid,res);
                if (!VG_(is_kerror)(res)) {
@@ -2342,8 +2367,8 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
 
             case SYS_SHUTDOWN:
                /* int shutdown(int s, int how); */
-               must_be_readable( "socketcall.shutdown(args)", 
-                                  arg2, 2*sizeof(Addr) );
+               must_be_readable( tst, "socketcall.shutdown(args)", 
+                                 arg2, 2*sizeof(Addr) );
                KERNEL_DO_SYSCALL(tid,res);
                break;
 
@@ -2358,7 +2383,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
                   */
 
                   struct msghdr *msg = (struct msghdr *)((UInt *)arg2)[ 1 ];
-                  msghdr_foreachfield ( msg, must_be_readable_sendmsg );
+                  msghdr_foreachfield ( tst, msg, must_be_readable_sendmsg );
 
                   KERNEL_DO_SYSCALL(tid,res);
                   break;
@@ -2375,12 +2400,12 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
                   */
 
                   struct msghdr *msg = (struct msghdr *)((UInt *)arg2)[ 1 ];
-                  msghdr_foreachfield ( msg, must_be_writable_recvmsg );
+                  msghdr_foreachfield ( tst, msg, must_be_writable_recvmsg );
 
                   KERNEL_DO_SYSCALL(tid,res);
 
                   if ( !VG_(is_kerror)( res ) )
-                     msghdr_foreachfield( msg, make_readable_recvmsg );
+                     msghdr_foreachfield( tst, msg, make_readable_recvmsg );
 
                   break;
                }
@@ -2396,8 +2421,8 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          /* int stat(const char *file_name, struct stat *buf); */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("stat ( %p, %p )\n",arg1,arg2);
-         must_be_readable_asciiz( "stat(file_name)", arg1 );
-         must_be_writable( "stat(buf)", arg2, sizeof(struct stat) );
+         must_be_readable_asciiz( tst, "stat(file_name)", arg1 );
+         must_be_writable( tst, "stat(buf)", arg2, sizeof(struct stat) );
          KERNEL_DO_SYSCALL(tid,res);
          if (!VG_(is_kerror)(res))
             make_readable( arg2, sizeof(struct stat) );
@@ -2407,8 +2432,8 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          /* int statfs(const char *path, struct statfs *buf); */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("statfs ( %p, %p )\n",arg1,arg2);
-         must_be_readable_asciiz( "statfs(path)", arg1 );
-         must_be_writable( "stat(buf)", arg2, sizeof(struct statfs) );
+         must_be_readable_asciiz( tst, "statfs(path)", arg1 );
+         must_be_writable( tst, "stat(buf)", arg2, sizeof(struct statfs) );
          KERNEL_DO_SYSCALL(tid,res);
          if (!VG_(is_kerror)(res))
             make_readable( arg2, sizeof(struct statfs) );
@@ -2418,8 +2443,8 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          /* int symlink(const char *oldpath, const char *newpath); */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("symlink ( %p, %p )\n",arg1,arg2);
-         must_be_readable_asciiz( "symlink(oldpath)", arg1 );
-         must_be_readable_asciiz( "symlink(newpath)", arg2 );
+         must_be_readable_asciiz( tst, "symlink(oldpath)", arg1 );
+         must_be_readable_asciiz( tst, "symlink(newpath)", arg2 );
          KERNEL_DO_SYSCALL(tid,res);
          break; 
 
@@ -2428,8 +2453,8 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          /* int stat64(const char *file_name, struct stat64 *buf); */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("stat64 ( %p, %p )\n",arg1,arg2);
-         must_be_readable_asciiz( "stat64(file_name)", arg1 );
-         must_be_writable( "stat64(buf)", arg2, sizeof(struct stat64) );
+         must_be_readable_asciiz( tst, "stat64(file_name)", arg1 );
+         must_be_writable( tst, "stat64(buf)", arg2, sizeof(struct stat64) );
          KERNEL_DO_SYSCALL(tid,res);
          if (!VG_(is_kerror)(res))
             make_readable( arg2, sizeof(struct stat64) );
@@ -2441,7 +2466,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          /* int fstat64(int filedes, struct stat64 *buf); */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("fstat64 ( %d, %p )\n",arg1,arg2);
-         must_be_writable( "fstat64(buf)", arg2, sizeof(struct stat64) );
+         must_be_writable( tst, "fstat64(buf)", arg2, sizeof(struct stat64) );
          KERNEL_DO_SYSCALL(tid,res);
          if (!VG_(is_kerror)(res))
             make_readable( arg2, sizeof(struct stat64) );
@@ -2452,7 +2477,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          /* int sysinfo(struct sysinfo *info); */
          if (VG_(clo_trace_syscalls)) 
             VG_(printf)("sysinfo ( %p )\n",arg1);
-         must_be_writable( "sysinfo(info)", arg1, sizeof(struct sysinfo) );
+         must_be_writable( tst, "sysinfo(info)", arg1, sizeof(struct sysinfo) );
          KERNEL_DO_SYSCALL(tid,res);
          if (!VG_(is_kerror)(res))
             make_readable( arg1, sizeof(struct sysinfo) );
@@ -2463,7 +2488,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          if (VG_(clo_trace_syscalls))
             VG_(printf)("time ( %p )\n",arg1);
          if (arg1 != (UInt)NULL) {
-            must_be_writable( "time", arg1, sizeof(time_t) );
+            must_be_writable( tst, "time", arg1, sizeof(time_t) );
          }
          KERNEL_DO_SYSCALL(tid,res);
          if (!VG_(is_kerror)(res) && arg1 != (UInt)NULL) {
@@ -2475,7 +2500,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          /* clock_t times(struct tms *buf); */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("times ( %p )\n",arg1);
-         must_be_writable( "times(buf)", arg1, sizeof(struct tms) );
+         must_be_writable( tst, "times(buf)", arg1, sizeof(struct tms) );
          KERNEL_DO_SYSCALL(tid,res);
          if (!VG_(is_kerror)(res) && arg1 != (UInt)NULL) {
             make_readable( arg1, sizeof(struct tms) );
@@ -2486,7 +2511,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          /* int truncate(const char *path, size_t length); */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("truncate ( %p, %d )\n", arg1,arg2);
-         must_be_readable_asciiz( "truncate(path)", arg1 );
+         must_be_readable_asciiz( tst, "truncate(path)", arg1 );
          KERNEL_DO_SYSCALL(tid,res);
          break;
 
@@ -2501,7 +2526,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          /* int unlink(const char *pathname) */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("ulink ( %p )\n",arg1);
-         must_be_readable_asciiz( "unlink(pathname)", arg1 );
+         must_be_readable_asciiz( tst, "unlink(pathname)", arg1 );
          KERNEL_DO_SYSCALL(tid,res);
          break;
 
@@ -2509,7 +2534,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          /* int uname(struct utsname *buf); */
          if (VG_(clo_trace_syscalls))
             VG_(printf)("uname ( %p )\n",arg1);
-         must_be_writable( "uname(buf)", arg1, sizeof(struct utsname) );
+         must_be_writable( tst, "uname(buf)", arg1, sizeof(struct utsname) );
          KERNEL_DO_SYSCALL(tid,res);
          if (!VG_(is_kerror)(res) && arg1 != (UInt)NULL) {
             make_readable( arg1, sizeof(struct utsname) );
@@ -2520,10 +2545,10 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          /* int utime(const char *filename, struct utimbuf *buf); */
          if (VG_(clo_trace_syscalls)) 
             VG_(printf)("utime ( %p, %p )\n", arg1,arg2);
-         must_be_readable_asciiz( "utime(filename)", arg1 );
+         must_be_readable_asciiz( tst, "utime(filename)", arg1 );
          if (arg2 != (UInt)NULL)
-            must_be_readable( "utime(buf)", arg2, 
-                                            sizeof(struct utimbuf) );
+            must_be_readable( tst, "utime(buf)", arg2, 
+                                                 sizeof(struct utimbuf) );
          KERNEL_DO_SYSCALL(tid,res);
          break;
 
@@ -2534,9 +2559,10 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
             VG_(printf)("wait4 ( %d, %p, %d, %p )\n",
                       arg1,arg2,arg3,arg4);
          if (arg2 != (Addr)NULL)
-            must_be_writable( "wait4(status)", arg2, sizeof(int) );
+            must_be_writable( tst, "wait4(status)", arg2, sizeof(int) );
          if (arg4 != (Addr)NULL)
-            must_be_writable( "wait4(rusage)", arg4, sizeof(struct rusage) );
+            must_be_writable( tst, "wait4(rusage)", arg4, 
+                              sizeof(struct rusage) );
          KERNEL_DO_SYSCALL(tid,res);
          if (!VG_(is_kerror)(res)) {
             if (arg2 != (Addr)NULL)
@@ -2552,12 +2578,12 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          struct iovec * vec;
          if (VG_(clo_trace_syscalls))
             VG_(printf)("writev ( %d, %p, %d )\n",arg1,arg2,arg3);
-         must_be_readable( "writev(vector)", 
+         must_be_readable( tst, "writev(vector)", 
                            arg2, arg3 * sizeof(struct iovec) );
          /* ToDo: don't do any of the following if the vector is invalid */
          vec = (struct iovec *)arg2;
          for (i = 0; i < arg3; i++)
-            must_be_readable( "writev(vector[...])",
+            must_be_readable( tst, "writev(vector[...])",
                               (UInt)vec[i].iov_base,vec[i].iov_len );
          KERNEL_DO_SYSCALL(tid,res);
          break;
@@ -2577,10 +2603,10 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          if (VG_(clo_trace_syscalls))
             VG_(printf)("sigaction ( %d, %p, %p )\n",arg1,arg2,arg3);
          if (arg2 != (UInt)NULL)
-            must_be_readable( "sigaction(act)", 
+            must_be_readable( tst, "sigaction(act)", 
                               arg2, sizeof(vki_ksigaction));
          if (arg3 != (UInt)NULL)
-            must_be_writable( "sigaction(oldact)", 
+            must_be_writable( tst, "sigaction(oldact)", 
                               arg3, sizeof(vki_ksigaction));
          /* We do this one ourselves! */
 #        if SIGNAL_SIMULATION
@@ -2601,10 +2627,10 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
          if (VG_(clo_trace_syscalls))
             VG_(printf)("sigprocmask ( %d, %p, %p )\n",arg1,arg2,arg3);
          if (arg2 != (UInt)NULL)
-            must_be_readable( "sigprocmask(set)", 
+            must_be_readable( tst, "sigprocmask(set)", 
                               arg2, sizeof(vki_ksigset_t));
          if (arg3 != (UInt)NULL)
-            must_be_writable( "sigprocmask(oldset)", 
+            must_be_writable( tst, "sigprocmask(oldset)", 
                               arg3, sizeof(vki_ksigset_t));
          KERNEL_DO_SYSCALL(tid,res);
          if (!VG_(is_kerror)(res) && res == 0 && arg3 != (UInt)NULL)
@@ -2661,7 +2687,7 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid )
    and the result value afterwards, we can't reliably use it to get
    the syscall number.  So the caller has to pass it explicitly.  
 */
-void VG_(check_known_blocking_syscall) ( ThreadId tid, 
+void VG_(check_known_blocking_syscall) ( ThreadId tid,
                                          Int syscallno,
                                          Int* /*IN*/ res )
 {
@@ -2692,7 +2718,7 @@ void VG_(check_known_blocking_syscall) ( ThreadId tid,
                   "SYSCALL--PRE[%d,%d]       read ( %d, %p, %d )\n", 
                   VG_(getpid)(), tid,
                   arg1, arg2, arg3);
-            must_be_writable( "read(buf)", arg2, arg3 );
+            must_be_writable( tst, "read(buf)", arg2, arg3 );
          } else {
             /* POST */
             if (VG_(clo_trace_syscalls))
@@ -2715,7 +2741,7 @@ void VG_(check_known_blocking_syscall) ( ThreadId tid,
                   "SYSCALL--PRE[%d,%d]       write ( %d, %p, %d )\n", 
                   VG_(getpid)(), tid,
                   arg1, arg2, arg3);
-            must_be_readable( "write(buf)", arg2, arg3 );
+            must_be_readable( tst, "write(buf)", arg2, arg3 );
         } else {
             /* POST */
             if (VG_(clo_trace_syscalls))