]> sourceware.org Git - systemtap.git/blame - tapset-itrace.cxx
tracepoints: Work with the tracequery's .o rather than .ko
[systemtap.git] / tapset-itrace.cxx
CommitLineData
93646f4d
JS
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
22using namespace std;
23using namespace __gnu_cxx;
24
25
4627ed58
JS
26static const string TOK_PROCESS("process");
27static const string TOK_INSN("insn");
28static const string TOK_BLOCK("block");
93646f4d
JS
29
30
31// ------------------------------------------------------------------------
32// itrace user-space probes
33// ------------------------------------------------------------------------
34
35
36struct 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
50struct itrace_derived_probe_group: public generic_dpg<itrace_derived_probe>
51{
52private:
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
61public:
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
71itrace_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{
e34d5d13 78 if (s.kernel_config["CONFIG_UTRACE"] != string("y"))
efee9a98 79 throw semantic_error (_("process probes not available without kernel CONFIG_UTRACE"));
93646f4d
JS
80}
81
82
83void
84itrace_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
94struct 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)
671ceda8
FCE
116 {
117 path = find_executable (path);
118 sess.unwindsym_modules.insert (path);
119 }
93646f4d
JS
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
129void
130itrace_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
144void
145itrace_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 {
b6921d59 153 s.op->line() << " .procname=\"" << p->path << "\",";
93646f4d
JS
154 s.op->line() << " .pid=0,";
155 }
156 else
157 {
b6921d59 158 s.op->line() << " .procname=NULL,";
93646f4d
JS
159 s.op->line() << " .pid=" << p->pid << ",";
160 }
161
162 s.op->line() << " .callback=&_stp_itrace_probe_cb,";
163 s.op->line() << " },";
faea5e16 164 s.op->line() << " .probe=" << common_probe_init (p) << ",";
93646f4d 165 s.op->line() << " .single_step=" << p->single_step << ",";
93646f4d
JS
166 s.op->line() << " },";
167}
168
169
170void
171itrace_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;";
26e63673 182 s.op->newline() << "struct stap_probe * const probe;";
93646f4d
JS
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
6eefe942
MW
192 common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "p->probe",
193 "_STP_PROBE_HANDLER_ITRACE");
d9aed31e 194 s.op->newline() << "c->uregs = regs;";
92c25572 195 s.op->newline() << "c->probe_flags |= _STP_PROBE_STATE_USER_MODE;";
93646f4d
JS
196
197 // call probe function
26e63673 198 s.op->newline() << "(*p->probe->ph) (c);";
93646f4d
JS
199 common_probe_entryfn_epilogue (s.op);
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
c8a44dea 214 s.op->newline() << "rc = usr_itrace_init(p->single_step, tsk, p);";
93646f4d 215 s.op->newline(-1) << "else";
4f600a5f 216 s.op->newline(1) << "remove_usr_itrace_info(find_itrace_info(tsk));";
93646f4d
JS
217 s.op->newline(-1) << "return rc;";
218 s.op->newline(-1) << "}";
219
93646f4d
JS
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
254void
255itrace_derived_probe_group::emit_module_init (systemtap_session& s)
256{
257 if (probes_by_path.empty() && probes_by_pid.empty())
258 return;
259
93646f4d
JS
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
287void
288itrace_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
296void
297register_tapset_itrace(systemtap_session& s)
298{
299 match_node* root = s.pattern_root;
300 derived_probe_builder *builder = new itrace_builder();
301
d2c9ec9b 302 root->bind_str(TOK_PROCESS)->bind(TOK_INSN)
d2c9ec9b
DB
303 ->bind(builder);
304 root->bind_num(TOK_PROCESS)->bind(TOK_INSN)
d2c9ec9b
DB
305 ->bind(builder);
306 root->bind_str(TOK_PROCESS)->bind(TOK_INSN)->bind(TOK_BLOCK)
d2c9ec9b
DB
307 ->bind(builder);
308 root->bind_num(TOK_PROCESS)->bind(TOK_INSN)->bind(TOK_BLOCK)
d2c9ec9b 309 ->bind(builder);
93646f4d
JS
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.102588 seconds and 5 git commands to generate.