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. */
65 Char** VG_(client_envp) = NULL;
66
67 /* Path to library directory */
68 const Char *VG_(libdir) = VG_LIBDIR;
69
70 const 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. */
VG_(getenv)81 Char *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
VG_(env_unsetenv)95 void 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 */
VG_(env_setenv)111 Char **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 */
mash_colon_env(Char * varp,const Char * remove_pattern)165 static 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.
VG_(env_remove_valgrind_env_stuff)222 void 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
VG_(waitpid)277 Int 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 */
VG_(env_clone)301 Char **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
VG_(execv)327 void 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! */
VG_(system)346 Int 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. */
VG_(getrlimit)399 Int 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. */
VG_(setrlimit)413 Int 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
VG_(gettid)425 Int 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. */
VG_(getpid)481 Int VG_(getpid) ( void )
482 {
483 /* ASSUMES SYSCALL ALWAYS SUCCEEDS */
484 return sr_Res( VG_(do_syscall0)(__NR_getpid) );
485 }
486
VG_(getpgrp)487 Int VG_(getpgrp) ( void )
488 {
489 /* ASSUMES SYSCALL ALWAYS SUCCEEDS */
490 return sr_Res( VG_(do_syscall0)(__NR_getpgrp) );
491 }
492
VG_(getppid)493 Int VG_(getppid) ( void )
494 {
495 /* ASSUMES SYSCALL ALWAYS SUCCEEDS */
496 return sr_Res( VG_(do_syscall0)(__NR_getppid) );
497 }
498
VG_(geteuid)499 Int 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
VG_(getegid)513 Int 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. */
VG_(getgroups)531 Int 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
VG_(ptrace)567 Int 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
VG_(fork)580 Int 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
VG_(read_millisecond_timer)609 UInt 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
677 struct 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
685 static struct atfork atforks[VG_MAX_ATFORK];
686 static Int n_atfork = 0;
687
VG_(atfork)688 void 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
VG_(do_atfork_pre)710 void 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
VG_(do_atfork_parent)719 void 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
729 void print_preamble(Bool logging_to_fd, const char* toolname);
730
731 Char* VG_(clo_log_fname_unexpanded) = NULL;
732 Char* 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.
open_new_logfile_for_forked_child(void)738 static 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
VG_(do_atfork_child)755 void 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