]> sourceware.org Git - systemtap.git/blob - tapset-mark.cxx
Merge branch 'master' of sourceware.org:/git/systemtap
[systemtap.git] / tapset-mark.cxx
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
5 //
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
9 // later version.
10
11 #include "session.h"
12 #include "tapsets.h"
13 #include "translate.h"
14 #include "util.h"
15
16 #include <cerrno>
17 #include <cstdlib>
18 #include <cstring>
19 #include <string>
20
21 extern "C" {
22 #include <fnmatch.h>
23 }
24
25
26 using namespace std;
27 using namespace __gnu_cxx;
28
29
30 static const string TOK_KERNEL("kernel");
31 static const string TOK_MARK("mark");
32 static const string TOK_FORMAT("format");
33
34
35 // ------------------------------------------------------------------------
36 // statically inserted macro-based derived probes
37 // ------------------------------------------------------------------------
38
39 struct mark_arg
40 {
41 bool str;
42 bool isptr;
43 string c_type;
44 exp_type stp_type;
45 };
46
47 struct mark_derived_probe: public derived_probe
48 {
49 mark_derived_probe (systemtap_session &s,
50 const string& probe_name, const string& probe_format,
51 probe* base_probe, probe_point* location);
52
53 systemtap_session& sess;
54 string probe_name, probe_format;
55 vector <struct mark_arg *> mark_args;
56 bool target_symbol_seen;
57
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;
63
64 void parse_probe_format ();
65 };
66
67
68 struct mark_derived_probe_group: public generic_dpg<mark_derived_probe>
69 {
70 public:
71 void emit_module_decls (systemtap_session& s);
72 void emit_module_init (systemtap_session& s);
73 void emit_module_exit (systemtap_session& s);
74 };
75
76
77 struct mark_var_expanding_visitor: public var_expanding_visitor
78 {
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;
84 string probe_name;
85 vector <struct mark_arg *> &mark_args;
86 bool target_symbol_seen;
87
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);
91 };
92
93
94 void
95 mark_var_expanding_visitor::visit_target_symbol_arg (target_symbol* e)
96 {
97 string argnum_s = e->base_name.substr(4,e->base_name.length()-4);
98 int argnum = atoi (argnum_s.c_str());
99
100 if (argnum < 1 || argnum > (int)mark_args.size())
101 throw semantic_error ("invalid marker argument number", e->tok);
102
103 if (is_active_lvalue (e))
104 throw semantic_error("write to marker parameter not permitted", e->tok);
105
106 e->assert_no_components("marker");
107
108 // Remember that we've seen a target variable.
109 target_symbol_seen = true;
110
111 e->probe_context_var = "__mark_arg" + lex_cast(argnum);
112 e->type = mark_args[argnum-1]->stp_type;
113 provide (e);
114 }
115
116
117 void
118 mark_var_expanding_visitor::visit_target_symbol_context (target_symbol* e)
119 {
120 string sname = e->base_name;
121
122 if (is_active_lvalue (e))
123 throw semantic_error("write to marker '" + sname + "' not permitted", e->tok);
124
125 e->assert_no_components("marker");
126
127 if (e->base_name == "$format" || e->base_name == "$name") {
128 string fname;
129 if (e->base_name == "$format") {
130 fname = string("_mark_format_get");
131 } else {
132 fname = string("_mark_name_get");
133 }
134
135 // Synthesize a functioncall.
136 functioncall* n = new functioncall;
137 n->tok = e->tok;
138 n->function = fname;
139 n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session
140 provide (n);
141 }
142 else if (e->base_name == "$$vars" || e->base_name == "$$parms")
143 {
144 //copy from tracepoint
145 print_format* pf = new print_format;
146 token* pf_tok = new token(*e->tok);
147 pf_tok->content = "sprintf";
148 pf->tok = pf_tok;
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;
154
155 for (unsigned i = 0; i < mark_args.size(); ++i)
156 {
157 if (i > 0)
158 pf->raw_components += " ";
159 pf->raw_components += "$arg" + lex_cast(i+1);
160 target_symbol *tsym = new target_symbol;
161 tsym->tok = e->tok;
162 tsym->base_name = "$arg" + lex_cast(i+1);
163
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)
168 {
169 case pe_long:
170 pf->raw_components += mark_args[i]->isptr ? "=%p" : "=%#x";
171 break;
172 case pe_string:
173 pf->raw_components += "=%s";
174 break;
175 default:
176 pf->raw_components += "=%#x";
177 break;
178 }
179 pf->args.push_back(texp);
180 }
181 pf->components = print_format::string_to_components(pf->raw_components);
182 provide (pf);
183 }
184 }
185
186 void
187 mark_var_expanding_visitor::visit_target_symbol (target_symbol* e)
188 {
189 assert(e->base_name.size() > 0 && e->base_name[0] == '$');
190
191 if (e->addressof)
192 throw semantic_error("cannot take address of marker variable", e->tok);
193
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);
199 else
200 throw semantic_error ("invalid target symbol for marker, $argN, $name, $format, $$parms or $$vars expected",
201 e->tok);
202 }
203
204
205
206 mark_derived_probe::mark_derived_probe (systemtap_session &s,
207 const string& p_n,
208 const string& p_f,
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)
213 {
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;
220
221 // expand the marker format
222 parse_probe_format();
223
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;
228
229 if (sess.verbose > 2)
230 clog << "marker-based " << name << " mark=" << probe_name
231 << " fmt='" << probe_format << "'" << endl;
232 }
233
234
235 static int
236 skip_atoi(const char **s)
237 {
238 int i = 0;
239 while (isdigit(**s))
240 i = i * 10 + *((*s)++) - '0';
241 return i;
242 }
243
244
245 void
246 mark_derived_probe::parse_probe_format()
247 {
248 const char *fmt = probe_format.c_str();
249 int qualifier; // 'h', 'l', or 'L' for integer fields
250 mark_arg *arg;
251
252 for (; *fmt ; ++fmt)
253 {
254 if (*fmt != '%')
255 {
256 /* Skip text */
257 continue;
258 }
259
260 repeat:
261 ++fmt;
262
263 // skip conversion flags (if present)
264 switch (*fmt)
265 {
266 case '-':
267 case '+':
268 case ' ':
269 case '#':
270 case '0':
271 goto repeat;
272 }
273
274 // skip minimum field witdh (if present)
275 if (isdigit(*fmt))
276 skip_atoi(&fmt);
277
278 // skip precision (if present)
279 if (*fmt == '.')
280 {
281 ++fmt;
282 if (isdigit(*fmt))
283 skip_atoi(&fmt);
284 }
285
286 // get the conversion qualifier (if present)
287 qualifier = -1;
288 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L')
289 {
290 qualifier = *fmt;
291 ++fmt;
292 if (qualifier == 'l' && *fmt == 'l')
293 {
294 qualifier = 'L';
295 ++fmt;
296 }
297 }
298
299 // get the conversion type
300 switch (*fmt)
301 {
302 case 'c':
303 arg = new mark_arg;
304 arg->str = false;
305 arg->isptr = false;
306 arg->c_type = "int";
307 arg->stp_type = pe_long;
308 mark_args.push_back(arg);
309 continue;
310
311 case 's':
312 arg = new mark_arg;
313 arg->str = true;
314 arg->isptr = false;
315 arg->c_type = "char *";
316 arg->stp_type = pe_string;
317 mark_args.push_back(arg);
318 continue;
319
320 case 'p':
321 arg = new mark_arg;
322 arg->str = false;
323 arg->isptr = true;
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);
331 continue;
332
333 case '%':
334 continue;
335
336 case 'o':
337 case 'X':
338 case 'x':
339 case 'd':
340 case 'i':
341 case 'u':
342 // fall through...
343 break;
344
345 default:
346 if (!*fmt)
347 --fmt;
348 continue;
349 }
350
351 arg = new mark_arg;
352 arg->str = false;
353 arg->isptr = false;
354 arg->stp_type = pe_long;
355 switch (qualifier)
356 {
357 case 'L':
358 arg->c_type = "long long";
359 break;
360
361 case 'l':
362 arg->c_type = "long";
363 break;
364
365 case 'h':
366 arg->c_type = "short";
367 break;
368
369 default:
370 arg->c_type = "int";
371 break;
372 }
373 mark_args.push_back(arg);
374 }
375 }
376
377
378 void
379 mark_derived_probe::join_group (systemtap_session& s)
380 {
381 if (! s.mark_derived_probes)
382 {
383 s.mark_derived_probes = new mark_derived_probe_group ();
384
385 // Make sure <linux/marker.h> is included early.
386 embeddedcode *ec = new embeddedcode;
387 ec->tok = NULL;
388 ec->code = string("#if ! defined(CONFIG_MARKERS)\n")
389 + string("#error \"Need CONFIG_MARKERS!\"\n")
390 + string("#endif\n")
391 + string("#include <linux/marker.h>\n");
392
393 s.embeds.push_back(ec);
394 }
395 s.mark_derived_probes->enroll (this);
396 }
397
398
399 void
400 mark_derived_probe::print_dupe_stamp (ostream& o)
401 {
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;
405 }
406
407
408 void
409 mark_derived_probe::emit_probe_context_vars (translator_output* o)
410 {
411 // If we haven't seen a target symbol for this probe, quit.
412 if (! target_symbol_seen)
413 return;
414
415 for (unsigned i = 0; i < mark_args.size(); i++)
416 {
417 string localname = "__mark_arg" + lex_cast(i+1);
418 switch (mark_args[i]->stp_type)
419 {
420 case pe_long:
421 o->newline() << "int64_t " << localname << ";";
422 break;
423 case pe_string:
424 o->newline() << "string_t " << localname << ";";
425 break;
426 default:
427 throw semantic_error ("cannot expand unknown type");
428 break;
429 }
430 }
431 }
432
433
434 void
435 mark_derived_probe::initialize_probe_context_vars (translator_output* o)
436 {
437 // If we haven't seen a target symbol for this probe, quit.
438 if (! target_symbol_seen)
439 return;
440
441 bool deref_fault_needed = false;
442 for (unsigned i = 0; i < mark_args.size(); i++)
443 {
444 string localname = "l->__mark_arg" + lex_cast(i+1);
445 switch (mark_args[i]->stp_type)
446 {
447 case pe_long:
448 o->newline() << localname << " = va_arg(*c->mark_va_list, "
449 << mark_args[i]->c_type << ");";
450 break;
451
452 case pe_string:
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;
461 break;
462
463 default:
464 throw semantic_error ("cannot expand unknown type");
465 break;
466 }
467 }
468 if (deref_fault_needed)
469 // Need to report errors?
470 o->newline() << "deref_fault: ;";
471 }
472
473 void
474 mark_derived_probe::printargs(std::ostream &o) const
475 {
476 for (unsigned i = 0; i < mark_args.size(); i++)
477 {
478 string localname = "$arg" + lex_cast(i+1);
479 switch (mark_args[i]->stp_type)
480 {
481 case pe_long:
482 o << " " << localname << ":long";
483 break;
484 case pe_string:
485 o << " " << localname << ":string";
486 break;
487 default:
488 o << " " << localname << ":unknown";
489 break;
490 }
491 }
492 }
493
494
495 void
496 mark_derived_probe_group::emit_module_decls (systemtap_session& s)
497 {
498 if (probes.empty())
499 return;
500
501 s.op->newline() << "/* ---- marker probes ---- */";
502
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 *);";
508
509 s.op->newline(-1) << "} stap_marker_probes [" << probes.size() << "] = {";
510 s.op->indent(1);
511 for (unsigned i=0; i < probes.size(); i++)
512 {
513 s.op->newline () << "{";
514 s.op->line() << " .name=" << lex_cast_qstring(probes[i]->probe_name)
515 << ",";
516 s.op->line() << " .format=" << lex_cast_qstring(probes[i]->probe_format)
517 << ",";
518 s.op->line() << " .pp=" << lex_cast_qstring (*probes[i]->sole_location())
519 << ",";
520 s.op->line() << " .ph=&" << probes[i]->name;
521 s.op->line() << " },";
522 }
523 s.op->newline(-1) << "};";
524 s.op->newline();
525
526
527 // Emit the marker callback function
528 s.op->newline();
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;";
538
539 common_probe_entryfn_epilogue (s.op);
540 s.op->newline(-1) << "}";
541
542 return;
543 }
544
545
546 void
547 mark_derived_probe_group::emit_module_init (systemtap_session &s)
548 {
549 if (probes.size () == 0)
550 return;
551
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
565 }
566
567
568 void
569 mark_derived_probe_group::emit_module_exit (systemtap_session& s)
570 {
571 if (probes.empty())
572 return;
573
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
579 }
580
581
582 struct mark_builder: public derived_probe_builder
583 {
584 private:
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;
591
592 public:
593 mark_builder(): cache_initialized(false) {}
594
595 void build_no_more (systemtap_session &s)
596 {
597 if (! mark_cache.empty())
598 {
599 if (s.verbose > 3)
600 clog << "mark_builder releasing cache" << endl;
601 mark_cache.clear();
602 }
603 }
604
605 void build(systemtap_session & sess,
606 probe * base,
607 probe_point * location,
608 literal_map_t const & parameters,
609 vector<derived_probe *> & finished_results);
610 };
611
612
613 void
614 mark_builder::build(systemtap_session & sess,
615 probe * base,
616 probe_point *loc,
617 literal_map_t const & parameters,
618 vector<derived_probe *> & finished_results)
619 {
620 string mark_str_val;
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);
625 (void) has_mark_str;
626
627 if (! cache_initialized)
628 {
629 cache_initialized = true;
630 string module_markers_path = sess.kernel_build_tree + "/Module.markers";
631
632 ifstream module_markers;
633 module_markers.open(module_markers_path.c_str(), ifstream::in);
634 if (! module_markers)
635 {
636 if (sess.verbose>3)
637 clog << module_markers_path << " cannot be opened: "
638 << strerror(errno) << endl;
639 return;
640 }
641
642 string name, module, format;
643 do
644 {
645 module_markers >> name >> module;
646 getline(module_markers, format);
647
648 // trim leading whitespace
649 string::size_type notwhite = format.find_first_not_of(" \t");
650 format.erase(0, notwhite);
651
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)
655 format = " ";
656
657 if (sess.verbose>3)
658 clog << "'" << name << "' '" << module << "' '" << format
659 << "'" << endl;
660
661 if (mark_cache.count(name) > 0)
662 {
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;
670
671 ret = mark_cache.equal_range(name);
672 for (it = ret.first; it != ret.second; ++it)
673 {
674 if (format == it->second)
675 {
676 matching_format_string = true;
677 break;
678 }
679 }
680
681 if (! matching_format_string)
682 mark_cache.insert(pair<string,string>(name, format));
683 }
684 else
685 mark_cache.insert(pair<string,string>(name, format));
686 }
687 while (! module_markers.eof());
688 module_markers.close();
689 }
690
691 // Search marker list for matching markers
692 for (mark_cache_const_iterator_t it = mark_cache.begin();
693 it != mark_cache.end(); it++)
694 {
695 // Below, "rc" has negative polarity: zero iff matching.
696 int rc = fnmatch(mark_str_val.c_str(), it->first.c_str(), 0);
697 if (! rc)
698 {
699 bool add_result = true;
700
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))
704 add_result = false;
705
706 if (add_result)
707 {
708 derived_probe *dp
709 = new mark_derived_probe (sess,
710 it->first, it->second,
711 base, loc);
712 finished_results.push_back (dp);
713 }
714 }
715 }
716 }
717
718
719
720 void
721 register_tapset_mark(systemtap_session& s)
722 {
723 match_node* root = s.pattern_root;
724 derived_probe_builder *builder = new mark_builder();
725
726 root = root->bind(TOK_KERNEL);
727 root = root->bind_str(TOK_MARK);
728
729 root->bind(builder);
730 root->bind_str(TOK_FORMAT)->bind(builder);
731 }
732
733 /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
This page took 0.089392 seconds and 6 git commands to generate.