* buildrun.cxx (make_dyninst_run_command): pass module arguments on to stapdyn.
* runtime/dyninst/runtime.h (set_int64_t): new function.
* runtime/dyninst/stapdyn.h (stp_global_setter): function prototype.
* stapdyn/mutator.cxx (mutator::mutator): add modoptions to mutator.
(mutator::init_modoptions): new function.
(mutator::run_module_init): call init_modoptions to initialize globals.
* stapdyn/mutator.h (class mutator): add modoptions to mutator.
* stapdyn/stapdyn.cxx (main): collect module arguments from command line.
* translate.cxx (struct c_unparser): new emit_global_init_* functions.
(c_unparser::emit_global_param): stapdyn no longer calls this function.
(c_unparser::emit_global_init_setters): new function.
(c_unparser::emit_global_init): emit default initial values in stapdyn mode.
(c_unparser::emit_global_init_type): new function.
(c_unparser::emit_module_init): copy initial values of stapdyn globals
to shared memory as appropriate.
(translate_pass): emit static-initialization struct for stapdyn,
and also emit the setter function to access this struct.
* translate.h (struct c_unparser): document new emit_global_init_* functions.
cmd.push_back((remotedir.empty() ? s.tmpdir : remotedir)
+ "/" + s.module_filename());
+ // add module arguments
+ cmd.insert(cmd.end(), s.globalopts.begin(), s.globalopts.end());
+
return cmd;
}
#include "stat.c"
#include "unwind.c"
+/* Support function for int64_t module parameters. */
+static int set_int64_t(const char *val, int64_t *mp)
+{
+ char *endp;
+ long long ll;
+
+ if (!val)
+ return -EINVAL;
+
+ ll = strtoull(val, &endp, 0);
+
+ if ((endp == val) || ((int64_t)ll != ll) || (*endp != '\0'))
+ return -EINVAL;
+
+ *mp = (int64_t)ll;
+ return 0;
+}
+
static int systemtap_module_init(void);
static void systemtap_module_exit(void);
extern const char* stp_dyninst_shm_init(void);
extern int stp_dyninst_shm_connect(const char* name);
+/* The following function is dynamically generated by systemtap, and
+ used by stapdyn to modify global variables at module startup only
+ (that is, *before* running stp_dyninst_session_init()): */
+extern int stp_global_setter(const char *name, const char *value);
#define STAPDYN_PROBE_ALL_FLAGS (uint64_t)(STAPDYN_PROBE_FLAG_RETURN \
| STAPDYN_PROBE_FLAG_PROC_BEGIN | STAPDYN_PROBE_FLAG_PROC_END \
}
-mutator:: mutator (const string& module_name):
+mutator:: mutator (const string& module_name,
+ vector<string>& module_options):
module(NULL), module_name(resolve_path(module_name)),
- p_target_created(false), signal_count(0), utrace_enter_fn(NULL)
+ modoptions(module_options), p_target_created(false),
+ signal_count(0), utrace_enter_fn(NULL)
{
// NB: dlopen does a library-path search if the filename doesn't have any
// path components, which is why we use resolve_path(module_name)
return true;
}
+bool
+mutator::init_modoptions()
+{
+ typeof(&stp_global_setter) global_setter = NULL;
+ set_dlsym(global_setter, module, "stp_global_setter", false);
+
+ if (global_setter == NULL)
+ {
+ // Hypothetical backwards compatibility with older stapdyn:
+ stapwarn() << "compiled module does not support -G globals" << endl;
+ return false;
+ }
+
+ for (vector<string>::iterator it = modoptions.begin();
+ it != modoptions.end(); it++)
+ {
+ string modoption = *it;
+
+ // Parse modoption as "name=value"
+ // XXX: compare whether this behaviour fits safety regex in buildrun.cxx
+ string::size_type separator = modoption.find('=');
+ if (separator == string::npos)
+ {
+ stapwarn() << "could not parse module option '" << modoption << "'" << endl;
+ return false; // XXX: perhaps ignore the option instead?
+ }
+ string name = modoption.substr(0, separator);
+ string value = modoption.substr(separator+1);
+
+ int rc = global_setter(name.c_str(), value.c_str());
+ if (rc != 0)
+ {
+ stapwarn() << "incorrect module option '" << modoption << "'" << endl;
+ return false; // XXX: perhaps ignore the option instead?
+ }
+ }
+
+ return true;
+}
+
// Initialize the module session
bool
mutator::run_module_init()
return false;
}
+ // Before init runs, set any custom variables
+ if (!modoptions.empty() && !init_modoptions())
+ return false;
+
int rc = session_init();
if (rc)
{
void* module; // the locally dlopened probe module
std::string module_name; // the filename of the probe module
+ std::vector<std::string> modoptions; // custom globals from -G option
std::string module_shmem; // the global name of this module's shared memory
std::vector<dynprobe_target> targets; // the probe targets in the module
mutator (const mutator& other);
mutator& operator= (const mutator& other);
+ // Initialize the module global variables
+ bool init_modoptions();
+
// Initialize the module session
bool run_module_init();
typeof(&enter_dyninst_utrace_probe) utrace_enter_fn;
public:
- mutator (const std::string& module_name);
+ mutator (const std::string& module_name,
+ std::vector<std::string>& module_options);
~mutator ();
// Load the stap module and initialize all probe info.
}
// The first non-option is our stap module, required.
- if (optind == argc - 1)
- module = argv[optind];
+ if (optind < argc)
+ module = argv[optind++];
+
+ // Remaining non-options, if any, specify global variables.
+ vector<string> modoptions;
+ while (optind < argc)
+ {
+ modoptions.push_back(string(argv[optind++]));
+ }
if (!module || (command && pid))
usage (1);
if (!check_dyninst_sebools())
return 1;
- auto_ptr<mutator> session(new mutator(module));
+ auto_ptr<mutator> session(new mutator(module, modoptions));
if (!session.get() || !session->load())
{
staperror() << "failed to create the mutator!" << endl;
void emit_common_header ();
void emit_global (vardecl* v);
void emit_global_init (vardecl* v);
+ void emit_global_init_type (vardecl *v);
void emit_global_param (vardecl* v);
+ void emit_global_init_setters ();
void emit_functionsig (functiondecl* v);
void emit_module_init ();
void emit_module_refresh ();
{
string vn = c_globalname (v->name);
- // XXX: No module parameters with dyninst.
- if (session->runtime_usermode_p())
- return;
+ // For dyninst, use the emit_global_init_* functionality instead.
+ assert (!session->runtime_usermode_p());
// NB: systemtap globals can collide with linux macros,
// e.g. VM_FAULT_MAJOR. We want the parameter name anyway. This
}
+void
+c_unparser::emit_global_init_setters ()
+{
+ // Hack for dyninst module params: setter function forms a little
+ // linear lookup table ditty to find a global variable by name.
+ o->newline() << "int stp_global_setter (const char *name, const char *value) {";
+ o->newline(1);
+ for (unsigned i=0; i<session->globals.size(); i++)
+ {
+ vardecl* v = session->globals[i];
+ if (v->arity > 0) continue;
+ if (v->type != pe_string && v->type != pe_long) continue;
+
+ // Do not mangle v->name for the comparison!
+ o->line() << "if (0 == strcmp(name,\"" << v->name << "\"))" << " {";
+
+ o->indent(1);
+ if (v->type == pe_string)
+ {
+ c_assign("stp_global_init." + c_globalname(v->name), "value", pe_string, "BUG: global module param", v->tok);
+ o->newline() << "return 0;";
+ }
+ else
+ {
+ o->newline() << "return set_int64_t(value, &stp_global_init." << c_globalname(v->name) << ");";
+ }
+
+ o->newline(-1) << "} else ";
+ }
+ o->line() << "return -EINVAL;";
+ o->newline(-1) << "}";
+ o->newline();
+}
+
+
void
c_unparser::emit_global (vardecl *v)
{
v->init->visit(this);
o->line() << ",";
}
+ else if (v->arity == 0 && session->runtime_usermode_p())
+ {
+ // For dyninst: always try to put a default value into the initial
+ // static structure, so we don't have to guess if it was customized.
+ if (v->type == pe_long)
+ o->newline() << "." << c_globalname (v->name) << " = 0,";
+ else if (v->type == pe_string)
+ o->newline() << "." << c_globalname (v->name) << " = { '\\0' },"; // XXX: ""
+ }
// The lock and lock_skip_count are handled in emit_module_init.
}
+void
+c_unparser::emit_global_init_type (vardecl *v)
+{
+ // We can only statically initialize some scalars.
+ if (v->arity == 0) // ... although we still allow !v->init here.
+ {
+ o->newline() << c_typename(v->type) << " " << c_globalname(v->name) << ";";
+ }
+}
+
+
void
c_unparser::emit_functionsig (functiondecl* v)
vardecl* v = session->globals[i];
if (v->index_types.size() > 0)
o->newline() << getmap (v).init();
- else if (v->init && session->runtime_usermode_p())
- c_assign(getvar (v).value(), v->init, "global initialization");
+ else if (session->runtime_usermode_p() && v->arity == 0
+ && (v->type == pe_long || v->type == pe_string))
+ c_assign(getvar (v).value(), "stp_global_init." + c_globalname(v->name), v->type, "BUG: global initialization", v->tok);
else
o->newline() << getvar (v).init();
// NB: in case of failure of allocation, "rc" will be set to non-zero.
// We only need to statically initialize globals in kernel modules,
// where module parameters may want to override the script's value. In
- // stapdyn, the globals are actually part of the dynamic shared memory.
- if (!s.runtime_usermode_p())
+ // stapdyn, the globals are actually part of the dynamic shared memory,
+ // and the static structure is merely used as a source of default values.
+ s.op->newline();
+ if (!s.runtime_usermode_p ())
+ s.op->newline() << "static struct stp_globals stp_global = {";
+ else
+ {
+ s.op->newline() << "static struct {";
+ s.op->indent(1);
+ for (unsigned i=0; i<s.globals.size(); i++)
+ {
+ assert_no_interrupts();
+ s.up->emit_global_init_type (s.globals[i]);
+ }
+ s.op->newline(-1) << "} stp_global_init = {";
+ }
+ s.op->newline(1);
+ for (unsigned i=0; i<s.globals.size(); i++)
{
- s.op->newline();
- s.op->newline() << "static struct stp_globals stp_global = {";
- s.op->newline(1);
- for (unsigned i=0; i<s.globals.size(); i++)
- {
- assert_no_interrupts();
- s.up->emit_global_init (s.globals[i]);
- }
- s.op->newline(-1) << "};";
+ assert_no_interrupts();
+ s.up->emit_global_init (s.globals[i]);
}
+ s.op->newline(-1) << "};";
s.op->assert_0_indent();
}
s.op->assert_0_indent();
- // PR10298: attempt to avoid collisions with symbols
- for (unsigned i=0; i<s.globals.size(); i++)
- {
- s.op->newline();
- s.up->emit_global_param (s.globals[i]);
- }
+ if (s.runtime_usermode_p())
+ s.up->emit_global_init_setters();
+ else
+ // PR10298: attempt to avoid collisions with symbols
+ for (unsigned i=0; i<s.globals.size(); i++)
+ {
+ s.op->newline();
+ s.up->emit_global_param (s.globals[i]);
+ }
s.op->assert_0_indent();
}
catch (const semantic_error& e)
virtual void emit_global_init (vardecl* v) = 0;
// };
- virtual void emit_global_param (vardecl* v) = 0;
+ // struct {
+ virtual void emit_global_init_type (vardecl* v) = 0;
+ // TYPE s_NAME;
+ // } global_init = {
+ // ...
+ // }; // variation of the above for dyninst static-initialization
+
+ virtual void emit_global_param (vardecl* v) = 0; // for kernel
// module_param_... -- at end of file
+ virtual void emit_global_init_setters () = 0; // for dyninst
+ // int stp_global_setter (const char *name, const char *value);
+ // -- at end of file; returns -EINVAL on error
+
virtual void emit_functionsig (functiondecl* v) = 0;
// static void function_NAME (context* c);