blob: 5c551fdd566ad3227f49281d4a5a86b21d2c6647 [file] [log] [blame]
sewardjde4a1d02002-03-22 01:27:54 +00001
2/*--------------------------------------------------------------------*/
njnf39e9a32005-06-12 02:43:17 +00003/*--- Process-related libc stuff. m_libcproc.c ---*/
sewardjde4a1d02002-03-22 01:27:54 +00004/*--------------------------------------------------------------------*/
njned6b8242005-06-01 00:03:17 +00005
sewardjde4a1d02002-03-22 01:27:54 +00006/*
njnb9c427c2004-12-01 14:14:42 +00007 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
sewardjde4a1d02002-03-22 01:27:54 +00009
njn53612422005-03-12 16:22:54 +000010 Copyright (C) 2000-2005 Julian Seward
sewardjde4a1d02002-03-22 01:27:54 +000011 jseward@acm.org
sewardjde4a1d02002-03-22 01:27:54 +000012
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
njn25e49d8e72002-09-23 09:36:25 +000028 The GNU General Public License is contained in the file COPYING.
sewardjde4a1d02002-03-22 01:27:54 +000029*/
30
nethercotef1e5e152004-09-01 23:58:16 +000031#include "core.h"
njn97405b22005-06-02 03:39:33 +000032#include "pub_core_libcbase.h"
njn132bfcc2005-06-04 19:16:06 +000033#include "pub_core_libcassert.h"
njn36a20fa2005-06-03 03:08:39 +000034#include "pub_core_libcprint.h"
njnf39e9a32005-06-12 02:43:17 +000035#include "pub_core_libcproc.h"
njnaf1d7df2005-06-11 01:31:52 +000036#include "pub_core_mallocfree.h"
njn3c660b62005-05-13 22:18:47 +000037#include "vki_unistd.h"
sewardj1cf558c2005-04-25 01:36:56 +000038
njnf39e9a32005-06-12 02:43:17 +000039/* ---------------------------------------------------------------------
40 Command line and environment stuff
41 ------------------------------------------------------------------ */
sewardjde4a1d02002-03-22 01:27:54 +000042
njnf39e9a32005-06-12 02:43:17 +000043/* As deduced from sp_at_startup, the client's argc, argv[] and
44 envp[] as extracted from the client's stack at startup-time. */
45Int VG_(client_argc);
46Char** VG_(client_argv);
47Char** VG_(client_envp);
48
njn8d9965c2005-06-12 17:47:24 +000049/* Path to library directory */
50const Char *VG_(libdir) = VG_LIBDIR;
51
njnf39e9a32005-06-12 02:43:17 +000052/* We do getenv without libc's help by snooping around in
53 VG_(client_envp) as determined at startup time. */
54Char *VG_(getenv)(Char *varname)
jsgf855d93d2003-10-13 22:26:55 +000055{
njnf39e9a32005-06-12 02:43:17 +000056 Int i, n;
57 n = VG_(strlen)(varname);
58 for (i = 0; VG_(client_envp)[i] != NULL; i++) {
59 Char* s = VG_(client_envp)[i];
60 if (VG_(strncmp)(varname, s, n) == 0 && s[n] == '=') {
61 return & s[n+1];
thughes8ef6d962004-10-16 10:46:01 +000062 }
63 }
njnf39e9a32005-06-12 02:43:17 +000064 return NULL;
nethercoteff9721d2004-01-26 17:10:01 +000065}
66
fitzhardinge98abfc72003-12-16 02:05:15 +000067void VG_(env_unsetenv) ( Char **env, const Char *varname )
68{
69 Char **from;
70 Char **to = NULL;
71 Int len = VG_(strlen)(varname);
72
73 for(from = to = env; from && *from; from++) {
74 if (!(VG_(strncmp)(varname, *from, len) == 0 && (*from)[len] == '=')) {
75 *to = *from;
76 to++;
77 }
78 }
79 *to = *from;
80}
81
82/* set the environment; returns the old env if a new one was allocated */
83Char **VG_(env_setenv) ( Char ***envp, const Char* varname, const Char *val )
84{
85 Char **env = (*envp);
86 Char **cpp;
87 Int len = VG_(strlen)(varname);
88 Char *valstr = VG_(arena_malloc)(VG_AR_CORE, len + VG_(strlen)(val) + 2);
89 Char **oldenv = NULL;
90
91 VG_(sprintf)(valstr, "%s=%s", varname, val);
92
93 for(cpp = env; cpp && *cpp; cpp++) {
94 if (VG_(strncmp)(varname, *cpp, len) == 0 && (*cpp)[len] == '=') {
95 *cpp = valstr;
96 return oldenv;
97 }
98 }
99
100 if (env == NULL) {
101 env = VG_(arena_malloc)(VG_AR_CORE, sizeof(Char **) * 2);
102 env[0] = valstr;
103 env[1] = NULL;
104
105 *envp = env;
106
107 } else {
108 Int envlen = (cpp-env) + 2;
109 Char **newenv = VG_(arena_malloc)(VG_AR_CORE, envlen * sizeof(Char **));
110
111 for(cpp = newenv; *env; )
112 *cpp++ = *env++;
113 *cpp++ = valstr;
114 *cpp++ = NULL;
115
116 oldenv = *envp;
117
118 *envp = newenv;
119 }
120
121 return oldenv;
122}
123
nethercote60a96c52004-08-03 13:08:31 +0000124/* Walk through a colon-separated environment variable, and remove the
125 entries which match remove_pattern. It slides everything down over
126 the removed entries, and pads the remaining space with '\0'. It
127 modifies the entries in place (in the client address space), but it
128 shouldn't matter too much, since we only do this just before an
129 execve().
130
131 This is also careful to mop up any excess ':'s, since empty strings
132 delimited by ':' are considered to be '.' in a path.
133*/
134static void mash_colon_env(Char *varp, const Char *remove_pattern)
135{
136 Char *const start = varp;
137 Char *entry_start = varp;
138 Char *output = varp;
139
140 if (varp == NULL)
141 return;
142
143 while(*varp) {
144 if (*varp == ':') {
145 Char prev;
146 Bool match;
147
148 /* This is a bit subtle: we want to match against the entry
149 we just copied, because it may have overlapped with
150 itself, junking the original. */
151
152 prev = *output;
153 *output = '\0';
154
155 match = VG_(string_match)(remove_pattern, entry_start);
156
157 *output = prev;
158
159 if (match) {
160 output = entry_start;
161 varp++; /* skip ':' after removed entry */
162 } else
163 entry_start = output+1; /* entry starts after ':' */
164 }
165
166 *output++ = *varp++;
167 }
168
169 /* match against the last entry */
170 if (VG_(string_match)(remove_pattern, entry_start)) {
171 output = entry_start;
172 if (output > start) {
173 /* remove trailing ':' */
174 output--;
175 vg_assert(*output == ':');
176 }
177 }
178
179 /* pad out the left-overs with '\0' */
180 while(output < varp)
181 *output++ = '\0';
182}
183
184
185// Removes all the Valgrind-added stuff from the passed environment. Used
186// when starting child processes, so they don't see that added stuff.
187void VG_(env_remove_valgrind_env_stuff)(Char** envp)
188{
189 Int i;
190 Char* ld_preload_str = NULL;
191 Char* ld_library_path_str = NULL;
192 Char* buf;
193
194 // Find LD_* variables
195 for (i = 0; envp[i] != NULL; i++) {
196 if (VG_(strncmp)(envp[i], "LD_PRELOAD=", 11) == 0)
197 ld_preload_str = &envp[i][11];
198 if (VG_(strncmp)(envp[i], "LD_LIBRARY_PATH=", 16) == 0)
199 ld_library_path_str = &envp[i][16];
200 }
201
202 buf = VG_(arena_malloc)(VG_AR_CORE, VG_(strlen)(VG_(libdir)) + 20);
203
204 // Remove Valgrind-specific entries from LD_*.
205 VG_(sprintf)(buf, "%s*/vg_inject.so", VG_(libdir));
206 mash_colon_env(ld_preload_str, buf);
207 VG_(sprintf)(buf, "%s*/vgpreload_*.so", VG_(libdir));
208 mash_colon_env(ld_preload_str, buf);
209 VG_(sprintf)(buf, "%s*", VG_(libdir));
210 mash_colon_env(ld_library_path_str, buf);
211
212 // Remove VALGRIND_CLO variable.
213 VG_(env_unsetenv)(envp, VALGRINDCLO);
214
215 // XXX if variable becomes empty, remove it completely?
216
217 VG_(arena_free)(VG_AR_CORE, buf);
218}
219
njnf39e9a32005-06-12 02:43:17 +0000220/* ---------------------------------------------------------------------
221 Various important syscall wrappers
222 ------------------------------------------------------------------ */
223
224Int VG_(waitpid)(Int pid, Int *status, Int options)
225{
226 SysRes res = VG_(do_syscall4)(__NR_wait4, pid, (UWord)status, options, 0);
227 return res.isError ? -1 : res.val;
228}
229
njnf39e9a32005-06-12 02:43:17 +0000230Int VG_(poll)( struct vki_pollfd *ufds, UInt nfds, Int timeout)
231{
232 SysRes res = VG_(do_syscall3)(__NR_poll, (UWord)ufds, nfds, timeout);
233 /* ASSUMES SYSCALL ALWAYS SUCCEEDS */
234 return res.val;
235}
236
237/* clone the environment */
238static Char **env_clone ( Char **oldenv )
239{
240 Char **oldenvp;
241 Char **newenvp;
242 Char **newenv;
243 Int envlen;
244
245 for (oldenvp = oldenv; oldenvp && *oldenvp; oldenvp++);
246
247 envlen = oldenvp - oldenv + 1;
248
249 newenv = VG_(arena_malloc)(VG_AR_CORE, envlen * sizeof(Char **));
250
251 oldenvp = oldenv;
252 newenvp = newenv;
253
254 while (oldenvp && *oldenvp) {
255 *newenvp++ = *oldenvp++;
256 }
257
258 *newenvp = *oldenvp;
259
260 return newenv;
261}
262
sewardje6a25242002-04-21 22:03:07 +0000263/* Return -1 if error, else 0. NOTE does not indicate return code of
264 child! */
265Int VG_(system) ( Char* cmd )
266{
sewardja8d8e232005-06-07 20:04:56 +0000267 Int pid;
268 SysRes res;
sewardje6a25242002-04-21 22:03:07 +0000269 if (cmd == NULL)
270 return 1;
sewardja8d8e232005-06-07 20:04:56 +0000271 res = VG_(do_syscall0)(__NR_fork);
272 if (res.isError)
sewardje6a25242002-04-21 22:03:07 +0000273 return -1;
sewardja8d8e232005-06-07 20:04:56 +0000274 pid = res.val;
sewardje6a25242002-04-21 22:03:07 +0000275 if (pid == 0) {
276 /* child */
nethercoteff9721d2004-01-26 17:10:01 +0000277 static Char** envp = NULL;
sewardje6a25242002-04-21 22:03:07 +0000278 Char* argv[4];
nethercoteff9721d2004-01-26 17:10:01 +0000279
fitzhardingeb50068f2004-02-24 23:42:55 +0000280 /* restore the DATA rlimit for the child */
281 VG_(setrlimit)(VKI_RLIMIT_DATA, &VG_(client_rlimit_data));
282
nethercote60a96c52004-08-03 13:08:31 +0000283 envp = env_clone(VG_(client_envp));
284 VG_(env_remove_valgrind_env_stuff)( envp );
nethercoteff9721d2004-01-26 17:10:01 +0000285
sewardje6a25242002-04-21 22:03:07 +0000286 argv[0] = "/bin/sh";
287 argv[1] = "-c";
288 argv[2] = cmd;
289 argv[3] = 0;
nethercoteff9721d2004-01-26 17:10:01 +0000290
njnca6fef02004-11-29 16:49:18 +0000291 (void)VG_(do_syscall3)(__NR_execve,
292 (UWord)"/bin/sh", (UWord)argv, (UWord)envp);
nethercoteff9721d2004-01-26 17:10:01 +0000293
sewardje6a25242002-04-21 22:03:07 +0000294 /* If we're still alive here, execve failed. */
fitzhardingeabab8392004-03-02 21:38:51 +0000295 VG_(exit)(1);
sewardje6a25242002-04-21 22:03:07 +0000296 } else {
297 /* parent */
sewardja8d8e232005-06-07 20:04:56 +0000298 Int zzz = VG_(waitpid)(pid, NULL, 0);
299 return zzz == -1 ? -1 : 0;
sewardje6a25242002-04-21 22:03:07 +0000300 }
301}
302
njnf39e9a32005-06-12 02:43:17 +0000303/* ---------------------------------------------------------------------
304 Resource limits
305 ------------------------------------------------------------------ */
306
307struct vki_rlimit VG_(client_rlimit_data);
308struct vki_rlimit VG_(client_rlimit_stack);
309
310/* Support for getrlimit. */
311Int VG_(getrlimit) (Int resource, struct vki_rlimit *rlim)
312{
313 SysRes res = VG_(mk_SysRes_Error)(VKI_ENOSYS);
314 /* res = getrlimit( resource, rlim ); */
315# ifdef __NR_ugetrlimit
316 res = VG_(do_syscall2)(__NR_ugetrlimit, resource, (UWord)rlim);
317# endif
318 if (res.isError && res.val == VKI_ENOSYS)
319 res = VG_(do_syscall2)(__NR_getrlimit, resource, (UWord)rlim);
320 return res.isError ? -1 : res.val;
321}
322
323
324/* Support for setrlimit. */
325Int VG_(setrlimit) (Int resource, const struct vki_rlimit *rlim)
326{
327 SysRes res;
328 /* res = setrlimit( resource, rlim ); */
329 res = VG_(do_syscall2)(__NR_setrlimit, resource, (UWord)rlim);
330 return res.isError ? -1 : res.val;
331}
sewardje6a25242002-04-21 22:03:07 +0000332
sewardjde4a1d02002-03-22 01:27:54 +0000333/* ---------------------------------------------------------------------
njnf39e9a32005-06-12 02:43:17 +0000334 pids, etc
335 ------------------------------------------------------------------ */
336
337Int VG_(gettid)(void)
338{
339 SysRes res = VG_(do_syscall0)(__NR_gettid);
340
341 if (res.isError && res.val == VKI_ENOSYS) {
342 Char pid[16];
343 /*
344 * The gettid system call does not exist. The obvious assumption
345 * to make at this point would be that we are running on an older
346 * system where the getpid system call actually returns the ID of
347 * the current thread.
348 *
349 * Unfortunately it seems that there are some systems with a kernel
350 * where getpid has been changed to return the ID of the thread group
351 * leader but where the gettid system call has not yet been added.
352 *
353 * So instead of calling getpid here we use readlink to see where
354 * the /proc/self link is pointing...
355 */
356
357 res = VG_(do_syscall3)(__NR_readlink, (UWord)"/proc/self",
358 (UWord)pid, sizeof(pid));
359 if (!res.isError && res.val > 0) {
360 pid[res.val] = '\0';
361 res.val = VG_(atoll)(pid);
362 }
363 }
364
365 return res.val;
366}
367
368/* You'd be amazed how many places need to know the current pid. */
369Int VG_(getpid) ( void )
370{
371 /* ASSUMES SYSCALL ALWAYS SUCCEEDS */
372 return VG_(do_syscall0)(__NR_getpid) . val;
373}
374
375Int VG_(getpgrp) ( void )
376{
377 /* ASSUMES SYSCALL ALWAYS SUCCEEDS */
378 return VG_(do_syscall0)(__NR_getpgrp) . val;
379}
380
381Int VG_(getppid) ( void )
382{
383 /* ASSUMES SYSCALL ALWAYS SUCCEEDS */
384 return VG_(do_syscall0)(__NR_getppid) . val;
385}
386
387Int VG_(setpgid) ( Int pid, Int pgrp )
388{
389 /* ASSUMES SYSCALL ALWAYS SUCCEEDS */
390 return VG_(do_syscall2)(__NR_setpgid, pid, pgrp) . val;
391}
392
393/* ---------------------------------------------------------------------
394 Timing stuff
sewardj5f07b662002-04-23 16:52:51 +0000395 ------------------------------------------------------------------ */
396
sewardj5f07b662002-04-23 16:52:51 +0000397UInt VG_(read_millisecond_timer) ( void )
398{
fitzhardinge426f9e62004-01-25 03:44:18 +0000399 static ULong base = 0;
fitzhardinge66871692004-01-25 03:32:58 +0000400 struct vki_timeval tv_now;
sewardja8d8e232005-06-07 20:04:56 +0000401 ULong now;
402 SysRes res;
sewardj5f07b662002-04-23 16:52:51 +0000403
njnca6fef02004-11-29 16:49:18 +0000404 res = VG_(do_syscall2)(__NR_gettimeofday, (UWord)&tv_now, (UWord)NULL);
sewardj5f07b662002-04-23 16:52:51 +0000405
fitzhardinge66871692004-01-25 03:32:58 +0000406 now = tv_now.tv_sec * 1000000ULL + tv_now.tv_usec;
407
408 if (base == 0)
409 base = now;
sewardj5f07b662002-04-23 16:52:51 +0000410
fitzhardinge66871692004-01-25 03:32:58 +0000411 return (now - base) / 1000;
sewardj5f07b662002-04-23 16:52:51 +0000412}
413
414
sewardjb5f6f512005-03-10 23:59:00 +0000415void VG_(nanosleep)(struct vki_timespec *ts)
416{
sewardja8d8e232005-06-07 20:04:56 +0000417 (void)VG_(do_syscall2)(__NR_nanosleep, (UWord)ts, (UWord)NULL);
sewardjb5f6f512005-03-10 23:59:00 +0000418}
419
sewardj5f07b662002-04-23 16:52:51 +0000420/* ---------------------------------------------------------------------
sewardja8d8e232005-06-07 20:04:56 +0000421 A simple atfork() facility for Valgrind's internal use
422 ------------------------------------------------------------------ */
423
424struct atfork {
425 vg_atfork_t pre;
426 vg_atfork_t parent;
427 vg_atfork_t child;
428};
429
430#define VG_MAX_ATFORK 10
431
432static struct atfork atforks[VG_MAX_ATFORK];
433static Int n_atfork;
434
435void VG_(atfork)(vg_atfork_t pre, vg_atfork_t parent, vg_atfork_t child)
436{
437 Int i;
438
439 for(i = 0; i < n_atfork; i++) {
440 if (atforks[i].pre == pre &&
441 atforks[i].parent == parent &&
442 atforks[i].child == child)
443 return;
444 }
445
446 if (n_atfork >= VG_MAX_ATFORK)
447 VG_(core_panic)("Too many VG_(atfork) handlers requested: "
448 "raise VG_MAX_ATFORK");
449
450 atforks[n_atfork].pre = pre;
451 atforks[n_atfork].parent = parent;
452 atforks[n_atfork].child = child;
453
454 n_atfork++;
455}
456
457void VG_(do_atfork_pre)(ThreadId tid)
458{
459 Int i;
460
461 for(i = 0; i < n_atfork; i++)
462 if (atforks[i].pre != NULL)
463 (*atforks[i].pre)(tid);
464}
465
466void VG_(do_atfork_parent)(ThreadId tid)
467{
468 Int i;
469
470 for(i = 0; i < n_atfork; i++)
471 if (atforks[i].parent != NULL)
472 (*atforks[i].parent)(tid);
473}
474
475void VG_(do_atfork_child)(ThreadId tid)
476{
477 Int i;
478
479 for(i = 0; i < n_atfork; i++)
480 if (atforks[i].child != NULL)
481 (*atforks[i].child)(tid);
482}
483
sewardjde4a1d02002-03-22 01:27:54 +0000484/*--------------------------------------------------------------------*/
njnc6168192004-11-29 13:54:10 +0000485/*--- end ---*/
sewardjde4a1d02002-03-22 01:27:54 +0000486/*--------------------------------------------------------------------*/