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