tapset-utrace.cxx - systemtap
Data types defined
Functions defined
Source code
#include "session.h"
#include "tapsets.h"
#include "task_finder.h"
#include "tapset-dynprobe.h"
#include "translate.h"
#include "util.h"
#include <cstring>
#include <string>
using namespace std;
using namespace __gnu_cxx;
static const string TOK_PROCESS("process");
static const string TOK_BEGIN("begin");
static const string TOK_END("end");
static const string TOK_THREAD("thread");
static const string TOK_SYSCALL("syscall");
static const string TOK_RETURN("return");
enum utrace_derived_probe_flags {
UDPF_NONE,
UDPF_BEGIN, UDPF_END, UDPF_THREAD_BEGIN, UDPF_THREAD_END, UDPF_SYSCALL, UDPF_SYSCALL_RETURN, UDPF_NFLAGS
};
struct utrace_derived_probe: public derived_probe
{
bool has_path;
string path;
bool has_library;
string library;
int64_t pid;
enum utrace_derived_probe_flags flags;
bool target_symbol_seen;
utrace_derived_probe (systemtap_session &s, probe* p, probe_point* l,
bool hp, string &pn, int64_t pd,
enum utrace_derived_probe_flags f);
void join_group (systemtap_session& s);
void emit_privilege_assertion (translator_output*);
void print_dupe_stamp(ostream& o);
void getargs (std::list<std::string> &arg_set) const;
};
struct utrace_derived_probe_group: public generic_dpg<utrace_derived_probe>
{
private:
map<string, vector<utrace_derived_probe*> > probes_by_path;
typedef map<string, vector<utrace_derived_probe*> >::iterator p_b_path_iterator;
map<int64_t, vector<utrace_derived_probe*> > probes_by_pid;
typedef map<int64_t, vector<utrace_derived_probe*> >::iterator p_b_pid_iterator;
unsigned num_probes;
bool flags_seen[UDPF_NFLAGS];
void emit_linux_probe_decl (systemtap_session& s, utrace_derived_probe *p);
void emit_module_linux_decls (systemtap_session& s);
void emit_module_linux_init (systemtap_session& s);
void emit_module_linux_exit (systemtap_session& s);
void emit_dyninst_probe_decl (systemtap_session& s, const string& path,
utrace_derived_probe *p);
void emit_module_dyninst_decls (systemtap_session& s);
void emit_module_dyninst_init (systemtap_session& s);
void emit_module_dyninst_exit (systemtap_session& s);
public:
utrace_derived_probe_group(): num_probes(0), flags_seen() { }
void enroll (utrace_derived_probe* probe);
void emit_module_decls (systemtap_session& s);
void emit_module_init (systemtap_session& s);
void emit_module_exit (systemtap_session& s);
};
struct utrace_var_expanding_visitor: public var_expanding_visitor
{
utrace_var_expanding_visitor(systemtap_session& s, probe_point* l,
const string& pn,
enum utrace_derived_probe_flags f):
sess (s), base_loc (l), probe_name (pn), flags (f),
target_symbol_seen (false), add_block(NULL), add_probe(NULL) {}
systemtap_session& sess;
probe_point* base_loc;
string probe_name;
enum utrace_derived_probe_flags flags;
bool target_symbol_seen;
block *add_block;
probe *add_probe;
std::map<std::string, symbol *> return_ts_map;
void visit_target_symbol_arg (target_symbol* e);
void visit_target_symbol_context (target_symbol* e);
void visit_target_symbol_cached (target_symbol* e);
void visit_target_symbol (target_symbol* e);
};
utrace_derived_probe::utrace_derived_probe (systemtap_session &s,
probe* p, probe_point* l,
bool hp, string &pn, int64_t pd,
enum utrace_derived_probe_flags f):
derived_probe (p, l, true ),
has_path(hp), path(pn), has_library(false), pid(pd), flags(f),
target_symbol_seen(false)
{
if (!s.runtime_usermode_p())
check_process_probe_kernel_support(s);
utrace_var_expanding_visitor v (s, l, name, flags);
v.replace (this->body);
target_symbol_seen = v.target_symbol_seen;
if (v.add_block)
this->body = new block(v.add_block, this->body);
if (v.add_probe)
{
stapfile *f = new stapfile;
f->probes.push_back(v.add_probe);
s.files.push_back(f);
}
vector<probe_point::component*> comps;
if (hp)
comps.push_back (new probe_point::component(TOK_PROCESS, new literal_string(path)));
else if (pid != 0)
comps.push_back (new probe_point::component(TOK_PROCESS, new literal_number(pid)));
else
comps.push_back (new probe_point::component(TOK_PROCESS));
switch (flags)
{
case UDPF_THREAD_BEGIN:
comps.push_back (new probe_point::component(TOK_THREAD));
comps.push_back (new probe_point::component(TOK_BEGIN));
break;
case UDPF_THREAD_END:
comps.push_back (new probe_point::component(TOK_THREAD));
comps.push_back (new probe_point::component(TOK_END));
break;
case UDPF_SYSCALL:
comps.push_back (new probe_point::component(TOK_SYSCALL));
break;
case UDPF_SYSCALL_RETURN:
comps.push_back (new probe_point::component(TOK_SYSCALL));
comps.push_back (new probe_point::component(TOK_RETURN));
break;
case UDPF_BEGIN:
comps.push_back (new probe_point::component(TOK_BEGIN));
break;
case UDPF_END:
comps.push_back (new probe_point::component(TOK_END));
break;
default:
assert (0);
}
this->sole_location()->components = comps;
}
void
utrace_derived_probe::join_group (systemtap_session& s)
{
if (! s.utrace_derived_probes)
{
s.utrace_derived_probes = new utrace_derived_probe_group ();
}
s.utrace_derived_probes->enroll (this);
this->group = s.utrace_derived_probes;
if (s.runtime_usermode_p())
enable_dynprobes(s);
else
enable_task_finder(s);
}
void
utrace_derived_probe::emit_privilege_assertion (translator_output* o)
{
if (flags == UDPF_END)
return;
emit_process_owner_assertion (o);
}
void
utrace_derived_probe::print_dupe_stamp(ostream& o)
{
if (flags == UDPF_END)
print_dupe_stamp_unprivileged (o);
else
print_dupe_stamp_unprivileged_process_owner (o);
}
void
utrace_derived_probe::getargs(std::list<std::string> &arg_set) const
{
arg_set.push_back("$syscall:long");
arg_set.push_back("$arg1:long");
arg_set.push_back("$arg2:long");
arg_set.push_back("$arg3:long");
arg_set.push_back("$arg4:long");
arg_set.push_back("$arg5:long");
arg_set.push_back("$arg6:long");
}
void
utrace_var_expanding_visitor::visit_target_symbol_cached (target_symbol* e)
{
stringstream ts_name_stream;
e->print(ts_name_stream);
string ts_name = ts_name_stream.str();
map<string, symbol *>::iterator i = return_ts_map.find(ts_name);
if (i != return_ts_map.end())
{
provide (i->second);
return;
}
string aname = (string("_utrace_tvar_")
+ e->sym_name()
+ "_" + lex_cast(tick++));
vardecl* vd = new vardecl;
vd->name = aname;
vd->tok = e->tok;
sess.globals.push_back (vd);
symbol* tidsym = new symbol;
tidsym->name = string("_utrace_tvar_tid");
tidsym->tok = e->tok;
if (add_block == NULL)
{
add_block = new block;
add_block->tok = e->tok;
functioncall* fc = new functioncall;
fc->tok = e->tok;
fc->function = string("tid");
assignment* a = new assignment;
a->tok = e->tok;
a->op = "=";
a->left = tidsym;
a->right = fc;
expr_statement* es = new expr_statement;
es->tok = e->tok;
es->value = a;
add_block->statements.push_back (es);
}
arrayindex* ai_tvar = new arrayindex;
ai_tvar->tok = e->tok;
symbol* sym = new symbol;
sym->name = aname;
sym->tok = e->tok;
ai_tvar->base = sym;
ai_tvar->indexes.push_back(tidsym);
symbol* tmpsym = new symbol;
tmpsym->name = aname + "_tmp";
tmpsym->tok = e->tok;
assignment* a = new assignment;
a->tok = e->tok;
a->op = "=";
a->left = tmpsym;
a->right = ai_tvar;
expr_statement* es = new expr_statement;
es->tok = e->tok;
es->value = a;
add_block->statements.push_back (es);
delete_statement* ds = new delete_statement;
ds->tok = e->tok;
ds->value = ai_tvar;
add_block->statements.push_back (ds);
if (add_probe == NULL)
{
add_probe = new probe;
add_probe->tok = e->tok;
probe_point* pp = new probe_point;
for (unsigned c = 0; c < base_loc->components.size(); c++)
{
if (base_loc->components[c]->functor == "return")
break;
else
pp->components.push_back(base_loc->components[c]);
}
pp->optional = base_loc->optional;
add_probe->locations.push_back(pp);
add_probe->body = new block;
add_probe->body->tok = e->tok;
functioncall* fc = new functioncall;
fc->tok = e->tok;
fc->function = string("tid");
assignment* a = new assignment;
a->tok = e->tok;
a->op = "=";
a->left = tidsym;
a->right = fc;
expr_statement* es = new expr_statement;
es->tok = e->tok;
es->value = a;
add_probe->body = new block(add_probe->body, es);
vardecl* vd = new vardecl;
vd->tok = e->tok;
vd->name = tidsym->name;
vd->type = pe_long;
vd->set_arity(0, e->tok);
add_probe->locals.push_back(vd);
}
a = new assignment;
a->tok = e->tok;
a->op = "=";
a->left = ai_tvar;
a->right = e;
es = new expr_statement;
es->tok = e->tok;
es->value = a;
add_probe->body = new block(add_probe->body, es);
provide (tmpsym);
return_ts_map[ts_name] = tmpsym;
return;
}
void
utrace_var_expanding_visitor::visit_target_symbol_arg (target_symbol* e)
{
if (flags != UDPF_SYSCALL)
throw SEMANTIC_ERROR (_("only \"process(PATH_OR_PID).syscall\" support $argN or $$parms."), e->tok);
if (e->name == "$$parms")
{
print_format* pf = print_format::create(e->tok, "sprintf");
target_symbol_seen = true;
for (unsigned i = 0; i < 6; ++i)
{
if (i > 0)
pf->raw_components += " ";
pf->raw_components += "$arg" + lex_cast(i+1);
target_symbol *tsym = new target_symbol;
tsym->tok = e->tok;
tsym->name = "$arg" + lex_cast(i+1);
tsym->saved_conversion_error = 0;
pf->raw_components += "=%#x"; FIXME
functioncall* n = new functioncall; n->tok = e->tok;
n->function = "_utrace_syscall_arg";
n->referent = 0;
literal_number *num = new literal_number(i);
num->tok = e->tok;
n->args.push_back(num);
pf->args.push_back(n);
}
pf->components = print_format::string_to_components(pf->raw_components);
provide (pf);
}
else {
string argnum_s = e->name.substr(4,e->name.length()-4);
int argnum = 0;
try
{
argnum = lex_cast<int>(argnum_s);
}
catch (const runtime_error& f) {
throw SEMANTIC_ERROR (_("invalid syscall argument number (1-6)"), e->tok);
}
e->assert_no_components("utrace");
FIXME if (argnum < 1 || argnum > 6)
throw SEMANTIC_ERROR (_("invalid syscall argument number (1-6)"), e->tok);
bool lvalue = is_active_lvalue(e);
if (lvalue)
throw SEMANTIC_ERROR(_("utrace '$argN' variable is read-only"), e->tok);
target_symbol_seen = true;
functioncall* n = new functioncall;
n->tok = e->tok;
n->function = "_utrace_syscall_arg";
n->referent = 0;
literal_number *num = new literal_number(argnum - 1);
num->tok = e->tok;
n->args.push_back(num);
provide (n);
}
}
void
utrace_var_expanding_visitor::visit_target_symbol_context (target_symbol* e)
{
const string& sname = e->name;
e->assert_no_components("utrace");
bool lvalue = is_active_lvalue(e);
if (lvalue)
throw SEMANTIC_ERROR(_F("utrace '%s' variable is read-only", sname.c_str()), e->tok);
string fname;
if (sname == "$return")
{
if (flags != UDPF_SYSCALL_RETURN)
throw SEMANTIC_ERROR (_("only \"process(PATH_OR_PID).syscall.return\" support $return."), e->tok);
fname = "_utrace_syscall_return";
}
else if (sname == "$syscall")
{
if (flags == UDPF_SYSCALL) {
fname = "_utrace_syscall_nr";
}
else {
visit_target_symbol_cached (e);
target_symbol_seen = true;
return;
}
}
else
{
throw SEMANTIC_ERROR (_("unknown target variable"), e->tok);
}
target_symbol_seen = true;
functioncall* n = new functioncall;
n->tok = e->tok;
n->function = fname;
n->referent = 0;
provide (n);
}
void
utrace_var_expanding_visitor::visit_target_symbol (target_symbol* e)
{
assert(e->name.size() > 0 && e->name[0] == '$');
try
{
if (flags != UDPF_SYSCALL && flags != UDPF_SYSCALL_RETURN)
throw SEMANTIC_ERROR (_("only \"process(PATH_OR_PID).syscall\""
" and \"process(PATH_OR_PID).syscall.return\" probes support target symbols"),
e->tok);
if (e->addressof)
throw SEMANTIC_ERROR(_("cannot take address of utrace variable"), e->tok);
if (startswith(e->name, "$arg") || e->name == "$$parms")
visit_target_symbol_arg(e);
else if (e->name == "$syscall" || e->name == "$return")
visit_target_symbol_context(e);
else
throw SEMANTIC_ERROR (_("invalid target symbol for utrace probe,"
" $syscall, $return, $argN or $$parms expected"),
e->tok);
}
catch (const semantic_error &er)
{
e->chain (er);
provide(e);
return;
}
}
struct utrace_builder: public derived_probe_builder
{
utrace_builder() {}
virtual void build(systemtap_session & sess,
probe * base,
probe_point * location,
literal_map_t const & parameters,
vector<derived_probe *> & finished_results)
{
string path, path_tgt;
int64_t pid;
bool has_path = get_param (parameters, TOK_PROCESS, path);
bool has_pid = get_param (parameters, TOK_PROCESS, pid);
enum utrace_derived_probe_flags flags = UDPF_NONE;
if (has_null_param (parameters, TOK_THREAD))
{
if (has_null_param (parameters, TOK_BEGIN))
flags = UDPF_THREAD_BEGIN;
else if (has_null_param (parameters, TOK_END))
flags = UDPF_THREAD_END;
}
else if (has_null_param (parameters, TOK_SYSCALL))
{
if (sess.runtime_usermode_p())
throw SEMANTIC_ERROR (_("process.syscall probes not available with the dyninst runtime"));
if (has_null_param (parameters, TOK_RETURN))
flags = UDPF_SYSCALL_RETURN;
else
flags = UDPF_SYSCALL;
}
else if (has_null_param (parameters, TOK_BEGIN))
flags = UDPF_BEGIN;
else if (has_null_param (parameters, TOK_END))
flags = UDPF_END;
if (has_pid || sess.target_pid)
{
string pid_err_msg;
if (!is_valid_pid(has_pid ? pid : sess.target_pid, pid_err_msg))
throw SEMANTIC_ERROR(pid_err_msg);
}
if (! has_path && ! has_pid)
{
has_path = false;
path.clear();
has_pid = true;
pid = 0;
}
else if (has_path)
{
path = find_executable (path, sess.sysroot, sess.sysenv);
sess.unwindsym_modules.insert (path);
path_tgt = path_remove_sysroot(sess, path);
}
finished_results.push_back(new utrace_derived_probe(sess, base, location,
has_path, path_tgt, pid,
flags));
}
};
void
utrace_derived_probe_group::enroll (utrace_derived_probe* p)
{
if (p->has_path)
probes_by_path[p->path].push_back(p);
else
probes_by_pid[p->pid].push_back(p);
num_probes++;
flags_seen[p->flags] = true;
XXX }
void
utrace_derived_probe_group::emit_linux_probe_decl (systemtap_session& s,
utrace_derived_probe *p)
{
s.op->newline() << "{";
s.op->line() << " .tgt={";
s.op->line() << " .purpose=\"lifecycle tracking\",";
if (p->has_path)
{
s.op->line() << " .procname=\"" << p->path << "\",";
s.op->line() << " .pid=0,";
}
else
{
s.op->line() << " .procname=NULL,";
s.op->line() << " .pid=" << p->pid << ",";
}
s.op->line() << " .callback=&_stp_utrace_probe_cb,";
s.op->line() << " .mmap_callback=NULL,";
s.op->line() << " .munmap_callback=NULL,";
s.op->line() << " .mprotect_callback=NULL,";
s.op->line() << " },";
s.op->line() << " .probe=" << common_probe_init (p) << ",";
switch (p->flags)
{
case UDPF_BEGIN: s.op->line() << " .flags=(UDPF_BEGIN),";
break;
case UDPF_THREAD_BEGIN: s.op->line() << " .flags=(UDPF_THREAD_BEGIN),";
break;
case UDPF_END: s.op->line() << " .flags=(UDPF_END),";
break;
case UDPF_THREAD_END: s.op->line() << " .flags=(UDPF_THREAD_END),";
break;
case UDPF_SYSCALL:
s.op->line() << " .flags=(UDPF_SYSCALL),";
s.op->newline() << "#if !defined(CONFIG_UTRACE)";
s.op->newline() << " .ops={ .report_syscall_entry=stap_utrace_probe_syscall, .report_death=stap_utrace_task_finder_report_death },";
s.op->line() << " .events=(UTRACE_EVENT(SYSCALL_ENTRY)|UTRACE_EVENT(DEATH)),";
s.op->newline() << "#else";
s.op->newline() << " .ops={ .report_syscall_entry=stap_utrace_probe_syscall, .report_exit=stap_utrace_task_finder_report_exit },";
s.op->line() << " .events=(UTRACE_EVENT(SYSCALL_ENTRY)|UTRACE_EVENT(EXIT)),";
s.op->newline() << "#endif";
s.op->newline();
break;
case UDPF_SYSCALL_RETURN:
s.op->line() << " .flags=(UDPF_SYSCALL_RETURN),";
s.op->newline() << "#if !defined(CONFIG_UTRACE)";
s.op->newline() << " .ops={ .report_syscall_exit=stap_utrace_probe_syscall, .report_death=stap_utrace_task_finder_report_death },";
s.op->line() << " .events=(UTRACE_EVENT(SYSCALL_EXIT)|UTRACE_EVENT(DEATH)),";
s.op->newline() << "#else";
s.op->newline() << " .ops={ .report_syscall_exit=stap_utrace_probe_syscall, .report_exit=stap_utrace_task_finder_report_exit },";
s.op->line() << " .events=(UTRACE_EVENT(SYSCALL_EXIT)|UTRACE_EVENT(EXIT)),";
s.op->newline() << "#endif";
s.op->newline();
break;
case UDPF_NONE:
s.op->line() << " .flags=(UDPF_NONE),";
s.op->line() << " .ops={ },";
s.op->line() << " .events=0,";
break;
default:
throw SEMANTIC_ERROR ("bad utrace probe flag");
break;
}
s.op->line() << " .engine_attached=0,";
s.op->line() << " },";
}
void
utrace_derived_probe_group::emit_module_linux_decls (systemtap_session& s)
{
if (probes_by_path.empty() && probes_by_pid.empty())
return;
s.op->newline();
s.op->newline() << "/* ---- utrace probes ---- */";
s.op->newline() << "enum utrace_derived_probe_flags {";
s.op->indent(1);
s.op->newline() << "UDPF_NONE,";
s.op->newline() << "UDPF_BEGIN,";
s.op->newline() << "UDPF_END,";
s.op->newline() << "UDPF_THREAD_BEGIN,";
s.op->newline() << "UDPF_THREAD_END,";
s.op->newline() << "UDPF_SYSCALL,";
s.op->newline() << "UDPF_SYSCALL_RETURN,";
s.op->newline() << "UDPF_NFLAGS";
s.op->newline(-1) << "};";
s.op->newline() << "struct stap_utrace_probe {";
s.op->indent(1);
s.op->newline() << "struct stap_task_finder_target tgt;";
s.op->newline() << "const struct stap_probe * const probe;";
s.op->newline() << "int engine_attached;";
s.op->newline() << "enum utrace_derived_probe_flags flags;";
s.op->newline() << "struct utrace_engine_ops ops;";
s.op->newline() << "unsigned long events;";
s.op->newline(-1) << "};";
if (flags_seen[UDPF_BEGIN] || flags_seen[UDPF_THREAD_BEGIN]
|| flags_seen[UDPF_END] || flags_seen[UDPF_THREAD_END])
{
s.op->newline() << "static void stap_utrace_probe_handler(struct task_struct *tsk, struct stap_utrace_probe *p) {";
s.op->indent(1);
common_probe_entryfn_prologue (s, "STAP_SESSION_RUNNING", "p->probe",
"stp_probe_type_utrace");
s.op->newline() << "(*p->probe->ph) (c);";
common_probe_entryfn_epilogue (s, true, otf_safe_context(s));
s.op->newline() << "return;";
s.op->newline(-1) << "}";
}
if (flags_seen[UDPF_SYSCALL] || flags_seen[UDPF_SYSCALL_RETURN])
{
s.op->newline() << "#ifdef UTRACE_ORIG_VERSION";
s.op->newline() << "static u32 stap_utrace_probe_syscall(struct utrace_engine *engine, struct task_struct *tsk, struct pt_regs *regs) {";
s.op->newline() << "#else";
s.op->newline() << "#if defined(UTRACE_API_VERSION) && (UTRACE_API_VERSION >= 20091216)";
s.op->newline() << "static u32 stap_utrace_probe_syscall(u32 action, struct utrace_engine *engine, struct pt_regs *regs) {";
s.op->newline() << "#else";
s.op->newline() << "static u32 stap_utrace_probe_syscall(enum utrace_resume_action action, struct utrace_engine *engine, struct task_struct *tsk, struct pt_regs *regs) {";
s.op->newline() << "#endif";
s.op->newline() << "#endif";
s.op->indent(1);
s.op->newline() << "struct stap_utrace_probe *p = (struct stap_utrace_probe *)engine->data;";
common_probe_entryfn_prologue (s, "STAP_SESSION_RUNNING", "p->probe",
"stp_probe_type_utrace_syscall");
s.op->newline() << "c->uregs = regs;";
s.op->newline() << "c->user_mode_p = 1;";
s.op->newline() << "(*p->probe->ph) (c);";
common_probe_entryfn_epilogue (s, true, otf_safe_context(s));
s.op->newline() << "if ((atomic_read (session_state()) != STAP_SESSION_STARTING) && (atomic_read (session_state()) != STAP_SESSION_RUNNING)) {";
s.op->indent(1);
s.op->newline() << "debug_task_finder_detach();";
s.op->newline() << "return UTRACE_DETACH;";
s.op->newline(-1) << "}";
s.op->newline() << "return UTRACE_RESUME;";
s.op->newline(-1) << "}";
}
s.op->newline() << "static int _stp_utrace_probe_cb(struct stap_task_finder_target *tgt, struct task_struct *tsk, int register_p, int process_p) {";
s.op->indent(1);
s.op->newline() << "int rc = 0;";
s.op->newline() << "struct stap_utrace_probe *p = container_of(tgt, struct stap_utrace_probe, tgt);";
s.op->newline() << "struct utrace_engine *engine;";
s.op->newline() << "if (register_p) {";
s.op->indent(1);
s.op->newline() << "switch (p->flags) {";
s.op->indent(1);
if (flags_seen[UDPF_BEGIN])
{
s.op->newline() << "case UDPF_BEGIN:";
s.op->indent(1);
s.op->newline() << "if (process_p) {";
s.op->indent(1);
s.op->newline() << "stap_utrace_probe_handler(tsk, p);";
s.op->newline(-1) << "}";
s.op->newline() << "break;";
s.op->indent(-1);
}
if (flags_seen[UDPF_THREAD_BEGIN])
{
s.op->newline() << "case UDPF_THREAD_BEGIN:";
s.op->indent(1);
s.op->newline() << "if (! process_p) {";
s.op->indent(1);
s.op->newline() << "stap_utrace_probe_handler(tsk, p);";
s.op->newline(-1) << "}";
s.op->newline() << "break;";
s.op->indent(-1);
}
if (flags_seen[UDPF_END] || flags_seen[UDPF_THREAD_END])
{
s.op->newline() << "case UDPF_END:";
s.op->newline() << "case UDPF_THREAD_END:";
s.op->indent(1);
s.op->newline() << "break;";
s.op->indent(-1);
}
if (flags_seen[UDPF_SYSCALL] || flags_seen[UDPF_SYSCALL_RETURN])
{
s.op->newline() << "case UDPF_SYSCALL:";
s.op->newline() << "case UDPF_SYSCALL_RETURN:";
s.op->indent(1);
s.op->newline() << "rc = stap_utrace_attach(tsk, &p->ops, p, p->events);";
s.op->newline() << "if (rc == 0) {";
s.op->indent(1);
s.op->newline() << "p->engine_attached = 1;";
s.op->newline(-1) << "}";
s.op->newline() << "break;";
s.op->indent(-1);
}
s.op->newline() << "default:";
s.op->indent(1);
s.op->newline() << "_stp_error(\"unhandled flag value %d at %s:%d\", p->flags, __FUNCTION__, __LINE__);";
s.op->newline() << "break;";
s.op->indent(-1);
s.op->newline(-1) << "}";
s.op->newline(-1) << "}";
s.op->newline() << "else {";
s.op->indent(1);
s.op->newline() << "switch (p->flags) {";
s.op->indent(1);
if (flags_seen[UDPF_END])
{
s.op->newline() << "case UDPF_END:";
s.op->indent(1);
s.op->newline() << "if (process_p) {";
s.op->indent(1);
s.op->newline() << "stap_utrace_probe_handler(tsk, p);";
s.op->newline(-1) << "}";
s.op->newline() << "break;";
s.op->indent(-1);
}
if (flags_seen[UDPF_THREAD_END])
{
s.op->newline() << "case UDPF_THREAD_END:";
s.op->indent(1);
s.op->newline() << "if (! process_p) {";
s.op->indent(1);
s.op->newline() << "stap_utrace_probe_handler(tsk, p);";
s.op->newline(-1) << "}";
s.op->newline() << "break;";
s.op->indent(-1);
}
if (flags_seen[UDPF_BEGIN] || flags_seen[UDPF_THREAD_BEGIN])
{
s.op->newline() << "case UDPF_BEGIN:";
s.op->newline() << "case UDPF_THREAD_BEGIN:";
s.op->indent(1);
s.op->newline() << "break;";
s.op->indent(-1);
}
if (flags_seen[UDPF_SYSCALL] || flags_seen[UDPF_SYSCALL_RETURN])
{
s.op->newline() << "case UDPF_SYSCALL:";
s.op->newline() << "case UDPF_SYSCALL_RETURN:";
s.op->indent(1);
s.op->newline() << "stap_utrace_detach(tsk, &p->ops);";
s.op->newline() << "break;";
s.op->indent(-1);
}
s.op->newline() << "default:";
s.op->indent(1);
s.op->newline() << "_stp_error(\"unhandled flag value %d at %s:%d\", p->flags, __FUNCTION__, __LINE__);";
s.op->newline() << "break;";
s.op->indent(-1);
s.op->newline(-1) << "}";
s.op->newline(-1) << "}";
s.op->newline() << "return rc;";
s.op->newline(-1) << "}";
s.op->newline() << "static struct stap_utrace_probe stap_utrace_probes[] = {";
s.op->indent(1);
if (! probes_by_path.empty())
{
for (p_b_path_iterator it = probes_by_path.begin();
it != probes_by_path.end(); it++)
{
for (unsigned i = 0; i < it->second.size(); i++)
{
utrace_derived_probe *p = it->second[i];
emit_linux_probe_decl(s, p);
}
}
}
if (! probes_by_pid.empty())
{
for (p_b_pid_iterator it = probes_by_pid.begin();
it != probes_by_pid.end(); it++)
{
for (unsigned i = 0; i < it->second.size(); i++)
{
utrace_derived_probe *p = it->second[i];
emit_linux_probe_decl(s, p);
}
}
}
s.op->newline(-1) << "};";
}
void
utrace_derived_probe_group::emit_dyninst_probe_decl (systemtap_session& s,
const string& path,
utrace_derived_probe *p)
{
string flags_str;
switch (p->flags)
{
case UDPF_BEGIN: flags_str = "STAPDYN_PROBE_FLAG_PROC_BEGIN";
break;
case UDPF_THREAD_BEGIN: flags_str = "STAPDYN_PROBE_FLAG_THREAD_BEGIN";
break;
case UDPF_END: flags_str = "STAPDYN_PROBE_FLAG_PROC_END";
break;
case UDPF_THREAD_END: flags_str = "STAPDYN_PROBE_FLAG_THREAD_END";
break;
FIXME#if 0
#endif
default:
throw SEMANTIC_ERROR ("bad utrace probe flag");
break;
}
if (p->has_path)
dynprobe_add_utrace_path(s, path, flags_str, common_probe_init(p));
else
dynprobe_add_utrace_pid(s, p->pid, flags_str, common_probe_init(p));
}
void
utrace_derived_probe_group::emit_module_dyninst_decls (systemtap_session& s)
{
if (probes_by_path.empty() && probes_by_pid.empty())
return;
s.op->newline();
s.op->newline() << "/* ---- dyninst utrace probes ---- */";
s.op->newline() << "#include \"dyninst/uprobes.h\"";
s.op->newline() << "#define STAPDYN_UTRACE_PROBES";
s.op->newline() << "static struct stapdu_probe stapdu_probes[];";
if (! probes_by_path.empty())
{
for (p_b_path_iterator it = probes_by_path.begin();
it != probes_by_path.end(); it++)
{
for (unsigned i = 0; i < it->second.size(); i++)
{
utrace_derived_probe *p = it->second[i];
emit_dyninst_probe_decl(s, it->first, p);
}
}
}
if (! probes_by_pid.empty())
{
for (p_b_pid_iterator it = probes_by_pid.begin();
it != probes_by_pid.end(); it++)
{
for (unsigned i = 0; i < it->second.size(); i++)
{
utrace_derived_probe *p = it->second[i];
emit_dyninst_probe_decl(s, "", p);
}
}
}
s.op->newline() << "static struct pt_regs stapdu_dummy_uregs;";
s.op->newline() << "int enter_dyninst_utrace_probe "
<< "(uint64_t index, struct pt_regs *regs) {";
s.op->newline(1) << "struct stapdu_probe *sup = &stapdu_probes[index];";
common_probe_entryfn_prologue (s, "STAP_SESSION_RUNNING", "sup->probe",
"stp_probe_type_utrace");
s.op->newline() << "c->uregs = regs ?: &stapdu_dummy_uregs;";
s.op->newline() << "c->user_mode_p = 1;";
XXX XXX s.op->newline() << "(*sup->probe->ph) (c);";
common_probe_entryfn_epilogue (s, true, otf_safe_context(s));
s.op->newline() << "return 0;";
s.op->newline(-1) << "}";
s.op->assert_0_indent();
}
void
utrace_derived_probe_group::emit_module_decls (systemtap_session& s)
{
if (s.runtime_usermode_p())
emit_module_dyninst_decls (s);
else
emit_module_linux_decls (s);
}
void
utrace_derived_probe_group::emit_module_linux_init (systemtap_session& s)
{
if (probes_by_path.empty() && probes_by_pid.empty())
return;
s.op->newline() << "/* ---- utrace probes ---- */";
s.op->newline() << "for (i=0; i<ARRAY_SIZE(stap_utrace_probes); i++) {";
s.op->newline(1) << "struct stap_utrace_probe *p = &stap_utrace_probes[i];";
s.op->newline() << "probe_point = p->probe->pp;"; s.op->newline() << "rc = stap_register_task_finder_target(&p->tgt);";
XXX s.op->newline() << "if (rc) break;";
s.op->newline(-1) << "}";
}
void
utrace_derived_probe_group::emit_module_dyninst_init (systemtap_session& s)
{
if (probes_by_path.empty() && probes_by_pid.empty())
return;
s.op->newline() << "/* ---- dyninst utrace probes ---- */";
s.op->newline() << "/* this section left intentionally blank */";
}
void
utrace_derived_probe_group::emit_module_init (systemtap_session& s)
{
if (s.runtime_usermode_p())
emit_module_dyninst_init (s);
else
emit_module_linux_init(s);
}
void
utrace_derived_probe_group::emit_module_linux_exit (systemtap_session& s)
{
if (probes_by_path.empty() && probes_by_pid.empty()) return;
s.op->newline();
s.op->newline() << "/* ---- utrace probes ---- */";
s.op->newline() << "for (i=0; i<ARRAY_SIZE(stap_utrace_probes); i++) {";
s.op->newline(1) << "struct stap_utrace_probe *p = &stap_utrace_probes[i];";
s.op->newline() << "if (p->engine_attached) {";
s.op->newline(1) << "stap_utrace_detach_ops(&p->ops);";
s.op->newline(-1) << "}";
s.op->newline(-1) << "}";
}
void
utrace_derived_probe_group::emit_module_dyninst_exit (systemtap_session& s)
{
if (probes_by_path.empty() && probes_by_pid.empty())
return;
s.op->newline() << "/* ---- dyninst utrace probes ---- */";
s.op->newline() << "/* this section left intentionally blank */";
}
void
utrace_derived_probe_group::emit_module_exit (systemtap_session& s)
{
if (s.runtime_usermode_p())
emit_module_dyninst_exit (s);
else
emit_module_linux_exit(s);
}
void
register_tapset_utrace(systemtap_session& s)
{
match_node* root = s.pattern_root;
derived_probe_builder *builder = new utrace_builder();
vector<match_node*> roots;
roots.push_back(root->bind(TOK_PROCESS));
roots.push_back(root->bind_str(TOK_PROCESS));
roots.push_back(root->bind_num(TOK_PROCESS));
for (unsigned i = 0; i < roots.size(); ++i)
{
roots[i]->bind(TOK_BEGIN)
->bind_privilege(pr_all)
->bind(builder);
roots[i]->bind(TOK_END)
->bind_privilege(pr_all)
->bind(builder);
roots[i]->bind(TOK_THREAD)->bind(TOK_BEGIN)
->bind_privilege(pr_all)
->bind(builder);
roots[i]->bind(TOK_THREAD)->bind(TOK_END)
->bind_privilege(pr_all)
->bind(builder);
roots[i]->bind(TOK_SYSCALL)
->bind_privilege(pr_all)
->bind(builder);
roots[i]->bind(TOK_SYSCALL)->bind(TOK_RETURN)
->bind_privilege(pr_all)
->bind(builder);
}
}