]> Git Repo - binutils.git/blob - gprofng/src/envsets.cc
Automatic date update in version.in
[binutils.git] / gprofng / src / envsets.cc
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 #include "config.h"
22 #include <assert.h>
23 #include <ctype.h>
24 #include <sys/param.h>
25 #include <unistd.h>
26
27 #include "gp-defs.h"
28 #include "util.h"
29 #include "collctrl.h"
30 #include "collect.h"
31 #include "StringBuilder.h"
32 #include "Settings.h"
33
34 #define STDEBUFSIZE     24000
35
36 #define LIBGP_COLLECTOR             "libgp-collector.so"
37 #define GPROFNG_PRELOAD_LIBDIRS     "GPROFNG_PRELOAD_LIBDIRS"
38 #define SP_COLLECTOR_EXPNAME        "SP_COLLECTOR_EXPNAME"
39 #define SP_COLLECTOR_FOLLOW_SPEC    "SP_COLLECTOR_FOLLOW_SPEC"
40 #define SP_COLLECTOR_PARAMS         "SP_COLLECTOR_PARAMS"
41 #define SP_COLLECTOR_FOUNDER        "SP_COLLECTOR_FOUNDER"
42 #define SP_COLLECTOR_ORIGIN_COLLECT "SP_COLLECTOR_ORIGIN_COLLECT"
43
44 static const char *LD_AUDIT[] = {
45   //    "LD_AUDIT",     Do not set LD_AUDIT on Linux
46   NULL
47 };
48
49 static const char *LD_PRELOAD[] = {
50   "LD_PRELOAD",
51   NULL
52 };
53
54 static const char *SP_PRELOAD[] = {
55   "SP_COLLECTOR_PRELOAD",
56   NULL
57 };
58
59 static const char *LD_LIBRARY_PATH[] = {
60   "LD_LIBRARY_PATH",
61   NULL,
62 };
63
64 static int
65 add_env (char *ev)
66 {
67   int r = putenv (ev);
68   if (r != 0)
69     {
70       dbe_write (2, GTXT ("Can't putenv of %s: run aborted\n"), ev);
71       free (ev);
72     }
73   return r;
74 }
75
76 int
77 collect::putenv_libcollector_ld_audits ()
78 {
79   StringBuilder sb;
80   for (unsigned int ii = 0; ii < ARR_SIZE (LD_AUDIT) && LD_AUDIT[ii]; ++ii)
81     {
82       sb.sprintf ("%s=%s", LD_AUDIT[ii], SP_LIBAUDIT_NAME);
83       // Append the current value. Check if already set
84       char *old_val = getenv (LD_AUDIT[ii]);
85       if (old_val != NULL)
86         {
87           while (isspace (*old_val))
88             ++old_val;
89           if (*old_val != (char) 0)
90             {
91               int fromIdx = sb.length ();
92               sb.append (" ");
93               sb.append (old_val);
94               if (sb.indexOf (SP_LIBAUDIT_NAME, fromIdx) >= 0)
95                 continue;       // Already set. Do nothing.
96             }
97         }
98       if (add_env (sb.toString ()))
99         return 1;
100     }
101   return 0;
102 }
103
104 int
105 collect::putenv_libcollector_ld_preloads ()
106 {
107   // for those data types that get extra libs LD_PRELOAD'd, add them
108   if (cc->get_synctrace_mode () != 0)
109     add_ld_preload ("libgp-sync.so");
110   if (cc->get_heaptrace_mode () != 0)
111     add_ld_preload ("libgp-heap.so");
112   if (cc->get_iotrace_mode () != 0)
113     add_ld_preload ("libgp-iotrace.so");
114   add_ld_preload (SP_LIBCOLLECTOR_NAME);
115
116   // --- putenv SP_COLLECTOR_PRELOAD*
117   int ii;
118   for (ii = 0; SP_PRELOAD[ii]; ii++)
119     {
120       // construct the SP_PRELOAD_* environment variables
121       // and put them into the environment
122       if (add_env (dbe_sprintf ("%s=%s", SP_PRELOAD[ii], sp_preload_list[ii])))
123         return 1;
124     }
125   // --- putenv LD_PRELOADS
126   /* purge LD_PRELOAD* of values containing contents of SP_LIBCOLLECTOR_NAME */
127   if (putenv_purged_ld_preloads (SP_LIBCOLLECTOR_NAME))
128     dbe_write (2, GTXT ("Warning: %s is already defined in one or more LD_PRELOAD environment variables\n"),
129                SP_LIBCOLLECTOR_NAME);
130   if (putenv_ld_preloads ())
131     return 1;
132   return 0;
133 }
134
135 int
136 collect::putenv_libcollector_ld_misc ()
137 {
138 #if 0 // XXX 1 turns on LD_DEBUG
139   putenv (strdup ("LD_DEBUG=audit,bindings,detail"));
140 #endif
141   // workaround to have the dynamic linker use absolute names
142   if (add_env (dbe_strdup ("LD_ORIGIN=yes")))
143     return 1;
144
145   // On Linux we have to provide SP_COLLECTOR_LIBRARY_PATH and LD_LIBRARY_PATH
146   // so that -agentlib:gp-collector works
147   // and so that collect -F works with 32/64-bit mix of processes
148
149   // Set GPROFNG_PRELOAD_LIBDIRS
150   char *ev = getenv (GPROFNG_PRELOAD_LIBDIRS);
151   char *libpath_list = NULL;
152   if (ev == NULL && settings->preload_libdirs == NULL)
153     {
154       settings->read_rc (false);
155       ev = settings->preload_libdirs;
156     }
157   ev = dbe_strdup (ev);
158   StringBuilder sb;
159   sb.appendf ("%s=", "SP_COLLECTOR_LIBRARY_PATH");
160   int len = sb.length ();
161   int cnt = 0;
162   char *fname = dbe_sprintf ("%s/%s/%s", LIBDIR, PACKAGE, LIBGP_COLLECTOR);
163   if (access (fname, R_OK | F_OK) == 0)
164     {
165       ++cnt;
166       sb.appendf ("%s/%s", LIBDIR, PACKAGE);
167     }
168   free (fname);
169   for (char *s = ev; s;)
170     {
171       char *s1 = strchr (s, ':');
172       if (s1)
173         *(s1++) = 0;
174       if (*s == '/')
175         {
176           fname = dbe_sprintf ("%s/%s/%s", s, PACKAGE, LIBGP_COLLECTOR);
177           if (access (fname, R_OK | F_OK) == 0)
178             {
179               if (++cnt != 1)
180                 sb.append (':');
181               sb.appendf ("%s", s);
182             }
183         }
184       else
185         {
186           fname = dbe_sprintf ("%s/%s/%s/%s", run_dir, s, PACKAGE, LIBGP_COLLECTOR);
187           if (access (fname, R_OK | F_OK) == 0)
188             {
189               if (++cnt != 1)
190                 sb.append (':');
191               sb.appendf ("%s/%s/%s", run_dir, s, PACKAGE);
192             }
193         }
194       free (fname);
195       s = s1;
196     }
197   free (ev);
198   if (cnt == 0)
199     {
200       dbe_write (2, GTXT ("configuration error: can not find %s. run aborted\n"),
201                  LIBGP_COLLECTOR);
202       return 1;
203     }
204   libpath_list = sb.toString ();
205   if (add_env (libpath_list))
206     return 1;
207   libpath_list += len;
208
209   // --- set LD_LIBRARY_PATH using libpath_list
210   char *old = getenv (LD_LIBRARY_PATH[0]);
211   if (old)
212     ev = dbe_sprintf ("%s=%s:%s", LD_LIBRARY_PATH[0], libpath_list, old);
213   else
214     ev = dbe_sprintf ("%s=%s", LD_LIBRARY_PATH[0], libpath_list);
215   if (add_env (ev))
216     return 1;
217   return 0;
218 }
219
220 void
221 collect::add_ld_preload (const char *lib)
222 {
223   for (int ii = 0; SP_PRELOAD[ii]; ii++)
224     {
225       char *old_sp = sp_preload_list[ii];
226       if (old_sp == NULL)
227         sp_preload_list[ii] = strdup (lib);
228       else
229         {
230           sp_preload_list[ii] = dbe_sprintf ("%s %s", old_sp, lib);
231           free (old_sp);
232         }
233     }
234 }
235
236 int
237 collect::putenv_memso ()
238 {
239   // Set environment variable "MEM_USE_LOG" to 1, to keep it out of stderr
240   if (add_env (dbe_strdup ("MEM_USE_LOG=1")))
241     return 1;
242   // Set environment variable "MEM_ABORT_ON_ERROR", to force a core dump
243   if (add_env (dbe_strdup ("MEM_ABORT_ON_ERROR=1")))
244     return 1;
245   add_ld_preload ("mem.so");
246   return putenv_ld_preloads ();
247 }
248
249 // set LD_PRELOAD and friends to prepend the given library or libraries
250
251 int
252 collect::putenv_ld_preloads ()
253 {
254   for (int ii = 0; LD_PRELOAD[ii]; ii++)
255     {
256       char *old_val = getenv (LD_PRELOAD[ii]);
257       int sp_num = ii;
258       assert (SP_PRELOAD[sp_num]);
259       char *preload_def;
260       if (old_val)
261         preload_def = dbe_sprintf ("%s=%s %s", LD_PRELOAD[ii], sp_preload_list[sp_num], old_val);
262       else
263         preload_def = dbe_sprintf ("%s=%s", LD_PRELOAD[ii], sp_preload_list[sp_num]);
264       if (add_env (preload_def))
265         return 1;
266     }
267   return 0;
268 }
269
270 /* copied from linetrace.c */
271 /*
272    function: env_strip()
273      Finds str in env; Removes
274      all characters from previous ':' or ' '
275      up to and including any trailing ':' or ' '.
276    params:
277      env: environment variable
278      str: substring to find
279      return: count of instances removed from env
280  */
281 int
282 collect::env_strip (char *env, const char *str)
283 {
284   int removed = 0;
285   char *p, *q;
286   if (env == NULL || str == NULL || *str == 0)
287     return 0;
288   size_t maxlen = strlen (env);
289   size_t len = strlen (str);
290   q = env;
291   while ((p = strstr (q, str)) != NULL)
292     {
293       q = p;
294       p += len;
295       if (*p)
296         {
297           while ((*p) && (*p != ':') && (*p != ' '))
298             p++;      /* skip the rest of the name*/
299           while ((*p == ':') || (*p == ' '))
300             p++; /* strip trailing separator */
301         }
302       while (*q != ':' && *q != ' ' && *q != '=' && q != env)
303         q--; /* strip path */
304       if (*p)
305         { /* copy the rest of the string */
306           if (q != env)
307             q++; /* restore leading separator (if any) */
308           size_t n = (maxlen - (q - env));
309           strncpy (q, p, n);
310         }
311       else
312         *q = 0;
313       removed++;
314     }
315   return removed;
316 }
317 /*
318    function: putenv_purged_ld_preloads()
319      Remove selected preload strings from all LD_PRELOAD* env vars.
320    params:
321      var: executable name (leading characters don't have to match)
322      return: number of instances removed from all PRELOAD vars.
323  */
324 int
325 collect::putenv_purged_ld_preloads (const char *var)
326 {
327   int total_removed = 0;
328   if (!var || *var == 0)
329     return 0;
330   for (int ii = 0; LD_PRELOAD[ii]; ii++)
331     {
332       char *ev = getenv (LD_PRELOAD[ii]);
333       int removed = 0;
334       if (!ev)
335         continue;
336       removed = env_strip (ev, var);
337       if (!removed)
338         continue;
339       if (putenv (ev) != 0)
340         dbe_write (2, GTXT ("Can't putenv of %s\n"), ev);
341       total_removed += removed;
342     }
343   return total_removed;
344 }
345 /*
346    function: putenv_append()
347      append string to current enviroment variable setting and then do a putenv()
348    params:
349      var: environment variable name
350      val: string to append
351  */
352 int
353 collect::putenv_append (const char *var, const char *val)
354 {
355   char *ev;
356   if (!var || !val)
357     return 1;
358   const char *old_val = getenv (var);
359   if (old_val == NULL || *old_val == 0)
360     ev = dbe_sprintf ("%s=%s", var, val);
361   else
362     ev = dbe_sprintf ("%s=%s %s", var, old_val, val);
363
364   // now put the new variable into the environment
365   if (add_env (ev))
366     return 1;
367   return 0;
368 }
369
370 int
371 collect::putenv_libcollector (void)
372 {
373   char buf[MAXPATHLEN + 1];
374   // --- set SP_COLLECTOR_EXPNAME
375   // fetch the experiment name and CWD
376   char *exp = cc->get_experiment ();
377   char *cwd = getcwd (buf, MAXPATHLEN);
378   char *ev;
379
380   // format the environment variable for the experiment directory name
381   if (cwd != NULL && exp[0] != '/')  // experiment is a relative path
382     ev = dbe_sprintf ("%s=%s/%s", SP_COLLECTOR_EXPNAME, cwd, exp);
383   else      // getcwd failed or experiment is a fullpath
384     ev = dbe_sprintf ("%s=%s", SP_COLLECTOR_EXPNAME, exp);
385
386   // set the experiment directory name
387   if (add_env (ev))
388     return 1;
389
390   // --- set SP_COLLECTOR_PARAMS
391   // set the data descriptor
392   exp = cc->get_data_desc ();
393   if (add_env (dbe_sprintf ("%s=%s", SP_COLLECTOR_PARAMS, exp)))
394     return 1;
395
396   // --- set SP_COLLECTOR_FOLLOW_SPEC
397   const char *follow_spec = cc->get_follow_cmp_spec ();
398   if (follow_spec)
399     // selective following has been enabled
400     if (add_env (dbe_sprintf ("%s=%s", SP_COLLECTOR_FOLLOW_SPEC, follow_spec)))
401       return 1;
402
403   if (add_env (dbe_sprintf ("%s=%d", SP_COLLECTOR_FOUNDER, getpid ())))
404     return 1;
405   if (add_env (dbe_sprintf ("%s=1", SP_COLLECTOR_ORIGIN_COLLECT)))
406     return 1;
407
408   // --- set LD_*
409   if (putenv_libcollector_ld_misc ())
410     return 1;
411
412   // --- set LD_PRELOAD*
413   if (putenv_libcollector_ld_preloads () != 0)
414     return 1;
415
416   // --- set JAVA_TOOL_OPTIONS
417   if (cc->get_java_mode () == 1)
418     if (putenv_append ("JAVA_TOOL_OPTIONS", "-agentlib:gp-collector"))
419         exit (1);
420 #if 0
421   // --- set LD_AUDIT*
422   if (putenv_libcollector_ld_audits () != 0)
423     return 1;
424 #endif
425   return 0;
426 }
This page took 0.047455 seconds and 4 git commands to generate.