]> sourceware.org Git - systemtap.git/blob - tapset-procfs.cxx
Merge branch 'master' of git://sources.redhat.com/git/systemtap
[systemtap.git] / tapset-procfs.cxx
1 // tapset for procfs
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 "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 static const string TOK_PROCFS("procfs");
26 static const string TOK_READ("read");
27 static const string TOK_WRITE("write");
28
29
30 // ------------------------------------------------------------------------
31 // procfs file derived probes
32 // ------------------------------------------------------------------------
33
34
35 struct procfs_derived_probe: public derived_probe
36 {
37 string path;
38 bool write;
39 bool target_symbol_seen;
40
41 procfs_derived_probe (systemtap_session &, probe* p, probe_point* l, string ps, bool w);
42 void join_group (systemtap_session& s);
43 };
44
45
46 struct procfs_probe_set
47 {
48 procfs_derived_probe* read_probe;
49 procfs_derived_probe* write_probe;
50
51 procfs_probe_set () : read_probe (NULL), write_probe (NULL) {}
52 };
53
54
55 struct procfs_derived_probe_group: public generic_dpg<procfs_derived_probe>
56 {
57 private:
58 map<string, procfs_probe_set*> probes_by_path;
59 typedef map<string, procfs_probe_set*>::iterator p_b_p_iterator;
60 bool has_read_probes;
61 bool has_write_probes;
62
63 public:
64 procfs_derived_probe_group () :
65 has_read_probes(false), has_write_probes(false) {}
66
67 void enroll (procfs_derived_probe* probe);
68 void emit_module_decls (systemtap_session& s);
69 void emit_module_init (systemtap_session& s);
70 void emit_module_exit (systemtap_session& s);
71 };
72
73
74 struct procfs_var_expanding_visitor: public var_expanding_visitor
75 {
76 procfs_var_expanding_visitor(systemtap_session& s, const string& pn,
77 string path, bool write_probe):
78 sess (s), probe_name (pn), path (path), write_probe (write_probe),
79 target_symbol_seen (false) {}
80
81 systemtap_session& sess;
82 string probe_name;
83 string path;
84 bool write_probe;
85 bool target_symbol_seen;
86
87 void visit_target_symbol (target_symbol* e);
88 };
89
90
91 procfs_derived_probe::procfs_derived_probe (systemtap_session &s, probe* p,
92 probe_point* l, string ps, bool w):
93 derived_probe(p, l), path(ps), write(w), target_symbol_seen(false)
94 {
95 // Expand local variables in the probe body
96 procfs_var_expanding_visitor v (s, name, path, write);
97 this->body = v.require (this->body);
98 target_symbol_seen = v.target_symbol_seen;
99 }
100
101
102 void
103 procfs_derived_probe::join_group (systemtap_session& s)
104 {
105 if (! s.procfs_derived_probes)
106 {
107 s.procfs_derived_probes = new procfs_derived_probe_group ();
108
109 // Make sure 'struct _stp_procfs_data' is defined early.
110 embeddedcode *ec = new embeddedcode;
111 ec->tok = NULL;
112 ec->code = string("struct _stp_procfs_data {\n")
113 + string(" const char *buffer;\n")
114 + string(" off_t off;\n")
115 + string(" unsigned long count;\n")
116 + string("};\n");
117 s.embeds.push_back(ec);
118 }
119 s.procfs_derived_probes->enroll (this);
120 }
121
122
123 void
124 procfs_derived_probe_group::enroll (procfs_derived_probe* p)
125 {
126 procfs_probe_set *pset;
127
128 if (probes_by_path.count(p->path) == 0)
129 {
130 pset = new procfs_probe_set;
131 probes_by_path[p->path] = pset;
132 }
133 else
134 {
135 pset = probes_by_path[p->path];
136
137 // You can only specify 1 read and 1 write probe.
138 if (p->write && pset->write_probe != NULL)
139 throw semantic_error("only one write procfs probe can exist for procfs path \"" + p->path + "\"");
140 else if (! p->write && pset->read_probe != NULL)
141 throw semantic_error("only one read procfs probe can exist for procfs path \"" + p->path + "\"");
142
143 // XXX: multiple writes should be acceptable
144 }
145
146 if (p->write)
147 {
148 pset->write_probe = p;
149 has_write_probes = true;
150 }
151 else
152 {
153 pset->read_probe = p;
154 has_read_probes = true;
155 }
156 }
157
158
159 void
160 procfs_derived_probe_group::emit_module_decls (systemtap_session& s)
161 {
162 if (probes_by_path.empty())
163 return;
164
165 s.op->newline() << "/* ---- procfs probes ---- */";
166 s.op->newline() << "#include \"procfs.c\"";
167
168 // Emit the procfs probe data list
169 s.op->newline() << "static struct stap_procfs_probe {";
170 s.op->newline(1)<< "const char *path;";
171 s.op->newline() << "const char *read_pp;";
172 s.op->newline() << "void (*read_ph) (struct context*);";
173 s.op->newline() << "const char *write_pp;";
174 s.op->newline() << "void (*write_ph) (struct context*);";
175 s.op->newline(-1) << "} stap_procfs_probes[] = {";
176 s.op->indent(1);
177
178 for (p_b_p_iterator it = probes_by_path.begin(); it != probes_by_path.end();
179 it++)
180 {
181 procfs_probe_set *pset = it->second;
182
183 s.op->newline() << "{";
184 s.op->line() << " .path=" << lex_cast_qstring (it->first) << ",";
185
186 if (pset->read_probe != NULL)
187 {
188 s.op->line() << " .read_pp="
189 << lex_cast_qstring (*pset->read_probe->sole_location())
190 << ",";
191 s.op->line() << " .read_ph=&" << pset->read_probe->name << ",";
192 }
193 else
194 {
195 s.op->line() << " .read_pp=NULL,";
196 s.op->line() << " .read_ph=NULL,";
197 }
198
199 if (pset->write_probe != NULL)
200 {
201 s.op->line() << " .write_pp="
202 << lex_cast_qstring (*pset->write_probe->sole_location())
203 << ",";
204 s.op->line() << " .write_ph=&" << pset->write_probe->name;
205 }
206 else
207 {
208 s.op->line() << " .write_pp=NULL,";
209 s.op->line() << " .write_ph=NULL";
210 }
211 s.op->line() << " },";
212 }
213 s.op->newline(-1) << "};";
214
215 if (has_read_probes)
216 {
217 // Output routine to fill in 'page' with our data.
218 s.op->newline();
219
220 s.op->newline() << "static int _stp_procfs_read(char *page, char **start, off_t off, int count, int *eof, void *data) {";
221
222 s.op->newline(1) << "struct stap_procfs_probe *spp = (struct stap_procfs_probe *)data;";
223 s.op->newline() << "struct _stp_procfs_data pdata;";
224
225 common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "spp->read_pp");
226
227 s.op->newline() << "pdata.buffer = page;";
228 s.op->newline() << "pdata.off = off;";
229 s.op->newline() << "pdata.count = count;";
230 s.op->newline() << "if (c->data == NULL)";
231 s.op->newline(1) << "c->data = &pdata;";
232 s.op->newline(-1) << "else {";
233
234 s.op->newline(1) << "if (unlikely (atomic_inc_return (& skipped_count) > MAXSKIPPED)) {";
235 s.op->newline(1) << "atomic_set (& session_state, STAP_SESSION_ERROR);";
236 s.op->newline() << "_stp_exit ();";
237 s.op->newline(-1) << "}";
238 s.op->newline() << "atomic_dec (& c->busy);";
239 s.op->newline() << "goto probe_epilogue;";
240 s.op->newline(-1) << "}";
241
242 // call probe function
243 s.op->newline() << "(*spp->read_ph) (c);";
244
245 // Note that _procfs_value_set copied string data into 'page'
246 s.op->newline() << "c->data = NULL;";
247 common_probe_entryfn_epilogue (s.op);
248 s.op->newline() << "if (pdata.count == 0)";
249 s.op->newline(1) << "*eof = 1;";
250 s.op->indent(-1);
251 s.op->newline() << "return pdata.count;";
252
253 s.op->newline(-1) << "}";
254 }
255 if (has_write_probes)
256 {
257 s.op->newline() << "static int _stp_procfs_write(struct file *file, const char *buffer, unsigned long count, void *data) {";
258
259 s.op->newline(1) << "struct stap_procfs_probe *spp = (struct stap_procfs_probe *)data;";
260 s.op->newline() << "struct _stp_procfs_data pdata;";
261
262 common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "spp->write_pp");
263
264 s.op->newline() << "if (count > (MAXSTRINGLEN - 1))";
265 s.op->newline(1) << "count = MAXSTRINGLEN - 1;";
266 s.op->indent(-1);
267 s.op->newline() << "pdata.buffer = buffer;";
268 s.op->newline() << "pdata.count = count;";
269
270 s.op->newline() << "if (c->data == NULL)";
271 s.op->newline(1) << "c->data = &pdata;";
272 s.op->newline(-1) << "else {";
273
274 s.op->newline(1) << "if (unlikely (atomic_inc_return (& skipped_count) > MAXSKIPPED)) {";
275 s.op->newline(1) << "atomic_set (& session_state, STAP_SESSION_ERROR);";
276 s.op->newline() << "_stp_exit ();";
277 s.op->newline(-1) << "}";
278 s.op->newline() << "atomic_dec (& c->busy);";
279 s.op->newline() << "goto probe_epilogue;";
280 s.op->newline(-1) << "}";
281
282 // call probe function
283 s.op->newline() << "(*spp->write_ph) (c);";
284
285 s.op->newline() << "c->data = NULL;";
286 common_probe_entryfn_epilogue (s.op);
287
288 s.op->newline() << "return count;";
289 s.op->newline(-1) << "}";
290 }
291 }
292
293
294 void
295 procfs_derived_probe_group::emit_module_init (systemtap_session& s)
296 {
297 if (probes_by_path.empty())
298 return;
299
300 s.op->newline() << "for (i = 0; i < " << probes_by_path.size() << "; i++) {";
301 s.op->newline(1) << "struct stap_procfs_probe *spp = &stap_procfs_probes[i];";
302
303 s.op->newline() << "if (spp->read_pp)";
304 s.op->newline(1) << "probe_point = spp->read_pp;";
305 s.op->newline(-1) << "else";
306 s.op->newline(1) << "probe_point = spp->write_pp;";
307
308 s.op->newline(-1) << "rc = _stp_create_procfs(spp->path, i);";
309
310 s.op->newline() << "if (rc) {";
311 s.op->newline(1) << "_stp_close_procfs();";
312 s.op->newline() << "break;";
313 s.op->newline(-1) << "}";
314
315 if (has_read_probes)
316 {
317 s.op->newline() << "if (spp->read_pp)";
318 s.op->newline(1) << "_stp_procfs_files[i]->read_proc = &_stp_procfs_read;";
319 s.op->newline(-1) << "else";
320 s.op->newline(1) << "_stp_procfs_files[i]->read_proc = NULL;";
321 s.op->indent(-1);
322 }
323 else
324 s.op->newline() << "_stp_procfs_files[i]->read_proc = NULL;";
325
326 if (has_write_probes)
327 {
328 s.op->newline() << "if (spp->write_pp)";
329 s.op->newline(1) << "_stp_procfs_files[i]->write_proc = &_stp_procfs_write;";
330 s.op->newline(-1) << "else";
331 s.op->newline(1) << "_stp_procfs_files[i]->write_proc = NULL;";
332 s.op->indent(-1);
333 }
334 else
335 s.op->newline() << "_stp_procfs_files[i]->write_proc = NULL;";
336
337 s.op->newline() << "_stp_procfs_files[i]->data = spp;";
338 s.op->newline(-1) << "}"; // for loop
339 }
340
341
342 void
343 procfs_derived_probe_group::emit_module_exit (systemtap_session& s)
344 {
345 if (probes_by_path.empty())
346 return;
347
348 s.op->newline() << "_stp_close_procfs();";
349 }
350
351
352 void
353 procfs_var_expanding_visitor::visit_target_symbol (target_symbol* e)
354 {
355 assert(e->base_name.size() > 0 && e->base_name[0] == '$');
356
357 if (e->base_name != "$value")
358 throw semantic_error ("invalid target symbol for procfs probe, $value expected",
359 e->tok);
360
361 if (e->components.size() > 0)
362 {
363 switch (e->components[0].first)
364 {
365 case target_symbol::comp_literal_array_index:
366 throw semantic_error("procfs target variable '$value' may not be used as array",
367 e->tok);
368 break;
369 case target_symbol::comp_struct_member:
370 throw semantic_error("procfs target variable '$value' may not be used as a structure",
371 e->tok);
372 break;
373 default:
374 throw semantic_error ("invalid use of procfs target variable '$value'",
375 e->tok);
376 break;
377 }
378 }
379
380 bool lvalue = is_active_lvalue(e);
381 if (write_probe && lvalue)
382 throw semantic_error("procfs $value variable is read-only in a procfs write probe", e->tok);
383 else if (! write_probe && ! lvalue)
384 throw semantic_error("procfs $value variable cannot be read in a procfs read probe", e->tok);
385
386 // Remember that we've seen a target variable.
387 target_symbol_seen = true;
388
389 // Synthesize a function.
390 functiondecl *fdecl = new functiondecl;
391 fdecl->tok = e->tok;
392 embeddedcode *ec = new embeddedcode;
393 ec->tok = e->tok;
394
395 string fname = (string(lvalue ? "_procfs_value_set" : "_procfs_value_get")
396 + "_" + lex_cast<string>(tick++));
397 string locvalue = "CONTEXT->data";
398
399 if (! lvalue)
400 ec->code = string("_stp_copy_from_user(THIS->__retvalue, ((struct _stp_procfs_data *)(")
401 + locvalue + string("))->buffer, ((struct _stp_procfs_data *)(") + locvalue
402 + string("))->count); /* pure */");
403 else
404 ec->code = string("int bytes = 0;\n")
405 + string(" struct _stp_procfs_data *data = (struct _stp_procfs_data *)(") + locvalue + string(");\n")
406 + string(" bytes = strnlen(THIS->value, MAXSTRINGLEN - 1);\n")
407 + string(" if (data->off >= bytes)\n")
408 + string(" bytes = 0;\n")
409 + string(" else {\n")
410 + string(" bytes -= data->off;\n")
411 + string(" if (bytes > data->count)\n")
412 + string(" bytes = data->count;\n")
413 + string(" memcpy((void *)data->buffer, THIS->value + data->off, bytes);\n")
414 + string(" }\n")
415 + string(" data->count = bytes;\n");
416
417 fdecl->name = fname;
418 fdecl->body = ec;
419 fdecl->type = pe_string;
420
421 if (lvalue)
422 {
423 // Modify the fdecl so it carries a single pe_string formal
424 // argument called "value".
425
426 vardecl *v = new vardecl;
427 v->type = pe_string;
428 v->name = "value";
429 v->tok = e->tok;
430 fdecl->formal_args.push_back(v);
431 }
432 sess.functions[fdecl->name]=fdecl;
433
434 // Synthesize a functioncall.
435 functioncall* n = new functioncall;
436 n->tok = e->tok;
437 n->function = fname;
438 n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session
439
440 if (lvalue)
441 {
442 // Provide the functioncall to our parent, so that it can be
443 // used to substitute for the assignment node immediately above
444 // us.
445 assert(!target_symbol_setter_functioncalls.empty());
446 *(target_symbol_setter_functioncalls.top()) = n;
447 }
448
449 provide (n);
450 }
451
452
453 struct procfs_builder: public derived_probe_builder
454 {
455 procfs_builder() {}
456 virtual void build(systemtap_session & sess,
457 probe * base,
458 probe_point * location,
459 literal_map_t const & parameters,
460 vector<derived_probe *> & finished_results);
461 };
462
463
464 void
465 procfs_builder::build(systemtap_session & sess,
466 probe * base,
467 probe_point * location,
468 literal_map_t const & parameters,
469 vector<derived_probe *> & finished_results)
470 {
471 string path;
472 bool has_procfs = get_param(parameters, TOK_PROCFS, path);
473 bool has_read = (parameters.find(TOK_READ) != parameters.end());
474 bool has_write = (parameters.find(TOK_WRITE) != parameters.end());
475
476 // If no procfs path, default to "command". The runtime will do
477 // this for us, but if we don't do it here, we'll think the
478 // following 2 probes are attached to different paths:
479 //
480 // probe procfs("command").read {}"
481 // probe procfs.write {}
482
483 if (! has_procfs)
484 path = "command";
485 // If we have a path, we need to validate it.
486 else
487 {
488 string::size_type start_pos, end_pos;
489 string component;
490 start_pos = 0;
491 while ((end_pos = path.find('/', start_pos)) != string::npos)
492 {
493 // Make sure it doesn't start with '/'.
494 if (end_pos == 0)
495 throw semantic_error ("procfs path cannot start with a '/'",
496 location->tok);
497
498 component = path.substr(start_pos, end_pos - start_pos);
499 // Make sure it isn't empty.
500 if (component.size() == 0)
501 throw semantic_error ("procfs path component cannot be empty",
502 location->tok);
503 // Make sure it isn't relative.
504 else if (component == "." || component == "..")
505 throw semantic_error ("procfs path cannot be relative (and contain '.' or '..')", location->tok);
506
507 start_pos = end_pos + 1;
508 }
509 component = path.substr(start_pos);
510 // Make sure it doesn't end with '/'.
511 if (component.size() == 0)
512 throw semantic_error ("procfs path cannot end with a '/'", location->tok);
513 // Make sure it isn't relative.
514 else if (component == "." || component == "..")
515 throw semantic_error ("procfs path cannot be relative (and contain '.' or '..')", location->tok);
516 }
517
518 if (!(has_read ^ has_write))
519 throw semantic_error ("need read/write component", location->tok);
520
521 finished_results.push_back(new procfs_derived_probe(sess, base, location,
522 path, has_write));
523 }
524
525
526 void
527 register_tapset_procfs(systemtap_session& s)
528 {
529 match_node* root = s.pattern_root;
530 derived_probe_builder *builder = new procfs_builder();
531
532 root->bind(TOK_PROCFS)->bind(TOK_READ)->bind(builder);
533 root->bind_str(TOK_PROCFS)->bind(TOK_READ)->bind(builder);
534 root->bind(TOK_PROCFS)->bind(TOK_WRITE)->bind(builder);
535 root->bind_str(TOK_PROCFS)->bind(TOK_WRITE)->bind(builder);
536 }
537
538
539
540 /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
This page took 0.078063 seconds and 6 git commands to generate.