Branch data Line data Source code
1 : : // tapset for timers
2 : : // Copyright (C) 2005-2013 Red Hat Inc.
3 : : // Copyright (C) 2005-2007 Intel Corporation.
4 : : //
5 : : // This file is part of systemtap, and is free software. You can
6 : : // redistribute it and/or modify it under the terms of the GNU General
7 : : // Public License (GPL); either version 2, or (at your option) any
8 : : // later version.
9 : :
10 : :
11 : : #include "session.h"
12 : : #include "tapsets.h"
13 : : #include "task_finder.h"
14 : : #include "translate.h"
15 : : #include "util.h"
16 : :
17 : : #include <cstring>
18 : : #include <string>
19 : :
20 : :
21 : : using namespace std;
22 : : using namespace __gnu_cxx;
23 : :
24 : :
25 [ + - ]: 2414 : static const string TOK_PROCESS("process");
26 [ + - ]: 2414 : static const string TOK_INSN("insn");
27 [ + - ]: 2414 : static const string TOK_BLOCK("block");
28 : :
29 : :
30 : : // ------------------------------------------------------------------------
31 : : // itrace user-space probes
32 : : // ------------------------------------------------------------------------
33 : :
34 : :
35 [ # # ][ # # ]: 0 : struct itrace_derived_probe: public derived_probe
36 : : {
37 : : bool has_path;
38 : : string path;
39 : : int64_t pid;
40 : : int single_step;
41 : :
42 : : itrace_derived_probe (systemtap_session &s, probe* p, probe_point* l,
43 : : bool hp, string &pn, int64_t pd, int ss
44 : : );
45 : : void join_group (systemtap_session& s);
46 : : };
47 : :
48 : :
49 [ # # ][ # # ]: 0 : struct itrace_derived_probe_group: public generic_dpg<itrace_derived_probe>
[ # # ]
50 : : {
51 : : private:
52 : : map<string, vector<itrace_derived_probe*> > probes_by_path;
53 : : typedef map<string, vector<itrace_derived_probe*> >::iterator p_b_path_iterator;
54 : : map<int64_t, vector<itrace_derived_probe*> > probes_by_pid;
55 : : typedef map<int64_t, vector<itrace_derived_probe*> >::iterator p_b_pid_iterator;
56 : : unsigned num_probes;
57 : :
58 : : void emit_probe_decl (systemtap_session& s, itrace_derived_probe *p);
59 : :
60 : : public:
61 [ # # ][ # # ]: 0 : itrace_derived_probe_group(): num_probes(0) { }
62 : :
63 : : void enroll (itrace_derived_probe* probe);
64 : : void emit_module_decls (systemtap_session& s);
65 : : void emit_module_init (systemtap_session& s);
66 : : void emit_module_exit (systemtap_session& s);
67 : : };
68 : :
69 : :
70 : 0 : itrace_derived_probe::itrace_derived_probe (systemtap_session &s,
71 : : probe* p, probe_point* l,
72 : : bool hp, string &pn, int64_t pd,
73 : : int ss
74 : : ):
75 [ # # ]: 0 : derived_probe(p, l), has_path(hp), path(pn), pid(pd), single_step(ss)
76 : : {
77 [ # # ][ # # ]: 0 : if (s.kernel_config["CONFIG_UTRACE"] != string("y"))
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
78 [ # # ][ # # ]: 0 : throw semantic_error (_("process probes not available without kernel CONFIG_UTRACE"));
79 : 0 : }
80 : :
81 : :
82 : : void
83 : 0 : itrace_derived_probe::join_group (systemtap_session& s)
84 : : {
85 [ # # ]: 0 : if (! s.itrace_derived_probes)
86 [ # # ]: 0 : s.itrace_derived_probes = new itrace_derived_probe_group ();
87 : :
88 : 0 : s.itrace_derived_probes->enroll (this);
89 : :
90 : 0 : enable_task_finder(s);
91 : 0 : }
92 : :
93 [ # # ]: 0 : struct itrace_builder: public derived_probe_builder
94 : : {
95 : 1218 : itrace_builder() {}
96 : 0 : virtual void build(systemtap_session & sess,
97 : : probe * base,
98 : : probe_point * location,
99 : : std::map<std::string, literal *> const & parameters,
100 : : vector<derived_probe *> & finished_results)
101 : : {
102 [ # # ][ # # ]: 0 : string path, path_tgt;
103 : 0 : int64_t pid = 0;
104 : : int single_step;
105 : :
106 [ # # ]: 0 : bool has_path = get_param (parameters, TOK_PROCESS, path);
107 [ # # ]: 0 : bool has_pid = get_param (parameters, TOK_PROCESS, pid);
108 : : // XXX: PR 6445 needs !has_path && !has_pid support
109 [ # # ][ # # ]: 0 : assert (has_path || has_pid);
110 : :
111 [ # # ]: 0 : single_step = ! has_null_param (parameters, TOK_BLOCK);
112 : :
113 : : // If we have a path, we need to validate it.
114 [ # # ]: 0 : if (has_path)
115 : : {
116 [ # # ][ # # ]: 0 : path = find_executable (path, sess.sysroot, sess.sysenv);
[ # # ][ # # ]
[ # # ]
117 [ # # ]: 0 : sess.unwindsym_modules.insert (path);
118 [ # # ][ # # ]: 0 : path_tgt = path_remove_sysroot(sess, path);
[ # # ]
119 : : }
120 : :
121 : : finished_results.push_back(new itrace_derived_probe(sess, base, location,
122 : : has_path, path_tgt, pid,
123 : : single_step
124 [ # # ][ # # ]: 0 : ));
[ # # ][ # # ]
[ # # ]
125 : 0 : }
126 : : };
127 : :
128 : :
129 : : void
130 : 0 : itrace_derived_probe_group::enroll (itrace_derived_probe* p)
131 : : {
132 [ # # ]: 0 : if (p->has_path)
133 : 0 : probes_by_path[p->path].push_back(p);
134 : : else
135 : 0 : probes_by_pid[p->pid].push_back(p);
136 : 0 : num_probes++;
137 : :
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.
141 : 0 : }
142 : :
143 : :
144 : : void
145 : 0 : itrace_derived_probe_group::emit_probe_decl (systemtap_session& s,
146 : : itrace_derived_probe *p)
147 : : {
148 : 0 : s.op->newline() << "{";
149 : 0 : s.op->line() << " .tgt={";
150 : 0 : s.op->line() << " .purpose=\"itrace\",";
151 : :
152 [ # # ]: 0 : if (p->has_path)
153 : : {
154 : 0 : s.op->line() << " .procname=\"" << p->path << "\",";
155 : 0 : s.op->line() << " .pid=0,";
156 : : }
157 : : else
158 : : {
159 : 0 : s.op->line() << " .procname=NULL,";
160 : 0 : s.op->line() << " .pid=" << p->pid << ",";
161 : : }
162 : :
163 : 0 : s.op->line() << " .callback=&_stp_itrace_probe_cb,";
164 : 0 : s.op->line() << " },";
165 [ # # ][ # # ]: 0 : s.op->line() << " .probe=" << common_probe_init (p) << ",";
166 : 0 : s.op->line() << " .single_step=" << p->single_step << ",";
167 : 0 : s.op->line() << " },";
168 : 0 : }
169 : :
170 : :
171 : : void
172 : 0 : itrace_derived_probe_group::emit_module_decls (systemtap_session& s)
173 : : {
174 [ # # ][ # # ]: 0 : if (probes_by_path.empty() && probes_by_pid.empty())
[ # # ]
175 : 0 : return;
176 : :
177 : 0 : s.op->newline();
178 : 0 : s.op->newline() << "/* ---- itrace probes ---- */";
179 : :
180 : 0 : s.op->newline() << "struct stap_itrace_probe {";
181 : 0 : s.op->indent(1);
182 : 0 : s.op->newline() << "struct stap_task_finder_target tgt;";
183 : 0 : s.op->newline() << "const struct stap_probe * const probe;";
184 : 0 : s.op->newline() << "int single_step;";
185 : 0 : s.op->newline(-1) << "};";
186 : 0 : s.op->newline() << "static void enter_itrace_probe(struct stap_itrace_probe *p, struct pt_regs *regs, void *data);";
187 : 0 : s.op->newline() << "#include \"linux/itrace.c\"";
188 : :
189 : : // output routine to call itrace probe
190 : 0 : s.op->newline() << "static void enter_itrace_probe(struct stap_itrace_probe *p, struct pt_regs *regs, void *data) {";
191 : 0 : s.op->indent(1);
192 : :
193 : : common_probe_entryfn_prologue (s, "STAP_SESSION_RUNNING", "p->probe",
194 [ # # ][ # # ]: 0 : "stp_probe_type_itrace");
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
195 : 0 : s.op->newline() << "c->uregs = regs;";
196 : 0 : s.op->newline() << "c->user_mode_p = 1;";
197 : :
198 : : // call probe function
199 : 0 : s.op->newline() << "(*p->probe->ph) (c);";
200 : 0 : common_probe_entryfn_epilogue (s, true);
201 : :
202 : 0 : s.op->newline() << "return;";
203 : 0 : s.op->newline(-1) << "}";
204 : :
205 : : // Output task finder callback routine that gets called for all
206 : : // itrace probe types.
207 : 0 : 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 : 0 : s.op->indent(1);
209 : 0 : s.op->newline() << "int rc = 0;";
210 : 0 : s.op->newline() << "struct stap_itrace_probe *p = container_of(tgt, struct stap_itrace_probe, tgt);";
211 : :
212 : 0 : s.op->newline() << "if (register_p) ";
213 : 0 : s.op->indent(1);
214 : :
215 : 0 : s.op->newline() << "rc = usr_itrace_init(p->single_step, tsk, p);";
216 : 0 : s.op->newline(-1) << "else";
217 : 0 : s.op->newline(1) << "remove_usr_itrace_info(find_itrace_info(tsk));";
218 : 0 : s.op->newline(-1) << "return rc;";
219 : 0 : s.op->newline(-1) << "}";
220 : :
221 : 0 : s.op->newline() << "static struct stap_itrace_probe stap_itrace_probes[] = {";
222 : 0 : s.op->indent(1);
223 : :
224 : : // Set up 'process(PATH)' probes
225 [ # # ]: 0 : if (! probes_by_path.empty())
226 : : {
227 [ # # ][ # # ]: 0 : for (p_b_path_iterator it = probes_by_path.begin();
228 [ # # ]: 0 : it != probes_by_path.end(); it++)
229 : : {
230 [ # # ][ # # ]: 0 : for (unsigned i = 0; i < it->second.size(); i++)
231 : : {
232 [ # # ]: 0 : itrace_derived_probe *p = it->second[i];
233 [ # # ]: 0 : emit_probe_decl(s, p);
234 : : }
235 : : }
236 : : }
237 : :
238 : : // Set up 'process(PID)' probes
239 [ # # ]: 0 : if (! probes_by_pid.empty())
240 : : {
241 [ # # ][ # # ]: 0 : for (p_b_pid_iterator it = probes_by_pid.begin();
242 [ # # ]: 0 : it != probes_by_pid.end(); it++)
243 : : {
244 [ # # ][ # # ]: 0 : for (unsigned i = 0; i < it->second.size(); i++)
245 : : {
246 [ # # ]: 0 : itrace_derived_probe *p = it->second[i];
247 [ # # ]: 0 : emit_probe_decl(s, p);
248 : : }
249 : : }
250 : : }
251 : 0 : s.op->newline(-1) << "};";
252 : : }
253 : :
254 : :
255 : : void
256 : 0 : itrace_derived_probe_group::emit_module_init (systemtap_session& s)
257 : : {
258 [ # # ][ # # ]: 0 : if (probes_by_path.empty() && probes_by_pid.empty())
[ # # ]
259 : 0 : return;
260 : :
261 : 0 : s.op->newline();
262 : 0 : s.op->newline() << "/* ---- itrace probes ---- */";
263 : :
264 : 0 : s.op->newline() << "for (i=0; i<" << num_probes << "; i++) {";
265 : 0 : s.op->indent(1);
266 : 0 : s.op->newline() << "struct stap_itrace_probe *p = &stap_itrace_probes[i];";
267 : :
268 : : // 'arch_has_single_step' needs to be defined for either single step mode
269 : : // or branch mode.
270 : 0 : s.op->newline() << "if (!arch_has_single_step()) {";
271 : 0 : s.op->indent(1);
272 : 0 : s.op->newline() << "_stp_error (\"insn probe init: arch does not support step mode\");";
273 : 0 : s.op->newline() << "rc = -EPERM;";
274 : 0 : s.op->newline() << "break;";
275 : 0 : s.op->newline(-1) << "}";
276 : 0 : s.op->newline() << "if (!p->single_step && !arch_has_block_step()) {";
277 : 0 : s.op->indent(1);
278 : 0 : s.op->newline() << "_stp_error (\"insn probe init: arch does not support block step mode\");";
279 : 0 : s.op->newline() << "rc = -EPERM;";
280 : 0 : s.op->newline() << "break;";
281 : 0 : s.op->newline(-1) << "}";
282 : :
283 : 0 : s.op->newline() << "rc = stap_register_task_finder_target(&p->tgt);";
284 : 0 : s.op->newline(-1) << "}";
285 : : }
286 : :
287 : :
288 : : void
289 : 0 : itrace_derived_probe_group::emit_module_exit (systemtap_session& s)
290 : : {
291 [ # # ][ # # ]: 0 : if (probes_by_path.empty() && probes_by_pid.empty()) return;
[ # # ]
292 : 0 : s.op->newline();
293 : 0 : s.op->newline() << "/* ---- itrace probes ---- */";
294 : 0 : s.op->newline() << "cleanup_usr_itrace();";
295 : : }
296 : :
297 : : void
298 : 1218 : register_tapset_itrace(systemtap_session& s)
299 : : {
300 : 1218 : match_node* root = s.pattern_root;
301 : 1218 : derived_probe_builder *builder = new itrace_builder();
302 : :
303 : : root->bind_str(TOK_PROCESS)->bind(TOK_INSN)
304 : 1218 : ->bind(builder);
305 : : root->bind_num(TOK_PROCESS)->bind(TOK_INSN)
306 : 1218 : ->bind(builder);
307 : : root->bind_str(TOK_PROCESS)->bind(TOK_INSN)->bind(TOK_BLOCK)
308 : 1218 : ->bind(builder);
309 : : root->bind_num(TOK_PROCESS)->bind(TOK_INSN)->bind(TOK_BLOCK)
310 : 1218 : ->bind(builder);
311 [ + - ][ + - ]: 8460 : }
312 : :
313 : :
314 : :
315 : : /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
|