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