]>
Commit | Line | Data |
---|---|---|
93646f4d | 1 | // tapset for timers |
1af100fc | 2 | // Copyright (C) 2005-2013 Red Hat Inc. |
93646f4d | 3 | // Copyright (C) 2005-2007 Intel Corporation. |
93646f4d 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" | |
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 | ||
4627ed58 JS |
25 | static const string TOK_PROCESS("process"); |
26 | static const string TOK_INSN("insn"); | |
27 | static const string TOK_BLOCK("block"); | |
93646f4d JS |
28 | |
29 | ||
30 | // ------------------------------------------------------------------------ | |
31 | // itrace user-space probes | |
32 | // ------------------------------------------------------------------------ | |
33 | ||
34 | ||
35 | 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 | 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 | 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 | 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 | derived_probe(p, l), has_path(hp), path(pn), pid(pd), single_step(ss) | |
76 | { | |
e34d5d13 | 77 | if (s.kernel_config["CONFIG_UTRACE"] != string("y")) |
dc09353a | 78 | throw SEMANTIC_ERROR (_("process probes not available without kernel CONFIG_UTRACE")); |
93646f4d JS |
79 | } |
80 | ||
81 | ||
82 | void | |
83 | itrace_derived_probe::join_group (systemtap_session& s) | |
84 | { | |
85 | if (! s.itrace_derived_probes) | |
86 | s.itrace_derived_probes = new itrace_derived_probe_group (); | |
87 | ||
88 | s.itrace_derived_probes->enroll (this); | |
ca6d3b0f | 89 | this->group = s.itrace_derived_probes; |
93646f4d JS |
90 | |
91 | enable_task_finder(s); | |
92 | } | |
93 | ||
94 | struct itrace_builder: public derived_probe_builder | |
95 | { | |
96 | itrace_builder() {} | |
97 | virtual void build(systemtap_session & sess, | |
98 | probe * base, | |
99 | probe_point * location, | |
100 | std::map<std::string, literal *> const & parameters, | |
101 | vector<derived_probe *> & finished_results) | |
102 | { | |
05fb3e0c | 103 | string path, path_tgt; |
93646f4d JS |
104 | int64_t pid = 0; |
105 | int single_step; | |
106 | ||
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); | |
111 | ||
112 | single_step = ! has_null_param (parameters, TOK_BLOCK); | |
113 | ||
114 | // If we have a path, we need to validate it. | |
115 | if (has_path) | |
671ceda8 | 116 | { |
05fb3e0c | 117 | path = find_executable (path, sess.sysroot, sess.sysenv); |
671ceda8 | 118 | sess.unwindsym_modules.insert (path); |
05fb3e0c | 119 | path_tgt = path_remove_sysroot(sess, path); |
671ceda8 | 120 | } |
5c6f9e92 AJ |
121 | else // (has_pid) |
122 | { | |
a03a3744 JS |
123 | string pid_err_msg; |
124 | if (!is_valid_pid(pid, pid_err_msg)) | |
125 | throw SEMANTIC_ERROR(pid_err_msg); | |
5c6f9e92 | 126 | } |
93646f4d JS |
127 | |
128 | finished_results.push_back(new itrace_derived_probe(sess, base, location, | |
05fb3e0c | 129 | has_path, path_tgt, pid, |
93646f4d JS |
130 | single_step |
131 | )); | |
132 | } | |
133 | }; | |
134 | ||
135 | ||
136 | void | |
137 | itrace_derived_probe_group::enroll (itrace_derived_probe* p) | |
138 | { | |
139 | if (p->has_path) | |
140 | probes_by_path[p->path].push_back(p); | |
141 | else | |
142 | probes_by_pid[p->pid].push_back(p); | |
143 | num_probes++; | |
144 | ||
145 | // XXX: multiple exec probes (for instance) for the same path (or | |
146 | // pid) should all share a itrace report function, and have their | |
147 | // handlers executed sequentially. | |
148 | } | |
149 | ||
150 | ||
151 | void | |
152 | itrace_derived_probe_group::emit_probe_decl (systemtap_session& s, | |
153 | itrace_derived_probe *p) | |
154 | { | |
155 | s.op->newline() << "{"; | |
156 | s.op->line() << " .tgt={"; | |
1af100fc | 157 | s.op->line() << " .purpose=\"itrace\","; |
93646f4d JS |
158 | |
159 | if (p->has_path) | |
160 | { | |
b6921d59 | 161 | s.op->line() << " .procname=\"" << p->path << "\","; |
93646f4d JS |
162 | s.op->line() << " .pid=0,"; |
163 | } | |
164 | else | |
165 | { | |
b6921d59 | 166 | s.op->line() << " .procname=NULL,"; |
93646f4d JS |
167 | s.op->line() << " .pid=" << p->pid << ","; |
168 | } | |
169 | ||
170 | s.op->line() << " .callback=&_stp_itrace_probe_cb,"; | |
171 | s.op->line() << " },"; | |
faea5e16 | 172 | s.op->line() << " .probe=" << common_probe_init (p) << ","; |
93646f4d | 173 | s.op->line() << " .single_step=" << p->single_step << ","; |
93646f4d JS |
174 | s.op->line() << " },"; |
175 | } | |
176 | ||
177 | ||
178 | void | |
179 | itrace_derived_probe_group::emit_module_decls (systemtap_session& s) | |
180 | { | |
181 | if (probes_by_path.empty() && probes_by_pid.empty()) | |
182 | return; | |
183 | ||
184 | s.op->newline(); | |
185 | s.op->newline() << "/* ---- itrace probes ---- */"; | |
186 | ||
187 | s.op->newline() << "struct stap_itrace_probe {"; | |
188 | s.op->indent(1); | |
189 | s.op->newline() << "struct stap_task_finder_target tgt;"; | |
7c3e97f4 | 190 | s.op->newline() << "const struct stap_probe * const probe;"; |
93646f4d JS |
191 | s.op->newline() << "int single_step;"; |
192 | s.op->newline(-1) << "};"; | |
193 | s.op->newline() << "static void enter_itrace_probe(struct stap_itrace_probe *p, struct pt_regs *regs, void *data);"; | |
2ba1736a | 194 | s.op->newline() << "#include \"linux/itrace.c\""; |
93646f4d JS |
195 | |
196 | // output routine to call itrace probe | |
197 | s.op->newline() << "static void enter_itrace_probe(struct stap_itrace_probe *p, struct pt_regs *regs, void *data) {"; | |
198 | s.op->indent(1); | |
199 | ||
71db462b | 200 | common_probe_entryfn_prologue (s, "STAP_SESSION_RUNNING", "p->probe", |
cda141c2 | 201 | "stp_probe_type_itrace"); |
d9aed31e | 202 | s.op->newline() << "c->uregs = regs;"; |
e04b5d74 | 203 | s.op->newline() << "c->user_mode_p = 1;"; |
93646f4d JS |
204 | |
205 | // call probe function | |
26e63673 | 206 | s.op->newline() << "(*p->probe->ph) (c);"; |
ef1337ee | 207 | common_probe_entryfn_epilogue (s, true, otf_safe_context(s)); |
93646f4d JS |
208 | |
209 | s.op->newline() << "return;"; | |
210 | s.op->newline(-1) << "}"; | |
211 | ||
212 | // Output task finder callback routine that gets called for all | |
213 | // itrace probe types. | |
214 | 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) {"; | |
215 | s.op->indent(1); | |
216 | s.op->newline() << "int rc = 0;"; | |
217 | s.op->newline() << "struct stap_itrace_probe *p = container_of(tgt, struct stap_itrace_probe, tgt);"; | |
218 | ||
219 | s.op->newline() << "if (register_p) "; | |
220 | s.op->indent(1); | |
221 | ||
c8a44dea | 222 | s.op->newline() << "rc = usr_itrace_init(p->single_step, tsk, p);"; |
93646f4d | 223 | s.op->newline(-1) << "else"; |
4f600a5f | 224 | s.op->newline(1) << "remove_usr_itrace_info(find_itrace_info(tsk));"; |
93646f4d JS |
225 | s.op->newline(-1) << "return rc;"; |
226 | s.op->newline(-1) << "}"; | |
227 | ||
93646f4d JS |
228 | s.op->newline() << "static struct stap_itrace_probe stap_itrace_probes[] = {"; |
229 | s.op->indent(1); | |
230 | ||
231 | // Set up 'process(PATH)' probes | |
232 | if (! probes_by_path.empty()) | |
233 | { | |
234 | for (p_b_path_iterator it = probes_by_path.begin(); | |
235 | it != probes_by_path.end(); it++) | |
236 | { | |
237 | for (unsigned i = 0; i < it->second.size(); i++) | |
238 | { | |
239 | itrace_derived_probe *p = it->second[i]; | |
240 | emit_probe_decl(s, p); | |
241 | } | |
242 | } | |
243 | } | |
244 | ||
245 | // Set up 'process(PID)' probes | |
246 | if (! probes_by_pid.empty()) | |
247 | { | |
248 | for (p_b_pid_iterator it = probes_by_pid.begin(); | |
249 | it != probes_by_pid.end(); it++) | |
250 | { | |
251 | for (unsigned i = 0; i < it->second.size(); i++) | |
252 | { | |
253 | itrace_derived_probe *p = it->second[i]; | |
254 | emit_probe_decl(s, p); | |
255 | } | |
256 | } | |
257 | } | |
258 | s.op->newline(-1) << "};"; | |
259 | } | |
260 | ||
261 | ||
262 | void | |
263 | itrace_derived_probe_group::emit_module_init (systemtap_session& s) | |
264 | { | |
265 | if (probes_by_path.empty() && probes_by_pid.empty()) | |
266 | return; | |
267 | ||
93646f4d JS |
268 | s.op->newline(); |
269 | s.op->newline() << "/* ---- itrace probes ---- */"; | |
270 | ||
271 | s.op->newline() << "for (i=0; i<" << num_probes << "; i++) {"; | |
272 | s.op->indent(1); | |
273 | s.op->newline() << "struct stap_itrace_probe *p = &stap_itrace_probes[i];"; | |
274 | ||
275 | // 'arch_has_single_step' needs to be defined for either single step mode | |
276 | // or branch mode. | |
277 | s.op->newline() << "if (!arch_has_single_step()) {"; | |
278 | s.op->indent(1); | |
279 | s.op->newline() << "_stp_error (\"insn probe init: arch does not support step mode\");"; | |
280 | s.op->newline() << "rc = -EPERM;"; | |
281 | s.op->newline() << "break;"; | |
282 | s.op->newline(-1) << "}"; | |
283 | s.op->newline() << "if (!p->single_step && !arch_has_block_step()) {"; | |
284 | s.op->indent(1); | |
285 | s.op->newline() << "_stp_error (\"insn probe init: arch does not support block step mode\");"; | |
286 | s.op->newline() << "rc = -EPERM;"; | |
287 | s.op->newline() << "break;"; | |
288 | s.op->newline(-1) << "}"; | |
289 | ||
290 | s.op->newline() << "rc = stap_register_task_finder_target(&p->tgt);"; | |
291 | s.op->newline(-1) << "}"; | |
292 | } | |
293 | ||
294 | ||
295 | void | |
296 | itrace_derived_probe_group::emit_module_exit (systemtap_session& s) | |
297 | { | |
298 | if (probes_by_path.empty() && probes_by_pid.empty()) return; | |
299 | s.op->newline(); | |
300 | s.op->newline() << "/* ---- itrace probes ---- */"; | |
301 | s.op->newline() << "cleanup_usr_itrace();"; | |
302 | } | |
303 | ||
304 | void | |
305 | register_tapset_itrace(systemtap_session& s) | |
306 | { | |
307 | match_node* root = s.pattern_root; | |
308 | derived_probe_builder *builder = new itrace_builder(); | |
309 | ||
d2c9ec9b | 310 | root->bind_str(TOK_PROCESS)->bind(TOK_INSN) |
d2c9ec9b DB |
311 | ->bind(builder); |
312 | root->bind_num(TOK_PROCESS)->bind(TOK_INSN) | |
d2c9ec9b DB |
313 | ->bind(builder); |
314 | root->bind_str(TOK_PROCESS)->bind(TOK_INSN)->bind(TOK_BLOCK) | |
d2c9ec9b DB |
315 | ->bind(builder); |
316 | root->bind_num(TOK_PROCESS)->bind(TOK_INSN)->bind(TOK_BLOCK) | |
d2c9ec9b | 317 | ->bind(builder); |
93646f4d JS |
318 | } |
319 | ||
320 | ||
321 | ||
322 | /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */ |