1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Process-related libc stuff.                     m_libcproc.c ---*/
4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This file is part of Valgrind, a dynamic binary instrumentation
8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   framework.
9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   Copyright (C) 2000-2012 Julian Seward
11ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      jseward@acm.org
12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This program is free software; you can redistribute it and/or
14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   modify it under the terms of the GNU General Public License as
15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   published by the Free Software Foundation; either version 2 of the
16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   License, or (at your option) any later version.
17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This program is distributed in the hope that it will be useful, but
19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   WITHOUT ANY WARRANTY; without even the implied warranty of
20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   General Public License for more details.
22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   You should have received a copy of the GNU General Public License
24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   along with this program; if not, write to the Free Software
25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   02111-1307, USA.
27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The GNU General Public License is contained in the file COPYING.
29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_basics.h"
32663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#include "pub_core_machine.h"    // For VG_(machine_get_VexArchInfo)
33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_vki.h"
34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_vkiscnums.h"
35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcbase.h"
36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcassert.h"
37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcprint.h"
38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcproc.h"
39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcsignal.h"
40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_seqmatch.h"
41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_mallocfree.h"
42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_syscall.h"
43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_xarray.h"
44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_clientstate.h"
45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(VGO_darwin)
47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --- !!! --- EXTERNAL HEADERS start --- !!! --- */
48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <mach/mach.h>   /* mach_thread_self */
49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --- !!! --- EXTERNAL HEADERS end --- !!! --- */
50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* IMPORTANT: on Darwin it is essential to use the _nocancel versions
53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   of syscalls rather than the vanilla version, if a _nocancel version
54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   is available.  See docs/internals/Darwin-notes.txt for the reason
55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   why. */
56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ---------------------------------------------------------------------
58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Command line and environment stuff
59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ------------------------------------------------------------------ */
60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* As deduced from sp_at_startup, the client's argc, argv[] and
62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   envp[] as extracted from the client's stack at startup-time. */
63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownChar** VG_(client_envp) = NULL;
64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Path to library directory */
66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownconst Char *VG_(libdir) = VG_LIBDIR;
67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownconst Char *VG_(LD_PRELOAD_var_name) =
69b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#if defined(VGO_linux)
70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   "LD_PRELOAD";
71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGO_darwin)
72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   "DYLD_INSERT_LIBRARIES";
73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#else
74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  error Unknown OS
75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* We do getenv without libc's help by snooping around in
78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(client_envp) as determined at startup time. */
79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownChar *VG_(getenv)(Char *varname)
80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int i, n;
82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert( VG_(client_envp) );
83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   n = VG_(strlen)(varname);
84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; VG_(client_envp)[i] != NULL; i++) {
85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Char* s = VG_(client_envp)[i];
86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (VG_(strncmp)(varname, s, n) == 0 && s[n] == '=') {
87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return & s[n+1];
88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return NULL;
91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid  VG_(env_unsetenv) ( Char **env, const Char *varname )
94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
95b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Char **from, **to;
96b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   vg_assert(env);
97b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   vg_assert(varname);
98b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   to = NULL;
99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int len = VG_(strlen)(varname);
100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (from = to = env; from && *from; from++) {
102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!(VG_(strncmp)(varname, *from, len) == 0 && (*from)[len] == '=')) {
103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 *to = *from;
104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 to++;
105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *to = *from;
108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* set the environment; returns the old env if a new one was allocated */
111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownChar **VG_(env_setenv) ( Char ***envp, const Char* varname, const Char *val )
112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Char **env = (*envp);
114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Char **cpp;
115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int len = VG_(strlen)(varname);
116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Char *valstr = VG_(arena_malloc)(VG_AR_CORE, "libcproc.es.1",
117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    len + VG_(strlen)(val) + 2);
118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Char **oldenv = NULL;
119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(sprintf)(valstr, "%s=%s", varname, val);
121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (cpp = env; cpp && *cpp; cpp++) {
123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (VG_(strncmp)(varname, *cpp, len) == 0 && (*cpp)[len] == '=') {
124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 *cpp = valstr;
125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 return oldenv;
126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (env == NULL) {
130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      env = VG_(arena_malloc)(VG_AR_CORE, "libcproc.es.2", sizeof(Char **) * 2);
131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      env[0] = valstr;
132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      env[1] = NULL;
133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *envp = env;
135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }  else {
137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int envlen = (cpp-env) + 2;
138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Char **newenv = VG_(arena_malloc)(VG_AR_CORE, "libcproc.es.3",
139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        envlen * sizeof(Char **));
140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (cpp = newenv; *env; )
142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 *cpp++ = *env++;
143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *cpp++ = valstr;
144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *cpp++ = NULL;
145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      oldenv = *envp;
147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *envp = newenv;
149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return oldenv;
152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Walk through a colon-separated environment variable, and remove the
156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   entries which match remove_pattern.  It slides everything down over
157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the removed entries, and pads the remaining space with '\0'.  It
158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   modifies the entries in place (in the client address space), but it
159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   shouldn't matter too much, since we only do this just before an
160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   execve().
161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This is also careful to mop up any excess ':'s, since empty strings
163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   delimited by ':' are considered to be '.' in a path.
164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void mash_colon_env(Char *varp, const Char *remove_pattern)
166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Char *const start = varp;
168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Char *entry_start = varp;
169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Char *output = varp;
170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (varp == NULL)
172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return;
173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while(*varp) {
175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (*varp == ':') {
176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 Char prev;
177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 Bool match;
178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 /* This is a bit subtle: we want to match against the entry
180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    we just copied, because it may have overlapped with
181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    itself, junking the original. */
182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 prev = *output;
184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 *output = '\0';
185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 match = VG_(string_match)(remove_pattern, entry_start);
187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 *output = prev;
189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 if (match) {
191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    output = entry_start;
192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    varp++;			/* skip ':' after removed entry */
193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 } else
194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    entry_start = output+1;	/* entry starts after ':' */
195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (*varp)
198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         *output++ = *varp++;
199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* make sure last entry is nul terminated */
202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *output = '\0';
203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* match against the last entry */
205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(string_match)(remove_pattern, entry_start)) {
206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      output = entry_start;
207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (output > start) {
208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 /* remove trailing ':' */
209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 output--;
210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 vg_assert(*output == ':');
211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* pad out the left-overs with '\0' */
215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while(output < varp)
216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *output++ = '\0';
217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Removes all the Valgrind-added stuff from the passed environment.  Used
221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// when starting child processes, so they don't see that added stuff.
222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(env_remove_valgrind_env_stuff)(Char** envp)
223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(VGO_darwin)
226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Environment cleanup is also handled during parent launch
228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // in vg_preloaded.c:vg_cleanup_env().
229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int i;
233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Char* ld_preload_str = NULL;
234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Char* ld_library_path_str = NULL;
235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Char* dyld_insert_libraries_str = NULL;
236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Char* buf;
237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Find LD_* variables
239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // DDD: should probably conditionally compiled some of this:
240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // - LD_LIBRARY_PATH is universal?
241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // - LD_PRELOAD is on Linux, not on Darwin, not sure about AIX
242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // - DYLD_INSERT_LIBRARIES and DYLD_SHARED_REGION are Darwin-only
243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; envp[i] != NULL; i++) {
244663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      if (VG_(strncmp)(envp[i], "LD_PRELOAD=", 11) == 0) {
245663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         envp[i] = VG_(arena_strdup)(VG_AR_CORE, "libcproc.erves.1", envp[i]);
246663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         ld_preload_str = &envp[i][11];
247663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      }
248663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      if (VG_(strncmp)(envp[i], "LD_LIBRARY_PATH=", 16) == 0) {
249663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         envp[i] = VG_(arena_strdup)(VG_AR_CORE, "libcproc.erves.2", envp[i]);
250663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         ld_library_path_str = &envp[i][16];
251663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      }
252663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      if (VG_(strncmp)(envp[i], "DYLD_INSERT_LIBRARIES=", 22) == 0) {
253663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         envp[i] = VG_(arena_strdup)(VG_AR_CORE, "libcproc.erves.3", envp[i]);
254663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         dyld_insert_libraries_str = &envp[i][22];
255663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      }
256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
258b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   buf = VG_(arena_malloc)(VG_AR_CORE, "libcproc.erves.4",
259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           VG_(strlen)(VG_(libdir)) + 20);
260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Remove Valgrind-specific entries from LD_*.
262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(sprintf)(buf, "%s*/vgpreload_*.so", VG_(libdir));
263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mash_colon_env(ld_preload_str, buf);
264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mash_colon_env(dyld_insert_libraries_str, buf);
265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(sprintf)(buf, "%s*", VG_(libdir));
266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mash_colon_env(ld_library_path_str, buf);
267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Remove VALGRIND_LAUNCHER variable.
269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(env_unsetenv)(envp, VALGRIND_LAUNCHER);
270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Remove DYLD_SHARED_REGION variable.
272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(env_unsetenv)(envp, "DYLD_SHARED_REGION");
273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // XXX if variable becomes empty, remove it completely?
275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(arena_free)(VG_AR_CORE, buf);
277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ---------------------------------------------------------------------
280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Various important syscall wrappers
281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ------------------------------------------------------------------ */
282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(waitpid)(Int pid, Int *status, Int options)
284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGO_linux)
286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res = VG_(do_syscall4)(__NR_wait4,
287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 pid, (UWord)status, options, 0);
288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGO_darwin)
290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res = VG_(do_syscall4)(__NR_wait4_nocancel,
291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 pid, (UWord)status, options, 0);
292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error Unknown OS
295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* clone the environment */
299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownChar **VG_(env_clone) ( Char **oldenv )
300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Char **oldenvp;
302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Char **newenvp;
303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Char **newenv;
304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int  envlen;
305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
306b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   vg_assert(oldenv);
307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (oldenvp = oldenv; oldenvp && *oldenvp; oldenvp++);
308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   envlen = oldenvp - oldenv + 1;
310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   newenv = VG_(arena_malloc)(VG_AR_CORE, "libcproc.ec.1",
312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              envlen * sizeof(Char **));
313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   oldenvp = oldenv;
315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   newenvp = newenv;
316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (oldenvp && *oldenvp) {
318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *newenvp++ = *oldenvp++;
319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *newenvp = *oldenvp;
322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return newenv;
324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(execv) ( Char* filename, Char** argv )
327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Char** envp;
329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* restore the DATA rlimit for the child */
332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(setrlimit)(VKI_RLIMIT_DATA, &VG_(client_rlimit_data));
333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   envp = VG_(env_clone)(VG_(client_envp));
335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(env_remove_valgrind_env_stuff)( envp );
336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall3)(__NR_execve,
338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          (UWord)filename, (UWord)argv, (UWord)envp);
339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)("EXEC failed, errno = %lld\n", (Long)sr_Err(res));
341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Return -1 if error, else 0.  NOTE does not indicate return code of
344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   child! */
345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(system) ( Char* cmd )
346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int pid;
348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (cmd == NULL)
349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return 1;
350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   pid = VG_(fork)();
351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (pid < 0)
352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return -1;
353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (pid == 0) {
354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* child */
355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Char* argv[4] = { "/bin/sh", "-c", cmd, 0 };
356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(execv)(argv[0], argv);
357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* If we're still alive here, execve failed. */
359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(exit)(1);
360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* parent */
362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* We have to set SIGCHLD to its default behaviour in order that
363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(waitpid) works (at least on AIX).  According to the Linux
364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         man page for waitpid:
365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         POSIX.1-2001 specifies that if the disposition of SIGCHLD is
367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         set to SIG_IGN or the SA_NOCLDWAIT flag is set for SIGCHLD
368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         (see sigaction(2)), then children that terminate do not
369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         become zombies and a call to wait() or waitpid() will block
370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         until all children have terminated, and then fail with errno
371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         set to ECHILD.  (The original POSIX standard left the
372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         behaviour of setting SIGCHLD to SIG_IGN unspecified.)
373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int ir, zzz;
375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vki_sigaction_toK_t sa, sa2;
376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vki_sigaction_fromK_t saved_sa;
377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(memset)( &sa, 0, sizeof(sa) );
378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(sigemptyset)(&sa.sa_mask);
379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sa.ksa_handler = VKI_SIG_DFL;
380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sa.sa_flags    = 0;
381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ir = VG_(sigaction)(VKI_SIGCHLD, &sa, &saved_sa);
382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(ir == 0);
383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      zzz = VG_(waitpid)(pid, NULL, 0);
385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(convert_sigaction_fromK_to_toK)( &saved_sa, &sa2 );
387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ir = VG_(sigaction)(VKI_SIGCHLD, &sa2, NULL);
388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(ir == 0);
389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return zzz == -1 ? -1 : 0;
390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ---------------------------------------------------------------------
394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Resource limits
395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ------------------------------------------------------------------ */
396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Support for getrlimit. */
398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(getrlimit) (Int resource, struct vki_rlimit *rlim)
399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res = VG_(mk_SysRes_Error)(VKI_ENOSYS);
401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* res = getrlimit( resource, rlim ); */
402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  ifdef __NR_ugetrlimit
403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall2)(__NR_ugetrlimit, resource, (UWord)rlim);
404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sr_isError(res) && sr_Err(res) == VKI_ENOSYS)
406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      res = VG_(do_syscall2)(__NR_getrlimit, resource, (UWord)rlim);
407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Support for setrlimit. */
412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(setrlimit) (Int resource, const struct vki_rlimit *rlim)
413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* res = setrlimit( resource, rlim ); */
416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall2)(__NR_setrlimit, resource, (UWord)rlim);
417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
420b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* Support for prctl. */
421b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy StepanovInt VG_(prctl) (Int option,
422b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                ULong arg2, ULong arg3, ULong arg4, ULong arg5)
423b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
424b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   SysRes res = VG_(mk_SysRes_Error)(VKI_ENOSYS);
425b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  if defined(VGO_linux)
426b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* res = prctl( option, arg2, arg3, arg4, arg5 ); */
427b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   res = VG_(do_syscall5)(__NR_prctl, (UWord) option,
428b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                          (UWord) arg2, (UWord) arg3, (UWord) arg4,
429b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                          (UWord) arg5);
430b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  endif
431b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
432b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   return sr_isError(res) ? -1 : sr_Res(res);
433b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
434b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ---------------------------------------------------------------------
436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   pids, etc
437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ------------------------------------------------------------------ */
438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(gettid)(void)
440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGO_linux)
442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res = VG_(do_syscall0)(__NR_gettid);
443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sr_isError(res) && sr_Res(res) == VKI_ENOSYS) {
445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Char pid[16];
446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /*
447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       * The gettid system call does not exist. The obvious assumption
448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       * to make at this point would be that we are running on an older
449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       * system where the getpid system call actually returns the ID of
450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       * the current thread.
451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       *
452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       * Unfortunately it seems that there are some systems with a kernel
453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       * where getpid has been changed to return the ID of the thread group
454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       * leader but where the gettid system call has not yet been added.
455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       *
456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       * So instead of calling getpid here we use readlink to see where
457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       * the /proc/self link is pointing...
458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       */
459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      res = VG_(do_syscall3)(__NR_readlink, (UWord)"/proc/self",
461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             (UWord)pid, sizeof(pid));
462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!sr_isError(res) && sr_Res(res) > 0) {
463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Char* s;
464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         pid[sr_Res(res)] = '\0';
465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         res = VG_(mk_SysRes_Success)(  VG_(strtoll10)(pid, &s) );
466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (*s != '\0') {
467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(message)(Vg_DebugMsg,
468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               "Warning: invalid file name linked to by /proc/self: %s\n",
469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               pid);
470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_Res(res);
475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGO_darwin)
477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Darwin's gettid syscall is something else.
478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Use Mach thread ports for lwpid instead.
479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return mach_thread_self();
480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "Unknown OS"
483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* You'd be amazed how many places need to know the current pid. */
487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(getpid) ( void )
488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ASSUMES SYSCALL ALWAYS SUCCEEDS */
490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_Res( VG_(do_syscall0)(__NR_getpid) );
491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(getpgrp) ( void )
494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ASSUMES SYSCALL ALWAYS SUCCEEDS */
496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_Res( VG_(do_syscall0)(__NR_getpgrp) );
497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(getppid) ( void )
500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ASSUMES SYSCALL ALWAYS SUCCEEDS */
502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_Res( VG_(do_syscall0)(__NR_getppid) );
503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(geteuid) ( void )
506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ASSUMES SYSCALL ALWAYS SUCCEEDS */
508b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  if defined(__NR_geteuid32)
509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // We use the 32-bit version if it's supported.  Otherwise, IDs greater
510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // than 65536 cause problems, as bug #151209 showed.
511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_Res( VG_(do_syscall0)(__NR_geteuid32) );
512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_Res( VG_(do_syscall0)(__NR_geteuid) );
514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(getegid) ( void )
518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ASSUMES SYSCALL ALWAYS SUCCEEDS */
520b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  if defined(__NR_getegid32)
521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // We use the 32-bit version if it's supported.  Otherwise, IDs greater
522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // than 65536 cause problems, as bug #151209 showed.
523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_Res( VG_(do_syscall0)(__NR_getegid32) );
524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_Res( VG_(do_syscall0)(__NR_getegid) );
526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Get supplementary groups into list[0 .. size-1].  Returns the
530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   number of groups written, or -1 if error.  Note that in order to be
531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   portable, the groups are 32-bit unsigned ints regardless of the
532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   platform. */
533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(getgroups)( Int size, UInt* list )
534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGP_x86_linux) || defined(VGP_ppc32_linux)
536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    i;
537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes sres;
538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UShort list16[64];
539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (size < 0) return -1;
540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (size > 64) size = 64;
541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sres = VG_(do_syscall2)(__NR_getgroups, size, (Addr)list16);
542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sr_isError(sres))
543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return -1;
544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sr_Res(sres) > size)
545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return -1;
546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < sr_Res(sres); i++)
547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      list[i] = (UInt)list16[i];
548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_Res(sres);
549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_amd64_linux) || defined(VGP_ppc64_linux)  \
551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        || defined(VGP_arm_linux)                             \
552663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng        || defined(VGO_darwin) || defined(VGP_s390x_linux)    \
553663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng        || defined(VGP_mips32_linux)
554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes sres;
555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sres = VG_(do_syscall2)(__NR_getgroups, size, (Addr)list);
556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sr_isError(sres))
557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return -1;
558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_Res(sres);
559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     error "VG_(getgroups): needs implementation on this platform"
562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ---------------------------------------------------------------------
566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Process tracing
567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ------------------------------------------------------------------ */
568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(ptrace) ( Int request, Int pid, void *addr, void *data )
570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall4)(__NR_ptrace, request, pid, (UWord)addr, (UWord)data);
573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sr_isError(res))
574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return -1;
575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_Res(res);
576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ---------------------------------------------------------------------
579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Fork
580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ------------------------------------------------------------------ */
581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(fork) ( void )
583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
584b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  if defined(VGO_linux)
585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall0)(__NR_fork);
587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sr_isError(res))
588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return -1;
589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_Res(res);
590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGO_darwin)
592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall0)(__NR_fork); /* __NR_fork is UX64 */
594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sr_isError(res))
595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return -1;
596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* on success: wLO = child pid; wHI = 1 for child, 0 for parent */
597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sr_ResHI(res) != 0) {
598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return 0;  /* this is child: return 0 instead of child pid */
599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_Res(res);
601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "Unknown OS"
604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ---------------------------------------------------------------------
608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Timing stuff
609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ------------------------------------------------------------------ */
610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt VG_(read_millisecond_timer) ( void )
612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 'now' and 'base' are in microseconds */
614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static ULong base = 0;
615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ULong  now;
616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGO_linux)
618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   { SysRes res;
619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     struct vki_timespec ts_now;
620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     res = VG_(do_syscall2)(__NR_clock_gettime, VKI_CLOCK_MONOTONIC,
621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            (UWord)&ts_now);
622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (sr_isError(res) == 0) {
623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        now = ts_now.tv_sec * 1000000ULL + ts_now.tv_nsec / 1000;
624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     } else {
625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       struct vki_timeval tv_now;
626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       res = VG_(do_syscall2)(__NR_gettimeofday, (UWord)&tv_now, (UWord)NULL);
627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       vg_assert(! sr_isError(res));
628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       now = tv_now.tv_sec * 1000000ULL + tv_now.tv_usec;
629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGO_darwin)
633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Weird: it seems that gettimeofday() doesn't fill in the timeval, but
634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // rather returns the tv_sec as the low 32 bits of the result and the
635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // tv_usec as the high 32 bits of the result.  (But the timeval cannot be
636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // NULL!)  See bug 200990.
637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   { SysRes res;
638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     struct vki_timeval tv_now = { 0, 0 };
639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     res = VG_(do_syscall2)(__NR_gettimeofday, (UWord)&tv_now, (UWord)NULL);
640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     vg_assert(! sr_isError(res));
641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     now = sr_Res(res) * 1000000ULL + sr_ResHI(res);
642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "Unknown OS"
646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* COMMON CODE */
649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (base == 0)
650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      base = now;
651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return (now - base) / 1000;
653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ---------------------------------------------------------------------
657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   atfork()
658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ------------------------------------------------------------------ */
659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstruct atfork {
661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_atfork_t  pre;
662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_atfork_t  parent;
663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_atfork_t  child;
664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown};
665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define VG_MAX_ATFORK 10
667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic struct atfork atforks[VG_MAX_ATFORK];
669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int n_atfork = 0;
670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(atfork)(vg_atfork_t pre, vg_atfork_t parent, vg_atfork_t child)
672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int i;
674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < n_atfork; i++) {
676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (atforks[i].pre == pre &&
677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          atforks[i].parent == parent &&
678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          atforks[i].child == child)
679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return;
680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (n_atfork >= VG_MAX_ATFORK)
683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(core_panic)(
684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         "Too many VG_(atfork) handlers requested: raise VG_MAX_ATFORK");
685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   atforks[n_atfork].pre    = pre;
687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   atforks[n_atfork].parent = parent;
688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   atforks[n_atfork].child  = child;
689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   n_atfork++;
691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(do_atfork_pre)(ThreadId tid)
694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int i;
696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < n_atfork; i++)
698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (atforks[i].pre != NULL)
699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         (*atforks[i].pre)(tid);
700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(do_atfork_parent)(ThreadId tid)
703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int i;
705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < n_atfork; i++)
707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (atforks[i].parent != NULL)
708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         (*atforks[i].parent)(tid);
709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
711663860b1408516d02ebfcb3a9999a134e6cfb223Ben Chengvoid VG_(do_atfork_child)(ThreadId tid)
712663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng{
713663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   Int i;
714f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov
715663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   for (i = 0; i < n_atfork; i++)
716663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      if (atforks[i].child != NULL)
717663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         (*atforks[i].child)(tid);
718663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng}
719f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov
720663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
721663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng/* ---------------------------------------------------------------------
722663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   icache invalidation
723663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   ------------------------------------------------------------------ */
724663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
725663860b1408516d02ebfcb3a9999a134e6cfb223Ben Chengvoid VG_(invalidate_icache) ( void *ptr, SizeT nbytes )
726f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov{
727663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#  if defined(VGA_ppc32) || defined(VGA_ppc64)
728663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   Addr startaddr = (Addr) ptr;
729663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   Addr endaddr   = startaddr + nbytes;
730663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   Addr cls;
731663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   Addr addr;
732663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VexArchInfo vai;
733f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov
734663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   if (nbytes == 0) return;
735663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vg_assert(nbytes > 0);
736f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov
737663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_(machine_get_VexArchInfo)( NULL, &vai );
738663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   cls = vai.ppc_cache_line_szB;
739663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
740663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   /* Stay sane .. */
741663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vg_assert(cls == 32 || cls == 64 || cls == 128);
742663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
743663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   startaddr &= ~(cls - 1);
744663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   for (addr = startaddr; addr < endaddr; addr += cls) {
745663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      __asm__ __volatile__("dcbst 0,%0" : : "r" (addr));
746f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov   }
747663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   __asm__ __volatile__("sync");
748663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   for (addr = startaddr; addr < endaddr; addr += cls) {
749663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      __asm__ __volatile__("icbi 0,%0" : : "r" (addr));
750663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   }
751663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   __asm__ __volatile__("sync; isync");
752f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov
753663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#  elif defined(VGA_x86)
754663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   /* no need to do anything, hardware provides coherence */
755f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov
756663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#  elif defined(VGA_amd64)
757663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   /* no need to do anything, hardware provides coherence */
758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
759663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#  elif defined(VGA_s390x)
760663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   /* no need to do anything, hardware provides coherence */
761f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov
762663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#  elif defined(VGP_arm_linux)
763663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   /* ARM cache flushes are privileged, so we must defer to the kernel. */
764663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   Addr startaddr = (Addr) ptr;
765663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   Addr endaddr   = startaddr + nbytes;
766663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_(do_syscall2)(__NR_ARM_cacheflush, startaddr, endaddr);
767663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
768663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#  elif defined(VGA_mips32)
769663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   SysRes sres = VG_(do_syscall3)(__NR_cacheflush, (UWord) ptr,
770663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                                 (UWord) nbytes, (UWord) 3);
771663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vg_assert( sres._isError == 0 );
772663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
773663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#  else
774663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#    error "Unknown ARCH"
775663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#  endif
776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- end                                                          ---*/
781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
782