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