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