Add documentation for the MIPS assembler's -march=from-abi command line option
[binutils-gdb.git] / gprofng / libcollector / linetrace.c
blob917bc95f6c9f722b5e13ff5f12bd76124426ed12
1 /* Copyright (C) 2021-2023 Free Software Foundation, Inc.
2 Contributed by Oracle.
4 This file is part of GNU Binutils.
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.
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.
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. */
22 * Lineage events for process fork, exec, etc.
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 #include <spawn.h>
35 #include "descendants.h"
37 #define LT_MAXNAMELEN 1024
38 #define LT_MAXPATHLEN 1024
40 int __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0;
41 int dbg_current_mode = FOLLOW_NONE; /* for debug only */
42 unsigned line_key = COLLECTOR_TSD_INVALID_KEY;
43 line_mode_t line_mode = LM_DORMANT;
44 int user_follow_mode = FOLLOW_ON;
45 int java_mode = 0;
47 static char *user_follow_spec;
48 static char new_lineage[LT_MAXNAMELEN];
49 static char curr_lineage[LT_MAXNAMELEN];
50 static char linetrace_exp_dir_name[LT_MAXPATHLEN + 1]; // experiment directory
52 /* lineage tracking for descendants of this process */
54 static int fork_linenum = 0;
55 static int line_initted = 0;
56 static collector_mutex_t fork_lineage_lock = COLLECTOR_MUTEX_INITIALIZER;
57 static collector_mutex_t clone_lineage_lock = COLLECTOR_MUTEX_INITIALIZER;
59 // For a given Linux, which lib functions have more than one GLIBC version? Do this:
60 // objdump -T `find /lib /lib64 -name "*.so*"` | grep GLIBC | grep text | grep \(
61 static pid_t (*__real_fork) (void) = NULL;
62 static pid_t (*__real_vfork) (void) = NULL;
63 static int (*__real_execve) (const char *file, char *const argv[],
64 char *const envp[]) = NULL;
65 static int (*__real_execvp) (const char *file, char *const argv[]) = NULL;
66 static int (*__real_execv) (const char *file, char *const argv[]) = NULL;
67 static int (*__real_execle) (const char *path, const char *arg, ...) = NULL;
68 static int (*__real_execlp) (const char *file, const char *arg, ...) = NULL;
69 static int (*__real_execl) (const char *file, const char *arg, ...) = NULL;
70 static int (*__real_clone) (int (*fn) (void *), void *child_stack,
71 int flags, void *arg, ...) = NULL;
72 static int (*__real_grantpt) (int fd) = NULL;
73 static char *(*__real_ptsname) (int fd) = NULL;
74 static FILE *(*__real_popen) (const char *command, const char *type) = NULL;
75 static int clone_linenum = 0;
76 static FILE *(*__real_popen_2_17) (const char *command, const char *type) = NULL;
77 static FILE *(*__real_popen_2_2_5) (const char *command, const char *type) = NULL;
78 static FILE *(*__real_popen_2_1) (const char *command, const char *type) = NULL;
79 static FILE *(*__real_popen_2_0) (const char *command, const char *type) = NULL;
81 static int (*__real_posix_spawn_2_17) (pid_t *pid, const char *path,
82 const posix_spawn_file_actions_t *file_actions,
83 const posix_spawnattr_t *attrp,
84 char *const argv[], char *const envp[]) = NULL;
85 static int (*__real_posix_spawn_2_15) (pid_t *pid, const char *path,
86 const posix_spawn_file_actions_t *file_actions,
87 const posix_spawnattr_t *attrp,
88 char *const argv[], char *const envp[]) = NULL;
89 static int (*__real_posix_spawn_2_2_5) (pid_t *pid, const char *path,
90 const posix_spawn_file_actions_t *file_actions,
91 const posix_spawnattr_t *attrp,
92 char *const argv[], char *const envp[]) = NULL;
93 static int (*__real_posix_spawn_2_2) (pid_t *pid, const char *path,
94 const posix_spawn_file_actions_t *file_actions,
95 const posix_spawnattr_t *attrp,
96 char *const argv[], char *const envp[]) = NULL;
98 static int (*__real_posix_spawnp_2_17) (pid_t *pid, const char *file,
99 const posix_spawn_file_actions_t *file_actions,
100 const posix_spawnattr_t *attrp,
101 char *const argv[], char *const envp[]) = NULL;
102 static int (*__real_posix_spawnp_2_15) (pid_t *pid, const char *file,
103 const posix_spawn_file_actions_t *file_actions,
104 const posix_spawnattr_t *attrp,
105 char *const argv[], char *const envp[]) = NULL;
106 static int (*__real_posix_spawnp_2_2_5) (pid_t *pid, const char *file,
107 const posix_spawn_file_actions_t *file_actions,
108 const posix_spawnattr_t *attrp,
109 char *const argv[], char *const envp[]) = NULL;
110 static int (*__real_posix_spawnp_2_2) (pid_t *pid, const char *file,
111 const posix_spawn_file_actions_t *file_actions,
112 const posix_spawnattr_t *attrp,
113 char *const argv[], char *const envp[]) = NULL;
114 static int (*__real_system) (const char *command) = NULL;
115 static int (*__real_posix_spawn) (pid_t *pid, const char *path,
116 const posix_spawn_file_actions_t *file_actions,
117 const posix_spawnattr_t *attrp,
118 char *const argv[], char *const envp[]) = NULL;
119 static int (*__real_posix_spawnp) (pid_t *pid, const char *file,
120 const posix_spawn_file_actions_t *file_actions,
121 const posix_spawnattr_t *attrp,
122 char *const argv[], char *const envp[]) = NULL;
123 static int (*__real_setuid) (uid_t uid) = NULL;
124 static int (*__real_seteuid) (uid_t euid) = NULL;
125 static int (*__real_setreuid) (uid_t ruid, uid_t euid) = NULL;
126 static int (*__real_setgid) (gid_t gid) = NULL;
127 static int (*__real_setegid) (gid_t egid) = NULL;
128 static int (*__real_setregid) (gid_t rgid, gid_t egid)= NULL;
129 static void linetrace_dormant ();
130 static int check_follow_fork ();
131 static int check_follow_exec (const char *execfile);
132 static int check_follow_combo (const char *execfile);
133 static int path_collectable (const char *execfile);
134 static char * build_experiment_path (char *instring, size_t instring_sz, const char *lineage_str);
135 static int init_lineage_intf ();
137 /* ------- "Previously dbx-visible" function prototypes ----------------- */
138 static int linetrace_follow_experiment (const char *follow_spec, const char *lineage_str, const char *execfile);
139 static char *lineage_from_expname (char *lineage_str, size_t lstr_sz, const char *expname);
140 static void linetrace_ext_fork_prologue (const char *variant, char * new_lineage, int *following_fork);
141 static void linetrace_ext_fork_epilogue (const char *variant, const pid_t ret, char * new_lineage, int *following_fork);
142 static char **linetrace_ext_exec_prologue (const char *variant,
143 const char* path, char *const argv[], char *const envp[], int *following_exec);
144 static void linetrace_ext_exec_epilogue (const char *variant, char *const envp[], const int ret, int *following_exec);
145 static void linetrace_ext_combo_prologue (const char *variant, const char *cmd, int *following_combo);
146 static void linetrace_ext_combo_epilogue (const char *variant, const int ret, int *following_combo);
148 #ifdef DEBUG
149 static int
150 get_combo_flag ()
152 int * guard = NULL;
153 int combo_flag = ((line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0);
154 return combo_flag;
156 #endif /* DEBUG */
158 /* must be called for potentially live experiment */
160 __collector_ext_line_init (int *precord_this_experiment,
161 const char * progspec, const char * progname)
163 *precord_this_experiment = 1;
164 TprintfT (DBG_LT0, "__collector_ext_line_init(%s)\n", progspec);
165 if (NULL_PTR (fork))
166 if (init_lineage_intf ())
168 TprintfT (DBG_LT0, "__collector_ext_line_init() ERROR: initialization failed.\n");
169 return COL_ERROR_LINEINIT;
171 /* check the follow spec */
172 user_follow_spec = CALL_UTIL (getenv)(SP_COLLECTOR_FOLLOW_SPEC);
173 if (user_follow_spec != NULL)
175 TprintfT (DBG_LT0, "collector: %s=%s\n", SP_COLLECTOR_FOLLOW_SPEC, user_follow_spec);
176 if (!linetrace_follow_experiment (user_follow_spec, curr_lineage, progname))
178 *precord_this_experiment = 0;
179 TprintfT (DBG_LT0, "collector: -F =<regex> does not match, will NOT be followed\n");
181 else
182 TprintfT (DBG_LT0, "collector: -F =<regex> matches, will be followed\n");
183 user_follow_mode = FOLLOW_ALL;
185 __collector_env_save_preloads ();
186 TprintfT (DBG_LT0, "__collector_ext_line_init(), progname=%s, followspec=%s, followthis=%d\n",
187 progname, user_follow_spec ? user_follow_spec : "NULL",
188 *precord_this_experiment);
189 line_mode = LM_TRACK_LINEAGE; /* even if we don't follow, we report the interposition */
190 line_initted = 1;
191 return COL_ERROR_NONE;
195 * int __collector_ext_line_install(args)
196 * Check args to determine which line events to follow.
197 * Create tsd key for combo flag.
200 __collector_ext_line_install (char *args, const char * expname)
202 if (!line_initted)
204 TprintfT (DBG_LT0, "__collector_ext_line_install(%s) ERROR: init hasn't be called yet\n", args);
205 return COL_ERROR_EXPOPEN;
207 TprintfT (DBG_LT0, "__collector_ext_line_install(%s, %s)\n", args, expname);
208 line_key = __collector_tsd_create_key (sizeof (int), NULL, NULL);
210 /* determine experiment name */
211 __collector_strlcpy (linetrace_exp_dir_name, expname, sizeof (linetrace_exp_dir_name));
212 lineage_from_expname (curr_lineage, sizeof (curr_lineage), linetrace_exp_dir_name);
213 user_follow_mode = CALL_UTIL (atoi)(args);
214 TprintfT (DBG_LT0, "__collector_ext_line_install() user_follow_mode=0x%X, linetrace_exp_dir_name=%s\n",
215 user_follow_mode, linetrace_exp_dir_name);
217 // determine java mode
218 char * java_follow_env = CALL_UTIL (getenv)(JAVA_TOOL_OPTIONS);
219 if (java_follow_env != NULL && CALL_UTIL (strstr)(java_follow_env, COLLECTOR_JVMTI_OPTION))
220 java_mode = 1;
222 // backup collector specific env
223 if (sp_env_backup == NULL)
225 sp_env_backup = __collector_env_backup ();
226 TprintfT (DBG_LT0, "__collector_ext_line_install creating sp_env_backup -- 0x%p\n", sp_env_backup);
228 else
229 TprintfT (DBG_LT0, "__collector_ext_line_install existing sp_env_backup -- 0x%p\n", sp_env_backup);
230 if (user_follow_mode == FOLLOW_NONE)
231 __collector_env_unset (NULL);
233 char logmsg[256];
234 logmsg[0] = '\0';
235 if (user_follow_mode != FOLLOW_NONE)
236 CALL_UTIL (strlcat)(logmsg, "fork|exec|combo", sizeof (logmsg));
237 size_t slen = __collector_strlen (logmsg);
238 if (slen > 0)
239 logmsg[slen] = '\0';
240 else
241 CALL_UTIL (strlcat)(logmsg, "none", sizeof (logmsg));
243 /* report which line events are followed */
244 (void) __collector_log_write ("<setting %s=\"%s\"/>\n", SP_JCMD_LINETRACE, logmsg);
245 TprintfT (DBG_LT0, "__collector_ext_line_install(%s): %s \n", expname, logmsg);
246 return COL_ERROR_NONE;
249 char *
250 lineage_from_expname (char *lineage_str, size_t lstr_sz, const char *expname)
252 TprintfT (DBG_LT0, "lineage_from_expname(%s, %s)\n", lineage_str, expname);
253 char *p = NULL;
254 if (lstr_sz < 1 || !lineage_str || !expname)
256 TprintfT (DBG_LT0, "lineage_from_expname(): ERROR, null string\n");
257 return NULL;
259 /* determine lineage from experiment name */
260 p = __collector_strrchr (expname, '/');
261 if ((p == NULL) || (*++p != '_'))
263 lineage_str[0] = 0;
264 TprintfT (DBG_LT2, "lineage_from_expname(): expt=%s lineage=\".\" (founder)\n", expname);
266 else
268 size_t tmp = __collector_strlcpy (lineage_str, p, lstr_sz);
269 if (tmp >= lstr_sz)
270 TprintfT (DBG_LT0, "lineage_from_expname(): ERROR: expt=%s lineage=\"%s\" truncated %ld characters\n",
271 expname, lineage_str, (long) (tmp - lstr_sz));
272 lineage_str[lstr_sz - 1] = 0;
273 p = __collector_strchr (lineage_str, '.');
274 if (p != NULL)
275 *p = '\0';
276 TprintfT (DBG_LT2, "lineage_from_expname(): expt=%s lineage=\"%s\"\n", expname, lineage_str);
278 return lineage_str;
282 * void __collector_line_cleanup (void)
283 * Disable logging. Clear backup ENV.
285 void
286 __collector_line_cleanup (void)
288 if (line_mode == LM_CLOSED)
290 TprintfT (DBG_LT0, "__collector_line_cleanup(): WARNING, line is already closed\n");
291 return;
293 else if (line_mode == LM_DORMANT)
294 TprintfT (DBG_LT0, "__collector_line_cleanup(): ERROR, line is DORMANT\n");
295 else
296 TprintfT (DBG_LT0, "__collector_line_cleanup()\n");
297 line_mode = LM_CLOSED;
298 user_follow_mode = FOLLOW_NONE;
299 dbg_current_mode = FOLLOW_NONE; /* for debug only */
300 line_key = COLLECTOR_TSD_INVALID_KEY;
301 java_mode = 0;
302 if (sp_env_backup != NULL)
304 __collector_env_backup_free ();
305 sp_env_backup = NULL;
307 return;
311 * void __collector_ext_line_close (void)
312 * Disable logging. Cleans ENV vars. Clear backup ENV.
314 void
315 __collector_ext_line_close (void)
317 TprintfT (DBG_LT0, "__collector_ext_line_close()\n");
318 __collector_line_cleanup ();
319 __collector_env_unset (NULL);
320 return;
324 * void linetrace_dormant(void)
325 * Disable logging. Preserve ENV vars.
327 static void
328 linetrace_dormant (void)
330 if (line_mode == LM_DORMANT)
332 TprintfT (DBG_LT0, "linetrace_dormant() -- already dormant\n");
333 return;
335 else if (line_mode == LM_CLOSED)
337 TprintfT (DBG_LT0, "linetrace_dormant(): ERROR, line is already CLOSED\n");
338 return;
340 else
341 TprintfT (DBG_LT0, "linetrace_dormant()\n");
342 line_mode = LM_DORMANT;
343 return;
346 static int
347 check_follow_fork ()
349 int follow = (user_follow_mode != FOLLOW_NONE);
350 TprintfT (DBG_LT0, "check_follow_fork()=%d\n", follow);
351 return follow;
354 static int
355 check_follow_exec (const char *execfile)
357 int follow = (user_follow_mode != FOLLOW_NONE);
358 if (follow)
360 /* revise based on collectability of execfile */
361 follow = path_collectable (execfile);
363 TprintfT (DBG_LT0, "check_follow_exec(%s)=%d\n", execfile, follow);
364 return follow;
367 static int
368 check_follow_combo (const char *execfile)
370 int follow = (user_follow_mode != FOLLOW_NONE);
371 TprintfT (DBG_LT0, "check_follow_combo(%s)=%d\n", execfile, follow);
372 return follow;
375 static int
376 check_fd_dynamic (int fd)
378 TprintfT (DBG_LT0, "check_fd_dynamic(%d)\n", fd);
379 off_t off = CALL_UTIL (lseek)(fd, (off_t) 0, SEEK_END);
380 size_t sz = (size_t) 8192; /* one page should suffice */
381 if (sz > off)
382 sz = off;
383 char *p = CALL_UTIL (mmap64_)((char *) 0, sz, PROT_READ, MAP_PRIVATE, fd, (off64_t) 0);
384 if (p == MAP_FAILED)
386 TprintfT (DBG_LT0, "check_fd_dynamic(): ERROR/WARNING: mmap failed for `%d'\n", fd);
387 (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
388 COL_WARN_NOFOLLOW, "mmap-failed");
389 return 0;
391 char elfclass = p[EI_CLASS];
392 if ((p[EI_MAG0] != ELFMAG0) ||
393 (p[EI_MAG1] != ELFMAG1) ||
394 (p[EI_MAG2] != ELFMAG2) ||
395 (p[EI_MAG3] != ELFMAG3) ||
396 (elfclass != ELFCLASS32 && elfclass != ELFCLASS64)
399 TprintfT (DBG_LT0, "check_fd_dynamic(): WARNING: Command `%d' is not executable ELF!\n", fd);
400 CALL_UTIL (munmap)(p, sz);
401 return 1;
403 Elf32_Ehdr *ehdr32 = (Elf32_Ehdr*) p;
404 Elf64_Ehdr *ehdr64 = (Elf64_Ehdr*) p;
405 Elf64_Off e_phoff;
406 Elf64_Half e_phnum;
407 Elf64_Half e_phentsize;
408 if (elfclass == ELFCLASS32)
410 e_phoff = ehdr32->e_phoff;
411 e_phnum = ehdr32->e_phnum;
412 e_phentsize = ehdr32->e_phentsize;
414 else
416 e_phoff = ehdr64->e_phoff;
417 e_phnum = ehdr64->e_phnum;
418 e_phentsize = ehdr64->e_phentsize;
420 if ((sizeof (Elf32_Ehdr) > sz) ||
421 (sizeof (Elf64_Ehdr) > sz) ||
422 (e_phoff + e_phentsize * (e_phnum - 1) > sz))
424 TprintfT (DBG_LT0, "check_fd_dynamic(): WARNING: Command `%d' ELF file did not fit in page!\n", fd);
425 #if 0
426 (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
427 COL_WARN_RISKYFOLLOW, "ELF header size");
428 #endif
429 CALL_UTIL (munmap)(p, sz);
430 return 1;
432 TprintfT (DBG_LT2, "check_fd_dynamic(): elfclass=%d, e_phoff=%lu e_phnum=%lu e_phentsize=%lu\n",
433 (int) elfclass, (unsigned long) e_phoff, (unsigned long) e_phnum,
434 (unsigned long) e_phentsize);
435 int dynamic = 0;
436 Elf64_Half i;
437 for (i = 0; i < e_phnum; i++)
439 if (elfclass == ELFCLASS32)
441 if (PT_DYNAMIC ==
442 ((Elf32_Phdr*) (p + e_phoff + e_phentsize * i))->p_type)
444 dynamic = 1;
445 break;
448 else
450 if (PT_DYNAMIC ==
451 ((Elf64_Phdr*) (p + e_phoff + e_phentsize * i))->p_type)
453 dynamic = 1;
454 break;
458 if (!dynamic)
460 TprintfT (DBG_LT0, "check_fd_dynamic(): ERROR/WARNING: Command `%d' is not a dynamic executable!\n", fd);
461 #if 0
462 (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
463 COL_WARN_NOFOLLOW, "!dynamic");
464 #endif
466 else
467 TprintfT (DBG_LT2, "check_fd_dynamic(): Command `%d' is a dynamic executable!\n", fd);
468 CALL_UTIL (munmap)(p, sz);
469 return dynamic;
472 static int
473 check_dynamic (const char *execfile)
475 TprintfT (DBG_LT2, "check_dynamic(%s)\n", execfile);
476 int fd = CALL_UTIL (open)(execfile, O_RDONLY);
477 if (fd == -1)
479 TprintfT (DBG_LT0, "check_dynamic(): ERROR/WARNING: Command `%s' could not be opened!\n", execfile);
480 (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
481 COL_WARN_RISKYFOLLOW, "open");
482 return 1; /* follow, though exec will presumably fail */
484 int ret = check_fd_dynamic (fd);
485 CALL_UTIL (close)(fd);
486 return ret;
489 static int
490 path_collectable (const char *execfile)
492 TprintfT (DBG_LT0, "path_collectable(%s)\n", execfile);
493 /* Check that execfile exists and is a collectable executable */
494 /* logging warning when collection is likely to be unsuccessful */
495 /* (if check isn't accurate, generally best not to include it) */
497 if (execfile && !__collector_strchr (execfile, '/'))
498 { /* got an unqualified name */
499 /* XXXX locate execfile on PATH to be able to check it */
500 TprintfT (DBG_LT0, "path_collectable(): WARNING: Can't check unqualified executable `%s'\n", execfile);
501 #if 0
502 (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
503 COL_WARN_RISKYFOLLOW, "path");
504 #endif
505 return 1; /* follow unqualified execfile unchecked */
507 struct stat sbuf;
508 if (stat (execfile, &sbuf))
509 { /* can't stat it */
510 TprintfT (DBG_LT0, "path_collectable(): WARNING: Can't stat `%s'\n", execfile);
511 #if 0
512 (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
513 COL_WARN_RISKYFOLLOW, "stat");
514 #endif
515 return 1; /* follow, though exec will probably fail */
517 TprintfT (DBG_LT2, "path_collectable(%s) mode=0%o uid=%d gid=%d\n",
518 execfile, sbuf.st_mode, sbuf.st_uid, sbuf.st_gid);
519 if (((sbuf.st_mode & S_IXUSR) == 0) || ((sbuf.st_mode & S_IFMT) == S_IFDIR))
521 TprintfT (DBG_LT0, "path_collectable(): WARNING: Command `%s' is NOT an executable file!\n", execfile);
522 #if 0
523 (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
524 COL_WARN_RISKYFOLLOW, "mode");
525 #endif
526 return 1; /* follow, though exec will presumably fail */
528 /* XXXX setxid(root) is OK iff libcollector is registered as secure */
529 /* XXXX setxid(non-root) is OK iff umask is accomodating */
530 if (((sbuf.st_mode & S_ISUID) != 0) || ((sbuf.st_mode & S_ISGID) != 0))
532 TprintfT (DBG_LT0, "path_collectable(): WARNING: Command `%s' is SetXID!\n", execfile);
533 #if 0
534 (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
535 COL_WARN_RISKYFOLLOW, "setxid");
536 #endif
537 return 1; /* follow, though collection may be unreliable */
539 if (!check_dynamic (execfile))
541 TprintfT (DBG_LT0, "path_collectable(%s) WARNING/ERROR: not dynamic, not collectng!\n", execfile);
542 return 0; /* don't follow, collection will fail unpredictably */
544 TprintfT (DBG_LT2, "path_collectable(%s) OK!\n", execfile);
545 return 1; /* OK to follow */
548 static char *
549 build_experiment_path (char * instring, size_t instring_sz, const char *lineage_str)
551 TprintfT (DBG_LT0, "build_experiment_path(,%ld, %s)\n",
552 (long) instring_sz, lineage_str);
553 const char *p = CALL_UTIL (strstr)(linetrace_exp_dir_name, DESCENDANT_EXPT_KEY);
554 int basedir_sz;
555 if (p)
556 basedir_sz = p - linetrace_exp_dir_name + 4; /* +3 because of DESCENDANT_EXPT_KEY */
557 else
558 basedir_sz = __collector_strlen (linetrace_exp_dir_name) + 1;
559 int additional_sz = __collector_strlen (lineage_str) + 4;
560 if (basedir_sz + additional_sz > instring_sz)
562 TprintfT (DBG_LT0, "build_experiment_path(%s,%s): ERROR: path too long: %d > %ld\n",
563 linetrace_exp_dir_name, lineage_str,
564 basedir_sz + additional_sz, (long) instring_sz);
565 *instring = 0;
566 return NULL;
568 __collector_strlcpy (instring, linetrace_exp_dir_name, basedir_sz);
569 size_t slen = __collector_strlen (instring);
570 CALL_UTIL (snprintf)(instring + slen, instring_sz - slen, "/%s.er", lineage_str);
571 assert (__collector_strlen (instring) + 1 == basedir_sz + additional_sz);
572 return instring;
575 static void
576 check_reuid_change (uid_t ruid, uid_t euid)
578 uid_t curr_ruid = getuid ();
579 uid_t curr_euid = geteuid ();
580 mode_t curr_umask = umask (0);
581 umask (curr_umask); /* restore original umask */
582 int W_oth = !(curr_umask & S_IWOTH);
583 TprintfT (DBG_LT0, "check_reuid_change(%d,%d): umask=%03o\n", ruid, euid, curr_umask);
584 TprintfT (DBG_LT0, "check_reuid_change(): umask W usr=%d grp=%d oth=%d\n",
585 (int) (!(curr_umask & S_IWUSR)), (int) (!(curr_umask & S_IWGRP)), W_oth);
586 if (ruid != -1)
588 TprintfT (DBG_LT0, "check_reuid_change(%d->%d)\n", curr_ruid, ruid);
589 if ((curr_euid == 0) && (ruid != 0) && !W_oth)
591 /* changing to non-root ID, with umask blocking writes by other */
592 TprintfT (DBG_LT0, "check_reuid_change(): ERROR/WARNING: umask blocks write other after ruid change (%d->%d)\n",
593 curr_ruid, ruid);
594 (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">umask %03o ruid %d->%d</event>\n",
595 SP_JCMD_CWARN, COL_WARN_IDCHNG, curr_umask, curr_ruid, ruid);
598 if (euid != -1)
600 TprintfT (DBG_LT0, "check_reuid_change(%d->%d)\n", curr_euid, euid);
601 if ((curr_euid == 0) && (euid != 0) && !W_oth)
603 /* changing to non-root ID, with umask blocking writes by other */
604 TprintfT (DBG_LT0, "check_reuid_change(): ERROR/WARNING: umask blocks write other after euid change (%d->%d)\n",
605 curr_euid, euid);
606 (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">umask %03o euid %d->%d</event>\n",
607 SP_JCMD_CWARN, COL_WARN_IDCHNG, curr_umask, curr_euid, euid);
612 static void
613 check_regid_change (gid_t rgid, gid_t egid)
615 gid_t curr_rgid = getgid ();
616 gid_t curr_egid = getegid ();
617 uid_t curr_euid = geteuid ();
618 mode_t curr_umask = umask (0);
619 umask (curr_umask); /* restore original umask */
620 int W_oth = !(curr_umask & S_IWOTH);
621 TprintfT (DBG_LT0, "check_regid_change(%d,%d): umask=%03o euid=%d\n",
622 rgid, egid, curr_umask, curr_euid);
623 TprintfT (DBG_LT0, "umask W usr=%d grp=%d oth=%d\n",
624 (int) (!(curr_umask & S_IWUSR)), (int) (!(curr_umask & S_IWGRP)), W_oth);
625 if (rgid != -1)
627 TprintfT (DBG_LT0, "check_regid_change(%d->%d)\n", curr_rgid, rgid);
628 if ((curr_euid == 0) && (rgid != 0) && !W_oth)
630 /* changing to non-root ID, with umask blocking writes by other */
631 TprintfT (DBG_LT0, "check_regid_change(): WARNING/ERROR: umask blocks write other after rgid change (%d->%d)\n",
632 curr_rgid, rgid);
633 (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">umask %03o rgid %d->%d</event>\n",
634 SP_JCMD_CWARN, COL_WARN_IDCHNG, curr_umask, curr_rgid, rgid);
637 if (egid != -1)
639 TprintfT (DBG_LT0, "check_regid_change(): check_egid_change(%d->%d)\n", curr_egid, egid);
640 if ((curr_euid == 0) && (egid != 0) && !W_oth)
642 /* changing to non-root ID, with umask blocking writes by other */
643 TprintfT (DBG_LT0, "check_regid_change(): WARNING/ERROR: umask blocks write other after egid change (%d->%d)\n",
644 curr_egid, egid);
645 (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">umask %03o egid %d->%d</event>\n",
646 SP_JCMD_CWARN, COL_WARN_IDCHNG, curr_umask, curr_egid, egid);
651 static int
652 init_lineage_intf ()
654 void *dlflag;
655 TprintfT (DBG_LT2, "init_lineage_intf()\n");
657 static int nesting_check = 0;
658 if (nesting_check >= 2)
660 /* segv before stack blows up */
661 nesting_check /= (nesting_check - 2);
663 nesting_check++;
665 __real_fork = dlsym (RTLD_NEXT, "fork");
666 if (__real_fork == NULL)
668 __real_fork = dlsym (RTLD_DEFAULT, "fork");
669 if (__real_fork == NULL)
670 return 1;
671 dlflag = RTLD_DEFAULT;
673 else
674 dlflag = RTLD_NEXT;
675 TprintfT (DBG_LT2, "init_lineage_intf() using RTLD_%s\n",
676 dlflag == RTLD_DEFAULT ? "DEFAULT" : "NEXT");
677 __real_vfork = dlsym (dlflag, "vfork");
678 __real_execve = dlsym (dlflag, "execve");
679 __real_execvp = dlsym (dlflag, "execvp");
680 __real_execv = dlsym (dlflag, "execv");
681 __real_execle = dlsym (dlflag, "execle");
682 __real_execlp = dlsym (dlflag, "execlp");
683 __real_execl = dlsym (dlflag, "execl");
684 __real_clone = dlsym (dlflag, "clone");
686 __real_popen_2_17 = dlvsym (dlflag, "popen", "GLIBC_2.17");
687 __real_popen_2_2_5 = dlvsym (dlflag, "popen", "GLIBC_2.2.5");
688 __real_popen_2_1 = dlvsym (dlflag, "popen", "GLIBC_2.1");
689 __real_popen_2_0 = dlvsym (dlflag, "popen", "GLIBC_2.0");
690 if (__real_popen_2_17)
691 __real_popen = __real_popen_2_17;
692 else if (__real_popen_2_2_5)
693 __real_popen = __real_popen_2_2_5;
694 else if (__real_popen_2_1)
695 __real_popen = __real_popen_2_1;
696 else if (__real_popen_2_0)
697 __real_popen = __real_popen_2_0;
698 else
699 __real_popen = dlsym (dlflag, "popen");
701 __real_posix_spawn_2_17 = dlvsym (dlflag, "posix_spawn", "GLIBC_2.17");
702 __real_posix_spawn_2_15 = dlvsym (dlflag, "posix_spawn", "GLIBC_2.15");
703 __real_posix_spawn_2_2_5 = dlvsym (dlflag, "posix_spawn", "GLIBC_2.2.5");
704 __real_posix_spawn_2_2 = dlvsym (dlflag, "posix_spawn", "GLIBC_2.2");
705 if (__real_posix_spawn_2_17)
706 __real_posix_spawn = __real_posix_spawn_2_17;
707 else if (__real_posix_spawn_2_15)
708 __real_posix_spawn = __real_posix_spawn_2_15;
709 else if (__real_posix_spawn_2_2_5)
710 __real_posix_spawn = __real_posix_spawn_2_2_5;
711 else if (__real_posix_spawn_2_2)
712 __real_posix_spawn = __real_posix_spawn_2_2;
713 else
714 __real_posix_spawn = dlsym (dlflag, "posix_spawn");
716 __real_posix_spawnp_2_17 = dlvsym (dlflag, "posix_spawnp", "GLIBC_2.17");
717 __real_posix_spawnp_2_15 = dlvsym (dlflag, "posix_spawnp", "GLIBC_2.15");
718 __real_posix_spawnp_2_2_5 = dlvsym (dlflag, "posix_spawnp", "GLIBC_2.2.5");
719 __real_posix_spawnp_2_2 = dlvsym (dlflag, "posix_spawnp", "GLIBC_2.2");
720 if (__real_posix_spawnp_2_17)
721 __real_posix_spawnp = __real_posix_spawnp_2_17;
722 else if (__real_posix_spawnp_2_15)
723 __real_posix_spawnp = __real_posix_spawnp_2_15;
724 else if (__real_posix_spawnp_2_2_5)
725 __real_posix_spawnp = __real_posix_spawnp_2_2_5;
726 else if (__real_posix_spawnp_2_2)
727 __real_posix_spawnp = __real_posix_spawnp_2_2;
728 else
729 __real_posix_spawnp = dlsym (dlflag, "posix_spawnp");
731 __real_grantpt = dlsym (dlflag, "grantpt");
732 __real_ptsname = dlsym (dlflag, "ptsname");
733 __real_system = dlsym (dlflag, "system");
734 __real_setuid = dlsym (dlflag, "setuid");
735 __real_seteuid = dlsym (dlflag, "seteuid");
736 __real_setreuid = dlsym (dlflag, "setreuid");
737 __real_setgid = dlsym (dlflag, "setgid");
738 __real_setegid = dlsym (dlflag, "setegid");
739 __real_setregid = dlsym (dlflag, "setregid");
741 #define PR_FUNC(f) TprintfT (DBG_LT2, "linetrace.c: " #f ": @%p\n", f)
742 PR_FUNC (__real_fork);
743 PR_FUNC (__real_vfork);
744 PR_FUNC (__real_execve);
745 PR_FUNC (__real_execvp);
746 PR_FUNC (__real_execv);
747 PR_FUNC (__real_execle);
748 PR_FUNC (__real_execlp);
749 PR_FUNC (__real_execl);
750 PR_FUNC (__real_clone);
751 PR_FUNC (__real_grantpt);
752 PR_FUNC (__real_ptsname);
753 PR_FUNC (__real_popen);
754 PR_FUNC (__real_popen_2_17);
755 PR_FUNC (__real_popen_2_2_5);
756 PR_FUNC (__real_popen_2_1);
757 PR_FUNC (__real_popen_2_0);
758 PR_FUNC (__real_posix_spawn_2_17);
759 PR_FUNC (__real_posix_spawn_2_15);
760 PR_FUNC (__real_posix_spawn_2_2_5);
761 PR_FUNC (__real_posix_spawn_2_2);
762 PR_FUNC (__real_posix_spawnp_2_17);
763 PR_FUNC (__real_posix_spawnp_2_15);
764 PR_FUNC (__real_posix_spawnp_2_2_5);
765 PR_FUNC (__real_posix_spawnp_2_2);
766 PR_FUNC (__real_system);
767 PR_FUNC (__real_posix_spawn);
768 PR_FUNC (__real_posix_spawnp);
769 PR_FUNC (__real_setuid);
770 PR_FUNC (__real_seteuid);
771 PR_FUNC (__real_setreuid);
772 PR_FUNC (__real_setgid);
773 PR_FUNC (__real_setegid);
774 PR_FUNC (__real_setregid);
776 return 0;
779 /*------------------------------------------------------------------------ */
780 /* Note: The following _prologue and _epilogue functions used to be dbx-visible.
782 They are used to appropriately manage lineage-changing events, by
783 quiescing and re-enabling/re-setting experiment collection before and after,
784 and logging the lineage-change in the process/experiment undertaking it.
785 As shown by the interposition functions for fork, exec, etc., which follow,
786 the _prologue should be called immediately prior (such as a breakpoint
787 action defined at function entry) and the _epilogue called immediately
788 after (such as a breakpoint action defined at function return).
792 Notes on MT from Solaris 10 man pthread_atfork:
794 All multithreaded applications that call fork() in a POSIX
795 threads program and do more than simply call exec(2) in the
796 child of the fork need to ensure that the child is protected
797 from deadlock.
799 Since the "fork-one" model results in duplicating only the
800 thread that called fork(), it is possible that at the time
801 of the call another thread in the parent owns a lock. This
802 thread is not duplicated in the child, so no thread will
803 unlock this lock in the child. Deadlock occurs if the sin-
804 gle thread in the child needs this lock.
806 The problem is more serious with locks in libraries. Since
807 a library writer does not know if the application using the
808 library calls fork(), the library must protect itself from
809 such a deadlock scenario. If the application that links
810 with this library calls fork() and does not call exec() in
811 the child, and if it needs a library lock that may be held
812 by some other thread in the parent that is inside the
813 library at the time of the fork, the application deadlocks
814 inside the library.
817 static void
818 linetrace_ext_fork_prologue (const char *variant, char * n_lineage, int *following_fork)
820 TprintfT (DBG_LT0, "linetrace_ext_fork_prologue; variant=%s; new_lineage=%s; follow=%d\n",
821 variant, n_lineage, *following_fork);
822 __collector_env_print ("fork_prologue start");
823 if (dbg_current_mode != FOLLOW_NONE)
824 TprintfT (DBG_LT0, "linetrace_ext_fork_prologue(%s) ERROR: dbg_current_mode=%d, changing to FOLLOW_FORK!\n",
825 variant, dbg_current_mode);
826 dbg_current_mode = FOLLOW_ON;
827 if (__collector_strncmp ((char *) variant, "clone", sizeof ("clone") - 1) == 0)
829 __collector_mutex_lock (&clone_lineage_lock);
830 CALL_UTIL (snprintf)(n_lineage, LT_MAXNAMELEN, "%s_C%d", curr_lineage, ++clone_linenum);
831 __collector_mutex_unlock (&clone_lineage_lock);
833 else
835 __collector_mutex_lock (&fork_lineage_lock);
836 CALL_UTIL (snprintf)(n_lineage, LT_MAXNAMELEN, "%s_f%d", curr_lineage, ++fork_linenum);
837 __collector_mutex_unlock (&fork_lineage_lock);
839 *following_fork = check_follow_fork ();
841 /* write message before suspending, or it won't be written */
842 hrtime_t ts = GETRELTIME ();
843 TprintfT (DBG_LT0, "linetrace_ext_fork_prologue; variant=%s; new_lineage=%s; follow=%d\n",
844 variant, n_lineage, *following_fork);
845 __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" variant=\"%s\" lineage=\"%s\" follow=\"%d\"/>\n",
846 SP_JCMD_DESC_START,
847 (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
848 variant, n_lineage, *following_fork);
849 __collector_ext_dispatcher_thread_timer_suspend ();
850 __collector_ext_hwc_lwp_suspend ();
851 __collector_env_print ("fork_prologue end");
854 static void
855 linetrace_ext_fork_epilogue (const char *variant, const pid_t ret, char * n_lineage, int *following_fork)
857 if (dbg_current_mode == FOLLOW_NONE)
858 TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue(%s) ERROR: dbg_current_mode=%d!\n",
859 variant, dbg_current_mode);
860 /* compute descendant experiment name */
861 char new_exp_name[LT_MAXPATHLEN];
862 /* save exp_name to global var */
863 if (!build_experiment_path (new_exp_name, sizeof (new_exp_name), n_lineage))
864 TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue(%s): ERROR SP_COLLECTOR_EXPNAME not set\n", n_lineage);
865 TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue(%s):%d() returned %d %s; child experiment name = %s\n",
866 variant, *following_fork, ret, (ret ? "parent" : "child"), new_exp_name);
867 if (ret == 0)
869 /* *************************************child */
870 __collector_env_print ("fork_epilogue child at start");
871 /* start a new line */
872 fork_linenum = 0;
873 __collector_mutex_init (&fork_lineage_lock);
874 clone_linenum = 0;
875 __collector_mutex_init (&clone_lineage_lock);
876 __collector_env_update (NULL);
877 __collector_env_print ("fork_epilogue child after env_update");
878 __collector_clean_state ();
879 __collector_env_print ("fork_epilogue child after clean_slate");
880 __collector_line_cleanup ();
881 __collector_env_print ("fork_epilogue child after line_cleanup");
882 if (*following_fork)
884 /* stop recording this experiment, but preserve env vars */
885 linetrace_dormant ();
886 __collector_env_print ("fork_epilogue child after linetrace_dormant");
888 //static char exp_name_env[LT_MAXPATHLEN];
889 char * exp_name_env = CALL_UTIL (calloc)(LT_MAXPATHLEN, 1);
890 CALL_UTIL (snprintf)(exp_name_env, LT_MAXPATHLEN, "%s=%s", SP_COLLECTOR_EXPNAME, new_exp_name);
891 CALL_UTIL (putenv)(exp_name_env);
893 const char *params = CALL_UTIL (getenv)(SP_COLLECTOR_PARAMS);
894 int ret;
895 if (*new_exp_name == 0)
896 TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue: ERROR: getenv(%s) undefined -- new expt aborted!\n",
897 SP_COLLECTOR_EXPNAME);
898 else if (params == NULL)
899 TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue: ERROR: getenv(%s) undefined -- new expt aborted!\n",
900 SP_COLLECTOR_PARAMS);
901 else if ((ret = __collector_open_experiment (new_exp_name, params, SP_ORIGIN_FORK)))
902 TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue: ERROR: '%s' open failed, ret=%d\n",
903 new_exp_name, ret);
904 else
905 TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue: opened(%s)\n", new_exp_name);
906 TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue(%s) returning to *child*\n", variant);
908 else
910 /* disable current and further linetrace experiment resumption */
911 TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue(%s) child calling line_close\n", variant);
912 __collector_ext_line_close ();
914 __collector_env_print ("fork_epilogue child at end");
915 /* *************************************end child */
917 else
919 /* *************************************parent */
920 __collector_env_print ("fork_epilogue parent at start");
921 __collector_ext_dispatcher_thread_timer_resume ();
922 __collector_ext_hwc_lwp_resume ();
923 hrtime_t ts = GETRELTIME ();
924 char msg[256 + LT_MAXPATHLEN];
925 if (ret >= 0)
926 CALL_UTIL (snprintf)(msg, sizeof (msg), "pid=%d", ret);
927 else
929 /* delete stillborn experiment? */
930 char errmsg[256];
931 strerror_r (errno, errmsg, sizeof (errmsg));
932 CALL_UTIL (snprintf)(msg, sizeof (msg), "err %s", errmsg);
934 __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" variant=\"%s\" lineage=\"%s\" follow=\"%d\" msg=\"%s\"/>\n",
935 SP_JCMD_DESC_STARTED,
936 (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
937 variant, n_lineage, *following_fork, msg);
938 /* environment remains set for collection */
939 __collector_env_print ("fork_epilogue parent at end");
940 /* *************************************end parent */
942 dbg_current_mode = FOLLOW_NONE;
943 *following_fork = 0;
946 static char**
947 linetrace_ext_exec_prologue_end (const char *variant, const char* cmd_string,
948 char *const envp[], int following_exec)
950 char **coll_env;
951 TprintfT (DBG_LT0, "linetrace_ext_exec_prologue_end; variant=%s; cmd_string=%s; follow=%d\n",
952 variant, cmd_string, following_exec);
953 /* write message before suspending, or it won't be written */
954 hrtime_t ts = GETRELTIME ();
955 __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" variant=\"%s\" lineage=\"%s\" follow=\"%d\" msg=\"%s\"/>\n",
956 SP_JCMD_EXEC_START,
957 (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
958 variant, new_lineage, following_exec, cmd_string);
959 if (following_exec)
961 coll_env = __collector_env_allocate (envp, 0);
962 __collector_env_update (coll_env);
963 extern char **environ; /* the process' actual environment */
964 if (environ == envp) /* user selected process environment */
965 environ = coll_env;
967 else
968 coll_env = (char**) envp;
969 __collector_env_printall ("linetrace_ext_exec_prologue_end", coll_env);
970 if (!CALL_UTIL (strstr)(variant, "posix_spawn"))
972 __collector_linetrace_shutdown_hwcs_6830763_XXXX = 1;
973 __collector_suspend_experiment ("suspend_for_exec");
974 __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0;
976 if (CALL_UTIL (strstr)(variant, "posix_spawn"))
978 __collector_ext_dispatcher_thread_timer_suspend ();
979 __collector_linetrace_shutdown_hwcs_6830763_XXXX = 1;
980 __collector_ext_hwc_lwp_suspend ();
981 __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0;
983 return (coll_env);
986 static char**
987 linetrace_ext_exec_prologue (const char *variant,
988 const char* path, char *const argv[],
989 char *const envp[], int *following_exec)
991 char cmd_string[_POSIX_ARG_MAX] = {'\0'};
993 if (dbg_current_mode != FOLLOW_NONE)
994 TprintfT (DBG_LT0, "linetrace_ext_exec_prologue() ERROR: dbg_current_mode=%d, changing to FOLLOW_EXEC!\n", dbg_current_mode);
995 dbg_current_mode = FOLLOW_ON;
996 *following_exec = check_follow_exec (path);
997 if (path != NULL)
999 /* escape any newline, " or \ characters in the exec command */
1000 TprintfT (DBG_LT3, "linetrace_ext_exec_prologue(): arg0=%s\n", path);
1001 /* leave space in log message for terminator (and header) */
1002 __collector_strlcpy (cmd_string, path, sizeof (cmd_string));
1003 size_t len;
1004 unsigned argn = 0;
1005 if (argv[0])
1007 char *p;
1008 while (((p = argv[++argn]) != 0) &&
1009 (len = __collector_strlen (cmd_string)) < sizeof (cmd_string) - 2)
1011 cmd_string[len++] = ' ';
1012 __collector_strlcpy (cmd_string + len, p, sizeof (cmd_string) - len);
1016 TprintfT (DBG_LT0, "linetrace_ext_exec_prologue(%s), lineage=%s, follow=%d, prog=%s, path=%s \n",
1017 variant, new_lineage, *following_exec, cmd_string, path);
1018 return linetrace_ext_exec_prologue_end (variant, cmd_string, envp, *following_exec);
1021 static void
1022 linetrace_ext_exec_epilogue (const char *variant, char *const envp[], const int ret, int *following_exec)
1024 /* For exec, this routine is only entered if the exec failed */
1025 /* However, posix_spawn() is expected to return */
1026 if (dbg_current_mode == FOLLOW_NONE)
1027 TprintfT (DBG_LT0, "linetrace_ext_exec_epilogue() ERROR: dbg_current_mode=%d!\n", dbg_current_mode);
1028 TprintfT (DBG_LT0, "linetrace_ext_exec_epilogue(%s):%d returned: %d, errno=%d\n",
1029 variant, *following_exec, ret, errno);
1030 if (!CALL_UTIL (strstr)(variant, "posix_spawn"))
1032 __collector_linetrace_shutdown_hwcs_6830763_XXXX = 1;
1033 __collector_resume_experiment ();
1034 __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0;
1036 if (CALL_UTIL (strstr)(variant, "posix_spawn"))
1038 __collector_ext_dispatcher_thread_timer_resume ();
1039 __collector_linetrace_shutdown_hwcs_6830763_XXXX = 1;
1040 __collector_ext_hwc_lwp_resume ();
1041 __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0;
1043 hrtime_t ts = GETRELTIME ();
1044 char msg[256];
1045 if (ret)
1047 char errmsg[256];
1048 strerror_r (errno, errmsg, sizeof (errmsg));
1049 CALL_UTIL (snprintf)(msg, sizeof (msg), "err %s", errmsg);
1051 else
1052 CALL_UTIL (snprintf)(msg, sizeof (msg), "rc=%d", ret);
1053 if (!CALL_UTIL (strstr)(variant, "posix_spawn"))
1054 __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" variant=\"%s\" lineage=\"%s\" follow=\"%d\" msg=\"%s\"/>\n",
1055 SP_JCMD_EXEC_ERROR,
1056 (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
1057 variant, new_lineage, *following_exec, msg);
1058 if (envp == NULL)
1059 TprintfT (DBG_LT0, "linetrace_ext_exec_epilogue() ERROR: envp NULL after %s!\n", variant);
1060 dbg_current_mode = FOLLOW_NONE;
1061 *following_exec = 0;
1064 static void
1065 linetrace_ext_combo_prologue (const char *variant, const char *cmd, int *following_combo)
1067 char cmd_string[_POSIX_ARG_MAX] = {'\0'};
1068 char execfile[_POSIX_ARG_MAX] = {'\0'};
1070 if (dbg_current_mode != FOLLOW_NONE)
1071 TprintfT (DBG_LT0, "linetrace_ext_combo_prologue() ERROR: dbg_current_mode=%d! changing to FOLLOW_ON\n",
1072 dbg_current_mode);
1073 dbg_current_mode = FOLLOW_ON;
1074 if (cmd != NULL)
1076 /* extract executable name from combo command */
1077 unsigned len = strcspn (cmd, " ");
1078 __collector_strlcpy (execfile, cmd, len + 1);
1080 /* escape any newline, " or \ characters in the combo command */
1081 /* leave space in log message for terminator (and header) */
1082 __collector_strlcpy (cmd_string, cmd, sizeof (cmd_string));
1085 *following_combo = check_follow_combo (execfile);
1086 TprintfT (DBG_LT0, "linetrace_ext_combo_prologue(%s) follow=%d, prog=%s\n\n",
1087 variant, *following_combo, cmd_string);
1089 /* Construct the lineage string for the new image */
1090 new_lineage[0] = 0;
1091 __collector_strcat (new_lineage, "XXX");
1093 /* write message before suspending, or it won't be written */
1094 hrtime_t ts = GETRELTIME ();
1095 __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" variant=\"%s\" lineage=\"%s\" follow=\"%d\" msg=\"%s\"/>\n",
1096 SP_JCMD_DESC_START,
1097 (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
1098 variant, new_lineage, *following_combo, cmd_string);
1099 if (*following_combo)
1101 __collector_env_update (NULL);
1102 TprintfT (DBG_LT0, "linetrace_ext_combo_prologue(): Following %s(\"%s\")\n", variant, execfile);
1104 __collector_ext_dispatcher_thread_timer_suspend ();
1105 __collector_linetrace_shutdown_hwcs_6830763_XXXX = 1;
1106 __collector_ext_hwc_lwp_suspend ();
1107 __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0;
1110 static void
1111 linetrace_ext_combo_epilogue (const char *variant, const int ret, int *following_combo)
1113 if (dbg_current_mode == FOLLOW_NONE)
1114 TprintfT (DBG_LT0, "linetrace_ext_combo_epilogue() ERROR: dbg_current_mode=FOLLOW_NONE\n");
1115 TprintfT (DBG_LT0, "linetrace_ext_combo_epilogue(%s):%d() returned %d\n",
1116 variant, *following_combo, ret);
1117 __collector_ext_dispatcher_thread_timer_resume ();
1118 __collector_linetrace_shutdown_hwcs_6830763_XXXX = 1;
1119 __collector_ext_hwc_lwp_resume ();
1120 __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0;
1121 hrtime_t ts = GETRELTIME ();
1122 __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" variant=\"%s\" follow=\"%d\" msg=\"rc=%d\"/>\n",
1123 SP_JCMD_DESC_STARTED,
1124 (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
1125 variant, *following_combo, ret);
1127 dbg_current_mode = FOLLOW_NONE;
1128 *following_combo = 0;
1131 /*------------------------------------------------------------- fork */
1132 pid_t fork () __attribute__ ((weak, alias ("__collector_fork")));
1133 pid_t _fork () __attribute__ ((weak, alias ("__collector_fork")));
1135 pid_t
1136 __collector_fork (void)
1138 pid_t ret;
1139 if (NULL_PTR (fork))
1141 TprintfT (DBG_LT0, "__collector_fork() calling init_lineage_intf()\n");
1142 init_lineage_intf ();
1144 __collector_env_print ("__collector_fork start");
1145 int * guard = NULL;
1146 int combo_flag = (line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0;
1147 TprintfT (DBG_LT0, "__collector_fork() interposition: line_mode=%d combo=%d\n",
1148 line_mode, combo_flag);
1149 if ((line_mode != LM_TRACK_LINEAGE) || combo_flag)
1151 TprintfT (DBG_LT0, "__collector_fork() not following, returning CALL_REAL(fork)()\n");
1152 return CALL_REAL (fork)();
1154 int following_fork = 0;
1155 linetrace_ext_fork_prologue ("fork", new_lineage, &following_fork);
1157 /* since libpthread/fork ends up calling fork1, it's a combo */
1158 PUSH_REENTRANCE (guard);
1159 ret = CALL_REAL (fork)();
1160 POP_REENTRANCE (guard);
1161 linetrace_ext_fork_epilogue ("fork", ret, new_lineage, &following_fork);
1162 return ret;
1165 /*------------------------------------------------------------- vfork */
1166 /* vfork interposition in the usual sense is not possible, since vfork(2)
1167 relies on specifics of the stack frames in the parent and child which
1168 only work when the child's exec (or _exit) are in the same stack frame
1169 as the vfork: this isn't the case when there's interposition on exec.
1170 As a workaround, the interposing vfork calls fork1 instead of the real
1171 vfork. Note that fork1 is somewhat less efficient than vfork, and requires
1172 additional memory, which may result in a change of application behaviour
1173 when libcollector is loaded (even when collection is not active),
1174 affecting not only direct use of vfork by the subject application,
1175 but also indirect use through system, popen, and the other combos.
1177 pid_t vfork () __attribute__ ((weak, alias ("__collector_vfork")));
1178 pid_t _vfork () __attribute__ ((weak, alias ("__collector_vfork")));
1180 pid_t
1181 __collector_vfork (void)
1183 if (NULL_PTR (vfork))
1184 init_lineage_intf ();
1186 int * guard = NULL;
1187 int combo_flag = (line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0;
1189 TprintfT (DBG_LT0, "__collector_vfork() interposing: line_mode=%d combo=%d\n",
1190 line_mode, combo_flag);
1191 if ((line_mode != LM_TRACK_LINEAGE) || combo_flag)
1192 return CALL_REAL (fork)();
1194 /* this warning is also appropriate for combos which use vfork,
1195 however, let's assume this is achieved elsewhere */
1196 (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
1197 COL_WARN_VFORK, "fork");
1199 char new_lineage[LT_MAXNAMELEN];
1200 new_lineage[0] = 0;
1201 int following_fork = 0;
1202 linetrace_ext_fork_prologue ("vfork", new_lineage, &following_fork);
1204 pid_t ret = CALL_REAL (fork)();
1205 linetrace_ext_fork_epilogue ("vfork", ret, new_lineage, &following_fork);
1206 return ret;
1209 /*------------------------------------------------------------- execve */
1210 int execve () __attribute__ ((weak, alias ("__collector_execve")));
1213 __collector_execve (const char* path, char *const argv[], char *const envp[])
1215 static char **coll_env = NULL; /* environment for collection */
1216 if (NULL_PTR (execve))
1217 init_lineage_intf ();
1218 int * guard = NULL;
1219 int combo_flag = (line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0;
1220 TprintfT (DBG_LT0,
1221 "__collector_execve(path=%s, argv[0]=%s, env[0]=%s) interposing: line_mode=%d combo=%d\n",
1222 path ? path : "NULL",
1223 argv ? (argv[0] ? argv[0] : "NULL") : "NULL",
1224 envp ? (envp[0] ? envp[0] : "NULL") : "NULL",
1225 line_mode, combo_flag);
1226 if (line_mode == LM_CLOSED) /* ensure collection environment is sanitised */
1227 __collector_env_unset ((char**) envp);
1228 if (line_mode != LM_TRACK_LINEAGE || combo_flag)
1229 return CALL_REAL (execve)(path, argv, envp);
1231 int following_exec = 0;
1232 coll_env = linetrace_ext_exec_prologue ("execve", path, argv, envp, &following_exec);
1233 TprintfT (DBG_LT2, "__collector_execve(): coll_env=0x%p\n", coll_env);
1234 __collector_env_printall ("__collector_execve", coll_env);
1235 int ret = CALL_REAL (execve)(path, argv, coll_env);
1236 linetrace_ext_exec_epilogue ("execve", envp, ret, &following_exec);
1237 return ret;
1240 int execvp () __attribute__ ((weak, alias ("__collector_execvp")));
1243 __collector_execvp (const char* file, char *const argv[])
1245 extern char **environ; /* the process' actual environment */
1246 char ** envp = environ;
1247 if (NULL_PTR (execvp))
1248 init_lineage_intf ();
1249 int * guard = NULL;
1250 int combo_flag = (line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0;
1251 TprintfT (DBG_LT0,
1252 "__collector_execvp(file=%s, argv[0]=%s) interposing: line_mode=%d combo=%d\n",
1253 file ? file : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL",
1254 line_mode, combo_flag);
1255 if (line_mode == LM_CLOSED) /* ensure collection environment is sanitised */
1256 __collector_env_unset ((char**) envp);
1257 if ((line_mode != LM_TRACK_LINEAGE) || combo_flag)
1258 return CALL_REAL (execvp)(file, argv);
1260 int following_exec = 0;
1261 #ifdef DEBUG
1262 char **coll_env = /* environment for collection */
1263 #endif /* DEBUG */
1264 linetrace_ext_exec_prologue ("execvp", file, argv, envp, &following_exec);
1265 TprintfT (DBG_LT0, "__collector_execvp(): coll_env=0x%p\n", coll_env);
1267 int ret = CALL_REAL (execvp)(file, argv);
1268 linetrace_ext_exec_epilogue ("execvp", envp, ret, &following_exec);
1269 return ret;
1272 int execv () __attribute__ ((weak, alias ("__collector_execv")));
1275 __collector_execv (const char* path, char *const argv[])
1277 int ret;
1278 extern char **environ; /* the process' actual environment */
1279 char ** envp = environ;
1280 TprintfT (DBG_LT0, "__collector_execv(path=%s, argv[0]=%s) interposing: line_mode=%d combo=%d\n",
1281 path ? path : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL",
1282 line_mode, get_combo_flag ());
1284 ret = __collector_execve (path, argv, envp);
1285 return ret;
1288 int execle (const char* path, const char *arg0, ...) __attribute__ ((weak, alias ("__collector_execle")));
1291 __collector_execle (const char* path, const char *arg0, ...)
1293 TprintfT (DBG_LT0,
1294 "__collector_execle(path=%s, arg0=%s) interposing: line_mode=%d combo=%d\n",
1295 path ? path : "NULL", arg0 ? arg0 : "NULL",
1296 line_mode, get_combo_flag ());
1298 char **argp;
1299 va_list args;
1300 char **argvec;
1301 register char **environmentp;
1302 int nargs = 0;
1303 char *nextarg;
1305 va_start (args, arg0);
1306 while (va_arg (args, char *) != (char *) 0)
1307 nargs++;
1310 * save the environment pointer, which is at the end of the
1311 * variable argument list
1313 environmentp = va_arg (args, char **);
1314 va_end (args);
1317 * load the arguments in the variable argument list
1318 * into the argument vector, and add the terminating null pointer
1320 va_start (args, arg0);
1321 /* workaround for bugid 1242839 */
1322 argvec = (char **) alloca ((size_t) ((nargs + 2) * sizeof (char *)));
1323 argp = argvec;
1324 *argp++ = (char *) arg0;
1325 while ((nextarg = va_arg (args, char *)) != (char *) 0)
1326 *argp++ = nextarg;
1327 va_end (args);
1328 *argp = (char *) 0;
1329 return __collector_execve (path, argvec, environmentp);
1332 int execlp (const char* file, const char *arg0, ...) __attribute__ ((weak, alias ("__collector_execlp")));
1335 __collector_execlp (const char* file, const char *arg0, ...)
1337 TprintfT (DBG_LT0,
1338 "__collector_execlp(file=%s, arg0=%s) interposing: line_mode=%d combo=%d\n",
1339 file ? file : "NULL", arg0 ? arg0 : "NULL",
1340 line_mode, get_combo_flag ());
1341 char **argp;
1342 va_list args;
1343 char **argvec;
1344 int nargs = 0;
1345 char *nextarg;
1347 va_start (args, arg0);
1348 while (va_arg (args, char *) != (char *) 0)
1349 nargs++;
1350 va_end (args);
1353 * load the arguments in the variable argument list
1354 * into the argument vector and add the terminating null pointer
1356 va_start (args, arg0);
1358 /* workaround for bugid 1242839 */
1359 argvec = (char **) alloca ((size_t) ((nargs + 2) * sizeof (char *)));
1360 argp = argvec;
1361 *argp++ = (char *) arg0;
1362 while ((nextarg = va_arg (args, char *)) != (char *) 0)
1363 *argp++ = nextarg;
1364 va_end (args);
1365 *argp = (char *) 0;
1366 return __collector_execvp (file, argvec);
1369 int execl (const char* path, const char *arg0, ...) __attribute__ ((weak, alias ("__collector_execl")));
1372 __collector_execl (const char* path, const char *arg0, ...)
1374 TprintfT (DBG_LT0,
1375 "__collector_execl(path=%s, arg0=%s) interposing: line_mode=%d combo=%d\n",
1376 path ? path : "NULL", arg0 ? arg0 : "NULL",
1377 line_mode, get_combo_flag ());
1378 char **argp;
1379 va_list args;
1380 char **argvec;
1381 extern char **environ;
1382 int nargs = 0;
1383 char *nextarg;
1384 va_start (args, arg0);
1385 while (va_arg (args, char *) != (char *) 0)
1386 nargs++;
1387 va_end (args);
1390 * load the arguments in the variable argument list
1391 * into the argument vector and add the terminating null pointer
1393 va_start (args, arg0);
1395 /* workaround for bugid 1242839 */
1396 argvec = (char **) alloca ((size_t) ((nargs + 2) * sizeof (char *)));
1397 argp = argvec;
1398 *argp++ = (char *) arg0;
1399 while ((nextarg = va_arg (args, char *)) != (char *) 0)
1400 *argp++ = nextarg;
1401 va_end (args);
1402 *argp = (char *) 0;
1403 return __collector_execve (path, argvec, environ);
1406 #include <spawn.h>
1408 /*-------------------------------------------------------- posix_spawn */
1409 // map interposed symbol versions
1410 static int
1411 gprofng_posix_spawn (int(real_posix_spawn) (),
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[])
1417 int ret;
1418 static char **coll_env = NULL; /* environment for collection */
1419 if (real_posix_spawn == NULL)
1421 TprintfT (DBG_LT0, "gprofng_posix_spawn (path=%s) interposin ERROR, posix_spawn() not found by dlsym\n",
1422 path ? path : "NULL");
1423 return -1; /* probably should set errno */
1425 int *guard = NULL;
1426 int combo_flag = (line_mode == LM_TRACK_LINEAGE &&
1427 CHCK_REENTRANCE (guard)) ? 1 : 0;
1428 TprintfT (DBG_LT0, "gprofng_posix_spawn @%p (%s, argv[0]=%s, env[0]=%s)"
1429 "line_mode=%d combo=%d\n", (real_posix_spawn), path ? path : "NULL",
1430 (argv && argv[0]) ? argv[0] : "NULL",
1431 (envp && envp[0]) ? envp[0] : "NULL", line_mode, combo_flag);
1432 if (line_mode == LM_CLOSED) /* ensure collection environment is sanitised */
1433 __collector_env_unset ((char**) envp);
1435 if (line_mode != LM_TRACK_LINEAGE || combo_flag)
1436 return (real_posix_spawn) (pidp, path, file_actions, attrp, argv, envp);
1437 int following_exec = 0;
1438 coll_env = linetrace_ext_exec_prologue ("posix_spawn", path, argv, envp,
1439 &following_exec);
1440 __collector_env_printall ("gprofng_posix_spawn", coll_env);
1441 PUSH_REENTRANCE (guard);
1442 ret = real_posix_spawn (pidp, path, file_actions, attrp, argv, coll_env);
1443 POP_REENTRANCE (guard);
1444 linetrace_ext_exec_epilogue ("posix_spawn", envp, ret, &following_exec);
1445 return ret;
1448 #define DCL_POSIX_SPAWN(dcl_f) \
1449 int dcl_f (pid_t *pidp, const char *path, \
1450 const posix_spawn_file_actions_t *file_actions, \
1451 const posix_spawnattr_t *attrp, \
1452 char *const argv[], char *const envp[]) \
1454 if (__real_posix_spawn == NULL) \
1455 init_lineage_intf (); \
1456 return gprofng_posix_spawn (__real_posix_spawn, pidp, path, file_actions, \
1457 attrp, argv, envp); \
1461 DCL_FUNC_VER (DCL_POSIX_SPAWN, posix_spawn_2_17, posix_spawn@GLIBC_2.17)
1462 DCL_FUNC_VER (DCL_POSIX_SPAWN, posix_spawn_2_15, posix_spawn@GLIBC_2.15)
1463 DCL_FUNC_VER (DCL_POSIX_SPAWN, posix_spawn_2_2_5, posix_spawn@GLIBC_2.2.5)
1464 DCL_FUNC_VER (DCL_POSIX_SPAWN, posix_spawn_2_2, posix_spawn@GLIBC_2.2)
1465 DCL_POSIX_SPAWN (posix_spawn)
1467 /*-------------------------------------------------------- posix_spawnp */
1468 static int
1469 gprofng_posix_spawnp (int (real_posix_spawnp) (),
1470 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[])
1475 static char **coll_env = NULL; /* environment for collection */
1477 if (real_posix_spawnp == NULL)
1479 TprintfT (DBG_LT0, "gprofng_posix_spawnp (path=%s) interposin ERROR\n",
1480 path ? path : "NULL");
1481 return -1; /* probably should set errno */
1483 int *guard = NULL;
1484 int combo_flag = (line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0;
1485 TprintfT (DBG_LT0, "gprofng_posix_spawnp @%p (path=%s, argv[0]=%s, env[0]=%s) line_mode=%d combo=%d\n",
1486 real_posix_spawnp, path ? path : "NULL",
1487 argv && argv[0] ? argv[0] : "NULL",
1488 envp && envp[0] ? envp[0] : "NULL", line_mode, combo_flag);
1490 if (line_mode == LM_CLOSED) /* ensure collection environment is sanitized */
1491 __collector_env_unset ((char**) envp);
1492 if (line_mode != LM_TRACK_LINEAGE || combo_flag)
1493 return (real_posix_spawnp) (pidp, path, file_actions, attrp, argv, envp);
1494 int following_exec = 0;
1495 coll_env = linetrace_ext_exec_prologue ("posix_spawnp", path, argv, envp, &following_exec);
1496 TprintfT (DBG_LT0, "__collector_posix_spawnp(): coll_env=0x%p\n", coll_env);
1497 __collector_env_printall ("__collector_posix_spawnp", coll_env);
1498 PUSH_REENTRANCE (guard);
1499 int ret = real_posix_spawnp (pidp, path, file_actions, attrp, argv, coll_env);
1500 POP_REENTRANCE (guard);
1501 linetrace_ext_exec_epilogue ("posix_spawnp", envp, ret, &following_exec);
1502 return ret;
1505 #define DCL_POSIX_SPAWNP(dcl_f) \
1506 int dcl_f (pid_t *pidp, const char *path, \
1507 const posix_spawn_file_actions_t *file_actions, \
1508 const posix_spawnattr_t *attrp, \
1509 char *const argv[], char *const envp[]) \
1511 if (__real_posix_spawnp == NULL) \
1512 init_lineage_intf (); \
1513 return gprofng_posix_spawnp (__real_posix_spawnp, pidp, path, \
1514 file_actions, attrp, argv, envp); \
1517 DCL_FUNC_VER (DCL_POSIX_SPAWNP, posix_spawnp_2_17, posix_spawnp@GLIBC_2.17)
1518 DCL_FUNC_VER (DCL_POSIX_SPAWNP, posix_spawnp_2_15, posix_spawnp@GLIBC_2.15)
1519 DCL_FUNC_VER (DCL_POSIX_SPAWNP, posix_spawnp_2_2_5, posix_spawnp@GLIBC_2.2.5)
1520 DCL_FUNC_VER (DCL_POSIX_SPAWNP, posix_spawnp_2_2, posix_spawnp@GLIBC_2.2)
1521 DCL_POSIX_SPAWNP (posix_spawnp)
1523 /*------------------------------------------------------------- system */
1524 int system () __attribute__ ((weak, alias ("__collector_system")));
1527 __collector_system (const char *cmd)
1529 if (NULL_PTR (system))
1530 init_lineage_intf ();
1531 TprintfT (DBG_LT0,
1532 "__collector_system(cmd=%s) interposing: line_mode=%d combo=%d\n",
1533 cmd ? cmd : "NULL", line_mode, get_combo_flag ());
1534 int *guard = NULL;
1535 if (line_mode == LM_TRACK_LINEAGE)
1536 INIT_REENTRANCE (guard);
1537 if (guard == NULL)
1538 return CALL_REAL (system)(cmd);
1539 int following_combo = 0;
1540 linetrace_ext_combo_prologue ("system", cmd, &following_combo);
1541 PUSH_REENTRANCE (guard);
1542 int ret = CALL_REAL (system)(cmd);
1543 POP_REENTRANCE (guard);
1544 linetrace_ext_combo_epilogue ("system", ret, &following_combo);
1545 return ret;
1548 /*------------------------------------------------------------- popen */
1549 // map interposed symbol versions
1550 #define DCL_POPEN(dcl_f) \
1551 FILE *dcl_f (const char *cmd, const char *mode) \
1553 if (__real_popen == NULL) \
1554 init_lineage_intf (); \
1555 TprintfT (DBG_LT0, #dcl_f " (%s) interposing: line_mode=%d combo=%d\n", \
1556 cmd ? cmd : "NULL", line_mode, get_combo_flag ()); \
1557 int *guard = NULL; \
1558 if (line_mode == LM_TRACK_LINEAGE) \
1559 INIT_REENTRANCE (guard); \
1560 if (guard == NULL) \
1561 return __real_popen (cmd, mode); \
1562 int following_combo = 0; \
1563 linetrace_ext_combo_prologue ("popen", cmd, &following_combo); \
1564 PUSH_REENTRANCE (guard); \
1565 FILE *ret = __real_popen (cmd, mode); \
1566 POP_REENTRANCE (guard); \
1567 linetrace_ext_combo_epilogue ("popen", ret == NULL ? -1 : 0, \
1568 &following_combo); \
1569 return ret; \
1572 DCL_FUNC_VER (DCL_POPEN, popen_2_17, popen@GLIBC_2.17)
1573 DCL_FUNC_VER (DCL_POPEN, popen_2_2_5, popen@GLIBC_2.2.5)
1574 DCL_FUNC_VER (DCL_POPEN, popen_2_1, popen@GLIBC_2.1)
1575 DCL_FUNC_VER (DCL_POPEN, popen_2_0, popen@GLIBC_2.0)
1576 DCL_POPEN (popen)
1578 /*------------------------------------------------------------- grantpt */
1579 int grantpt () __attribute__ ((weak, alias ("__collector_grantpt")));
1582 __collector_grantpt (const int fildes)
1584 if (NULL_PTR (grantpt))
1585 init_lineage_intf ();
1586 TprintfT (DBG_LT0,
1587 "__collector_grantpt(%d) interposing: line_mode=%d combo=%d\n",
1588 fildes, line_mode, get_combo_flag ());
1589 int *guard = NULL;
1590 if (line_mode == LM_TRACK_LINEAGE)
1591 INIT_REENTRANCE (guard);
1592 if (guard == NULL)
1593 return CALL_REAL (grantpt)(fildes);
1594 int following_combo = 0;
1595 linetrace_ext_combo_prologue ("grantpt", "/usr/lib/pt_chmod", &following_combo);
1596 PUSH_REENTRANCE (guard);
1597 int ret = CALL_REAL (grantpt)(fildes);
1598 POP_REENTRANCE (guard);
1599 linetrace_ext_combo_epilogue ("grantpt", ret, &following_combo);
1600 return ret;
1603 /*------------------------------------------------------------- ptsname */
1604 char *ptsname () __attribute__ ((weak, alias ("__collector_ptsname")));
1606 char *
1607 __collector_ptsname (const int fildes)
1609 if (NULL_PTR (ptsname))
1610 init_lineage_intf ();
1611 TprintfT (DBG_LT0,
1612 "__collector_ptsname(%d) interposing: line_mode=%d combo=%d\n",
1613 fildes, line_mode, get_combo_flag ());
1614 int *guard = NULL;
1615 if (line_mode == LM_TRACK_LINEAGE)
1616 INIT_REENTRANCE (guard);
1617 if (guard == NULL)
1618 return CALL_REAL (ptsname)(fildes);
1619 int following_combo = 0;
1620 linetrace_ext_combo_prologue ("ptsname", "/usr/lib/pt_chmod", &following_combo);
1621 PUSH_REENTRANCE (guard);
1622 char *ret = CALL_REAL (ptsname)(fildes);
1623 POP_REENTRANCE (guard);
1624 linetrace_ext_combo_epilogue ("ptsname", (ret == NULL) ? (-1) : 1, &following_combo);
1625 return ret;
1628 /*------------------------------------------------------------- clone */
1629 /* clone can be fork-like or pthread_create-like, depending on whether
1630 * the flag CLONE_VM is set. If CLONE_VM is not set, then we interpose
1631 * clone in the way similar to interposing fork; if CLONE_VM is set,
1632 * then we interpose clone in the way similar to interposing pthread_create.
1633 * One special case is not handled: when CLONE_VM is set but CLONE_THREAD
1634 * is not, if the parent process exits earlier than the child process,
1635 * experiment will close, losing data from child process.
1637 typedef struct __collector_clone_arg
1639 int (*fn)(void *);
1640 void * arg;
1641 char * new_lineage;
1642 int following_fork;
1643 } __collector_clone_arg_t;
1645 static int
1646 __collector_clone_fn (void *fn_arg)
1648 int (*fn)(void *) = ((__collector_clone_arg_t*) fn_arg)->fn;
1649 void * arg = ((__collector_clone_arg_t*) fn_arg)->arg;
1650 char * new_lineage = ((__collector_clone_arg_t*) fn_arg)->new_lineage;
1651 int following_fork = ((__collector_clone_arg_t*) fn_arg)->following_fork;
1652 __collector_freeCSize (__collector_heap, fn_arg, sizeof (__collector_clone_arg_t));
1653 linetrace_ext_fork_epilogue ("clone", 0, new_lineage, &following_fork);
1654 return fn (arg);
1657 int clone (int (*fn)(void *), void *, int, void *, ...) __attribute__ ((weak, alias ("__collector_clone")));
1660 __collector_clone (int (*fn)(void *), void *child_stack, int flags, void *arg,
1661 ... /* pid_t *ptid, struct user_desc *tls, pid_t *" ctid" */)
1663 int ret;
1664 va_list va;
1665 if (flags & CLONE_VM)
1667 va_start (va, arg);
1668 ret = __collector_ext_clone_pthread (fn, child_stack, flags, arg, va);
1669 va_end (va);
1671 else
1673 if (NULL_PTR (clone))
1674 init_lineage_intf ();
1675 int *guard = NULL;
1676 int combo_flag = (line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0;
1677 TprintfT (DBG_LT0, "__collector_clone() interposition: line_mode=%d combo=%d\n",
1678 line_mode, combo_flag);
1679 char new_lineage[LT_MAXNAMELEN];
1680 int following_fork = 0;
1681 __collector_clone_arg_t *funcinfo = __collector_allocCSize (__collector_heap, sizeof (__collector_clone_arg_t), 1);
1682 (*funcinfo).fn = fn;
1683 (*funcinfo).arg = arg;
1684 (*funcinfo).new_lineage = new_lineage;
1685 (*funcinfo).following_fork = 0;
1686 pid_t * ptid = NULL;
1687 struct user_desc * tls = NULL;
1688 pid_t * ctid = NULL;
1689 int num_args = 0;
1690 va_start (va, arg);
1691 if (flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID))
1693 ptid = va_arg (va, pid_t *);
1694 tls = va_arg (va, struct user_desc*);
1695 ctid = va_arg (va, pid_t *);
1696 num_args = 3;
1698 else if (flags & CLONE_SETTLS)
1700 ptid = va_arg (va, pid_t *);
1701 tls = va_arg (va, struct user_desc*);
1702 num_args = 2;
1704 else if (flags & CLONE_PARENT_SETTID)
1706 ptid = va_arg (va, pid_t *);
1707 num_args = 1;
1709 if ((line_mode != LM_TRACK_LINEAGE) || combo_flag || funcinfo == NULL)
1711 switch (num_args)
1713 case 3:
1714 ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid, tls, ctid);
1715 break;
1716 case 2:
1717 ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid, tls);
1718 break;
1719 case 1:
1720 ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid);
1721 break;
1722 default:
1723 ret = CALL_REAL (clone)(fn, child_stack, flags, arg);
1724 break;
1727 va_end (va);
1728 return ret;
1730 linetrace_ext_fork_prologue ("clone", new_lineage, &following_fork);
1731 (*funcinfo).following_fork = following_fork;
1732 switch (num_args)
1734 case 3:
1735 ret = CALL_REAL (clone)(__collector_clone_fn, child_stack, flags, funcinfo, ptid, tls, ctid);
1736 break;
1737 case 2:
1738 ret = CALL_REAL (clone)(__collector_clone_fn, child_stack, flags, funcinfo, ptid, tls);
1739 break;
1740 case 1:
1741 ret = CALL_REAL (clone)(__collector_clone_fn, child_stack, flags, funcinfo, ptid);
1742 break;
1743 default:
1744 ret = CALL_REAL (clone)(__collector_clone_fn, child_stack, flags, funcinfo);
1745 break;
1747 va_end (va);
1748 if (ret < 0)
1749 __collector_freeCSize (__collector_heap, funcinfo, sizeof (__collector_clone_arg_t));
1750 TprintfT (DBG_LT0, "__collector_clone() interposing: pid=%d\n", ret);
1751 linetrace_ext_fork_epilogue ("clone", ret, new_lineage, &following_fork);
1753 return ret;
1756 /*-------------------------------------------------------------------- setuid */
1757 int setuid () __attribute__ ((weak, alias ("__collector_setuid")));
1758 int _setuid () __attribute__ ((weak, alias ("__collector_setuid")));
1761 __collector_setuid (uid_t ruid)
1763 if (NULL_PTR (setuid))
1764 init_lineage_intf ();
1765 TprintfT (DBG_LT0, "__collector_setuid(0x%x) interposing\n", ruid);
1766 check_reuid_change (ruid, -1);
1767 int ret = CALL_REAL (setuid)(ruid);
1768 TprintfT (DBG_LT0, "__collector_setuid(0x%x) returning %d\n", ruid, ret);
1769 return ret;
1772 /*------------------------------------------------------------------- seteuid */
1773 int seteuid () __attribute__ ((weak, alias ("__collector_seteuid")));
1774 int _seteuid () __attribute__ ((weak, alias ("__collector_seteuid")));
1777 __collector_seteuid (uid_t euid)
1779 if (NULL_PTR (seteuid))
1780 init_lineage_intf ();
1781 TprintfT (DBG_LT0, "__collector_seteuid(0x%x) interposing\n", euid);
1782 check_reuid_change (-1, euid);
1783 int ret = CALL_REAL (seteuid)(euid);
1784 TprintfT (DBG_LT0, "__collector_seteuid(0x%x) returning %d\n", euid, ret);
1785 return ret;
1788 /*------------------------------------------------------------------ setreuid */
1789 int setreuid () __attribute__ ((weak, alias ("__collector_setreuid")));
1790 int _setreuid () __attribute__ ((weak, alias ("__collector_setreuid")));
1793 __collector_setreuid (uid_t ruid, uid_t euid)
1795 if (NULL_PTR (setreuid))
1796 init_lineage_intf ();
1797 TprintfT (DBG_LT0, "__collector_setreuid(0x%x,0x%x) interposing\n", ruid, euid);
1798 check_reuid_change (ruid, euid);
1799 int ret = CALL_REAL (setreuid)(ruid, euid);
1800 TprintfT (DBG_LT0, "__collector_setreuid(0x%x,0x%x) returning %d\n", ruid, euid, ret);
1801 return ret;
1804 /*-------------------------------------------------------------------- setgid */
1805 int setgid () __attribute__ ((weak, alias ("__collector_setgid")));
1806 int _setgid () __attribute__ ((weak, alias ("__collector_setgid")));
1809 __collector_setgid (gid_t rgid)
1811 if (NULL_PTR (setgid))
1812 init_lineage_intf ();
1813 TprintfT (DBG_LT0, "__collector_setgid(0x%x) interposing\n", rgid);
1814 check_regid_change (rgid, -1);
1815 int ret = CALL_REAL (setgid)(rgid);
1816 TprintfT (DBG_LT0, "__collector_setgid(0x%x) returning %d\n", rgid, ret);
1817 return ret;
1820 /*------------------------------------------------------------------- setegid */
1821 int setegid () __attribute__ ((weak, alias ("__collector_setegid")));
1822 int _setegid () __attribute__ ((weak, alias ("__collector_setegid")));
1825 __collector_setegid (gid_t egid)
1827 if (NULL_PTR (setegid))
1828 init_lineage_intf ();
1829 TprintfT (DBG_LT0, "__collector_setegid(0x%x) interposing\n", egid);
1830 check_regid_change (-1, egid);
1831 int ret = CALL_REAL (setegid)(egid);
1832 TprintfT (DBG_LT0, "__collector_setegid(0x%x) returning %d\n", egid, ret);
1833 return ret;
1836 /*------------------------------------------------------------------ setregid */
1837 int setregid () __attribute__ ((weak, alias ("__collector_setregid")));
1838 int _setregid () __attribute__ ((weak, alias ("__collector_setregid")));
1841 __collector_setregid (gid_t rgid, gid_t egid)
1843 if (NULL_PTR (setregid))
1844 init_lineage_intf ();
1845 TprintfT (DBG_LT0, "__collector_setregid(0x%x,0x%x) interposing\n", rgid, egid);
1846 check_regid_change (rgid, egid);
1847 int ret = CALL_REAL (setregid)(rgid, egid);
1848 TprintfT (DBG_LT0, "__collector_setregid(0x%x,0x%x) returning %d\n", rgid, egid, ret);
1849 return ret;
1852 /*------------------------------------------------------- selective following */
1854 static int
1855 linetrace_follow_experiment (const char *follow_spec, const char *lineage_str, const char *progname)
1857 regex_t regex_desc;
1858 if (!follow_spec)
1860 TprintfT (DBG_LT0, "linetrace_follow_experiment(): MATCHES NULL follow_spec\n");
1861 return 1;
1863 int ercode = regcomp (&regex_desc, follow_spec, REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
1864 if (ercode)
1866 // syntax error in parsing string
1867 #ifdef DEBUG
1868 char errbuf[256];
1869 regerror (ercode, &regex_desc, errbuf, sizeof (errbuf));
1870 TprintfT (DBG_LT0, "linetrace_follow_experiment: regerror()=%s\n", errbuf);
1871 #endif
1872 return 1;
1874 TprintfT (DBG_LT0, "linetrace_follow_experiment(): compiled spec='%s'\n", follow_spec);
1875 if (lineage_str)
1877 if (!regexec (&regex_desc, lineage_str, 0, NULL, 0))
1879 TprintfT (DBG_LT0, "linetrace_follow_experiment(): MATCHES lineage (follow_spec=%s,lineage=%s)\n",
1880 follow_spec, lineage_str);
1881 return 1;
1884 if (progname)
1886 if (!regexec (&regex_desc, progname, 0, NULL, 0))
1888 TprintfT (DBG_LT0, "linetrace_follow_experiment(): MATCHES progname (follow_spec=%s,progname=%s)\n",
1889 follow_spec, progname);
1890 return 1;
1893 TprintfT (DBG_LT0, "linetrace_follow_experiment(): DOES NOT MATCH (follow_spec=%s,lineage=%s,progname=%s)\n",
1894 follow_spec, lineage_str ? lineage_str : "NULL",
1895 progname ? progname : "NULL");
1896 return 0;