]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gprofng/libcollector/linetrace.c
Update year range in gprofng copyright notices
[thirdparty/binutils-gdb.git] / gprofng / libcollector / linetrace.c
1 /* Copyright (C) 2021-2023 Free Software Foundation, Inc.
2 Contributed by Oracle.
3
4 This file is part of GNU Binutils.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, 51 Franklin Street - Fifth Floor, Boston,
19 MA 02110-1301, USA. */
20
21 /*
22 * Lineage events for process fork, exec, etc.
23 */
24
25 #include "config.h"
26 #include <string.h>
27 #include <elf.h>
28 #include <regex.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <sys/mman.h>
32 #include <limits.h>
33
34
35 #include "descendants.h"
36
37 /* TprintfT(<level>,...) definitions. Adjust per module as needed */
38 #define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings
39 #define DBG_LTT 0 // for interposition on GLIBC functions
40 #define DBG_LT1 1 // for configuration details, warnings
41 #define DBG_LT2 2
42 #define DBG_LT3 3
43
44 #define LT_MAXNAMELEN 1024
45 #define LT_MAXPATHLEN 1024
46
47 int __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0;
48 int dbg_current_mode = FOLLOW_NONE; /* for debug only */
49 unsigned line_key = COLLECTOR_TSD_INVALID_KEY;
50 line_mode_t line_mode = LM_DORMANT;
51 int user_follow_mode = FOLLOW_ON;
52 int java_mode = 0;
53
54 static char *user_follow_spec;
55 static char new_lineage[LT_MAXNAMELEN];
56 static char curr_lineage[LT_MAXNAMELEN];
57 static char linetrace_exp_dir_name[LT_MAXPATHLEN + 1]; // experiment directory
58
59 /* lineage tracking for descendants of this process */
60
61 static int fork_linenum = 0;
62 static int line_initted = 0;
63 static collector_mutex_t fork_lineage_lock = COLLECTOR_MUTEX_INITIALIZER;
64 static collector_mutex_t clone_lineage_lock = COLLECTOR_MUTEX_INITIALIZER;
65
66 /* interposition */
67 #define CALL_REAL(x) (*(int(*)())__real_##x)
68 #define CALL_REALC(x) (*(char*(*)())__real_##x)
69 #define CALL_REALF(x) (*(FILE*(*)())__real_##x)
70 #define NULL_PTR(x) ( __real_##x == NULL )
71
72 // For a given Linux, which lib functions have more than one GLIBC version? Do this:
73 // objdump -T `find /lib /lib64 -name "*.so*"` | grep GLIBC | grep text | grep \(
74 static void *__real_fork = NULL;
75 static void *__real_vfork = NULL;
76 static void *__real_execve = NULL;
77 static void *__real_execvp = NULL;
78 static void *__real_execv = NULL;
79 static void *__real_execle = NULL;
80 static void *__real_execlp = NULL;
81 static void *__real_execl = NULL;
82 static void *__real_clone = NULL;
83 static void *__real_grantpt = NULL;
84 static void *__real_ptsname = NULL;
85 static void *__real_popen = NULL;
86 static int clone_linenum = 0;
87 #if ARCH(Intel)
88 #if WSIZE(32)
89 static void *__real_popen_2_1 = NULL;
90 static void *__real_popen_2_0 = NULL;
91 static void *__real_posix_spawn_2_15 = NULL;
92 static void *__real_posix_spawnp_2_15 = NULL;
93 static void *__real_posix_spawn_2_2 = NULL;
94 static void *__real_posix_spawnp_2_2 = NULL;
95 #elif WSIZE(64)
96 static void *__real_posix_spawn_2_15 = NULL;
97 static void *__real_posix_spawnp_2_15 = NULL;
98 static void *__real_posix_spawn_2_2_5 = NULL;
99 static void *__real_posix_spawnp_2_2_5 = NULL;
100 #endif /* WSIZE() */
101 #endif /* ARCH(Intel) */
102 static void *__real_system = NULL;
103 static void *__real_posix_spawn = NULL;
104 static void *__real_posix_spawnp = NULL;
105 static void *__real_setuid = NULL;
106 static void *__real_seteuid = NULL;
107 static void *__real_setreuid = NULL;
108 static void *__real_setgid = NULL;
109 static void *__real_setegid = NULL;
110 static void *__real_setregid = NULL;
111 static void linetrace_dormant ();
112 static int check_follow_fork ();
113 static int check_follow_exec (const char *execfile);
114 static int check_follow_combo (const char *execfile);
115 static int path_collectable (const char *execfile);
116 static char * build_experiment_path (char *instring, size_t instring_sz, const char *lineage_str);
117 static int init_lineage_intf ();
118
119 /* ------- "Previously dbx-visible" function prototypes ----------------- */
120 static int linetrace_follow_experiment (const char *follow_spec, const char *lineage_str, const char *execfile);
121 static char *lineage_from_expname (char *lineage_str, size_t lstr_sz, const char *expname);
122 static void linetrace_ext_fork_prologue (const char *variant, char * new_lineage, int *following_fork);
123 static void linetrace_ext_fork_epilogue (const char *variant, const pid_t ret, char * new_lineage, int *following_fork);
124 static char **linetrace_ext_exec_prologue (const char *variant,
125 const char* path, char *const argv[], char *const envp[], int *following_exec);
126 static void linetrace_ext_exec_epilogue (const char *variant, char *const envp[], const int ret, int *following_exec);
127 static void linetrace_ext_combo_prologue (const char *variant, const char *cmd, int *following_combo);
128 static void linetrace_ext_combo_epilogue (const char *variant, const int ret, int *following_combo);
129
130 #ifdef DEBUG
131 static int
132 get_combo_flag ()
133 {
134 int * guard = NULL;
135 int combo_flag = ((line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0);
136 return combo_flag;
137 }
138 #endif /* DEBUG */
139
140 /* must be called for potentially live experiment */
141 int
142 __collector_ext_line_init (int *precord_this_experiment,
143 const char * progspec, const char * progname)
144 {
145 *precord_this_experiment = 1;
146 TprintfT (DBG_LT0, "__collector_ext_line_init(%s)\n", progspec);
147 if (NULL_PTR (fork))
148 if (init_lineage_intf ())
149 {
150 TprintfT (DBG_LT0, "__collector_ext_line_init() ERROR: initialization failed.\n");
151 return COL_ERROR_LINEINIT;
152 }
153 /* check the follow spec */
154 user_follow_spec = CALL_UTIL (getenv)(SP_COLLECTOR_FOLLOW_SPEC);
155 if (user_follow_spec != NULL)
156 {
157 TprintfT (DBG_LT0, "collector: %s=%s\n", SP_COLLECTOR_FOLLOW_SPEC, user_follow_spec);
158 if (!linetrace_follow_experiment (user_follow_spec, curr_lineage, progname))
159 {
160 *precord_this_experiment = 0;
161 TprintfT (DBG_LT0, "collector: -F =<regex> does not match, will NOT be followed\n");
162 }
163 else
164 TprintfT (DBG_LT0, "collector: -F =<regex> matches, will be followed\n");
165 user_follow_mode = FOLLOW_ALL;
166 }
167 __collector_env_save_preloads ();
168 TprintfT (DBG_LT0, "__collector_ext_line_init(), progname=%s, followspec=%s, followthis=%d\n",
169 progname, user_follow_spec ? user_follow_spec : "NULL",
170 *precord_this_experiment);
171 line_mode = LM_TRACK_LINEAGE; /* even if we don't follow, we report the interposition */
172 line_initted = 1;
173 return COL_ERROR_NONE;
174 }
175
176 /*
177 * int __collector_ext_line_install(args)
178 * Check args to determine which line events to follow.
179 * Create tsd key for combo flag.
180 */
181 int
182 __collector_ext_line_install (char *args, const char * expname)
183 {
184 if (!line_initted)
185 {
186 TprintfT (DBG_LT0, "__collector_ext_line_install(%s) ERROR: init hasn't be called yet\n", args);
187 return COL_ERROR_EXPOPEN;
188 }
189 TprintfT (DBG_LT0, "__collector_ext_line_install(%s, %s)\n", args, expname);
190 line_key = __collector_tsd_create_key (sizeof (int), NULL, NULL);
191
192 /* determine experiment name */
193 __collector_strlcpy (linetrace_exp_dir_name, expname, sizeof (linetrace_exp_dir_name));
194 lineage_from_expname (curr_lineage, sizeof (curr_lineage), linetrace_exp_dir_name);
195 user_follow_mode = CALL_UTIL (atoi)(args);
196 TprintfT (DBG_LT0, "__collector_ext_line_install() user_follow_mode=0x%X, linetrace_exp_dir_name=%s\n",
197 user_follow_mode, linetrace_exp_dir_name);
198
199 // determine java mode
200 char * java_follow_env = CALL_UTIL (getenv)(JAVA_TOOL_OPTIONS);
201 if (java_follow_env != NULL && CALL_UTIL (strstr)(java_follow_env, COLLECTOR_JVMTI_OPTION))
202 java_mode = 1;
203
204 // backup collector specific env
205 if (sp_env_backup == NULL)
206 {
207 sp_env_backup = __collector_env_backup ();
208 TprintfT (DBG_LT0, "__collector_ext_line_install creating sp_env_backup -- 0x%p\n", sp_env_backup);
209 }
210 else
211 TprintfT (DBG_LT0, "__collector_ext_line_install existing sp_env_backup -- 0x%p\n", sp_env_backup);
212 if (user_follow_mode == FOLLOW_NONE)
213 __collector_env_unset (NULL);
214
215 char logmsg[256];
216 logmsg[0] = '\0';
217 if (user_follow_mode != FOLLOW_NONE)
218 CALL_UTIL (strlcat)(logmsg, "fork|exec|combo", sizeof (logmsg));
219 size_t slen = __collector_strlen (logmsg);
220 if (slen > 0)
221 logmsg[slen] = '\0';
222 else
223 CALL_UTIL (strlcat)(logmsg, "none", sizeof (logmsg));
224
225 /* report which line events are followed */
226 (void) __collector_log_write ("<setting %s=\"%s\"/>\n", SP_JCMD_LINETRACE, logmsg);
227 TprintfT (DBG_LT0, "__collector_ext_line_install(%s): %s \n", expname, logmsg);
228 return COL_ERROR_NONE;
229 }
230
231 char *
232 lineage_from_expname (char *lineage_str, size_t lstr_sz, const char *expname)
233 {
234 TprintfT (DBG_LT0, "lineage_from_expname(%s, %s)\n", lineage_str, expname);
235 char *p = NULL;
236 if (lstr_sz < 1 || !lineage_str || !expname)
237 {
238 TprintfT (DBG_LT0, "lineage_from_expname(): ERROR, null string\n");
239 return NULL;
240 }
241 /* determine lineage from experiment name */
242 p = __collector_strrchr (expname, '/');
243 if ((p == NULL) || (*++p != '_'))
244 {
245 lineage_str[0] = 0;
246 TprintfT (DBG_LT2, "lineage_from_expname(): expt=%s lineage=\".\" (founder)\n", expname);
247 }
248 else
249 {
250 size_t tmp = __collector_strlcpy (lineage_str, p, lstr_sz);
251 if (tmp >= lstr_sz)
252 TprintfT (DBG_LT0, "lineage_from_expname(): ERROR: expt=%s lineage=\"%s\" truncated %ld characters\n",
253 expname, lineage_str, (long) (tmp - lstr_sz));
254 lineage_str[lstr_sz - 1] = 0;
255 p = __collector_strchr (lineage_str, '.');
256 if (p != NULL)
257 *p = '\0';
258 TprintfT (DBG_LT2, "lineage_from_expname(): expt=%s lineage=\"%s\"\n", expname, lineage_str);
259 }
260 return lineage_str;
261 }
262
263 /*
264 * void __collector_line_cleanup (void)
265 * Disable logging. Clear backup ENV.
266 */
267 void
268 __collector_line_cleanup (void)
269 {
270 if (line_mode == LM_CLOSED)
271 {
272 TprintfT (DBG_LT0, "__collector_line_cleanup(): WARNING, line is already closed\n");
273 return;
274 }
275 else if (line_mode == LM_DORMANT)
276 TprintfT (DBG_LT0, "__collector_line_cleanup(): ERROR, line is DORMANT\n");
277 else
278 TprintfT (DBG_LT0, "__collector_line_cleanup()\n");
279 line_mode = LM_CLOSED;
280 user_follow_mode = FOLLOW_NONE;
281 dbg_current_mode = FOLLOW_NONE; /* for debug only */
282 line_key = COLLECTOR_TSD_INVALID_KEY;
283 java_mode = 0;
284 if (sp_env_backup != NULL)
285 {
286 __collector_env_backup_free ();
287 sp_env_backup = NULL;
288 }
289 return;
290 }
291
292 /*
293 * void __collector_ext_line_close (void)
294 * Disable logging. Cleans ENV vars. Clear backup ENV.
295 */
296 void
297 __collector_ext_line_close (void)
298 {
299 TprintfT (DBG_LT0, "__collector_ext_line_close()\n");
300 __collector_line_cleanup ();
301 __collector_env_unset (NULL);
302 return;
303 }
304
305 /*
306 * void linetrace_dormant(void)
307 * Disable logging. Preserve ENV vars.
308 */
309 static void
310 linetrace_dormant (void)
311 {
312 if (line_mode == LM_DORMANT)
313 {
314 TprintfT (DBG_LT0, "linetrace_dormant() -- already dormant\n");
315 return;
316 }
317 else if (line_mode == LM_CLOSED)
318 {
319 TprintfT (DBG_LT0, "linetrace_dormant(): ERROR, line is already CLOSED\n");
320 return;
321 }
322 else
323 TprintfT (DBG_LT0, "linetrace_dormant()\n");
324 line_mode = LM_DORMANT;
325 return;
326 }
327
328 static int
329 check_follow_fork ()
330 {
331 int follow = (user_follow_mode != FOLLOW_NONE);
332 TprintfT (DBG_LT0, "check_follow_fork()=%d\n", follow);
333 return follow;
334 }
335
336 static int
337 check_follow_exec (const char *execfile)
338 {
339 int follow = (user_follow_mode != FOLLOW_NONE);
340 if (follow)
341 {
342 /* revise based on collectability of execfile */
343 follow = path_collectable (execfile);
344 }
345 TprintfT (DBG_LT0, "check_follow_exec(%s)=%d\n", execfile, follow);
346 return follow;
347 }
348
349 static int
350 check_follow_combo (const char *execfile)
351 {
352 int follow = (user_follow_mode != FOLLOW_NONE);
353 TprintfT (DBG_LT0, "check_follow_combo(%s)=%d\n", execfile, follow);
354 return follow;
355 }
356
357 static int
358 check_fd_dynamic (int fd)
359 {
360 TprintfT (DBG_LT0, "check_fd_dynamic(%d)\n", fd);
361 off_t off = CALL_UTIL (lseek)(fd, (off_t) 0, SEEK_END);
362 size_t sz = (size_t) 8192; /* one page should suffice */
363 if (sz > off)
364 sz = off;
365 char *p = CALL_UTIL (mmap64_)((char *) 0, sz, PROT_READ, MAP_PRIVATE, fd, (off64_t) 0);
366 if (p == MAP_FAILED)
367 {
368 TprintfT (DBG_LT0, "check_fd_dynamic(): ERROR/WARNING: mmap failed for `%d'\n", fd);
369 (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
370 COL_WARN_NOFOLLOW, "mmap-failed");
371 return 0;
372 }
373 char elfclass = p[EI_CLASS];
374 if ((p[EI_MAG0] != ELFMAG0) ||
375 (p[EI_MAG1] != ELFMAG1) ||
376 (p[EI_MAG2] != ELFMAG2) ||
377 (p[EI_MAG3] != ELFMAG3) ||
378 (elfclass != ELFCLASS32 && elfclass != ELFCLASS64)
379 )
380 {
381 TprintfT (DBG_LT0, "check_fd_dynamic(): WARNING: Command `%d' is not executable ELF!\n", fd);
382 CALL_UTIL (munmap)(p, sz);
383 return 1;
384 }
385 Elf32_Ehdr *ehdr32 = (Elf32_Ehdr*) p;
386 Elf64_Ehdr *ehdr64 = (Elf64_Ehdr*) p;
387 Elf64_Off e_phoff;
388 Elf64_Half e_phnum;
389 Elf64_Half e_phentsize;
390 if (elfclass == ELFCLASS32)
391 {
392 e_phoff = ehdr32->e_phoff;
393 e_phnum = ehdr32->e_phnum;
394 e_phentsize = ehdr32->e_phentsize;
395 }
396 else
397 {
398 e_phoff = ehdr64->e_phoff;
399 e_phnum = ehdr64->e_phnum;
400 e_phentsize = ehdr64->e_phentsize;
401 }
402 if ((sizeof (Elf32_Ehdr) > sz) ||
403 (sizeof (Elf64_Ehdr) > sz) ||
404 (e_phoff + e_phentsize * (e_phnum - 1) > sz))
405 {
406 TprintfT (DBG_LT0, "check_fd_dynamic(): WARNING: Command `%d' ELF file did not fit in page!\n", fd);
407 #if 0
408 (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
409 COL_WARN_RISKYFOLLOW, "ELF header size");
410 #endif
411 CALL_UTIL (munmap)(p, sz);
412 return 1;
413 }
414 TprintfT (DBG_LT2, "check_fd_dynamic(): elfclass=%d, e_phoff=%lu e_phnum=%lu e_phentsize=%lu\n",
415 (int) elfclass, (unsigned long) e_phoff, (unsigned long) e_phnum,
416 (unsigned long) e_phentsize);
417 int dynamic = 0;
418 Elf64_Half i;
419 for (i = 0; i < e_phnum; i++)
420 {
421 if (elfclass == ELFCLASS32)
422 {
423 if (PT_DYNAMIC ==
424 ((Elf32_Phdr*) (p + e_phoff + e_phentsize * i))->p_type)
425 {
426 dynamic = 1;
427 break;
428 }
429 }
430 else
431 {
432 if (PT_DYNAMIC ==
433 ((Elf64_Phdr*) (p + e_phoff + e_phentsize * i))->p_type)
434 {
435 dynamic = 1;
436 break;
437 }
438 }
439 }
440 if (!dynamic)
441 {
442 TprintfT (DBG_LT0, "check_fd_dynamic(): ERROR/WARNING: Command `%d' is not a dynamic executable!\n", fd);
443 #if 0
444 (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
445 COL_WARN_NOFOLLOW, "!dynamic");
446 #endif
447 }
448 else
449 TprintfT (DBG_LT2, "check_fd_dynamic(): Command `%d' is a dynamic executable!\n", fd);
450 CALL_UTIL (munmap)(p, sz);
451 return dynamic;
452 }
453
454 static int
455 check_dynamic (const char *execfile)
456 {
457 TprintfT (DBG_LT2, "check_dynamic(%s)\n", execfile);
458 int fd = CALL_UTIL (open)(execfile, O_RDONLY);
459 if (fd == -1)
460 {
461 TprintfT (DBG_LT0, "check_dynamic(): ERROR/WARNING: Command `%s' could not be opened!\n", execfile);
462 (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
463 COL_WARN_RISKYFOLLOW, "open");
464 return 1; /* follow, though exec will presumably fail */
465 }
466 int ret = check_fd_dynamic (fd);
467 CALL_UTIL (close)(fd);
468 return ret;
469 }
470
471 static int
472 path_collectable (const char *execfile)
473 {
474 TprintfT (DBG_LT0, "path_collectable(%s)\n", execfile);
475 /* Check that execfile exists and is a collectable executable */
476 /* logging warning when collection is likely to be unsuccessful */
477 /* (if check isn't accurate, generally best not to include it) */
478
479 if (execfile && !__collector_strchr (execfile, '/'))
480 { /* got an unqualified name */
481 /* XXXX locate execfile on PATH to be able to check it */
482 TprintfT (DBG_LT0, "path_collectable(): WARNING: Can't check unqualified executable `%s'\n", execfile);
483 #if 0
484 (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
485 COL_WARN_RISKYFOLLOW, "path");
486 #endif
487 return 1; /* follow unqualified execfile unchecked */
488 }
489 struct stat sbuf;
490 if (stat (execfile, &sbuf))
491 { /* can't stat it */
492 TprintfT (DBG_LT0, "path_collectable(): WARNING: Can't stat `%s'\n", execfile);
493 #if 0
494 (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
495 COL_WARN_RISKYFOLLOW, "stat");
496 #endif
497 return 1; /* follow, though exec will probably fail */
498 }
499 TprintfT (DBG_LT2, "path_collectable(%s) mode=0%o uid=%d gid=%d\n",
500 execfile, sbuf.st_mode, sbuf.st_uid, sbuf.st_gid);
501 if (((sbuf.st_mode & S_IXUSR) == 0) || ((sbuf.st_mode & S_IFMT) == S_IFDIR))
502 {
503 TprintfT (DBG_LT0, "path_collectable(): WARNING: Command `%s' is NOT an executable file!\n", execfile);
504 #if 0
505 (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
506 COL_WARN_RISKYFOLLOW, "mode");
507 #endif
508 return 1; /* follow, though exec will presumably fail */
509 }
510 /* XXXX setxid(root) is OK iff libcollector is registered as secure */
511 /* XXXX setxid(non-root) is OK iff umask is accomodating */
512 if (((sbuf.st_mode & S_ISUID) != 0) || ((sbuf.st_mode & S_ISGID) != 0))
513 {
514 TprintfT (DBG_LT0, "path_collectable(): WARNING: Command `%s' is SetXID!\n", execfile);
515 #if 0
516 (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
517 COL_WARN_RISKYFOLLOW, "setxid");
518 #endif
519 return 1; /* follow, though collection may be unreliable */
520 }
521 if (!check_dynamic (execfile))
522 {
523 TprintfT (DBG_LT0, "path_collectable(%s) WARNING/ERROR: not dynamic, not collectng!\n", execfile);
524 return 0; /* don't follow, collection will fail unpredictably */
525 }
526 TprintfT (DBG_LT2, "path_collectable(%s) OK!\n", execfile);
527 return 1; /* OK to follow */
528 }
529
530 static char *
531 build_experiment_path (char * instring, size_t instring_sz, const char *lineage_str)
532 {
533 TprintfT (DBG_LT0, "build_experiment_path(,%ld, %s)\n",
534 (long) instring_sz, lineage_str);
535 const char *p = CALL_UTIL (strstr)(linetrace_exp_dir_name, DESCENDANT_EXPT_KEY);
536 int basedir_sz;
537 if (p)
538 basedir_sz = p - linetrace_exp_dir_name + 4; /* +3 because of DESCENDANT_EXPT_KEY */
539 else
540 basedir_sz = __collector_strlen (linetrace_exp_dir_name) + 1;
541 int additional_sz = __collector_strlen (lineage_str) + 4;
542 if (basedir_sz + additional_sz > instring_sz)
543 {
544 TprintfT (DBG_LT0, "build_experiment_path(%s,%s): ERROR: path too long: %d > %ld\n",
545 linetrace_exp_dir_name, lineage_str,
546 basedir_sz + additional_sz, (long) instring_sz);
547 *instring = 0;
548 return NULL;
549 }
550 __collector_strlcpy (instring, linetrace_exp_dir_name, basedir_sz);
551 size_t slen = __collector_strlen (instring);
552 CALL_UTIL (snprintf)(instring + slen, instring_sz - slen, "/%s.er", lineage_str);
553 assert (__collector_strlen (instring) + 1 == basedir_sz + additional_sz);
554 return instring;
555 }
556
557 static void
558 check_reuid_change (uid_t ruid, uid_t euid)
559 {
560 uid_t curr_ruid = getuid ();
561 uid_t curr_euid = geteuid ();
562 mode_t curr_umask = umask (0);
563 umask (curr_umask); /* restore original umask */
564 int W_oth = !(curr_umask & S_IWOTH);
565 TprintfT (DBG_LT0, "check_reuid_change(%d,%d): umask=%03o\n", ruid, euid, curr_umask);
566 TprintfT (DBG_LT0, "check_reuid_change(): umask W usr=%d grp=%d oth=%d\n",
567 (int) (!(curr_umask & S_IWUSR)), (int) (!(curr_umask & S_IWGRP)), W_oth);
568 if (ruid != -1)
569 {
570 TprintfT (DBG_LT0, "check_reuid_change(%d->%d)\n", curr_ruid, ruid);
571 if ((curr_euid == 0) && (ruid != 0) && !W_oth)
572 {
573 /* changing to non-root ID, with umask blocking writes by other */
574 TprintfT (DBG_LT0, "check_reuid_change(): ERROR/WARNING: umask blocks write other after ruid change (%d->%d)\n",
575 curr_ruid, ruid);
576 (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">umask %03o ruid %d->%d</event>\n",
577 SP_JCMD_CWARN, COL_WARN_IDCHNG, curr_umask, curr_ruid, ruid);
578 }
579 }
580 if (euid != -1)
581 {
582 TprintfT (DBG_LT0, "check_reuid_change(%d->%d)\n", curr_euid, euid);
583 if ((curr_euid == 0) && (euid != 0) && !W_oth)
584 {
585 /* changing to non-root ID, with umask blocking writes by other */
586 TprintfT (DBG_LT0, "check_reuid_change(): ERROR/WARNING: umask blocks write other after euid change (%d->%d)\n",
587 curr_euid, euid);
588 (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">umask %03o euid %d->%d</event>\n",
589 SP_JCMD_CWARN, COL_WARN_IDCHNG, curr_umask, curr_euid, euid);
590 }
591 }
592 }
593
594 static void
595 check_regid_change (gid_t rgid, gid_t egid)
596 {
597 gid_t curr_rgid = getgid ();
598 gid_t curr_egid = getegid ();
599 uid_t curr_euid = geteuid ();
600 mode_t curr_umask = umask (0);
601 umask (curr_umask); /* restore original umask */
602 int W_oth = !(curr_umask & S_IWOTH);
603 TprintfT (DBG_LT0, "check_regid_change(%d,%d): umask=%03o euid=%d\n",
604 rgid, egid, curr_umask, curr_euid);
605 TprintfT (DBG_LT0, "umask W usr=%d grp=%d oth=%d\n",
606 (int) (!(curr_umask & S_IWUSR)), (int) (!(curr_umask & S_IWGRP)), W_oth);
607 if (rgid != -1)
608 {
609 TprintfT (DBG_LT0, "check_regid_change(%d->%d)\n", curr_rgid, rgid);
610 if ((curr_euid == 0) && (rgid != 0) && !W_oth)
611 {
612 /* changing to non-root ID, with umask blocking writes by other */
613 TprintfT (DBG_LT0, "check_regid_change(): WARNING/ERROR: umask blocks write other after rgid change (%d->%d)\n",
614 curr_rgid, rgid);
615 (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">umask %03o rgid %d->%d</event>\n",
616 SP_JCMD_CWARN, COL_WARN_IDCHNG, curr_umask, curr_rgid, rgid);
617 }
618 }
619 if (egid != -1)
620 {
621 TprintfT (DBG_LT0, "check_regid_change(): check_egid_change(%d->%d)\n", curr_egid, egid);
622 if ((curr_euid == 0) && (egid != 0) && !W_oth)
623 {
624 /* changing to non-root ID, with umask blocking writes by other */
625 TprintfT (DBG_LT0, "check_regid_change(): WARNING/ERROR: umask blocks write other after egid change (%d->%d)\n",
626 curr_egid, egid);
627 (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">umask %03o egid %d->%d</event>\n",
628 SP_JCMD_CWARN, COL_WARN_IDCHNG, curr_umask, curr_egid, egid);
629 }
630 }
631 }
632
633 static int
634 init_lineage_intf ()
635 {
636 void *dlflag;
637 TprintfT (DBG_LT2, "init_lineage_intf()\n");
638
639 static int nesting_check = 0;
640 if (nesting_check >= 2)
641 {
642 /* segv before stack blows up */
643 nesting_check /= (nesting_check - 2);
644 }
645 nesting_check++;
646
647 __real_fork = dlsym (RTLD_NEXT, "fork");
648 if (__real_fork == NULL)
649 {
650 __real_fork = dlsym (RTLD_DEFAULT, "fork");
651 if (__real_fork == NULL)
652 return 1;
653 dlflag = RTLD_DEFAULT;
654 }
655 else
656 dlflag = RTLD_NEXT;
657 TprintfT (DBG_LT2, "init_lineage_intf() using RTLD_%s\n",
658 dlflag == RTLD_DEFAULT ? "DEFAULT" : "NEXT");
659 TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_fork\n", __real_fork);
660 __real_vfork = dlsym (dlflag, "vfork");
661 TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_vfork\n", __real_vfork);
662 __real_execve = dlsym (dlflag, "execve");
663 TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_execve\n", __real_execve);
664 __real_execvp = dlsym (dlflag, "execvp");
665 TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_execvp\n", __real_execvp);
666 __real_execv = dlsym (dlflag, "execv");
667 TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_execv\n", __real_execv);
668 __real_execle = dlsym (dlflag, "execle");
669 TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_execle\n", __real_execle);
670 __real_execlp = dlsym (dlflag, "execlp");
671 TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_execlp\n", __real_execlp);
672 __real_execl = dlsym (dlflag, "execl");
673 TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_execl\n", __real_execl);
674 __real_clone = dlsym (dlflag, "clone");
675 TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_clone\n", __real_clone);
676 __real_posix_spawn = dlsym (dlflag, "posix_spawn");
677 TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_posix_spawn\n",
678 __real_posix_spawn);
679 __real_posix_spawnp = dlsym (dlflag, "posix_spawnp");
680 TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_posix_spawnp\n",
681 __real_posix_spawnp);
682 __real_popen = dlvsym (dlflag, "popen", SYS_POPEN_VERSION);
683 TprintfT (DBG_LT2, "init_lineage_intf()[%s] @0x%p __real_popen\n",
684 SYS_POPEN_VERSION, __real_popen);
685 #if ARCH(Intel)
686 __real_posix_spawn_2_15 = dlvsym (dlflag, "posix_spawn", SYS_POSIX_SPAWN_VERSION);
687 __real_posix_spawnp_2_15 = dlvsym (dlflag, "posix_spawnp", SYS_POSIX_SPAWN_VERSION);
688 #if WSIZE(32)
689 __real_popen_2_1 = __real_popen;
690 __real_popen_2_0 = dlvsym (dlflag, "popen", "GLIBC_2.0");
691 __real_posix_spawn_2_2 = dlvsym (dlflag, "posix_spawn", "GLIBC_2.2");
692 __real_posix_spawnp_2_2 = dlvsym (dlflag, "posix_spawnp", "GLIBC_2.2");
693 #elif WSIZE(64)
694 __real_posix_spawn_2_2_5 = dlvsym (dlflag, "posix_spawn", "GLIBC_2.2.5");
695 __real_posix_spawnp_2_2_5 = dlvsym (dlflag, "posix_spawnp", "GLIBC_2.2.5");
696 #endif /* WSIZE() */
697 #endif /* ARCH(Intel) */
698 __real_grantpt = dlsym (dlflag, "grantpt");
699 TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_grantpt\n", __real_grantpt);
700 __real_ptsname = dlsym (dlflag, "ptsname");
701 TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_ptsname\n", __real_ptsname);
702 __real_system = dlsym (dlflag, "system");
703 TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_system\n", __real_system);
704 __real_setuid = dlsym (dlflag, "setuid");
705 TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_setuid\n", __real_setuid);
706 __real_seteuid = dlsym (dlflag, "seteuid");
707 TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_seteuid\n", __real_seteuid);
708 __real_setreuid = dlsym (dlflag, "setreuid");
709 TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_setreuid\n", __real_setreuid);
710 __real_setgid = dlsym (dlflag, "setgid");
711 TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_setgid\n", __real_setgid);
712 __real_setegid = dlsym (dlflag, "setegid");
713 TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_setegid\n", __real_setegid);
714 __real_setregid = dlsym (dlflag, "setregid");
715 TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_setregid\n", __real_setregid);
716 return 0;
717 }
718
719 /*------------------------------------------------------------------------ */
720 /* Note: The following _prologue and _epilogue functions used to be dbx-visible.
721
722 They are used to appropriately manage lineage-changing events, by
723 quiescing and re-enabling/re-setting experiment collection before and after,
724 and logging the lineage-change in the process/experiment undertaking it.
725 As shown by the interposition functions for fork, exec, etc., which follow,
726 the _prologue should be called immediately prior (such as a breakpoint
727 action defined at function entry) and the _epilogue called immediately
728 after (such as a breakpoint action defined at function return).
729 */
730
731 /*
732 Notes on MT from Solaris 10 man pthread_atfork:
733
734 All multithreaded applications that call fork() in a POSIX
735 threads program and do more than simply call exec(2) in the
736 child of the fork need to ensure that the child is protected
737 from deadlock.
738
739 Since the "fork-one" model results in duplicating only the
740 thread that called fork(), it is possible that at the time
741 of the call another thread in the parent owns a lock. This
742 thread is not duplicated in the child, so no thread will
743 unlock this lock in the child. Deadlock occurs if the sin-
744 gle thread in the child needs this lock.
745
746 The problem is more serious with locks in libraries. Since
747 a library writer does not know if the application using the
748 library calls fork(), the library must protect itself from
749 such a deadlock scenario. If the application that links
750 with this library calls fork() and does not call exec() in
751 the child, and if it needs a library lock that may be held
752 by some other thread in the parent that is inside the
753 library at the time of the fork, the application deadlocks
754 inside the library.
755 */
756
757 static void
758 linetrace_ext_fork_prologue (const char *variant, char * n_lineage, int *following_fork)
759 {
760 TprintfT (DBG_LT0, "linetrace_ext_fork_prologue; variant=%s; new_lineage=%s; follow=%d\n",
761 variant, n_lineage, *following_fork);
762 __collector_env_print ("fork_prologue start");
763 if (dbg_current_mode != FOLLOW_NONE)
764 TprintfT (DBG_LT0, "linetrace_ext_fork_prologue(%s) ERROR: dbg_current_mode=%d, changing to FOLLOW_FORK!\n",
765 variant, dbg_current_mode);
766 dbg_current_mode = FOLLOW_ON;
767 if (__collector_strncmp ((char *) variant, "clone", sizeof ("clone") - 1) == 0)
768 {
769 __collector_mutex_lock (&clone_lineage_lock);
770 CALL_UTIL (snprintf)(n_lineage, LT_MAXNAMELEN, "%s_C%d", curr_lineage, ++clone_linenum);
771 __collector_mutex_unlock (&clone_lineage_lock);
772 }
773 else
774 {
775 __collector_mutex_lock (&fork_lineage_lock);
776 CALL_UTIL (snprintf)(n_lineage, LT_MAXNAMELEN, "%s_f%d", curr_lineage, ++fork_linenum);
777 __collector_mutex_unlock (&fork_lineage_lock);
778 }
779 *following_fork = check_follow_fork ();
780
781 /* write message before suspending, or it won't be written */
782 hrtime_t ts = GETRELTIME ();
783 TprintfT (DBG_LT0, "linetrace_ext_fork_prologue; variant=%s; new_lineage=%s; follow=%d\n",
784 variant, n_lineage, *following_fork);
785 __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" variant=\"%s\" lineage=\"%s\" follow=\"%d\"/>\n",
786 SP_JCMD_DESC_START,
787 (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
788 variant, n_lineage, *following_fork);
789 __collector_ext_dispatcher_thread_timer_suspend ();
790 __collector_ext_hwc_lwp_suspend ();
791 __collector_env_print ("fork_prologue end");
792 }
793
794 static void
795 linetrace_ext_fork_epilogue (const char *variant, const pid_t ret, char * n_lineage, int *following_fork)
796 {
797 if (dbg_current_mode == FOLLOW_NONE)
798 TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue(%s) ERROR: dbg_current_mode=%d!\n",
799 variant, dbg_current_mode);
800 /* compute descendant experiment name */
801 char new_exp_name[LT_MAXPATHLEN];
802 /* save exp_name to global var */
803 if (!build_experiment_path (new_exp_name, sizeof (new_exp_name), n_lineage))
804 TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue(%s): ERROR SP_COLLECTOR_EXPNAME not set\n", n_lineage);
805 TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue(%s):%d() returned %d %s; child experiment name = %s\n",
806 variant, *following_fork, ret, (ret ? "parent" : "child"), new_exp_name);
807 if (ret == 0)
808 {
809 /* *************************************child */
810 __collector_env_print ("fork_epilogue child at start");
811 /* start a new line */
812 fork_linenum = 0;
813 __collector_mutex_init (&fork_lineage_lock);
814 clone_linenum = 0;
815 __collector_mutex_init (&clone_lineage_lock);
816 __collector_env_update (NULL);
817 __collector_env_print ("fork_epilogue child after env_update");
818 __collector_clean_state ();
819 __collector_env_print ("fork_epilogue child after clean_slate");
820 __collector_line_cleanup ();
821 __collector_env_print ("fork_epilogue child after line_cleanup");
822 if (*following_fork)
823 {
824 /* stop recording this experiment, but preserve env vars */
825 linetrace_dormant ();
826 __collector_env_print ("fork_epilogue child after linetrace_dormant");
827
828 //static char exp_name_env[LT_MAXPATHLEN];
829 char * exp_name_env = CALL_UTIL (calloc)(LT_MAXPATHLEN, 1);
830 CALL_UTIL (snprintf)(exp_name_env, LT_MAXPATHLEN, "%s=%s", SP_COLLECTOR_EXPNAME, new_exp_name);
831 CALL_UTIL (putenv)(exp_name_env);
832
833 const char *params = CALL_UTIL (getenv)(SP_COLLECTOR_PARAMS);
834 int ret;
835 if (*new_exp_name == 0)
836 TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue: ERROR: getenv(%s) undefined -- new expt aborted!\n",
837 SP_COLLECTOR_EXPNAME);
838 else if (params == NULL)
839 TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue: ERROR: getenv(%s) undefined -- new expt aborted!\n",
840 SP_COLLECTOR_PARAMS);
841 else if ((ret = __collector_open_experiment (new_exp_name, params, SP_ORIGIN_FORK)))
842 TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue: ERROR: '%s' open failed, ret=%d\n",
843 new_exp_name, ret);
844 else
845 TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue: opened(%s)\n", new_exp_name);
846 TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue(%s) returning to *child*\n", variant);
847 }
848 else
849 {
850 /* disable current and further linetrace experiment resumption */
851 TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue(%s) child calling line_close\n", variant);
852 __collector_ext_line_close ();
853 }
854 __collector_env_print ("fork_epilogue child at end");
855 /* *************************************end child */
856 }
857 else
858 {
859 /* *************************************parent */
860 __collector_env_print ("fork_epilogue parent at start");
861 __collector_ext_dispatcher_thread_timer_resume ();
862 __collector_ext_hwc_lwp_resume ();
863 hrtime_t ts = GETRELTIME ();
864 char msg[256 + LT_MAXPATHLEN];
865 if (ret >= 0)
866 CALL_UTIL (snprintf)(msg, sizeof (msg), "pid=%d", ret);
867 else
868 {
869 /* delete stillborn experiment? */
870 char errmsg[256];
871 strerror_r (errno, errmsg, sizeof (errmsg));
872 CALL_UTIL (snprintf)(msg, sizeof (msg), "err %s", errmsg);
873 }
874 __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" variant=\"%s\" lineage=\"%s\" follow=\"%d\" msg=\"%s\"/>\n",
875 SP_JCMD_DESC_STARTED,
876 (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
877 variant, n_lineage, *following_fork, msg);
878 /* environment remains set for collection */
879 __collector_env_print ("fork_epilogue parent at end");
880 /* *************************************end parent */
881 }
882 dbg_current_mode = FOLLOW_NONE;
883 *following_fork = 0;
884 }
885
886 static char**
887 linetrace_ext_exec_prologue_end (const char *variant, const char* cmd_string,
888 char *const envp[], int following_exec)
889 {
890 char **coll_env;
891 TprintfT (DBG_LT0, "linetrace_ext_exec_prologue_end; variant=%s; cmd_string=%s; follow=%d\n",
892 variant, cmd_string, following_exec);
893 /* write message before suspending, or it won't be written */
894 hrtime_t ts = GETRELTIME ();
895 __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" variant=\"%s\" lineage=\"%s\" follow=\"%d\" msg=\"%s\"/>\n",
896 SP_JCMD_EXEC_START,
897 (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
898 variant, new_lineage, following_exec, cmd_string);
899 if (following_exec)
900 {
901 coll_env = __collector_env_allocate (envp, 0);
902 __collector_env_update (coll_env);
903 extern char **environ; /* the process' actual environment */
904 if (environ == envp) /* user selected process environment */
905 environ = coll_env;
906 }
907 else
908 coll_env = (char**) envp;
909 __collector_env_printall ("linetrace_ext_exec_prologue_end", coll_env);
910 if (!CALL_UTIL (strstr)(variant, "posix_spawn"))
911 {
912 __collector_linetrace_shutdown_hwcs_6830763_XXXX = 1;
913 __collector_suspend_experiment ("suspend_for_exec");
914 __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0;
915 }
916 if (CALL_UTIL (strstr)(variant, "posix_spawn"))
917 {
918 __collector_ext_dispatcher_thread_timer_suspend ();
919 __collector_linetrace_shutdown_hwcs_6830763_XXXX = 1;
920 __collector_ext_hwc_lwp_suspend ();
921 __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0;
922 }
923 return (coll_env);
924 }
925
926 static char**
927 linetrace_ext_exec_prologue (const char *variant,
928 const char* path, char *const argv[],
929 char *const envp[], int *following_exec)
930 {
931 char cmd_string[_POSIX_ARG_MAX] = {'\0'};
932
933 if (dbg_current_mode != FOLLOW_NONE)
934 TprintfT (DBG_LT0, "linetrace_ext_exec_prologue() ERROR: dbg_current_mode=%d, changing to FOLLOW_EXEC!\n", dbg_current_mode);
935 dbg_current_mode = FOLLOW_ON;
936 *following_exec = check_follow_exec (path);
937 if (path != NULL)
938 {
939 /* escape any newline, " or \ characters in the exec command */
940 TprintfT (DBG_LT3, "linetrace_ext_exec_prologue(): arg0=%s\n", path);
941 /* leave space in log message for terminator (and header) */
942 __collector_strlcpy (cmd_string, path, sizeof (cmd_string));
943 size_t len;
944 unsigned argn = 0;
945 if (argv[0])
946 {
947 char *p;
948 while (((p = argv[++argn]) != 0) &&
949 (len = __collector_strlen (cmd_string)) < sizeof (cmd_string) - 2)
950 {
951 cmd_string[len++] = ' ';
952 __collector_strlcpy (cmd_string + len, p, sizeof (cmd_string) - len);
953 }
954 }
955 }
956 TprintfT (DBG_LT0, "linetrace_ext_exec_prologue(%s), lineage=%s, follow=%d, prog=%s, path=%s \n",
957 variant, new_lineage, *following_exec, cmd_string, path);
958 return linetrace_ext_exec_prologue_end (variant, cmd_string, envp, *following_exec);
959 }
960
961 static void
962 linetrace_ext_exec_epilogue (const char *variant, char *const envp[], const int ret, int *following_exec)
963 {
964 /* For exec, this routine is only entered if the exec failed */
965 /* However, posix_spawn() is expected to return */
966 if (dbg_current_mode == FOLLOW_NONE)
967 TprintfT (DBG_LT0, "linetrace_ext_exec_epilogue() ERROR: dbg_current_mode=%d!\n", dbg_current_mode);
968 TprintfT (DBG_LT0, "linetrace_ext_exec_epilogue(%s):%d returned: %d, errno=%d\n",
969 variant, *following_exec, ret, errno);
970 if (!CALL_UTIL (strstr)(variant, "posix_spawn"))
971 {
972 __collector_linetrace_shutdown_hwcs_6830763_XXXX = 1;
973 __collector_resume_experiment ();
974 __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0;
975 }
976 if (CALL_UTIL (strstr)(variant, "posix_spawn"))
977 {
978 __collector_ext_dispatcher_thread_timer_resume ();
979 __collector_linetrace_shutdown_hwcs_6830763_XXXX = 1;
980 __collector_ext_hwc_lwp_resume ();
981 __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0;
982 }
983 hrtime_t ts = GETRELTIME ();
984 char msg[256];
985 if (ret)
986 {
987 char errmsg[256];
988 strerror_r (errno, errmsg, sizeof (errmsg));
989 CALL_UTIL (snprintf)(msg, sizeof (msg), "err %s", errmsg);
990 }
991 else
992 CALL_UTIL (snprintf)(msg, sizeof (msg), "rc=%d", ret);
993 if (!CALL_UTIL (strstr)(variant, "posix_spawn"))
994 __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" variant=\"%s\" lineage=\"%s\" follow=\"%d\" msg=\"%s\"/>\n",
995 SP_JCMD_EXEC_ERROR,
996 (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
997 variant, new_lineage, *following_exec, msg);
998 if (envp == NULL)
999 TprintfT (DBG_LT0, "linetrace_ext_exec_epilogue() ERROR: envp NULL after %s!\n", variant);
1000 dbg_current_mode = FOLLOW_NONE;
1001 *following_exec = 0;
1002 }
1003
1004 static void
1005 linetrace_ext_combo_prologue (const char *variant, const char *cmd, int *following_combo)
1006 {
1007 char cmd_string[_POSIX_ARG_MAX] = {'\0'};
1008 char execfile[_POSIX_ARG_MAX] = {'\0'};
1009
1010 if (dbg_current_mode != FOLLOW_NONE)
1011 TprintfT (DBG_LT0, "linetrace_ext_combo_prologue() ERROR: dbg_current_mode=%d! changing to FOLLOW_ON\n",
1012 dbg_current_mode);
1013 dbg_current_mode = FOLLOW_ON;
1014 if (cmd != NULL)
1015 {
1016 /* extract executable name from combo command */
1017 unsigned len = strcspn (cmd, " ");
1018 __collector_strlcpy (execfile, cmd, len + 1);
1019
1020 /* escape any newline, " or \ characters in the combo command */
1021 /* leave space in log message for terminator (and header) */
1022 __collector_strlcpy (cmd_string, cmd, sizeof (cmd_string));
1023 }
1024
1025 *following_combo = check_follow_combo (execfile);
1026 TprintfT (DBG_LT0, "linetrace_ext_combo_prologue(%s) follow=%d, prog=%s\n\n",
1027 variant, *following_combo, cmd_string);
1028
1029 /* Construct the lineage string for the new image */
1030 new_lineage[0] = 0;
1031 __collector_strcat (new_lineage, "XXX");
1032
1033 /* write message before suspending, or it won't be written */
1034 hrtime_t ts = GETRELTIME ();
1035 __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" variant=\"%s\" lineage=\"%s\" follow=\"%d\" msg=\"%s\"/>\n",
1036 SP_JCMD_DESC_START,
1037 (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
1038 variant, new_lineage, *following_combo, cmd_string);
1039 if (*following_combo)
1040 {
1041 __collector_env_update (NULL);
1042 TprintfT (DBG_LT0, "linetrace_ext_combo_prologue(): Following %s(\"%s\")\n", variant, execfile);
1043 }
1044 __collector_ext_dispatcher_thread_timer_suspend ();
1045 __collector_linetrace_shutdown_hwcs_6830763_XXXX = 1;
1046 __collector_ext_hwc_lwp_suspend ();
1047 __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0;
1048 }
1049
1050 static void
1051 linetrace_ext_combo_epilogue (const char *variant, const int ret, int *following_combo)
1052 {
1053 if (dbg_current_mode == FOLLOW_NONE)
1054 TprintfT (DBG_LT0, "linetrace_ext_combo_epilogue() ERROR: dbg_current_mode=FOLLOW_NONE\n");
1055 TprintfT (DBG_LT0, "linetrace_ext_combo_epilogue(%s):%d() returned %d\n",
1056 variant, *following_combo, ret);
1057 __collector_ext_dispatcher_thread_timer_resume ();
1058 __collector_linetrace_shutdown_hwcs_6830763_XXXX = 1;
1059 __collector_ext_hwc_lwp_resume ();
1060 __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0;
1061 hrtime_t ts = GETRELTIME ();
1062 __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" variant=\"%s\" follow=\"%d\" msg=\"rc=%d\"/>\n",
1063 SP_JCMD_DESC_STARTED,
1064 (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
1065 variant, *following_combo, ret);
1066
1067 dbg_current_mode = FOLLOW_NONE;
1068 *following_combo = 0;
1069 }
1070
1071 /*------------------------------------------------------------- fork */
1072 pid_t fork () __attribute__ ((weak, alias ("__collector_fork")));
1073 pid_t _fork () __attribute__ ((weak, alias ("__collector_fork")));
1074
1075 pid_t
1076 __collector_fork (void)
1077 {
1078 pid_t ret;
1079 if (NULL_PTR (fork))
1080 {
1081 TprintfT (DBG_LT0, "__collector_fork() calling init_lineage_intf()\n");
1082 init_lineage_intf ();
1083 }
1084 __collector_env_print ("__collector_fork start");
1085 int * guard = NULL;
1086 int combo_flag = (line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0;
1087 TprintfT (DBG_LT0, "__collector_fork() interposition: line_mode=%d combo=%d\n",
1088 line_mode, combo_flag);
1089 if ((line_mode != LM_TRACK_LINEAGE) || combo_flag)
1090 {
1091 TprintfT (DBG_LT0, "__collector_fork() not following, returning CALL_REAL(fork)()\n");
1092 return CALL_REAL (fork)();
1093 }
1094 int following_fork = 0;
1095 linetrace_ext_fork_prologue ("fork", new_lineage, &following_fork);
1096
1097 /* since libpthread/fork ends up calling fork1, it's a combo */
1098 PUSH_REENTRANCE (guard);
1099 ret = CALL_REAL (fork)();
1100 POP_REENTRANCE (guard);
1101 linetrace_ext_fork_epilogue ("fork", ret, new_lineage, &following_fork);
1102 return ret;
1103 }
1104
1105 /*------------------------------------------------------------- vfork */
1106 /* vfork interposition in the usual sense is not possible, since vfork(2)
1107 relies on specifics of the stack frames in the parent and child which
1108 only work when the child's exec (or _exit) are in the same stack frame
1109 as the vfork: this isn't the case when there's interposition on exec.
1110 As a workaround, the interposing vfork calls fork1 instead of the real
1111 vfork. Note that fork1 is somewhat less efficient than vfork, and requires
1112 additional memory, which may result in a change of application behaviour
1113 when libcollector is loaded (even when collection is not active),
1114 affecting not only direct use of vfork by the subject application,
1115 but also indirect use through system, popen, and the other combos.
1116 */
1117 pid_t vfork () __attribute__ ((weak, alias ("__collector_vfork")));
1118 pid_t _vfork () __attribute__ ((weak, alias ("__collector_vfork")));
1119
1120 pid_t
1121 __collector_vfork (void)
1122 {
1123 if (NULL_PTR (vfork))
1124 init_lineage_intf ();
1125
1126 int * guard = NULL;
1127 int combo_flag = (line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0;
1128
1129 TprintfT (DBG_LT0, "__collector_vfork() interposing: line_mode=%d combo=%d\n",
1130 line_mode, combo_flag);
1131 if ((line_mode != LM_TRACK_LINEAGE) || combo_flag)
1132 return CALL_REAL (fork)();
1133
1134 /* this warning is also appropriate for combos which use vfork,
1135 however, let's assume this is achieved elsewhere */
1136 (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
1137 COL_WARN_VFORK, "fork");
1138
1139 char new_lineage[LT_MAXNAMELEN];
1140 new_lineage[0] = 0;
1141 int following_fork = 0;
1142 linetrace_ext_fork_prologue ("vfork", new_lineage, &following_fork);
1143
1144 pid_t ret = CALL_REAL (fork)();
1145 linetrace_ext_fork_epilogue ("vfork", ret, new_lineage, &following_fork);
1146 return ret;
1147 }
1148
1149 /*------------------------------------------------------------- execve */
1150 int execve () __attribute__ ((weak, alias ("__collector_execve")));
1151
1152 int
1153 __collector_execve (const char* path, char *const argv[], char *const envp[])
1154 {
1155 static char **coll_env = NULL; /* environment for collection */
1156 if (NULL_PTR (execve))
1157 init_lineage_intf ();
1158 int * guard = NULL;
1159 int combo_flag = (line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0;
1160 TprintfT (DBG_LT0,
1161 "__collector_execve(path=%s, argv[0]=%s, env[0]=%s) interposing: line_mode=%d combo=%d\n",
1162 path ? path : "NULL",
1163 argv ? (argv[0] ? argv[0] : "NULL") : "NULL",
1164 envp ? (envp[0] ? envp[0] : "NULL") : "NULL",
1165 line_mode, combo_flag);
1166 if (line_mode == LM_CLOSED) /* ensure collection environment is sanitised */
1167 __collector_env_unset ((char**) envp);
1168 if (line_mode != LM_TRACK_LINEAGE || combo_flag)
1169 return CALL_REAL (execve)(path, argv, envp);
1170
1171 int following_exec = 0;
1172 coll_env = linetrace_ext_exec_prologue ("execve", path, argv, envp, &following_exec);
1173 TprintfT (DBG_LT2, "__collector_execve(): coll_env=0x%p\n", coll_env);
1174 __collector_env_printall ("__collector_execve", coll_env);
1175 int ret = CALL_REAL (execve)(path, argv, coll_env);
1176 linetrace_ext_exec_epilogue ("execve", envp, ret, &following_exec);
1177 return ret;
1178 }
1179
1180 int execvp () __attribute__ ((weak, alias ("__collector_execvp")));
1181
1182 int
1183 __collector_execvp (const char* file, char *const argv[])
1184 {
1185 extern char **environ; /* the process' actual environment */
1186 char ** envp = environ;
1187 if (NULL_PTR (execvp))
1188 init_lineage_intf ();
1189 int * guard = NULL;
1190 int combo_flag = (line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0;
1191 TprintfT (DBG_LT0,
1192 "__collector_execvp(file=%s, argv[0]=%s) interposing: line_mode=%d combo=%d\n",
1193 file ? file : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL",
1194 line_mode, combo_flag);
1195 if (line_mode == LM_CLOSED) /* ensure collection environment is sanitised */
1196 __collector_env_unset ((char**) envp);
1197 if ((line_mode != LM_TRACK_LINEAGE) || combo_flag)
1198 return CALL_REAL (execvp)(file, argv);
1199
1200 int following_exec = 0;
1201 #ifdef DEBUG
1202 char **coll_env = /* environment for collection */
1203 #endif /* DEBUG */
1204 linetrace_ext_exec_prologue ("execvp", file, argv, envp, &following_exec);
1205 TprintfT (DBG_LT0, "__collector_execvp(): coll_env=0x%p\n", coll_env);
1206
1207 int ret = CALL_REAL (execvp)(file, argv);
1208 linetrace_ext_exec_epilogue ("execvp", envp, ret, &following_exec);
1209 return ret;
1210 }
1211
1212 int execv () __attribute__ ((weak, alias ("__collector_execv")));
1213
1214 int
1215 __collector_execv (const char* path, char *const argv[])
1216 {
1217 int ret;
1218 extern char **environ; /* the process' actual environment */
1219 char ** envp = environ;
1220 TprintfT (DBG_LT0, "__collector_execv(path=%s, argv[0]=%s) interposing: line_mode=%d combo=%d\n",
1221 path ? path : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL",
1222 line_mode, get_combo_flag ());
1223
1224 ret = __collector_execve (path, argv, envp);
1225 return ret;
1226 }
1227
1228 int execle (const char* path, const char *arg0, ...) __attribute__ ((weak, alias ("__collector_execle")));
1229
1230 int
1231 __collector_execle (const char* path, const char *arg0, ...)
1232 {
1233 TprintfT (DBG_LT0,
1234 "__collector_execle(path=%s, arg0=%s) interposing: line_mode=%d combo=%d\n",
1235 path ? path : "NULL", arg0 ? arg0 : "NULL",
1236 line_mode, get_combo_flag ());
1237
1238 char **argp;
1239 va_list args;
1240 char **argvec;
1241 register char **environmentp;
1242 int nargs = 0;
1243 char *nextarg;
1244
1245 va_start (args, arg0);
1246 while (va_arg (args, char *) != (char *) 0)
1247 nargs++;
1248
1249 /*
1250 * save the environment pointer, which is at the end of the
1251 * variable argument list
1252 */
1253 environmentp = va_arg (args, char **);
1254 va_end (args);
1255
1256 /*
1257 * load the arguments in the variable argument list
1258 * into the argument vector, and add the terminating null pointer
1259 */
1260 va_start (args, arg0);
1261 /* workaround for bugid 1242839 */
1262 argvec = (char **) alloca ((size_t) ((nargs + 2) * sizeof (char *)));
1263 argp = argvec;
1264 *argp++ = (char *) arg0;
1265 while ((nextarg = va_arg (args, char *)) != (char *) 0)
1266 *argp++ = nextarg;
1267 va_end (args);
1268 *argp = (char *) 0;
1269 return __collector_execve (path, argvec, environmentp);
1270 }
1271
1272 int execlp (const char* file, const char *arg0, ...) __attribute__ ((weak, alias ("__collector_execlp")));
1273
1274 int
1275 __collector_execlp (const char* file, const char *arg0, ...)
1276 {
1277 TprintfT (DBG_LT0,
1278 "__collector_execlp(file=%s, arg0=%s) interposing: line_mode=%d combo=%d\n",
1279 file ? file : "NULL", arg0 ? arg0 : "NULL",
1280 line_mode, get_combo_flag ());
1281 char **argp;
1282 va_list args;
1283 char **argvec;
1284 int nargs = 0;
1285 char *nextarg;
1286
1287 va_start (args, arg0);
1288 while (va_arg (args, char *) != (char *) 0)
1289 nargs++;
1290 va_end (args);
1291
1292 /*
1293 * load the arguments in the variable argument list
1294 * into the argument vector and add the terminating null pointer
1295 */
1296 va_start (args, arg0);
1297
1298 /* workaround for bugid 1242839 */
1299 argvec = (char **) alloca ((size_t) ((nargs + 2) * sizeof (char *)));
1300 argp = argvec;
1301 *argp++ = (char *) arg0;
1302 while ((nextarg = va_arg (args, char *)) != (char *) 0)
1303 *argp++ = nextarg;
1304 va_end (args);
1305 *argp = (char *) 0;
1306 return __collector_execvp (file, argvec);
1307 }
1308
1309 int execl (const char* path, const char *arg0, ...) __attribute__ ((weak, alias ("__collector_execl")));
1310
1311 int
1312 __collector_execl (const char* path, const char *arg0, ...)
1313 {
1314 TprintfT (DBG_LT0,
1315 "__collector_execl(path=%s, arg0=%s) interposing: line_mode=%d combo=%d\n",
1316 path ? path : "NULL", arg0 ? arg0 : "NULL",
1317 line_mode, get_combo_flag ());
1318 char **argp;
1319 va_list args;
1320 char **argvec;
1321 extern char **environ;
1322 int nargs = 0;
1323 char *nextarg;
1324 va_start (args, arg0);
1325 while (va_arg (args, char *) != (char *) 0)
1326 nargs++;
1327 va_end (args);
1328
1329 /*
1330 * load the arguments in the variable argument list
1331 * into the argument vector and add the terminating null pointer
1332 */
1333 va_start (args, arg0);
1334
1335 /* workaround for bugid 1242839 */
1336 argvec = (char **) alloca ((size_t) ((nargs + 2) * sizeof (char *)));
1337 argp = argvec;
1338 *argp++ = (char *) arg0;
1339 while ((nextarg = va_arg (args, char *)) != (char *) 0)
1340 *argp++ = nextarg;
1341 va_end (args);
1342 *argp = (char *) 0;
1343 return __collector_execve (path, argvec, environ);
1344 }
1345
1346 #include <spawn.h>
1347
1348 /*-------------------------------------------------------- posix_spawn */
1349 #if ARCH(Intel)
1350 // map interposed symbol versions
1351 static int
1352 __collector_posix_spawn_symver (int(real_posix_spawn) (),
1353 pid_t *pidp, const char *path,
1354 const posix_spawn_file_actions_t *file_actions,
1355 const posix_spawnattr_t *attrp,
1356 char *const argv[], char *const envp[]);
1357
1358 SYMVER_ATTRIBUTE (__collector_posix_spawn_2_15, posix_spawn@GLIBC_2.15)
1359 int
1360 __collector_posix_spawn_2_15 (pid_t *pidp, const char *path,
1361 const posix_spawn_file_actions_t *file_actions,
1362 const posix_spawnattr_t *attrp,
1363 char *const argv[], char *const envp[])
1364 {
1365 TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_posix_spawn_2_15@%p(path=%s, argv[0]=%s, env[0]=%s)\n",
1366 CALL_REAL (posix_spawn_2_15), path ? path : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL", envp ? (envp[0] ? envp[0] : "NULL") : "NULL");
1367 if (NULL_PTR (posix_spawn))
1368 init_lineage_intf ();
1369 return __collector_posix_spawn_symver (CALL_REAL (posix_spawn_2_15), pidp,
1370 path, file_actions, attrp, argv, envp);
1371 }
1372
1373 #if WSIZE(32)
1374 SYMVER_ATTRIBUTE (__collector_posix_spawn_2_2, posix_spawn@GLIBC_2.2)
1375 int
1376 __collector_posix_spawn_2_2 (pid_t *pidp, const char *path,
1377 const posix_spawn_file_actions_t *file_actions,
1378 const posix_spawnattr_t *attrp,
1379 char *const argv[], char *const envp[])
1380 {
1381 TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_posix_spawn_2_2@%p(path=%s, argv[0]=%s, env[0]=%s)\n",
1382 CALL_REAL (posix_spawn_2_2), path ? path : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL", envp ? (envp[0] ? envp[0] : "NULL") : "NULL");
1383 if (NULL_PTR (posix_spawn))
1384 init_lineage_intf ();
1385 return __collector_posix_spawn_symver (CALL_REAL (posix_spawn_2_2), pidp,
1386 path, file_actions, attrp, argv, envp);
1387 }
1388
1389 #else /* ^WSIZE(32) */
1390 SYMVER_ATTRIBUTE (__collector_posix_spawn_2_2_5, posix_spawn@GLIBC_2.2.5)
1391 int
1392 __collector_posix_spawn_2_2_5 (pid_t *pidp, const char *path,
1393 const posix_spawn_file_actions_t *file_actions,
1394 const posix_spawnattr_t *attrp,
1395 char *const argv[], char *const envp[])
1396 {
1397 TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_posix_spawn_2_2_5@%p(path=%s, argv[0]=%s, env[0]=%s)\n",
1398 CALL_REAL (posix_spawn_2_2_5), path ? path : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL", envp ? (envp[0] ? envp[0] : "NULL") : "NULL");
1399 if (NULL_PTR (posix_spawn))
1400 init_lineage_intf ();
1401 return __collector_posix_spawn_symver (CALL_REAL (posix_spawn_2_2_5), pidp,
1402 path, file_actions, attrp, argv, envp);
1403 }
1404 #endif /* ^WSIZE(32) */
1405
1406 static int
1407 __collector_posix_spawn_symver (int(real_posix_spawn) (),
1408 #else /* ^ARCH(Intel) */
1409 int
1410 __collector_posix_spawn (
1411 #endif /* ARCH() */
1412 pid_t *pidp, const char *path,
1413 const posix_spawn_file_actions_t *file_actions,
1414 const posix_spawnattr_t *attrp,
1415 char *const argv[], char *const envp[])
1416 {
1417 int ret;
1418 static char **coll_env = NULL; /* environment for collection */
1419 if (NULL_PTR (posix_spawn))
1420 init_lineage_intf ();
1421 if (NULL_PTR (posix_spawn))
1422 {
1423 TprintfT (DBG_LT0, "__collector_posix_spawn(path=%s) interposing: ERROR, posix_spawn() not found by dlsym\n",
1424 path ? path : "NULL");
1425 return -1; /* probably should set errno */
1426 }
1427 int * guard = NULL;
1428 int combo_flag = (line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0;
1429 TprintfT (DBG_LT0, "__collector_posix_spawn(path=%s, argv[0]=%s, env[0]=%s) interposing: line_mode=%d combo=%d\n",
1430 path ? path : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL", envp ? (envp[0] ? envp[0] : "NULL") : "NULL", line_mode, combo_flag);
1431 if (line_mode == LM_CLOSED) /* ensure collection environment is sanitised */
1432 __collector_env_unset ((char**) envp);
1433
1434 if ((line_mode != LM_TRACK_LINEAGE) || combo_flag)
1435 {
1436 #if ARCH(Intel)
1437 return (real_posix_spawn) (pidp, path, file_actions, attrp, argv, envp);
1438 #else
1439 return CALL_REAL (posix_spawn)(pidp, path, file_actions, attrp, argv, envp);
1440 #endif
1441 }
1442 int following_exec = 0;
1443 coll_env = linetrace_ext_exec_prologue ("posix_spawn", path, argv, envp, &following_exec);
1444 TprintfT (DBG_LT0, "__collector_posix_spawn(): coll_env=0x%p\n", coll_env);
1445 __collector_env_printall ("__collector_posix_spawn", coll_env);
1446 PUSH_REENTRANCE (guard);
1447 #if ARCH(Intel)
1448 ret = (real_posix_spawn) (pidp, path, file_actions, attrp, argv, coll_env);
1449 #else
1450 ret = CALL_REAL (posix_spawn)(pidp, path, file_actions, attrp, argv, coll_env);
1451 #endif
1452 POP_REENTRANCE (guard);
1453 linetrace_ext_exec_epilogue ("posix_spawn", envp, ret, &following_exec);
1454 return ret;
1455 }
1456
1457 /*-------------------------------------------------------- posix_spawnp */
1458 #if ARCH(Intel)
1459 // map interposed symbol versions
1460
1461 static int
1462 __collector_posix_spawnp_symver (int(real_posix_spawnp) (), pid_t *pidp,
1463 const char *path,
1464 const posix_spawn_file_actions_t *file_actions,
1465 const posix_spawnattr_t *attrp,
1466 char *const argv[], char *const envp[]);
1467
1468 SYMVER_ATTRIBUTE (__collector_posix_spawnp_2_15, posix_spawnp@GLIBC_2.15)
1469 int // Common interposition
1470 __collector_posix_spawnp_2_15 (pid_t *pidp, const char *path,
1471 const posix_spawn_file_actions_t *file_actions,
1472 const posix_spawnattr_t *attrp,
1473 char *const argv[], char *const envp[])
1474 {
1475 TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_posix_spawnp_2_15@%p(path=%s, argv[0]=%s, env[0]=%s)\n",
1476 CALL_REAL (posix_spawnp_2_15), path ? path : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL", envp ? (envp[0] ? envp[0] : "NULL") : "NULL");
1477 if (NULL_PTR (posix_spawnp))
1478 init_lineage_intf ();
1479 return __collector_posix_spawnp_symver (CALL_REAL (posix_spawnp_2_15), pidp,
1480 path, file_actions, attrp, argv, envp);
1481 }
1482
1483 #if WSIZE(32)
1484
1485 SYMVER_ATTRIBUTE (__collector_posix_spawnp_2_2, posix_spawnp@GLIBC_2.2)
1486 int
1487 __collector_posix_spawnp_2_2 (pid_t *pidp, const char *path,
1488 const posix_spawn_file_actions_t *file_actions,
1489 const posix_spawnattr_t *attrp,
1490 char *const argv[], char *const envp[])
1491 {
1492 TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_posix_spawnp_2_2@%p(path=%s, argv[0]=%s, env[0]=%s)\n",
1493 CALL_REAL (posix_spawnp_2_2), path ? path : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL", envp ? (envp[0] ? envp[0] : "NULL") : "NULL");
1494 if (NULL_PTR (posix_spawnp))
1495 init_lineage_intf ();
1496 return __collector_posix_spawnp_symver (CALL_REAL (posix_spawnp_2_2), pidp,
1497 path, file_actions, attrp, argv, envp);
1498 }
1499
1500 #else /* ^WSIZE(32) */
1501 SYMVER_ATTRIBUTE (__collector_posix_spawnp_2_2_5, posix_spawnp@GLIBC_2.2.5)
1502 int
1503 __collector_posix_spawnp_2_2_5 (pid_t *pidp, const char *path,
1504 const posix_spawn_file_actions_t *file_actions,
1505 const posix_spawnattr_t *attrp,
1506 char *const argv[], char *const envp[])
1507 {
1508 TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_posix_spawnp_2_2_5@%p(path=%s, argv[0]=%s, env[0]=%s)\n",
1509 CALL_REAL (posix_spawnp_2_2_5), path ? path : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL", envp ? (envp[0] ? envp[0] : "NULL") : "NULL");
1510 if (NULL_PTR (posix_spawnp))
1511 init_lineage_intf ();
1512 return __collector_posix_spawnp_symver (CALL_REAL (posix_spawnp_2_2_5), pidp,
1513 path, file_actions, attrp, argv, envp);
1514 }
1515
1516 #endif /* ^WSIZE(32) */
1517
1518 static int
1519 __collector_posix_spawnp_symver (int(real_posix_spawnp) (),
1520 #else /* ^ARCH(Intel) */
1521 int
1522 __collector_posix_spawnp (
1523 #endif /* ARCH() */
1524 pid_t *pidp, const char *path,
1525 const posix_spawn_file_actions_t *file_actions,
1526 const posix_spawnattr_t *attrp,
1527 char *const argv[], char *const envp[]){
1528 int ret;
1529 static char **coll_env = NULL; /* environment for collection */
1530 if (NULL_PTR (posix_spawnp))
1531 init_lineage_intf ();
1532 if (NULL_PTR (posix_spawnp))
1533 {
1534 TprintfT (DBG_LT0, "__collector_posix_spawnp(path=%s) interposing: ERROR, posix_spawnp() not found by dlsym\n",
1535 path ? path : "NULL");
1536 return -1; /* probably should set errno */
1537 }
1538 int * guard = NULL;
1539 int combo_flag = (line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0;
1540 TprintfT (DBG_LT0, "__collector_posix_spawnp(path=%s, argv[0]=%s, env[0]=%s) interposing: line_mode=%d combo=%d\n",
1541 path ? path : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL",
1542 envp ? (envp[0] ? envp[0] : "NULL") : "NULL", line_mode, combo_flag);
1543
1544 if (line_mode == LM_CLOSED) /* ensure collection environment is sanitised */
1545 __collector_env_unset ((char**) envp);
1546 if (line_mode != LM_TRACK_LINEAGE || combo_flag)
1547 {
1548 #if ARCH(Intel)
1549 return (real_posix_spawnp) (pidp, path, file_actions, attrp, argv, envp);
1550 #else
1551 return CALL_REAL (posix_spawnp)(pidp, path, file_actions, attrp, argv, envp);
1552 #endif
1553 }
1554 int following_exec = 0;
1555 coll_env = linetrace_ext_exec_prologue ("posix_spawnp", path, argv, envp, &following_exec);
1556 TprintfT (DBG_LT0, "__collector_posix_spawnp(): coll_env=0x%p\n", coll_env);
1557 __collector_env_printall ("__collector_posix_spawnp", coll_env);
1558 PUSH_REENTRANCE (guard);
1559 #if ARCH(Intel)
1560 ret = (real_posix_spawnp) (pidp, path, file_actions, attrp, argv, coll_env);
1561 #else
1562 ret = CALL_REAL (posix_spawnp)(pidp, path, file_actions, attrp, argv, coll_env);
1563 #endif
1564 POP_REENTRANCE (guard);
1565 linetrace_ext_exec_epilogue ("posix_spawnp", envp, ret, &following_exec);
1566 return ret;
1567 }
1568
1569 /*------------------------------------------------------------- system */
1570 int system () __attribute__ ((weak, alias ("__collector_system")));
1571
1572 int
1573 __collector_system (const char *cmd)
1574 {
1575 if (NULL_PTR (system))
1576 init_lineage_intf ();
1577 TprintfT (DBG_LT0,
1578 "__collector_system(cmd=%s) interposing: line_mode=%d combo=%d\n",
1579 cmd ? cmd : "NULL", line_mode, get_combo_flag ());
1580 int *guard = NULL;
1581 if (line_mode == LM_TRACK_LINEAGE)
1582 INIT_REENTRANCE (guard);
1583 if (guard == NULL)
1584 return CALL_REAL (system)(cmd);
1585 int following_combo = 0;
1586 linetrace_ext_combo_prologue ("system", cmd, &following_combo);
1587 PUSH_REENTRANCE (guard);
1588 int ret = CALL_REAL (system)(cmd);
1589 POP_REENTRANCE (guard);
1590 linetrace_ext_combo_epilogue ("system", ret, &following_combo);
1591 return ret;
1592 }
1593
1594 /*------------------------------------------------------------- popen */
1595 // map interposed symbol versions
1596 #if ARCH(Intel) && WSIZE(32)
1597 static FILE *
1598 __collector_popen_symver (FILE*(real_popen) (), const char *cmd, const char *mode);
1599
1600 SYMVER_ATTRIBUTE (__collector_popen_2_1, popen@GLIBC_2.1)
1601 FILE *
1602 __collector_popen_2_1 (const char *cmd, const char *mode)
1603 {
1604 if (NULL_PTR (popen))
1605 init_lineage_intf ();
1606 TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_popen_2_1@%p\n", CALL_REAL (popen_2_1));
1607 return __collector_popen_symver (CALL_REALF (popen_2_1), cmd, mode);
1608 }
1609
1610 SYMVER_ATTRIBUTE (__collector_popen_2_0, popen@GLIBC_2.0)
1611 FILE *
1612 __collector_popen_2_0 (const char *cmd, const char *mode)
1613 {
1614 if (NULL_PTR (popen))
1615 init_lineage_intf ();
1616 TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_popen_2_0@%p\n", CALL_REAL (popen_2_0));
1617 return __collector_popen_symver (CALL_REALF (popen_2_0), cmd, mode);
1618 }
1619
1620 SYMVER_ATTRIBUTE (__collector__popen_2_1, _popen@GLIBC_2.1)
1621 FILE *
1622 __collector__popen_2_1 (const char *cmd, const char *mode)
1623 {
1624 if (NULL_PTR (popen))
1625 init_lineage_intf ();
1626 TprintfT (DBG_LTT, "linetrace: GLIBC: __collector__popen_2_1@%p\n", CALL_REAL (popen_2_1));
1627 return __collector_popen_symver (CALL_REALF (popen_2_1), cmd, mode);
1628 }
1629
1630 SYMVER_ATTRIBUTE (__collector__popen_2_0, _popen@GLIBC_2.0)
1631 FILE *
1632 __collector__popen_2_0 (const char *cmd, const char *mode)
1633 {
1634 if (NULL_PTR (popen))
1635 init_lineage_intf ();
1636 return __collector_popen_symver (CALL_REALF (popen_2_0), cmd, mode);
1637 }
1638 #else // WSIZE(64)
1639 FILE * popen () __attribute__ ((weak, alias ("__collector_popen")));
1640 #endif
1641
1642 #if ARCH(Intel) && WSIZE(32)
1643 static FILE *
1644 __collector_popen_symver (FILE*(real_popen) (), const char *cmd, const char *mode)
1645 #else
1646
1647 FILE *
1648 __collector_popen (const char *cmd, const char *mode)
1649 #endif
1650 {
1651 FILE *ret;
1652 if (NULL_PTR (popen))
1653 init_lineage_intf ();
1654 TprintfT (DBG_LT0,
1655 "__collector_popen(cmd=%s) interposing: line_mode=%d combo=%d\n",
1656 cmd ? cmd : "NULL", line_mode, get_combo_flag ());
1657 int *guard = NULL;
1658 if (line_mode == LM_TRACK_LINEAGE)
1659 INIT_REENTRANCE (guard);
1660 if (guard == NULL)
1661 {
1662 #if ARCH(Intel) && WSIZE(32)
1663 return (real_popen) (cmd, mode);
1664 #else
1665 return CALL_REALF (popen)(cmd, mode);
1666 #endif
1667 }
1668 int following_combo = 0;
1669 linetrace_ext_combo_prologue ("popen", cmd, &following_combo);
1670 PUSH_REENTRANCE (guard);
1671 #if ARCH(Intel) && WSIZE(32)
1672 ret = (real_popen) (cmd, mode);
1673 #else
1674 ret = CALL_REALF (popen)(cmd, mode);
1675 #endif
1676 POP_REENTRANCE (guard);
1677 linetrace_ext_combo_epilogue ("popen", (ret == NULL) ? (-1) : 0, &following_combo);
1678 return ret;
1679 }
1680
1681 /*------------------------------------------------------------- grantpt */
1682 int grantpt () __attribute__ ((weak, alias ("__collector_grantpt")));
1683
1684 int
1685 __collector_grantpt (const int fildes)
1686 {
1687 if (NULL_PTR (grantpt))
1688 init_lineage_intf ();
1689 TprintfT (DBG_LT0,
1690 "__collector_grantpt(%d) interposing: line_mode=%d combo=%d\n",
1691 fildes, line_mode, get_combo_flag ());
1692 int *guard = NULL;
1693 if (line_mode == LM_TRACK_LINEAGE)
1694 INIT_REENTRANCE (guard);
1695 if (guard == NULL)
1696 return CALL_REAL (grantpt)(fildes);
1697 int following_combo = 0;
1698 linetrace_ext_combo_prologue ("grantpt", "/usr/lib/pt_chmod", &following_combo);
1699 PUSH_REENTRANCE (guard);
1700 int ret = CALL_REAL (grantpt)(fildes);
1701 POP_REENTRANCE (guard);
1702 linetrace_ext_combo_epilogue ("grantpt", ret, &following_combo);
1703 return ret;
1704 }
1705
1706 /*------------------------------------------------------------- ptsname */
1707 char *ptsname () __attribute__ ((weak, alias ("__collector_ptsname")));
1708
1709 char *
1710 __collector_ptsname (const int fildes)
1711 {
1712 if (NULL_PTR (ptsname))
1713 init_lineage_intf ();
1714 TprintfT (DBG_LT0,
1715 "__collector_ptsname(%d) interposing: line_mode=%d combo=%d\n",
1716 fildes, line_mode, get_combo_flag ());
1717 int *guard = NULL;
1718 if (line_mode == LM_TRACK_LINEAGE)
1719 INIT_REENTRANCE (guard);
1720 if (guard == NULL)
1721 return CALL_REALC (ptsname)(fildes);
1722 int following_combo = 0;
1723 linetrace_ext_combo_prologue ("ptsname", "/usr/lib/pt_chmod", &following_combo);
1724 PUSH_REENTRANCE (guard);
1725 char *ret = CALL_REALC (ptsname)(fildes);
1726 POP_REENTRANCE (guard);
1727 linetrace_ext_combo_epilogue ("ptsname", (ret == NULL) ? (-1) : 1, &following_combo);
1728 return ret;
1729 }
1730
1731 /*------------------------------------------------------------- clone */
1732 /* clone can be fork-like or pthread_create-like, depending on whether
1733 * the flag CLONE_VM is set. If CLONE_VM is not set, then we interpose
1734 * clone in the way similar to interposing fork; if CLONE_VM is set,
1735 * then we interpose clone in the way similar to interposing pthread_create.
1736 * One special case is not handled: when CLONE_VM is set but CLONE_THREAD
1737 * is not, if the parent process exits earlier than the child process,
1738 * experiment will close, losing data from child process.
1739 */
1740 typedef struct __collector_clone_arg
1741 {
1742 int (*fn)(void *);
1743 void * arg;
1744 char * new_lineage;
1745 int following_fork;
1746 } __collector_clone_arg_t;
1747
1748 static int
1749 __collector_clone_fn (void *fn_arg)
1750 {
1751 int (*fn)(void *) = ((__collector_clone_arg_t*) fn_arg)->fn;
1752 void * arg = ((__collector_clone_arg_t*) fn_arg)->arg;
1753 char * new_lineage = ((__collector_clone_arg_t*) fn_arg)->new_lineage;
1754 int following_fork = ((__collector_clone_arg_t*) fn_arg)->following_fork;
1755 __collector_freeCSize (__collector_heap, fn_arg, sizeof (__collector_clone_arg_t));
1756 linetrace_ext_fork_epilogue ("clone", 0, new_lineage, &following_fork);
1757 return fn (arg);
1758 }
1759
1760 int clone (int (*fn)(void *), void *, int, void *, ...) __attribute__ ((weak, alias ("__collector_clone")));
1761
1762 int
1763 __collector_clone (int (*fn)(void *), void *child_stack, int flags, void *arg,
1764 ... /* pid_t *ptid, struct user_desc *tls, pid_t *" ctid" */)
1765 {
1766 int ret;
1767 va_list va;
1768 if (flags & CLONE_VM)
1769 {
1770 va_start (va, arg);
1771 ret = __collector_ext_clone_pthread (fn, child_stack, flags, arg, va);
1772 va_end (va);
1773 }
1774 else
1775 {
1776 if (NULL_PTR (clone))
1777 init_lineage_intf ();
1778 int *guard = NULL;
1779 int combo_flag = (line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0;
1780 TprintfT (DBG_LT0, "__collector_clone() interposition: line_mode=%d combo=%d\n",
1781 line_mode, combo_flag);
1782 char new_lineage[LT_MAXNAMELEN];
1783 int following_fork = 0;
1784 __collector_clone_arg_t *funcinfo = __collector_allocCSize (__collector_heap, sizeof (__collector_clone_arg_t), 1);
1785 (*funcinfo).fn = fn;
1786 (*funcinfo).arg = arg;
1787 (*funcinfo).new_lineage = new_lineage;
1788 (*funcinfo).following_fork = 0;
1789 pid_t * ptid = NULL;
1790 struct user_desc * tls = NULL;
1791 pid_t * ctid = NULL;
1792 int num_args = 0;
1793 va_start (va, arg);
1794 if (flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID))
1795 {
1796 ptid = va_arg (va, pid_t *);
1797 tls = va_arg (va, struct user_desc*);
1798 ctid = va_arg (va, pid_t *);
1799 num_args = 3;
1800 }
1801 else if (flags & CLONE_SETTLS)
1802 {
1803 ptid = va_arg (va, pid_t *);
1804 tls = va_arg (va, struct user_desc*);
1805 num_args = 2;
1806 }
1807 else if (flags & CLONE_PARENT_SETTID)
1808 {
1809 ptid = va_arg (va, pid_t *);
1810 num_args = 1;
1811 }
1812 if ((line_mode != LM_TRACK_LINEAGE) || combo_flag || funcinfo == NULL)
1813 {
1814 switch (num_args)
1815 {
1816 case 3:
1817 ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid, tls, ctid);
1818 break;
1819 case 2:
1820 ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid, tls);
1821 break;
1822 case 1:
1823 ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid);
1824 break;
1825 default:
1826 ret = CALL_REAL (clone)(fn, child_stack, flags, arg);
1827 break;
1828 }
1829
1830 va_end (va);
1831 return ret;
1832 }
1833 linetrace_ext_fork_prologue ("clone", new_lineage, &following_fork);
1834 (*funcinfo).following_fork = following_fork;
1835 switch (num_args)
1836 {
1837 case 3:
1838 ret = CALL_REAL (clone)(__collector_clone_fn, child_stack, flags, funcinfo, ptid, tls, ctid);
1839 break;
1840 case 2:
1841 ret = CALL_REAL (clone)(__collector_clone_fn, child_stack, flags, funcinfo, ptid, tls);
1842 break;
1843 case 1:
1844 ret = CALL_REAL (clone)(__collector_clone_fn, child_stack, flags, funcinfo, ptid);
1845 break;
1846 default:
1847 ret = CALL_REAL (clone)(__collector_clone_fn, child_stack, flags, funcinfo);
1848 break;
1849 }
1850 va_end (va);
1851 if (ret < 0)
1852 __collector_freeCSize (__collector_heap, funcinfo, sizeof (__collector_clone_arg_t));
1853 TprintfT (DBG_LT0, "__collector_clone() interposing: pid=%d\n", ret);
1854 linetrace_ext_fork_epilogue ("clone", ret, new_lineage, &following_fork);
1855 }
1856 return ret;
1857 }
1858
1859 /*-------------------------------------------------------------------- setuid */
1860 int setuid () __attribute__ ((weak, alias ("__collector_setuid")));
1861 int _setuid () __attribute__ ((weak, alias ("__collector_setuid")));
1862
1863 int
1864 __collector_setuid (uid_t ruid)
1865 {
1866 if (NULL_PTR (setuid))
1867 init_lineage_intf ();
1868 TprintfT (DBG_LT0, "__collector_setuid(0x%x) interposing\n", ruid);
1869 check_reuid_change (ruid, -1);
1870 int ret = CALL_REAL (setuid)(ruid);
1871 TprintfT (DBG_LT0, "__collector_setuid(0x%x) returning %d\n", ruid, ret);
1872 return ret;
1873 }
1874
1875 /*------------------------------------------------------------------- seteuid */
1876 int seteuid () __attribute__ ((weak, alias ("__collector_seteuid")));
1877 int _seteuid () __attribute__ ((weak, alias ("__collector_seteuid")));
1878
1879 int
1880 __collector_seteuid (uid_t euid)
1881 {
1882 if (NULL_PTR (seteuid))
1883 init_lineage_intf ();
1884 TprintfT (DBG_LT0, "__collector_seteuid(0x%x) interposing\n", euid);
1885 check_reuid_change (-1, euid);
1886 int ret = CALL_REAL (seteuid)(euid);
1887 TprintfT (DBG_LT0, "__collector_seteuid(0x%x) returning %d\n", euid, ret);
1888 return ret;
1889 }
1890
1891 /*------------------------------------------------------------------ setreuid */
1892 int setreuid () __attribute__ ((weak, alias ("__collector_setreuid")));
1893 int _setreuid () __attribute__ ((weak, alias ("__collector_setreuid")));
1894
1895 int
1896 __collector_setreuid (uid_t ruid, uid_t euid)
1897 {
1898 if (NULL_PTR (setreuid))
1899 init_lineage_intf ();
1900 TprintfT (DBG_LT0, "__collector_setreuid(0x%x,0x%x) interposing\n", ruid, euid);
1901 check_reuid_change (ruid, euid);
1902 int ret = CALL_REAL (setreuid)(ruid, euid);
1903 TprintfT (DBG_LT0, "__collector_setreuid(0x%x,0x%x) returning %d\n", ruid, euid, ret);
1904 return ret;
1905 }
1906
1907 /*-------------------------------------------------------------------- setgid */
1908 int setgid () __attribute__ ((weak, alias ("__collector_setgid")));
1909 int _setgid () __attribute__ ((weak, alias ("__collector_setgid")));
1910
1911 int
1912 __collector_setgid (gid_t rgid)
1913 {
1914 if (NULL_PTR (setgid))
1915 init_lineage_intf ();
1916 TprintfT (DBG_LT0, "__collector_setgid(0x%x) interposing\n", rgid);
1917 check_regid_change (rgid, -1);
1918 int ret = CALL_REAL (setgid)(rgid);
1919 TprintfT (DBG_LT0, "__collector_setgid(0x%x) returning %d\n", rgid, ret);
1920 return ret;
1921 }
1922
1923 /*------------------------------------------------------------------- setegid */
1924 int setegid () __attribute__ ((weak, alias ("__collector_setegid")));
1925 int _setegid () __attribute__ ((weak, alias ("__collector_setegid")));
1926
1927 int
1928 __collector_setegid (gid_t egid)
1929 {
1930 if (NULL_PTR (setegid))
1931 init_lineage_intf ();
1932 TprintfT (DBG_LT0, "__collector_setegid(0x%x) interposing\n", egid);
1933 check_regid_change (-1, egid);
1934 int ret = CALL_REAL (setegid)(egid);
1935 TprintfT (DBG_LT0, "__collector_setegid(0x%x) returning %d\n", egid, ret);
1936 return ret;
1937 }
1938
1939 /*------------------------------------------------------------------ setregid */
1940 int setregid () __attribute__ ((weak, alias ("__collector_setregid")));
1941 int _setregid () __attribute__ ((weak, alias ("__collector_setregid")));
1942
1943 int
1944 __collector_setregid (gid_t rgid, gid_t egid)
1945 {
1946 if (NULL_PTR (setregid))
1947 init_lineage_intf ();
1948 TprintfT (DBG_LT0, "__collector_setregid(0x%x,0x%x) interposing\n", rgid, egid);
1949 check_regid_change (rgid, egid);
1950 int ret = CALL_REAL (setregid)(rgid, egid);
1951 TprintfT (DBG_LT0, "__collector_setregid(0x%x,0x%x) returning %d\n", rgid, egid, ret);
1952 return ret;
1953 }
1954
1955 /*------------------------------------------------------- selective following */
1956
1957 static int
1958 linetrace_follow_experiment (const char *follow_spec, const char *lineage_str, const char *progname)
1959 {
1960 regex_t regex_desc;
1961 if (!follow_spec)
1962 {
1963 TprintfT (DBG_LT0, "linetrace_follow_experiment(): MATCHES NULL follow_spec\n");
1964 return 1;
1965 }
1966 int ercode = regcomp (&regex_desc, follow_spec, REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
1967 if (ercode)
1968 {
1969 // syntax error in parsing string
1970 #ifdef DEBUG
1971 char errbuf[256];
1972 regerror (ercode, &regex_desc, errbuf, sizeof (errbuf));
1973 TprintfT (DBG_LT0, "linetrace_follow_experiment: regerror()=%s\n", errbuf);
1974 #endif
1975 return 1;
1976 }
1977 TprintfT (DBG_LT0, "linetrace_follow_experiment(): compiled spec='%s'\n", follow_spec);
1978 if (lineage_str)
1979 {
1980 if (!regexec (&regex_desc, lineage_str, 0, NULL, 0))
1981 {
1982 TprintfT (DBG_LT0, "linetrace_follow_experiment(): MATCHES lineage (follow_spec=%s,lineage=%s)\n",
1983 follow_spec, lineage_str);
1984 return 1;
1985 }
1986 }
1987 if (progname)
1988 {
1989 if (!regexec (&regex_desc, progname, 0, NULL, 0))
1990 {
1991 TprintfT (DBG_LT0, "linetrace_follow_experiment(): MATCHES progname (follow_spec=%s,progname=%s)\n",
1992 follow_spec, progname);
1993 return 1;
1994 }
1995 }
1996 TprintfT (DBG_LT0, "linetrace_follow_experiment(): DOES NOT MATCH (follow_spec=%s,lineage=%s,progname=%s)\n",
1997 follow_spec, lineage_str ? lineage_str : "NULL",
1998 progname ? progname : "NULL");
1999 return 0;
2000 }