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-2012 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_machine.h" // For VG_(machine_get_VexArchInfo) 33 #include "pub_core_vki.h" 34 #include "pub_core_vkiscnums.h" 35 #include "pub_core_libcbase.h" 36 #include "pub_core_libcassert.h" 37 #include "pub_core_libcprint.h" 38 #include "pub_core_libcproc.h" 39 #include "pub_core_libcsignal.h" 40 #include "pub_core_seqmatch.h" 41 #include "pub_core_mallocfree.h" 42 #include "pub_core_syscall.h" 43 #include "pub_core_xarray.h" 44 #include "pub_core_clientstate.h" 45 46 #if defined(VGO_darwin) 47 /* --- !!! --- EXTERNAL HEADERS start --- !!! --- */ 48 #include <mach/mach.h> /* mach_thread_self */ 49 /* --- !!! --- EXTERNAL HEADERS end --- !!! --- */ 50 #endif 51 52 /* IMPORTANT: on Darwin it is essential to use the _nocancel versions 53 of syscalls rather than the vanilla version, if a _nocancel version 54 is available. See docs/internals/Darwin-notes.txt for the reason 55 why. */ 56 57 /* --------------------------------------------------------------------- 58 Command line and environment stuff 59 ------------------------------------------------------------------ */ 60 61 /* As deduced from sp_at_startup, the client's argc, argv[] and 62 envp[] as extracted from the client's stack at startup-time. */ 63 Char** VG_(client_envp) = NULL; 64 65 /* Path to library directory */ 66 const Char *VG_(libdir) = VG_LIBDIR; 67 68 const Char *VG_(LD_PRELOAD_var_name) = 69 #if defined(VGO_linux) 70 "LD_PRELOAD"; 71 #elif defined(VGO_darwin) 72 "DYLD_INSERT_LIBRARIES"; 73 #else 74 # error Unknown OS 75 #endif 76 77 /* We do getenv without libc's help by snooping around in 78 VG_(client_envp) as determined at startup time. */ 79 Char *VG_(getenv)(Char *varname) 80 { 81 Int i, n; 82 vg_assert( VG_(client_envp) ); 83 n = VG_(strlen)(varname); 84 for (i = 0; VG_(client_envp)[i] != NULL; i++) { 85 Char* s = VG_(client_envp)[i]; 86 if (VG_(strncmp)(varname, s, n) == 0 && s[n] == '=') { 87 return & s[n+1]; 88 } 89 } 90 return NULL; 91 } 92 93 void VG_(env_unsetenv) ( Char **env, const Char *varname ) 94 { 95 Char **from, **to; 96 vg_assert(env); 97 vg_assert(varname); 98 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 */ 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 */ 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. 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 envp[i] = VG_(arena_strdup)(VG_AR_CORE, "libcproc.erves.1", envp[i]); 246 ld_preload_str = &envp[i][11]; 247 } 248 if (VG_(strncmp)(envp[i], "LD_LIBRARY_PATH=", 16) == 0) { 249 envp[i] = VG_(arena_strdup)(VG_AR_CORE, "libcproc.erves.2", envp[i]); 250 ld_library_path_str = &envp[i][16]; 251 } 252 if (VG_(strncmp)(envp[i], "DYLD_INSERT_LIBRARIES=", 22) == 0) { 253 envp[i] = VG_(arena_strdup)(VG_AR_CORE, "libcproc.erves.3", envp[i]); 254 dyld_insert_libraries_str = &envp[i][22]; 255 } 256 } 257 258 buf = VG_(arena_malloc)(VG_AR_CORE, "libcproc.erves.4", 259 VG_(strlen)(VG_(libdir)) + 20); 260 261 // Remove Valgrind-specific entries from LD_*. 262 VG_(sprintf)(buf, "%s*/vgpreload_*.so", VG_(libdir)); 263 mash_colon_env(ld_preload_str, buf); 264 mash_colon_env(dyld_insert_libraries_str, buf); 265 VG_(sprintf)(buf, "%s*", VG_(libdir)); 266 mash_colon_env(ld_library_path_str, buf); 267 268 // Remove VALGRIND_LAUNCHER variable. 269 VG_(env_unsetenv)(envp, VALGRIND_LAUNCHER); 270 271 // Remove DYLD_SHARED_REGION variable. 272 VG_(env_unsetenv)(envp, "DYLD_SHARED_REGION"); 273 274 // XXX if variable becomes empty, remove it completely? 275 276 VG_(arena_free)(VG_AR_CORE, buf); 277 } 278 279 /* --------------------------------------------------------------------- 280 Various important syscall wrappers 281 ------------------------------------------------------------------ */ 282 283 Int VG_(waitpid)(Int pid, Int *status, Int options) 284 { 285 # if defined(VGO_linux) 286 SysRes res = VG_(do_syscall4)(__NR_wait4, 287 pid, (UWord)status, options, 0); 288 return sr_isError(res) ? -1 : sr_Res(res); 289 # elif defined(VGO_darwin) 290 SysRes res = VG_(do_syscall4)(__NR_wait4_nocancel, 291 pid, (UWord)status, options, 0); 292 return sr_isError(res) ? -1 : sr_Res(res); 293 # else 294 # error Unknown OS 295 # endif 296 } 297 298 /* clone the environment */ 299 Char **VG_(env_clone) ( Char **oldenv ) 300 { 301 Char **oldenvp; 302 Char **newenvp; 303 Char **newenv; 304 Int envlen; 305 306 vg_assert(oldenv); 307 for (oldenvp = oldenv; oldenvp && *oldenvp; oldenvp++); 308 309 envlen = oldenvp - oldenv + 1; 310 311 newenv = VG_(arena_malloc)(VG_AR_CORE, "libcproc.ec.1", 312 envlen * sizeof(Char **)); 313 314 oldenvp = oldenv; 315 newenvp = newenv; 316 317 while (oldenvp && *oldenvp) { 318 *newenvp++ = *oldenvp++; 319 } 320 321 *newenvp = *oldenvp; 322 323 return newenv; 324 } 325 326 void VG_(execv) ( Char* filename, Char** argv ) 327 { 328 Char** envp; 329 SysRes res; 330 331 /* restore the DATA rlimit for the child */ 332 VG_(setrlimit)(VKI_RLIMIT_DATA, &VG_(client_rlimit_data)); 333 334 envp = VG_(env_clone)(VG_(client_envp)); 335 VG_(env_remove_valgrind_env_stuff)( envp ); 336 337 res = VG_(do_syscall3)(__NR_execve, 338 (UWord)filename, (UWord)argv, (UWord)envp); 339 340 VG_(printf)("EXEC failed, errno = %lld\n", (Long)sr_Err(res)); 341 } 342 343 /* Return -1 if error, else 0. NOTE does not indicate return code of 344 child! */ 345 Int VG_(system) ( Char* cmd ) 346 { 347 Int pid; 348 if (cmd == NULL) 349 return 1; 350 pid = VG_(fork)(); 351 if (pid < 0) 352 return -1; 353 if (pid == 0) { 354 /* child */ 355 Char* argv[4] = { "/bin/sh", "-c", cmd, 0 }; 356 VG_(execv)(argv[0], argv); 357 358 /* If we're still alive here, execve failed. */ 359 VG_(exit)(1); 360 } else { 361 /* parent */ 362 /* We have to set SIGCHLD to its default behaviour in order that 363 VG_(waitpid) works (at least on AIX). According to the Linux 364 man page for waitpid: 365 366 POSIX.1-2001 specifies that if the disposition of SIGCHLD is 367 set to SIG_IGN or the SA_NOCLDWAIT flag is set for SIGCHLD 368 (see sigaction(2)), then children that terminate do not 369 become zombies and a call to wait() or waitpid() will block 370 until all children have terminated, and then fail with errno 371 set to ECHILD. (The original POSIX standard left the 372 behaviour of setting SIGCHLD to SIG_IGN unspecified.) 373 */ 374 Int ir, zzz; 375 vki_sigaction_toK_t sa, sa2; 376 vki_sigaction_fromK_t saved_sa; 377 VG_(memset)( &sa, 0, sizeof(sa) ); 378 VG_(sigemptyset)(&sa.sa_mask); 379 sa.ksa_handler = VKI_SIG_DFL; 380 sa.sa_flags = 0; 381 ir = VG_(sigaction)(VKI_SIGCHLD, &sa, &saved_sa); 382 vg_assert(ir == 0); 383 384 zzz = VG_(waitpid)(pid, NULL, 0); 385 386 VG_(convert_sigaction_fromK_to_toK)( &saved_sa, &sa2 ); 387 ir = VG_(sigaction)(VKI_SIGCHLD, &sa2, NULL); 388 vg_assert(ir == 0); 389 return zzz == -1 ? -1 : 0; 390 } 391 } 392 393 /* --------------------------------------------------------------------- 394 Resource limits 395 ------------------------------------------------------------------ */ 396 397 /* Support for getrlimit. */ 398 Int VG_(getrlimit) (Int resource, struct vki_rlimit *rlim) 399 { 400 SysRes res = VG_(mk_SysRes_Error)(VKI_ENOSYS); 401 /* res = getrlimit( resource, rlim ); */ 402 # ifdef __NR_ugetrlimit 403 res = VG_(do_syscall2)(__NR_ugetrlimit, resource, (UWord)rlim); 404 # endif 405 if (sr_isError(res) && sr_Err(res) == VKI_ENOSYS) 406 res = VG_(do_syscall2)(__NR_getrlimit, resource, (UWord)rlim); 407 return sr_isError(res) ? -1 : sr_Res(res); 408 } 409 410 411 /* Support for setrlimit. */ 412 Int VG_(setrlimit) (Int resource, const struct vki_rlimit *rlim) 413 { 414 SysRes res; 415 /* res = setrlimit( resource, rlim ); */ 416 res = VG_(do_syscall2)(__NR_setrlimit, resource, (UWord)rlim); 417 return sr_isError(res) ? -1 : sr_Res(res); 418 } 419 420 /* Support for prctl. */ 421 Int VG_(prctl) (Int option, 422 ULong arg2, ULong arg3, ULong arg4, ULong arg5) 423 { 424 SysRes res = VG_(mk_SysRes_Error)(VKI_ENOSYS); 425 # if defined(VGO_linux) 426 /* res = prctl( option, arg2, arg3, arg4, arg5 ); */ 427 res = VG_(do_syscall5)(__NR_prctl, (UWord) option, 428 (UWord) arg2, (UWord) arg3, (UWord) arg4, 429 (UWord) arg5); 430 # endif 431 432 return sr_isError(res) ? -1 : sr_Res(res); 433 } 434 435 /* --------------------------------------------------------------------- 436 pids, etc 437 ------------------------------------------------------------------ */ 438 439 Int VG_(gettid)(void) 440 { 441 # if defined(VGO_linux) 442 SysRes res = VG_(do_syscall0)(__NR_gettid); 443 444 if (sr_isError(res) && sr_Res(res) == VKI_ENOSYS) { 445 Char pid[16]; 446 /* 447 * The gettid system call does not exist. The obvious assumption 448 * to make at this point would be that we are running on an older 449 * system where the getpid system call actually returns the ID of 450 * the current thread. 451 * 452 * Unfortunately it seems that there are some systems with a kernel 453 * where getpid has been changed to return the ID of the thread group 454 * leader but where the gettid system call has not yet been added. 455 * 456 * So instead of calling getpid here we use readlink to see where 457 * the /proc/self link is pointing... 458 */ 459 460 res = VG_(do_syscall3)(__NR_readlink, (UWord)"/proc/self", 461 (UWord)pid, sizeof(pid)); 462 if (!sr_isError(res) && sr_Res(res) > 0) { 463 Char* s; 464 pid[sr_Res(res)] = '\0'; 465 res = VG_(mk_SysRes_Success)( VG_(strtoll10)(pid, &s) ); 466 if (*s != '\0') { 467 VG_(message)(Vg_DebugMsg, 468 "Warning: invalid file name linked to by /proc/self: %s\n", 469 pid); 470 } 471 } 472 } 473 474 return sr_Res(res); 475 476 # elif defined(VGO_darwin) 477 // Darwin's gettid syscall is something else. 478 // Use Mach thread ports for lwpid instead. 479 return mach_thread_self(); 480 481 # else 482 # error "Unknown OS" 483 # endif 484 } 485 486 /* You'd be amazed how many places need to know the current pid. */ 487 Int VG_(getpid) ( void ) 488 { 489 /* ASSUMES SYSCALL ALWAYS SUCCEEDS */ 490 return sr_Res( VG_(do_syscall0)(__NR_getpid) ); 491 } 492 493 Int VG_(getpgrp) ( void ) 494 { 495 /* ASSUMES SYSCALL ALWAYS SUCCEEDS */ 496 return sr_Res( VG_(do_syscall0)(__NR_getpgrp) ); 497 } 498 499 Int VG_(getppid) ( void ) 500 { 501 /* ASSUMES SYSCALL ALWAYS SUCCEEDS */ 502 return sr_Res( VG_(do_syscall0)(__NR_getppid) ); 503 } 504 505 Int VG_(geteuid) ( void ) 506 { 507 /* ASSUMES SYSCALL ALWAYS SUCCEEDS */ 508 # if defined(__NR_geteuid32) 509 // We use the 32-bit version if it's supported. Otherwise, IDs greater 510 // than 65536 cause problems, as bug #151209 showed. 511 return sr_Res( VG_(do_syscall0)(__NR_geteuid32) ); 512 # else 513 return sr_Res( VG_(do_syscall0)(__NR_geteuid) ); 514 # endif 515 } 516 517 Int VG_(getegid) ( void ) 518 { 519 /* ASSUMES SYSCALL ALWAYS SUCCEEDS */ 520 # if defined(__NR_getegid32) 521 // We use the 32-bit version if it's supported. Otherwise, IDs greater 522 // than 65536 cause problems, as bug #151209 showed. 523 return sr_Res( VG_(do_syscall0)(__NR_getegid32) ); 524 # else 525 return sr_Res( VG_(do_syscall0)(__NR_getegid) ); 526 # endif 527 } 528 529 /* Get supplementary groups into list[0 .. size-1]. Returns the 530 number of groups written, or -1 if error. Note that in order to be 531 portable, the groups are 32-bit unsigned ints regardless of the 532 platform. */ 533 Int VG_(getgroups)( Int size, UInt* list ) 534 { 535 # if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) 536 Int i; 537 SysRes sres; 538 UShort list16[64]; 539 if (size < 0) return -1; 540 if (size > 64) size = 64; 541 sres = VG_(do_syscall2)(__NR_getgroups, size, (Addr)list16); 542 if (sr_isError(sres)) 543 return -1; 544 if (sr_Res(sres) > size) 545 return -1; 546 for (i = 0; i < sr_Res(sres); i++) 547 list[i] = (UInt)list16[i]; 548 return sr_Res(sres); 549 550 # elif defined(VGP_amd64_linux) || defined(VGP_ppc64_linux) \ 551 || defined(VGP_arm_linux) \ 552 || defined(VGO_darwin) || defined(VGP_s390x_linux) \ 553 || defined(VGP_mips32_linux) 554 SysRes sres; 555 sres = VG_(do_syscall2)(__NR_getgroups, size, (Addr)list); 556 if (sr_isError(sres)) 557 return -1; 558 return sr_Res(sres); 559 560 # else 561 # error "VG_(getgroups): needs implementation on this platform" 562 # endif 563 } 564 565 /* --------------------------------------------------------------------- 566 Process tracing 567 ------------------------------------------------------------------ */ 568 569 Int VG_(ptrace) ( Int request, Int pid, void *addr, void *data ) 570 { 571 SysRes res; 572 res = VG_(do_syscall4)(__NR_ptrace, request, pid, (UWord)addr, (UWord)data); 573 if (sr_isError(res)) 574 return -1; 575 return sr_Res(res); 576 } 577 578 /* --------------------------------------------------------------------- 579 Fork 580 ------------------------------------------------------------------ */ 581 582 Int VG_(fork) ( void ) 583 { 584 # if defined(VGO_linux) 585 SysRes res; 586 res = VG_(do_syscall0)(__NR_fork); 587 if (sr_isError(res)) 588 return -1; 589 return sr_Res(res); 590 591 # elif defined(VGO_darwin) 592 SysRes res; 593 res = VG_(do_syscall0)(__NR_fork); /* __NR_fork is UX64 */ 594 if (sr_isError(res)) 595 return -1; 596 /* on success: wLO = child pid; wHI = 1 for child, 0 for parent */ 597 if (sr_ResHI(res) != 0) { 598 return 0; /* this is child: return 0 instead of child pid */ 599 } 600 return sr_Res(res); 601 602 # else 603 # error "Unknown OS" 604 # endif 605 } 606 607 /* --------------------------------------------------------------------- 608 Timing stuff 609 ------------------------------------------------------------------ */ 610 611 UInt VG_(read_millisecond_timer) ( void ) 612 { 613 /* 'now' and 'base' are in microseconds */ 614 static ULong base = 0; 615 ULong now; 616 617 # if defined(VGO_linux) 618 { SysRes res; 619 struct vki_timespec ts_now; 620 res = VG_(do_syscall2)(__NR_clock_gettime, VKI_CLOCK_MONOTONIC, 621 (UWord)&ts_now); 622 if (sr_isError(res) == 0) { 623 now = ts_now.tv_sec * 1000000ULL + ts_now.tv_nsec / 1000; 624 } else { 625 struct vki_timeval tv_now; 626 res = VG_(do_syscall2)(__NR_gettimeofday, (UWord)&tv_now, (UWord)NULL); 627 vg_assert(! sr_isError(res)); 628 now = tv_now.tv_sec * 1000000ULL + tv_now.tv_usec; 629 } 630 } 631 632 # elif defined(VGO_darwin) 633 // Weird: it seems that gettimeofday() doesn't fill in the timeval, but 634 // rather returns the tv_sec as the low 32 bits of the result and the 635 // tv_usec as the high 32 bits of the result. (But the timeval cannot be 636 // NULL!) See bug 200990. 637 { SysRes res; 638 struct vki_timeval tv_now = { 0, 0 }; 639 res = VG_(do_syscall2)(__NR_gettimeofday, (UWord)&tv_now, (UWord)NULL); 640 vg_assert(! sr_isError(res)); 641 now = sr_Res(res) * 1000000ULL + sr_ResHI(res); 642 } 643 644 # else 645 # error "Unknown OS" 646 # endif 647 648 /* COMMON CODE */ 649 if (base == 0) 650 base = now; 651 652 return (now - base) / 1000; 653 } 654 655 656 /* --------------------------------------------------------------------- 657 atfork() 658 ------------------------------------------------------------------ */ 659 660 struct atfork { 661 vg_atfork_t pre; 662 vg_atfork_t parent; 663 vg_atfork_t child; 664 }; 665 666 #define VG_MAX_ATFORK 10 667 668 static struct atfork atforks[VG_MAX_ATFORK]; 669 static Int n_atfork = 0; 670 671 void VG_(atfork)(vg_atfork_t pre, vg_atfork_t parent, vg_atfork_t child) 672 { 673 Int i; 674 675 for (i = 0; i < n_atfork; i++) { 676 if (atforks[i].pre == pre && 677 atforks[i].parent == parent && 678 atforks[i].child == child) 679 return; 680 } 681 682 if (n_atfork >= VG_MAX_ATFORK) 683 VG_(core_panic)( 684 "Too many VG_(atfork) handlers requested: raise VG_MAX_ATFORK"); 685 686 atforks[n_atfork].pre = pre; 687 atforks[n_atfork].parent = parent; 688 atforks[n_atfork].child = child; 689 690 n_atfork++; 691 } 692 693 void VG_(do_atfork_pre)(ThreadId tid) 694 { 695 Int i; 696 697 for (i = 0; i < n_atfork; i++) 698 if (atforks[i].pre != NULL) 699 (*atforks[i].pre)(tid); 700 } 701 702 void VG_(do_atfork_parent)(ThreadId tid) 703 { 704 Int i; 705 706 for (i = 0; i < n_atfork; i++) 707 if (atforks[i].parent != NULL) 708 (*atforks[i].parent)(tid); 709 } 710 711 void VG_(do_atfork_child)(ThreadId tid) 712 { 713 Int i; 714 715 for (i = 0; i < n_atfork; i++) 716 if (atforks[i].child != NULL) 717 (*atforks[i].child)(tid); 718 } 719 720 721 /* --------------------------------------------------------------------- 722 icache invalidation 723 ------------------------------------------------------------------ */ 724 725 void VG_(invalidate_icache) ( void *ptr, SizeT nbytes ) 726 { 727 # if defined(VGA_ppc32) || defined(VGA_ppc64) 728 Addr startaddr = (Addr) ptr; 729 Addr endaddr = startaddr + nbytes; 730 Addr cls; 731 Addr addr; 732 VexArchInfo vai; 733 734 if (nbytes == 0) return; 735 vg_assert(nbytes > 0); 736 737 VG_(machine_get_VexArchInfo)( NULL, &vai ); 738 cls = vai.ppc_cache_line_szB; 739 740 /* Stay sane .. */ 741 vg_assert(cls == 32 || cls == 64 || cls == 128); 742 743 startaddr &= ~(cls - 1); 744 for (addr = startaddr; addr < endaddr; addr += cls) { 745 __asm__ __volatile__("dcbst 0,%0" : : "r" (addr)); 746 } 747 __asm__ __volatile__("sync"); 748 for (addr = startaddr; addr < endaddr; addr += cls) { 749 __asm__ __volatile__("icbi 0,%0" : : "r" (addr)); 750 } 751 __asm__ __volatile__("sync; isync"); 752 753 # elif defined(VGA_x86) 754 /* no need to do anything, hardware provides coherence */ 755 756 # elif defined(VGA_amd64) 757 /* no need to do anything, hardware provides coherence */ 758 759 # elif defined(VGA_s390x) 760 /* no need to do anything, hardware provides coherence */ 761 762 # elif defined(VGP_arm_linux) 763 /* ARM cache flushes are privileged, so we must defer to the kernel. */ 764 Addr startaddr = (Addr) ptr; 765 Addr endaddr = startaddr + nbytes; 766 VG_(do_syscall2)(__NR_ARM_cacheflush, startaddr, endaddr); 767 768 # elif defined(VGA_mips32) 769 SysRes sres = VG_(do_syscall3)(__NR_cacheflush, (UWord) ptr, 770 (UWord) nbytes, (UWord) 3); 771 vg_assert( sres._isError == 0 ); 772 773 # else 774 # error "Unknown ARCH" 775 # endif 776 } 777 778 779 /*--------------------------------------------------------------------*/ 780 /*--- end ---*/ 781 /*--------------------------------------------------------------------*/ 782