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@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. */
VG_(getenv)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
VG_(env_unsetenv)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 */
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 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
VG_(waitpid)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 */
VG_(env_clone)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
VG_(execv)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! */
VG_(system)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. */
VG_(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. */
VG_(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. */
VG_(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
VG_(gettid)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. */
VG_(getpid)487 Int VG_(getpid) ( void )
488 {
489 /* ASSUMES SYSCALL ALWAYS SUCCEEDS */
490 return sr_Res( VG_(do_syscall0)(__NR_getpid) );
491 }
492
VG_(getpgrp)493 Int VG_(getpgrp) ( void )
494 {
495 /* ASSUMES SYSCALL ALWAYS SUCCEEDS */
496 return sr_Res( VG_(do_syscall0)(__NR_getpgrp) );
497 }
498
VG_(getppid)499 Int VG_(getppid) ( void )
500 {
501 /* ASSUMES SYSCALL ALWAYS SUCCEEDS */
502 return sr_Res( VG_(do_syscall0)(__NR_getppid) );
503 }
504
VG_(geteuid)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
VG_(getegid)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. */
VG_(getgroups)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
VG_(ptrace)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
VG_(fork)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
VG_(read_millisecond_timer)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
VG_(atfork)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
VG_(do_atfork_pre)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
VG_(do_atfork_parent)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
VG_(do_atfork_child)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
VG_(invalidate_icache)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