1 // tapset for kernel static markers
2 // Copyright (C) 2005-2009 Red Hat Inc.
3 // Copyright (C) 2005-2007 Intel Corporation.
4 // Copyright (C) 2008 James.Bottomley@HansenPartnership.com
6 // This file is part of systemtap, and is free software. You can
7 // redistribute it and/or modify it under the terms of the GNU General
8 // Public License (GPL); either version 2, or (at your option) any
13 #include "translate.h"
27 using namespace __gnu_cxx
;
30 static const string
TOK_KERNEL("kernel");
31 static const string
TOK_MARK("mark");
32 static const string
TOK_FORMAT("format");
35 // ------------------------------------------------------------------------
36 // statically inserted macro-based derived probes
37 // ------------------------------------------------------------------------
47 struct mark_derived_probe
: public derived_probe
49 mark_derived_probe (systemtap_session
&s
,
50 const string
& probe_name
, const string
& probe_format
,
51 probe
* base_probe
, probe_point
* location
);
53 systemtap_session
& sess
;
54 string probe_name
, probe_format
;
55 vector
<struct mark_arg
*> mark_args
;
56 bool target_symbol_seen
;
58 void join_group (systemtap_session
& s
);
59 void print_dupe_stamp (ostream
& o
);
60 void emit_probe_context_vars (translator_output
* o
);
61 void initialize_probe_context_vars (translator_output
* o
);
62 void printargs (std::ostream
&o
) const;
64 void parse_probe_format ();
68 struct mark_derived_probe_group
: public generic_dpg
<mark_derived_probe
>
71 void emit_module_decls (systemtap_session
& s
);
72 void emit_module_init (systemtap_session
& s
);
73 void emit_module_exit (systemtap_session
& s
);
77 struct mark_var_expanding_visitor
: public var_expanding_visitor
79 mark_var_expanding_visitor(systemtap_session
& s
, const string
& pn
,
80 vector
<struct mark_arg
*> &mark_args
):
81 sess (s
), probe_name (pn
), mark_args (mark_args
),
82 target_symbol_seen (false) {}
83 systemtap_session
& sess
;
85 vector
<struct mark_arg
*> &mark_args
;
86 bool target_symbol_seen
;
88 void visit_target_symbol (target_symbol
* e
);
89 void visit_target_symbol_arg (target_symbol
* e
);
90 void visit_target_symbol_context (target_symbol
* e
);
95 mark_var_expanding_visitor::visit_target_symbol_arg (target_symbol
* e
)
97 string argnum_s
= e
->base_name
.substr(4,e
->base_name
.length()-4);
98 int argnum
= atoi (argnum_s
.c_str());
100 if (argnum
< 1 || argnum
> (int)mark_args
.size())
101 throw semantic_error ("invalid marker argument number", e
->tok
);
103 if (is_active_lvalue (e
))
104 throw semantic_error("write to marker parameter not permitted", e
->tok
);
106 e
->assert_no_components("marker");
108 // Remember that we've seen a target variable.
109 target_symbol_seen
= true;
111 e
->probe_context_var
= "__mark_arg" + lex_cast(argnum
);
112 e
->type
= mark_args
[argnum
-1]->stp_type
;
118 mark_var_expanding_visitor::visit_target_symbol_context (target_symbol
* e
)
120 string sname
= e
->base_name
;
122 if (is_active_lvalue (e
))
123 throw semantic_error("write to marker '" + sname
+ "' not permitted", e
->tok
);
125 e
->assert_no_components("marker");
127 if (e
->base_name
== "$format" || e
->base_name
== "$name") {
129 if (e
->base_name
== "$format") {
130 fname
= string("_mark_format_get");
132 fname
= string("_mark_name_get");
135 // Synthesize a functioncall.
136 functioncall
* n
= new functioncall
;
139 n
->referent
= 0; // NB: must not resolve yet, to ensure inclusion in session
142 else if (e
->base_name
== "$$vars" || e
->base_name
== "$$parms")
144 //copy from tracepoint
145 print_format
* pf
= new print_format
;
146 token
* pf_tok
= new token(*e
->tok
);
147 pf_tok
->content
= "sprintf";
149 pf
->print_to_stream
= false;
150 pf
->print_with_format
= true;
151 pf
->print_with_delim
= false;
152 pf
->print_with_newline
= false;
153 pf
->print_char
= false;
155 for (unsigned i
= 0; i
< mark_args
.size(); ++i
)
158 pf
->raw_components
+= " ";
159 pf
->raw_components
+= "$arg" + lex_cast(i
+1);
160 target_symbol
*tsym
= new target_symbol
;
162 tsym
->base_name
= "$arg" + lex_cast(i
+1);
164 tsym
->saved_conversion_error
= 0;
165 expression
*texp
= require (tsym
); //same treatment as tracepoint
166 assert (!tsym
->saved_conversion_error
);
167 switch (mark_args
[i
]->stp_type
)
170 pf
->raw_components
+= mark_args
[i
]->isptr
? "=%p" : "=%#x";
173 pf
->raw_components
+= "=%s";
176 pf
->raw_components
+= "=%#x";
179 pf
->args
.push_back(texp
);
181 pf
->components
= print_format::string_to_components(pf
->raw_components
);
187 mark_var_expanding_visitor::visit_target_symbol (target_symbol
* e
)
189 assert(e
->base_name
.size() > 0 && e
->base_name
[0] == '$');
192 throw semantic_error("cannot take address of marker variable", e
->tok
);
194 if (e
->base_name
.substr(0,4) == "$arg")
195 visit_target_symbol_arg (e
);
196 else if (e
->base_name
== "$format" || e
->base_name
== "$name"
197 || e
->base_name
== "$$parms" || e
->base_name
== "$$vars")
198 visit_target_symbol_context (e
);
200 throw semantic_error ("invalid target symbol for marker, $argN, $name, $format, $$parms or $$vars expected",
206 mark_derived_probe::mark_derived_probe (systemtap_session
&s
,
209 probe
* base
, probe_point
* loc
):
210 derived_probe (base
, new probe_point(*loc
) /* .components soon rewritten */),
211 sess (s
), probe_name (p_n
), probe_format (p_f
),
212 target_symbol_seen (false)
214 // create synthetic probe point name; preserve condition
215 vector
<probe_point::component
*> comps
;
216 comps
.push_back (new probe_point::component (TOK_KERNEL
));
217 comps
.push_back (new probe_point::component (TOK_MARK
, new literal_string (probe_name
)));
218 comps
.push_back (new probe_point::component (TOK_FORMAT
, new literal_string (probe_format
)));
219 this->sole_location()->components
= comps
;
221 // expand the marker format
222 parse_probe_format();
224 // Now expand the local variables in the probe body
225 mark_var_expanding_visitor
v (sess
, name
, mark_args
);
226 v
.replace (this->body
);
227 target_symbol_seen
= v
.target_symbol_seen
;
229 if (sess
.verbose
> 2)
230 clog
<< "marker-based " << name
<< " mark=" << probe_name
231 << " fmt='" << probe_format
<< "'" << endl
;
236 skip_atoi(const char **s
)
240 i
= i
* 10 + *((*s
)++) - '0';
246 mark_derived_probe::parse_probe_format()
248 const char *fmt
= probe_format
.c_str();
249 int qualifier
; // 'h', 'l', or 'L' for integer fields
263 // skip conversion flags (if present)
274 // skip minimum field witdh (if present)
278 // skip precision (if present)
286 // get the conversion qualifier (if present)
288 if (*fmt
== 'h' || *fmt
== 'l' || *fmt
== 'L')
292 if (qualifier
== 'l' && *fmt
== 'l')
299 // get the conversion type
307 arg
->stp_type
= pe_long
;
308 mark_args
.push_back(arg
);
315 arg
->c_type
= "char *";
316 arg
->stp_type
= pe_string
;
317 mark_args
.push_back(arg
);
324 // This should really be 'void *'. But, then we'll get a
325 // compile error when we assign the void pointer to an
326 // integer without a cast. So, we use 'long' instead, since
327 // it should have the same size as 'void *'.
328 arg
->c_type
= "long";
329 arg
->stp_type
= pe_long
;
330 mark_args
.push_back(arg
);
354 arg
->stp_type
= pe_long
;
358 arg
->c_type
= "long long";
362 arg
->c_type
= "long";
366 arg
->c_type
= "short";
373 mark_args
.push_back(arg
);
379 mark_derived_probe::join_group (systemtap_session
& s
)
381 if (! s
.mark_derived_probes
)
383 s
.mark_derived_probes
= new mark_derived_probe_group ();
385 // Make sure <linux/marker.h> is included early.
386 embeddedcode
*ec
= new embeddedcode
;
388 ec
->code
= string("#if ! defined(CONFIG_MARKERS)\n")
389 + string("#error \"Need CONFIG_MARKERS!\"\n")
391 + string("#include <linux/marker.h>\n");
393 s
.embeds
.push_back(ec
);
395 s
.mark_derived_probes
->enroll (this);
400 mark_derived_probe::print_dupe_stamp (ostream
& o
)
402 if (target_symbol_seen
)
403 for (unsigned i
= 0; i
< mark_args
.size(); i
++)
404 o
<< mark_args
[i
]->c_type
<< " __mark_arg" << (i
+1) << endl
;
409 mark_derived_probe::emit_probe_context_vars (translator_output
* o
)
411 // If we haven't seen a target symbol for this probe, quit.
412 if (! target_symbol_seen
)
415 for (unsigned i
= 0; i
< mark_args
.size(); i
++)
417 string localname
= "__mark_arg" + lex_cast(i
+1);
418 switch (mark_args
[i
]->stp_type
)
421 o
->newline() << "int64_t " << localname
<< ";";
424 o
->newline() << "string_t " << localname
<< ";";
427 throw semantic_error ("cannot expand unknown type");
435 mark_derived_probe::initialize_probe_context_vars (translator_output
* o
)
437 // If we haven't seen a target symbol for this probe, quit.
438 if (! target_symbol_seen
)
441 bool deref_fault_needed
= false;
442 for (unsigned i
= 0; i
< mark_args
.size(); i
++)
444 string localname
= "l->__mark_arg" + lex_cast(i
+1);
445 switch (mark_args
[i
]->stp_type
)
448 o
->newline() << localname
<< " = va_arg(*c->mark_va_list, "
449 << mark_args
[i
]->c_type
<< ");";
453 // We're assuming that this is a kernel string (this code is
454 // basically the guts of kernel_string), not a user string.
455 o
->newline() << "{ " << mark_args
[i
]->c_type
456 << " tmp_str = va_arg(*c->mark_va_list, "
457 << mark_args
[i
]->c_type
<< ");";
458 o
->newline() << "deref_string (" << localname
459 << ", tmp_str, MAXSTRINGLEN); }";
460 deref_fault_needed
= true;
464 throw semantic_error ("cannot expand unknown type");
468 if (deref_fault_needed
)
469 // Need to report errors?
470 o
->newline() << "deref_fault: ;";
474 mark_derived_probe::printargs(std::ostream
&o
) const
476 for (unsigned i
= 0; i
< mark_args
.size(); i
++)
478 string localname
= "$arg" + lex_cast(i
+1);
479 switch (mark_args
[i
]->stp_type
)
482 o
<< " " << localname
<< ":long";
485 o
<< " " << localname
<< ":string";
488 o
<< " " << localname
<< ":unknown";
496 mark_derived_probe_group::emit_module_decls (systemtap_session
& s
)
501 s
.op
->newline() << "/* ---- marker probes ---- */";
503 s
.op
->newline() << "static struct stap_marker_probe {";
504 s
.op
->newline(1) << "const char * const name;";
505 s
.op
->newline() << "const char * const format;";
506 s
.op
->newline() << "const char * const pp;";
507 s
.op
->newline() << "void (* const ph) (struct context *);";
509 s
.op
->newline(-1) << "} stap_marker_probes [" << probes
.size() << "] = {";
511 for (unsigned i
=0; i
< probes
.size(); i
++)
513 s
.op
->newline () << "{";
514 s
.op
->line() << " .name=" << lex_cast_qstring(probes
[i
]->probe_name
)
516 s
.op
->line() << " .format=" << lex_cast_qstring(probes
[i
]->probe_format
)
518 s
.op
->line() << " .pp=" << lex_cast_qstring (*probes
[i
]->sole_location())
520 s
.op
->line() << " .ph=&" << probes
[i
]->name
;
521 s
.op
->line() << " },";
523 s
.op
->newline(-1) << "};";
527 // Emit the marker callback function
529 s
.op
->newline() << "static void enter_marker_probe (void *probe_data, void *call_data, const char *fmt, va_list *args) {";
530 s
.op
->newline(1) << "struct stap_marker_probe *smp = (struct stap_marker_probe *)probe_data;";
531 common_probe_entryfn_prologue (s
.op
, "STAP_SESSION_RUNNING", "smp->pp");
532 s
.op
->newline() << "c->marker_name = smp->name;";
533 s
.op
->newline() << "c->marker_format = smp->format;";
534 s
.op
->newline() << "c->mark_va_list = args;";
535 s
.op
->newline() << "(*smp->ph) (c);";
536 s
.op
->newline() << "c->mark_va_list = NULL;";
537 s
.op
->newline() << "c->data = NULL;";
539 common_probe_entryfn_epilogue (s
.op
);
540 s
.op
->newline(-1) << "}";
547 mark_derived_probe_group::emit_module_init (systemtap_session
&s
)
549 if (probes
.size () == 0)
552 s
.op
->newline() << "/* init marker probes */";
553 s
.op
->newline() << "for (i=0; i<" << probes
.size() << "; i++) {";
554 s
.op
->newline(1) << "struct stap_marker_probe *smp = &stap_marker_probes[i];";
555 s
.op
->newline() << "probe_point = smp->pp;";
556 s
.op
->newline() << "rc = marker_probe_register(smp->name, smp->format, enter_marker_probe, smp);";
557 s
.op
->newline() << "if (rc) {";
558 s
.op
->newline(1) << "for (j=i-1; j>=0; j--) {"; // partial rollback
559 s
.op
->newline(1) << "struct stap_marker_probe *smp2 = &stap_marker_probes[j];";
560 s
.op
->newline() << "marker_probe_unregister(smp2->name, enter_marker_probe, smp2);";
561 s
.op
->newline(-1) << "}";
562 s
.op
->newline() << "break;"; // don't attempt to register any more probes
563 s
.op
->newline(-1) << "}";
564 s
.op
->newline(-1) << "}"; // for loop
569 mark_derived_probe_group::emit_module_exit (systemtap_session
& s
)
574 s
.op
->newline() << "/* deregister marker probes */";
575 s
.op
->newline() << "for (i=0; i<" << probes
.size() << "; i++) {";
576 s
.op
->newline(1) << "struct stap_marker_probe *smp = &stap_marker_probes[i];";
577 s
.op
->newline() << "marker_probe_unregister(smp->name, enter_marker_probe, smp);";
578 s
.op
->newline(-1) << "}"; // for loop
582 struct mark_builder
: public derived_probe_builder
585 bool cache_initialized
;
586 typedef multimap
<string
, string
> mark_cache_t
;
587 typedef multimap
<string
, string
>::const_iterator mark_cache_const_iterator_t
;
588 typedef pair
<mark_cache_const_iterator_t
, mark_cache_const_iterator_t
>
589 mark_cache_const_iterator_pair_t
;
590 mark_cache_t mark_cache
;
593 mark_builder(): cache_initialized(false) {}
595 void build_no_more (systemtap_session
&s
)
597 if (! mark_cache
.empty())
600 clog
<< "mark_builder releasing cache" << endl
;
605 void build(systemtap_session
& sess
,
607 probe_point
* location
,
608 literal_map_t
const & parameters
,
609 vector
<derived_probe
*> & finished_results
);
614 mark_builder::build(systemtap_session
& sess
,
617 literal_map_t
const & parameters
,
618 vector
<derived_probe
*> & finished_results
)
621 bool has_mark_str
= get_param (parameters
, TOK_MARK
, mark_str_val
);
622 string mark_format_val
;
623 bool has_mark_format
= get_param (parameters
, TOK_FORMAT
, mark_format_val
);
624 assert (has_mark_str
);
627 if (! cache_initialized
)
629 cache_initialized
= true;
630 string module_markers_path
= sess
.kernel_build_tree
+ "/Module.markers";
632 ifstream module_markers
;
633 module_markers
.open(module_markers_path
.c_str(), ifstream::in
);
634 if (! module_markers
)
637 clog
<< module_markers_path
<< " cannot be opened: "
638 << strerror(errno
) << endl
;
642 string name
, module
, format
;
645 module_markers
>> name
>> module
;
646 getline(module_markers
, format
);
648 // trim leading whitespace
649 string::size_type notwhite
= format
.find_first_not_of(" \t");
650 format
.erase(0, notwhite
);
652 // If the format is empty, make sure we add back a space
653 // character, which is what MARK_NOARGS expands to.
654 if (format
.length() == 0)
658 clog
<< "'" << name
<< "' '" << module
<< "' '" << format
661 if (mark_cache
.count(name
) > 0)
663 // If we have 2 markers with the same we've got 2 cases:
664 // different format strings or duplicate format strings.
665 // If an existing marker in the cache doesn't have the
666 // same format string, add this marker.
667 mark_cache_const_iterator_pair_t ret
;
668 mark_cache_const_iterator_t it
;
669 bool matching_format_string
= false;
671 ret
= mark_cache
.equal_range(name
);
672 for (it
= ret
.first
; it
!= ret
.second
; ++it
)
674 if (format
== it
->second
)
676 matching_format_string
= true;
681 if (! matching_format_string
)
682 mark_cache
.insert(pair
<string
,string
>(name
, format
));
685 mark_cache
.insert(pair
<string
,string
>(name
, format
));
687 while (! module_markers
.eof());
688 module_markers
.close();
691 // Search marker list for matching markers
692 for (mark_cache_const_iterator_t it
= mark_cache
.begin();
693 it
!= mark_cache
.end(); it
++)
695 // Below, "rc" has negative polarity: zero iff matching.
696 int rc
= fnmatch(mark_str_val
.c_str(), it
->first
.c_str(), 0);
699 bool add_result
= true;
701 // Match format strings (if the user specified one)
702 if (has_mark_format
&& fnmatch(mark_format_val
.c_str(),
703 it
->second
.c_str(), 0))
709 = new mark_derived_probe (sess
,
710 it
->first
, it
->second
,
712 finished_results
.push_back (dp
);
721 register_tapset_mark(systemtap_session
& s
)
723 match_node
* root
= s
.pattern_root
;
724 derived_probe_builder
*builder
= new mark_builder();
726 root
= root
->bind(TOK_KERNEL
);
727 root
= root
->bind_str(TOK_MARK
);
730 root
->bind_str(TOK_FORMAT
)->bind(builder
);
733 /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */