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