tapset-method.cxx - systemtap
Data types defined
Functions defined
Source code
#include "session.h"
#include "tapsets.h"
#include "translate.h"
#include "util.h"
#include "config.h"
#include "staptree.h"
#include "unistd.h"
#include "sys/wait.h"
#include "sys/types.h"
#include <cerrno>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
extern "C" {
#include <fnmatch.h>
}
using namespace std;
using namespace __gnu_cxx;
static const string TOK_CLASS ("class");
static const string TOK_METHOD ("method");
static const string TOK_PROCESS ("process");
static const string TOK_PROVIDER ("provider");
static const string TOK_MARK ("mark");
static const string TOK_JAVA ("java");
static const string TOK_RETURN ("return");
static const string TOK_BEGIN ("begin");
static const string TOK_END ("end");
static const string TOK_ERROR ("error");
struct java_details_inspection: public functioncall_traversing_visitor
{
bool java_backtrace;
java_details_inspection(): java_backtrace(false) {}
void visit_functioncall(functioncall* e);
};
void
java_details_inspection::visit_functioncall(functioncall* e)
{
assert(!e->referent); if (e->function == "sprint_java_backtrace" || e->function == "print_java_backtrace" ){
java_backtrace = true;
return; }
traversing_visitor::visit_functioncall(e);
}
struct java_builder: public derived_probe_builder
{
private:
typedef multimap<string, string> java_cache_t;
typedef multimap<string, string>::const_iterator java_cache_const_iterator_t;
typedef pair<java_cache_const_iterator_t, java_cache_const_iterator_t>
java_cache_const_iterator_pair_t;
java_cache_t java_cache;
public:
java_builder () {}
void build (systemtap_session & sess,
probe * base,
probe_point * location,
literal_map_t const & parameters,
vector <derived_probe *> & finished_results);
bool has_null_param (literal_map_t const & params,
string const & k);
bool get_number_param (literal_map_t const & params,
string const & k, int & v);
bool get_param (std::map<std::string, literal*> const & params,
const std::string& key,
std::string& value);
std::string mark_param(int i);
};
bool
java_builder::has_null_param(literal_map_t const & params,
string const & k)
{
return derived_probe_builder::has_null_param(params, k);
}
bool
java_builder::get_number_param (literal_map_t const & params,
string const & k, int & v)
{
int64_t value;
bool present = derived_probe_builder::get_param (params, k, value);
v = (int) value;
return present;
}
bool
java_builder::get_param (std::map<std::string, literal*> const & params,
const std::string& key,
std::string& value)
{
map<string, literal *>::const_iterator i = params.find (key);
if (i == params.end())
return false;
literal_string * ls = dynamic_cast<literal_string *>(i->second);
if (!ls)
return false;
value = ls->value;
return true;
}
std::string
java_builder::mark_param(int i)
{
switch (i)
{
case 0:
return "method__0";
case 1:
return "method__1";
case 2:
return "method__2";
case 3:
return "method__3";
case 4:
return "method__4";
case 5:
return "method__5";
case 6:
return "method__6";
case 7:
return "method__7";
case 8:
return "method__8";
case 9:
return "method__9";
case 10:
return "method__10";
default:
return "*";
}
}
void
java_builder::build (systemtap_session & sess,
probe * base,
probe_point * loc,
literal_map_t const & parameters,
vector <derived_probe *> & finished_results)
{
string method_str_val = "";
string method_line_val = "";
bool has_method_str = get_param (parameters, TOK_METHOD, method_str_val);
int short_method_pos = method_str_val.find ('(');
bool one_arg = false; if (short_method_pos)
{
int second_method_pos = 0;
second_method_pos = method_str_val.find (')');
if ((second_method_pos - short_method_pos) > 1)
one_arg = true;
}
int _java_pid = 0;
string _java_proc_class = "";
string short_method_str = method_str_val.substr (0, short_method_pos);
string class_str_val; bool has_class_str = get_param (parameters, TOK_CLASS, class_str_val);
bool has_pid_int = get_number_param (parameters, TOK_JAVA, _java_pid);
bool has_pid_str = get_param (parameters, TOK_JAVA, _java_proc_class);
bool has_return = has_null_param (parameters, TOK_RETURN);
bool has_line_number = false;
loc->well_formed = true;
size_t line_position = 0;
size_t method_end_pos = method_str_val.size();
line_position = method_str_val.find_first_of(":"); if (line_position == string::npos)
has_line_number = false;
else
{
has_line_number = true;
method_line_val = method_str_val.substr(line_position+1, method_end_pos);
method_str_val = method_str_val.substr(0, line_position);
line_position = method_line_val.find_first_of(":");
if (line_position != string::npos)
throw SEMANTIC_ERROR (_("maximum of one line number (:NNN)"));
if (has_line_number && has_return)
throw SEMANTIC_ERROR (_("conflict :NNN and .return probe"));
}
int method_params_count = count (method_str_val.begin (), method_str_val.end (), ',');
if (one_arg)
method_params_count++;
if (method_params_count > 10)
throw SEMANTIC_ERROR (_("maximum of 10 java method parameters may be specified"));
assert (has_method_str);
(void) has_method_str;
assert (has_class_str);
(void) has_class_str;
string java_pid_str = "";
if(has_pid_int)
java_pid_str = lex_cast(_java_pid);
else
java_pid_str = _java_proc_class;
if (! (has_pid_int || has_pid_str) )
throw SEMANTIC_ERROR (_("missing JVMID"));
struct java_details_inspection jdi;
base->body->visit(&jdi);
string libhelper = string(PKGLIBDIR) + "/libHelperSDT_*.so";
string rule_name = "module_name() . " + lex_cast_qstring(base->name);
const token* tok = base->body->tok;
if (jdi.java_backtrace)
{
stringstream bt_code;
bt_code << "probe process(" << literal_string(libhelper) << ")"
<< ".provider(\"HelperSDT\").mark(\"method__bt\") {" << endl;
bt_code << "if (user_string($arg3) != " << rule_name << ") next;" << endl;
bt_code << "__assign_stacktrace($arg1, $arg2);" << endl;
bt_code << "}" << endl;
probe* new_mark_bt_probe = parse_synthetic_probe (sess, bt_code, tok);
if (!new_mark_bt_probe)
throw SEMANTIC_ERROR (_("can't create java backtrace probe"), tok);
derive_probes(sess, new_mark_bt_probe, finished_results);
stringstream btd_code;
btd_code << "probe process(" << literal_string(libhelper) << ")"
<< ".provider(\"HelperSDT\").mark(\"method__bt__delete\") {" << endl;
btd_code << "if (user_string($arg1) != " << rule_name << ") next;" << endl;
btd_code << "__delete_backtrace();" << endl;
btd_code << "}" << endl;
probe* new_mark_btd_probe = parse_synthetic_probe (sess, btd_code, tok);
if (!new_mark_btd_probe)
throw SEMANTIC_ERROR (_("can't create java backtrace delete probe"), tok);
derive_probes(sess, new_mark_btd_probe, finished_results);
}
stringstream code;
code << "probe process(" << literal_string(libhelper) << ")" << ".provider(\"HelperSDT\")"
<< ".mark(" << literal_string (mark_param(method_params_count)) << ") {" << endl;
code << "if (user_string($arg" << (method_params_count+1)
<< ") != " << rule_name << ") next;" << endl;
code << "}" << endl;
probe* new_mark_probe = parse_synthetic_probe (sess, code, tok);
if (!new_mark_probe)
throw SEMANTIC_ERROR (_("can't create java method probe"), tok);
new_mark_probe->base = new probe(base, loc);
new_mark_probe->body = new block (new_mark_probe->body, base->body);
derive_probes (sess, new_mark_probe, finished_results);
stringstream begin_code;
begin_code << "probe begin {" << endl;
string leftbits = string(PKGLIBDIR) + "/stapbm install " +
lex_cast_qstring(has_pid_int ? java_pid_str : _java_proc_class) + " ";
string rightbits = " " + lex_cast_qstring(class_str_val) +
" " + lex_cast_qstring(method_str_val) +
" " + lex_cast(method_params_count) +
" " + ((!has_return && !has_line_number) ? string("entry") :
((has_return && !has_line_number) ? string("exit") :
method_line_val)) +
" " + (jdi.java_backtrace ? string("1") : string("0"));
begin_code << "system(" << literal_string(leftbits) << " . " << rule_name
<< " . " << literal_string(rightbits) << ");" << endl;
begin_code << "}" << endl;
probe* new_begin_probe = parse_synthetic_probe (sess, begin_code, tok);
if (!new_begin_probe)
throw SEMANTIC_ERROR (_("can't create java begin probe"), tok);
derive_probes (sess, new_begin_probe, finished_results);
stringstream end_code;
end_code << "probe end, error {" << endl;
leftbits = string(PKGLIBDIR) + "/stapbm uninstall " +
lex_cast_qstring(has_pid_int ? java_pid_str : _java_proc_class) + " ";
end_code << "system(" << literal_string(leftbits) << " . " << rule_name
<< " . " << literal_string(rightbits) << ");" << endl;
end_code << "}" << endl;
probe* new_end_probe = parse_synthetic_probe (sess, end_code, tok);
if (!new_end_probe)
throw SEMANTIC_ERROR (_("can't create java end probe"), tok);
derive_probes (sess, new_end_probe, finished_results);
}
void
register_tapset_java (systemtap_session& s)
{
(void) s;
#ifdef HAVE_JAVA
match_node* root = s.pattern_root;
derived_probe_builder *builder = new java_builder ();
root->bind_str (TOK_JAVA)
->bind_str (TOK_CLASS)->bind_str (TOK_METHOD)
->bind_privilege(pr_all)
->bind(builder);
root->bind_str (TOK_JAVA)
->bind_str (TOK_CLASS)->bind_str (TOK_METHOD)
->bind (TOK_RETURN)
->bind_privilege(pr_all)
->bind(builder);
root->bind_num (TOK_JAVA)
->bind_str (TOK_CLASS)->bind_str (TOK_METHOD)
->bind_privilege(pr_all)
->bind (builder);
root->bind_num (TOK_JAVA)
->bind_str (TOK_CLASS)->bind_str (TOK_METHOD)
->bind (TOK_RETURN)
->bind_privilege(pr_all)
->bind (builder);
#endif
}