2 // Copyright (C) 2005-2009 Red Hat Inc.
3 // Copyright (C) 2005-2007 Intel Corporation.
4 // Copyright (C) 2008 James.Bottomley@HansenPartnership.com
6 // This file is part of systemtap, and is free software. You can
7 // redistribute it and/or modify it under the terms of the GNU General
8 // Public License (GPL); either version 2, or (at your option) any
14 #include "task_finder.h"
15 #include "translate.h"
23 using namespace __gnu_cxx
;
26 static const string
TOK_PROCESS("process");
27 static const string
TOK_INSN("insn");
28 static const string
TOK_BLOCK("block");
31 // ------------------------------------------------------------------------
32 // itrace user-space probes
33 // ------------------------------------------------------------------------
36 struct itrace_derived_probe
: public derived_probe
43 itrace_derived_probe (systemtap_session
&s
, probe
* p
, probe_point
* l
,
44 bool hp
, string
&pn
, int64_t pd
, int ss
46 void join_group (systemtap_session
& s
);
50 struct itrace_derived_probe_group
: public generic_dpg
<itrace_derived_probe
>
53 map
<string
, vector
<itrace_derived_probe
*> > probes_by_path
;
54 typedef map
<string
, vector
<itrace_derived_probe
*> >::iterator p_b_path_iterator
;
55 map
<int64_t, vector
<itrace_derived_probe
*> > probes_by_pid
;
56 typedef map
<int64_t, vector
<itrace_derived_probe
*> >::iterator p_b_pid_iterator
;
59 void emit_probe_decl (systemtap_session
& s
, itrace_derived_probe
*p
);
62 itrace_derived_probe_group(): num_probes(0) { }
64 void enroll (itrace_derived_probe
* probe
);
65 void emit_module_decls (systemtap_session
& s
);
66 void emit_module_init (systemtap_session
& s
);
67 void emit_module_exit (systemtap_session
& s
);
71 itrace_derived_probe::itrace_derived_probe (systemtap_session
&s
,
72 probe
* p
, probe_point
* l
,
73 bool hp
, string
&pn
, int64_t pd
,
76 derived_probe(p
, l
), has_path(hp
), path(pn
), pid(pd
), single_step(ss
)
78 if (s
.kernel_config
["CONFIG_UTRACE"] != string("y"))
79 throw semantic_error (_("process probes not available without kernel CONFIG_UTRACE"));
84 itrace_derived_probe::join_group (systemtap_session
& s
)
86 if (! s
.itrace_derived_probes
)
87 s
.itrace_derived_probes
= new itrace_derived_probe_group ();
89 s
.itrace_derived_probes
->enroll (this);
91 enable_task_finder(s
);
94 struct itrace_builder
: public derived_probe_builder
97 virtual void build(systemtap_session
& sess
,
99 probe_point
* location
,
100 std::map
<std::string
, literal
*> const & parameters
,
101 vector
<derived_probe
*> & finished_results
)
107 bool has_path
= get_param (parameters
, TOK_PROCESS
, path
);
108 bool has_pid
= get_param (parameters
, TOK_PROCESS
, pid
);
109 // XXX: PR 6445 needs !has_path && !has_pid support
110 assert (has_path
|| has_pid
);
112 single_step
= ! has_null_param (parameters
, TOK_BLOCK
);
114 // If we have a path, we need to validate it.
117 path
= find_executable (path
);
118 sess
.unwindsym_modules
.insert (path
);
121 finished_results
.push_back(new itrace_derived_probe(sess
, base
, location
,
130 itrace_derived_probe_group::enroll (itrace_derived_probe
* p
)
133 probes_by_path
[p
->path
].push_back(p
);
135 probes_by_pid
[p
->pid
].push_back(p
);
138 // XXX: multiple exec probes (for instance) for the same path (or
139 // pid) should all share a itrace report function, and have their
140 // handlers executed sequentially.
145 itrace_derived_probe_group::emit_probe_decl (systemtap_session
& s
,
146 itrace_derived_probe
*p
)
148 s
.op
->newline() << "{";
149 s
.op
->line() << " .tgt={";
153 s
.op
->line() << " .procname=\"" << p
->path
<< "\",";
154 s
.op
->line() << " .pid=0,";
158 s
.op
->line() << " .procname=NULL,";
159 s
.op
->line() << " .pid=" << p
->pid
<< ",";
162 s
.op
->line() << " .callback=&_stp_itrace_probe_cb,";
163 s
.op
->line() << " },";
164 s
.op
->line() << " .probe=" << common_probe_init (p
) << ",";
165 s
.op
->line() << " .single_step=" << p
->single_step
<< ",";
166 s
.op
->line() << " },";
171 itrace_derived_probe_group::emit_module_decls (systemtap_session
& s
)
173 if (probes_by_path
.empty() && probes_by_pid
.empty())
177 s
.op
->newline() << "/* ---- itrace probes ---- */";
179 s
.op
->newline() << "struct stap_itrace_probe {";
181 s
.op
->newline() << "struct stap_task_finder_target tgt;";
182 s
.op
->newline() << "struct stap_probe * const probe;";
183 s
.op
->newline() << "int single_step;";
184 s
.op
->newline(-1) << "};";
185 s
.op
->newline() << "static void enter_itrace_probe(struct stap_itrace_probe *p, struct pt_regs *regs, void *data);";
186 s
.op
->newline() << "#include \"itrace.c\"";
188 // output routine to call itrace probe
189 s
.op
->newline() << "static void enter_itrace_probe(struct stap_itrace_probe *p, struct pt_regs *regs, void *data) {";
192 common_probe_entryfn_prologue (s
.op
, "STAP_SESSION_RUNNING", "p->probe",
193 "_STP_PROBE_HANDLER_ITRACE");
194 s
.op
->newline() << "c->uregs = regs;";
195 s
.op
->newline() << "c->probe_flags |= _STP_PROBE_STATE_USER_MODE;";
197 // call probe function
198 s
.op
->newline() << "(*p->probe->ph) (c);";
199 common_probe_entryfn_epilogue (s
.op
, true, s
.suppress_handler_errors
);
201 s
.op
->newline() << "return;";
202 s
.op
->newline(-1) << "}";
204 // Output task finder callback routine that gets called for all
205 // itrace probe types.
206 s
.op
->newline() << "static int _stp_itrace_probe_cb(struct stap_task_finder_target *tgt, struct task_struct *tsk, int register_p, int process_p) {";
208 s
.op
->newline() << "int rc = 0;";
209 s
.op
->newline() << "struct stap_itrace_probe *p = container_of(tgt, struct stap_itrace_probe, tgt);";
211 s
.op
->newline() << "if (register_p) ";
214 s
.op
->newline() << "rc = usr_itrace_init(p->single_step, tsk, p);";
215 s
.op
->newline(-1) << "else";
216 s
.op
->newline(1) << "remove_usr_itrace_info(find_itrace_info(tsk));";
217 s
.op
->newline(-1) << "return rc;";
218 s
.op
->newline(-1) << "}";
220 s
.op
->newline() << "static struct stap_itrace_probe stap_itrace_probes[] = {";
223 // Set up 'process(PATH)' probes
224 if (! probes_by_path
.empty())
226 for (p_b_path_iterator it
= probes_by_path
.begin();
227 it
!= probes_by_path
.end(); it
++)
229 for (unsigned i
= 0; i
< it
->second
.size(); i
++)
231 itrace_derived_probe
*p
= it
->second
[i
];
232 emit_probe_decl(s
, p
);
237 // Set up 'process(PID)' probes
238 if (! probes_by_pid
.empty())
240 for (p_b_pid_iterator it
= probes_by_pid
.begin();
241 it
!= probes_by_pid
.end(); it
++)
243 for (unsigned i
= 0; i
< it
->second
.size(); i
++)
245 itrace_derived_probe
*p
= it
->second
[i
];
246 emit_probe_decl(s
, p
);
250 s
.op
->newline(-1) << "};";
255 itrace_derived_probe_group::emit_module_init (systemtap_session
& s
)
257 if (probes_by_path
.empty() && probes_by_pid
.empty())
261 s
.op
->newline() << "/* ---- itrace probes ---- */";
263 s
.op
->newline() << "for (i=0; i<" << num_probes
<< "; i++) {";
265 s
.op
->newline() << "struct stap_itrace_probe *p = &stap_itrace_probes[i];";
267 // 'arch_has_single_step' needs to be defined for either single step mode
269 s
.op
->newline() << "if (!arch_has_single_step()) {";
271 s
.op
->newline() << "_stp_error (\"insn probe init: arch does not support step mode\");";
272 s
.op
->newline() << "rc = -EPERM;";
273 s
.op
->newline() << "break;";
274 s
.op
->newline(-1) << "}";
275 s
.op
->newline() << "if (!p->single_step && !arch_has_block_step()) {";
277 s
.op
->newline() << "_stp_error (\"insn probe init: arch does not support block step mode\");";
278 s
.op
->newline() << "rc = -EPERM;";
279 s
.op
->newline() << "break;";
280 s
.op
->newline(-1) << "}";
282 s
.op
->newline() << "rc = stap_register_task_finder_target(&p->tgt);";
283 s
.op
->newline(-1) << "}";
288 itrace_derived_probe_group::emit_module_exit (systemtap_session
& s
)
290 if (probes_by_path
.empty() && probes_by_pid
.empty()) return;
292 s
.op
->newline() << "/* ---- itrace probes ---- */";
293 s
.op
->newline() << "cleanup_usr_itrace();";
297 register_tapset_itrace(systemtap_session
& s
)
299 match_node
* root
= s
.pattern_root
;
300 derived_probe_builder
*builder
= new itrace_builder();
302 root
->bind_str(TOK_PROCESS
)->bind(TOK_INSN
)
304 root
->bind_num(TOK_PROCESS
)->bind(TOK_INSN
)
306 root
->bind_str(TOK_PROCESS
)->bind(TOK_INSN
)->bind(TOK_BLOCK
)
308 root
->bind_num(TOK_PROCESS
)->bind(TOK_INSN
)->bind(TOK_BLOCK
)
314 /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */