]> sourceware.org Git - systemtap.git/blob - tapset-method.cxx
java/byteman configury: rename libHelperSDT.so --> libHelperSDT_{arch}.so for multiar...
[systemtap.git] / tapset-method.cxx
1 // Tapset for per-method based probes
2 // Copyright (C) 2013 Red Hat Inc.
3
4 // This file is part of systemtap, and is free software. You can
5 // redistribute it and/or modify it under the terms of the GNU General
6 // Public License (GPL); either version 2, or (at your option) any
7 // later version.
8
9 #include "session.h"
10 #include "tapsets.h"
11 #include "translate.h"
12 #include "util.h"
13 #include "config.h"
14
15 #include "unistd.h"
16 #include "sys/wait.h"
17 #include "sys/types.h"
18
19 #include <cerrno>
20 #include <cstdlib>
21 #include <cstring>
22 #include <string>
23 #include <algorithm>
24
25 extern "C" {
26 #include <fnmatch.h>
27 }
28
29 using namespace std;
30 using namespace __gnu_cxx;
31
32 static const string TOK_CLASS ("class");
33 static const string TOK_METHOD ("method");
34 static const string TOK_PROCESS ("process");
35 static const string TOK_MARK ("mark");
36 static const string TOK_JAVA ("java");
37 static const string TOK_RETURN ("return");
38 static const string TOK_BEGIN ("begin");
39 static const string TOK_END ("end");
40 static const string TOK_ERROR ("error");
41
42 /* Escape all double quotes with a backslash in the string s: */
43 string bmoption_escape (string s) {
44 size_t n = 0;
45 for (;;) {
46 n = s.find('"', n);
47 if (n == string::npos) break;
48 s.insert(n, 1, '\\'); n++;
49 }
50 return s;
51 }
52
53 // --------------------------------------------------------------------------
54
55 struct java_builder: public derived_probe_builder
56 {
57 private:
58 bool cache_initialized;
59 typedef multimap<string, string> java_cache_t;
60 typedef multimap<string, string>::const_iterator java_cache_const_iterator_t;
61 typedef pair<java_cache_const_iterator_t, java_cache_const_iterator_t>
62 java_cache_const_iterator_pair_t;
63 java_cache_t java_cache;
64
65 public:
66 java_builder (): cache_initialized (false) {}
67
68 void build (systemtap_session & sess,
69 probe * base,
70 probe_point * location,
71 literal_map_t const & parameters,
72 vector <derived_probe *> & finished_results);
73
74 bool has_null_param (literal_map_t const & params,
75 string const & k);
76
77 bool get_number_param (literal_map_t const & params,
78 string const & k, int & v);
79 bool get_param (std::map<std::string, literal*> const & params,
80 const std::string& key,
81 std::string& value);
82 std::string mark_param(int i);
83
84 };
85
86 bool
87 java_builder::has_null_param(literal_map_t const & params,
88 string const & k)
89 {
90 return derived_probe_builder::has_null_param(params, k);
91 }
92
93 bool
94 java_builder::get_number_param (literal_map_t const & params,
95 string const & k, int & v)
96 {
97 int64_t value;
98 bool present = derived_probe_builder::get_param (params, k, value);
99 v = (int) value;
100 return present;
101 }
102
103 bool
104 java_builder::get_param (std::map<std::string, literal*> const & params,
105 const std::string& key,
106 std::string& value)
107 {
108 map<string, literal *>::const_iterator i = params.find (key);
109 if (i == params.end())
110 return false;
111 literal_string * ls = dynamic_cast<literal_string *>(i->second);
112 if (!ls)
113 return false;
114 value = ls->value;
115 return true;
116 }
117
118 std::string
119 java_builder::mark_param(int i)
120 {
121 switch (i)
122 {
123 case 0:
124 return "method__0";
125 case 1:
126 return "method__1";
127 case 2:
128 return "method__2";
129 case 3:
130 return "method__3";
131 case 4:
132 return "method__4";
133 case 5:
134 return "method__5";
135 case 6:
136 return "method__6";
137 case 7:
138 return "method__7";
139 case 8:
140 return "method__8";
141 case 9:
142 return "method__9";
143 case 10:
144 return "method__10";
145 default:
146 return "*";
147 }
148 }
149
150 void
151 java_builder::build (systemtap_session & sess,
152 probe * base,
153 probe_point * loc,
154 literal_map_t const & parameters,
155 vector <derived_probe *> & finished_results)
156 {
157 string method_str_val = "";
158 string method_line_val = "";
159 bool has_method_str = get_param (parameters, TOK_METHOD, method_str_val);
160 int short_method_pos = method_str_val.find ('(');
161 //only if it exists, run check
162 bool one_arg = false; // used to check if there is an argument in the method
163 if (short_method_pos)
164 {
165 int second_method_pos = 0;
166 second_method_pos = method_str_val.find (')');
167 if ((second_method_pos - short_method_pos) > 1)
168 one_arg = true;
169 }
170 int _java_pid = 0;
171 string _java_proc_class = "";
172 string short_method_str = method_str_val.substr (0, short_method_pos);
173 string class_str_val; // fully qualified class string
174 bool has_class_str = get_param (parameters, TOK_CLASS, class_str_val);
175 bool has_pid_int = get_number_param (parameters, TOK_JAVA, _java_pid);
176 bool has_pid_str = get_param (parameters, TOK_JAVA, _java_proc_class);
177 bool has_return = has_null_param (parameters, TOK_RETURN);
178 bool has_line_number = false;
179
180 //find if we're probing at a specific line number
181 size_t line_position = 0;
182
183 size_t method_end_pos = method_str_val.size();
184 line_position = method_str_val.find_first_of(":"); //this will return the position ':' is found at
185 if (line_position == string::npos)
186 has_line_number = false;
187 else
188 {
189 has_line_number = true;
190 method_line_val = method_str_val.substr(line_position+1, method_end_pos);
191 method_str_val = method_str_val.substr(0, line_position);
192 line_position = method_line_val.find_first_of(":");
193 if (line_position != string::npos)
194 {
195 cerr << _("Error: You may only specify one line number (more than one ':' found)") << endl;
196 return;
197 }
198 if (has_line_number && has_return)
199 {
200 cerr << _("Error: You may not declare a line number and a .return probe at the same probe point") << endl;
201 return;
202 }
203 }
204
205 //need to count the number of parameters, exit if more than 10
206
207 int method_params_count = count (method_str_val.begin (), method_str_val.end (), ',');
208 if (one_arg)
209 method_params_count++; // in this case we know there was at least a var, but no ','
210
211 if (method_params_count > 10)
212 {
213 cerr << _("Error: Maximum of 10 method parameters may be specified") << endl;
214 return;
215 }
216 assert (has_method_str);
217 (void) has_method_str;
218 assert (has_class_str);
219 (void) has_class_str;
220
221 string java_pid_str = "";
222 if(has_pid_int)
223 {
224 string _tmp = "";
225 _tmp = static_cast <ostringstream*> ( & (ostringstream ()
226 << (_java_pid)))->str ();
227 java_pid_str = _tmp;
228 }
229 else
230 java_pid_str = _java_proc_class;
231
232 #ifdef HAVE_JAVA
233
234 if (! (has_pid_int || has_pid_str) )
235 exit (1); //XXX proper exit with warning message
236
237 /*
238 * while looking at sdt_query::convert_location as an example
239 * create a new probe_point*, with same (*base_loc)
240 * using a vector, iterate though, changing as needed
241 * redefine functor values with new literal_string("foo")
242 */
243
244 string helper_location = PKGLIBDIR;
245 helper_location.append("/libHelperSDT_*.so");
246 probe_point* new_loc = new probe_point(*loc);
247 vector<probe_point::component*> java_marker;
248 java_marker.push_back( new probe_point::component
249 (TOK_PROCESS, new literal_string (helper_location)));
250 java_marker.push_back( new probe_point::component
251 (TOK_MARK, new literal_string (mark_param(method_params_count))));
252 probe_point * derived_loc = new probe_point (java_marker);
253
254 block *b = new block;
255 b->tok = base->body->tok;
256
257 // first half of argument
258 target_symbol *cc = new target_symbol;
259 cc->tok = b->tok;
260 cc->name = "$provider";
261
262 functioncall *ccus = new functioncall;
263 ccus->function = "user_string";
264 ccus->type = pe_string;
265 ccus->tok = b->tok;
266 ccus->args.push_back(cc);
267
268 // second half of argument
269 target_symbol *mc = new target_symbol;
270 mc->tok = b->tok;
271 mc->name = "$name";
272
273 functioncall *mcus = new functioncall;
274 mcus->function = "user_string";
275 mcus->type = pe_string;
276 mcus->tok = b->tok;
277 mcus->args.push_back(mc);
278
279 //build if statement
280 if_statement *ifs = new if_statement;
281 ifs->thenblock = new next_statement;
282 ifs->elseblock = NULL;
283 ifs->tok = b->tok;
284 ifs->thenblock->tok = b->tok;
285
286 //class comparison
287 comparison *ce = new comparison;
288 ce->op = "!=";
289 ce->tok = b->tok;
290 ce->left = ccus;
291 ce->right = new literal_string(class_str_val);
292 ce->right->tok = b->tok;
293
294 //method comparision
295 comparison *me = new comparison;
296 me->op = "!=";
297 me->tok = b->tok;
298 me->left = mcus;
299 me->right = new literal_string(method_str_val);
300 me->right->tok = b->tok;
301
302 logical_or_expr *le = new logical_or_expr;
303 le->op = "||";
304 le->left = ce;
305 le->right = me;
306 le->tok = b->tok;
307 ifs->condition = le;
308 b->statements.push_back(ifs);
309
310 b->statements.push_back(base->body);
311 base->body = b;
312
313 derived_loc->components = java_marker;
314 probe* new_mark_probe = base->create_alias (derived_loc, new_loc);
315 derive_probes (sess, new_mark_probe, finished_results);
316
317
318 //the begin portion of the probe
319 vector<probe_point::component*> java_begin_marker;
320 java_begin_marker.push_back( new probe_point::component
321 (TOK_PROCESS, new literal_string ("/usr/bin/java")));
322 java_begin_marker.push_back( new probe_point::component (TOK_BEGIN));
323
324 probe_point * der_begin_loc = new probe_point(java_begin_marker);
325
326 /* stapbm contains the following arguments in a space
327 seperated list
328 $1 - install/uninstall
329 $2 - $STAPTMPDIR
330 $3 - PID/unique name
331 $4 - RULE name
332 $5 - class
333 $6 - method
334 $7 - number of args
335 $8 - entry/exit/line
336 $9 - options to pass to bminstall
337 */
338
339 char arg_count[3];
340 snprintf(arg_count, 3, "%d", method_params_count);
341 string new_method = method_str_val;
342 size_t string_pos = new_method.find(')', 0);
343 while(string_pos != string::npos){
344 new_method.insert(int(string_pos), "\\\\");
345 string_pos = new_method.find(')',string_pos+4);
346 }
347 string_pos = new_method.find('(', 0);
348 while(string_pos != string::npos){
349 new_method.insert(int(string_pos), "\\\\");
350 string_pos = new_method.find('(',string_pos+4);
351 }
352 string new_no_method = new_method;
353 string_pos = new_no_method.find(' ', 0);
354 while(string_pos != string::npos){
355 new_no_method.erase(string_pos, 1);
356 string_pos = new_no_method.find(' ',string_pos+1);
357 }
358 string_pos = new_method.find(' ', 0);
359 while(string_pos != string::npos){
360 new_method.insert(int(string_pos), "\\\\");
361 string_pos = new_method.find(' ',string_pos+4);
362 }
363
364 string stapbm_string = "";
365 stapbm_string.append(PKGLIBDIR);
366 stapbm_string.append("/stapbm ");
367 stapbm_string.append("install");
368 stapbm_string.append(" ");
369 stapbm_string.append(sess.tmpdir);
370 stapbm_string.append(" ");
371 if (has_pid_int)
372 stapbm_string.append(java_pid_str);
373 else
374 stapbm_string.append(_java_proc_class);
375 stapbm_string.append(" ");
376 stapbm_string.append(class_str_val + "-" + new_no_method);
377 stapbm_string.append(" ");
378 stapbm_string.append(class_str_val);
379 stapbm_string.append(" ");
380 stapbm_string.append(new_method);
381 stapbm_string.append(" ");
382 stapbm_string.append(arg_count);
383 stapbm_string.append(" ");
384 if(!has_return && !has_line_number)
385 stapbm_string.append("entry");
386 else if(has_return && !has_line_number)
387 stapbm_string.append("exit");
388 else if(!has_return && has_line_number)
389 stapbm_string.append(method_line_val);
390 if(sess.bminstallflags.size() > 1)
391 {
392 stapbm_string.append(" \"");
393 for (vector<string>::iterator it = sess.bminstallflags.begin();
394 it != sess.bminstallflags.end(); ++it)
395 stapbm_string.append(bmoption_escape(*it) + " ");
396 stapbm_string.append("\"");
397 }
398 else if (!sess.bminstallflags.empty())
399 {
400 stapbm_string.append(" " + sess.bminstallflags[0]);
401 }
402
403 block *bb = new block;
404 bb->tok = base->body->tok;
405 functioncall *fc = new functioncall;
406 fc->function = "system";
407 fc->tok = bb->tok;
408 literal_string* num = new literal_string(stapbm_string);
409 num->tok = bb->tok;
410 fc->args.push_back(num);
411
412 expr_statement* bs = new expr_statement;
413 bs->tok = bb->tok;
414 bs->value = fc;
415
416 bb->statements.push_back(bs);
417 base->body = bb;
418 der_begin_loc->components = java_begin_marker;
419 probe * bbase = new probe(*base, der_begin_loc);
420 probe* new_begin_probe = new probe(*bbase, der_begin_loc);
421 derive_probes (sess, new_begin_probe, finished_results);
422
423 //the end/error portion of the probe
424 vector<probe_point::component*> java_end_marker;
425 java_end_marker.push_back( new probe_point::component
426 (TOK_PROCESS, new literal_string ("/usr/bin/java")));
427 java_end_marker.push_back( new probe_point::component (TOK_END));
428
429 probe_point *der_end_loc = new probe_point (java_end_marker);
430
431 block *eb = new block;
432 eb->tok = base->body->tok;
433 functioncall *efc = new functioncall;
434 efc->function = "system";
435 efc->tok = eb->tok;
436
437 string stapbm_remove = "";
438 stapbm_remove.append(PKGLIBDIR);
439 stapbm_remove.append("/stapbm ");
440 stapbm_remove.append("uninstall ");
441 stapbm_remove.append(sess.tmpdir);
442 stapbm_remove.append(" ");
443 if (has_pid_int)
444 stapbm_remove.append(java_pid_str);
445 else
446 stapbm_remove.append(_java_proc_class);
447 stapbm_remove.append(" ");
448 stapbm_remove.append(class_str_val + "-" + new_method);
449 stapbm_remove.append(" ");
450 stapbm_remove.append(class_str_val);
451 stapbm_remove.append(" ");
452 stapbm_remove.append(new_method);
453 stapbm_remove.append(" ");
454 stapbm_remove.append(arg_count);
455 stapbm_remove.append(" ");
456 if(!has_return && !has_line_number)
457 stapbm_remove.append("entry");
458 else if(has_return && !has_line_number)
459 stapbm_remove.append("exit");
460 else if(!has_return && has_line_number)
461 stapbm_remove.append(method_line_val);
462
463 literal_string* es = new literal_string(stapbm_remove);
464 es->tok = eb->tok;
465 efc->args.push_back(es);
466
467 expr_statement* ees = new expr_statement;
468 ees->tok = eb->tok;
469 ees->value = efc;
470
471 eb->statements.push_back(ees);
472 base->body = eb;
473
474 der_end_loc->components = java_end_marker;
475 probe* ebase = new probe(*base, der_end_loc);
476 probe* new_end_probe = new probe(*ebase, der_end_loc);
477 derive_probes (sess, new_end_probe, finished_results);
478
479 #else
480 (void) java_pid_str;
481 (void) has_pid_str;
482 cerr << _("Cannot probe java method, configure --with-jdk=") << endl;
483 #endif
484 }
485
486 void
487 register_tapset_java (systemtap_session& s)
488 {
489 match_node* root = s.pattern_root;
490 derived_probe_builder *builder = new java_builder ();
491
492 root->bind_str (TOK_JAVA)
493 ->bind_str (TOK_CLASS)->bind_str (TOK_METHOD)
494 ->bind(builder);
495
496
497 root->bind_str (TOK_JAVA)
498 ->bind_str (TOK_CLASS)->bind_str (TOK_METHOD)
499 ->bind (TOK_RETURN)->bind(builder);
500
501 root->bind_num (TOK_JAVA)
502 ->bind_str (TOK_CLASS)->bind_str (TOK_METHOD)
503 ->bind (builder);
504
505 root->bind_num (TOK_JAVA)
506 ->bind_str (TOK_CLASS)->bind_str (TOK_METHOD)
507 ->bind (TOK_RETURN)->bind (builder);
508
509 }
510
This page took 0.058831 seconds and 5 git commands to generate.