1 /* Copyright (C) 2021-2023 Free Software Foundation, Inc.
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)
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.
29 #include <sys/types.h>
35 #include "descendants.h"
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
44 #define LT_MAXNAMELEN 1024
45 #define LT_MAXPATHLEN 1024
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
;
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
59 /* lineage tracking for descendants of this process */
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
;
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 )
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;
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
;
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
;
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 ();
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
);
135 int combo_flag
= ((line_mode
== LM_TRACK_LINEAGE
) ? ((CHCK_REENTRANCE (guard
)) ? 1 : 0) : 0);
140 /* must be called for potentially live experiment */
142 __collector_ext_line_init (int *precord_this_experiment
,
143 const char * progspec
, const char * progname
)
145 *precord_this_experiment
= 1;
146 TprintfT (DBG_LT0
, "__collector_ext_line_init(%s)\n", progspec
);
148 if (init_lineage_intf ())
150 TprintfT (DBG_LT0
, "__collector_ext_line_init() ERROR: initialization failed.\n");
151 return COL_ERROR_LINEINIT
;
153 /* check the follow spec */
154 user_follow_spec
= CALL_UTIL (getenv
)(SP_COLLECTOR_FOLLOW_SPEC
);
155 if (user_follow_spec
!= NULL
)
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
))
160 *precord_this_experiment
= 0;
161 TprintfT (DBG_LT0
, "collector: -F =<regex> does not match, will NOT be followed\n");
164 TprintfT (DBG_LT0
, "collector: -F =<regex> matches, will be followed\n");
165 user_follow_mode
= FOLLOW_ALL
;
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 */
173 return COL_ERROR_NONE
;
177 * int __collector_ext_line_install(args)
178 * Check args to determine which line events to follow.
179 * Create tsd key for combo flag.
182 __collector_ext_line_install (char *args
, const char * expname
)
186 TprintfT (DBG_LT0
, "__collector_ext_line_install(%s) ERROR: init hasn't be called yet\n", args
);
187 return COL_ERROR_EXPOPEN
;
189 TprintfT (DBG_LT0
, "__collector_ext_line_install(%s, %s)\n", args
, expname
);
190 line_key
= __collector_tsd_create_key (sizeof (int), NULL
, NULL
);
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
);
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
))
204 // backup collector specific env
205 if (sp_env_backup
== NULL
)
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
);
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
);
217 if (user_follow_mode
!= FOLLOW_NONE
)
218 CALL_UTIL (strlcat
)(logmsg
, "fork|exec|combo", sizeof (logmsg
));
219 size_t slen
= __collector_strlen (logmsg
);
223 CALL_UTIL (strlcat
)(logmsg
, "none", sizeof (logmsg
));
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
;
232 lineage_from_expname (char *lineage_str
, size_t lstr_sz
, const char *expname
)
234 TprintfT (DBG_LT0
, "lineage_from_expname(%s, %s)\n", lineage_str
, expname
);
236 if (lstr_sz
< 1 || !lineage_str
|| !expname
)
238 TprintfT (DBG_LT0
, "lineage_from_expname(): ERROR, null string\n");
241 /* determine lineage from experiment name */
242 p
= __collector_strrchr (expname
, '/');
243 if ((p
== NULL
) || (*++p
!= '_'))
246 TprintfT (DBG_LT2
, "lineage_from_expname(): expt=%s lineage=\".\" (founder)\n", expname
);
250 size_t tmp
= __collector_strlcpy (lineage_str
, p
, 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
, '.');
258 TprintfT (DBG_LT2
, "lineage_from_expname(): expt=%s lineage=\"%s\"\n", expname
, lineage_str
);
264 * void __collector_line_cleanup (void)
265 * Disable logging. Clear backup ENV.
268 __collector_line_cleanup (void)
270 if (line_mode
== LM_CLOSED
)
272 TprintfT (DBG_LT0
, "__collector_line_cleanup(): WARNING, line is already closed\n");
275 else if (line_mode
== LM_DORMANT
)
276 TprintfT (DBG_LT0
, "__collector_line_cleanup(): ERROR, line is DORMANT\n");
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
;
284 if (sp_env_backup
!= NULL
)
286 __collector_env_backup_free ();
287 sp_env_backup
= NULL
;
293 * void __collector_ext_line_close (void)
294 * Disable logging. Cleans ENV vars. Clear backup ENV.
297 __collector_ext_line_close (void)
299 TprintfT (DBG_LT0
, "__collector_ext_line_close()\n");
300 __collector_line_cleanup ();
301 __collector_env_unset (NULL
);
306 * void linetrace_dormant(void)
307 * Disable logging. Preserve ENV vars.
310 linetrace_dormant (void)
312 if (line_mode
== LM_DORMANT
)
314 TprintfT (DBG_LT0
, "linetrace_dormant() -- already dormant\n");
317 else if (line_mode
== LM_CLOSED
)
319 TprintfT (DBG_LT0
, "linetrace_dormant(): ERROR, line is already CLOSED\n");
323 TprintfT (DBG_LT0
, "linetrace_dormant()\n");
324 line_mode
= LM_DORMANT
;
331 int follow
= (user_follow_mode
!= FOLLOW_NONE
);
332 TprintfT (DBG_LT0
, "check_follow_fork()=%d\n", follow
);
337 check_follow_exec (const char *execfile
)
339 int follow
= (user_follow_mode
!= FOLLOW_NONE
);
342 /* revise based on collectability of execfile */
343 follow
= path_collectable (execfile
);
345 TprintfT (DBG_LT0
, "check_follow_exec(%s)=%d\n", execfile
, follow
);
350 check_follow_combo (const char *execfile
)
352 int follow
= (user_follow_mode
!= FOLLOW_NONE
);
353 TprintfT (DBG_LT0
, "check_follow_combo(%s)=%d\n", execfile
, follow
);
358 check_fd_dynamic (int fd
)
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 */
365 char *p
= CALL_UTIL (mmap64_
)((char *) 0, sz
, PROT_READ
, MAP_PRIVATE
, fd
, (off64_t
) 0);
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");
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
)
381 TprintfT (DBG_LT0
, "check_fd_dynamic(): WARNING: Command `%d' is not executable ELF!\n", fd
);
382 CALL_UTIL (munmap
)(p
, sz
);
385 Elf32_Ehdr
*ehdr32
= (Elf32_Ehdr
*) p
;
386 Elf64_Ehdr
*ehdr64
= (Elf64_Ehdr
*) p
;
389 Elf64_Half e_phentsize
;
390 if (elfclass
== ELFCLASS32
)
392 e_phoff
= ehdr32
->e_phoff
;
393 e_phnum
= ehdr32
->e_phnum
;
394 e_phentsize
= ehdr32
->e_phentsize
;
398 e_phoff
= ehdr64
->e_phoff
;
399 e_phnum
= ehdr64
->e_phnum
;
400 e_phentsize
= ehdr64
->e_phentsize
;
402 if ((sizeof (Elf32_Ehdr
) > sz
) ||
403 (sizeof (Elf64_Ehdr
) > sz
) ||
404 (e_phoff
+ e_phentsize
* (e_phnum
- 1) > sz
))
406 TprintfT (DBG_LT0
, "check_fd_dynamic(): WARNING: Command `%d' ELF file did not fit in page!\n", fd
);
408 (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN
,
409 COL_WARN_RISKYFOLLOW
, "ELF header size");
411 CALL_UTIL (munmap
)(p
, sz
);
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
);
419 for (i
= 0; i
< e_phnum
; i
++)
421 if (elfclass
== ELFCLASS32
)
424 ((Elf32_Phdr
*) (p
+ e_phoff
+ e_phentsize
* i
))->p_type
)
433 ((Elf64_Phdr
*) (p
+ e_phoff
+ e_phentsize
* i
))->p_type
)
442 TprintfT (DBG_LT0
, "check_fd_dynamic(): ERROR/WARNING: Command `%d' is not a dynamic executable!\n", fd
);
444 (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN
,
445 COL_WARN_NOFOLLOW
, "!dynamic");
449 TprintfT (DBG_LT2
, "check_fd_dynamic(): Command `%d' is a dynamic executable!\n", fd
);
450 CALL_UTIL (munmap
)(p
, sz
);
455 check_dynamic (const char *execfile
)
457 TprintfT (DBG_LT2
, "check_dynamic(%s)\n", execfile
);
458 int fd
= CALL_UTIL (open
)(execfile
, O_RDONLY
);
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 */
466 int ret
= check_fd_dynamic (fd
);
467 CALL_UTIL (close
)(fd
);
472 path_collectable (const char *execfile
)
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) */
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
);
484 (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN
,
485 COL_WARN_RISKYFOLLOW
, "path");
487 return 1; /* follow unqualified execfile unchecked */
490 if (stat (execfile
, &sbuf
))
491 { /* can't stat it */
492 TprintfT (DBG_LT0
, "path_collectable(): WARNING: Can't stat `%s'\n", execfile
);
494 (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN
,
495 COL_WARN_RISKYFOLLOW
, "stat");
497 return 1; /* follow, though exec will probably fail */
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
))
503 TprintfT (DBG_LT0
, "path_collectable(): WARNING: Command `%s' is NOT an executable file!\n", execfile
);
505 (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN
,
506 COL_WARN_RISKYFOLLOW
, "mode");
508 return 1; /* follow, though exec will presumably fail */
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))
514 TprintfT (DBG_LT0
, "path_collectable(): WARNING: Command `%s' is SetXID!\n", execfile
);
516 (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN
,
517 COL_WARN_RISKYFOLLOW
, "setxid");
519 return 1; /* follow, though collection may be unreliable */
521 if (!check_dynamic (execfile
))
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 */
526 TprintfT (DBG_LT2
, "path_collectable(%s) OK!\n", execfile
);
527 return 1; /* OK to follow */
531 build_experiment_path (char * instring
, size_t instring_sz
, const char *lineage_str
)
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
);
538 basedir_sz
= p
- linetrace_exp_dir_name
+ 4; /* +3 because of DESCENDANT_EXPT_KEY */
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
)
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
);
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
);
558 check_reuid_change (uid_t ruid
, uid_t euid
)
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
);
570 TprintfT (DBG_LT0
, "check_reuid_change(%d->%d)\n", curr_ruid
, ruid
);
571 if ((curr_euid
== 0) && (ruid
!= 0) && !W_oth
)
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",
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
);
582 TprintfT (DBG_LT0
, "check_reuid_change(%d->%d)\n", curr_euid
, euid
);
583 if ((curr_euid
== 0) && (euid
!= 0) && !W_oth
)
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",
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
);
595 check_regid_change (gid_t rgid
, gid_t egid
)
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
);
609 TprintfT (DBG_LT0
, "check_regid_change(%d->%d)\n", curr_rgid
, rgid
);
610 if ((curr_euid
== 0) && (rgid
!= 0) && !W_oth
)
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",
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
);
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
)
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",
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
);
637 TprintfT (DBG_LT2
, "init_lineage_intf()\n");
639 static int nesting_check
= 0;
640 if (nesting_check
>= 2)
642 /* segv before stack blows up */
643 nesting_check
/= (nesting_check
- 2);
647 __real_fork
= dlsym (RTLD_NEXT
, "fork");
648 if (__real_fork
== NULL
)
650 __real_fork
= dlsym (RTLD_DEFAULT
, "fork");
651 if (__real_fork
== NULL
)
653 dlflag
= RTLD_DEFAULT
;
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",
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
);
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
);
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");
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");
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
);
719 /*------------------------------------------------------------------------ */
720 /* Note: The following _prologue and _epilogue functions used to be dbx-visible.
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).
732 Notes on MT from Solaris 10 man pthread_atfork:
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
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.
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
758 linetrace_ext_fork_prologue (const char *variant
, char * n_lineage
, int *following_fork
)
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)
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
);
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
);
779 *following_fork
= check_follow_fork ();
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",
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");
795 linetrace_ext_fork_epilogue (const char *variant
, const pid_t ret
, char * n_lineage
, int *following_fork
)
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
);
809 /* *************************************child */
810 __collector_env_print ("fork_epilogue child at start");
811 /* start a new line */
813 __collector_mutex_init (&fork_lineage_lock
);
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");
824 /* stop recording this experiment, but preserve env vars */
825 linetrace_dormant ();
826 __collector_env_print ("fork_epilogue child after linetrace_dormant");
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
);
833 const char *params
= CALL_UTIL (getenv
)(SP_COLLECTOR_PARAMS
);
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",
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
);
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 ();
854 __collector_env_print ("fork_epilogue child at end");
855 /* *************************************end child */
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
];
866 CALL_UTIL (snprintf
)(msg
, sizeof (msg
), "pid=%d", ret
);
869 /* delete stillborn experiment? */
871 strerror_r (errno
, errmsg
, sizeof (errmsg
));
872 CALL_UTIL (snprintf
)(msg
, sizeof (msg
), "err %s", errmsg
);
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 */
882 dbg_current_mode
= FOLLOW_NONE
;
887 linetrace_ext_exec_prologue_end (const char *variant
, const char* cmd_string
,
888 char *const envp
[], int following_exec
)
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",
897 (unsigned) (ts
/ NANOSEC
), (unsigned) (ts
% NANOSEC
),
898 variant
, new_lineage
, following_exec
, cmd_string
);
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 */
908 coll_env
= (char**) envp
;
909 __collector_env_printall ("linetrace_ext_exec_prologue_end", coll_env
);
910 if (!CALL_UTIL (strstr
)(variant
, "posix_spawn"))
912 __collector_linetrace_shutdown_hwcs_6830763_XXXX
= 1;
913 __collector_suspend_experiment ("suspend_for_exec");
914 __collector_linetrace_shutdown_hwcs_6830763_XXXX
= 0;
916 if (CALL_UTIL (strstr
)(variant
, "posix_spawn"))
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;
927 linetrace_ext_exec_prologue (const char *variant
,
928 const char* path
, char *const argv
[],
929 char *const envp
[], int *following_exec
)
931 char cmd_string
[_POSIX_ARG_MAX
] = {'\0'};
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
);
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
));
948 while (((p
= argv
[++argn
]) != 0) &&
949 (len
= __collector_strlen (cmd_string
)) < sizeof (cmd_string
) - 2)
951 cmd_string
[len
++] = ' ';
952 __collector_strlcpy (cmd_string
+ len
, p
, sizeof (cmd_string
) - len
);
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
);
962 linetrace_ext_exec_epilogue (const char *variant
, char *const envp
[], const int ret
, int *following_exec
)
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"))
972 __collector_linetrace_shutdown_hwcs_6830763_XXXX
= 1;
973 __collector_resume_experiment ();
974 __collector_linetrace_shutdown_hwcs_6830763_XXXX
= 0;
976 if (CALL_UTIL (strstr
)(variant
, "posix_spawn"))
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;
983 hrtime_t ts
= GETRELTIME ();
988 strerror_r (errno
, errmsg
, sizeof (errmsg
));
989 CALL_UTIL (snprintf
)(msg
, sizeof (msg
), "err %s", errmsg
);
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",
996 (unsigned) (ts
/ NANOSEC
), (unsigned) (ts
% NANOSEC
),
997 variant
, new_lineage
, *following_exec
, msg
);
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;
1005 linetrace_ext_combo_prologue (const char *variant
, const char *cmd
, int *following_combo
)
1007 char cmd_string
[_POSIX_ARG_MAX
] = {'\0'};
1008 char execfile
[_POSIX_ARG_MAX
] = {'\0'};
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",
1013 dbg_current_mode
= FOLLOW_ON
;
1016 /* extract executable name from combo command */
1017 unsigned len
= strcspn (cmd
, " ");
1018 __collector_strlcpy (execfile
, cmd
, len
+ 1);
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
));
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
);
1029 /* Construct the lineage string for the new image */
1031 __collector_strcat (new_lineage
, "XXX");
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",
1037 (unsigned) (ts
/ NANOSEC
), (unsigned) (ts
% NANOSEC
),
1038 variant
, new_lineage
, *following_combo
, cmd_string
);
1039 if (*following_combo
)
1041 __collector_env_update (NULL
);
1042 TprintfT (DBG_LT0
, "linetrace_ext_combo_prologue(): Following %s(\"%s\")\n", variant
, execfile
);
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;
1051 linetrace_ext_combo_epilogue (const char *variant
, const int ret
, int *following_combo
)
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
);
1067 dbg_current_mode
= FOLLOW_NONE
;
1068 *following_combo
= 0;
1071 /*------------------------------------------------------------- fork */
1072 pid_t
fork () __attribute__ ((weak
, alias ("__collector_fork")));
1073 pid_t
_fork () __attribute__ ((weak
, alias ("__collector_fork")));
1076 __collector_fork (void)
1079 if (NULL_PTR (fork
))
1081 TprintfT (DBG_LT0
, "__collector_fork() calling init_lineage_intf()\n");
1082 init_lineage_intf ();
1084 __collector_env_print ("__collector_fork start");
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
)
1091 TprintfT (DBG_LT0
, "__collector_fork() not following, returning CALL_REAL(fork)()\n");
1092 return CALL_REAL (fork
)();
1094 int following_fork
= 0;
1095 linetrace_ext_fork_prologue ("fork", new_lineage
, &following_fork
);
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
);
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.
1117 pid_t
vfork () __attribute__ ((weak
, alias ("__collector_vfork")));
1118 pid_t
_vfork () __attribute__ ((weak
, alias ("__collector_vfork")));
1121 __collector_vfork (void)
1123 if (NULL_PTR (vfork
))
1124 init_lineage_intf ();
1127 int combo_flag
= (line_mode
== LM_TRACK_LINEAGE
) ? ((CHCK_REENTRANCE (guard
)) ? 1 : 0) : 0;
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
)();
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");
1139 char new_lineage
[LT_MAXNAMELEN
];
1141 int following_fork
= 0;
1142 linetrace_ext_fork_prologue ("vfork", new_lineage
, &following_fork
);
1144 pid_t ret
= CALL_REAL (fork
)();
1145 linetrace_ext_fork_epilogue ("vfork", ret
, new_lineage
, &following_fork
);
1149 /*------------------------------------------------------------- execve */
1150 int execve () __attribute__ ((weak
, alias ("__collector_execve")));
1153 __collector_execve (const char* path
, char *const argv
[], char *const envp
[])
1155 static char **coll_env
= NULL
; /* environment for collection */
1156 if (NULL_PTR (execve
))
1157 init_lineage_intf ();
1159 int combo_flag
= (line_mode
== LM_TRACK_LINEAGE
) ? ((CHCK_REENTRANCE (guard
)) ? 1 : 0) : 0;
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
);
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
);
1180 int execvp () __attribute__ ((weak
, alias ("__collector_execvp")));
1183 __collector_execvp (const char* file
, char *const argv
[])
1185 extern char **environ
; /* the process' actual environment */
1186 char ** envp
= environ
;
1187 if (NULL_PTR (execvp
))
1188 init_lineage_intf ();
1190 int combo_flag
= (line_mode
== LM_TRACK_LINEAGE
) ? ((CHCK_REENTRANCE (guard
)) ? 1 : 0) : 0;
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
);
1200 int following_exec
= 0;
1202 char **coll_env
= /* environment for collection */
1204 linetrace_ext_exec_prologue ("execvp", file
, argv
, envp
, &following_exec
);
1205 TprintfT (DBG_LT0
, "__collector_execvp(): coll_env=0x%p\n", coll_env
);
1207 int ret
= CALL_REAL (execvp
)(file
, argv
);
1208 linetrace_ext_exec_epilogue ("execvp", envp
, ret
, &following_exec
);
1212 int execv () __attribute__ ((weak
, alias ("__collector_execv")));
1215 __collector_execv (const char* path
, char *const argv
[])
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 ());
1224 ret
= __collector_execve (path
, argv
, envp
);
1228 int execle (const char* path
, const char *arg0
, ...) __attribute__ ((weak
, alias ("__collector_execle")));
1231 __collector_execle (const char* path
, const char *arg0
, ...)
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 ());
1241 register char **environmentp
;
1245 va_start (args
, arg0
);
1246 while (va_arg (args
, char *) != (char *) 0)
1250 * save the environment pointer, which is at the end of the
1251 * variable argument list
1253 environmentp
= va_arg (args
, char **);
1257 * load the arguments in the variable argument list
1258 * into the argument vector, and add the terminating null pointer
1260 va_start (args
, arg0
);
1261 /* workaround for bugid 1242839 */
1262 argvec
= (char **) alloca ((size_t) ((nargs
+ 2) * sizeof (char *)));
1264 *argp
++ = (char *) arg0
;
1265 while ((nextarg
= va_arg (args
, char *)) != (char *) 0)
1269 return __collector_execve (path
, argvec
, environmentp
);
1272 int execlp (const char* file
, const char *arg0
, ...) __attribute__ ((weak
, alias ("__collector_execlp")));
1275 __collector_execlp (const char* file
, const char *arg0
, ...)
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 ());
1287 va_start (args
, arg0
);
1288 while (va_arg (args
, char *) != (char *) 0)
1293 * load the arguments in the variable argument list
1294 * into the argument vector and add the terminating null pointer
1296 va_start (args
, arg0
);
1298 /* workaround for bugid 1242839 */
1299 argvec
= (char **) alloca ((size_t) ((nargs
+ 2) * sizeof (char *)));
1301 *argp
++ = (char *) arg0
;
1302 while ((nextarg
= va_arg (args
, char *)) != (char *) 0)
1306 return __collector_execvp (file
, argvec
);
1309 int execl (const char* path
, const char *arg0
, ...) __attribute__ ((weak
, alias ("__collector_execl")));
1312 __collector_execl (const char* path
, const char *arg0
, ...)
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 ());
1321 extern char **environ
;
1324 va_start (args
, arg0
);
1325 while (va_arg (args
, char *) != (char *) 0)
1330 * load the arguments in the variable argument list
1331 * into the argument vector and add the terminating null pointer
1333 va_start (args
, arg0
);
1335 /* workaround for bugid 1242839 */
1336 argvec
= (char **) alloca ((size_t) ((nargs
+ 2) * sizeof (char *)));
1338 *argp
++ = (char *) arg0
;
1339 while ((nextarg
= va_arg (args
, char *)) != (char *) 0)
1343 return __collector_execve (path
, argvec
, environ
);
1348 /*-------------------------------------------------------- posix_spawn */
1350 // map interposed symbol versions
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
[]);
1358 SYMVER_ATTRIBUTE (__collector_posix_spawn_2_15
, posix_spawn@GLIBC_2
.15
)
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
[])
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
);
1374 SYMVER_ATTRIBUTE (__collector_posix_spawn_2_2
, posix_spawn@GLIBC_2
.2
)
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
[])
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
);
1389 #else /* ^WSIZE(32) */
1390 SYMVER_ATTRIBUTE (__collector_posix_spawn_2_2_5
, posix_spawn@GLIBC_2
.2
.5)
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
[])
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
);
1404 #endif /* ^WSIZE(32) */
1407 __collector_posix_spawn_symver (int(real_posix_spawn
) (),
1408 #else /* ^ARCH(Intel) */
1410 __collector_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
[])
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
))
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 */
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
);
1434 if ((line_mode
!= LM_TRACK_LINEAGE
) || combo_flag
)
1437 return (real_posix_spawn
) (pidp
, path
, file_actions
, attrp
, argv
, envp
);
1439 return CALL_REAL (posix_spawn
)(pidp
, path
, file_actions
, attrp
, argv
, envp
);
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
);
1448 ret
= (real_posix_spawn
) (pidp
, path
, file_actions
, attrp
, argv
, coll_env
);
1450 ret
= CALL_REAL (posix_spawn
)(pidp
, path
, file_actions
, attrp
, argv
, coll_env
);
1452 POP_REENTRANCE (guard
);
1453 linetrace_ext_exec_epilogue ("posix_spawn", envp
, ret
, &following_exec
);
1457 /*-------------------------------------------------------- posix_spawnp */
1459 // map interposed symbol versions
1462 __collector_posix_spawnp_symver (int(real_posix_spawnp
) (), pid_t
*pidp
,
1464 const posix_spawn_file_actions_t
*file_actions
,
1465 const posix_spawnattr_t
*attrp
,
1466 char *const argv
[], char *const envp
[]);
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
[])
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
);
1485 SYMVER_ATTRIBUTE (__collector_posix_spawnp_2_2
, posix_spawnp@GLIBC_2
.2
)
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
[])
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
);
1500 #else /* ^WSIZE(32) */
1501 SYMVER_ATTRIBUTE (__collector_posix_spawnp_2_2_5
, posix_spawnp@GLIBC_2
.2
.5)
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
[])
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
);
1516 #endif /* ^WSIZE(32) */
1519 __collector_posix_spawnp_symver (int(real_posix_spawnp
) (),
1520 #else /* ^ARCH(Intel) */
1522 __collector_posix_spawnp (
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
[]){
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
))
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 */
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
);
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
)
1549 return (real_posix_spawnp
) (pidp
, path
, file_actions
, attrp
, argv
, envp
);
1551 return CALL_REAL (posix_spawnp
)(pidp
, path
, file_actions
, attrp
, argv
, envp
);
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
);
1560 ret
= (real_posix_spawnp
) (pidp
, path
, file_actions
, attrp
, argv
, coll_env
);
1562 ret
= CALL_REAL (posix_spawnp
)(pidp
, path
, file_actions
, attrp
, argv
, coll_env
);
1564 POP_REENTRANCE (guard
);
1565 linetrace_ext_exec_epilogue ("posix_spawnp", envp
, ret
, &following_exec
);
1569 /*------------------------------------------------------------- system */
1570 int system () __attribute__ ((weak
, alias ("__collector_system")));
1573 __collector_system (const char *cmd
)
1575 if (NULL_PTR (system
))
1576 init_lineage_intf ();
1578 "__collector_system(cmd=%s) interposing: line_mode=%d combo=%d\n",
1579 cmd
? cmd
: "NULL", line_mode
, get_combo_flag ());
1581 if (line_mode
== LM_TRACK_LINEAGE
)
1582 INIT_REENTRANCE (guard
);
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
);
1594 /*------------------------------------------------------------- popen */
1595 // map interposed symbol versions
1596 #if ARCH(Intel) && WSIZE(32)
1598 __collector_popen_symver (FILE*(real_popen
) (), const char *cmd
, const char *mode
);
1600 SYMVER_ATTRIBUTE (__collector_popen_2_1
, popen@GLIBC_2
.1
)
1602 __collector_popen_2_1 (const char *cmd
, const char *mode
)
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
);
1610 SYMVER_ATTRIBUTE (__collector_popen_2_0
, popen@GLIBC_2
.0
)
1612 __collector_popen_2_0 (const char *cmd
, const char *mode
)
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
);
1620 SYMVER_ATTRIBUTE (__collector__popen_2_1
, _popen@GLIBC_2
.1
)
1622 __collector__popen_2_1 (const char *cmd
, const char *mode
)
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
);
1630 SYMVER_ATTRIBUTE (__collector__popen_2_0
, _popen@GLIBC_2
.0
)
1632 __collector__popen_2_0 (const char *cmd
, const char *mode
)
1634 if (NULL_PTR (popen
))
1635 init_lineage_intf ();
1636 return __collector_popen_symver (CALL_REALF (popen_2_0
), cmd
, mode
);
1639 FILE * popen () __attribute__ ((weak
, alias ("__collector_popen")));
1642 #if ARCH(Intel) && WSIZE(32)
1644 __collector_popen_symver (FILE*(real_popen
) (), const char *cmd
, const char *mode
)
1648 __collector_popen (const char *cmd
, const char *mode
)
1652 if (NULL_PTR (popen
))
1653 init_lineage_intf ();
1655 "__collector_popen(cmd=%s) interposing: line_mode=%d combo=%d\n",
1656 cmd
? cmd
: "NULL", line_mode
, get_combo_flag ());
1658 if (line_mode
== LM_TRACK_LINEAGE
)
1659 INIT_REENTRANCE (guard
);
1662 #if ARCH(Intel) && WSIZE(32)
1663 return (real_popen
) (cmd
, mode
);
1665 return CALL_REALF (popen
)(cmd
, mode
);
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
);
1674 ret
= CALL_REALF (popen
)(cmd
, mode
);
1676 POP_REENTRANCE (guard
);
1677 linetrace_ext_combo_epilogue ("popen", (ret
== NULL
) ? (-1) : 0, &following_combo
);
1681 /*------------------------------------------------------------- grantpt */
1682 int grantpt () __attribute__ ((weak
, alias ("__collector_grantpt")));
1685 __collector_grantpt (const int fildes
)
1687 if (NULL_PTR (grantpt
))
1688 init_lineage_intf ();
1690 "__collector_grantpt(%d) interposing: line_mode=%d combo=%d\n",
1691 fildes
, line_mode
, get_combo_flag ());
1693 if (line_mode
== LM_TRACK_LINEAGE
)
1694 INIT_REENTRANCE (guard
);
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
);
1706 /*------------------------------------------------------------- ptsname */
1707 char *ptsname () __attribute__ ((weak
, alias ("__collector_ptsname")));
1710 __collector_ptsname (const int fildes
)
1712 if (NULL_PTR (ptsname
))
1713 init_lineage_intf ();
1715 "__collector_ptsname(%d) interposing: line_mode=%d combo=%d\n",
1716 fildes
, line_mode
, get_combo_flag ());
1718 if (line_mode
== LM_TRACK_LINEAGE
)
1719 INIT_REENTRANCE (guard
);
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
);
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.
1740 typedef struct __collector_clone_arg
1746 } __collector_clone_arg_t
;
1749 __collector_clone_fn (void *fn_arg
)
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
);
1760 int clone (int (*fn
)(void *), void *, int, void *, ...) __attribute__ ((weak
, alias ("__collector_clone")));
1763 __collector_clone (int (*fn
)(void *), void *child_stack
, int flags
, void *arg
,
1764 ... /* pid_t *ptid, struct user_desc *tls, pid_t *" ctid" */)
1768 if (flags
& CLONE_VM
)
1771 ret
= __collector_ext_clone_pthread (fn
, child_stack
, flags
, arg
, va
);
1776 if (NULL_PTR (clone
))
1777 init_lineage_intf ();
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
;
1794 if (flags
& (CLONE_CHILD_SETTID
| CLONE_CHILD_CLEARTID
))
1796 ptid
= va_arg (va
, pid_t
*);
1797 tls
= va_arg (va
, struct user_desc
*);
1798 ctid
= va_arg (va
, pid_t
*);
1801 else if (flags
& CLONE_SETTLS
)
1803 ptid
= va_arg (va
, pid_t
*);
1804 tls
= va_arg (va
, struct user_desc
*);
1807 else if (flags
& CLONE_PARENT_SETTID
)
1809 ptid
= va_arg (va
, pid_t
*);
1812 if ((line_mode
!= LM_TRACK_LINEAGE
) || combo_flag
|| funcinfo
== NULL
)
1817 ret
= CALL_REAL (clone
)(fn
, child_stack
, flags
, arg
, ptid
, tls
, ctid
);
1820 ret
= CALL_REAL (clone
)(fn
, child_stack
, flags
, arg
, ptid
, tls
);
1823 ret
= CALL_REAL (clone
)(fn
, child_stack
, flags
, arg
, ptid
);
1826 ret
= CALL_REAL (clone
)(fn
, child_stack
, flags
, arg
);
1833 linetrace_ext_fork_prologue ("clone", new_lineage
, &following_fork
);
1834 (*funcinfo
).following_fork
= following_fork
;
1838 ret
= CALL_REAL (clone
)(__collector_clone_fn
, child_stack
, flags
, funcinfo
, ptid
, tls
, ctid
);
1841 ret
= CALL_REAL (clone
)(__collector_clone_fn
, child_stack
, flags
, funcinfo
, ptid
, tls
);
1844 ret
= CALL_REAL (clone
)(__collector_clone_fn
, child_stack
, flags
, funcinfo
, ptid
);
1847 ret
= CALL_REAL (clone
)(__collector_clone_fn
, child_stack
, flags
, funcinfo
);
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
);
1859 /*-------------------------------------------------------------------- setuid */
1860 int setuid () __attribute__ ((weak
, alias ("__collector_setuid")));
1861 int _setuid () __attribute__ ((weak
, alias ("__collector_setuid")));
1864 __collector_setuid (uid_t ruid
)
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
);
1875 /*------------------------------------------------------------------- seteuid */
1876 int seteuid () __attribute__ ((weak
, alias ("__collector_seteuid")));
1877 int _seteuid () __attribute__ ((weak
, alias ("__collector_seteuid")));
1880 __collector_seteuid (uid_t euid
)
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
);
1891 /*------------------------------------------------------------------ setreuid */
1892 int setreuid () __attribute__ ((weak
, alias ("__collector_setreuid")));
1893 int _setreuid () __attribute__ ((weak
, alias ("__collector_setreuid")));
1896 __collector_setreuid (uid_t ruid
, uid_t euid
)
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
);
1907 /*-------------------------------------------------------------------- setgid */
1908 int setgid () __attribute__ ((weak
, alias ("__collector_setgid")));
1909 int _setgid () __attribute__ ((weak
, alias ("__collector_setgid")));
1912 __collector_setgid (gid_t rgid
)
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
);
1923 /*------------------------------------------------------------------- setegid */
1924 int setegid () __attribute__ ((weak
, alias ("__collector_setegid")));
1925 int _setegid () __attribute__ ((weak
, alias ("__collector_setegid")));
1928 __collector_setegid (gid_t egid
)
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
);
1939 /*------------------------------------------------------------------ setregid */
1940 int setregid () __attribute__ ((weak
, alias ("__collector_setregid")));
1941 int _setregid () __attribute__ ((weak
, alias ("__collector_setregid")));
1944 __collector_setregid (gid_t rgid
, gid_t egid
)
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
);
1955 /*------------------------------------------------------- selective following */
1958 linetrace_follow_experiment (const char *follow_spec
, const char *lineage_str
, const char *progname
)
1963 TprintfT (DBG_LT0
, "linetrace_follow_experiment(): MATCHES NULL follow_spec\n");
1966 int ercode
= regcomp (®ex_desc
, follow_spec
, REG_EXTENDED
| REG_NOSUB
| REG_NEWLINE
);
1969 // syntax error in parsing string
1972 regerror (ercode
, ®ex_desc
, errbuf
, sizeof (errbuf
));
1973 TprintfT (DBG_LT0
, "linetrace_follow_experiment: regerror()=%s\n", errbuf
);
1977 TprintfT (DBG_LT0
, "linetrace_follow_experiment(): compiled spec='%s'\n", follow_spec
);
1980 if (!regexec (®ex_desc
, lineage_str
, 0, NULL
, 0))
1982 TprintfT (DBG_LT0
, "linetrace_follow_experiment(): MATCHES lineage (follow_spec=%s,lineage=%s)\n",
1983 follow_spec
, lineage_str
);
1989 if (!regexec (®ex_desc
, progname
, 0, NULL
, 0))
1991 TprintfT (DBG_LT0
, "linetrace_follow_experiment(): MATCHES progname (follow_spec=%s,progname=%s)\n",
1992 follow_spec
, progname
);
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");