]> sourceware.org Git - systemtap.git/blob - tapset-itrace.cxx
Give information about online servers and which servers were specified when no suitab...
[systemtap.git] / tapset-itrace.cxx
1 // tapset for timers
2 // Copyright (C) 2005-2009 Red Hat Inc.
3 // Copyright (C) 2005-2007 Intel Corporation.
4 // Copyright (C) 2008 James.Bottomley@HansenPartnership.com
5 //
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
9 // later version.
10
11
12 #include "session.h"
13 #include "tapsets.h"
14 #include "task_finder.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_INSN("insn");
28 static const string TOK_BLOCK("block");
29
30
31 // ------------------------------------------------------------------------
32 // itrace user-space probes
33 // ------------------------------------------------------------------------
34
35
36 struct itrace_derived_probe: public derived_probe
37 {
38 bool has_path;
39 string path;
40 int64_t pid;
41 int single_step;
42
43 itrace_derived_probe (systemtap_session &s, probe* p, probe_point* l,
44 bool hp, string &pn, int64_t pd, int ss
45 );
46 void join_group (systemtap_session& s);
47 };
48
49
50 struct itrace_derived_probe_group: public generic_dpg<itrace_derived_probe>
51 {
52 private:
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;
57 unsigned num_probes;
58
59 void emit_probe_decl (systemtap_session& s, itrace_derived_probe *p);
60
61 public:
62 itrace_derived_probe_group(): num_probes(0) { }
63
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);
68 };
69
70
71 itrace_derived_probe::itrace_derived_probe (systemtap_session &s,
72 probe* p, probe_point* l,
73 bool hp, string &pn, int64_t pd,
74 int ss
75 ):
76 derived_probe(p, l), has_path(hp), path(pn), pid(pd), single_step(ss)
77 {
78 if (s.kernel_config["CONFIG_UTRACE"] != string("y"))
79 throw semantic_error (_("process probes not available without kernel CONFIG_UTRACE"));
80 }
81
82
83 void
84 itrace_derived_probe::join_group (systemtap_session& s)
85 {
86 if (! s.itrace_derived_probes)
87 s.itrace_derived_probes = new itrace_derived_probe_group ();
88
89 s.itrace_derived_probes->enroll (this);
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 {
103 string path;
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)
116 {
117 path = find_executable (path);
118 sess.unwindsym_modules.insert (path);
119 }
120
121 finished_results.push_back(new itrace_derived_probe(sess, base, location,
122 has_path, path, pid,
123 single_step
124 ));
125 }
126 };
127
128
129 void
130 itrace_derived_probe_group::enroll (itrace_derived_probe* p)
131 {
132 if (p->has_path)
133 probes_by_path[p->path].push_back(p);
134 else
135 probes_by_pid[p->pid].push_back(p);
136 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 }
142
143
144 void
145 itrace_derived_probe_group::emit_probe_decl (systemtap_session& s,
146 itrace_derived_probe *p)
147 {
148 s.op->newline() << "{";
149 s.op->line() << " .tgt={";
150
151 if (p->has_path)
152 {
153 s.op->line() << " .procname=\"" << p->path << "\",";
154 s.op->line() << " .pid=0,";
155 }
156 else
157 {
158 s.op->line() << " .procname=NULL,";
159 s.op->line() << " .pid=" << p->pid << ",";
160 }
161
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() << " },";
167 }
168
169
170 void
171 itrace_derived_probe_group::emit_module_decls (systemtap_session& s)
172 {
173 if (probes_by_path.empty() && probes_by_pid.empty())
174 return;
175
176 s.op->newline();
177 s.op->newline() << "/* ---- itrace probes ---- */";
178
179 s.op->newline() << "struct stap_itrace_probe {";
180 s.op->indent(1);
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\"";
187
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) {";
190 s.op->indent(1);
191
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;";
196
197 // call probe function
198 s.op->newline() << "(*p->probe->ph) (c);";
199 common_probe_entryfn_epilogue (s.op, true, s.suppress_handler_errors);
200
201 s.op->newline() << "return;";
202 s.op->newline(-1) << "}";
203
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) {";
207 s.op->indent(1);
208 s.op->newline() << "int rc = 0;";
209 s.op->newline() << "struct stap_itrace_probe *p = container_of(tgt, struct stap_itrace_probe, tgt);";
210
211 s.op->newline() << "if (register_p) ";
212 s.op->indent(1);
213
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) << "}";
219
220 s.op->newline() << "static struct stap_itrace_probe stap_itrace_probes[] = {";
221 s.op->indent(1);
222
223 // Set up 'process(PATH)' probes
224 if (! probes_by_path.empty())
225 {
226 for (p_b_path_iterator it = probes_by_path.begin();
227 it != probes_by_path.end(); it++)
228 {
229 for (unsigned i = 0; i < it->second.size(); i++)
230 {
231 itrace_derived_probe *p = it->second[i];
232 emit_probe_decl(s, p);
233 }
234 }
235 }
236
237 // Set up 'process(PID)' probes
238 if (! probes_by_pid.empty())
239 {
240 for (p_b_pid_iterator it = probes_by_pid.begin();
241 it != probes_by_pid.end(); it++)
242 {
243 for (unsigned i = 0; i < it->second.size(); i++)
244 {
245 itrace_derived_probe *p = it->second[i];
246 emit_probe_decl(s, p);
247 }
248 }
249 }
250 s.op->newline(-1) << "};";
251 }
252
253
254 void
255 itrace_derived_probe_group::emit_module_init (systemtap_session& s)
256 {
257 if (probes_by_path.empty() && probes_by_pid.empty())
258 return;
259
260 s.op->newline();
261 s.op->newline() << "/* ---- itrace probes ---- */";
262
263 s.op->newline() << "for (i=0; i<" << num_probes << "; i++) {";
264 s.op->indent(1);
265 s.op->newline() << "struct stap_itrace_probe *p = &stap_itrace_probes[i];";
266
267 // 'arch_has_single_step' needs to be defined for either single step mode
268 // or branch mode.
269 s.op->newline() << "if (!arch_has_single_step()) {";
270 s.op->indent(1);
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()) {";
276 s.op->indent(1);
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) << "}";
281
282 s.op->newline() << "rc = stap_register_task_finder_target(&p->tgt);";
283 s.op->newline(-1) << "}";
284 }
285
286
287 void
288 itrace_derived_probe_group::emit_module_exit (systemtap_session& s)
289 {
290 if (probes_by_path.empty() && probes_by_pid.empty()) return;
291 s.op->newline();
292 s.op->newline() << "/* ---- itrace probes ---- */";
293 s.op->newline() << "cleanup_usr_itrace();";
294 }
295
296 void
297 register_tapset_itrace(systemtap_session& s)
298 {
299 match_node* root = s.pattern_root;
300 derived_probe_builder *builder = new itrace_builder();
301
302 root->bind_str(TOK_PROCESS)->bind(TOK_INSN)
303 ->bind(builder);
304 root->bind_num(TOK_PROCESS)->bind(TOK_INSN)
305 ->bind(builder);
306 root->bind_str(TOK_PROCESS)->bind(TOK_INSN)->bind(TOK_BLOCK)
307 ->bind(builder);
308 root->bind_num(TOK_PROCESS)->bind(TOK_INSN)->bind(TOK_BLOCK)
309 ->bind(builder);
310 }
311
312
313
314 /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
This page took 0.053183 seconds and 5 git commands to generate.