Branch data Line data Source code
1 : : // utrace tapset
2 : : // Copyright (C) 2005-2013 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 : :
11 : : #include "session.h"
12 : : #include "tapsets.h"
13 : : #include "task_finder.h"
14 : : #include "tapset-dynprobe.h"
15 : : #include "translate.h"
16 : : #include "util.h"
17 : :
18 : : #include <cstring>
19 : : #include <string>
20 : :
21 : :
22 : : using namespace std;
23 : : using namespace __gnu_cxx;
24 : :
25 : :
26 [ + - ]: 2414 : static const string TOK_PROCESS("process");
27 [ + - ]: 2414 : static const string TOK_BEGIN("begin");
28 [ + - ]: 2414 : static const string TOK_END("end");
29 [ + - ]: 2414 : static const string TOK_THREAD("thread");
30 [ + - ]: 2414 : static const string TOK_SYSCALL("syscall");
31 [ + - ]: 2414 : static const string TOK_RETURN("return");
32 : :
33 : :
34 : : // ------------------------------------------------------------------------
35 : : // utrace user-space probes
36 : : // ------------------------------------------------------------------------
37 : :
38 : : // Note that these flags don't match up exactly with UTRACE_EVENT
39 : : // flags (and that's OK).
40 : : enum utrace_derived_probe_flags {
41 : : UDPF_NONE,
42 : : UDPF_BEGIN, // process begin
43 : : UDPF_END, // process end
44 : : UDPF_THREAD_BEGIN, // thread begin
45 : : UDPF_THREAD_END, // thread end
46 : : UDPF_SYSCALL, // syscall entry
47 : : UDPF_SYSCALL_RETURN, // syscall exit
48 : : UDPF_NFLAGS
49 : : };
50 : :
51 [ # # ][ # # ]: 0 : struct utrace_derived_probe: public derived_probe
[ # # ]
52 : : {
53 : : bool has_path;
54 : : string path;
55 : : bool has_library;
56 : : string library;
57 : : int64_t pid;
58 : : enum utrace_derived_probe_flags flags;
59 : : bool target_symbol_seen;
60 : :
61 : : utrace_derived_probe (systemtap_session &s, probe* p, probe_point* l,
62 : : bool hp, string &pn, int64_t pd,
63 : : enum utrace_derived_probe_flags f);
64 : : void join_group (systemtap_session& s);
65 : :
66 : : void emit_privilege_assertion (translator_output*);
67 : : void print_dupe_stamp(ostream& o);
68 : : void getargs (std::list<std::string> &arg_set) const;
69 : : };
70 : :
71 : :
72 [ # # ][ # # ]: 0 : struct utrace_derived_probe_group: public generic_dpg<utrace_derived_probe>
[ # # ]
73 : : {
74 : : private:
75 : : map<string, vector<utrace_derived_probe*> > probes_by_path;
76 : : typedef map<string, vector<utrace_derived_probe*> >::iterator p_b_path_iterator;
77 : : map<int64_t, vector<utrace_derived_probe*> > probes_by_pid;
78 : : typedef map<int64_t, vector<utrace_derived_probe*> >::iterator p_b_pid_iterator;
79 : : unsigned num_probes;
80 : : bool flags_seen[UDPF_NFLAGS];
81 : :
82 : : // Using the linux backend
83 : : void emit_linux_probe_decl (systemtap_session& s, utrace_derived_probe *p);
84 : : void emit_module_linux_decls (systemtap_session& s);
85 : : void emit_module_linux_init (systemtap_session& s);
86 : : void emit_module_linux_exit (systemtap_session& s);
87 : :
88 : : // Using the dyninst backend (via stapdyn)
89 : : void emit_dyninst_probe_decl (systemtap_session& s, const string& path,
90 : : utrace_derived_probe *p);
91 : : void emit_module_dyninst_decls (systemtap_session& s);
92 : : void emit_module_dyninst_init (systemtap_session& s);
93 : : void emit_module_dyninst_exit (systemtap_session& s);
94 : :
95 : : public:
96 [ + - ][ + - ]: 128 : utrace_derived_probe_group(): num_probes(0), flags_seen() { }
[ + + ]
97 : :
98 : : void enroll (utrace_derived_probe* probe);
99 : : void emit_module_decls (systemtap_session& s);
100 : : void emit_module_init (systemtap_session& s);
101 : : void emit_module_exit (systemtap_session& s);
102 : : };
103 : :
104 : :
105 [ + - ][ + - ]: 18 : struct utrace_var_expanding_visitor: public var_expanding_visitor
[ - + ]
106 : : {
107 : 18 : utrace_var_expanding_visitor(systemtap_session& s, probe_point* l,
108 : : const string& pn,
109 : : enum utrace_derived_probe_flags f):
110 : : sess (s), base_loc (l), probe_name (pn), flags (f),
111 [ + - ][ + - ]: 18 : target_symbol_seen (false), add_block(NULL), add_probe(NULL) {}
112 : :
113 : : systemtap_session& sess;
114 : : probe_point* base_loc;
115 : : string probe_name;
116 : : enum utrace_derived_probe_flags flags;
117 : : bool target_symbol_seen;
118 : : block *add_block;
119 : : probe *add_probe;
120 : : std::map<std::string, symbol *> return_ts_map;
121 : :
122 : : void visit_target_symbol_arg (target_symbol* e);
123 : : void visit_target_symbol_context (target_symbol* e);
124 : : void visit_target_symbol_cached (target_symbol* e);
125 : : void visit_target_symbol (target_symbol* e);
126 : : };
127 : :
128 : :
129 : :
130 : 18 : utrace_derived_probe::utrace_derived_probe (systemtap_session &s,
131 : : probe* p, probe_point* l,
132 : : bool hp, string &pn, int64_t pd,
133 : : enum utrace_derived_probe_flags f):
134 : : derived_probe (p, l, true /* .components soon rewritten */ ),
135 : : has_path(hp), path(pn), has_library(false), pid(pd), flags(f),
136 [ + - ][ + - ]: 18 : target_symbol_seen(false)
137 : : {
138 [ + - ]: 18 : check_process_probe_kernel_support(s);
139 : :
140 : : // Expand local variables in the probe body
141 [ + - ]: 18 : utrace_var_expanding_visitor v (s, l, name, flags);
142 [ + - ]: 18 : v.replace (this->body);
143 : 18 : target_symbol_seen = v.target_symbol_seen;
144 : :
145 : : // If during target-variable-expanding the probe, we added a new block
146 : : // of code, add it to the start of the probe.
147 [ + + ]: 18 : if (v.add_block)
148 [ + - ][ + - ]: 1 : this->body = new block(v.add_block, this->body);
149 : : // If when target-variable-expanding the probe, we added a new
150 : : // probe, add it in a new file to the list of files to be processed.
151 [ + + ]: 18 : if (v.add_probe)
152 : : {
153 [ + - ][ + - ]: 1 : stapfile *f = new stapfile;
154 [ + - ]: 1 : f->probes.push_back(v.add_probe);
155 [ + - ]: 1 : s.files.push_back(f);
156 : : }
157 : :
158 : : // Reset the sole element of the "locations" vector as a
159 : : // "reverse-engineered" form of the incoming (q.base_loc) probe
160 : : // point. This allows a user to see what program etc.
161 : : // number any particular match of the wildcards.
162 : :
163 [ + - ]: 18 : vector<probe_point::component*> comps;
164 [ + + ]: 18 : if (hp)
165 [ + - ][ + - ]: 13 : comps.push_back (new probe_point::component(TOK_PROCESS, new literal_string(path)));
[ + - ][ + - ]
[ + - ]
166 [ - + ]: 5 : else if (pid != 0)
167 [ # # ][ # # ]: 0 : comps.push_back (new probe_point::component(TOK_PROCESS, new literal_number(pid)));
[ # # ][ # # ]
[ # # ]
168 : : else
169 [ + - ][ + - ]: 5 : comps.push_back (new probe_point::component(TOK_PROCESS));
[ + - ]
170 : :
171 [ - - + + : 18 : switch (flags)
+ + - ]
172 : : {
173 : : case UDPF_THREAD_BEGIN:
174 [ # # ][ # # ]: 0 : comps.push_back (new probe_point::component(TOK_THREAD));
[ # # ]
175 [ # # ][ # # ]: 0 : comps.push_back (new probe_point::component(TOK_BEGIN));
[ # # ]
176 : 0 : break;
177 : : case UDPF_THREAD_END:
178 [ # # ][ # # ]: 0 : comps.push_back (new probe_point::component(TOK_THREAD));
[ # # ]
179 [ # # ][ # # ]: 0 : comps.push_back (new probe_point::component(TOK_END));
[ # # ]
180 : 0 : break;
181 : : case UDPF_SYSCALL:
182 [ + - ][ + - ]: 10 : comps.push_back (new probe_point::component(TOK_SYSCALL));
[ + - ]
183 : 10 : break;
184 : : case UDPF_SYSCALL_RETURN:
185 [ + - ][ + - ]: 4 : comps.push_back (new probe_point::component(TOK_SYSCALL));
[ + - ]
186 [ + - ][ + - ]: 4 : comps.push_back (new probe_point::component(TOK_RETURN));
[ + - ]
187 : 4 : break;
188 : : case UDPF_BEGIN:
189 [ + - ][ + - ]: 3 : comps.push_back (new probe_point::component(TOK_BEGIN));
[ + - ]
190 : 3 : break;
191 : : case UDPF_END:
192 [ + - ][ + - ]: 1 : comps.push_back (new probe_point::component(TOK_END));
[ + - ]
193 : 1 : break;
194 : : default:
195 : 0 : assert (0);
196 : : }
197 : :
198 : : // Overwrite it.
199 [ + - ][ + - ]: 18 : this->sole_location()->components = comps;
[ + - ][ + - ]
200 : 18 : }
201 : :
202 : :
203 : : void
204 : 18 : utrace_derived_probe::join_group (systemtap_session& s)
205 : : {
206 [ + + ]: 18 : if (! s.utrace_derived_probes)
207 : : {
208 [ + - ]: 16 : s.utrace_derived_probes = new utrace_derived_probe_group ();
209 : : }
210 : 18 : s.utrace_derived_probes->enroll (this);
211 : :
212 [ - + ]: 18 : if (s.runtime_usermode_p())
213 : 0 : enable_dynprobes(s);
214 : : else
215 : 18 : enable_task_finder(s);
216 : 18 : }
217 : :
218 : :
219 : : void
220 : 4 : utrace_derived_probe::emit_privilege_assertion (translator_output* o)
221 : : {
222 : : // Process end probes can fire for unprivileged users even if the process
223 : : // does not belong to the user. On example is that process.end will fire
224 : : // at the end of a process which executes execve on an executable which
225 : : // has the setuid bit set. When the setuid executable ends, the process.end
226 : : // will fire even though the owner of the process is different than the
227 : : // original owner.
228 : : // Unprivileged users must use check is_myproc() from within any
229 : : // process.end variant in their script before doing anything "dangerous".
230 [ - + ]: 4 : if (flags == UDPF_END)
231 : 4 : return;
232 : :
233 : : // Other process probes should only fire for unprivileged users in the
234 : : // context of processes which they own. Generate an assertion to this effect
235 : : // as a safety net.
236 : 4 : emit_process_owner_assertion (o);
237 : : }
238 : :
239 : : void
240 : 8 : utrace_derived_probe::print_dupe_stamp(ostream& o)
241 : : {
242 : : // Process end probes can fire for unprivileged users even if the process
243 : : // does not belong to the user. On example is that process.end will fire
244 : : // at the end of a process which executes execve on an executable which
245 : : // has the setuid bit set. When the setuid executable ends, the process.end
246 : : // will fire even though the owner of the process is different than the
247 : : // original owner.
248 : : // Unprivileged users must use check is_myproc() from within any
249 : : // process.end variant in their script before doing anything "dangerous".
250 : : //
251 : : // Other process probes should only fire for unprivileged users in the
252 : : // context of processes which they own.
253 [ - + ]: 8 : if (flags == UDPF_END)
254 : 0 : print_dupe_stamp_unprivileged (o);
255 : : else
256 : 8 : print_dupe_stamp_unprivileged_process_owner (o);
257 : 8 : }
258 : :
259 : : void
260 : 0 : utrace_derived_probe::getargs(std::list<std::string> &arg_set) const
261 : : {
262 [ # # ][ # # ]: 0 : arg_set.push_back("$syscall:long");
[ # # ]
263 [ # # ][ # # ]: 0 : arg_set.push_back("$arg1:long");
[ # # ]
264 [ # # ][ # # ]: 0 : arg_set.push_back("$arg2:long");
[ # # ]
265 [ # # ][ # # ]: 0 : arg_set.push_back("$arg3:long");
[ # # ]
266 [ # # ][ # # ]: 0 : arg_set.push_back("$arg4:long");
[ # # ]
267 [ # # ][ # # ]: 0 : arg_set.push_back("$arg5:long");
[ # # ]
268 [ # # ][ # # ]: 0 : arg_set.push_back("$arg6:long");
[ # # ]
269 : 0 : }
270 : :
271 : : void
272 : 1 : utrace_var_expanding_visitor::visit_target_symbol_cached (target_symbol* e)
273 : : {
274 : : // Get the full name of the target symbol.
275 [ + - ]: 1 : stringstream ts_name_stream;
276 [ + - ]: 1 : e->print(ts_name_stream);
277 [ + - ]: 1 : string ts_name = ts_name_stream.str();
278 : :
279 : : // Check and make sure we haven't already seen this target
280 : : // variable in this return probe. If we have, just return our
281 : : // last replacement.
282 [ + - ]: 1 : map<string, symbol *>::iterator i = return_ts_map.find(ts_name);
283 [ + - ][ - + ]: 1 : if (i != return_ts_map.end())
284 : : {
285 [ # # ][ # # ]: 0 : provide (i->second);
286 : : return;
287 : : }
288 : :
289 : : // We've got to do several things here to handle target
290 : : // variables in return probes.
291 : :
292 : : // (1) Synthesize a global array which is the cache of the
293 : : // target variable value. We don't need a nesting level counter
294 : : // like the dwarf_var_expanding_visitor::visit_target_symbol()
295 : : // does since a particular thread can only be in one system
296 : : // calls at a time. The array will look like this:
297 : : //
298 : : // _utrace_tvar_{name}_{num}
299 : : string aname = (string("_utrace_tvar_")
300 : : + e->sym_name()
301 [ + - ][ + - ]: 1 : + "_" + lex_cast(tick++));
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ]
302 [ + - ][ + - ]: 1 : vardecl* vd = new vardecl;
303 [ + - ]: 1 : vd->name = aname;
304 : 1 : vd->tok = e->tok;
305 [ + - ]: 1 : sess.globals.push_back (vd);
306 : :
307 : : // (2) Create a new code block we're going to insert at the
308 : : // beginning of this probe to get the cached value into a
309 : : // temporary variable. We'll replace the target variable
310 : : // reference with the temporary variable reference. The code
311 : : // will look like this:
312 : : //
313 : : // _utrace_tvar_tid = tid()
314 : : // _utrace_tvar_{name}_{num}_tmp
315 : : // = _utrace_tvar_{name}_{num}[_utrace_tvar_tid]
316 : : // delete _utrace_tvar_{name}_{num}[_utrace_tvar_tid]
317 : :
318 : : // (2a) Synthesize the tid temporary expression, which will look
319 : : // like this:
320 : : //
321 : : // _utrace_tvar_tid = tid()
322 [ + - ][ + - ]: 1 : symbol* tidsym = new symbol;
323 [ + - ][ + - ]: 1 : tidsym->name = string("_utrace_tvar_tid");
[ + - ]
324 : 1 : tidsym->tok = e->tok;
325 : :
326 [ + - ]: 1 : if (add_block == NULL)
327 : : {
328 [ + - ][ + - ]: 1 : add_block = new block;
329 : 1 : add_block->tok = e->tok;
330 : :
331 : : // Synthesize a functioncall to grab the thread id.
332 [ + - ][ + - ]: 1 : functioncall* fc = new functioncall;
333 : 1 : fc->tok = e->tok;
334 [ + - ][ + - ]: 1 : fc->function = string("tid");
[ + - ]
335 : :
336 : : // Assign the tid to '_utrace_tvar_tid'.
337 [ + - ][ + - ]: 1 : assignment* a = new assignment;
338 : 1 : a->tok = e->tok;
339 [ + - ]: 1 : a->op = "=";
340 : 1 : a->left = tidsym;
341 : 1 : a->right = fc;
342 : :
343 [ + - ][ + - ]: 1 : expr_statement* es = new expr_statement;
344 : 1 : es->tok = e->tok;
345 : 1 : es->value = a;
346 [ + - ]: 1 : add_block->statements.push_back (es);
347 : : }
348 : :
349 : : // (2b) Synthesize an array reference and assign it to a
350 : : // temporary variable (that we'll use as replacement for the
351 : : // target variable reference). It will look like this:
352 : : //
353 : : // _utrace_tvar_{name}_{num}_tmp
354 : : // = _utrace_tvar_{name}_{num}[_utrace_tvar_tid]
355 : :
356 [ + - ][ + - ]: 1 : arrayindex* ai_tvar = new arrayindex;
357 : 1 : ai_tvar->tok = e->tok;
358 : :
359 [ + - ][ + - ]: 1 : symbol* sym = new symbol;
360 [ + - ]: 1 : sym->name = aname;
361 : 1 : sym->tok = e->tok;
362 : 1 : ai_tvar->base = sym;
363 : :
364 [ + - ]: 1 : ai_tvar->indexes.push_back(tidsym);
365 : :
366 [ + - ][ + - ]: 1 : symbol* tmpsym = new symbol;
367 [ + - ][ + - ]: 1 : tmpsym->name = aname + "_tmp";
[ + - ]
368 : 1 : tmpsym->tok = e->tok;
369 : :
370 [ + - ][ + - ]: 1 : assignment* a = new assignment;
371 : 1 : a->tok = e->tok;
372 [ + - ]: 1 : a->op = "=";
373 : 1 : a->left = tmpsym;
374 : 1 : a->right = ai_tvar;
375 : :
376 [ + - ][ + - ]: 1 : expr_statement* es = new expr_statement;
377 : 1 : es->tok = e->tok;
378 : 1 : es->value = a;
379 : :
380 [ + - ]: 1 : add_block->statements.push_back (es);
381 : :
382 : : // (2c) Delete the array value. It will look like this:
383 : : //
384 : : // delete _utrace_tvar_{name}_{num}[_utrace_tvar_tid]
385 : :
386 [ + - ][ + - ]: 1 : delete_statement* ds = new delete_statement;
387 : 1 : ds->tok = e->tok;
388 : 1 : ds->value = ai_tvar;
389 [ + - ]: 1 : add_block->statements.push_back (ds);
390 : :
391 : : // (3) We need an entry probe that saves the value for us in the
392 : : // global array we created. Create the entry probe, which will
393 : : // look like this:
394 : : //
395 : : // probe process(PATH_OR_PID).syscall {
396 : : // _utrace_tvar_tid = tid()
397 : : // _utrace_tvar_{name}_{num}[_utrace_tvar_tid] = ${param}
398 : : // }
399 : : //
400 : : // Why the temporary for tid()? If we end up caching more
401 : : // than one target variable, we can reuse the temporary instead
402 : : // of calling tid() multiple times.
403 : :
404 [ + - ]: 1 : if (add_probe == NULL)
405 : : {
406 [ + - ][ + - ]: 1 : add_probe = new probe;
407 : 1 : add_probe->tok = e->tok;
408 : :
409 : : // We need the name of the current probe point, minus the
410 : : // ".return". Create a new probe point, copying all the
411 : : // components, stopping when we see the ".return"
412 : : // component.
413 [ + - ][ + - ]: 1 : probe_point* pp = new probe_point;
414 [ + - ]: 3 : for (unsigned c = 0; c < base_loc->components.size(); c++)
415 : : {
416 [ + - ][ + + ]: 3 : if (base_loc->components[c]->functor == "return")
417 : 1 : break;
418 : : else
419 [ + - ]: 2 : pp->components.push_back(base_loc->components[c]);
420 : : }
421 : 1 : pp->optional = base_loc->optional;
422 [ + - ]: 1 : add_probe->locations.push_back(pp);
423 : :
424 [ + - ][ + - ]: 1 : add_probe->body = new block;
425 : 1 : add_probe->body->tok = e->tok;
426 : :
427 : : // Synthesize a functioncall to grab the thread id.
428 [ + - ][ + - ]: 1 : functioncall* fc = new functioncall;
429 : 1 : fc->tok = e->tok;
430 [ + - ][ + - ]: 1 : fc->function = string("tid");
[ + - ]
431 : :
432 : : // Assign the tid to '_utrace_tvar_tid'.
433 [ + - ][ + - ]: 1 : assignment* a = new assignment;
434 : 1 : a->tok = e->tok;
435 [ + - ]: 1 : a->op = "=";
436 : 1 : a->left = tidsym;
437 : 1 : a->right = fc;
438 : :
439 [ + - ][ + - ]: 1 : expr_statement* es = new expr_statement;
440 : 1 : es->tok = e->tok;
441 : 1 : es->value = a;
442 [ + - ][ + - ]: 1 : add_probe->body = new block(add_probe->body, es);
443 : :
444 [ + - ][ + - ]: 1 : vardecl* vd = new vardecl;
445 : 1 : vd->tok = e->tok;
446 [ + - ]: 1 : vd->name = tidsym->name;
447 : 1 : vd->type = pe_long;
448 [ + - ]: 1 : vd->set_arity(0, e->tok);
449 [ + - ]: 1 : add_probe->locals.push_back(vd);
450 : : }
451 : :
452 : : // Save the value, like this:
453 : : //
454 : : // _utrace_tvar_{name}_{num}[_utrace_tvar_tid] = ${param}
455 [ + - ][ + - ]: 1 : a = new assignment;
456 : 1 : a->tok = e->tok;
457 [ + - ]: 1 : a->op = "=";
458 : 1 : a->left = ai_tvar;
459 : 1 : a->right = e;
460 : :
461 [ + - ][ + - ]: 1 : es = new expr_statement;
462 : 1 : es->tok = e->tok;
463 : 1 : es->value = a;
464 : :
465 [ + - ][ + - ]: 1 : add_probe->body = new block(add_probe->body, es);
466 : :
467 : : // (4) Provide the '_utrace_tvar_{name}_{num}_tmp' variable to
468 : : // our parent so it can be used as a substitute for the target
469 : : // symbol.
470 [ + - ]: 1 : provide (tmpsym);
471 : :
472 : : // (5) Remember this replacement since we might be able to reuse
473 : : // it later if the same return probe references this target
474 : : // symbol again.
475 [ + - ]: 1 : return_ts_map[ts_name] = tmpsym;
476 [ + - ][ + - ]: 1 : return;
[ + - ]
477 : : }
478 : :
479 : :
480 : : void
481 : 10 : utrace_var_expanding_visitor::visit_target_symbol_arg (target_symbol* e)
482 : : {
483 [ + + ]: 10 : if (flags != UDPF_SYSCALL)
484 [ + - ][ + - ]: 1 : throw semantic_error (_("only \"process(PATH_OR_PID).syscall\" support $argN or $$parms."), e->tok);
485 : :
486 [ - + ]: 9 : if (e->name == "$$parms")
487 : : {
488 : : // copy from tracepoint
489 [ # # ]: 0 : token* pf_tok = new token(*e->tok);
490 : 0 : pf_tok->content = "sprintf";
491 : 0 : print_format* pf = print_format::create(pf_tok);
492 : :
493 : 0 : target_symbol_seen = true;
494 : :
495 [ # # ]: 0 : for (unsigned i = 0; i < 6; ++i)
496 : : {
497 [ # # ]: 0 : if (i > 0)
498 : 0 : pf->raw_components += " ";
499 [ # # ][ # # ]: 0 : pf->raw_components += "$arg" + lex_cast(i+1);
[ # # ][ # # ]
[ # # ]
500 [ # # ]: 0 : target_symbol *tsym = new target_symbol;
501 : 0 : tsym->tok = e->tok;
502 [ # # ][ # # ]: 0 : tsym->name = "$arg" + lex_cast(i+1);
[ # # ][ # # ]
[ # # ]
503 : 0 : tsym->saved_conversion_error = 0;
504 : 0 : pf->raw_components += "=%#x"; //FIXME: missing type info
505 : :
506 [ # # ]: 0 : functioncall* n = new functioncall; //same as the following
507 : 0 : n->tok = e->tok;
508 : 0 : n->function = "_utrace_syscall_arg";
509 : 0 : n->referent = 0;
510 [ # # ]: 0 : literal_number *num = new literal_number(i);
511 : 0 : num->tok = e->tok;
512 [ # # ]: 0 : n->args.push_back(num);
513 : :
514 [ # # ]: 0 : pf->args.push_back(n);
515 : : }
516 [ # # ]: 0 : pf->components = print_format::string_to_components(pf->raw_components);
517 : :
518 : 0 : provide (pf);
519 : : }
520 : : else // $argN
521 : : {
522 [ + - ][ + - ]: 9 : string argnum_s = e->name.substr(4,e->name.length()-4);
523 : 9 : int argnum = 0;
524 : : try
525 : : {
526 [ + - ]: 9 : argnum = lex_cast<int>(argnum_s);
527 : : }
528 [ # # ]: : catch (const runtime_error& f) // non-integral $arg suffix: e.g. $argKKKSDF
529 : : {
530 [ # # # # ]: : throw semantic_error (_("invalid syscall argument number (1-6)"), e->tok);
531 : : }
532 : :
533 [ + - ][ + + ]: 9 : e->assert_no_components("utrace");
[ + - ]
534 : :
535 : : // FIXME: max argnument number should not be hardcoded.
536 [ + - ][ - + ]: 7 : if (argnum < 1 || argnum > 6)
537 [ # # ][ # # ]: 0 : throw semantic_error (_("invalid syscall argument number (1-6)"), e->tok);
538 : :
539 [ + - ]: 7 : bool lvalue = is_active_lvalue(e);
540 [ + + ]: 7 : if (lvalue)
541 [ + - ][ + - ]: 1 : throw semantic_error(_("utrace '$argN' variable is read-only"), e->tok);
542 : :
543 : : // Remember that we've seen a target variable.
544 : 6 : target_symbol_seen = true;
545 : :
546 : : // We're going to substitute a synthesized '_utrace_syscall_arg'
547 : : // function call for the '$argN' reference.
548 [ + - ][ + - ]: 6 : functioncall* n = new functioncall;
549 : 6 : n->tok = e->tok;
550 [ + - ]: 6 : n->function = "_utrace_syscall_arg";
551 : 6 : n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session
552 : :
553 [ + - ][ + - ]: 6 : literal_number *num = new literal_number(argnum - 1);
554 : 6 : num->tok = e->tok;
555 [ + - ]: 6 : n->args.push_back(num);
556 : :
557 [ + - ][ + - ]: 9 : provide (n);
558 : : }
559 : 6 : }
560 : :
561 : : void
562 : 11 : utrace_var_expanding_visitor::visit_target_symbol_context (target_symbol* e)
563 : : {
564 : 11 : const string& sname = e->name;
565 : :
566 [ + - ][ + + ]: 11 : e->assert_no_components("utrace");
[ + - ]
567 : :
568 [ + - ]: 7 : bool lvalue = is_active_lvalue(e);
569 [ + + ]: 7 : if (lvalue)
570 [ + - ][ + - ]: 2 : throw semantic_error(_F("utrace '%s' variable is read-only", sname.c_str()), e->tok);
[ + - ]
571 : :
572 [ + - ]: 5 : string fname;
573 [ + - ][ + + ]: 5 : if (sname == "$return")
574 : : {
575 [ + + ]: 2 : if (flags != UDPF_SYSCALL_RETURN)
576 [ + - ][ + - ]: 1 : throw semantic_error (_("only \"process(PATH_OR_PID).syscall.return\" support $return."), e->tok);
577 [ + - ]: 1 : fname = "_utrace_syscall_return";
578 : : }
579 [ + - ][ + - ]: 3 : else if (sname == "$syscall")
580 : : {
581 : : // If we've got a syscall entry probe, we can just call the
582 : : // right function.
583 [ + + ]: 3 : if (flags == UDPF_SYSCALL) {
584 [ + - ]: 2 : fname = "_utrace_syscall_nr";
585 : : }
586 : : // If we're in a syscal return probe, we can't really access
587 : : // $syscall. So, similar to what
588 : : // dwarf_var_expanding_visitor::visit_target_symbol() does,
589 : : // we'll create an syscall entry probe to cache $syscall, then
590 : : // we'll access the cached value in the syscall return probe.
591 : : else {
592 [ + - ]: 1 : visit_target_symbol_cached (e);
593 : :
594 : : // Remember that we've seen a target variable.
595 : 1 : target_symbol_seen = true;
596 : 4 : return;
597 : : }
598 : : }
599 : : else
600 : : {
601 [ # # ][ # # ]: 0 : throw semantic_error (_("unknown target variable"), e->tok);
602 : : }
603 : :
604 : : // Remember that we've seen a target variable.
605 : 3 : target_symbol_seen = true;
606 : :
607 : : // We're going to substitute a synthesized '_utrace_syscall_nr'
608 : : // function call for the '$syscall' reference.
609 [ + - ][ + - ]: 3 : functioncall* n = new functioncall;
610 : 3 : n->tok = e->tok;
611 [ + - ]: 3 : n->function = fname;
612 : 3 : n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session
613 : :
614 [ + - ][ + - ]: 11 : provide (n);
[ + + ]
615 : : }
616 : :
617 : : void
618 : 22 : utrace_var_expanding_visitor::visit_target_symbol (target_symbol* e)
619 : : {
620 [ + - ][ - + ]: 22 : assert(e->name.size() > 0 && e->name[0] == '$');
621 : :
622 : : try
623 : : {
624 [ + + ][ + + ]: 22 : if (flags != UDPF_SYSCALL && flags != UDPF_SYSCALL_RETURN)
625 : 1 : throw semantic_error (_("only \"process(PATH_OR_PID).syscall\""
626 : : " and \"process(PATH_OR_PID).syscall.return\" probes support target symbols"),
627 [ + - ][ + - ]: 1 : e->tok);
628 : :
629 [ - + ]: 21 : if (e->addressof)
630 [ # # ][ # # ]: 0 : throw semantic_error(_("cannot take address of utrace variable"), e->tok);
631 : :
632 [ + - ][ + + ]: 21 : if (startswith(e->name, "$arg") || e->name == "$$parms")
[ + - ][ - + ]
[ + + ]
633 [ + + ]: 10 : visit_target_symbol_arg(e);
634 [ + - ][ + + ]: 11 : else if (e->name == "$syscall" || e->name == "$return")
[ + - ][ + - ]
[ + - ]
635 [ + + ]: 11 : visit_target_symbol_context(e);
636 : : else
637 : 0 : throw semantic_error (_("invalid target symbol for utrace probe,"
638 : : " $syscall, $return, $argN or $$parms expected"),
639 [ # # ][ # # ]: 0 : e->tok);
640 : : }
641 [ - + ]: 24 : catch (const semantic_error &er)
642 : : {
643 [ - + ]: 12 : e->chain (er);
644 [ - + ]: 12 : provide(e);
645 : 22 : return;
646 : : }
647 : : }
648 : :
649 : :
650 [ # # ]: 0 : struct utrace_builder: public derived_probe_builder
651 : : {
652 : 1218 : utrace_builder() {}
653 : 19 : virtual void build(systemtap_session & sess,
654 : : probe * base,
655 : : probe_point * location,
656 : : literal_map_t const & parameters,
657 : : vector<derived_probe *> & finished_results)
658 : : {
659 [ + - ][ + - ]: 19 : string path, path_tgt;
660 : : int64_t pid;
661 : :
662 [ + - ]: 19 : bool has_path = get_param (parameters, TOK_PROCESS, path);
663 [ + - ]: 19 : bool has_pid = get_param (parameters, TOK_PROCESS, pid);
664 : 19 : enum utrace_derived_probe_flags flags = UDPF_NONE;
665 : :
666 [ + - ][ - + ]: 19 : if (has_null_param (parameters, TOK_THREAD))
667 : : {
668 [ # # ][ # # ]: 0 : if (has_null_param (parameters, TOK_BEGIN))
669 : 0 : flags = UDPF_THREAD_BEGIN;
670 [ # # ][ # # ]: 0 : else if (has_null_param (parameters, TOK_END))
671 : 0 : flags = UDPF_THREAD_END;
672 : : }
673 [ + - ][ + + ]: 19 : else if (has_null_param (parameters, TOK_SYSCALL))
674 : : {
675 [ - + ]: 14 : if (sess.runtime_usermode_p())
676 [ # # ][ # # ]: 0 : throw semantic_error (_("process.syscall probes not available with the dyninst runtime"));
677 : :
678 [ + - ][ + + ]: 14 : if (has_null_param (parameters, TOK_RETURN))
679 : 4 : flags = UDPF_SYSCALL_RETURN;
680 : : else
681 : 10 : flags = UDPF_SYSCALL;
682 : : }
683 [ + - ][ + + ]: 5 : else if (has_null_param (parameters, TOK_BEGIN))
684 : 4 : flags = UDPF_BEGIN;
685 [ + - ][ + - ]: 1 : else if (has_null_param (parameters, TOK_END))
686 : 1 : flags = UDPF_END;
687 : :
688 : : // If we didn't get a path or pid, this means to probe everything.
689 : : // Convert this to a pid-based probe.
690 [ + + ][ + + ]: 19 : if (! has_path && ! has_pid)
691 : : {
692 : 5 : has_path = false;
693 [ + - ]: 5 : path.clear();
694 : 5 : has_pid = true;
695 : 5 : pid = 0;
696 : : }
697 [ + + ]: 14 : else if (has_path)
698 : : {
699 [ + - ][ + - ]: 13 : path = find_executable (path, sess.sysroot, sess.sysenv);
[ + - ][ + - ]
[ + - ]
700 [ + - ]: 13 : sess.unwindsym_modules.insert (path);
701 [ + - ][ + - ]: 13 : path_tgt = path_remove_sysroot(sess, path);
[ + - ]
702 : : }
703 [ + - ]: 1 : else if (has_pid)
704 : : {
705 : : // We can't probe 'init' (pid 1). XXX: where does this limitation come from?
706 [ + - ]: 1 : if (pid < 2)
707 : 1 : throw semantic_error (_("process pid must be greater than 1"),
708 [ + - ][ + - ]: 1 : location->components.front()->tok);
[ + - ]
709 : :
710 : : // XXX: could we use /proc/$pid/exe in unwindsym_modules and elsewhere?
711 : : }
712 : :
713 : : finished_results.push_back(new utrace_derived_probe(sess, base, location,
714 : : has_path, path_tgt, pid,
715 [ + - ][ + - ]: 19 : flags));
[ + - ][ + - ]
[ + - ]
716 : 18 : }
717 : : };
718 : :
719 : :
720 : : void
721 : 18 : utrace_derived_probe_group::enroll (utrace_derived_probe* p)
722 : : {
723 [ + + ]: 18 : if (p->has_path)
724 : 13 : probes_by_path[p->path].push_back(p);
725 : : else
726 : 5 : probes_by_pid[p->pid].push_back(p);
727 : 18 : num_probes++;
728 : 18 : flags_seen[p->flags] = true;
729 : :
730 : : // XXX: multiple exec probes (for instance) for the same path (or
731 : : // pid) should all share a utrace report function, and have their
732 : : // handlers executed sequentially.
733 : 18 : }
734 : :
735 : :
736 : : void
737 : 4 : utrace_derived_probe_group::emit_linux_probe_decl (systemtap_session& s,
738 : : utrace_derived_probe *p)
739 : : {
740 : 4 : s.op->newline() << "{";
741 : 4 : s.op->line() << " .tgt={";
742 : 4 : s.op->line() << " .purpose=\"lifecycle tracking\",";
743 [ - + ]: 4 : if (p->has_path)
744 : : {
745 : 0 : s.op->line() << " .procname=\"" << p->path << "\",";
746 : 0 : s.op->line() << " .pid=0,";
747 : : }
748 : : else
749 : : {
750 : 4 : s.op->line() << " .procname=NULL,";
751 : 4 : s.op->line() << " .pid=" << p->pid << ",";
752 : : }
753 : :
754 : 4 : s.op->line() << " .callback=&_stp_utrace_probe_cb,";
755 : 4 : s.op->line() << " .mmap_callback=NULL,";
756 : 4 : s.op->line() << " .munmap_callback=NULL,";
757 : 4 : s.op->line() << " .mprotect_callback=NULL,";
758 : 4 : s.op->line() << " },";
759 [ + - ][ + - ]: 4 : s.op->line() << " .probe=" << common_probe_init (p) << ",";
760 : :
761 : : // Handle flags
762 [ + - - - : 4 : switch (p->flags)
+ + - - ]
763 : : {
764 : : // Notice that we'll just call the probe directly when we get
765 : : // notified, since the task_finder layer stops the thread for us.
766 : : case UDPF_BEGIN: // process begin
767 : 1 : s.op->line() << " .flags=(UDPF_BEGIN),";
768 : 1 : break;
769 : : case UDPF_THREAD_BEGIN: // thread begin
770 : 0 : s.op->line() << " .flags=(UDPF_THREAD_BEGIN),";
771 : 0 : break;
772 : :
773 : : // Notice we're not setting up a .ops/.report_death handler for
774 : : // either UDPF_END or UDPF_THREAD_END. Instead, we'll just call
775 : : // the probe directly when we get notified.
776 : : case UDPF_END: // process end
777 : 0 : s.op->line() << " .flags=(UDPF_END),";
778 : 0 : break;
779 : : case UDPF_THREAD_END: // thread end
780 : 0 : s.op->line() << " .flags=(UDPF_THREAD_END),";
781 : 0 : break;
782 : :
783 : : // For UDPF_SYSCALL/UDPF_SYSCALL_RETURN probes, the .report_death
784 : : // handler isn't strictly necessary. However, it helps to keep
785 : : // our attaches/detaches symmetrical. Since the task_finder layer
786 : : // stops the thread, that works around bug 6841.
787 : : case UDPF_SYSCALL:
788 : 2 : s.op->line() << " .flags=(UDPF_SYSCALL),";
789 : 2 : s.op->line() << " .ops={ .report_syscall_entry=stap_utrace_probe_syscall, .report_death=stap_utrace_task_finder_report_death },";
790 : 2 : s.op->line() << " .events=(UTRACE_EVENT(SYSCALL_ENTRY)|UTRACE_EVENT(DEATH)),";
791 : 2 : break;
792 : : case UDPF_SYSCALL_RETURN:
793 : 1 : s.op->line() << " .flags=(UDPF_SYSCALL_RETURN),";
794 : 1 : s.op->line() << " .ops={ .report_syscall_exit=stap_utrace_probe_syscall, .report_death=stap_utrace_task_finder_report_death },";
795 : 1 : s.op->line() << " .events=(UTRACE_EVENT(SYSCALL_EXIT)|UTRACE_EVENT(DEATH)),";
796 : 1 : break;
797 : :
798 : : case UDPF_NONE:
799 : 0 : s.op->line() << " .flags=(UDPF_NONE),";
800 : 0 : s.op->line() << " .ops={ },";
801 : 0 : s.op->line() << " .events=0,";
802 : 0 : break;
803 : : default:
804 [ # # ][ # # ]: 0 : throw semantic_error ("bad utrace probe flag");
805 : : break;
806 : : }
807 : 4 : s.op->line() << " .engine_attached=0,";
808 : 4 : s.op->line() << " },";
809 : 4 : }
810 : :
811 : :
812 : : void
813 : 2 : utrace_derived_probe_group::emit_module_linux_decls (systemtap_session& s)
814 : : {
815 [ + - ][ - + ]: 2 : if (probes_by_path.empty() && probes_by_pid.empty())
[ - + ]
816 : 2 : return;
817 : :
818 : 2 : s.op->newline();
819 : 2 : s.op->newline() << "/* ---- utrace probes ---- */";
820 : :
821 : 2 : s.op->newline() << "enum utrace_derived_probe_flags {";
822 : 2 : s.op->indent(1);
823 : 2 : s.op->newline() << "UDPF_NONE,";
824 : 2 : s.op->newline() << "UDPF_BEGIN,";
825 : 2 : s.op->newline() << "UDPF_END,";
826 : 2 : s.op->newline() << "UDPF_THREAD_BEGIN,";
827 : 2 : s.op->newline() << "UDPF_THREAD_END,";
828 : 2 : s.op->newline() << "UDPF_SYSCALL,";
829 : 2 : s.op->newline() << "UDPF_SYSCALL_RETURN,";
830 : 2 : s.op->newline() << "UDPF_NFLAGS";
831 : 2 : s.op->newline(-1) << "};";
832 : :
833 : 2 : s.op->newline() << "struct stap_utrace_probe {";
834 : 2 : s.op->indent(1);
835 : 2 : s.op->newline() << "struct stap_task_finder_target tgt;";
836 : 2 : s.op->newline() << "const struct stap_probe * const probe;";
837 : 2 : s.op->newline() << "int engine_attached;";
838 : 2 : s.op->newline() << "enum utrace_derived_probe_flags flags;";
839 : 2 : s.op->newline() << "struct utrace_engine_ops ops;";
840 : 2 : s.op->newline() << "unsigned long events;";
841 : 2 : s.op->newline(-1) << "};";
842 : :
843 : :
844 : : // Output handler function for UDPF_BEGIN, UDPF_THREAD_BEGIN,
845 : : // UDPF_END, and UDPF_THREAD_END
846 [ + + ][ + - ]: 2 : if (flags_seen[UDPF_BEGIN] || flags_seen[UDPF_THREAD_BEGIN]
[ + - ][ - + ]
847 : 2 : || flags_seen[UDPF_END] || flags_seen[UDPF_THREAD_END])
848 : : {
849 : 1 : s.op->newline() << "static void stap_utrace_probe_handler(struct task_struct *tsk, struct stap_utrace_probe *p) {";
850 : 1 : s.op->indent(1);
851 : :
852 : : common_probe_entryfn_prologue (s, "STAP_SESSION_RUNNING", "p->probe",
853 [ + - ][ + - ]: 1 : "stp_probe_type_utrace");
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ]
854 : :
855 : : // call probe function
856 : 1 : s.op->newline() << "(*p->probe->ph) (c);";
857 : 1 : common_probe_entryfn_epilogue (s, true);
858 : :
859 : 1 : s.op->newline() << "return;";
860 : 1 : s.op->newline(-1) << "}";
861 : : }
862 : :
863 : : // Output handler function for SYSCALL_ENTRY and SYSCALL_EXIT events
864 [ + + ][ - + ]: 2 : if (flags_seen[UDPF_SYSCALL] || flags_seen[UDPF_SYSCALL_RETURN])
865 : : {
866 : 1 : s.op->newline() << "#ifdef UTRACE_ORIG_VERSION";
867 : 1 : s.op->newline() << "static u32 stap_utrace_probe_syscall(struct utrace_engine *engine, struct task_struct *tsk, struct pt_regs *regs) {";
868 : 1 : s.op->newline() << "#else";
869 : 1 : s.op->newline() << "#if defined(UTRACE_API_VERSION) && (UTRACE_API_VERSION >= 20091216)";
870 : 1 : s.op->newline() << "static u32 stap_utrace_probe_syscall(u32 action, struct utrace_engine *engine, struct pt_regs *regs) {";
871 : 1 : s.op->newline() << "#else";
872 : 1 : s.op->newline() << "static u32 stap_utrace_probe_syscall(enum utrace_resume_action action, struct utrace_engine *engine, struct task_struct *tsk, struct pt_regs *regs) {";
873 : 1 : s.op->newline() << "#endif";
874 : 1 : s.op->newline() << "#endif";
875 : :
876 : 1 : s.op->indent(1);
877 : 1 : s.op->newline() << "struct stap_utrace_probe *p = (struct stap_utrace_probe *)engine->data;";
878 : :
879 : : common_probe_entryfn_prologue (s, "STAP_SESSION_RUNNING", "p->probe",
880 [ + - ][ + - ]: 1 : "stp_probe_type_utrace_syscall");
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ]
881 : 1 : s.op->newline() << "c->uregs = regs;";
882 : 1 : s.op->newline() << "c->user_mode_p = 1;";
883 : :
884 : : // call probe function
885 : 1 : s.op->newline() << "(*p->probe->ph) (c);";
886 : 1 : common_probe_entryfn_epilogue (s, true);
887 : :
888 : 1 : s.op->newline() << "if ((atomic_read (session_state()) != STAP_SESSION_STARTING) && (atomic_read (session_state()) != STAP_SESSION_RUNNING)) {";
889 : 1 : s.op->indent(1);
890 : 1 : s.op->newline() << "debug_task_finder_detach();";
891 : 1 : s.op->newline() << "return UTRACE_DETACH;";
892 : 1 : s.op->newline(-1) << "}";
893 : 1 : s.op->newline() << "return UTRACE_RESUME;";
894 : 1 : s.op->newline(-1) << "}";
895 : : }
896 : :
897 : : // Output task_finder callback routine that gets called for all
898 : : // utrace probe types.
899 : 2 : s.op->newline() << "static int _stp_utrace_probe_cb(struct stap_task_finder_target *tgt, struct task_struct *tsk, int register_p, int process_p) {";
900 : 2 : s.op->indent(1);
901 : 2 : s.op->newline() << "int rc = 0;";
902 : 2 : s.op->newline() << "struct stap_utrace_probe *p = container_of(tgt, struct stap_utrace_probe, tgt);";
903 : 2 : s.op->newline() << "struct utrace_engine *engine;";
904 : :
905 : 2 : s.op->newline() << "if (register_p) {";
906 : 2 : s.op->indent(1);
907 : :
908 : 2 : s.op->newline() << "switch (p->flags) {";
909 : 2 : s.op->indent(1);
910 : :
911 : : // When receiving a UTRACE_EVENT(CLONE) event, we can't call the
912 : : // begin/thread.begin probe directly. So, we'll just attach an
913 : : // engine that waits for the thread to quiesce. When the thread
914 : : // quiesces, then call the probe.
915 [ + + ]: 2 : if (flags_seen[UDPF_BEGIN])
916 : : {
917 : 1 : s.op->newline() << "case UDPF_BEGIN:";
918 : 1 : s.op->indent(1);
919 : 1 : s.op->newline() << "if (process_p) {";
920 : 1 : s.op->indent(1);
921 : 1 : s.op->newline() << "stap_utrace_probe_handler(tsk, p);";
922 : 1 : s.op->newline(-1) << "}";
923 : 1 : s.op->newline() << "break;";
924 : 1 : s.op->indent(-1);
925 : : }
926 [ - + ]: 2 : if (flags_seen[UDPF_THREAD_BEGIN])
927 : : {
928 : 0 : s.op->newline() << "case UDPF_THREAD_BEGIN:";
929 : 0 : s.op->indent(1);
930 : 0 : s.op->newline() << "if (! process_p) {";
931 : 0 : s.op->indent(1);
932 : 0 : s.op->newline() << "stap_utrace_probe_handler(tsk, p);";
933 : 0 : s.op->newline(-1) << "}";
934 : 0 : s.op->newline() << "break;";
935 : 0 : s.op->indent(-1);
936 : : }
937 : :
938 : : // For end/thread_end probes, do nothing at registration time.
939 : : // We'll handle these in the 'register_p == 0' case.
940 [ + - ][ - + ]: 2 : if (flags_seen[UDPF_END] || flags_seen[UDPF_THREAD_END])
941 : : {
942 : 0 : s.op->newline() << "case UDPF_END:";
943 : 0 : s.op->newline() << "case UDPF_THREAD_END:";
944 : 0 : s.op->indent(1);
945 : 0 : s.op->newline() << "break;";
946 : 0 : s.op->indent(-1);
947 : : }
948 : :
949 : : // Attach an engine for SYSCALL_ENTRY and SYSCALL_EXIT events.
950 [ + + ][ - + ]: 2 : if (flags_seen[UDPF_SYSCALL] || flags_seen[UDPF_SYSCALL_RETURN])
951 : : {
952 : 1 : s.op->newline() << "case UDPF_SYSCALL:";
953 : 1 : s.op->newline() << "case UDPF_SYSCALL_RETURN:";
954 : 1 : s.op->indent(1);
955 : 1 : s.op->newline() << "rc = stap_utrace_attach(tsk, &p->ops, p, p->events);";
956 : 1 : s.op->newline() << "if (rc == 0) {";
957 : 1 : s.op->indent(1);
958 : 1 : s.op->newline() << "p->engine_attached = 1;";
959 : 1 : s.op->newline(-1) << "}";
960 : 1 : s.op->newline() << "break;";
961 : 1 : s.op->indent(-1);
962 : : }
963 : :
964 : 2 : s.op->newline() << "default:";
965 : 2 : s.op->indent(1);
966 : 2 : s.op->newline() << "_stp_error(\"unhandled flag value %d at %s:%d\", p->flags, __FUNCTION__, __LINE__);";
967 : 2 : s.op->newline() << "break;";
968 : 2 : s.op->indent(-1);
969 : 2 : s.op->newline(-1) << "}";
970 : 2 : s.op->newline(-1) << "}";
971 : :
972 : : // Since this engine could be attached to multiple threads, don't
973 : : // call stap_utrace_detach_ops() here, only call
974 : : // stap_utrace_detach() as necessary.
975 : 2 : s.op->newline() << "else {";
976 : 2 : s.op->indent(1);
977 : 2 : s.op->newline() << "switch (p->flags) {";
978 : 2 : s.op->indent(1);
979 : : // For end probes, go ahead and call the probe directly.
980 [ - + ]: 2 : if (flags_seen[UDPF_END])
981 : : {
982 : 0 : s.op->newline() << "case UDPF_END:";
983 : 0 : s.op->indent(1);
984 : 0 : s.op->newline() << "if (process_p) {";
985 : 0 : s.op->indent(1);
986 : 0 : s.op->newline() << "stap_utrace_probe_handler(tsk, p);";
987 : 0 : s.op->newline(-1) << "}";
988 : 0 : s.op->newline() << "break;";
989 : 0 : s.op->indent(-1);
990 : : }
991 [ - + ]: 2 : if (flags_seen[UDPF_THREAD_END])
992 : : {
993 : 0 : s.op->newline() << "case UDPF_THREAD_END:";
994 : 0 : s.op->indent(1);
995 : 0 : s.op->newline() << "if (! process_p) {";
996 : 0 : s.op->indent(1);
997 : 0 : s.op->newline() << "stap_utrace_probe_handler(tsk, p);";
998 : 0 : s.op->newline(-1) << "}";
999 : 0 : s.op->newline() << "break;";
1000 : 0 : s.op->indent(-1);
1001 : : }
1002 : :
1003 : : // For begin/thread_begin probes, we don't need to do anything.
1004 [ + + ][ - + ]: 2 : if (flags_seen[UDPF_BEGIN] || flags_seen[UDPF_THREAD_BEGIN])
1005 : : {
1006 : 1 : s.op->newline() << "case UDPF_BEGIN:";
1007 : 1 : s.op->newline() << "case UDPF_THREAD_BEGIN:";
1008 : 1 : s.op->indent(1);
1009 : 1 : s.op->newline() << "break;";
1010 : 1 : s.op->indent(-1);
1011 : : }
1012 : :
1013 [ + + ][ - + ]: 2 : if (flags_seen[UDPF_SYSCALL] || flags_seen[UDPF_SYSCALL_RETURN])
1014 : : {
1015 : 1 : s.op->newline() << "case UDPF_SYSCALL:";
1016 : 1 : s.op->newline() << "case UDPF_SYSCALL_RETURN:";
1017 : 1 : s.op->indent(1);
1018 : 1 : s.op->newline() << "stap_utrace_detach(tsk, &p->ops);";
1019 : 1 : s.op->newline() << "break;";
1020 : 1 : s.op->indent(-1);
1021 : : }
1022 : :
1023 : 2 : s.op->newline() << "default:";
1024 : 2 : s.op->indent(1);
1025 : 2 : s.op->newline() << "_stp_error(\"unhandled flag value %d at %s:%d\", p->flags, __FUNCTION__, __LINE__);";
1026 : 2 : s.op->newline() << "break;";
1027 : 2 : s.op->indent(-1);
1028 : 2 : s.op->newline(-1) << "}";
1029 : 2 : s.op->newline(-1) << "}";
1030 : 2 : s.op->newline() << "return rc;";
1031 : 2 : s.op->newline(-1) << "}";
1032 : :
1033 : 2 : s.op->newline() << "static struct stap_utrace_probe stap_utrace_probes[] = {";
1034 : 2 : s.op->indent(1);
1035 : :
1036 : : // Set up 'process(PATH)' probes
1037 [ - + ]: 2 : if (! probes_by_path.empty())
1038 : : {
1039 [ # # ][ # # ]: 0 : for (p_b_path_iterator it = probes_by_path.begin();
1040 [ # # ]: 0 : it != probes_by_path.end(); it++)
1041 : : {
1042 [ # # ][ # # ]: 0 : for (unsigned i = 0; i < it->second.size(); i++)
1043 : : {
1044 [ # # ]: 0 : utrace_derived_probe *p = it->second[i];
1045 [ # # ]: 0 : emit_linux_probe_decl(s, p);
1046 : : }
1047 : : }
1048 : : }
1049 : :
1050 : : // Set up 'process(PID)' probes
1051 [ + - ]: 2 : if (! probes_by_pid.empty())
1052 : : {
1053 [ + - ][ + + ]: 8 : for (p_b_pid_iterator it = probes_by_pid.begin();
1054 [ + - ]: 4 : it != probes_by_pid.end(); it++)
1055 : : {
1056 [ + - ][ + + ]: 6 : for (unsigned i = 0; i < it->second.size(); i++)
1057 : : {
1058 [ + - ]: 4 : utrace_derived_probe *p = it->second[i];
1059 [ + - ]: 4 : emit_linux_probe_decl(s, p);
1060 : : }
1061 : : }
1062 : : }
1063 : 2 : s.op->newline(-1) << "};";
1064 : : }
1065 : :
1066 : :
1067 : : void
1068 : 0 : utrace_derived_probe_group::emit_dyninst_probe_decl (systemtap_session& s,
1069 : : const string& path,
1070 : : utrace_derived_probe *p)
1071 : : {
1072 [ # # ]: 0 : string flags_str;
1073 : :
1074 : : // Handle flags
1075 [ # # # # : 0 : switch (p->flags)
# ]
1076 : : {
1077 : : case UDPF_BEGIN: // process begin
1078 [ # # ]: 0 : flags_str = "STAPDYN_PROBE_FLAG_PROC_BEGIN";
1079 : 0 : break;
1080 : : case UDPF_THREAD_BEGIN: // thread begin
1081 [ # # ]: 0 : flags_str = "STAPDYN_PROBE_FLAG_THREAD_BEGIN";
1082 : 0 : break;
1083 : : case UDPF_END: // process end
1084 [ # # ]: 0 : flags_str = "STAPDYN_PROBE_FLAG_PROC_END";
1085 : 0 : break;
1086 : : case UDPF_THREAD_END: // thread end
1087 [ # # ]: 0 : flags_str = "STAPDYN_PROBE_FLAG_THREAD_END";
1088 : 0 : break;
1089 : :
1090 : : // FIXME: No handling of syscall probes for dyninst yet.
1091 : : #if 0
1092 : : case UDPF_SYSCALL:
1093 : : break;
1094 : : case UDPF_SYSCALL_RETURN:
1095 : : break;
1096 : :
1097 : : case UDPF_NONE:
1098 : : s.op->line() << " .flags=(UDPF_NONE),";
1099 : : s.op->line() << " .ops={ },";
1100 : : s.op->line() << " .events=0,";
1101 : : break;
1102 : : #endif
1103 : : default:
1104 [ # # ][ # # ]: 0 : throw semantic_error ("bad utrace probe flag");
1105 : : break;
1106 : : }
1107 : :
1108 [ # # ]: 0 : if (p->has_path)
1109 [ # # ][ # # ]: 0 : dynprobe_add_utrace_path(s, path, flags_str, common_probe_init(p));
[ # # ][ # # ]
[ # # ]
1110 : : else
1111 [ # # ][ # # ]: 0 : dynprobe_add_utrace_pid(s, p->pid, flags_str, common_probe_init(p));
[ # # ][ # # ]
[ # # ][ # # ]
1112 : 0 : }
1113 : :
1114 : : void
1115 : 0 : utrace_derived_probe_group::emit_module_dyninst_decls (systemtap_session& s)
1116 : : {
1117 [ # # ][ # # ]: 0 : if (probes_by_path.empty() && probes_by_pid.empty())
[ # # ]
1118 : 0 : return;
1119 : :
1120 : 0 : s.op->newline();
1121 : 0 : s.op->newline() << "/* ---- dyninst utrace probes ---- */";
1122 : 0 : s.op->newline() << "#include \"dyninst/uprobes.h\"";
1123 : 0 : s.op->newline() << "#define STAPDYN_UTRACE_PROBES";
1124 : :
1125 : : // Let the dynprobe_derived_probe_group handle outputting targets
1126 : : // and probes. This allows us to merge different types of probes.
1127 : 0 : s.op->newline() << "static struct stapdu_probe stapdu_probes[];";
1128 : :
1129 : : // Set up 'process(PATH)' probes
1130 [ # # ]: 0 : if (! probes_by_path.empty())
1131 : : {
1132 [ # # ][ # # ]: 0 : for (p_b_path_iterator it = probes_by_path.begin();
1133 [ # # ]: 0 : it != probes_by_path.end(); it++)
1134 : : {
1135 [ # # ][ # # ]: 0 : for (unsigned i = 0; i < it->second.size(); i++)
1136 : : {
1137 [ # # ]: 0 : utrace_derived_probe *p = it->second[i];
1138 [ # # ][ # # ]: 0 : emit_dyninst_probe_decl(s, it->first, p);
1139 : : }
1140 : : }
1141 : : }
1142 : : // Set up 'process(PID)' probes
1143 [ # # ]: 0 : if (! probes_by_pid.empty())
1144 : : {
1145 [ # # ][ # # ]: 0 : for (p_b_pid_iterator it = probes_by_pid.begin();
1146 [ # # ]: 0 : it != probes_by_pid.end(); it++)
1147 : : {
1148 [ # # ][ # # ]: 0 : for (unsigned i = 0; i < it->second.size(); i++)
1149 : : {
1150 [ # # ]: 0 : utrace_derived_probe *p = it->second[i];
1151 [ # # ][ # # ]: 0 : emit_dyninst_probe_decl(s, "", p);
[ # # ]
1152 : : }
1153 : : }
1154 : : }
1155 : :
1156 : : // loc2c-generated code assumes pt_regs are available, so use this to make
1157 : : // sure we always have *something* for it to dereference...
1158 : 0 : s.op->newline() << "static struct pt_regs stapdu_dummy_uregs;";
1159 : :
1160 : : // Write the probe handler.
1161 : : // NB: not static, so dyninst can find it
1162 : 0 : s.op->newline() << "int enter_dyninst_utrace_probe "
1163 : 0 : << "(uint64_t index, struct pt_regs *regs) {";
1164 : 0 : s.op->newline(1) << "struct stapdu_probe *sup = &stapdu_probes[index];";
1165 : :
1166 : : common_probe_entryfn_prologue (s, "STAP_SESSION_RUNNING", "sup->probe",
1167 [ # # ][ # # ]: 0 : "stp_probe_type_utrace");
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
1168 : 0 : s.op->newline() << "c->uregs = regs ?: &stapdu_dummy_uregs;";
1169 : 0 : s.op->newline() << "c->user_mode_p = 1;";
1170 : : // XXX: once we have regs, check how dyninst sets the IP
1171 : : // XXX: the way that dyninst rewrites stuff is probably going to be
1172 : : // ... very confusing to our backtracer (at least if we stay in process)
1173 : 0 : s.op->newline() << "(*sup->probe->ph) (c);";
1174 : 0 : common_probe_entryfn_epilogue (s, true);
1175 : 0 : s.op->newline() << "return 0;";
1176 : 0 : s.op->newline(-1) << "}";
1177 : 0 : s.op->assert_0_indent();
1178 : : }
1179 : :
1180 : :
1181 : : void
1182 : 2 : utrace_derived_probe_group::emit_module_decls (systemtap_session& s)
1183 : : {
1184 [ - + ]: 2 : if (s.runtime_usermode_p())
1185 : 0 : emit_module_dyninst_decls (s);
1186 : : else
1187 : 2 : emit_module_linux_decls (s);
1188 : 2 : }
1189 : :
1190 : :
1191 : : void
1192 : 2 : utrace_derived_probe_group::emit_module_linux_init (systemtap_session& s)
1193 : : {
1194 [ + - ][ - + ]: 2 : if (probes_by_path.empty() && probes_by_pid.empty())
[ - + ]
1195 : 2 : return;
1196 : :
1197 : 2 : s.op->newline() << "/* ---- utrace probes ---- */";
1198 : 2 : s.op->newline() << "for (i=0; i<ARRAY_SIZE(stap_utrace_probes); i++) {";
1199 : 2 : s.op->newline(1) << "struct stap_utrace_probe *p = &stap_utrace_probes[i];";
1200 : 2 : s.op->newline() << "probe_point = p->probe->pp;"; // for error messages
1201 : 2 : s.op->newline() << "rc = stap_register_task_finder_target(&p->tgt);";
1202 : :
1203 : : // NB: if (rc), there is no need (XXX: nor any way) to clean up any
1204 : : // finders already registered, since mere registration does not
1205 : : // cause any utrace or memory allocation actions. That happens only
1206 : : // later, once the task finder engine starts running. So, for a
1207 : : // partial initialization requiring unwind, we need do nothing.
1208 : 2 : s.op->newline() << "if (rc) break;";
1209 : :
1210 : 2 : s.op->newline(-1) << "}";
1211 : : }
1212 : :
1213 : :
1214 : : void
1215 : 0 : utrace_derived_probe_group::emit_module_dyninst_init (systemtap_session& s)
1216 : : {
1217 [ # # ][ # # ]: 0 : if (probes_by_path.empty() && probes_by_pid.empty())
[ # # ]
1218 : 0 : return;
1219 : :
1220 : : /* stapdyn handles the dirty work via dyninst */
1221 : 0 : s.op->newline() << "/* ---- dyninst utrace probes ---- */";
1222 : 0 : s.op->newline() << "/* this section left intentionally blank */";
1223 : : }
1224 : :
1225 : :
1226 : : void
1227 : 2 : utrace_derived_probe_group::emit_module_init (systemtap_session& s)
1228 : : {
1229 [ - + ]: 2 : if (s.runtime_usermode_p())
1230 : 0 : emit_module_dyninst_init (s);
1231 : : else
1232 : 2 : emit_module_linux_init(s);
1233 : 2 : }
1234 : :
1235 : :
1236 : : void
1237 : 4 : utrace_derived_probe_group::emit_module_linux_exit (systemtap_session& s)
1238 : : {
1239 [ + - ][ - + ]: 8 : if (probes_by_path.empty() && probes_by_pid.empty()) return;
[ - + ]
1240 : :
1241 : 4 : s.op->newline();
1242 : 4 : s.op->newline() << "/* ---- utrace probes ---- */";
1243 : 4 : s.op->newline() << "for (i=0; i<ARRAY_SIZE(stap_utrace_probes); i++) {";
1244 : 4 : s.op->newline(1) << "struct stap_utrace_probe *p = &stap_utrace_probes[i];";
1245 : :
1246 : 4 : s.op->newline() << "if (p->engine_attached) {";
1247 : 4 : s.op->newline(1) << "stap_utrace_detach_ops(&p->ops);";
1248 : :
1249 : 4 : s.op->newline(-1) << "}";
1250 : 4 : s.op->newline(-1) << "}";
1251 : : }
1252 : :
1253 : :
1254 : : void
1255 : 0 : utrace_derived_probe_group::emit_module_dyninst_exit (systemtap_session& s)
1256 : : {
1257 [ # # ][ # # ]: 0 : if (probes_by_path.empty() && probes_by_pid.empty())
[ # # ]
1258 : 0 : return;
1259 : :
1260 : : /* stapdyn handles the dirty work via dyninst */
1261 : 0 : s.op->newline() << "/* ---- dyninst utrace probes ---- */";
1262 : 0 : s.op->newline() << "/* this section left intentionally blank */";
1263 : : }
1264 : :
1265 : :
1266 : : void
1267 : 4 : utrace_derived_probe_group::emit_module_exit (systemtap_session& s)
1268 : : {
1269 [ - + ]: 4 : if (s.runtime_usermode_p())
1270 : 0 : emit_module_dyninst_exit (s);
1271 : : else
1272 : 4 : emit_module_linux_exit(s);
1273 : 4 : }
1274 : :
1275 : :
1276 : : void
1277 : 1218 : register_tapset_utrace(systemtap_session& s)
1278 : : {
1279 : 1218 : match_node* root = s.pattern_root;
1280 [ + - ]: 1218 : derived_probe_builder *builder = new utrace_builder();
1281 : :
1282 [ + - ]: 1218 : vector<match_node*> roots;
1283 [ + - ][ + - ]: 1218 : roots.push_back(root->bind(TOK_PROCESS));
1284 [ + - ][ + - ]: 1218 : roots.push_back(root->bind_str(TOK_PROCESS));
1285 [ + - ][ + - ]: 1218 : roots.push_back(root->bind_num(TOK_PROCESS));
1286 : :
1287 [ + + ]: 4872 : for (unsigned i = 0; i < roots.size(); ++i)
1288 : : {
1289 : 3654 : roots[i]->bind(TOK_BEGIN)
1290 : : ->bind_privilege(pr_all)
1291 [ + - ][ + - ]: 3654 : ->bind(builder);
[ + - ]
1292 : 3654 : roots[i]->bind(TOK_END)
1293 : : ->bind_privilege(pr_all)
1294 [ + - ][ + - ]: 3654 : ->bind(builder);
[ + - ]
1295 : 3654 : roots[i]->bind(TOK_THREAD)->bind(TOK_BEGIN)
1296 : : ->bind_privilege(pr_all)
1297 [ + - ][ + - ]: 3654 : ->bind(builder);
[ + - ][ + - ]
1298 : 3654 : roots[i]->bind(TOK_THREAD)->bind(TOK_END)
1299 : : ->bind_privilege(pr_all)
1300 [ + - ][ + - ]: 3654 : ->bind(builder);
[ + - ][ + - ]
1301 : 3654 : roots[i]->bind(TOK_SYSCALL)
1302 : : ->bind_privilege(pr_all)
1303 [ + - ][ + - ]: 3654 : ->bind(builder);
[ + - ]
1304 : 3654 : roots[i]->bind(TOK_SYSCALL)->bind(TOK_RETURN)
1305 : : ->bind_privilege(pr_all)
1306 [ + - ][ + - ]: 3654 : ->bind(builder);
[ + - ][ + - ]
1307 [ + - ]: 1218 : }
1308 [ + - ][ + - ]: 8460 : }
1309 : :
1310 : : /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
|