aboutsummaryrefslogtreecommitdiff
path: root/gprofng/src/envsets.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gprofng/src/envsets.cc')
-rw-r--r--gprofng/src/envsets.cc420
1 files changed, 420 insertions, 0 deletions
diff --git a/gprofng/src/envsets.cc b/gprofng/src/envsets.cc
new file mode 100644
index 0000000..de06fbf
--- /dev/null
+++ b/gprofng/src/envsets.cc
@@ -0,0 +1,420 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+ Contributed by Oracle.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+#include "config.h"
+#include <assert.h>
+#include <ctype.h>
+#include <sys/param.h>
+#include <unistd.h>
+
+#include "gp-defs.h"
+#include "util.h"
+#include "collctrl.h"
+#include "collect.h"
+#include "StringBuilder.h"
+#include "Settings.h"
+
+#define STDEBUFSIZE 24000
+
+#define LIBGP_COLLECTOR "libgp-collector.so"
+#define GPROFNG_PRELOAD_LIBDIRS "GPROFNG_PRELOAD_LIBDIRS"
+#define SP_COLLECTOR_EXPNAME "SP_COLLECTOR_EXPNAME"
+#define SP_COLLECTOR_FOLLOW_SPEC "SP_COLLECTOR_FOLLOW_SPEC"
+#define SP_COLLECTOR_PARAMS "SP_COLLECTOR_PARAMS"
+#define SP_COLLECTOR_FOUNDER "SP_COLLECTOR_FOUNDER"
+#define SP_COLLECTOR_ORIGIN_COLLECT "SP_COLLECTOR_ORIGIN_COLLECT"
+
+static const char *LD_AUDIT[] = {
+ // "LD_AUDIT", Do not set LD_AUDIT on Linux
+ NULL
+};
+
+static const char *LD_PRELOAD[] = {
+ "LD_PRELOAD",
+ NULL
+};
+
+static const char *SP_PRELOAD[] = {
+ "SP_COLLECTOR_PRELOAD",
+ NULL
+};
+
+static const char *LD_LIBRARY_PATH[] = {
+ "LD_LIBRARY_PATH",
+ NULL,
+};
+
+static int
+add_env (char *ev)
+{
+ int r = putenv (ev);
+ if (r != 0)
+ {
+ dbe_write (2, GTXT ("Can't putenv of %s: run aborted\n"), ev);
+ free (ev);
+ }
+ return r;
+}
+
+int
+collect::putenv_libcollector_ld_audits ()
+{
+ StringBuilder sb;
+ for (unsigned int ii = 0; ii < ARR_SIZE (LD_AUDIT) && LD_AUDIT[ii]; ++ii)
+ {
+ sb.sprintf ("%s=%s", LD_AUDIT[ii], SP_LIBAUDIT_NAME);
+ // Append the current value. Check if already set
+ char *old_val = getenv (LD_AUDIT[ii]);
+ if (old_val != NULL)
+ {
+ while (isspace (*old_val))
+ ++old_val;
+ if (*old_val != (char) 0)
+ {
+ int fromIdx = sb.length ();
+ sb.append (" ");
+ sb.append (old_val);
+ if (sb.indexOf (SP_LIBAUDIT_NAME, fromIdx) >= 0)
+ continue; // Already set. Do nothing.
+ }
+ }
+ if (add_env (sb.toString ()))
+ return 1;
+ }
+ return 0;
+}
+
+int
+collect::putenv_libcollector_ld_preloads ()
+{
+ // for those data types that get extra libs LD_PRELOAD'd, add them
+ if (cc->get_synctrace_mode () != 0)
+ add_ld_preload ("libgp-sync.so");
+ if (cc->get_heaptrace_mode () != 0)
+ add_ld_preload ("libgp-heap.so");
+ if (cc->get_iotrace_mode () != 0)
+ add_ld_preload ("libgp-iotrace.so");
+ add_ld_preload (SP_LIBCOLLECTOR_NAME);
+
+ // --- putenv SP_COLLECTOR_PRELOAD*
+ int ii;
+ for (ii = 0; SP_PRELOAD[ii]; ii++)
+ {
+ // construct the SP_PRELOAD_* environment variables
+ // and put them into the environment
+ if (add_env (dbe_sprintf ("%s=%s", SP_PRELOAD[ii], sp_preload_list[ii])))
+ return 1;
+ }
+ // --- putenv LD_PRELOADS
+ /* purge LD_PRELOAD* of values containing contents of SP_LIBCOLLECTOR_NAME */
+ if (putenv_purged_ld_preloads (SP_LIBCOLLECTOR_NAME))
+ dbe_write (2, GTXT ("Warning: %s is already defined in one or more LD_PRELOAD environment variables\n"),
+ SP_LIBCOLLECTOR_NAME);
+ if (putenv_ld_preloads ())
+ return 1;
+ return 0;
+}
+
+int
+collect::putenv_libcollector_ld_misc ()
+{
+#if 0 // XXX 1 turns on LD_DEBUG
+ putenv (strdup ("LD_DEBUG=audit,bindings,detail"));
+#endif
+ // workaround to have the dynamic linker use absolute names
+ if (add_env (dbe_strdup ("LD_ORIGIN=yes")))
+ return 1;
+
+ // On Linux we have to provide SP_COLLECTOR_LIBRARY_PATH and LD_LIBRARY_PATH
+ // so that -agentlib:gp-collector works
+ // and so that collect -F works with 32/64-bit mix of processes
+
+ // Set GPROFNG_PRELOAD_LIBDIRS
+ char *ev = getenv (GPROFNG_PRELOAD_LIBDIRS);
+ char *libpath_list = NULL;
+ if (ev == NULL && settings->preload_libdirs == NULL)
+ {
+ settings->read_rc (false);
+ ev = settings->preload_libdirs;
+ }
+ ev = dbe_strdup (ev);
+ StringBuilder sb;
+ sb.appendf ("%s=", "SP_COLLECTOR_LIBRARY_PATH");
+ int len = sb.length ();
+ int cnt = 0;
+ for (char *s = ev; s;)
+ {
+ char *s1 = strchr (s, ':');
+ if (s1)
+ *(s1++) = 0;
+ char *fname;
+ if (*s == '/')
+ {
+ fname = dbe_sprintf ("%s/%s", s, LIBGP_COLLECTOR);
+ if (access (fname, R_OK | F_OK) == 0)
+ {
+ if (++cnt != 1)
+ sb.append (':');
+ sb.appendf ("%s", s);
+ }
+ }
+ else
+ {
+ fname = dbe_sprintf ("%s/%s/%s", run_dir, s, LIBGP_COLLECTOR);
+ if (access (fname, R_OK | F_OK) == 0)
+ {
+ if (++cnt != 1)
+ sb.append (':');
+ sb.appendf ("%s/%s", run_dir, s);
+ }
+ }
+ free (fname);
+ s = s1;
+ }
+ free (ev);
+ if (cnt == 0)
+ {
+ dbe_write (2, GTXT ("configuration error: can not find %s. run aborted\n"),
+ LIBGP_COLLECTOR);
+ return 1;
+ }
+ libpath_list = sb.toString ();
+ if (add_env (libpath_list))
+ return 1;
+ libpath_list += len;
+
+ // --- set LD_LIBRARY_PATH using libpath_list
+ char *old = getenv (LD_LIBRARY_PATH[0]);
+ if (old)
+ ev = dbe_sprintf ("%s=%s:%s", LD_LIBRARY_PATH[0], libpath_list, old);
+ else
+ ev = dbe_sprintf ("%s=%s", LD_LIBRARY_PATH[0], libpath_list);
+ if (add_env (ev))
+ return 1;
+ return 0;
+}
+
+void
+collect::add_ld_preload (const char *lib)
+{
+ for (int ii = 0; SP_PRELOAD[ii]; ii++)
+ {
+ char *old_sp = sp_preload_list[ii];
+ if (old_sp == NULL)
+ sp_preload_list[ii] = strdup (lib);
+ else
+ {
+ sp_preload_list[ii] = dbe_sprintf ("%s %s", old_sp, lib);
+ free (old_sp);
+ }
+ }
+}
+
+int
+collect::putenv_memso ()
+{
+ // Set environment variable "MEM_USE_LOG" to 1, to keep it out of stderr
+ if (add_env (dbe_strdup ("MEM_USE_LOG=1")))
+ return 1;
+ // Set environment variable "MEM_ABORT_ON_ERROR", to force a core dump
+ if (add_env (dbe_strdup ("MEM_ABORT_ON_ERROR=1")))
+ return 1;
+ add_ld_preload ("mem.so");
+ return putenv_ld_preloads ();
+}
+
+// set LD_PRELOAD and friends to prepend the given library or libraries
+
+int
+collect::putenv_ld_preloads ()
+{
+ for (int ii = 0; LD_PRELOAD[ii]; ii++)
+ {
+ char *old_val = getenv (LD_PRELOAD[ii]);
+ int sp_num = ii;
+ assert (SP_PRELOAD[sp_num]);
+ char *preload_def;
+ if (old_val)
+ preload_def = dbe_sprintf ("%s=%s %s", LD_PRELOAD[ii], sp_preload_list[sp_num], old_val);
+ else
+ preload_def = dbe_sprintf ("%s=%s", LD_PRELOAD[ii], sp_preload_list[sp_num]);
+ if (add_env (preload_def))
+ return 1;
+ }
+ return 0;
+}
+
+/* copied from linetrace.c */
+/*
+ function: env_strip()
+ Finds str in env; Removes
+ all characters from previous ':' or ' '
+ up to and including any trailing ':' or ' '.
+ params:
+ env: environment variable
+ str: substring to find
+ return: count of instances removed from env
+ */
+int
+collect::env_strip (char *env, const char *str)
+{
+ int removed = 0;
+ char *p, *q;
+ if (env == NULL || str == NULL || *str == 0)
+ return 0;
+ size_t maxlen = strlen (env);
+ size_t len = strlen (str);
+ q = env;
+ while ((p = strstr (q, str)) != NULL)
+ {
+ q = p;
+ p += len;
+ if (*p)
+ {
+ while ((*p) && (*p != ':') && (*p != ' '))
+ p++; /* skip the rest of the name*/
+ while ((*p == ':') || (*p == ' '))
+ p++; /* strip trailing separator */
+ }
+ while (*q != ':' && *q != ' ' && *q != '=' && q != env)
+ q--; /* strip path */
+ if (*p)
+ { /* copy the rest of the string */
+ if (q != env)
+ q++; /* restore leading separator (if any) */
+ size_t n = (maxlen - (q - env));
+ strncpy (q, p, n);
+ }
+ else
+ *q = 0;
+ removed++;
+ }
+ return removed;
+}
+/*
+ function: putenv_purged_ld_preloads()
+ Remove selected preload strings from all LD_PRELOAD* env vars.
+ params:
+ var: executable name (leading characters don't have to match)
+ return: number of instances removed from all PRELOAD vars.
+ */
+int
+collect::putenv_purged_ld_preloads (const char *var)
+{
+ int total_removed = 0;
+ if (!var || *var == 0)
+ return 0;
+ for (int ii = 0; LD_PRELOAD[ii]; ii++)
+ {
+ char *ev = getenv (LD_PRELOAD[ii]);
+ int removed = 0;
+ if (!ev)
+ continue;
+ removed = env_strip (ev, var);
+ if (!removed)
+ continue;
+ if (putenv (ev) != 0)
+ dbe_write (2, GTXT ("Can't putenv of %s\n"), ev);
+ total_removed += removed;
+ }
+ return total_removed;
+}
+/*
+ function: putenv_append()
+ append string to current enviroment variable setting and then do a putenv()
+ params:
+ var: environment variable name
+ val: string to append
+ */
+int
+collect::putenv_append (const char *var, const char *val)
+{
+ char *ev;
+ if (!var || !val)
+ return 1;
+ const char *old_val = getenv (var);
+ if (old_val == NULL || *old_val == 0)
+ ev = dbe_sprintf ("%s=%s", var, val);
+ else
+ ev = dbe_sprintf ("%s=%s %s", var, old_val, val);
+
+ // now put the new variable into the environment
+ if (add_env (ev))
+ return 1;
+ return 0;
+}
+
+int
+collect::putenv_libcollector (void)
+{
+ char buf[MAXPATHLEN + 1];
+ // --- set SP_COLLECTOR_EXPNAME
+ // fetch the experiment name and CWD
+ char *exp = cc->get_experiment ();
+ char *cwd = getcwd (buf, MAXPATHLEN);
+ char *ev;
+
+ // format the environment variable for the experiment directory name
+ if (cwd != NULL && exp[0] != '/') // experiment is a relative path
+ ev = dbe_sprintf ("%s=%s/%s", SP_COLLECTOR_EXPNAME, cwd, exp);
+ else // getcwd failed or experiment is a fullpath
+ ev = dbe_sprintf ("%s=%s", SP_COLLECTOR_EXPNAME, exp);
+
+ // set the experiment directory name
+ if (add_env (ev))
+ return 1;
+
+ // --- set SP_COLLECTOR_PARAMS
+ // set the data descriptor
+ exp = cc->get_data_desc ();
+ if (add_env (dbe_sprintf ("%s=%s", SP_COLLECTOR_PARAMS, exp)))
+ return 1;
+
+ // --- set SP_COLLECTOR_FOLLOW_SPEC
+ const char *follow_spec = cc->get_follow_cmp_spec ();
+ if (follow_spec)
+ // selective following has been enabled
+ if (add_env (dbe_sprintf ("%s=%s", SP_COLLECTOR_FOLLOW_SPEC, follow_spec)))
+ return 1;
+
+ if (add_env (dbe_sprintf ("%s=%d", SP_COLLECTOR_FOUNDER, getpid ())))
+ return 1;
+ if (add_env (dbe_sprintf ("%s=1", SP_COLLECTOR_ORIGIN_COLLECT)))
+ return 1;
+
+ // --- set LD_*
+ if (putenv_libcollector_ld_misc ())
+ return 1;
+
+ // --- set LD_PRELOAD*
+ if (putenv_libcollector_ld_preloads () != 0)
+ return 1;
+
+ // --- set JAVA_TOOL_OPTIONS
+ if (cc->get_java_mode () == 1)
+ if (putenv_append ("JAVA_TOOL_OPTIONS", "-agentlib:gp-collector"))
+ exit (1);
+#if 0
+ // --- set LD_AUDIT*
+ if (putenv_libcollector_ld_audits () != 0)
+ return 1;
+#endif
+ return 0;
+}