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