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