mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-27 04:52:05 +08:00
76bdc7266a
This adds 'Innovative Computing Labs' as an external author to update-copyright.py, to cover the copyright notice in gprofng/common/opteron_pcbe.c, and uses that plus another external author 'Oracle and' to update gprofng copyright dates. I'm not going to commit 'Oracle and' as an accepted author, but that covers the string "Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved." found in gprofng/testsuite/gprofng.display/jsynprog files.
841 lines
27 KiB
C
841 lines
27 KiB
C
/* Copyright (C) 2021-2023 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. */
|
|
|
|
/*
|
|
* Routines for managing the target's environment array
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include "descendants.h"
|
|
|
|
#define MAX_LD_PRELOADS 2
|
|
|
|
/* TprintfT(<level>,...) definitions. Adjust per module as needed */
|
|
#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings
|
|
#define DBG_LT1 1 // for configuration details, warnings
|
|
#define DBG_LT2 2
|
|
#define DBG_LT3 3
|
|
#define DBG_LT4 4
|
|
|
|
/* original environment settings to be saved for later restoration */
|
|
static char *sp_preloads[MAX_LD_PRELOADS];
|
|
static char *sp_libpaths[MAX_LD_PRELOADS];
|
|
char **sp_env_backup;
|
|
|
|
static const char *SP_ENV[];
|
|
static const char *LD_ENV[];
|
|
static const char *SP_PRELOAD[];
|
|
static const char *LD_PRELOAD[];
|
|
static const char *SP_LIBRARY_PATH[];
|
|
static const char *LD_LIBRARY_PATH[];
|
|
static int NUM_SP_ENV_VARS;
|
|
static int NUM_LD_ENV_VARS;
|
|
static int NUM_SP_PRELOADS;
|
|
static int NUM_LD_PRELOADS;
|
|
static int NUM_SP_LIBPATHS;
|
|
static int NUM_LD_LIBPATHS;
|
|
|
|
static const char *SP_ENV[] = {
|
|
SP_COLLECTOR_PARAMS, /* data descriptor */
|
|
SP_COLLECTOR_EXPNAME, /* experiment name */
|
|
SP_COLLECTOR_FOLLOW_SPEC, /* linetrace */
|
|
SP_COLLECTOR_FOUNDER, /* determine founder exp */
|
|
SP_PRELOAD_STRINGS, /* LD_PRELOADs for data collection */
|
|
SP_LIBPATH_STRINGS, /* LD_LIBRARY_PATHs for data collection */
|
|
"SP_COLLECTOR_TRACELEVEL", /* tprintf */
|
|
#if DEBUG
|
|
"SP_COLLECTOR_SIGACTION", /* dispatcher, hwprofile */
|
|
#endif
|
|
/* JAVA* */
|
|
/* LD_DEBUG=audit,bindings,detail */
|
|
/* LD_ORIGIN=yes */
|
|
NULL
|
|
};
|
|
|
|
static const char *LD_ENV[] = {
|
|
LD_PRELOAD_STRINGS, /* LD_PRELOADs */
|
|
LD_LIBPATH_STRINGS, /* LD_LIBRARY_PATHs */
|
|
JAVA_TOOL_OPTIONS, /* enable -agentlib:collector for JVMTI */
|
|
NULL
|
|
};
|
|
|
|
static const char *SP_PRELOAD[] = {
|
|
SP_PRELOAD_STRINGS,
|
|
NULL
|
|
};
|
|
|
|
static const char *LD_PRELOAD[] = {
|
|
LD_PRELOAD_STRINGS,
|
|
NULL
|
|
};
|
|
|
|
static const char *SP_LIBRARY_PATH[] = {
|
|
SP_LIBPATH_STRINGS,
|
|
NULL
|
|
};
|
|
static const char *LD_LIBRARY_PATH[] = {
|
|
LD_LIBPATH_STRINGS,
|
|
NULL
|
|
};
|
|
|
|
void
|
|
__collector_env_save_preloads ()
|
|
{
|
|
/* save the list of SP_PRELOADs */
|
|
int v;
|
|
for (v = 0; SP_PRELOAD[v]; v++)
|
|
{
|
|
sp_preloads[v] = __collector_strdup (CALL_UTIL (getenv)(SP_PRELOAD[v]));
|
|
TprintfT (DBG_LT3, "__collector_env_save_preloads: %s=%s\n", SP_PRELOAD[v], sp_preloads[v]);
|
|
}
|
|
NUM_SP_PRELOADS = v;
|
|
for (v = 0; SP_LIBRARY_PATH[v]; v++)
|
|
{
|
|
sp_libpaths[v] = __collector_strdup (CALL_UTIL (getenv)(SP_LIBRARY_PATH[v]));
|
|
TprintfT (DBG_LT4, "__collector_env_save_preloads: %s=%s\n", SP_LIBRARY_PATH[v],
|
|
sp_libpaths[v] ? sp_libpaths[v] : "NULL");
|
|
}
|
|
NUM_SP_LIBPATHS = v;
|
|
for (v = 0; LD_PRELOAD[v]; v++)
|
|
;
|
|
NUM_LD_PRELOADS = v;
|
|
for (v = 0; LD_LIBRARY_PATH[v]; v++)
|
|
;
|
|
NUM_LD_LIBPATHS = v;
|
|
for (v = 0; SP_ENV[v]; v++)
|
|
;
|
|
NUM_SP_ENV_VARS = v;
|
|
for (v = 0; LD_ENV[v]; v++)
|
|
;
|
|
NUM_LD_ENV_VARS = v;
|
|
}
|
|
|
|
/* free the memory involved in backing up the environment */
|
|
void
|
|
__collector_env_backup_free ()
|
|
{
|
|
int v = 0;
|
|
TprintfT (DBG_LT2, "env_backup_free()\n");
|
|
for (v = 0; sp_env_backup[v]; v++)
|
|
{
|
|
TprintfT (DBG_LT2, "env_backup_free():sp_env_backup[%d]=%s \n", v, sp_env_backup[v]);
|
|
__collector_freeCSize (__collector_heap, (char *) sp_env_backup[v], __collector_strlen (sp_env_backup[v]) + 1);
|
|
}
|
|
__collector_freeCSize (__collector_heap, (char**) sp_env_backup,
|
|
(NUM_SP_ENV_VARS + NUM_LD_ENV_VARS + 1) * sizeof (char*));
|
|
}
|
|
|
|
char **
|
|
__collector_env_backup ()
|
|
{
|
|
TprintfT (DBG_LT2, "env_backup_()\n");
|
|
char **backup = __collector_env_allocate (NULL, 1);
|
|
__collector_env_update (backup);
|
|
TprintfT (DBG_LT2, "env_backup_()\n");
|
|
return backup;
|
|
}
|
|
|
|
/*
|
|
function: env_prepend()
|
|
given an <old_str>, check to see if <str>
|
|
is already defined by it. If not, allocate
|
|
a new string and concat <envvar>=<str><separator><old_str>
|
|
params:
|
|
old_str: original string
|
|
str: substring to prepend
|
|
return: pointer to updated string or NULL if string was not updated.
|
|
*/
|
|
static char *
|
|
env_prepend (const char *envvar, const char *str, const char *separator,
|
|
const char *old_str)
|
|
{
|
|
if (!envvar || *envvar == 0 || !str || *str == 0)
|
|
{
|
|
/* nothing to do */
|
|
TprintfT (DBG_LT2, "env_prepend(\"%s\", \"%s\", \"%s\", \"%s\") -- nothing to do\n",
|
|
envvar, str, separator, old_str);
|
|
|
|
return NULL;
|
|
}
|
|
TprintfT (DBG_LT2, "env_prepend(\"%s\", \"%s\", \"%s\", \"%s\")\n",
|
|
envvar, str, separator, old_str);
|
|
char *ev;
|
|
size_t strsz;
|
|
if (!old_str || *old_str == 0)
|
|
{
|
|
strsz = __collector_strlen (envvar) + 1 + __collector_strlen (str) + 1;
|
|
ev = (char*) __collector_allocCSize (__collector_heap, strsz, 1);
|
|
if (ev)
|
|
{
|
|
CALL_UTIL (snprintf)(ev, strsz, "%s=%s", envvar, str);
|
|
assert (__collector_strlen (ev) + 1 == strsz);
|
|
}
|
|
else
|
|
TprintfT (DBG_LT2, "env_prepend(): could not allocate memory\n");
|
|
}
|
|
else
|
|
{
|
|
char *p = CALL_UTIL (strstr)(old_str, str);
|
|
if (p)
|
|
{
|
|
TprintfT (DBG_LT2, "env_prepend(): %s=%s was already set\n",
|
|
envvar, old_str);
|
|
return NULL;
|
|
}
|
|
strsz = __collector_strlen (envvar) + 1 + __collector_strlen (str) +
|
|
__collector_strlen (separator) + __collector_strlen (old_str) + 1;
|
|
ev = (char*) __collector_allocCSize (__collector_heap, strsz, 1);
|
|
if (ev)
|
|
{
|
|
CALL_UTIL (snprintf)(ev, strsz, "%s=%s%s%s", envvar, str, separator, old_str);
|
|
assert (__collector_strlen (ev) + 1 == strsz);
|
|
}
|
|
else
|
|
TprintfT (DBG_LT2, "env_prepend(): could not allocate memory\n");
|
|
}
|
|
TprintfT (DBG_LT2, "env_prepend(\"%s\", \"%s\", \"%s\", \"%s\") returns \"%s\"\n",
|
|
envvar, str, separator, old_str, (ev == NULL ? "NULL" : ev));
|
|
return ev;
|
|
}
|
|
|
|
/*
|
|
function: putenv_prepend()
|
|
get environment variable <envvar>, check to see if <str>
|
|
is already defined by it. If not prepend <str>
|
|
and put it back to environment.
|
|
params:
|
|
envvar: environment variable
|
|
str: substring to find
|
|
return: 0==success, nonzero on failure.
|
|
*/
|
|
int
|
|
putenv_prepend (const char *envvar, const char *str, const char *separator)
|
|
{
|
|
if (!envvar || *envvar == 0)
|
|
return 1;
|
|
const char * old_str = CALL_UTIL (getenv)(envvar);
|
|
char * newstr = env_prepend (envvar, str, separator, old_str);
|
|
if (newstr)
|
|
// now put the new variable into the environment
|
|
if (CALL_UTIL (putenv)(newstr) != 0)
|
|
{
|
|
TprintfT (DBG_LT2, "putenv_prepend(): ERROR %s is not set!\n", newstr);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
function: env_strip()
|
|
Finds substr in origstr; Removes
|
|
all characters from previous ':' or ' '
|
|
up to and including any trailing ':' or ' '.
|
|
params:
|
|
env: environment variable contents
|
|
str: substring to find
|
|
return: count of instances removed from env
|
|
*/
|
|
static int
|
|
env_strip (char *origstr, const char *substr)
|
|
{
|
|
int removed = 0;
|
|
char *p, *q;
|
|
if (origstr == NULL || substr == NULL || *substr == 0)
|
|
return 0;
|
|
while ((p = q = CALL_UTIL (strstr)(origstr, substr)))
|
|
{
|
|
p += __collector_strlen (substr);
|
|
while (*p == ':' || *p == ' ') /* strip trailing separator */
|
|
p++;
|
|
while (*q != ':' && *q != ' ' && *q != '=' && q != origstr) /* strip path */
|
|
q--;
|
|
if (q != origstr) /* restore leading separator (if any) */
|
|
q++;
|
|
__collector_strlcpy (q, p, __collector_strlen (p) + 1);
|
|
removed++;
|
|
}
|
|
return removed;
|
|
}
|
|
|
|
/*
|
|
function: env_ld_preload_strip()
|
|
Removes known libcollector shared objects from envv.
|
|
params:
|
|
var: shared object name (leading characters don't have to match)
|
|
return: 0 = so's removed, non-zero = so's not found.
|
|
*/
|
|
static int
|
|
env_ld_preload_strip (char *envv)
|
|
{
|
|
if (!envv || *envv == 0)
|
|
{
|
|
TprintfT (DBG_LT2, "env_ld_preload_strip(): WARNING - envv is NULL\n");
|
|
return -1;
|
|
}
|
|
for (int v = 0; SP_PRELOAD[v]; v++)
|
|
if (env_strip (envv, sp_preloads[v]))
|
|
return 0;
|
|
if (line_mode != LM_CLOSED)
|
|
TprintfT (DBG_LT2, "env_ld_preload_strip(): WARNING - could not strip SP_PRELOADS from '%s'\n",
|
|
envv);
|
|
return -2;
|
|
}
|
|
|
|
void
|
|
__collector_env_print (char * label)
|
|
{
|
|
#if DEBUG
|
|
TprintfT (DBG_LT2, "__collector_env_print(%s)\n", label);
|
|
for (int v = 0; v < MAX_LD_PRELOADS; v++)
|
|
TprintfT (DBG_LT2, " %s sp_preloads[%d] (0x%p)=%s\n", label,
|
|
v, sp_preloads[v], (sp_preloads[v] == NULL ? "NULL" : sp_preloads[v]));
|
|
for (int v = 0; SP_ENV[v]; v++)
|
|
{
|
|
char *s = CALL_UTIL (getenv)(SP_ENV[v]);
|
|
if (s == NULL)
|
|
s = "<null>";
|
|
TprintfT (DBG_LT2, " %s SP_ENV[%d] (0x%p): %s=\"%s\"\n", label, v, SP_ENV[v], SP_ENV[v], s);
|
|
}
|
|
for (int v = 0; LD_ENV[v]; v++)
|
|
{
|
|
char *s = CALL_UTIL (getenv)(LD_ENV[v]);
|
|
if (s == NULL)
|
|
s = "<null>";
|
|
TprintfT (DBG_LT2, " %s LD_ENV[%d] (0x%p): %s=\"%s\"\n", label, v, LD_ENV[v], LD_ENV[v], s);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void
|
|
__collector_env_printall (char *label, char *envp[])
|
|
{
|
|
#if DEBUG
|
|
TprintfT (DBG_LT2, "__collector_env_printall(%s): environment @ 0x%p\n", label, envp);
|
|
for (int i = 0; envp[i]; i++)
|
|
Tprintf (DBG_LT2, "\tenv[%d]@0x%p == %s\n", i, envp[i], envp[i]);
|
|
#endif
|
|
}
|
|
|
|
/* match collector environment variable */
|
|
int
|
|
env_match (char *envp[], const char *envvar)
|
|
{
|
|
int match = -1;
|
|
if (envp == NULL)
|
|
TprintfT (DBG_LT1, "env_match(%s): NULL envp!\n", envvar);
|
|
else
|
|
{
|
|
int i = 0;
|
|
while ((envp[i] != NULL) && (__collector_strStartWith (envp[i], envvar)))
|
|
i++;
|
|
if ((envp[i] == NULL) || (envp[i][__collector_strlen (envvar)] != '='))
|
|
TprintfT (DBG_LT4, "env_match(): @%p []%s not defined in envp\n", envp, envvar);
|
|
else
|
|
{
|
|
TprintfT (DBG_LT4, "env_match(): @%p [%d]%s defined in envp\n", envp, i, envp[i]);
|
|
match = i;
|
|
}
|
|
}
|
|
TprintfT (DBG_LT1, "env_match(%s): found in slot %d\n", envvar, match);
|
|
return (match);
|
|
}
|
|
|
|
/* allocate new environment with collector variables */
|
|
/* 1) copy all current envp[] ptrs into a new array, coll_env[] */
|
|
/* 2) if collector-related env ptrs not in envp[], append them to coll_env */
|
|
/* from processes' "environ" (allocate_env==1) */
|
|
/* or from sp_env_backup (allocate_env==0)*/
|
|
/* If they already exist in envp, probably is an error... */
|
|
/* 3) return coll_env */
|
|
|
|
/* __collector__env_update() need be called after this to set LD_ENV*/
|
|
char **
|
|
__collector_env_allocate (char *const old_env[], int allocate_env)
|
|
{
|
|
extern char **environ; /* the process' actual environment */
|
|
char **new_env; /* a new environment for collection */
|
|
TprintfT (DBG_LT3, "__collector_env_allocate(old_env=0x%p %s environ=0x%p)\n",
|
|
old_env, (old_env == environ) ? "==" : "!=", environ);
|
|
/* set up a copy of the provided old_env for collector use */
|
|
int old_env_size = 0;
|
|
|
|
/* determine number of (used) slots in old_env */
|
|
if (old_env)
|
|
while (old_env[old_env_size] != NULL)
|
|
old_env_size++;
|
|
/* allocate a new vector with additional slots */
|
|
int new_env_alloc_sz = old_env_size + NUM_SP_ENV_VARS + NUM_LD_ENV_VARS + 1;
|
|
new_env = (char**) __collector_allocCSize (__collector_heap, new_env_alloc_sz * sizeof (char*), 1);
|
|
if (new_env == NULL)
|
|
return NULL;
|
|
TprintfT (DBG_LT4, "__collector_env_allocate(): old_env has %d entries, new_env @ 0x%p\n", old_env_size, new_env);
|
|
|
|
/* copy provided old_env pointers to new collector environment */
|
|
int new_env_size = 0;
|
|
for (new_env_size = 0; new_env_size < old_env_size; new_env_size++)
|
|
new_env[new_env_size] = old_env[new_env_size];
|
|
|
|
/* check each required environment variable, adding as required */
|
|
const char * env_var;
|
|
int v;
|
|
for (v = 0; (env_var = SP_ENV[v]) != NULL; v++)
|
|
{
|
|
if (env_match ((char**) old_env, env_var) == -1)
|
|
{
|
|
int idx;
|
|
/* not found in old_env */
|
|
if (allocate_env)
|
|
{
|
|
if ((idx = env_match (environ, env_var)) != -1)
|
|
{
|
|
/* found in environ */
|
|
TprintfT (DBG_LT4, "__collector_env_allocate(): [%d]%s env restored!\n",
|
|
new_env_size, environ[idx]);
|
|
int varsz = __collector_strlen (environ[idx]) + 1;
|
|
char * var = (char*) __collector_allocCSize (__collector_heap, varsz, 1);
|
|
if (var == NULL)
|
|
return NULL;
|
|
__collector_strlcpy (var, environ[idx], varsz);
|
|
new_env[new_env_size++] = var;
|
|
}
|
|
else
|
|
{
|
|
/* not found in environ */
|
|
if ((__collector_strcmp (env_var, SP_COLLECTOR_PARAMS) == 0) ||
|
|
(__collector_strcmp (env_var, SP_COLLECTOR_EXPNAME) == 0))
|
|
TprintfT (DBG_LT1, "__collector_env_allocate(): note: %s environment variable not found\n",
|
|
env_var);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((idx = env_match (sp_env_backup, env_var)) != -1)
|
|
{
|
|
/* found in backup */
|
|
TprintfT (DBG_LT4, "__collector_env_allocate(): [%d]%s env restored!\n",
|
|
new_env_size, sp_env_backup[idx]);
|
|
new_env[new_env_size++] = sp_env_backup[idx];
|
|
}
|
|
else
|
|
{
|
|
/* not found in environ */
|
|
if ((__collector_strcmp (env_var, SP_COLLECTOR_PARAMS) == 0) ||
|
|
(__collector_strcmp (env_var, SP_COLLECTOR_EXPNAME) == 0))
|
|
TprintfT (DBG_LT1, "__collector_env_allocate(): note: %s environment variable not found\n",
|
|
env_var);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (v = 0; (env_var = LD_ENV[v]) != NULL; v++)
|
|
{
|
|
if (env_match ((char**) old_env, env_var) == -1)
|
|
{
|
|
int idx;
|
|
/* not found in old_env */
|
|
if (allocate_env)
|
|
{
|
|
if ((idx = env_match (environ, env_var)) != -1)
|
|
{
|
|
/* found in environ */
|
|
TprintfT (DBG_LT4, "__collector_env_allocate(): [%d]%s env restored!\n",
|
|
new_env_size, environ[idx]);
|
|
|
|
int varsz = __collector_strlen (env_var) + 2;
|
|
char * var = (char*) __collector_allocCSize (__collector_heap, varsz, 1);
|
|
if (var == NULL)
|
|
return NULL;
|
|
// assume __collector_env_update() will fill content of env_var
|
|
CALL_UTIL (snprintf)(var, varsz, "%s=", env_var);
|
|
new_env[new_env_size++] = var;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((idx = env_match (sp_env_backup, env_var)) != -1)
|
|
{
|
|
/* found in backup */
|
|
TprintfT (DBG_LT4, "__collector_env_allocate(): [%d]%s env restored!\n",
|
|
new_env_size, sp_env_backup[idx]);
|
|
new_env[new_env_size++] = sp_env_backup[idx];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ensure new_env vector ends with NULL */
|
|
new_env[new_env_size] = NULL;
|
|
assert (new_env_size <= new_env_alloc_sz);
|
|
TprintfT (DBG_LT4, "__collector_env_allocate(): new_env has %d entries (%d added), new_env=0x%p\n",
|
|
new_env_size, new_env_size - old_env_size, new_env);
|
|
if (new_env_size != old_env_size && !allocate_env)
|
|
__collector_log_write ("<event kind=\"%s\" id=\"%d\">%d</event>\n",
|
|
SP_JCMD_CWARN, COL_WARN_EXECENV, new_env_size - old_env_size);
|
|
__collector_env_printall ("__collector_env_allocate", new_env);
|
|
return (new_env);
|
|
}
|
|
|
|
/* unset collection environment variables */
|
|
/* if they exist in env... */
|
|
/* 1) push non-collectorized version to env */
|
|
|
|
/* Not mt safe */
|
|
void
|
|
__collector_env_unset (char *envp[])
|
|
{
|
|
int v;
|
|
const char * env_name;
|
|
TprintfT (DBG_LT3, "env_unset(envp=0x%p)\n", envp);
|
|
if (envp == NULL)
|
|
{
|
|
for (v = 0; (env_name = LD_PRELOAD[v]); v++)
|
|
{
|
|
const char *env_val = CALL_UTIL (getenv)(env_name);
|
|
if (env_val && CALL_UTIL (strstr)(env_val, sp_preloads[v]))
|
|
{
|
|
size_t sz = __collector_strlen (env_name) + 1 + __collector_strlen (env_val) + 1;
|
|
char * ev = (char*) __collector_allocCSize (__collector_heap, sz, 1);
|
|
if (ev == NULL)
|
|
return;
|
|
CALL_UTIL (snprintf)(ev, sz, "%s=%s", env_name, env_val);
|
|
assert (__collector_strlen (ev) + 1 == sz);
|
|
TprintfT (DBG_LT4, "env_unset(): old %s\n", ev);
|
|
env_ld_preload_strip (ev);
|
|
CALL_UTIL (putenv)(ev);
|
|
TprintfT (DBG_LT4, "env_unset(): new %s\n", ev);
|
|
}
|
|
}
|
|
// unset JAVA_TOOL_OPTIONS
|
|
env_name = JAVA_TOOL_OPTIONS;
|
|
const char * env_val = CALL_UTIL (getenv)(env_name);
|
|
if (env_val && CALL_UTIL (strstr)(env_val, COLLECTOR_JVMTI_OPTION))
|
|
{
|
|
size_t sz = __collector_strlen (env_name) + 1 + __collector_strlen (env_val) + 1;
|
|
char * ev = (char*) __collector_allocCSize (__collector_heap, sz, 1);
|
|
if (ev == NULL)
|
|
return;
|
|
CALL_UTIL (snprintf)(ev, sz, "%s=%s", env_name, env_val);
|
|
assert (__collector_strlen (ev) + 1 == sz);
|
|
TprintfT (DBG_LT4, "env_unset(): old %s\n", ev);
|
|
env_strip (ev, COLLECTOR_JVMTI_OPTION);
|
|
CALL_UTIL (putenv)(ev);
|
|
TprintfT (DBG_LT4, "env_unset(): new %s\n", ev);
|
|
}
|
|
__collector_env_print ("__collector_env_unset");
|
|
}
|
|
else
|
|
{
|
|
__collector_env_printall ("__collector_env_unset, before", envp);
|
|
for (v = 0; (env_name = LD_PRELOAD[v]); v++)
|
|
{
|
|
int idx = env_match (envp, env_name);
|
|
if (idx != -1)
|
|
{
|
|
char *env_val = envp[idx];
|
|
TprintfT (DBG_LT4, "env_unset(): old %s\n", env_val);
|
|
envp[idx] = "junk="; /* xxxx is it ok to use original string? */
|
|
env_ld_preload_strip (env_val);
|
|
envp[idx] = env_val;
|
|
TprintfT (DBG_LT4, "env_unset(): new %s\n", envp[idx]);
|
|
}
|
|
}
|
|
// unset JAVA_TOOL_OPTIONS
|
|
env_name = JAVA_TOOL_OPTIONS;
|
|
int idx = env_match(envp, env_name);
|
|
if (idx != -1) {
|
|
char *env_val = envp[idx];
|
|
TprintfT(DBG_LT4, "env_unset(): old %s\n", env_val);
|
|
envp[idx] = "junk="; /* xxxx is it ok to use original string? */
|
|
env_strip(env_val, COLLECTOR_JVMTI_OPTION);
|
|
envp[idx] = env_val;
|
|
TprintfT(DBG_LT4, "env_unset(): new %s\n", envp[idx]);
|
|
}
|
|
__collector_env_printall ("__collector_env_unset, after", envp );
|
|
}
|
|
}
|
|
|
|
/* update collection environment variables */
|
|
/* update LD_PRELOADs and push them */
|
|
/* not mt safe */
|
|
void
|
|
__collector_env_update (char *envp[])
|
|
{
|
|
const char *env_name;
|
|
TprintfT (DBG_LT1, "__collector_env_update(envp=0x%p)\n", envp);
|
|
extern char **environ;
|
|
if (envp == NULL)
|
|
{
|
|
int v;
|
|
TprintfT (DBG_LT2, "__collector_env_update(envp=NULL)\n");
|
|
__collector_env_printall (" environ array, before", environ);
|
|
__collector_env_print (" env_update at entry ");
|
|
|
|
/* SP_ENV */
|
|
for (v = 0; (env_name = SP_ENV[v]) != NULL; v++)
|
|
{
|
|
if (env_match (environ, env_name) == -1)
|
|
{
|
|
int idx;
|
|
if ((idx = env_match (sp_env_backup, env_name)) != -1)
|
|
{
|
|
unsigned strsz = __collector_strlen (sp_env_backup[idx]) + 1;
|
|
char *ev = (char*) __collector_allocCSize (__collector_heap, strsz, 1);
|
|
CALL_UTIL (snprintf)(ev, strsz, "%s", sp_env_backup[idx]);
|
|
if (CALL_UTIL (putenv)(ev) != 0)
|
|
TprintfT (DBG_LT2, "__collector_env_update(): ERROR %s is not set!\n",
|
|
sp_env_backup[idx]);
|
|
}
|
|
}
|
|
}
|
|
__collector_env_print (" env_update after SP_ENV settings ");
|
|
|
|
/* LD_LIBRARY_PATH */
|
|
for (v = 0; (env_name = LD_LIBRARY_PATH[v]); v++)
|
|
/* assumes same index used between LD and SP vars */
|
|
if (putenv_prepend (env_name, sp_libpaths[v], ":"))
|
|
TprintfT (DBG_LT2, "collector: ERROR %s=%s could not be set\n",
|
|
env_name, sp_libpaths[v]);
|
|
__collector_env_print (" env_update after LD_LIBRARY_PATH settings ");
|
|
|
|
/* LD_PRELOAD */
|
|
for (v = 0; (env_name = LD_PRELOAD[v]); v++)
|
|
/* assumes same index used between LD and SP vars */
|
|
if (putenv_prepend (env_name, sp_preloads[v], " "))
|
|
TprintfT (DBG_LT2, "collector: ERROR %s=%s could not be set\n",
|
|
env_name, sp_preloads[v]);
|
|
__collector_env_print (" env_update after LD_PRELOAD settings ");
|
|
|
|
/* JAVA_TOOL_OPTIONS */
|
|
if (java_mode)
|
|
if (putenv_prepend (JAVA_TOOL_OPTIONS, COLLECTOR_JVMTI_OPTION, " "))
|
|
TprintfT (DBG_LT2, "collector: ERROR %s=%s could not be set\n",
|
|
JAVA_TOOL_OPTIONS, COLLECTOR_JVMTI_OPTION);
|
|
__collector_env_print (" env_update after JAVA_TOOL settings ");
|
|
}
|
|
else
|
|
{
|
|
int v;
|
|
int idx;
|
|
TprintfT (DBG_LT2, "__collector_env_update(envp=0x%p) not NULL\n", envp);
|
|
__collector_env_printall ("__collector_env_update, before", envp);
|
|
/* LD_LIBRARY_PATH */
|
|
for (v = 0; (env_name = LD_LIBRARY_PATH[v]); v++)
|
|
{
|
|
int idx = env_match (envp, env_name);
|
|
if (idx != -1)
|
|
{
|
|
char *env_val = __collector_strchr (envp[idx], '=');
|
|
if (env_val)
|
|
env_val++; /* skip '=' */
|
|
/* assumes same index used between LD and SP vars */
|
|
char *new_str = env_prepend (env_name, sp_libpaths[v],
|
|
":", env_val);
|
|
if (new_str)
|
|
envp[idx] = new_str;
|
|
}
|
|
}
|
|
|
|
/* LD_PRELOAD */
|
|
for (v = 0; (env_name = LD_PRELOAD[v]); v++)
|
|
{
|
|
int idx = env_match (envp, env_name);
|
|
if (idx != -1)
|
|
{
|
|
char *env_val = __collector_strchr (envp[idx], '=');
|
|
if (env_val)
|
|
env_val++; /* skip '=' */
|
|
/* assumes same index used between LD and SP vars */
|
|
char *new_str = env_prepend (env_name, sp_preloads[v],
|
|
" ", env_val);
|
|
if (new_str)
|
|
envp[idx] = new_str;
|
|
}
|
|
}
|
|
|
|
/* JAVA_TOOL_OPTIONS */
|
|
if (java_mode)
|
|
{
|
|
env_name = JAVA_TOOL_OPTIONS;
|
|
idx = env_match (envp, env_name);
|
|
if (idx != -1)
|
|
{
|
|
char *env_val = __collector_strchr (envp[idx], '=');
|
|
if (env_val)
|
|
env_val++; /* skip '=' */
|
|
char *new_str = env_prepend (env_name, COLLECTOR_JVMTI_OPTION,
|
|
" ", env_val);
|
|
if (new_str)
|
|
envp[idx] = new_str;
|
|
}
|
|
}
|
|
}
|
|
__collector_env_printall ("__collector_env_update, after", environ);
|
|
}
|
|
|
|
|
|
/*------------------------------------------------------------- putenv */
|
|
int putenv () __attribute__ ((weak, alias ("__collector_putenv")));
|
|
int _putenv () __attribute__ ((weak, alias ("__collector_putenv")));
|
|
|
|
int
|
|
__collector_putenv (char * string)
|
|
{
|
|
if (CALL_UTIL (putenv) == __collector_putenv ||
|
|
CALL_UTIL (putenv) == NULL)
|
|
{ // __collector_libc_funcs_init failed
|
|
CALL_UTIL (putenv) = (int(*)())dlsym (RTLD_NEXT, "putenv");
|
|
if (CALL_UTIL (putenv) == NULL || CALL_UTIL (putenv) == __collector_putenv)
|
|
CALL_UTIL (putenv) = (int(*)())dlsym (RTLD_DEFAULT, "putenv");
|
|
if (CALL_UTIL (putenv) == NULL || CALL_UTIL (putenv) == __collector_putenv)
|
|
{
|
|
TprintfT (DBG_LT2, "__collector_putenv(): ERROR: no pointer found.\n");
|
|
errno = EBUSY;
|
|
return -1;
|
|
}
|
|
}
|
|
if (user_follow_mode == FOLLOW_NONE)
|
|
return CALL_UTIL (putenv)(string);
|
|
char * envp[] = {string, NULL};
|
|
__collector_env_update (envp);
|
|
return CALL_UTIL (putenv)(envp[0]);
|
|
}
|
|
|
|
/*------------------------------------------------------------- setenv */
|
|
int setenv () __attribute__ ((weak, alias ("__collector_setenv")));
|
|
int _setenv () __attribute__ ((weak, alias ("__collector_setenv")));
|
|
|
|
int
|
|
__collector_setenv (const char *name, const char *value, int overwrite)
|
|
{
|
|
if (CALL_UTIL (setenv) == __collector_setenv ||
|
|
CALL_UTIL (setenv) == NULL)
|
|
{ // __collector_libc_funcs_init failed
|
|
CALL_UTIL (setenv) = (int(*)())dlsym (RTLD_NEXT, "setenv");
|
|
if (CALL_UTIL (setenv) == NULL || CALL_UTIL (setenv) == __collector_setenv)
|
|
CALL_UTIL (setenv) = (int(*)())dlsym (RTLD_DEFAULT, "setenv");
|
|
if (CALL_UTIL (setenv) == NULL || CALL_UTIL (setenv) == __collector_setenv)
|
|
{
|
|
TprintfT (DBG_LT2, "__collector_setenv(): ERROR: no pointer found.\n");
|
|
errno = EBUSY;
|
|
return -1;
|
|
}
|
|
}
|
|
if (user_follow_mode == FOLLOW_NONE || !overwrite)
|
|
return CALL_UTIL (setenv)(name, value, overwrite);
|
|
size_t sz = __collector_strlen (name) + 1 + __collector_strlen (value) + 1;
|
|
char *ev = (char*) __collector_allocCSize (__collector_heap, sz, 1);
|
|
if (ev == NULL)
|
|
return CALL_UTIL (setenv)(name, value, overwrite);
|
|
CALL_UTIL (snprintf)(ev, sz, "%s=%s", name, value);
|
|
char * envp[] = {ev, NULL};
|
|
__collector_env_update (envp);
|
|
if (envp[0] == ev)
|
|
{
|
|
__collector_freeCSize (__collector_heap, ev, sz);
|
|
return CALL_UTIL (setenv)(name, value, overwrite);
|
|
}
|
|
else
|
|
{
|
|
char *env_val = __collector_strchr (envp[0], '=');
|
|
if (env_val)
|
|
{
|
|
*env_val = '\0';
|
|
env_val++; /* skip '=' */
|
|
}
|
|
return CALL_UTIL (setenv)(envp[0], env_val, overwrite);
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------------------------- unsetenv */
|
|
int unsetenv () __attribute__ ((weak, alias ("__collector_unsetenv")));
|
|
int _unsetenv () __attribute__ ((weak, alias ("__collector_unsetenv")));
|
|
|
|
int
|
|
__collector_unsetenv (const char *name)
|
|
{
|
|
if (CALL_UTIL (unsetenv) == __collector_unsetenv ||
|
|
CALL_UTIL (unsetenv) == NULL)
|
|
{ // __collector_libc_funcs_init failed
|
|
CALL_UTIL (unsetenv) = (int(*)())dlsym (RTLD_NEXT, "unsetenv");
|
|
if (CALL_UTIL (unsetenv) == NULL || CALL_UTIL (unsetenv) == __collector_unsetenv)
|
|
CALL_UTIL (unsetenv) = (int(*)())dlsym (RTLD_DEFAULT, "unsetenv");
|
|
if (CALL_UTIL (unsetenv) == NULL || CALL_UTIL (unsetenv) == __collector_unsetenv)
|
|
{
|
|
TprintfT (DBG_LT2, "__collector_unsetenv(): ERROR: no pointer found.\n");
|
|
errno = EBUSY;
|
|
return -1;
|
|
}
|
|
}
|
|
int ret = CALL_UTIL (unsetenv)(name);
|
|
if (user_follow_mode == FOLLOW_NONE)
|
|
return ret;
|
|
TprintfT (DBG_LT2, "__collector_unsetenv(): %d.\n", user_follow_mode);
|
|
size_t sz = __collector_strlen (name) + 1 + 1;
|
|
char *ev = (char*) __collector_allocCSize (__collector_heap, sz, 1);
|
|
if (ev == NULL)
|
|
return ret;
|
|
CALL_UTIL (snprintf)(ev, sz, "%s=", name);
|
|
char * envp[] = {ev, NULL};
|
|
__collector_env_update (envp);
|
|
if (envp[0] == ev)
|
|
__collector_freeCSize (__collector_heap, ev, sz);
|
|
else
|
|
CALL_UTIL (putenv)(envp[0]);
|
|
return ret;
|
|
}
|
|
|
|
/*------------------------------------------------------------- clearenv */
|
|
int clearenv () __attribute__ ((weak, alias ("__collector_clearenv")));
|
|
|
|
int
|
|
__collector_clearenv (void)
|
|
{
|
|
if (CALL_UTIL (clearenv) == __collector_clearenv || CALL_UTIL (clearenv) == NULL)
|
|
{
|
|
/* __collector_libc_funcs_init failed; look up clearenv now */
|
|
CALL_UTIL (clearenv) = (int(*)())dlsym (RTLD_NEXT, "clearenv");
|
|
if (CALL_UTIL (clearenv) == NULL || CALL_UTIL (clearenv) == __collector_clearenv)
|
|
/* still not found; try again */
|
|
CALL_UTIL (clearenv) = (int(*)())dlsym (RTLD_DEFAULT, "clearenv");
|
|
if (CALL_UTIL (clearenv) == NULL || CALL_UTIL (clearenv) == __collector_clearenv)
|
|
{
|
|
/* still not found -- a fatal error */
|
|
TprintfT (DBG_LT2, "__collector_clearenv(): ERROR: %s\n", dlerror ());
|
|
CALL_UTIL (fprintf)(stderr, "__collector_clearenv(): ERROR: %s\n", dlerror ());
|
|
errno = EBUSY;
|
|
return -1;
|
|
}
|
|
}
|
|
int ret = CALL_UTIL (clearenv)();
|
|
if (user_follow_mode == FOLLOW_NONE)
|
|
return ret;
|
|
if (sp_env_backup == NULL)
|
|
{
|
|
TprintfT (DBG_LT2, "__collector_clearenv: ERROR sp_env_backup is not set!\n");
|
|
return ret;
|
|
}
|
|
for (int v = 0; v < NUM_SP_ENV_VARS + NUM_LD_ENV_VARS; v++)
|
|
if (sp_env_backup[v] && CALL_UTIL (putenv)(sp_env_backup[v]) != 0)
|
|
TprintfT (DBG_LT2, "__collector_clearenv: ERROR %s is not set!\n",
|
|
sp_env_backup[v]);
|
|
return ret;
|
|
}
|