}
}
+struct stable_tag_checker: public embedded_tags_visitor
+{
+ bool stable;
+ embeddedcode* code;
+ stable_tag_checker (): embedded_tags_visitor(true), stable(false) {}
+ void visit_embeddedcode (embeddedcode* e);
+};
+
+void stable_tag_checker::visit_embeddedcode (embeddedcode* e)
+{
+ code = e;
+ embedded_tags_visitor::visit_embeddedcode(e);
+ if (tagged_p("/* stable */"))
+ stable = true;
+}
+
+struct test_visitor: public update_visitor
+{
+ systemtap_session& session;
+ functiondecl* current_function;
+ derived_probe* current_probe;
+ map<string,vardecl*> replaced;
+ vector<expr_statement*> new_stmts;
+ test_visitor(systemtap_session& s):
+ session(s), current_function(0), current_probe(0) {};
+
+ void visit_functioncall (functioncall* e);
+};
+
+void test_visitor::visit_functioncall (functioncall* e)
+{
+ if (!e->args.size())
+ {
+ varuse_collecting_visitor vut(session);
+ vut.current_function = e->referent;
+ e->referent->body->visit(&vut);
+
+ stable_tag_checker stc;
+ e->referent->body->visit(&stc);
+
+ if (stc.stable)
+ {
+ assert(stc.code);
+ if (!vut.side_effect_free())
+ throw SEMANTIC_ERROR(_("stable function must also be /* pure */"),
+ stc.code->tok);
+
+ string name("__stable_");
+ name.append(e->function).append("_value");
+
+ if (replaced.find(e->function) == replaced.end())
+ {
+ // New variable declaration to store result of function call
+ vardecl* v = new vardecl;
+ v->name = name;
+ v->tok = e->tok;
+ v->set_arity(0, e->tok);
+ v->type = e->type;
+ if (current_function)
+ current_function->locals.push_back(v);
+ else
+ current_probe->locals.push_back(v);
+
+ symbol* sym = new symbol;
+ sym->name = name;
+ sym->tok = e->tok;
+ sym->referent = v;
+ sym->type = e->type;
+
+ functioncall* fc = new functioncall;
+ fc->tok = e->tok;
+ fc->function = e->function;
+ fc->referent = e->referent;
+ fc->type = e->type;
+
+ assignment* a = new assignment;
+ a->tok = e->tok;
+ a->op = "=";
+ a->left = sym;
+ a->right = fc;
+ a->type = e->type;
+
+ expr_statement* es = new expr_statement;
+ es->tok = e->tok;
+ es->value = a;
+ new_stmts.push_back(es);
+
+ replaced[e->function] = v;
+ provide(sym);
+ }
+ else
+ {
+ // Function call value already stored
+ symbol* sym = new symbol;
+ sym->name = name;
+ sym->tok = e->tok;
+ sym->referent = replaced[e->function];
+ sym->type = e->type;
+ provide(sym);
+ }
+ return;
+ }
+ }
+
+ provide(e);
+}
+
+void optimize_test(systemtap_session& s)
+{
+ for (vector<derived_probe*>::const_iterator it = s.probes.begin();
+ it != s.probes.end(); ++it)
+ {
+ test_visitor t(s);
+ t.current_probe = *it;
+ t.replace((*it)->body);
+ block* b = static_cast<block*>((*it)->body);
+ b->statements.insert(b->statements.begin(), t.new_stmts.begin(),
+ t.new_stmts.end());
+ }
+ for (map<string,functiondecl*>::const_iterator fn = s.functions.begin();
+ fn != s.functions.end(); ++fn)
+ {
+ test_visitor t(s);
+ t.current_function = (*fn).second;
+ t.replace((*fn).second->body);
+ block* b = static_cast<block*>((*fn).second->body);
+ b->statements.insert(b->statements.begin(), t.new_stmts.begin(),
+ t.new_stmts.end());
+ }
+}
static int
semantic_pass_optimize1 (systemtap_session& s)
iterations++;
}
+ if (!s.unoptimized)
+ optimize_test(s);
+
return rc;
}
* Description: Returns the execname of a target process (or group of processes).
*/
function execname:string ()
-%{ /* pure */ /* unprivileged */
+%{ /* pure */ /* unprivileged */ /* stable */
strlcpy (STAP_RETVALUE, current->comm, MAXSTRINGLEN);
%}
* Description: This function returns the ID of a target process.
*/
function pid:long ()
-%{ /* pure */ /* unprivileged */
+%{ /* pure */ /* unprivileged */ /* stable */
STAP_RETVALUE = current->tgid;
%}
* the target pid namespace.
*/
function ns_pid:long ()
-%{ /* pure */ /* unprivileged */
+%{ /* pure */ /* unprivileged */ /* stable */
int64_t rc = from_target_pid_ns(current, PID);
if (rc < 0) STAP_ERROR ("cannot resolve id in namespace");
else STAP_RETURN (rc);
* Description: This function returns the thread ID of the target process.
*/
function tid:long ()
-%{ /* pure */ /* unprivileged */
+%{ /* pure */ /* unprivileged */ /* stable */
STAP_RETVALUE = current->pid;
%}
* in the target pid namespace if provided, or the stap process namespace.
*/
function ns_tid:long ()
-%{ /* pure */ /* unprivileged */
+%{ /* pure */ /* unprivileged */ /* stable */
int64_t rc = from_target_pid_ns(current, TID);
if (rc < 0) STAP_ERROR ("cannot resolve id in namespace");
else STAP_RETURN (rc);
* Description: This function return the process ID of the target proccess's parent process.
*/
function ppid:long()
-%{ /* pure */ /* unprivileged */
+%{ /* pure */ /* unprivileged */ /* stable */
#if defined(STAPCONF_REAL_PARENT)
STAP_RETVALUE = current->real_parent->tgid;
#else
* Description: This function return the process ID of the target proccess's parent process as seen in the target pid namespace if provided, or the stap process namespace.
*/
function ns_ppid:long()
-%{ /* pure */ /* unprivileged */
+%{ /* pure */ /* unprivileged */ /* stable */
int64_t rc = from_target_pid_ns(current->parent, PID);
if (rc < 0) STAP_ERROR ("cannot resolve id in namespace");
else STAP_RETURN (rc);
* current process.
*/
function pgrp:long ()
-%{ /* pure */ /* unprivileged */
+%{ /* pure */ /* unprivileged */ /* stable */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
struct signal_struct *ss = kread( &(current->signal) );
STAP_RETVALUE = kread ( &(ss->pgrp) );
* current process as seen in the target pid namespace if provided, or the stap process namespace.
*/
function ns_pgrp:long ()
-%{ /* pure */ /* unprivileged */
+%{ /* pure */ /* unprivileged */ /* stable */
int64_t rc = from_target_pid_ns(current, PGRP);
if (rc < 0) STAP_ERROR ("cannot resolve id in namespace");
else STAP_RETURN (rc);
* since Kernel 2.6.0.
*/
function sid:long ()
-%{ /* pure */ /* unprivileged */
+%{ /* pure */ /* unprivileged */ /* stable */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
struct signal_struct *ss = kread( &(current->signal) );
STAP_RETVALUE = kread ( &(ss->session) );
* since Kernel 2.6.0.
*/
function ns_sid:long ()
-%{ /* pure */ /* unprivileged */
+%{ /* pure */ /* unprivileged */ /* stable */
int64_t rc = from_target_pid_ns(current, SID);
if (rc < 0) STAP_ERROR ("cannot resolve id in namespace");
else STAP_RETURN (rc);
* process's parent procces.
*/
function pexecname:string ()
-%{ /* pure */ /* unprivileged */
+%{ /* pure */ /* unprivileged */ /* stable */
#if defined(STAPCONF_REAL_PARENT)
strlcpy (STAP_RETVALUE, current->real_parent->comm, MAXSTRINGLEN);
#else
* Description: This function returns the group ID of a target process.
*/
function gid:long ()
-%{ /* pure */ /* unprivileged */
+%{ /* pure */ /* unprivileged */ /* stable */
#ifdef STAPCONF_TASK_UID
STAP_RETVALUE = current->gid;
#else
* Description: This function returns the group ID of a target process as seen in the target user namespace if provided, or the stap process namespace.
*/
function ns_gid:long ()
-%{ /* pure */ /* unprivileged */
+%{ /* pure */ /* unprivileged */ /* stable */
int64_t rc = from_target_user_ns(current, GID);
if (rc < 0) STAP_ERROR ("cannot resolve id in namespace");
else STAP_RETURN (rc);
* Description: This function returns the effective gid of a target process
*/
function egid:long ()
-%{ /* pure */ /* unprivileged */
+%{ /* pure */ /* unprivileged */ /* stable */
#ifdef STAPCONF_TASK_UID
STAP_RETVALUE = current->egid;
#else
* Description: This function returns the effective gid of a target process as seen in the target user namespace if provided, or the stap process namespace
*/
function ns_egid:long ()
-%{ /* pure */ /* unprivileged */
+%{ /* pure */ /* unprivileged */ /* stable */
int64_t rc = from_target_user_ns(current, EGID);
if (rc < 0) STAP_ERROR ("cannot resolve id in namespace");
else STAP_RETURN (rc);
* Description: This function returns the user ID of the target process.
*/
function uid:long ()
-%{ /* pure */ /* unprivileged */
+%{ /* pure */ /* unprivileged */ /* stable */
#ifdef STAPCONF_TASK_UID
STAP_RETVALUE = current->uid;
#else
* Description: This function returns the user ID of the target process as seen in the target user namespace if provided, or the stap process namespace.
*/
function ns_uid:long ()
-%{ /* pure */ /* unprivileged */
+%{ /* pure */ /* unprivileged */ /* stable */
int64_t rc = from_target_user_ns(current, UID);
if (rc < 0) STAP_ERROR ("cannot resolve id in namespace");
else STAP_RETURN (rc);
* Description: Returns the effective user ID of the target process.
*/
function euid:long ()
-%{ /* pure */ /* unprivileged */
+%{ /* pure */ /* unprivileged */ /* stable */
#ifdef STAPCONF_TASK_UID
STAP_RETVALUE = current->euid;
#else
* Description: This function returns the effective user ID of the target process as seen in the target user namespace if provided, or the stap process namespace.
*/
function ns_euid:long ()
-%{ /* pure */ /* unprivileged */
+%{ /* pure */ /* unprivileged */ /* stable */
int64_t rc = from_target_user_ns(current, EUID);
if (rc < 0) STAP_ERROR ("cannot resolve id in namespace");
else STAP_RETURN (rc);
* point has occurred in the user's own process.
*/
function is_myproc:long ()
-%{ /* pure */ /* unprivileged */
+%{ /* pure */ /* unprivileged */ /* stable */
STAP_RETVALUE = is_myproc();
%}
* Description: This function returns the current cpu number.
*/
function cpu:long ()
-%{ /* pure */ /* unprivileged */
+%{ /* pure */ /* unprivileged */ /* stable */
STAP_RETVALUE = smp_processor_id();
%}
* when called from a begin or end probe.
*/
function registers_valid:long ()
-%{ /* pure */ /* unprivileged */
+%{ /* pure */ /* unprivileged */ /* stable */
STAP_RETVALUE = (c->user_mode_p
? (CONTEXT->uregs != NULL)
: (CONTEXT->kregs != NULL));
* Return 1 if the probe point occurred in user-mode.
*/
function user_mode:long ()
-%{ /* pure */ /* unprivileged */
+%{ /* pure */ /* unprivileged */ /* stable */
STAP_RETVALUE = CONTEXT->user_mode_p ? 1 : 0;
%}
* returns 0 otherwise.
*/
function is_return:long ()
-%{ /* pure */
+%{ /* pure */ /* stable */ /* stable */
if (CONTEXT->probe_type == stp_probe_type_kretprobe
|| CONTEXT->probe_type == stp_probe_type_uretprobe)
STAP_RETVALUE = 1;
* target() returns the pid for the executed command specified by -c
*/
function target:long ()
-%{ /* pure */ /* unprivileged */
+%{ /* pure */ /* unprivileged */ /* stable */
STAP_RETVALUE = _stp_target;
%}
* or set by stap -m <module_name>.
*/
function module_name:string ()
-%{ /* pure */ /* unprivileged */
+%{ /* pure */ /* unprivileged */ /* stable */
strlcpy(STAP_RETVALUE, THIS_MODULE->name, MAXSTRINGLEN);
%}
* Description: This function returns the size of the kernel stack.
*/
function stack_size:long ()
-%{ /* pure */
+%{ /* pure */ /* stable */
STAP_RETVALUE = THREAD_SIZE;
%}
* currently used in the kernel stack.
*/
function stack_used:long ()
-%{ /* pure */
+%{ /* pure */ /* stable */
char a;
STAP_RETVALUE = THREAD_SIZE - ((long)&a & (THREAD_SIZE-1));
%}
* currently available in the kernel stack.
*/
function stack_unused:long ()
-%{ /* pure */
+%{ /* pure */ /* stable */
char a;
STAP_RETVALUE = (long)&a & (THREAD_SIZE-1);
%}
* like symname() and symdata().
*/
function addr:long ()
-%{ /* pure */
+%{ /* pure */ /* stable */
if (CONTEXT->user_mode_p) {
STAP_RETVALUE = (intptr_t)(CONTEXT->uregs ? REG_IP(CONTEXT->uregs) : 0);
} else {
* where it entered the kernel.
*/
function uaddr:long ()
-%{ /* pure */ /* myproc-unprivileged */
+%{ /* pure */ /* myproc-unprivileged */ /* stable */
struct pt_regs *uregs;
if (CONTEXT->user_mode_p)