]> sourceware.org Git - systemtap.git/blob - tapset-procfs.cxx
Merge branch 'master' into jistone/inode-uprobes
[systemtap.git] / tapset-procfs.cxx
1 // tapset for procfs
2 // Copyright (C) 2005-2010 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 static const string TOK_MAXSIZE("maxsize");
29 static const string TOK_UMASK("umask");
30
31
32 // ------------------------------------------------------------------------
33 // procfs file derived probes
34 // ------------------------------------------------------------------------
35
36
37 struct procfs_derived_probe: public derived_probe
38 {
39 string path;
40 bool write;
41 bool target_symbol_seen;
42 int64_t maxsize_val;
43 int64_t umask;
44
45
46 procfs_derived_probe (systemtap_session &, probe* p, probe_point* l, string ps, bool w, int64_t m, int64_t umask);
47 void join_group (systemtap_session& s);
48 };
49
50
51 struct procfs_probe_set
52 {
53 procfs_derived_probe* read_probe;
54 procfs_derived_probe* write_probe;
55
56 procfs_probe_set () : read_probe (NULL), write_probe (NULL) {}
57 };
58
59
60 struct procfs_derived_probe_group: public generic_dpg<procfs_derived_probe>
61 {
62 private:
63 map<string, procfs_probe_set*> probes_by_path;
64 typedef map<string, procfs_probe_set*>::iterator p_b_p_iterator;
65 bool has_read_probes;
66 bool has_write_probes;
67
68 public:
69 procfs_derived_probe_group () :
70 has_read_probes(false), has_write_probes(false) {}
71
72 void enroll (procfs_derived_probe* probe);
73 void emit_module_decls (systemtap_session& s);
74 void emit_module_init (systemtap_session& s);
75 void emit_module_exit (systemtap_session& s);
76 };
77
78
79 struct procfs_var_expanding_visitor: public var_expanding_visitor
80 {
81 procfs_var_expanding_visitor(systemtap_session& s, const string& pn,
82 string path, bool write_probe);
83
84 systemtap_session& sess;
85 string probe_name;
86 string path;
87 bool write_probe;
88 bool target_symbol_seen;
89
90 void visit_target_symbol (target_symbol* e);
91 };
92
93
94 procfs_derived_probe::procfs_derived_probe (systemtap_session &s, probe* p,
95 probe_point* l, string ps, bool w,
96 int64_t m, int64_t umask):
97 derived_probe(p, l), path(ps), write(w), target_symbol_seen(false),
98 maxsize_val(m), umask(umask)
99 {
100 // Expand local variables in the probe body
101 procfs_var_expanding_visitor v (s, name, path, write);
102 v.replace (this->body);
103 target_symbol_seen = v.target_symbol_seen;
104 }
105
106
107 void
108 procfs_derived_probe::join_group (systemtap_session& s)
109 {
110 if (! s.procfs_derived_probes)
111 {
112 s.procfs_derived_probes = new procfs_derived_probe_group ();
113
114 // Make sure 'struct _stp_procfs_data' is defined early.
115 embeddedcode *ec = new embeddedcode;
116 ec->tok = NULL;
117 ec->code = string("struct _stp_procfs_data {\n")
118 + string(" char *buffer;\n")
119 + string(" size_t bufsize;\n")
120 + string(" size_t count;\n")
121 + string("};\n")
122 + string("#ifndef STP_PROCFS_BUFSIZE\n")
123 + string("#define STP_PROCFS_BUFSIZE MAXSTRINGLEN\n")
124 + string("#endif\n");
125 s.embeds.push_back(ec);
126 }
127 s.procfs_derived_probes->enroll (this);
128 }
129
130
131 void
132 procfs_derived_probe_group::enroll (procfs_derived_probe* p)
133 {
134 procfs_probe_set *pset;
135
136 if (probes_by_path.count(p->path) == 0)
137 {
138 pset = new procfs_probe_set;
139 probes_by_path[p->path] = pset;
140 }
141 else
142 {
143 pset = probes_by_path[p->path];
144
145 // You can only specify 1 read and 1 write probe.
146 if (p->write && pset->write_probe != NULL)
147 throw semantic_error(_("only one write procfs probe can exist for procfs path \"") + p->path + "\"");
148 else if (! p->write && pset->read_probe != NULL)
149 throw semantic_error(_("only one read procfs probe can exist for procfs path \"") + p->path + "\"");
150
151 // XXX: multiple writes should be acceptable
152 }
153
154 if (p->write)
155 {
156 pset->write_probe = p;
157 has_write_probes = true;
158 }
159 else
160 {
161 pset->read_probe = p;
162 has_read_probes = true;
163 }
164 }
165
166
167 void
168 procfs_derived_probe_group::emit_module_decls (systemtap_session& s)
169 {
170 if (probes_by_path.empty())
171 return;
172
173 s.op->newline() << "/* ---- procfs probes ---- */";
174 s.op->newline() << "#include \"procfs.c\"";
175 s.op->newline() << "#include \"procfs-probes.c\"";
176
177 // Emit the procfs probe buffer structure
178 s.op->newline() << "static struct stap_procfs_probe_buffer {";
179 s.op->indent(1);
180 unsigned buf_index = 0; // used for buffer naming
181 for (p_b_p_iterator it = probes_by_path.begin(); it != probes_by_path.end();
182 it++)
183 {
184 procfs_probe_set *pset = it->second;
185 s.op->newline() << "char buf_" << buf_index++;
186
187 if (pset->read_probe != NULL)
188 {
189 if (pset->read_probe->maxsize_val == 0)
190 s.op->line() << "[STP_PROCFS_BUFSIZE];";
191 else
192 s.op->line() << "[" << pset->read_probe->maxsize_val << "];";
193 }
194 else
195 s.op->line() << "[MAXSTRINGLEN];";
196 }
197 s.op->newline(-1) << "} stap_procfs_probe_buffers;";
198
199 // Emit the procfs probe data list
200 s.op->newline() << "static struct stap_procfs_probe stap_procfs_probes[] = {";
201 s.op->indent(1);
202
203 buf_index = 0;
204 for (p_b_p_iterator it = probes_by_path.begin(); it != probes_by_path.end();
205 it++)
206 {
207 procfs_probe_set *pset = it->second;
208
209 s.op->newline() << "{";
210 s.op->line() << " .path=" << lex_cast_qstring (it->first) << ",";
211
212 if (pset->read_probe != NULL)
213 s.op->line() << " .read_probe=" << common_probe_init (pset->read_probe) << ",";
214
215 if (pset->write_probe != NULL)
216 s.op->line() << " .write_probe=" << common_probe_init (pset->write_probe) << ",";
217
218 s.op->line() << " .buffer=stap_procfs_probe_buffers.buf_" << buf_index++ << ",";
219 if (pset->read_probe != NULL)
220 {
221 if (pset->read_probe->maxsize_val == 0)
222 s.op->line() << " .bufsize=STP_PROCFS_BUFSIZE,";
223 else
224 s.op->line() << " .bufsize="
225 << pset->read_probe->maxsize_val << ",";
226 }
227 else
228 s.op->line() << " .bufsize=MAXSTRINGLEN,";
229
230 s.op->line() << " .permissions=" << (((pset->read_probe ? 0444 : 0)
231 | (pset->write_probe ? 0222 : 0)) &~
232 ((pset->read_probe ? pset->read_probe->umask : 0)
233 | (pset->write_probe ? pset->write_probe->umask : 0)))
234 << ",";
235
236 s.op->line() << " },";
237 }
238 s.op->newline(-1) << "};";
239
240 // Output routine to fill in the buffer with our data. Note that we
241 // need to do this even in the case where we have no read probes,
242 // but we can skip most of it then.
243 s.op->newline();
244
245 s.op->newline() << "static int _stp_proc_fill_read_buffer(struct stap_procfs_probe *spp) {";
246 s.op->indent(1);
247 if (has_read_probes)
248 {
249 s.op->newline() << "struct _stp_procfs_data pdata;";
250
251 common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING",
252 "spp->read_probe",
253 "_STP_PROBE_HANDLER_PROCFS");
254
255 s.op->newline() << "pdata.buffer = spp->buffer;";
256 s.op->newline() << "pdata.bufsize = spp->bufsize;";
257 s.op->newline() << "if (c->ips.procfs_data == NULL)";
258 s.op->newline(1) << "c->ips.procfs_data = &pdata;";
259 s.op->newline(-1) << "else {";
260
261 s.op->newline(1) << "if (unlikely (atomic_inc_return (& skipped_count) > MAXSKIPPED)) {";
262 s.op->newline(1) << "atomic_set (& session_state, STAP_SESSION_ERROR);";
263 s.op->newline() << "_stp_exit ();";
264 s.op->newline(-1) << "}";
265 s.op->newline() << "atomic_dec (& c->busy);";
266 s.op->newline() << "goto probe_epilogue;";
267 s.op->newline(-1) << "}";
268
269 // call probe function
270 s.op->newline() << "(*spp->read_probe->ph) (c);";
271
272 // Note that _procfs_value_set copied string data into spp->buffer
273 s.op->newline() << "c->ips.procfs_data = NULL;";
274 s.op->newline() << "spp->needs_fill = 0;";
275 s.op->newline() << "spp->count = strlen(spp->buffer);";
276
277 common_probe_entryfn_epilogue (s.op, true, s.suppress_handler_errors);
278
279 s.op->newline() << "if (spp->needs_fill) {";
280 s.op->newline(1) << "spp->needs_fill = 0;";
281 s.op->newline() << "return -EIO;";
282 s.op->newline(-1) << "}";
283 }
284 s.op->newline() << "return 0;";
285 s.op->newline(-1) << "}";
286
287 // Output routine to read data. Note that we need to do this even
288 // in the case where we have no write probes, but we can skip most
289 // of it then.
290 s.op->newline() << "static int _stp_process_write_buffer(struct stap_procfs_probe *spp, const char __user *buf, size_t count) {";
291 s.op->indent(1);
292 s.op->newline() << "int retval = 0;";
293 if (has_write_probes)
294 {
295 s.op->newline() << "struct _stp_procfs_data pdata;";
296
297 common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING",
298 "spp->write_probe",
299 "_STP_PROBE_HANDLER_PROCFS");
300
301 // We've got 2 problems here. The data count could be greater
302 // than MAXSTRINGLEN or greater than the bufsize (if the same
303 // procfs file had a size less than MAXSTRINGLEN).
304 s.op->newline() << "if (count >= MAXSTRINGLEN)";
305 s.op->newline(1) << "count = MAXSTRINGLEN - 1;";
306 s.op->indent(-1);
307 s.op->newline() << "pdata.bufsize = spp->bufsize;";
308 s.op->newline() << "if (count >= pdata.bufsize)";
309 s.op->newline(1) << "count = pdata.bufsize - 1;";
310 s.op->indent(-1);
311
312 s.op->newline() << "pdata.buffer = (char *)buf;";
313 s.op->newline() << "pdata.count = count;";
314
315 s.op->newline() << "if (c->ips.procfs_data == NULL)";
316 s.op->newline(1) << "c->ips.procfs_data = &pdata;";
317 s.op->newline(-1) << "else {";
318
319 s.op->newline(1) << "if (unlikely (atomic_inc_return (& skipped_count) > MAXSKIPPED)) {";
320 s.op->newline(1) << "atomic_set (& session_state, STAP_SESSION_ERROR);";
321 s.op->newline() << "_stp_exit ();";
322 s.op->newline(-1) << "}";
323 s.op->newline() << "atomic_dec (& c->busy);";
324 s.op->newline() << "goto probe_epilogue;";
325 s.op->newline(-1) << "}";
326
327 // call probe function
328 s.op->newline() << "(*spp->write_probe->ph) (c);";
329
330 s.op->newline() << "c->ips.procfs_data = NULL;";
331 s.op->newline() << "if (c->last_error == 0) {";
332 s.op->newline(1) << "retval = count;";
333 s.op->newline(-1) << "}";
334
335 common_probe_entryfn_epilogue (s.op, true, s.suppress_handler_errors);
336 }
337
338 s.op->newline() << "return retval;";
339 s.op->newline(-1) << "}";
340 }
341
342
343 void
344 procfs_derived_probe_group::emit_module_init (systemtap_session& s)
345 {
346 if (probes_by_path.empty())
347 return;
348
349 s.op->newline() << "for (i = 0; i < " << probes_by_path.size() << "; i++) {";
350 s.op->newline(1) << "struct stap_procfs_probe *spp = &stap_procfs_probes[i];";
351
352 s.op->newline() << "if (spp->read_probe)";
353 s.op->newline(1) << "probe_point = spp->read_probe->pp;";
354 s.op->newline(-1) << "else";
355 s.op->newline(1) << "probe_point = spp->write_probe->pp;";
356 s.op->indent(-1);
357
358 s.op->newline() << "_spp_init(spp);";
359 s.op->newline() << "rc = _stp_create_procfs(spp->path, i, &_stp_proc_fops, spp->permissions);";
360
361 s.op->newline() << "if (rc) {";
362 s.op->newline(1) << "_stp_close_procfs();";
363
364 s.op->newline() << "for (i = 0; i < " << probes_by_path.size() << "; i++) {";
365 s.op->newline(1) << "spp = &stap_procfs_probes[i];";
366 s.op->newline() << "_spp_shutdown(spp);";
367 s.op->newline(-1) << "}";
368 s.op->newline() << "break;";
369 s.op->newline(-1) << "}";
370
371 s.op->newline() << "_stp_procfs_files[i]->data = spp;";
372 s.op->newline(-1) << "}"; // for loop
373 }
374
375
376 void
377 procfs_derived_probe_group::emit_module_exit (systemtap_session& s)
378 {
379 if (probes_by_path.empty())
380 return;
381
382 s.op->newline() << "_stp_close_procfs();";
383 s.op->newline() << "for (i = 0; i < " << probes_by_path.size() << "; i++) {";
384 s.op->newline(1) << "struct stap_procfs_probe *spp = &stap_procfs_probes[i];";
385 s.op->newline() << "_spp_shutdown(spp);";
386 s.op->newline(-1) << "}";
387 }
388
389
390 procfs_var_expanding_visitor::procfs_var_expanding_visitor (systemtap_session& s,
391 const string& pn,
392 string path,
393 bool write_probe):
394 sess (s), probe_name (pn), path (path), write_probe (write_probe),
395 target_symbol_seen (false)
396 {
397 // procfs probes can also handle '.='.
398 valid_ops.insert (".=");
399 }
400
401
402 void
403 procfs_var_expanding_visitor::visit_target_symbol (target_symbol* e)
404 {
405 try
406 {
407 assert(e->name.size() > 0 && e->name[0] == '$');
408
409 if (e->name != "$value")
410 throw semantic_error (_("invalid target symbol for procfs probe, $value expected"),
411 e->tok);
412
413 e->assert_no_components("procfs");
414
415 bool lvalue = is_active_lvalue(e);
416 if (write_probe && lvalue)
417 throw semantic_error(_("procfs $value variable is read-only in a procfs write probe"), e->tok);
418 else if (! write_probe && ! lvalue)
419 throw semantic_error(_("procfs $value variable cannot be read in a procfs read probe"), e->tok);
420
421 if (e->addressof)
422 throw semantic_error(_("cannot take address of procfs variable"), e->tok);
423
424 // Remember that we've seen a target variable.
425 target_symbol_seen = true;
426
427 // Synthesize a function.
428 functiondecl *fdecl = new functiondecl;
429 fdecl->synthetic = true;
430 fdecl->tok = e->tok;
431 embeddedcode *ec = new embeddedcode;
432 ec->tok = e->tok;
433
434 string fname;
435 string locvalue = "CONTEXT->ips.procfs_data";
436
437 if (! lvalue)
438 {
439 fname = "_procfs_value_get";
440 ec->code = string(" struct _stp_procfs_data *data = (struct _stp_procfs_data *)(") + locvalue + string("); /* pure */\n")
441
442 + string(" _stp_copy_from_user(THIS->__retvalue, data->buffer, data->count);\n")
443 + string(" THIS->__retvalue[data->count] = '\\0';\n");
444 }
445 else // lvalue
446 {
447 if (*op == "=")
448 {
449 fname = "_procfs_value_set";
450 ec->code = string("struct _stp_procfs_data *data = (struct _stp_procfs_data *)(") + locvalue + string(");\n")
451 + string(" strlcpy(data->buffer, THIS->value, data->bufsize);\n")
452 + string(" data->count = strlen(data->buffer);\n");
453 }
454 else if (*op == ".=")
455 {
456 fname = "_procfs_value_append";
457 ec->code = string("struct _stp_procfs_data *data = (struct _stp_procfs_data *)(") + locvalue + string(");\n")
458 + string(" strlcat(data->buffer, THIS->value, data->bufsize);\n")
459 + string(" data->count = strlen(data->buffer);\n");
460 }
461 else
462 {
463 throw semantic_error (_("Only the following assign operators are"
464 " implemented on procfs read target variables:"
465 " '=', '.='"), e->tok);
466 }
467 }
468 fname += lex_cast(++tick);
469
470 fdecl->name = fname;
471 fdecl->body = ec;
472 fdecl->type = pe_string;
473
474 if (lvalue)
475 {
476 // Modify the fdecl so it carries a single pe_string formal
477 // argument called "value".
478
479 vardecl *v = new vardecl;
480 v->type = pe_string;
481 v->name = "value";
482 v->tok = e->tok;
483 fdecl->formal_args.push_back(v);
484 }
485 fdecl->join (sess);
486
487 // Synthesize a functioncall.
488 functioncall* n = new functioncall;
489 n->tok = e->tok;
490 n->function = fname;
491
492 if (lvalue)
493 {
494 // Provide the functioncall to our parent, so that it can be
495 // used to substitute for the assignment node immediately above
496 // us.
497 assert(!target_symbol_setter_functioncalls.empty());
498 *(target_symbol_setter_functioncalls.top()) = n;
499 }
500
501 provide (n);
502 }
503 catch (const semantic_error &er)
504 {
505 e->chain (er);
506 provide (e);
507 }
508 }
509
510
511 struct procfs_builder: public derived_probe_builder
512 {
513 procfs_builder() {}
514 virtual void build(systemtap_session & sess,
515 probe * base,
516 probe_point * location,
517 literal_map_t const & parameters,
518 vector<derived_probe *> & finished_results);
519 };
520
521
522 void
523 procfs_builder::build(systemtap_session & sess,
524 probe * base,
525 probe_point * location,
526 literal_map_t const & parameters,
527 vector<derived_probe *> & finished_results)
528 {
529 string path;
530 bool has_procfs = get_param(parameters, TOK_PROCFS, path);
531 bool has_read = (parameters.find(TOK_READ) != parameters.end());
532 bool has_write = (parameters.find(TOK_WRITE) != parameters.end());
533 bool has_umask = (parameters.find(TOK_UMASK) != parameters.end());
534 int64_t maxsize_val = 0;
535 int64_t umask_val;
536 if(has_umask)
537 get_param(parameters, TOK_UMASK, umask_val);
538 else /* no .umask */
539 {
540 if(has_read)
541 umask_val = 0044;
542 else if(has_write)
543 umask_val = 0022;
544 else
545 assert(0);
546 }
547 // Validate '.maxsize(NNN)', if it exists.
548 if (get_param(parameters, TOK_MAXSIZE, maxsize_val))
549 {
550 if (maxsize_val <= 0)
551 throw semantic_error (_("maxsize must be greater than 0"));
552 }
553
554 // If no procfs path, default to "command". The runtime will do
555 // this for us, but if we don't do it here, we'll think the
556 // following 2 probes are attached to different paths:
557 //
558 // probe procfs("command").read {}"
559 // probe procfs.write {}
560
561 if (! has_procfs)
562 path = "command";
563 // If we have a path, we need to validate it.
564 else
565 {
566 string::size_type start_pos, end_pos;
567 string component;
568 start_pos = 0;
569 while ((end_pos = path.find('/', start_pos)) != string::npos)
570 {
571 // Make sure it doesn't start with '/'.
572 if (end_pos == 0)
573 throw semantic_error (_("procfs path cannot start with a '/'"),
574 location->components.front()->tok);
575
576 component = path.substr(start_pos, end_pos - start_pos);
577 // Make sure it isn't empty.
578 if (component.size() == 0)
579 throw semantic_error (_("procfs path component cannot be empty"),
580 location->components.front()->tok);
581 // Make sure it isn't relative.
582 else if (component == "." || component == "..")
583 throw semantic_error (_("procfs path cannot be relative (and contain '.' or '..')"), location->components.front()->tok);
584
585 start_pos = end_pos + 1;
586 }
587 component = path.substr(start_pos);
588 // Make sure it doesn't end with '/'.
589 if (component.size() == 0)
590 throw semantic_error (_("procfs path cannot end with a '/'"), location->components.front()->tok);
591 // Make sure it isn't relative.
592 else if (component == "." || component == "..")
593 throw semantic_error (_("procfs path cannot be relative (and contain '.' or '..')"), location->components.front()->tok);
594 }
595
596 if (!(has_read ^ has_write))
597 throw semantic_error (_("need read/write component"), location->components.front()->tok);
598
599 finished_results.push_back(new procfs_derived_probe(sess, base, location,
600 path, has_write,
601 maxsize_val, umask_val));
602 }
603
604
605 void
606 register_tapset_procfs(systemtap_session& s)
607 {
608 match_node* root = s.pattern_root;
609 derived_probe_builder *builder = new procfs_builder();
610
611 root->bind(TOK_PROCFS)->bind(TOK_READ)->bind(builder);
612 root->bind(TOK_PROCFS)->bind_num(TOK_UMASK)->bind(TOK_READ)->bind(builder);
613 root->bind(TOK_PROCFS)->bind(TOK_READ)->bind_num(TOK_MAXSIZE)->bind(builder);
614 root->bind(TOK_PROCFS)->bind_num(TOK_UMASK)->bind(TOK_READ)->bind_num(TOK_MAXSIZE)->bind(builder);
615 root->bind_str(TOK_PROCFS)->bind(TOK_READ)->bind(builder);
616 root->bind_str(TOK_PROCFS)->bind_num(TOK_UMASK)->bind(TOK_READ)->bind(builder);
617 root->bind_str(TOK_PROCFS)->bind(TOK_READ)->bind_num(TOK_MAXSIZE)->bind(builder);
618 root->bind_str(TOK_PROCFS)->bind_num(TOK_UMASK)->bind(TOK_READ)->bind_num(TOK_MAXSIZE)->bind(builder);
619
620 root->bind(TOK_PROCFS)->bind(TOK_WRITE)->bind(builder);
621 root->bind(TOK_PROCFS)->bind_num(TOK_UMASK)->bind(TOK_WRITE)->bind(builder);
622 root->bind_str(TOK_PROCFS)->bind(TOK_WRITE)->bind(builder);
623 root->bind_str(TOK_PROCFS)->bind_num(TOK_UMASK)->bind(TOK_WRITE)->bind(builder);
624 }
625
626
627
628 /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
This page took 0.071731 seconds and 6 git commands to generate.