]> sourceware.org Git - systemtap.git/blob - tapset-utrace.cxx
2b644843ae64532b048e7283a3bb92957497f180
[systemtap.git] / tapset-utrace.cxx
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
104
105 struct utrace_var_expanding_visitor: public var_expanding_visitor
106 {
107 utrace_var_expanding_visitor(systemtap_session& s, probe_point* l,
108 enum utrace_derived_probe_flags f):
109 var_expanding_visitor (s),
110 base_loc (l), flags (f),
111 target_symbol_seen (false), add_block(NULL), add_probe(NULL) {}
112
113 probe_point* base_loc;
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,
130 bool hp, interned_string pn, int64_t pd,
131 enum utrace_derived_probe_flags f):
132 derived_probe (p, l, true /* .components soon rewritten */ ),
133 has_path(hp), path(pn), has_library(false), pid(pd), flags(f),
134 target_symbol_seen(false)
135 {
136 if (!s.runtime_usermode_p())
137 check_process_probe_kernel_support(s);
138
139 // Expand local variables in the probe body
140 utrace_var_expanding_visitor v (s, l, flags);
141 var_expand_const_fold_loop (s, this->body, v);
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);
210 this->group = s.utrace_derived_probes;
211
212 if (s.runtime_usermode_p())
213 enable_dynprobes(s);
214 else
215 enable_task_finder(s);
216 }
217
218
219 void
220 utrace_derived_probe::emit_privilege_assertion (translator_output* o)
221 {
222 // Process end probes can fire for unprivileged users even if the process
223 // does not belong to the user. On example is that process.end will fire
224 // at the end of a process which executes execve on an executable which
225 // has the setuid bit set. When the setuid executable ends, the process.end
226 // will fire even though the owner of the process is different than the
227 // original owner.
228 // Unprivileged users must use check is_myproc() from within any
229 // process.end variant in their script before doing anything "dangerous".
230 if (flags == UDPF_END)
231 return;
232
233 // Other process probes should only fire for unprivileged users in the
234 // context of processes which they own. Generate an assertion to this effect
235 // as a safety net.
236 emit_process_owner_assertion (o);
237 }
238
239 void
240 utrace_derived_probe::print_dupe_stamp(ostream& o)
241 {
242 // Process end probes can fire for unprivileged users even if the process
243 // does not belong to the user. On example is that process.end will fire
244 // at the end of a process which executes execve on an executable which
245 // has the setuid bit set. When the setuid executable ends, the process.end
246 // will fire even though the owner of the process is different than the
247 // original owner.
248 // Unprivileged users must use check is_myproc() from within any
249 // process.end variant in their script before doing anything "dangerous".
250 //
251 // Other process probes should only fire for unprivileged users in the
252 // context of processes which they own.
253 if (flags == UDPF_END)
254 print_dupe_stamp_unprivileged (o);
255 else
256 print_dupe_stamp_unprivileged_process_owner (o);
257 }
258
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 }
270
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}
299 string aname = (string("__global_utrace_tvar_")
300 + e->sym_name()
301 + "_" + lex_cast(tick++));
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 }
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;
446 vd->name = tidsym->name;
447 vd->type = pe_long;
448 vd->set_arity(0, e->tok);
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 {
483 if (flags != UDPF_SYSCALL)
484 throw SEMANTIC_ERROR (_("only \"process(PATH_OR_PID).syscall\" support $argN or $$parms."), e->tok);
485
486 if (e->name == "$$parms")
487 {
488 // copy from tracepoint
489 print_format* pf = print_format::create(e->tok, "sprintf");
490
491 target_symbol_seen = true;
492
493 for (unsigned i = 0; i < 6; ++i)
494 {
495 if (i > 0)
496 pf->raw_components += " ";
497 pf->raw_components += "$arg" + lex_cast(i+1);
498 target_symbol *tsym = new target_symbol;
499 tsym->tok = e->tok;
500 tsym->name = "$arg" + lex_cast(i+1);
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";
507 n->referents.clear();
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);
517 }
518 else // $argN
519 {
520 string argnum_s = (string)e->name.substr(4,e->name.length()-4);
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 {
528 throw SEMANTIC_ERROR (_("invalid syscall argument number (1-6)"), e->tok);
529 }
530
531 e->assert_no_components("utrace");
532
533 // FIXME: max argnument number should not be hardcoded.
534 if (argnum < 1 || argnum > 6)
535 throw SEMANTIC_ERROR (_("invalid syscall argument number (1-6)"), e->tok);
536
537 bool lvalue = is_active_lvalue(e);
538 if (lvalue)
539 throw SEMANTIC_ERROR(_("utrace '$argN' variable is read-only"), e->tok);
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";
549 n->referents.clear(); // NB: must not resolve yet, to ensure inclusion in session
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 }
557 }
558
559 void
560 utrace_var_expanding_visitor::visit_target_symbol_context (target_symbol* e)
561 {
562 string sname = e->name;
563
564 e->assert_no_components("utrace");
565
566 bool lvalue = is_active_lvalue(e);
567 if (lvalue)
568 throw SEMANTIC_ERROR(_F("utrace '%s' variable is read-only", sname.c_str()), e->tok);
569
570 string fname;
571 if (sname == "$return")
572 {
573 if (flags != UDPF_SYSCALL_RETURN)
574 throw SEMANTIC_ERROR (_("only \"process(PATH_OR_PID).syscall.return\" support $return."), e->tok);
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 {
599 throw SEMANTIC_ERROR (_("unknown target variable"), e->tok);
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;
610 n->referents.clear(); // NB: must not resolve yet, to ensure inclusion in session
611
612 provide (n);
613 }
614
615 void
616 utrace_var_expanding_visitor::visit_target_symbol (target_symbol* e)
617 {
618 assert(e->name.size() > 0 && e->name[0] == '$');
619
620 try
621 {
622 if (flags != UDPF_SYSCALL && flags != UDPF_SYSCALL_RETURN)
623 throw SEMANTIC_ERROR (_("only \"process(PATH_OR_PID).syscall\""
624 " and \"process(PATH_OR_PID).syscall.return\" probes support target symbols"),
625 e->tok);
626
627 if (e->addressof)
628 throw SEMANTIC_ERROR(_("cannot take address of utrace variable"), e->tok);
629
630 if (startswith(e->name, "$arg") || e->name == "$$parms")
631 visit_target_symbol_arg(e);
632 else if (e->name == "$syscall" || e->name == "$return")
633 visit_target_symbol_context(e);
634 else
635 throw SEMANTIC_ERROR (_("invalid target symbol for utrace probe,"
636 " $syscall, $return, $argN or $$parms expected"),
637 e->tok);
638 }
639 catch (const semantic_error &er)
640 {
641 e->chain (er);
642 provide(e);
643 return;
644 }
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 {
657 interned_string path, path_tgt;
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 {
673 if (sess.runtime_usermode_p())
674 throw SEMANTIC_ERROR (_("process.syscall probes not available with the dyninst runtime"));
675
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
686 // Check that if a pid was given, then it corresponds to a running process.
687 if (has_pid || sess.target_pid)
688 {
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);
692 }
693
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 {
705 if (path == "")
706 throw SEMANTIC_ERROR (_("empty module"));
707 path = find_executable (path, sess.sysroot, sess.sysenv);
708 sess.unwindsym_modules.insert (path);
709 path_tgt = path_remove_sysroot(sess, path);
710 }
711
712 finished_results.push_back(new utrace_derived_probe(sess, base, location,
713 has_path, path_tgt, pid,
714 flags));
715 }
716
717 virtual string name() { return "utrace builder"; }
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
738 utrace_derived_probe_group::emit_linux_probe_decl (systemtap_session& s,
739 utrace_derived_probe *p)
740 {
741 s.op->newline() << "{";
742 s.op->line() << " .tgt={";
743 s.op->line() << " .purpose=\"lifecycle tracking\",";
744 if (p->has_path)
745 {
746 s.op->line() << " .procname=\"" << p->path << "\",";
747 s.op->line() << " .pid=0,";
748 }
749 else
750 {
751 s.op->line() << " .procname=NULL,";
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() << " },";
760 s.op->line() << " .probe=" << common_probe_init (p) << ",";
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),";
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 },";
792 s.op->line() << " .events=(UTRACE_EVENT(SYSCALL_ENTRY)|UTRACE_EVENT(DEATH)),";
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();
798 break;
799 case UDPF_SYSCALL_RETURN:
800 s.op->line() << " .flags=(UDPF_SYSCALL_RETURN),";
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 },";
803 s.op->line() << " .events=(UTRACE_EVENT(SYSCALL_EXIT)|UTRACE_EVENT(DEATH)),";
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();
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:
817 throw SEMANTIC_ERROR ("bad utrace probe flag");
818 break;
819 }
820 s.op->line() << " .engine_attached=0,";
821 s.op->line() << " },";
822 }
823
824
825 void
826 utrace_derived_probe_group::emit_module_linux_decls (systemtap_session& s)
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;";
849 s.op->newline() << "const struct stap_probe * const probe;";
850 s.op->newline() << "int engine_attached;";
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;";
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
865 common_probe_entryfn_prologue (s, "STAP_SESSION_RUNNING", "p->probe",
866 "stp_probe_type_utrace");
867
868 // call probe function
869 s.op->newline() << "(*p->probe->ph) (c);";
870 common_probe_entryfn_epilogue (s, true, otf_safe_context(s));
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";
880 s.op->newline() << "static u32 stap_utrace_probe_syscall(struct utrace_engine *engine, struct task_struct *tsk, struct pt_regs *regs) {";
881 s.op->newline() << "#else";
882 s.op->newline() << "#if defined(UTRACE_API_VERSION) && (UTRACE_API_VERSION >= 20091216)";
883 s.op->newline() << "static u32 stap_utrace_probe_syscall(u32 action, struct utrace_engine *engine, struct pt_regs *regs) {";
884 s.op->newline() << "#else";
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) {";
886 s.op->newline() << "#endif";
887 s.op->newline() << "#endif";
888
889 s.op->indent(1);
890 s.op->newline() << "struct stap_utrace_probe *p = (struct stap_utrace_probe *)engine->data;";
891
892 common_probe_entryfn_prologue (s, "STAP_SESSION_RUNNING", "p->probe",
893 "stp_probe_type_utrace_syscall");
894 s.op->newline() << "c->uregs = regs;";
895 s.op->newline() << "c->user_mode_p = 1;";
896
897 // call probe function
898 s.op->newline() << "(*p->probe->ph) (c);";
899 common_probe_entryfn_epilogue (s, true, otf_safe_context(s));
900
901 s.op->newline() << "if ((atomic_read (session_state()) != STAP_SESSION_STARTING) && (atomic_read (session_state()) != STAP_SESSION_RUNNING)) {";
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);";
916 s.op->newline() << "struct utrace_engine *engine;";
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
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];
1058 emit_linux_probe_decl(s, p);
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];
1072 emit_linux_probe_decl(s, p);
1073 }
1074 }
1075 }
1076 s.op->newline(-1) << "};";
1077 }
1078
1079
1080 void
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:
1117 throw SEMANTIC_ERROR ("bad utrace probe flag");
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",
1180 "stp_probe_type_utrace");
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);";
1187 common_probe_entryfn_epilogue (s, true, otf_safe_context(s));
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)
1206 {
1207 if (probes_by_path.empty() && probes_by_pid.empty())
1208 return;
1209
1210 s.op->newline() << "/* ---- utrace probes ---- */";
1211 s.op->newline() << "for (i=0; i<ARRAY_SIZE(stap_utrace_probes); i++) {";
1212 s.op->newline(1) << "struct stap_utrace_probe *p = &stap_utrace_probes[i];";
1213 s.op->newline() << "probe_point = p->probe->pp;"; // for error messages
1214 s.op->newline() << "rc = stap_register_task_finder_target(&p->tgt);";
1215
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;";
1222
1223 s.op->newline(-1) << "}";
1224 }
1225
1226
1227 void
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)
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++) {";
1257 s.op->newline(1) << "struct stap_utrace_probe *p = &stap_utrace_probes[i];";
1258
1259 s.op->newline() << "if (p->engine_attached) {";
1260 s.op->newline(1) << "stap_utrace_detach_ops(&p->ops);";
1261
1262 s.op->newline(-1) << "}";
1263 s.op->newline(-1) << "}";
1264 }
1265
1266
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
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 {
1302 roots[i]->bind(TOK_BEGIN)
1303 ->bind_privilege(pr_all)
1304 ->bind(builder);
1305 roots[i]->bind(TOK_END)
1306 ->bind_privilege(pr_all)
1307 ->bind(builder);
1308 roots[i]->bind(TOK_THREAD)->bind(TOK_BEGIN)
1309 ->bind_privilege(pr_all)
1310 ->bind(builder);
1311 roots[i]->bind(TOK_THREAD)->bind(TOK_END)
1312 ->bind_privilege(pr_all)
1313 ->bind(builder);
1314 roots[i]->bind(TOK_SYSCALL)
1315 ->bind_privilege(pr_all)
1316 ->bind(builder);
1317 roots[i]->bind(TOK_SYSCALL)->bind(TOK_RETURN)
1318 ->bind_privilege(pr_all)
1319 ->bind(builder);
1320 }
1321 }
1322
1323 /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
This page took 0.102316 seconds and 5 git commands to generate.