mirror of
https://github.com/autc04/Retro68.git
synced 2024-06-07 13:33:06 +00:00
421 lines
11 KiB
C++
421 lines
11 KiB
C++
/* 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", s, PACKAGE, 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/%s", run_dir, s, PACKAGE, LIBGP_COLLECTOR);
|
|
if (access (fname, R_OK | F_OK) == 0)
|
|
{
|
|
if (++cnt != 1)
|
|
sb.append (':');
|
|
sb.appendf ("%s/%s/%s", run_dir, s, PACKAGE);
|
|
}
|
|
}
|
|
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;
|
|
}
|