]>
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") { |
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 | ||
180 | void | |
181 | mark_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 |
207 | mark_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 | ||
247 | static int | |
248 | skip_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 | ||
257 | void | |
258 | mark_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 | ||
272 | repeat: | |
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 | ||
390 | void | |
391 | mark_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 | ||
411 | void | |
412 | mark_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 |
420 | void |
421 | mark_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 | ||
459 | void | |
d0bfd2ac | 460 | mark_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 | ||
481 | void | |
482 | mark_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 | ||
526 | void | |
527 | mark_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 | ||
548 | void | |
549 | mark_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 | ||
562 | struct mark_builder: public derived_probe_builder | |
563 | { | |
564 | private: | |
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 | ||
572 | public: | |
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 | ||
593 | void | |
594 | mark_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 | ||
700 | void | |
701 | register_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 : */ |