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