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 (at) acm.org 12 13 This program is free software; you can redistribute it and/or 14 modify it under the terms of the GNU General Public License as 15 published by the Free Software Foundation; either version 2 of the 16 License, or (at your option) any later version. 17 18 This program is distributed in the hope that it will be useful, but 19 WITHOUT ANY WARRANTY; without even the implied warranty of 20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 General Public License for more details. 22 23 You should have received a copy of the GNU General Public License 24 along with this program; if not, write to the Free Software 25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 26 02111-1307, USA. 27 28 The GNU General Public License is contained in the file COPYING. 29 */ 30 31 #include "pub_core_basics.h" 32 #include "pub_core_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) 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. */ 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 95 void 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 */ 113 Char **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 */ 167 static 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. 224 void 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 279 Int 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 */ 295 Char **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 322 void 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! */ 341 Int 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. */ 394 Int 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. */ 408 Int 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. */ 417 Int 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 435 Int 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. */ 483 Int VG_(getpid) ( void ) 484 { 485 /* ASSUMES SYSCALL ALWAYS SUCCEEDS */ 486 return sr_Res( VG_(do_syscall0)(__NR_getpid) ); 487 } 488 489 Int VG_(getpgrp) ( void ) 490 { 491 /* ASSUMES SYSCALL ALWAYS SUCCEEDS */ 492 return sr_Res( VG_(do_syscall0)(__NR_getpgrp) ); 493 } 494 495 Int VG_(getppid) ( void ) 496 { 497 /* ASSUMES SYSCALL ALWAYS SUCCEEDS */ 498 return sr_Res( VG_(do_syscall0)(__NR_getppid) ); 499 } 500 501 Int 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 513 Int 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. */ 529 Int 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 564 Int 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 577 Int 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 606 UInt 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 655 struct 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 663 static struct atfork atforks[VG_MAX_ATFORK]; 664 static Int n_atfork = 0; 665 666 void 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 688 void 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 697 void 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 707 void print_preamble(Bool logging_to_fd, const char* toolname); 708 709 Char* VG_(clo_log_fname_unexpanded) = NULL; 710 Char* 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. 716 static 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 733 void 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