Home | History | Annotate | Download | only in coregrind
      1 
      2 /*--------------------------------------------------------------------*/
      3 /*--- Process-related libc stuff.                     m_libcproc.c ---*/
      4 /*--------------------------------------------------------------------*/
      5 
      6 /*
      7    This file is part of Valgrind, a dynamic binary instrumentation
      8    framework.
      9 
     10    Copyright (C) 2000-2015 Julian Seward
     11       jseward (at) acm.org
     12 
     13    This program is free software; you can redistribute it and/or
     14    modify it under the terms of the GNU General Public License as
     15    published by the Free Software Foundation; either version 2 of the
     16    License, or (at your option) any later version.
     17 
     18    This program is distributed in the hope that it will be useful, but
     19    WITHOUT ANY WARRANTY; without even the implied warranty of
     20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     21    General Public License for more details.
     22 
     23    You should have received a copy of the GNU General Public License
     24    along with this program; if not, write to the Free Software
     25    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
     26    02111-1307, USA.
     27 
     28    The GNU General Public License is contained in the file COPYING.
     29 */
     30 
     31 #include "pub_core_basics.h"
     32 #include "pub_core_machine.h"    // For VG_(machine_get_VexArchInfo)
     33 #include "pub_core_vki.h"
     34 #include "pub_core_vkiscnums.h"
     35 #include "pub_core_libcbase.h"
     36 #include "pub_core_libcassert.h"
     37 #include "pub_core_libcfile.h"
     38 #include "pub_core_libcprint.h"
     39 #include "pub_core_libcproc.h"
     40 #include "pub_core_libcsignal.h"
     41 #include "pub_core_seqmatch.h"
     42 #include "pub_core_mallocfree.h"
     43 #include "pub_core_syscall.h"
     44 #include "pub_core_xarray.h"
     45 #include "pub_core_clientstate.h"
     46 
     47 #if defined(VGO_darwin)
     48 /* --- !!! --- EXTERNAL HEADERS start --- !!! --- */
     49 #include <mach/mach.h>   /* mach_thread_self */
     50 /* --- !!! --- EXTERNAL HEADERS end --- !!! --- */
     51 #endif
     52 
     53 /* IMPORTANT: on Darwin it is essential to use the _nocancel versions
     54    of syscalls rather than the vanilla version, if a _nocancel version
     55    is available.  See docs/internals/Darwin-notes.txt for the reason
     56    why. */
     57 
     58 /* ---------------------------------------------------------------------
     59    Command line and environment stuff
     60    ------------------------------------------------------------------ */
     61 
     62 /* As deduced from sp_at_startup, the client's argc, argv[] and
     63    envp[] as extracted from the client's stack at startup-time. */
     64 HChar** VG_(client_envp) = NULL;
     65 
     66 /* Path to library directory */
     67 const HChar *VG_(libdir) = VG_LIBDIR;
     68 
     69 const HChar *VG_(LD_PRELOAD_var_name) =
     70 #if defined(VGO_linux) || defined(VGO_solaris)
     71    "LD_PRELOAD";
     72 #elif defined(VGO_darwin)
     73    "DYLD_INSERT_LIBRARIES";
     74 #else
     75 #  error Unknown OS
     76 #endif
     77 
     78 /* We do getenv without libc's help by snooping around in
     79    VG_(client_envp) as determined at startup time. */
     80 HChar *VG_(getenv)(const HChar *varname)
     81 {
     82    Int i, n;
     83    vg_assert( VG_(client_envp) );
     84    n = VG_(strlen)(varname);
     85    for (i = 0; VG_(client_envp)[i] != NULL; i++) {
     86       HChar* s = VG_(client_envp)[i];
     87       if (VG_(strncmp)(varname, s, n) == 0 && s[n] == '=') {
     88          return & s[n+1];
     89       }
     90    }
     91    return NULL;
     92 }
     93 
     94 /* If free_fn is not NULL, it is called on "unset" environment variable. */
     95 void  VG_(env_unsetenv) ( HChar **env, const HChar *varname,
     96                           void (*free_fn) (void *) )
     97 {
     98    HChar **from, **to;
     99    vg_assert(env);
    100    vg_assert(varname);
    101    to = NULL;
    102    Int len = VG_(strlen)(varname);
    103 
    104    for (from = to = env; from && *from; from++) {
    105       if (!(VG_(strncmp)(varname, *from, len) == 0 && (*from)[len] == '=')) {
    106 	 *to = *from;
    107 	 to++;
    108       } else if (free_fn != NULL) {
    109          free_fn(*from);
    110       }
    111    }
    112    *to = *from;
    113 }
    114 
    115 /* set the environment; returns the old env if a new one was allocated */
    116 HChar **VG_(env_setenv) ( HChar ***envp, const HChar* varname,
    117                           const HChar *val )
    118 {
    119    HChar **env = (*envp);
    120    HChar **cpp;
    121    Int len = VG_(strlen)(varname);
    122    HChar *valstr = VG_(malloc)("libcproc.es.1", len + VG_(strlen)(val) + 2);
    123    HChar **oldenv = NULL;
    124 
    125    VG_(sprintf)(valstr, "%s=%s", varname, val);
    126 
    127    for (cpp = env; cpp && *cpp; cpp++) {
    128       if (VG_(strncmp)(varname, *cpp, len) == 0 && (*cpp)[len] == '=') {
    129 	 *cpp = valstr;
    130 	 return oldenv;
    131       }
    132    }
    133 
    134    if (env == NULL) {
    135       env = VG_(malloc)("libcproc.es.2", sizeof(HChar *) * 2);
    136       env[0] = valstr;
    137       env[1] = NULL;
    138 
    139       *envp = env;
    140 
    141    }  else {
    142       Int envlen = (cpp-env) + 2;
    143       HChar **newenv = VG_(malloc)("libcproc.es.3", envlen * sizeof(HChar *));
    144 
    145       for (cpp = newenv; *env; )
    146 	 *cpp++ = *env++;
    147       *cpp++ = valstr;
    148       *cpp++ = NULL;
    149 
    150       oldenv = *envp;
    151 
    152       *envp = newenv;
    153    }
    154 
    155    return oldenv;
    156 }
    157 
    158 
    159 /* Walk through a colon-separated environment variable, and remove the
    160    entries which match remove_pattern.  It slides everything down over
    161    the removed entries, and pads the remaining space with '\0'.  It
    162    modifies the entries in place (in the client address space), but it
    163    shouldn't matter too much, since we only do this just before an
    164    execve().
    165 
    166    This is also careful to mop up any excess ':'s, since empty strings
    167    delimited by ':' are considered to be '.' in a path.
    168 */
    169 static void mash_colon_env(HChar *varp, const HChar *remove_pattern)
    170 {
    171    HChar *const start = varp;
    172    HChar *entry_start = varp;
    173    HChar *output = varp;
    174 
    175    if (varp == NULL)
    176       return;
    177 
    178    while(*varp) {
    179       if (*varp == ':') {
    180 	 HChar prev;
    181 	 Bool match;
    182 
    183 	 /* This is a bit subtle: we want to match against the entry
    184 	    we just copied, because it may have overlapped with
    185 	    itself, junking the original. */
    186 
    187 	 prev = *output;
    188 	 *output = '\0';
    189 
    190 	 match = VG_(string_match)(remove_pattern, entry_start);
    191 
    192 	 *output = prev;
    193 
    194 	 if (match) {
    195 	    output = entry_start;
    196 	    varp++;			/* skip ':' after removed entry */
    197 	 } else
    198 	    entry_start = output+1;	/* entry starts after ':' */
    199       }
    200 
    201       if (*varp)
    202          *output++ = *varp++;
    203    }
    204 
    205    /* make sure last entry is nul terminated */
    206    *output = '\0';
    207 
    208    /* match against the last entry */
    209    if (VG_(string_match)(remove_pattern, entry_start)) {
    210       output = entry_start;
    211       if (output > start) {
    212 	 /* remove trailing ':' */
    213 	 output--;
    214 	 vg_assert(*output == ':');
    215       }
    216    }
    217 
    218    /* pad out the left-overs with '\0' */
    219    while(output < varp)
    220       *output++ = '\0';
    221 }
    222 
    223 
    224 /* Removes all the Valgrind-added stuff from the passed environment.  Used
    225    when starting child processes, so they don't see that added stuff.
    226    If the ro_strings option is set to True then all strings referenced by envp
    227    are considered read-only, which means they will be duplicated before they
    228    are modified.
    229    If free_fn is not NULL, it is called on "unset" environment variables. */
    230 void VG_(env_remove_valgrind_env_stuff)(HChar** envp, Bool ro_strings,
    231                                         void (*free_fn) (void *) )
    232 {
    233    Int i;
    234    HChar* ld_preload_str = NULL;
    235    HChar* ld_library_path_str = NULL;
    236    HChar* dyld_insert_libraries_str = NULL;
    237    HChar* buf;
    238 
    239    // Find LD_* variables
    240    // DDD: should probably conditionally compiled some of this:
    241    // - LD_LIBRARY_PATH is universal?
    242    // - LD_PRELOAD is on Linux, not on Darwin, not sure about AIX
    243    // - DYLD_INSERT_LIBRARIES and DYLD_SHARED_REGION are Darwin-only
    244    for (i = 0; envp[i] != NULL; i++) {
    245       if (VG_(strncmp)(envp[i], "LD_PRELOAD=", 11) == 0) {
    246          if (ro_strings)
    247             envp[i] = VG_(strdup)("libcproc.erves.1", envp[i]);
    248          ld_preload_str = &envp[i][11];
    249       }
    250       if (VG_(strncmp)(envp[i], "LD_LIBRARY_PATH=", 16) == 0) {
    251          if (ro_strings)
    252             envp[i] = VG_(strdup)("libcproc.erves.2", envp[i]);
    253          ld_library_path_str = &envp[i][16];
    254       }
    255       if (VG_(strncmp)(envp[i], "DYLD_INSERT_LIBRARIES=", 22) == 0) {
    256          if (ro_strings)
    257             envp[i] = VG_(strdup)("libcproc.erves.3", envp[i]);
    258          dyld_insert_libraries_str = &envp[i][22];
    259       }
    260    }
    261 
    262    buf = VG_(malloc)("libcproc.erves.4", VG_(strlen)(VG_(libdir)) + 20);
    263 
    264    // Remove Valgrind-specific entries from LD_*.
    265    VG_(sprintf)(buf, "%s*/vgpreload_*.so", VG_(libdir));
    266    mash_colon_env(ld_preload_str, buf);
    267    mash_colon_env(dyld_insert_libraries_str, buf);
    268    VG_(sprintf)(buf, "%s*", VG_(libdir));
    269    mash_colon_env(ld_library_path_str, buf);
    270 
    271    // Remove VALGRIND_LAUNCHER variable.
    272    VG_(env_unsetenv)(envp, VALGRIND_LAUNCHER, free_fn);
    273 
    274    // Remove DYLD_SHARED_REGION variable.
    275    VG_(env_unsetenv)(envp, "DYLD_SHARED_REGION", free_fn);
    276 
    277    // XXX if variable becomes empty, remove it completely?
    278 
    279    VG_(free)(buf);
    280 }
    281 
    282 /* Resolves filename of VG_(cl_exec_fd) and copies it to the buffer.
    283    Buffer must not be NULL and buf_size must be at least 1.
    284    If buffer is not large enough it is terminated with '\0' only
    285    when 'terminate_with_NUL == True'. */
    286 void VG_(client_fname)(HChar *buffer, SizeT buf_size, Bool terminate_with_NUL)
    287 {
    288    vg_assert(buffer != NULL);
    289    vg_assert(buf_size >= 1);
    290 
    291    const HChar *name;
    292    if (VG_(resolve_filename)(VG_(cl_exec_fd), &name)) {
    293       const HChar *n = name + VG_(strlen)(name) - 1;
    294 
    295       while (n > name && *n != '/')
    296          n--;
    297       if (n != name)
    298          n++;
    299 
    300       VG_(strncpy)(buffer, n, buf_size);
    301       if (terminate_with_NUL)
    302          buffer[buf_size - 1] = '\0';
    303    } else {
    304       buffer[0] = '\0';
    305    }
    306 }
    307 
    308 static Bool add_string(HChar *buffer, SizeT *buf_size, const HChar *string)
    309 {
    310    SizeT len = VG_(strlen)(string);
    311    VG_(strncat)(buffer, string, *buf_size);
    312    if (len >= *buf_size - 1) {
    313       *buf_size = 0;
    314       return False;
    315    } else {
    316       *buf_size -= len;
    317       return True;
    318    }
    319 }
    320 
    321 /* Concatenates client exename and command line arguments into
    322    the buffer. Buffer must not be NULL and buf_size must be
    323    at least 1. Buffer is always terminated with '\0'. */
    324 void VG_(client_cmd_and_args)(HChar *buffer, SizeT buf_size)
    325 {
    326    vg_assert(buffer != NULL);
    327    vg_assert(buf_size >= 1);
    328 
    329    buffer[0] = '\0';
    330 
    331    if (add_string(buffer, &buf_size, VG_(args_the_exename)) == False)
    332       return;
    333 
    334    Int i;
    335    for (i = 0; i < VG_(sizeXA)(VG_(args_for_client)); i++) {
    336       if (add_string(buffer, &buf_size, " ") == False)
    337          return;
    338 
    339       HChar *arg = *(HChar **) VG_(indexXA)(VG_(args_for_client), i);
    340       if (add_string(buffer, &buf_size, arg) == False)
    341          return;
    342    }
    343 }
    344 
    345 /* ---------------------------------------------------------------------
    346    Various important syscall wrappers
    347    ------------------------------------------------------------------ */
    348 
    349 Int VG_(waitpid)(Int pid, Int *status, Int options)
    350 {
    351 #  if defined(VGO_linux)
    352    SysRes res = VG_(do_syscall4)(__NR_wait4,
    353                                  pid, (UWord)status, options, 0);
    354    return sr_isError(res) ? -1 : sr_Res(res);
    355 #  elif defined(VGO_darwin)
    356    SysRes res = VG_(do_syscall4)(__NR_wait4_nocancel,
    357                                  pid, (UWord)status, options, 0);
    358    return sr_isError(res) ? -1 : sr_Res(res);
    359 #  elif defined(VGO_solaris)
    360    SysRes res;
    361    vki_idtype_t idtype;
    362    vki_id_t id;
    363    vki_siginfo_t info;
    364 
    365    /* We need to do a lot of work here. */
    366 
    367    if (pid > 0) {
    368       idtype = VKI_P_PID;
    369       id = pid;
    370    }
    371    else if (pid < -1) {
    372       idtype = VKI_P_PGID;
    373       id = -pid;
    374    }
    375    else if (pid == -1) {
    376       idtype = VKI_P_ALL;
    377       id = 0;
    378    }
    379    else {
    380       idtype = VKI_P_PGID;
    381       res = VG_(do_syscall0)(__NR_getpid);
    382       id = sr_ResHI(res);
    383    }
    384 
    385    options |= VKI_WEXITED | VKI_WTRAPPED;
    386 
    387    res = VG_(do_syscall4)(__NR_waitsys, idtype, id, (UWord)&info, options);
    388    if (sr_isError(res))
    389       return -1;
    390 
    391    if (status) {
    392       Int s = info.si_status & 0xff;
    393 
    394       switch (info.si_code) {
    395          case VKI_CLD_EXITED:
    396             s <<= 8;
    397             break;
    398          case VKI_CLD_DUMPED:
    399             s |= VKI_WCOREFLG;
    400             break;
    401          case VKI_CLD_KILLED:
    402             break;
    403          case VKI_CLD_TRAPPED:
    404          case VKI_CLD_STOPPED:
    405             s <<= 8;
    406             s |= VKI_WSTOPFLG;
    407             break;
    408          case VKI_CLD_CONTINUED:
    409             s = VKI_WCONTFLG;
    410             break;
    411       }
    412       *status = s;
    413    }
    414 
    415    return info.si_pid;
    416 #  else
    417 #    error Unknown OS
    418 #  endif
    419 }
    420 
    421 /* clone the environment */
    422 HChar **VG_(env_clone) ( HChar **oldenv )
    423 {
    424    HChar **oldenvp;
    425    HChar **newenvp;
    426    HChar **newenv;
    427    Int  envlen;
    428 
    429    vg_assert(oldenv);
    430    for (oldenvp = oldenv; oldenvp && *oldenvp; oldenvp++);
    431 
    432    envlen = oldenvp - oldenv + 1;
    433 
    434    newenv = VG_(malloc)("libcproc.ec.1", envlen * sizeof(HChar *));
    435 
    436    oldenvp = oldenv;
    437    newenvp = newenv;
    438 
    439    while (oldenvp && *oldenvp) {
    440       *newenvp++ = *oldenvp++;
    441    }
    442 
    443    *newenvp = *oldenvp;
    444 
    445    return newenv;
    446 }
    447 
    448 void VG_(execv) ( const HChar* filename, const HChar** argv )
    449 {
    450    HChar** envp;
    451    SysRes res;
    452 
    453    /* restore the DATA rlimit for the child */
    454    VG_(setrlimit)(VKI_RLIMIT_DATA, &VG_(client_rlimit_data));
    455 
    456    envp = VG_(env_clone)(VG_(client_envp));
    457    VG_(env_remove_valgrind_env_stuff)( envp, True /*ro_strings*/, NULL );
    458 
    459    res = VG_(do_syscall3)(__NR_execve,
    460                           (UWord)filename, (UWord)argv, (UWord)envp);
    461 
    462    VG_(printf)("EXEC failed, errno = %lld\n", (Long)sr_Err(res));
    463 }
    464 
    465 /* Spawns a new child. Uses either spawn syscall or fork+execv combo. */
    466 Int VG_(spawn) ( const HChar *filename, const HChar **argv )
    467 {
    468    vg_assert(filename != NULL);
    469    vg_assert(argv != NULL);
    470 
    471 #  if defined(VGO_solaris) && defined(SOLARIS_SPAWN_SYSCALL)
    472    HChar **envp = VG_(env_clone)(VG_(client_envp));
    473    for (HChar **p = envp; *p != NULL; p++) {
    474       *p = VG_(strdup)("libcproc.s.1", *p);
    475    }
    476    VG_(env_remove_valgrind_env_stuff)(envp, /* ro_strings */ False, VG_(free));
    477 
    478    /* Now combine argv and argp into argenv. */
    479    SizeT argenv_size = 1 + 1;
    480    for (const HChar **p = argv; *p != NULL; p++) {
    481       argenv_size += VG_(strlen)(*p) + 2;
    482    }
    483    for (HChar **p = envp; *p != NULL; p++) {
    484       argenv_size += VG_(strlen)(*p) + 2;
    485    }
    486 
    487    HChar *argenv = VG_(malloc)("libcproc.s.2", argenv_size);
    488    HChar *current = argenv;
    489 #  define COPY_CHAR_TO_ARGENV(dst, character)  \
    490       do {                                     \
    491          *(dst) = character;                   \
    492          (dst) += 1;                           \
    493       } while (0)
    494 #  define COPY_STRING_TO_ARGENV(dst, src)        \
    495       do {                                       \
    496          COPY_CHAR_TO_ARGENV(dst, '\1');         \
    497          SizeT src_len = VG_(strlen)((src)) + 1; \
    498          VG_(memcpy)((dst), (src), src_len);     \
    499          (dst) += src_len;                       \
    500       } while (0)
    501 
    502    for (const HChar **p = argv; *p != NULL; p++) {
    503       COPY_STRING_TO_ARGENV(current, *p);
    504    }
    505    COPY_CHAR_TO_ARGENV(current, '\0');
    506    for (HChar **p = envp; *p != NULL; p++) {
    507       COPY_STRING_TO_ARGENV(current, *p);
    508    }
    509    COPY_CHAR_TO_ARGENV(current, '\0');
    510    vg_assert(current == argenv + argenv_size);
    511 #  undef COPY_CHAR_TO_ARGENV
    512 #  undef COPY_STRING_TOARGENV
    513 
    514    /* HACK: Temporarily restore the DATA rlimit for spawned child. */
    515    VG_(setrlimit)(VKI_RLIMIT_DATA, &VG_(client_rlimit_data));
    516 
    517    SysRes res = VG_(do_syscall5)(__NR_spawn, (UWord) filename, (UWord) NULL, 0,
    518                                  (UWord) argenv, argenv_size);
    519 
    520    /* Restore DATA rlimit back to its previous value set in m_main.c. */
    521    struct vki_rlimit zero = { 0, 0 };
    522    zero.rlim_max = VG_(client_rlimit_data).rlim_max;
    523    VG_(setrlimit)(VKI_RLIMIT_DATA, &zero);
    524 
    525    VG_(free)(argenv);
    526    for (HChar **p = envp; *p != NULL; p++) {
    527       VG_(free)(*p);
    528    }
    529    VG_(free)(envp);
    530 
    531    if (sr_isError(res))
    532       return -1;
    533    return sr_Res(res);
    534 
    535 #  else
    536 
    537    Int pid = VG_(fork)();
    538    if (pid < 0)
    539       return -1;
    540    if (pid == 0) {
    541       /* child */
    542       VG_(execv)(argv[0], argv);
    543 
    544       /* If we're still alive here, execv failed. */
    545       VG_(exit)(1);
    546    } else {
    547       return pid;
    548    }
    549 #  endif /* VGO_solaris && SOLARIS_SPAWN_SYSCALL */
    550 }
    551 
    552 /* Return -1 if error, else 0.  NOTE does not indicate return code of
    553    child! */
    554 Int VG_(system) ( const HChar* cmd )
    555 {
    556    Int pid;
    557    if (cmd == NULL)
    558       return 1;
    559 
    560    const HChar *argv[4] = { "/bin/sh", "-c", cmd, 0 };
    561    pid = VG_(spawn)(argv[0], argv);
    562    if (pid < 0)
    563       return -1;
    564 
    565    vg_assert(pid > 0);
    566    /* parent */
    567    /* We have to set SIGCHLD to its default behaviour in order that
    568       VG_(waitpid) works (at least on AIX).  According to the Linux
    569       man page for waitpid:
    570 
    571       POSIX.1-2001 specifies that if the disposition of SIGCHLD is
    572       set to SIG_IGN or the SA_NOCLDWAIT flag is set for SIGCHLD
    573       (see sigaction(2)), then children that terminate do not
    574       become zombies and a call to wait() or waitpid() will block
    575       until all children have terminated, and then fail with errno
    576       set to ECHILD.  (The original POSIX standard left the
    577       behaviour of setting SIGCHLD to SIG_IGN unspecified.)
    578    */
    579    Int ir, zzz;
    580    vki_sigaction_toK_t sa, sa2;
    581    vki_sigaction_fromK_t saved_sa;
    582    VG_(memset)( &sa, 0, sizeof(sa) );
    583    VG_(sigemptyset)(&sa.sa_mask);
    584    sa.ksa_handler = VKI_SIG_DFL;
    585    sa.sa_flags    = 0;
    586    ir = VG_(sigaction)(VKI_SIGCHLD, &sa, &saved_sa);
    587    vg_assert(ir == 0);
    588 
    589    zzz = VG_(waitpid)(pid, NULL, 0);
    590 
    591    VG_(convert_sigaction_fromK_to_toK)( &saved_sa, &sa2 );
    592    ir = VG_(sigaction)(VKI_SIGCHLD, &sa2, NULL);
    593    vg_assert(ir == 0);
    594    return zzz == -1 ? -1 : 0;
    595 }
    596 
    597 Int VG_(sysctl)(Int *name, UInt namelen, void *oldp, SizeT *oldlenp, void *newp, SizeT newlen)
    598 {
    599    SysRes res;
    600 #  if defined(VGO_darwin)
    601    res = VG_(do_syscall6)(__NR___sysctl,
    602                            (UWord)name, namelen, (UWord)oldp, (UWord)oldlenp, (UWord)newp, newlen);
    603 #  else
    604    res = VG_(mk_SysRes_Error)(VKI_ENOSYS);
    605 #  endif
    606    return sr_isError(res) ? -1 : sr_Res(res);
    607 }
    608 
    609 /* ---------------------------------------------------------------------
    610    Resource limits
    611    ------------------------------------------------------------------ */
    612 
    613 /* Support for getrlimit. */
    614 Int VG_(getrlimit) (Int resource, struct vki_rlimit *rlim)
    615 {
    616    SysRes res = VG_(mk_SysRes_Error)(VKI_ENOSYS);
    617    /* res = getrlimit( resource, rlim ); */
    618 #  ifdef __NR_ugetrlimit
    619    res = VG_(do_syscall2)(__NR_ugetrlimit, resource, (UWord)rlim);
    620 #  endif
    621    if (sr_isError(res) && sr_Err(res) == VKI_ENOSYS)
    622       res = VG_(do_syscall2)(__NR_getrlimit, resource, (UWord)rlim);
    623    return sr_isError(res) ? -1 : sr_Res(res);
    624 }
    625 
    626 
    627 /* Support for setrlimit. */
    628 Int VG_(setrlimit) (Int resource, const struct vki_rlimit *rlim)
    629 {
    630    SysRes res;
    631    /* res = setrlimit( resource, rlim ); */
    632    res = VG_(do_syscall2)(__NR_setrlimit, resource, (UWord)rlim);
    633    return sr_isError(res) ? -1 : sr_Res(res);
    634 }
    635 
    636 /* Support for prctl. */
    637 Int VG_(prctl) (Int option,
    638                 ULong arg2, ULong arg3, ULong arg4, ULong arg5)
    639 {
    640    SysRes res = VG_(mk_SysRes_Error)(VKI_ENOSYS);
    641 #  if defined(VGO_linux)
    642    /* res = prctl( option, arg2, arg3, arg4, arg5 ); */
    643    res = VG_(do_syscall5)(__NR_prctl, (UWord) option,
    644                           (UWord) arg2, (UWord) arg3, (UWord) arg4,
    645                           (UWord) arg5);
    646 #  endif
    647 
    648    return sr_isError(res) ? -1 : sr_Res(res);
    649 }
    650 
    651 /* ---------------------------------------------------------------------
    652    pids, etc
    653    ------------------------------------------------------------------ */
    654 
    655 Int VG_(gettid)(void)
    656 {
    657 #  if defined(VGO_linux)
    658    SysRes res = VG_(do_syscall0)(__NR_gettid);
    659 
    660    if (sr_isError(res) && sr_Res(res) == VKI_ENOSYS) {
    661       HChar pid[16];
    662       /*
    663        * The gettid system call does not exist. The obvious assumption
    664        * to make at this point would be that we are running on an older
    665        * system where the getpid system call actually returns the ID of
    666        * the current thread.
    667        *
    668        * Unfortunately it seems that there are some systems with a kernel
    669        * where getpid has been changed to return the ID of the thread group
    670        * leader but where the gettid system call has not yet been added.
    671        *
    672        * So instead of calling getpid here we use readlink to see where
    673        * the /proc/self link is pointing...
    674        */
    675 
    676 #     if defined(VGP_arm64_linux) || defined(VGP_tilegx_linux)
    677       res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD,
    678                              (UWord)"/proc/self",
    679                              (UWord)pid, sizeof(pid));
    680 #     else
    681       res = VG_(do_syscall3)(__NR_readlink, (UWord)"/proc/self",
    682                              (UWord)pid, sizeof(pid));
    683 #     endif
    684       if (!sr_isError(res) && sr_Res(res) > 0) {
    685          HChar* s;
    686          pid[sr_Res(res)] = '\0';
    687          res = VG_(mk_SysRes_Success)(  VG_(strtoll10)(pid, &s) );
    688          if (*s != '\0') {
    689             VG_(message)(Vg_DebugMsg,
    690                "Warning: invalid file name linked to by /proc/self: %s\n",
    691                pid);
    692          }
    693       }
    694    }
    695 
    696    return sr_Res(res);
    697 
    698 #  elif defined(VGO_darwin)
    699    // Darwin's gettid syscall is something else.
    700    // Use Mach thread ports for lwpid instead.
    701    return mach_thread_self();
    702 
    703 #  elif defined(VGO_solaris)
    704    SysRes res = VG_(do_syscall0)(__NR_lwp_self);
    705    return sr_Res(res);
    706 
    707 #  else
    708 #    error "Unknown OS"
    709 #  endif
    710 }
    711 
    712 /* You'd be amazed how many places need to know the current pid. */
    713 Int VG_(getpid) ( void )
    714 {
    715    /* ASSUMES SYSCALL ALWAYS SUCCEEDS */
    716    return sr_Res( VG_(do_syscall0)(__NR_getpid) );
    717 }
    718 
    719 Int VG_(getpgrp) ( void )
    720 {
    721    /* ASSUMES SYSCALL ALWAYS SUCCEEDS */
    722 #  if defined(VGO_linux) || defined(VGO_darwin)
    723    return sr_Res( VG_(do_syscall0)(__NR_getpgrp) );
    724 #  elif defined(VGO_solaris)
    725    /* Uses the shared pgrpsys syscall, 0 for the getpgrp variant. */
    726    return sr_Res( VG_(do_syscall1)(__NR_pgrpsys, 0) );
    727 #  else
    728 #    error Unknown OS
    729 #  endif
    730 }
    731 
    732 Int VG_(getppid) ( void )
    733 {
    734    /* ASSUMES SYSCALL ALWAYS SUCCEEDS */
    735 #  if defined(VGO_linux) || defined(VGO_darwin)
    736    return sr_Res( VG_(do_syscall0)(__NR_getppid) );
    737 #  elif defined(VGO_solaris)
    738    /* Uses the shared getpid/getppid syscall, val2 contains a parent pid. */
    739    return sr_ResHI( VG_(do_syscall0)(__NR_getpid) );
    740 #  else
    741 #    error Unknown OS
    742 #  endif
    743 }
    744 
    745 Int VG_(geteuid) ( void )
    746 {
    747    /* ASSUMES SYSCALL ALWAYS SUCCEEDS */
    748 #  if defined(VGO_linux) || defined(VGO_darwin)
    749    {
    750 #     if defined(__NR_geteuid32)
    751       // We use the 32-bit version if it's supported.  Otherwise, IDs greater
    752       // than 65536 cause problems, as bug #151209 showed.
    753       return sr_Res( VG_(do_syscall0)(__NR_geteuid32) );
    754 #     else
    755       return sr_Res( VG_(do_syscall0)(__NR_geteuid) );
    756 #     endif
    757    }
    758 #  elif defined(VGO_solaris)
    759    /* Uses the shared getuid/geteuid syscall, val2 contains the effective
    760       uid. */
    761    return sr_ResHI( VG_(do_syscall0)(__NR_getuid) );
    762 #  else
    763 #    error Unknown OS
    764 #  endif
    765 }
    766 
    767 Int VG_(getegid) ( void )
    768 {
    769 #  if defined(VGO_linux) || defined(VGO_darwin)
    770    /* ASSUMES SYSCALL ALWAYS SUCCEEDS */
    771 #    if defined(__NR_getegid32)
    772    // We use the 32-bit version if it's supported.  Otherwise, IDs greater
    773    // than 65536 cause problems, as bug #151209 showed.
    774    return sr_Res( VG_(do_syscall0)(__NR_getegid32) );
    775 #    else
    776    return sr_Res( VG_(do_syscall0)(__NR_getegid) );
    777 #    endif
    778 
    779 #  elif defined(VGO_solaris)
    780    /* Uses the shared getgid/getegid syscall, val2 contains the effective
    781       gid. */
    782    return sr_ResHI( VG_(do_syscall0)(__NR_getgid) );
    783 #  else
    784 #    error Unknown OS
    785 #  endif
    786 }
    787 
    788 /* Get supplementary groups into list[0 .. size-1].  Returns the
    789    number of groups written, or -1 if error.  Note that in order to be
    790    portable, the groups are 32-bit unsigned ints regardless of the
    791    platform.
    792    As a special case, if size == 0 the function returns the number of
    793    groups leaving list untouched. */
    794 Int VG_(getgroups)( Int size, UInt* list )
    795 {
    796    if (size < 0) return -1;
    797 
    798 #  if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
    799       || defined(VGP_mips64_linux) || defined(VGP_tilegx_linux)
    800    Int    i;
    801    SysRes sres;
    802    UShort list16[size];
    803    sres = VG_(do_syscall2)(__NR_getgroups, size, (Addr)list16);
    804    if (sr_isError(sres))
    805       return -1;
    806    if (size != 0) {
    807       for (i = 0; i < sr_Res(sres); i++)
    808          list[i] = (UInt)list16[i];
    809    }
    810    return sr_Res(sres);
    811 
    812 #  elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
    813         || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)  \
    814         || defined(VGO_darwin) || defined(VGP_s390x_linux)    \
    815         || defined(VGP_mips32_linux) || defined(VGP_arm64_linux) \
    816         || defined(VGO_solaris)
    817    SysRes sres;
    818    sres = VG_(do_syscall2)(__NR_getgroups, size, (Addr)list);
    819    if (sr_isError(sres))
    820       return -1;
    821    return sr_Res(sres);
    822 
    823 #  else
    824 #     error "VG_(getgroups): needs implementation on this platform"
    825 #  endif
    826 }
    827 
    828 /* ---------------------------------------------------------------------
    829    Process tracing
    830    ------------------------------------------------------------------ */
    831 
    832 Int VG_(ptrace) ( Int request, Int pid, void *addr, void *data )
    833 {
    834    SysRes res;
    835 #  if defined(VGO_linux) || defined(VGO_darwin)
    836    res = VG_(do_syscall4)(__NR_ptrace, request, pid, (UWord)addr, (UWord)data);
    837 #  elif defined(VGO_solaris)
    838    /* There is no ptrace syscall on Solaris.  Such requests has to be
    839       implemented using the /proc interface.  Callers of VG_(ptrace) should
    840       ensure that this function is not reached on Solaris, i.e. they must
    841       provide a special code for Solaris for whatever feature they provide. */
    842    I_die_here;
    843 #  else
    844 #    error Unknown OS
    845 #  endif
    846    if (sr_isError(res))
    847       return -1;
    848    return sr_Res(res);
    849 }
    850 
    851 /* ---------------------------------------------------------------------
    852    Fork
    853    ------------------------------------------------------------------ */
    854 
    855 Int VG_(fork) ( void )
    856 {
    857 #  if defined(VGP_arm64_linux) || defined(VGP_tilegx_linux)
    858    SysRes res;
    859    res = VG_(do_syscall5)(__NR_clone, VKI_SIGCHLD,
    860                           (UWord)NULL, (UWord)NULL, (UWord)NULL, (UWord)NULL);
    861    if (sr_isError(res))
    862       return -1;
    863    return sr_Res(res);
    864 
    865 #  elif defined(VGO_linux)
    866    SysRes res;
    867    res = VG_(do_syscall0)(__NR_fork);
    868    if (sr_isError(res))
    869       return -1;
    870    return sr_Res(res);
    871 
    872 #  elif defined(VGO_darwin)
    873    SysRes res;
    874    res = VG_(do_syscall0)(__NR_fork); /* __NR_fork is UX64 */
    875    if (sr_isError(res))
    876       return -1;
    877    /* on success: wLO = child pid; wHI = 1 for child, 0 for parent */
    878    if (sr_ResHI(res) != 0) {
    879       return 0;  /* this is child: return 0 instead of child pid */
    880    }
    881    return sr_Res(res);
    882 
    883 #  elif defined(VGO_solaris)
    884    /* Using fork() on Solaris is not really the best thing to do. Solaris
    885       does not do memory overcommitment so fork() can fail if there is not
    886       enough memory to copy the current process into a new one.
    887       Prefer to use VG_(spawn)() over VG_(fork)() + VG_(execv)(). */
    888    SysRes res;
    889    res = VG_(do_syscall2)(__NR_forksys, 0 /*subcode (fork)*/, 0 /*flags*/);
    890    if (sr_isError(res))
    891       return -1;
    892    /* On success:
    893         val = a pid of the child in the parent, a pid of the parent in the
    894               child,
    895         val2 = 0 in the parent process, 1 in the child process. */
    896    if (sr_ResHI(res) != 0) {
    897       return 0;
    898    }
    899    return sr_Res(res);
    900 
    901 #  else
    902 #    error "Unknown OS"
    903 #  endif
    904 }
    905 
    906 /* ---------------------------------------------------------------------
    907    Timing stuff
    908    ------------------------------------------------------------------ */
    909 
    910 UInt VG_(read_millisecond_timer) ( void )
    911 {
    912    /* 'now' and 'base' are in microseconds */
    913    static ULong base = 0;
    914    ULong  now;
    915 
    916 #  if defined(VGO_linux) || defined(VGO_solaris)
    917    { SysRes res;
    918      struct vki_timespec ts_now;
    919      res = VG_(do_syscall2)(__NR_clock_gettime, VKI_CLOCK_MONOTONIC,
    920                             (UWord)&ts_now);
    921      if (sr_isError(res) == 0) {
    922         now = ts_now.tv_sec * 1000000ULL + ts_now.tv_nsec / 1000;
    923      } else {
    924        struct vki_timeval tv_now;
    925        /* Note: On Solaris, this syscall takes only one parameter but the
    926           extra dummy one does not cause any harm. */
    927        res = VG_(do_syscall2)(__NR_gettimeofday, (UWord)&tv_now, (UWord)NULL);
    928        vg_assert(! sr_isError(res));
    929        now = tv_now.tv_sec * 1000000ULL + tv_now.tv_usec;
    930      }
    931    }
    932 
    933 #  elif defined(VGO_darwin)
    934    // Weird: it seems that gettimeofday() doesn't fill in the timeval, but
    935    // rather returns the tv_sec as the low 32 bits of the result and the
    936    // tv_usec as the high 32 bits of the result.  (But the timeval cannot be
    937    // NULL!)  See bug 200990.
    938    { SysRes res;
    939      struct vki_timeval tv_now = { 0, 0 };
    940      res = VG_(do_syscall2)(__NR_gettimeofday, (UWord)&tv_now, (UWord)NULL);
    941      vg_assert(! sr_isError(res));
    942      now = sr_Res(res) * 1000000ULL + sr_ResHI(res);
    943    }
    944 
    945 #  else
    946 #    error "Unknown OS"
    947 #  endif
    948 
    949    /* COMMON CODE */
    950    if (base == 0)
    951       base = now;
    952 
    953    return (now - base) / 1000;
    954 }
    955 
    956 Int VG_(gettimeofday)(struct vki_timeval *tv, struct vki_timezone *tz)
    957 {
    958    SysRes res;
    959    res = VG_(do_syscall2)(__NR_gettimeofday, (UWord)tv, (UWord)tz);
    960 
    961    if (! sr_isError(res)) return 0;
    962 
    963    /* Make sure, argument values are determinstic upon failure */
    964    if (tv) *tv = (struct vki_timeval){ .tv_sec = 0, .tv_usec = 0 };
    965    if (tz) *tz = (struct vki_timezone){ .tz_minuteswest = 0, .tz_dsttime = 0 };
    966 
    967    return -1;
    968 }
    969 
    970 
    971 /* ---------------------------------------------------------------------
    972    atfork()
    973    ------------------------------------------------------------------ */
    974 
    975 struct atfork {
    976    vg_atfork_t  pre;
    977    vg_atfork_t  parent;
    978    vg_atfork_t  child;
    979 };
    980 
    981 #define VG_MAX_ATFORK 10
    982 
    983 static struct atfork atforks[VG_MAX_ATFORK];
    984 static Int n_atfork = 0;
    985 
    986 void VG_(atfork)(vg_atfork_t pre, vg_atfork_t parent, vg_atfork_t child)
    987 {
    988    Int i;
    989 
    990    for (i = 0; i < n_atfork; i++) {
    991       if (atforks[i].pre == pre &&
    992           atforks[i].parent == parent &&
    993           atforks[i].child == child)
    994          return;
    995    }
    996 
    997    if (n_atfork >= VG_MAX_ATFORK)
    998       VG_(core_panic)(
    999          "Too many VG_(atfork) handlers requested: raise VG_MAX_ATFORK");
   1000 
   1001    atforks[n_atfork].pre    = pre;
   1002    atforks[n_atfork].parent = parent;
   1003    atforks[n_atfork].child  = child;
   1004 
   1005    n_atfork++;
   1006 }
   1007 
   1008 void VG_(do_atfork_pre)(ThreadId tid)
   1009 {
   1010    Int i;
   1011 
   1012    for (i = 0; i < n_atfork; i++)
   1013       if (atforks[i].pre != NULL)
   1014          (*atforks[i].pre)(tid);
   1015 }
   1016 
   1017 void VG_(do_atfork_parent)(ThreadId tid)
   1018 {
   1019    Int i;
   1020 
   1021    for (i = 0; i < n_atfork; i++)
   1022       if (atforks[i].parent != NULL)
   1023          (*atforks[i].parent)(tid);
   1024 }
   1025 
   1026 void VG_(do_atfork_child)(ThreadId tid)
   1027 {
   1028    Int i;
   1029 
   1030    for (i = 0; i < n_atfork; i++)
   1031       if (atforks[i].child != NULL)
   1032          (*atforks[i].child)(tid);
   1033 }
   1034 
   1035 
   1036 /* ---------------------------------------------------------------------
   1037    icache invalidation
   1038    ------------------------------------------------------------------ */
   1039 
   1040 void VG_(invalidate_icache) ( void *ptr, SizeT nbytes )
   1041 {
   1042    if (nbytes == 0) return;    // nothing to do
   1043 
   1044    // Get cache info
   1045    VexArchInfo vai;
   1046    VG_(machine_get_VexArchInfo)(NULL, &vai);
   1047 
   1048    // If I-caches are coherent, nothing needs to be done here
   1049    if (vai.hwcache_info.icaches_maintain_coherence) return;
   1050 
   1051 #  if defined(VGA_ppc32) || defined(VGA_ppc64be) || defined(VGA_ppc64le)
   1052    Addr startaddr = (Addr) ptr;
   1053    Addr endaddr   = startaddr + nbytes;
   1054    Addr cls;
   1055    Addr addr;
   1056 
   1057    cls = vai.ppc_icache_line_szB;
   1058 
   1059    /* Stay sane .. */
   1060    vg_assert(cls == 16 || cls == 32 || cls == 64 || cls == 128);
   1061 
   1062    startaddr &= ~(cls - 1);
   1063    for (addr = startaddr; addr < endaddr; addr += cls) {
   1064       __asm__ __volatile__("dcbst 0,%0" : : "r" (addr));
   1065    }
   1066    __asm__ __volatile__("sync");
   1067    for (addr = startaddr; addr < endaddr; addr += cls) {
   1068       __asm__ __volatile__("icbi 0,%0" : : "r" (addr));
   1069    }
   1070    __asm__ __volatile__("sync; isync");
   1071 
   1072 #  elif defined(VGP_arm_linux)
   1073    /* ARM cache flushes are privileged, so we must defer to the kernel. */
   1074    Addr startaddr = (Addr) ptr;
   1075    Addr endaddr   = startaddr + nbytes;
   1076    VG_(do_syscall2)(__NR_ARM_cacheflush, startaddr, endaddr);
   1077 
   1078 #  elif defined(VGP_arm64_linux)
   1079    // This arm64_linux section of this function VG_(invalidate_icache)
   1080    // is copied from
   1081    // https://github.com/armvixl/vixl/blob/master/src/a64/cpu-a64.cc
   1082    // which has the following copyright notice:
   1083    /*
   1084    Copyright 2013, ARM Limited
   1085    All rights reserved.
   1086 
   1087    Redistribution and use in source and binary forms, with or without
   1088    modification, are permitted provided that the following conditions are met:
   1089 
   1090    * Redistributions of source code must retain the above copyright notice,
   1091      this list of conditions and the following disclaimer.
   1092    * Redistributions in binary form must reproduce the above copyright notice,
   1093      this list of conditions and the following disclaimer in the documentation
   1094      and/or other materials provided with the distribution.
   1095    * Neither the name of ARM Limited nor the names of its contributors may be
   1096      used to endorse or promote products derived from this software without
   1097      specific prior written permission.
   1098 
   1099    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
   1100    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   1101    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   1102    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
   1103    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   1104    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   1105    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   1106    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   1107    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   1108    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   1109    */
   1110 
   1111    // Ask what the I and D line sizes are
   1112    UInt cache_type_register;
   1113    // Copy the content of the cache type register to a core register.
   1114    __asm__ __volatile__ ("mrs %[ctr], ctr_el0" // NOLINT
   1115                          : [ctr] "=r" (cache_type_register));
   1116 
   1117    const Int kDCacheLineSizeShift = 16;
   1118    const Int kICacheLineSizeShift = 0;
   1119    const UInt kDCacheLineSizeMask = 0xf << kDCacheLineSizeShift;
   1120    const UInt kICacheLineSizeMask = 0xf << kICacheLineSizeShift;
   1121 
   1122    // The cache type register holds the size of the I and D caches as a power of
   1123    // two.
   1124    const UInt dcache_line_size_power_of_two =
   1125        (cache_type_register & kDCacheLineSizeMask) >> kDCacheLineSizeShift;
   1126    const UInt icache_line_size_power_of_two =
   1127        (cache_type_register & kICacheLineSizeMask) >> kICacheLineSizeShift;
   1128 
   1129    const UInt dcache_line_size_ = 4 * (1 << dcache_line_size_power_of_two);
   1130    const UInt icache_line_size_ = 4 * (1 << icache_line_size_power_of_two);
   1131 
   1132    Addr start = (Addr)ptr;
   1133    // Sizes will be used to generate a mask big enough to cover a pointer.
   1134    Addr dsize = (Addr)dcache_line_size_;
   1135    Addr isize = (Addr)icache_line_size_;
   1136 
   1137    // Cache line sizes are always a power of 2.
   1138    Addr dstart = start & ~(dsize - 1);
   1139    Addr istart = start & ~(isize - 1);
   1140    Addr end    = start + nbytes;
   1141 
   1142    __asm__ __volatile__ (
   1143      // Clean every line of the D cache containing the target data.
   1144      "0: \n\t"
   1145      // dc : Data Cache maintenance
   1146      // c : Clean
   1147      // va : by (Virtual) Address
   1148      // u : to the point of Unification
   1149      // The point of unification for a processor is the point by which the
   1150      // instruction and data caches are guaranteed to see the same copy of a
   1151      // memory location. See ARM DDI 0406B page B2-12 for more information.
   1152      "dc cvau, %[dline] \n\t"
   1153      "add %[dline], %[dline], %[dsize] \n\t"
   1154      "cmp %[dline], %[end] \n\t"
   1155      "b.lt 0b \n\t"
   1156      // Barrier to make sure the effect of the code above is visible to the rest
   1157      // of the world.
   1158      // dsb : Data Synchronisation Barrier
   1159      // ish : Inner SHareable domain
   1160      // The point of unification for an Inner Shareable shareability domain is
   1161      // the point by which the instruction and data caches of all the processors
   1162      // in that Inner Shareable shareability domain are guaranteed to see the
   1163      // same copy of a memory location. See ARM DDI 0406B page B2-12 for more
   1164      // information.
   1165      "dsb ish \n\t"
   1166      // Invalidate every line of the I cache containing the target data.
   1167      "1: \n\t"
   1168      // ic : instruction cache maintenance
   1169      // i : invalidate
   1170      // va : by address
   1171      // u : to the point of unification
   1172      "ic ivau, %[iline] \n\t"
   1173      "add %[iline], %[iline], %[isize] \n\t"
   1174      "cmp %[iline], %[end] \n\t"
   1175      "b.lt 1b \n\t"
   1176      // Barrier to make sure the effect of the code above is visible to the rest
   1177      // of the world.
   1178      "dsb ish \n\t"
   1179      // Barrier to ensure any prefetching which happened before this code is
   1180      // discarded.
   1181      // isb : Instruction Synchronisation Barrier
   1182      "isb \n\t"
   1183      : [dline] "+r" (dstart),
   1184        [iline] "+r" (istart)
   1185      : [dsize] "r" (dsize),
   1186        [isize] "r" (isize),
   1187        [end] "r" (end)
   1188      // This code does not write to memory but without the dependency gcc might
   1189      // move this code before the code is generated.
   1190      : "cc", "memory"
   1191    );
   1192 
   1193 #  elif defined(VGA_mips32) || defined(VGA_mips64)
   1194    SysRes sres = VG_(do_syscall3)(__NR_cacheflush, (UWord) ptr,
   1195                                  (UWord) nbytes, (UWord) 3);
   1196    vg_assert( !sr_isError(sres) );
   1197 
   1198 #  elif defined(VGA_tilegx)
   1199    const HChar *start, *end;
   1200 
   1201    /* L1 ICache is 32KB. cacheline size is 64 bytes. */
   1202    if (nbytes > 0x8000) nbytes = 0x8000;
   1203 
   1204    start = (const HChar *)((unsigned long)ptr & -64ULL);
   1205    end = (const HChar*)ptr + nbytes - 1;
   1206 
   1207    __insn_mf();
   1208 
   1209    do {
   1210      const HChar* p;
   1211      for (p = start; p <= end; p += 64)
   1212        __insn_icoh(p);
   1213    } while (0);
   1214 
   1215    __insn_drain();
   1216 
   1217 #  endif
   1218 }
   1219 
   1220 
   1221 /* ---------------------------------------------------------------------
   1222    dcache flushing
   1223    ------------------------------------------------------------------ */
   1224 
   1225 void VG_(flush_dcache) ( void *ptr, SizeT nbytes )
   1226 {
   1227    /* Currently this is only required on ARM64. */
   1228 #  if defined(VGA_arm64)
   1229    Addr startaddr = (Addr) ptr;
   1230    Addr endaddr   = startaddr + nbytes;
   1231    Addr cls;
   1232    Addr addr;
   1233 
   1234    ULong ctr_el0;
   1235    __asm__ __volatile__ ("mrs %0, ctr_el0" : "=r"(ctr_el0));
   1236    cls = 4 * (1ULL << (0xF & (ctr_el0 >> 16)));
   1237 
   1238    /* Stay sane .. */
   1239    vg_assert(cls == 64);
   1240 
   1241    startaddr &= ~(cls - 1);
   1242    for (addr = startaddr; addr < endaddr; addr += cls) {
   1243       __asm__ __volatile__("dc cvau, %0" : : "r" (addr));
   1244    }
   1245    __asm__ __volatile__("dsb ish");
   1246 #  endif
   1247 }
   1248 
   1249 /*--------------------------------------------------------------------*/
   1250 /*--- end                                                          ---*/
   1251 /*--------------------------------------------------------------------*/
   1252