]> sourceware.org Git - systemtap.git/blob - tapset-mark.cxx
Merge branch 'master' of git://sources.redhat.com/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 string c_type;
43 exp_type stp_type;
44 };
45
46 struct mark_derived_probe: public derived_probe
47 {
48 mark_derived_probe (systemtap_session &s,
49 const string& probe_name, const string& probe_format,
50 probe* base_probe, probe_point* location);
51
52 systemtap_session& sess;
53 string probe_name, probe_format;
54 vector <struct mark_arg *> mark_args;
55 bool target_symbol_seen;
56
57 void join_group (systemtap_session& s);
58 void print_dupe_stamp (ostream& o);
59 void emit_probe_context_vars (translator_output* o);
60 void initialize_probe_context_vars (translator_output* o);
61 void printargs (std::ostream &o) const;
62
63 void parse_probe_format ();
64 };
65
66
67 struct mark_derived_probe_group: public generic_dpg<mark_derived_probe>
68 {
69 public:
70 void emit_module_decls (systemtap_session& s);
71 void emit_module_init (systemtap_session& s);
72 void emit_module_exit (systemtap_session& s);
73 };
74
75
76 struct mark_var_expanding_visitor: public var_expanding_visitor
77 {
78 mark_var_expanding_visitor(systemtap_session& s, const string& pn,
79 vector <struct mark_arg *> &mark_args):
80 sess (s), probe_name (pn), mark_args (mark_args),
81 target_symbol_seen (false) {}
82 systemtap_session& sess;
83 string probe_name;
84 vector <struct mark_arg *> &mark_args;
85 bool target_symbol_seen;
86
87 void visit_target_symbol (target_symbol* e);
88 void visit_target_symbol_arg (target_symbol* e);
89 void visit_target_symbol_context (target_symbol* e);
90 };
91
92
93 void
94 mark_var_expanding_visitor::visit_target_symbol_arg (target_symbol* e)
95 {
96 string argnum_s = e->base_name.substr(4,e->base_name.length()-4);
97 int argnum = atoi (argnum_s.c_str());
98
99 if (argnum < 1 || argnum > (int)mark_args.size())
100 throw semantic_error ("invalid marker argument number", e->tok);
101
102 if (is_active_lvalue (e))
103 throw semantic_error("write to marker parameter not permitted", e->tok);
104
105 if (e->components.size() > 0)
106 {
107 switch (e->components[0].first)
108 {
109 case target_symbol::comp_literal_array_index:
110 throw semantic_error("marker argument may not be used as array",
111 e->tok);
112 break;
113 case target_symbol::comp_struct_member:
114 throw semantic_error("marker argument may not be used as a structure",
115 e->tok);
116 break;
117 default:
118 throw semantic_error ("invalid marker argument use", e->tok);
119 break;
120 }
121 }
122
123 // Remember that we've seen a target variable.
124 target_symbol_seen = true;
125
126 e->probe_context_var = "__mark_arg" + lex_cast<string>(argnum);
127 e->type = mark_args[argnum-1]->stp_type;
128 provide (e);
129 }
130
131
132 void
133 mark_var_expanding_visitor::visit_target_symbol_context (target_symbol* e)
134 {
135 string sname = e->base_name;
136
137 if (is_active_lvalue (e))
138 throw semantic_error("write to marker '" + sname + "' not permitted", e->tok);
139
140 if (e->components.size() > 0)
141 {
142 switch (e->components[0].first)
143 {
144 case target_symbol::comp_literal_array_index:
145 throw semantic_error("marker '" + sname + "' may not be used as array",
146 e->tok);
147 break;
148 case target_symbol::comp_struct_member:
149 throw semantic_error("marker '" + sname + "' may not be used as a structure",
150 e->tok);
151 break;
152 default:
153 throw semantic_error ("invalid marker '" + sname + "' use", e->tok);
154 break;
155 }
156 }
157
158 string fname;
159 if (e->base_name == "$format") {
160 fname = string("_mark_format_get");
161 } else {
162 fname = string("_mark_name_get");
163 }
164
165 // Synthesize a functioncall.
166 functioncall* n = new functioncall;
167 n->tok = e->tok;
168 n->function = fname;
169 n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session
170 provide (n);
171 }
172
173 void
174 mark_var_expanding_visitor::visit_target_symbol (target_symbol* e)
175 {
176 assert(e->base_name.size() > 0 && e->base_name[0] == '$');
177
178 if (e->base_name.substr(0,4) == "$arg")
179 visit_target_symbol_arg (e);
180 else if (e->base_name == "$format" || e->base_name == "$name")
181 visit_target_symbol_context (e);
182 else
183 throw semantic_error ("invalid target symbol for marker, $argN, $name or $format expected",
184 e->tok);
185 }
186
187
188
189 mark_derived_probe::mark_derived_probe (systemtap_session &s,
190 const string& p_n,
191 const string& p_f,
192 probe* base, probe_point* loc):
193 derived_probe (base, new probe_point(*loc) /* .components soon rewritten */),
194 sess (s), probe_name (p_n), probe_format (p_f),
195 target_symbol_seen (false)
196 {
197 // create synthetic probe point name; preserve condition
198 vector<probe_point::component*> comps;
199 comps.push_back (new probe_point::component (TOK_KERNEL));
200 comps.push_back (new probe_point::component (TOK_MARK, new literal_string (probe_name)));
201 comps.push_back (new probe_point::component (TOK_FORMAT, new literal_string (probe_format)));
202 this->sole_location()->components = comps;
203
204 // expand the marker format
205 parse_probe_format();
206
207 // Now expand the local variables in the probe body
208 mark_var_expanding_visitor v (sess, name, mark_args);
209 this->body = v.require (this->body);
210 target_symbol_seen = v.target_symbol_seen;
211
212 if (sess.verbose > 2)
213 clog << "marker-based " << name << " mark=" << probe_name
214 << " fmt='" << probe_format << "'" << endl;
215 }
216
217
218 static int
219 skip_atoi(const char **s)
220 {
221 int i = 0;
222 while (isdigit(**s))
223 i = i * 10 + *((*s)++) - '0';
224 return i;
225 }
226
227
228 void
229 mark_derived_probe::parse_probe_format()
230 {
231 const char *fmt = probe_format.c_str();
232 int qualifier; // 'h', 'l', or 'L' for integer fields
233 mark_arg *arg;
234
235 for (; *fmt ; ++fmt)
236 {
237 if (*fmt != '%')
238 {
239 /* Skip text */
240 continue;
241 }
242
243 repeat:
244 ++fmt;
245
246 // skip conversion flags (if present)
247 switch (*fmt)
248 {
249 case '-':
250 case '+':
251 case ' ':
252 case '#':
253 case '0':
254 goto repeat;
255 }
256
257 // skip minimum field witdh (if present)
258 if (isdigit(*fmt))
259 skip_atoi(&fmt);
260
261 // skip precision (if present)
262 if (*fmt == '.')
263 {
264 ++fmt;
265 if (isdigit(*fmt))
266 skip_atoi(&fmt);
267 }
268
269 // get the conversion qualifier (if present)
270 qualifier = -1;
271 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L')
272 {
273 qualifier = *fmt;
274 ++fmt;
275 if (qualifier == 'l' && *fmt == 'l')
276 {
277 qualifier = 'L';
278 ++fmt;
279 }
280 }
281
282 // get the conversion type
283 switch (*fmt)
284 {
285 case 'c':
286 arg = new mark_arg;
287 arg->str = false;
288 arg->c_type = "int";
289 arg->stp_type = pe_long;
290 mark_args.push_back(arg);
291 continue;
292
293 case 's':
294 arg = new mark_arg;
295 arg->str = true;
296 arg->c_type = "char *";
297 arg->stp_type = pe_string;
298 mark_args.push_back(arg);
299 continue;
300
301 case 'p':
302 arg = new mark_arg;
303 arg->str = false;
304 // This should really be 'void *'. But, then we'll get a
305 // compile error when we assign the void pointer to an
306 // integer without a cast. So, we use 'long' instead, since
307 // it should have the same size as 'void *'.
308 arg->c_type = "long";
309 arg->stp_type = pe_long;
310 mark_args.push_back(arg);
311 continue;
312
313 case '%':
314 continue;
315
316 case 'o':
317 case 'X':
318 case 'x':
319 case 'd':
320 case 'i':
321 case 'u':
322 // fall through...
323 break;
324
325 default:
326 if (!*fmt)
327 --fmt;
328 continue;
329 }
330
331 arg = new mark_arg;
332 arg->str = false;
333 arg->stp_type = pe_long;
334 switch (qualifier)
335 {
336 case 'L':
337 arg->c_type = "long long";
338 break;
339
340 case 'l':
341 arg->c_type = "long";
342 break;
343
344 case 'h':
345 arg->c_type = "short";
346 break;
347
348 default:
349 arg->c_type = "int";
350 break;
351 }
352 mark_args.push_back(arg);
353 }
354 }
355
356
357 void
358 mark_derived_probe::join_group (systemtap_session& s)
359 {
360 if (! s.mark_derived_probes)
361 {
362 s.mark_derived_probes = new mark_derived_probe_group ();
363
364 // Make sure <linux/marker.h> is included early.
365 embeddedcode *ec = new embeddedcode;
366 ec->tok = NULL;
367 ec->code = string("#if ! defined(CONFIG_MARKERS)\n")
368 + string("#error \"Need CONFIG_MARKERS!\"\n")
369 + string("#endif\n")
370 + string("#include <linux/marker.h>\n");
371
372 s.embeds.push_back(ec);
373 }
374 s.mark_derived_probes->enroll (this);
375 }
376
377
378 void
379 mark_derived_probe::print_dupe_stamp (ostream& o)
380 {
381 if (target_symbol_seen)
382 for (unsigned i = 0; i < mark_args.size(); i++)
383 o << mark_args[i]->c_type << " __mark_arg" << (i+1) << endl;
384 }
385
386
387 void
388 mark_derived_probe::emit_probe_context_vars (translator_output* o)
389 {
390 // If we haven't seen a target symbol for this probe, quit.
391 if (! target_symbol_seen)
392 return;
393
394 for (unsigned i = 0; i < mark_args.size(); i++)
395 {
396 string localname = "__mark_arg" + lex_cast<string>(i+1);
397 switch (mark_args[i]->stp_type)
398 {
399 case pe_long:
400 o->newline() << "int64_t " << localname << ";";
401 break;
402 case pe_string:
403 o->newline() << "string_t " << localname << ";";
404 break;
405 default:
406 throw semantic_error ("cannot expand unknown type");
407 break;
408 }
409 }
410 }
411
412
413 void
414 mark_derived_probe::initialize_probe_context_vars (translator_output* o)
415 {
416 // If we haven't seen a target symbol for this probe, quit.
417 if (! target_symbol_seen)
418 return;
419
420 bool deref_fault_needed = false;
421 for (unsigned i = 0; i < mark_args.size(); i++)
422 {
423 string localname = "l->__mark_arg" + lex_cast<string>(i+1);
424 switch (mark_args[i]->stp_type)
425 {
426 case pe_long:
427 o->newline() << localname << " = va_arg(*c->mark_va_list, "
428 << mark_args[i]->c_type << ");";
429 break;
430
431 case pe_string:
432 // We're assuming that this is a kernel string (this code is
433 // basically the guts of kernel_string), not a user string.
434 o->newline() << "{ " << mark_args[i]->c_type
435 << " tmp_str = va_arg(*c->mark_va_list, "
436 << mark_args[i]->c_type << ");";
437 o->newline() << "deref_string (" << localname
438 << ", tmp_str, MAXSTRINGLEN); }";
439 deref_fault_needed = true;
440 break;
441
442 default:
443 throw semantic_error ("cannot expand unknown type");
444 break;
445 }
446 }
447 if (deref_fault_needed)
448 // Need to report errors?
449 o->newline() << "deref_fault: ;";
450 }
451
452 void
453 mark_derived_probe::printargs(std::ostream &o) const
454 {
455 for (unsigned i = 0; i < mark_args.size(); i++)
456 {
457 string localname = "$arg" + lex_cast<string>(i+1);
458 switch (mark_args[i]->stp_type)
459 {
460 case pe_long:
461 o << " " << localname << ":long";
462 break;
463 case pe_string:
464 o << " " << localname << ":string";
465 break;
466 default:
467 o << " " << localname << ":unknown";
468 break;
469 }
470 }
471 }
472
473
474 void
475 mark_derived_probe_group::emit_module_decls (systemtap_session& s)
476 {
477 if (probes.empty())
478 return;
479
480 s.op->newline() << "/* ---- marker probes ---- */";
481
482 s.op->newline() << "static struct stap_marker_probe {";
483 s.op->newline(1) << "const char * const name;";
484 s.op->newline() << "const char * const format;";
485 s.op->newline() << "const char * const pp;";
486 s.op->newline() << "void (* const ph) (struct context *);";
487
488 s.op->newline(-1) << "} stap_marker_probes [" << probes.size() << "] = {";
489 s.op->indent(1);
490 for (unsigned i=0; i < probes.size(); i++)
491 {
492 s.op->newline () << "{";
493 s.op->line() << " .name=" << lex_cast_qstring(probes[i]->probe_name)
494 << ",";
495 s.op->line() << " .format=" << lex_cast_qstring(probes[i]->probe_format)
496 << ",";
497 s.op->line() << " .pp=" << lex_cast_qstring (*probes[i]->sole_location())
498 << ",";
499 s.op->line() << " .ph=&" << probes[i]->name;
500 s.op->line() << " },";
501 }
502 s.op->newline(-1) << "};";
503 s.op->newline();
504
505
506 // Emit the marker callback function
507 s.op->newline();
508 s.op->newline() << "static void enter_marker_probe (void *probe_data, void *call_data, const char *fmt, va_list *args) {";
509 s.op->newline(1) << "struct stap_marker_probe *smp = (struct stap_marker_probe *)probe_data;";
510 common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "smp->pp");
511 s.op->newline() << "c->marker_name = smp->name;";
512 s.op->newline() << "c->marker_format = smp->format;";
513 s.op->newline() << "c->mark_va_list = args;";
514 s.op->newline() << "(*smp->ph) (c);";
515 s.op->newline() << "c->mark_va_list = NULL;";
516 s.op->newline() << "c->data = NULL;";
517
518 common_probe_entryfn_epilogue (s.op);
519 s.op->newline(-1) << "}";
520
521 return;
522 }
523
524
525 void
526 mark_derived_probe_group::emit_module_init (systemtap_session &s)
527 {
528 if (probes.size () == 0)
529 return;
530
531 s.op->newline() << "/* init marker probes */";
532 s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {";
533 s.op->newline(1) << "struct stap_marker_probe *smp = &stap_marker_probes[i];";
534 s.op->newline() << "probe_point = smp->pp;";
535 s.op->newline() << "rc = marker_probe_register(smp->name, smp->format, enter_marker_probe, smp);";
536 s.op->newline() << "if (rc) {";
537 s.op->newline(1) << "for (j=i-1; j>=0; j--) {"; // partial rollback
538 s.op->newline(1) << "struct stap_marker_probe *smp2 = &stap_marker_probes[j];";
539 s.op->newline() << "marker_probe_unregister(smp2->name, enter_marker_probe, smp2);";
540 s.op->newline(-1) << "}";
541 s.op->newline() << "break;"; // don't attempt to register any more probes
542 s.op->newline(-1) << "}";
543 s.op->newline(-1) << "}"; // for loop
544 }
545
546
547 void
548 mark_derived_probe_group::emit_module_exit (systemtap_session& s)
549 {
550 if (probes.empty())
551 return;
552
553 s.op->newline() << "/* deregister marker probes */";
554 s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {";
555 s.op->newline(1) << "struct stap_marker_probe *smp = &stap_marker_probes[i];";
556 s.op->newline() << "marker_probe_unregister(smp->name, enter_marker_probe, smp);";
557 s.op->newline(-1) << "}"; // for loop
558 }
559
560
561 struct mark_builder: public derived_probe_builder
562 {
563 private:
564 bool cache_initialized;
565 typedef multimap<string, string> mark_cache_t;
566 typedef multimap<string, string>::const_iterator mark_cache_const_iterator_t;
567 typedef pair<mark_cache_const_iterator_t, mark_cache_const_iterator_t>
568 mark_cache_const_iterator_pair_t;
569 mark_cache_t mark_cache;
570
571 public:
572 mark_builder(): cache_initialized(false) {}
573
574 void build_no_more (systemtap_session &s)
575 {
576 if (! mark_cache.empty())
577 {
578 if (s.verbose > 3)
579 clog << "mark_builder releasing cache" << endl;
580 mark_cache.clear();
581 }
582 }
583
584 void build(systemtap_session & sess,
585 probe * base,
586 probe_point * location,
587 literal_map_t const & parameters,
588 vector<derived_probe *> & finished_results);
589 };
590
591
592 void
593 mark_builder::build(systemtap_session & sess,
594 probe * base,
595 probe_point *loc,
596 literal_map_t const & parameters,
597 vector<derived_probe *> & finished_results)
598 {
599 string mark_str_val;
600 bool has_mark_str = get_param (parameters, TOK_MARK, mark_str_val);
601 string mark_format_val;
602 bool has_mark_format = get_param (parameters, TOK_FORMAT, mark_format_val);
603 assert (has_mark_str);
604 (void) has_mark_str;
605
606 if (! cache_initialized)
607 {
608 cache_initialized = true;
609 string module_markers_path = sess.kernel_build_tree + "/Module.markers";
610
611 ifstream module_markers;
612 module_markers.open(module_markers_path.c_str(), ifstream::in);
613 if (! module_markers)
614 {
615 if (sess.verbose>3)
616 clog << module_markers_path << " cannot be opened: "
617 << strerror(errno) << endl;
618 return;
619 }
620
621 string name, module, format;
622 do
623 {
624 module_markers >> name >> module;
625 getline(module_markers, format);
626
627 // trim leading whitespace
628 string::size_type notwhite = format.find_first_not_of(" \t");
629 format.erase(0, notwhite);
630
631 // If the format is empty, make sure we add back a space
632 // character, which is what MARK_NOARGS expands to.
633 if (format.length() == 0)
634 format = " ";
635
636 if (sess.verbose>3)
637 clog << "'" << name << "' '" << module << "' '" << format
638 << "'" << endl;
639
640 if (mark_cache.count(name) > 0)
641 {
642 // If we have 2 markers with the same we've got 2 cases:
643 // different format strings or duplicate format strings.
644 // If an existing marker in the cache doesn't have the
645 // same format string, add this marker.
646 mark_cache_const_iterator_pair_t ret;
647 mark_cache_const_iterator_t it;
648 bool matching_format_string = false;
649
650 ret = mark_cache.equal_range(name);
651 for (it = ret.first; it != ret.second; ++it)
652 {
653 if (format == it->second)
654 {
655 matching_format_string = true;
656 break;
657 }
658 }
659
660 if (! matching_format_string)
661 mark_cache.insert(pair<string,string>(name, format));
662 }
663 else
664 mark_cache.insert(pair<string,string>(name, format));
665 }
666 while (! module_markers.eof());
667 module_markers.close();
668 }
669
670 // Search marker list for matching markers
671 for (mark_cache_const_iterator_t it = mark_cache.begin();
672 it != mark_cache.end(); it++)
673 {
674 // Below, "rc" has negative polarity: zero iff matching.
675 int rc = fnmatch(mark_str_val.c_str(), it->first.c_str(), 0);
676 if (! rc)
677 {
678 bool add_result = true;
679
680 // Match format strings (if the user specified one)
681 if (has_mark_format && fnmatch(mark_format_val.c_str(),
682 it->second.c_str(), 0))
683 add_result = false;
684
685 if (add_result)
686 {
687 derived_probe *dp
688 = new mark_derived_probe (sess,
689 it->first, it->second,
690 base, loc);
691 finished_results.push_back (dp);
692 }
693 }
694 }
695 }
696
697
698
699 void
700 register_tapset_mark(systemtap_session& s)
701 {
702 match_node* root = s.pattern_root;
703 derived_probe_builder *builder = new mark_builder();
704
705 root = root->bind(TOK_KERNEL);
706 root = root->bind_str(TOK_MARK);
707
708 root->bind(builder);
709 root->bind_str(TOK_FORMAT)->bind(builder);
710 }
711
712 /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
This page took 0.07246 seconds and 6 git commands to generate.