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