Home | History | Annotate | Download | only in drd
      1 /*
      2   This file is part of drd, a thread error detector.
      3 
      4   Copyright (C) 2006-2012 Bart Van Assche <bvanassche (at) acm.org>.
      5 
      6   This program is free software; you can redistribute it and/or
      7   modify it under the terms of the GNU General Public License as
      8   published by the Free Software Foundation; either version 2 of the
      9   License, or (at your option) any later version.
     10 
     11   This program is distributed in the hope that it will be useful, but
     12   WITHOUT ANY WARRANTY; without even the implied warranty of
     13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14   General Public License for more details.
     15 
     16   You should have received a copy of the GNU General Public License
     17   along with this program; if not, write to the Free Software
     18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
     19   02111-1307, USA.
     20 
     21   The GNU General Public License is contained in the file COPYING.
     22 */
     23 
     24 
     25 #include "drd_barrier.h"
     26 #include "drd_clientreq.h"
     27 #include "drd_cond.h"
     28 #include "drd_error.h"
     29 #include "drd_hb.h"
     30 #include "drd_load_store.h"
     31 #include "drd_malloc_wrappers.h"
     32 #include "drd_mutex.h"
     33 #include "drd_rwlock.h"
     34 #include "drd_semaphore.h"
     35 #include "drd_suppression.h"      // drd_start_suppression()
     36 #include "drd_thread.h"
     37 #include "pub_tool_basics.h"      // Bool
     38 #include "pub_tool_debuginfo.h"   // VG_(describe_IP)()
     39 #include "pub_tool_libcassert.h"
     40 #include "pub_tool_libcassert.h"  // tl_assert()
     41 #include "pub_tool_libcprint.h"   // VG_(message)()
     42 #include "pub_tool_machine.h"     // VG_(get_SP)()
     43 #include "pub_tool_threadstate.h"
     44 #include "pub_tool_tooliface.h"   // VG_(needs_...)()
     45 
     46 
     47 /* Global variables. */
     48 
     49 Bool DRD_(g_free_is_write);
     50 
     51 
     52 /* Local function declarations. */
     53 
     54 static Bool handle_client_request(ThreadId vg_tid, UWord* arg, UWord* ret);
     55 
     56 
     57 /* Function definitions. */
     58 
     59 /**
     60  * Tell the Valgrind core the address of the DRD function that processes
     61  * client requests. Must be called before any client code is run.
     62  */
     63 void DRD_(clientreq_init)(void)
     64 {
     65    VG_(needs_client_requests)(handle_client_request);
     66 }
     67 
     68 /**
     69  * DRD's handler for Valgrind client requests. The code below handles both
     70  * DRD's public and tool-internal client requests.
     71  */
     72 #if defined(VGP_mips32_linux)
     73  /* There is a cse related issue in gcc for MIPS. Optimization level
     74     has to be lowered, so cse related optimizations are not
     75     included. */
     76  __attribute__((optimize("O1")))
     77 #endif
     78 static Bool handle_client_request(ThreadId vg_tid, UWord* arg, UWord* ret)
     79 {
     80    UWord result = 0;
     81    const DrdThreadId drd_tid = DRD_(thread_get_running_tid)();
     82 
     83    tl_assert(vg_tid == VG_(get_running_tid()));
     84    tl_assert(DRD_(VgThreadIdToDrdThreadId)(vg_tid) == drd_tid);
     85 
     86    switch (arg[0])
     87    {
     88    case VG_USERREQ__MALLOCLIKE_BLOCK:
     89       if (DRD_(g_free_is_write)) {
     90          GenericErrInfo GEI = {
     91             .tid = DRD_(thread_get_running_tid)(),
     92             .addr = 0,
     93          };
     94          VG_(maybe_record_error)(vg_tid,
     95                                  GenericErr,
     96                                  VG_(get_IP)(vg_tid),
     97                                  "--free-is-write=yes is incompatible with"
     98                                  " custom memory allocator client requests",
     99                                  &GEI);
    100       }
    101       if (arg[1])
    102          DRD_(malloclike_block)(vg_tid, arg[1]/*addr*/, arg[2]/*size*/);
    103       break;
    104 
    105    case VG_USERREQ__RESIZEINPLACE_BLOCK:
    106       if (!DRD_(freelike_block)(vg_tid, arg[1]/*addr*/, False))
    107       {
    108          GenericErrInfo GEI = {
    109             .tid = DRD_(thread_get_running_tid)(),
    110             .addr = 0,
    111          };
    112          VG_(maybe_record_error)(vg_tid,
    113                                  GenericErr,
    114                                  VG_(get_IP)(vg_tid),
    115                                  "Invalid VG_USERREQ__RESIZEINPLACE_BLOCK request",
    116                                  &GEI);
    117       }
    118       DRD_(malloclike_block)(vg_tid, arg[1]/*addr*/, arg[3]/*newSize*/);
    119       break;
    120 
    121    case VG_USERREQ__FREELIKE_BLOCK:
    122       if (arg[1] && ! DRD_(freelike_block)(vg_tid, arg[1]/*addr*/, False))
    123       {
    124          GenericErrInfo GEI = {
    125 	    .tid = DRD_(thread_get_running_tid)(),
    126 	    .addr = 0,
    127 	 };
    128          VG_(maybe_record_error)(vg_tid,
    129                                  GenericErr,
    130                                  VG_(get_IP)(vg_tid),
    131                                  "Invalid VG_USERREQ__FREELIKE_BLOCK request",
    132                                  &GEI);
    133       }
    134       break;
    135 
    136    case VG_USERREQ__DRD_GET_VALGRIND_THREAD_ID:
    137       result = vg_tid;
    138       break;
    139 
    140    case VG_USERREQ__DRD_GET_DRD_THREAD_ID:
    141       result = drd_tid;
    142       break;
    143 
    144    case VG_USERREQ__DRD_SET_THREAD_NAME:
    145       DRD_(thread_set_name)(drd_tid, (const char*)arg[1]);
    146       break;
    147 
    148    case VG_USERREQ__DRD_START_SUPPRESSION:
    149       /*_VG_USERREQ__HG_ARANGE_MAKE_UNTRACKED*/
    150    case VG_USERREQ_TOOL_BASE('H','G') + 256 + 39:
    151       DRD_(start_suppression)(arg[1], arg[1] + arg[2], "client");
    152       break;
    153 
    154    case VG_USERREQ__DRD_FINISH_SUPPRESSION:
    155       /*_VG_USERREQ__HG_ARANGE_MAKE_TRACKED*/
    156    case VG_USERREQ_TOOL_BASE('H','G') + 256 + 40:
    157       DRD_(finish_suppression)(arg[1], arg[1] + arg[2]);
    158       break;
    159 
    160    case VG_USERREQ__DRD_ANNOTATE_HAPPENS_BEFORE:
    161       DRD_(hb_happens_before)(drd_tid, arg[1]);
    162       break;
    163 
    164    case VG_USERREQ__DRD_ANNOTATE_HAPPENS_AFTER:
    165       DRD_(hb_happens_after)(drd_tid, arg[1]);
    166       break;
    167 
    168    case VG_USERREQ__DRD_ANNOTATE_RWLOCK_CREATE:
    169       if (arg[1])
    170       {
    171          struct mutex_info* const mutex_p = DRD_(mutex_get)(arg[1]);
    172          if (mutex_p && mutex_p->mutex_type == mutex_type_spinlock)
    173             break;
    174       }
    175       DRD_(rwlock_pre_init)(arg[1], user_rwlock);
    176       break;
    177 
    178    case VG_USERREQ__DRD_ANNOTATE_RWLOCK_DESTROY:
    179       if (arg[1])
    180       {
    181          struct mutex_info* const mutex_p = DRD_(mutex_get)(arg[1]);
    182          if (mutex_p && mutex_p->mutex_type == mutex_type_spinlock)
    183             break;
    184       }
    185       DRD_(rwlock_post_destroy)(arg[1], user_rwlock);
    186       break;
    187 
    188    case VG_USERREQ__DRD_ANNOTATE_RWLOCK_ACQUIRED:
    189       if (arg[1])
    190       {
    191          struct mutex_info* const mutex_p = DRD_(mutex_get)(arg[1]);
    192          if (mutex_p && mutex_p->mutex_type == mutex_type_spinlock)
    193             break;
    194       }
    195       tl_assert(arg[2] == !! arg[2]);
    196       if (arg[2])
    197       {
    198          DRD_(rwlock_pre_wrlock)(arg[1], user_rwlock);
    199          DRD_(rwlock_post_wrlock)(arg[1], user_rwlock, True);
    200       }
    201       else
    202       {
    203          DRD_(rwlock_pre_rdlock)(arg[1], user_rwlock);
    204          DRD_(rwlock_post_rdlock)(arg[1], user_rwlock, True);
    205       }
    206       break;
    207 
    208    case VG_USERREQ__DRD_ANNOTATE_RWLOCK_RELEASED:
    209       if (arg[1])
    210       {
    211          struct mutex_info* const mutex_p = DRD_(mutex_get)(arg[1]);
    212          if (mutex_p && mutex_p->mutex_type == mutex_type_spinlock)
    213             break;
    214       }
    215       tl_assert(arg[2] == !! arg[2]);
    216       DRD_(rwlock_pre_unlock)(arg[1], user_rwlock);
    217       break;
    218 
    219    case VG_USERREQ__SET_PTHREAD_COND_INITIALIZER:
    220       DRD_(pthread_cond_initializer) = (Addr)arg[1];
    221       DRD_(pthread_cond_initializer_size) = arg[2];
    222       break;
    223 
    224    case VG_USERREQ__DRD_START_NEW_SEGMENT:
    225       DRD_(thread_new_segment)(DRD_(PtThreadIdToDrdThreadId)(arg[1]));
    226       break;
    227 
    228    case VG_USERREQ__DRD_START_TRACE_ADDR:
    229       DRD_(start_tracing_address_range)(arg[1], arg[1] + arg[2], False);
    230       break;
    231 
    232    case VG_USERREQ__DRD_STOP_TRACE_ADDR:
    233       DRD_(stop_tracing_address_range)(arg[1], arg[1] + arg[2]);
    234       break;
    235 
    236    case VG_USERREQ__DRD_RECORD_LOADS:
    237       DRD_(thread_set_record_loads)(drd_tid, arg[1]);
    238       break;
    239 
    240    case VG_USERREQ__DRD_RECORD_STORES:
    241       DRD_(thread_set_record_stores)(drd_tid, arg[1]);
    242       break;
    243 
    244    case VG_USERREQ__SET_PTHREADID:
    245       // pthread_self() returns 0 for programs not linked with libpthread.so.
    246       if (arg[1] != INVALID_POSIX_THREADID)
    247          DRD_(thread_set_pthreadid)(drd_tid, arg[1]);
    248       break;
    249 
    250    case VG_USERREQ__SET_JOINABLE:
    251    {
    252       const DrdThreadId drd_joinable = DRD_(PtThreadIdToDrdThreadId)(arg[1]);
    253       if (drd_joinable != DRD_INVALID_THREADID)
    254          DRD_(thread_set_joinable)(drd_joinable, (Bool)arg[2]);
    255       else {
    256          InvalidThreadIdInfo ITI = { DRD_(thread_get_running_tid)(), arg[1] };
    257          VG_(maybe_record_error)(vg_tid,
    258                                  InvalidThreadId,
    259                                  VG_(get_IP)(vg_tid),
    260                                  "pthread_detach(): invalid thread ID",
    261                                  &ITI);
    262       }
    263       break;
    264    }
    265 
    266    case VG_USERREQ__ENTERING_PTHREAD_CREATE:
    267       DRD_(thread_entering_pthread_create)(drd_tid);
    268       break;
    269 
    270    case VG_USERREQ__LEFT_PTHREAD_CREATE:
    271       DRD_(thread_left_pthread_create)(drd_tid);
    272       break;
    273 
    274    case VG_USERREQ__POST_THREAD_JOIN:
    275    {
    276       const DrdThreadId thread_to_join = DRD_(PtThreadIdToDrdThreadId)(arg[1]);
    277       if (thread_to_join == DRD_INVALID_THREADID)
    278       {
    279          InvalidThreadIdInfo ITI = { DRD_(thread_get_running_tid)(), arg[1] };
    280          VG_(maybe_record_error)(vg_tid,
    281                                  InvalidThreadId,
    282                                  VG_(get_IP)(vg_tid),
    283                                  "pthread_join(): invalid thread ID",
    284                                  &ITI);
    285       }
    286       else
    287       {
    288          DRD_(thread_post_join)(drd_tid, thread_to_join);
    289       }
    290       break;
    291    }
    292 
    293    case VG_USERREQ__PRE_THREAD_CANCEL:
    294    {
    295       const DrdThreadId thread_to_cancel =DRD_(PtThreadIdToDrdThreadId)(arg[1]);
    296       if (thread_to_cancel == DRD_INVALID_THREADID)
    297       {
    298          InvalidThreadIdInfo ITI = { DRD_(thread_get_running_tid)(), arg[1] };
    299          VG_(maybe_record_error)(vg_tid,
    300                                  InvalidThreadId,
    301                                  VG_(get_IP)(vg_tid),
    302                                  "pthread_cancel(): invalid thread ID",
    303                                  &ITI);
    304       }
    305       else
    306       {
    307          DRD_(thread_pre_cancel)(thread_to_cancel);
    308       }
    309       break;
    310    }
    311 
    312    case VG_USERREQ__POST_THREAD_CANCEL:
    313       break;
    314 
    315    case VG_USERREQ__PRE_MUTEX_INIT:
    316       if (DRD_(thread_enter_synchr)(drd_tid) == 0)
    317          DRD_(mutex_init)(arg[1], arg[2]);
    318       break;
    319 
    320    case VG_USERREQ__POST_MUTEX_INIT:
    321       DRD_(thread_leave_synchr)(drd_tid);
    322       break;
    323 
    324    case VG_USERREQ__PRE_MUTEX_DESTROY:
    325       DRD_(thread_enter_synchr)(drd_tid);
    326       break;
    327 
    328    case VG_USERREQ__POST_MUTEX_DESTROY:
    329       if (DRD_(thread_leave_synchr)(drd_tid) == 0)
    330          DRD_(mutex_post_destroy)(arg[1]);
    331       break;
    332 
    333    case VG_USERREQ__PRE_MUTEX_LOCK:
    334       if (DRD_(thread_enter_synchr)(drd_tid) == 0)
    335          DRD_(mutex_pre_lock)(arg[1], arg[2], arg[3]);
    336       break;
    337 
    338    case VG_USERREQ__POST_MUTEX_LOCK:
    339       if (DRD_(thread_leave_synchr)(drd_tid) == 0)
    340          DRD_(mutex_post_lock)(arg[1], arg[2], False/*post_cond_wait*/);
    341       break;
    342 
    343    case VG_USERREQ__PRE_MUTEX_UNLOCK:
    344       if (DRD_(thread_enter_synchr)(drd_tid) == 0)
    345          DRD_(mutex_unlock)(arg[1], arg[2]);
    346       break;
    347 
    348    case VG_USERREQ__POST_MUTEX_UNLOCK:
    349       DRD_(thread_leave_synchr)(drd_tid);
    350       break;
    351 
    352    case VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK:
    353       if (DRD_(thread_enter_synchr)(drd_tid) == 0)
    354          DRD_(spinlock_init_or_unlock)(arg[1]);
    355       break;
    356 
    357    case VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK:
    358       DRD_(thread_leave_synchr)(drd_tid);
    359       break;
    360 
    361    case VG_USERREQ__PRE_COND_INIT:
    362       if (DRD_(thread_enter_synchr)(drd_tid) == 0)
    363          DRD_(cond_pre_init)(arg[1]);
    364       break;
    365 
    366    case VG_USERREQ__POST_COND_INIT:
    367       DRD_(thread_leave_synchr)(drd_tid);
    368       break;
    369 
    370    case VG_USERREQ__PRE_COND_DESTROY:
    371       DRD_(thread_enter_synchr)(drd_tid);
    372       break;
    373 
    374    case VG_USERREQ__POST_COND_DESTROY:
    375       if (DRD_(thread_leave_synchr)(drd_tid) == 0)
    376          DRD_(cond_post_destroy)(arg[1]);
    377       break;
    378 
    379    case VG_USERREQ__PRE_COND_WAIT:
    380       if (DRD_(thread_enter_synchr)(drd_tid) == 0)
    381       {
    382          const Addr cond = arg[1];
    383          const Addr mutex = arg[2];
    384          const MutexT mutex_type = arg[3];
    385          DRD_(mutex_unlock)(mutex, mutex_type);
    386          DRD_(cond_pre_wait)(cond, mutex);
    387       }
    388       break;
    389 
    390    case VG_USERREQ__POST_COND_WAIT:
    391       if (DRD_(thread_leave_synchr)(drd_tid) == 0)
    392       {
    393          const Addr cond = arg[1];
    394          const Addr mutex = arg[2];
    395          const Bool took_lock = arg[3];
    396          DRD_(cond_post_wait)(cond);
    397          DRD_(mutex_post_lock)(mutex, took_lock, True);
    398       }
    399       break;
    400 
    401    case VG_USERREQ__PRE_COND_SIGNAL:
    402       if (DRD_(thread_enter_synchr)(drd_tid) == 0)
    403          DRD_(cond_pre_signal)(arg[1]);
    404       break;
    405 
    406    case VG_USERREQ__POST_COND_SIGNAL:
    407       DRD_(thread_leave_synchr)(drd_tid);
    408       break;
    409 
    410    case VG_USERREQ__PRE_COND_BROADCAST:
    411       if (DRD_(thread_enter_synchr)(drd_tid) == 0)
    412          DRD_(cond_pre_broadcast)(arg[1]);
    413       break;
    414 
    415    case VG_USERREQ__POST_COND_BROADCAST:
    416       DRD_(thread_leave_synchr)(drd_tid);
    417       break;
    418 
    419    case VG_USERREQ__PRE_SEM_INIT:
    420       if (DRD_(thread_enter_synchr)(drd_tid) == 0)
    421          DRD_(semaphore_init)(arg[1], arg[2], arg[3]);
    422       break;
    423 
    424    case VG_USERREQ__POST_SEM_INIT:
    425       DRD_(thread_leave_synchr)(drd_tid);
    426       break;
    427 
    428    case VG_USERREQ__PRE_SEM_DESTROY:
    429       DRD_(thread_enter_synchr)(drd_tid);
    430       break;
    431 
    432    case VG_USERREQ__POST_SEM_DESTROY:
    433       if (DRD_(thread_leave_synchr)(drd_tid) == 0)
    434          DRD_(semaphore_destroy)(arg[1]);
    435       break;
    436 
    437    case VG_USERREQ__PRE_SEM_OPEN:
    438       DRD_(thread_enter_synchr)(drd_tid);
    439       break;
    440 
    441    case VG_USERREQ__POST_SEM_OPEN:
    442       if (DRD_(thread_leave_synchr)(drd_tid) == 0)
    443          DRD_(semaphore_open)(arg[1], (Char*)arg[2], arg[3], arg[4], arg[5]);
    444       break;
    445 
    446    case VG_USERREQ__PRE_SEM_CLOSE:
    447       if (DRD_(thread_enter_synchr)(drd_tid) == 0)
    448          DRD_(semaphore_close)(arg[1]);
    449       break;
    450 
    451    case VG_USERREQ__POST_SEM_CLOSE:
    452       DRD_(thread_leave_synchr)(drd_tid);
    453       break;
    454 
    455    case VG_USERREQ__PRE_SEM_WAIT:
    456       if (DRD_(thread_enter_synchr)(drd_tid) == 0)
    457          DRD_(semaphore_pre_wait)(arg[1]);
    458       break;
    459 
    460    case VG_USERREQ__POST_SEM_WAIT:
    461       if (DRD_(thread_leave_synchr)(drd_tid) == 0)
    462          DRD_(semaphore_post_wait)(drd_tid, arg[1], arg[2]);
    463       break;
    464 
    465    case VG_USERREQ__PRE_SEM_POST:
    466       if (DRD_(thread_enter_synchr)(drd_tid) == 0)
    467          DRD_(semaphore_pre_post)(drd_tid, arg[1]);
    468       break;
    469 
    470    case VG_USERREQ__POST_SEM_POST:
    471       if (DRD_(thread_leave_synchr)(drd_tid) == 0)
    472          DRD_(semaphore_post_post)(drd_tid, arg[1], arg[2]);
    473       break;
    474 
    475    case VG_USERREQ__PRE_BARRIER_INIT:
    476       if (DRD_(thread_enter_synchr)(drd_tid) == 0)
    477          DRD_(barrier_init)(arg[1], arg[2], arg[3], arg[4]);
    478       break;
    479 
    480    case VG_USERREQ__POST_BARRIER_INIT:
    481       DRD_(thread_leave_synchr)(drd_tid);
    482       break;
    483 
    484    case VG_USERREQ__PRE_BARRIER_DESTROY:
    485       DRD_(thread_enter_synchr)(drd_tid);
    486       break;
    487 
    488    case VG_USERREQ__POST_BARRIER_DESTROY:
    489       if (DRD_(thread_leave_synchr)(drd_tid) == 0)
    490          DRD_(barrier_destroy)(arg[1], arg[2]);
    491       break;
    492 
    493    case VG_USERREQ__PRE_BARRIER_WAIT:
    494       if (DRD_(thread_enter_synchr)(drd_tid) == 0)
    495          DRD_(barrier_pre_wait)(drd_tid, arg[1], arg[2]);
    496       break;
    497 
    498    case VG_USERREQ__POST_BARRIER_WAIT:
    499       if (DRD_(thread_leave_synchr)(drd_tid) == 0)
    500          DRD_(barrier_post_wait)(drd_tid, arg[1], arg[2], arg[3], arg[4]);
    501       break;
    502 
    503    case VG_USERREQ__PRE_RWLOCK_INIT:
    504       DRD_(rwlock_pre_init)(arg[1], pthread_rwlock);
    505       break;
    506 
    507    case VG_USERREQ__POST_RWLOCK_DESTROY:
    508       DRD_(rwlock_post_destroy)(arg[1], pthread_rwlock);
    509       break;
    510 
    511    case VG_USERREQ__PRE_RWLOCK_RDLOCK:
    512       if (DRD_(thread_enter_synchr)(drd_tid) == 0)
    513          DRD_(rwlock_pre_rdlock)(arg[1], pthread_rwlock);
    514       break;
    515 
    516    case VG_USERREQ__POST_RWLOCK_RDLOCK:
    517       if (DRD_(thread_leave_synchr)(drd_tid) == 0)
    518          DRD_(rwlock_post_rdlock)(arg[1], pthread_rwlock, arg[2]);
    519       break;
    520 
    521    case VG_USERREQ__PRE_RWLOCK_WRLOCK:
    522       if (DRD_(thread_enter_synchr)(drd_tid) == 0)
    523          DRD_(rwlock_pre_wrlock)(arg[1], pthread_rwlock);
    524       break;
    525 
    526    case VG_USERREQ__POST_RWLOCK_WRLOCK:
    527       if (DRD_(thread_leave_synchr)(drd_tid) == 0)
    528          DRD_(rwlock_post_wrlock)(arg[1], pthread_rwlock, arg[2]);
    529       break;
    530 
    531    case VG_USERREQ__PRE_RWLOCK_UNLOCK:
    532       if (DRD_(thread_enter_synchr)(drd_tid) == 0)
    533          DRD_(rwlock_pre_unlock)(arg[1], pthread_rwlock);
    534       break;
    535 
    536    case VG_USERREQ__POST_RWLOCK_UNLOCK:
    537       DRD_(thread_leave_synchr)(drd_tid);
    538       break;
    539 
    540    case VG_USERREQ__DRD_CLEAN_MEMORY:
    541       if (arg[2] > 0)
    542          DRD_(clean_memory)(arg[1], arg[2]);
    543       break;
    544 
    545    case VG_USERREQ__HELGRIND_ANNOTATION_UNIMP:
    546       {
    547          /* Note: it is assumed below that the text arg[1] points to is never
    548           * freed, e.g. because it points to static data.
    549           */
    550          UnimpClReqInfo UICR =
    551             { DRD_(thread_get_running_tid)(), (Char*)arg[1] };
    552          VG_(maybe_record_error)(vg_tid,
    553                                  UnimpHgClReq,
    554                                  VG_(get_IP)(vg_tid),
    555                                  "",
    556                                  &UICR);
    557       }
    558       break;
    559 
    560    case VG_USERREQ__DRD_ANNOTATION_UNIMP:
    561       {
    562          /* Note: it is assumed below that the text arg[1] points to is never
    563           * freed, e.g. because it points to static data.
    564           */
    565          UnimpClReqInfo UICR =
    566             { DRD_(thread_get_running_tid)(), (Char*)arg[1] };
    567          VG_(maybe_record_error)(vg_tid,
    568                                  UnimpDrdClReq,
    569                                  VG_(get_IP)(vg_tid),
    570                                  "",
    571                                  &UICR);
    572       }
    573       break;
    574 
    575    default:
    576 #if 0
    577       VG_(message)(Vg_DebugMsg, "Unrecognized client request 0x%lx 0x%lx",
    578                    arg[0], arg[1]);
    579       tl_assert(0);
    580 #endif
    581       return False;
    582    }
    583 
    584    *ret = result;
    585    return True;
    586 }
    587