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