1 // Tapset for per-method based probes
2 // Copyright (C) 2013 Red Hat Inc.
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
11 #include "translate.h"
17 #include "sys/types.h"
30 using namespace __gnu_cxx
;
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");
42 /* Escape all double quotes with a backslash in the string s: */
43 string
bmoption_escape (string s
) {
47 if (n
== string::npos
) break;
48 s
.insert(n
, 1, '\\'); n
++;
53 // --------------------------------------------------------------------------
55 struct java_builder
: public derived_probe_builder
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
;
66 java_builder (): cache_initialized (false) {}
68 void build (systemtap_session
& sess
,
70 probe_point
* location
,
71 literal_map_t
const & parameters
,
72 vector
<derived_probe
*> & finished_results
);
74 bool has_null_param (literal_map_t
const & params
,
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
,
82 std::string
mark_param(int i
);
87 java_builder::has_null_param(literal_map_t
const & params
,
90 return derived_probe_builder::has_null_param(params
, k
);
94 java_builder::get_number_param (literal_map_t
const & params
,
95 string
const & k
, int & v
)
98 bool present
= derived_probe_builder::get_param (params
, k
, value
);
104 java_builder::get_param (std::map
<std::string
, literal
*> const & params
,
105 const std::string
& key
,
108 map
<string
, literal
*>::const_iterator i
= params
.find (key
);
109 if (i
== params
.end())
111 literal_string
* ls
= dynamic_cast<literal_string
*>(i
->second
);
119 java_builder::mark_param(int i
)
151 java_builder::build (systemtap_session
& sess
,
154 literal_map_t
const & parameters
,
155 vector
<derived_probe
*> & finished_results
)
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
)
165 int second_method_pos
= 0;
166 second_method_pos
= method_str_val
.find (')');
167 if ((second_method_pos
- short_method_pos
) > 1)
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;
180 //find if we're probing at a specific line number
181 size_t line_position
= 0;
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;
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
)
195 cerr
<< _("Error: You may only specify one line number (more than one ':' found)") << endl
;
198 if (has_line_number
&& has_return
)
200 cerr
<< _("Error: You may not declare a line number and a .return probe at the same probe point") << endl
;
205 //need to count the number of parameters, exit if more than 10
207 int method_params_count
= count (method_str_val
.begin (), method_str_val
.end (), ',');
209 method_params_count
++; // in this case we know there was at least a var, but no ','
211 if (method_params_count
> 10)
213 cerr
<< _("Error: Maximum of 10 method parameters may be specified") << endl
;
216 assert (has_method_str
);
217 (void) has_method_str
;
218 assert (has_class_str
);
219 (void) has_class_str
;
221 string java_pid_str
= "";
225 _tmp
= static_cast <ostringstream
*> ( & (ostringstream ()
226 << (_java_pid
)))->str ();
230 java_pid_str
= _java_proc_class
;
234 if (! (has_pid_int
|| has_pid_str
) )
235 exit (1); //XXX proper exit with warning message
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")
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
);
254 block
*b
= new block
;
255 b
->tok
= base
->body
->tok
;
257 // first half of argument
258 target_symbol
*cc
= new target_symbol
;
260 cc
->name
= "$provider";
262 functioncall
*ccus
= new functioncall
;
263 ccus
->function
= "user_string";
264 ccus
->type
= pe_string
;
266 ccus
->args
.push_back(cc
);
268 // second half of argument
269 target_symbol
*mc
= new target_symbol
;
273 functioncall
*mcus
= new functioncall
;
274 mcus
->function
= "user_string";
275 mcus
->type
= pe_string
;
277 mcus
->args
.push_back(mc
);
280 if_statement
*ifs
= new if_statement
;
281 ifs
->thenblock
= new next_statement
;
282 ifs
->elseblock
= NULL
;
284 ifs
->thenblock
->tok
= b
->tok
;
287 comparison
*ce
= new comparison
;
291 ce
->right
= new literal_string(class_str_val
);
292 ce
->right
->tok
= b
->tok
;
295 comparison
*me
= new comparison
;
299 me
->right
= new literal_string(method_str_val
);
300 me
->right
->tok
= b
->tok
;
302 logical_or_expr
*le
= new logical_or_expr
;
308 b
->statements
.push_back(ifs
);
310 b
->statements
.push_back(base
->body
);
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
);
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
));
324 probe_point
* der_begin_loc
= new probe_point(java_begin_marker
);
326 /* stapbm contains the following arguments in a space
328 $1 - install/uninstall
336 $9 - options to pass to bminstall
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);
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);
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);
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);
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(" ");
372 stapbm_string
.append(java_pid_str
);
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)
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("\"");
398 else if (!sess
.bminstallflags
.empty())
400 stapbm_string
.append(" " + sess
.bminstallflags
[0]);
403 block
*bb
= new block
;
404 bb
->tok
= base
->body
->tok
;
405 functioncall
*fc
= new functioncall
;
406 fc
->function
= "system";
408 literal_string
* num
= new literal_string(stapbm_string
);
410 fc
->args
.push_back(num
);
412 expr_statement
* bs
= new expr_statement
;
416 bb
->statements
.push_back(bs
);
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
);
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
));
429 probe_point
*der_end_loc
= new probe_point (java_end_marker
);
431 block
*eb
= new block
;
432 eb
->tok
= base
->body
->tok
;
433 functioncall
*efc
= new functioncall
;
434 efc
->function
= "system";
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(" ");
444 stapbm_remove
.append(java_pid_str
);
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
);
463 literal_string
* es
= new literal_string(stapbm_remove
);
465 efc
->args
.push_back(es
);
467 expr_statement
* ees
= new expr_statement
;
471 eb
->statements
.push_back(ees
);
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
);
482 cerr
<< _("Cannot probe java method, configure --with-jdk=") << endl
;
487 register_tapset_java (systemtap_session
& s
)
489 match_node
* root
= s
.pattern_root
;
490 derived_probe_builder
*builder
= new java_builder ();
492 root
->bind_str (TOK_JAVA
)
493 ->bind_str (TOK_CLASS
)->bind_str (TOK_METHOD
)
497 root
->bind_str (TOK_JAVA
)
498 ->bind_str (TOK_CLASS
)->bind_str (TOK_METHOD
)
499 ->bind (TOK_RETURN
)->bind(builder
);
501 root
->bind_num (TOK_JAVA
)
502 ->bind_str (TOK_CLASS
)->bind_str (TOK_METHOD
)
505 root
->bind_num (TOK_JAVA
)
506 ->bind_str (TOK_CLASS
)->bind_str (TOK_METHOD
)
507 ->bind (TOK_RETURN
)->bind (builder
);