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