2 // Copyright (C) 2005-2009 Red Hat Inc.
3 // Copyright (C) 2005-2007 Intel Corporation.
4 // Copyright (C) 2008 James.Bottomley@HansenPartnership.com
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
14 #include "translate.h"
22 using namespace __gnu_cxx
;
25 static const string
TOK_PROCFS("procfs");
26 static const string
TOK_READ("read");
27 static const string
TOK_WRITE("write");
30 // ------------------------------------------------------------------------
31 // procfs file derived probes
32 // ------------------------------------------------------------------------
35 struct procfs_derived_probe
: public derived_probe
39 bool target_symbol_seen
;
41 procfs_derived_probe (systemtap_session
&, probe
* p
, probe_point
* l
, string ps
, bool w
);
42 void join_group (systemtap_session
& s
);
46 struct procfs_probe_set
48 procfs_derived_probe
* read_probe
;
49 procfs_derived_probe
* write_probe
;
51 procfs_probe_set () : read_probe (NULL
), write_probe (NULL
) {}
55 struct procfs_derived_probe_group
: public generic_dpg
<procfs_derived_probe
>
58 map
<string
, procfs_probe_set
*> probes_by_path
;
59 typedef map
<string
, procfs_probe_set
*>::iterator p_b_p_iterator
;
61 bool has_write_probes
;
64 procfs_derived_probe_group () :
65 has_read_probes(false), has_write_probes(false) {}
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
);
74 struct procfs_var_expanding_visitor
: public var_expanding_visitor
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) {}
81 systemtap_session
& sess
;
85 bool target_symbol_seen
;
87 void visit_target_symbol (target_symbol
* e
);
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)
95 // Expand local variables in the probe body
96 procfs_var_expanding_visitor
v (s
, name
, path
, write
);
97 v
.replace (this->body
);
98 target_symbol_seen
= v
.target_symbol_seen
;
103 procfs_derived_probe::join_group (systemtap_session
& s
)
105 if (! s
.procfs_derived_probes
)
107 s
.procfs_derived_probes
= new procfs_derived_probe_group ();
109 // Make sure 'struct _stp_procfs_data' is defined early.
110 embeddedcode
*ec
= new embeddedcode
;
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")
117 s
.embeds
.push_back(ec
);
119 s
.procfs_derived_probes
->enroll (this);
124 procfs_derived_probe_group::enroll (procfs_derived_probe
* p
)
126 procfs_probe_set
*pset
;
128 if (probes_by_path
.count(p
->path
) == 0)
130 pset
= new procfs_probe_set
;
131 probes_by_path
[p
->path
] = pset
;
135 pset
= probes_by_path
[p
->path
];
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
+ "\"");
143 // XXX: multiple writes should be acceptable
148 pset
->write_probe
= p
;
149 has_write_probes
= true;
153 pset
->read_probe
= p
;
154 has_read_probes
= true;
160 procfs_derived_probe_group::emit_module_decls (systemtap_session
& s
)
162 if (probes_by_path
.empty())
165 s
.op
->newline() << "/* ---- procfs probes ---- */";
166 s
.op
->newline() << "#include \"procfs.c\"";
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[] = {";
178 for (p_b_p_iterator it
= probes_by_path
.begin(); it
!= probes_by_path
.end();
181 procfs_probe_set
*pset
= it
->second
;
183 s
.op
->newline() << "{";
184 s
.op
->line() << " .path=" << lex_cast_qstring (it
->first
) << ",";
186 if (pset
->read_probe
!= NULL
)
188 s
.op
->line() << " .read_pp="
189 << lex_cast_qstring (*pset
->read_probe
->sole_location())
191 s
.op
->line() << " .read_ph=&" << pset
->read_probe
->name
<< ",";
195 s
.op
->line() << " .read_pp=NULL,";
196 s
.op
->line() << " .read_ph=NULL,";
199 if (pset
->write_probe
!= NULL
)
201 s
.op
->line() << " .write_pp="
202 << lex_cast_qstring (*pset
->write_probe
->sole_location())
204 s
.op
->line() << " .write_ph=&" << pset
->write_probe
->name
;
208 s
.op
->line() << " .write_pp=NULL,";
209 s
.op
->line() << " .write_ph=NULL";
211 s
.op
->line() << " },";
213 s
.op
->newline(-1) << "};";
217 // Output routine to fill in 'page' with our data.
220 s
.op
->newline() << "static int _stp_procfs_read(char *page, char **start, off_t off, int count, int *eof, void *data) {";
222 s
.op
->newline(1) << "struct stap_procfs_probe *spp = (struct stap_procfs_probe *)data;";
223 s
.op
->newline() << "struct _stp_procfs_data pdata;";
225 common_probe_entryfn_prologue (s
.op
, "STAP_SESSION_RUNNING", "spp->read_pp");
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 {";
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) << "}";
242 // call probe function
243 s
.op
->newline() << "(*spp->read_ph) (c);";
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;";
251 s
.op
->newline() << "return pdata.count;";
253 s
.op
->newline(-1) << "}";
255 if (has_write_probes
)
257 s
.op
->newline() << "static int _stp_procfs_write(struct file *file, const char *buffer, unsigned long count, void *data) {";
259 s
.op
->newline(1) << "struct stap_procfs_probe *spp = (struct stap_procfs_probe *)data;";
260 s
.op
->newline() << "struct _stp_procfs_data pdata;";
262 common_probe_entryfn_prologue (s
.op
, "STAP_SESSION_RUNNING", "spp->write_pp");
264 s
.op
->newline() << "if (count > (MAXSTRINGLEN - 1))";
265 s
.op
->newline(1) << "count = MAXSTRINGLEN - 1;";
267 s
.op
->newline() << "pdata.buffer = buffer;";
268 s
.op
->newline() << "pdata.count = count;";
270 s
.op
->newline() << "if (c->data == NULL)";
271 s
.op
->newline(1) << "c->data = &pdata;";
272 s
.op
->newline(-1) << "else {";
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) << "}";
282 // call probe function
283 s
.op
->newline() << "(*spp->write_ph) (c);";
285 s
.op
->newline() << "c->data = NULL;";
286 common_probe_entryfn_epilogue (s
.op
);
288 s
.op
->newline() << "return count;";
289 s
.op
->newline(-1) << "}";
295 procfs_derived_probe_group::emit_module_init (systemtap_session
& s
)
297 if (probes_by_path
.empty())
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];";
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;";
308 s
.op
->newline(-1) << "rc = _stp_create_procfs(spp->path, i);";
310 s
.op
->newline() << "if (rc) {";
311 s
.op
->newline(1) << "_stp_close_procfs();";
312 s
.op
->newline() << "break;";
313 s
.op
->newline(-1) << "}";
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;";
324 s
.op
->newline() << "_stp_procfs_files[i]->read_proc = NULL;";
326 if (has_write_probes
)
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;";
335 s
.op
->newline() << "_stp_procfs_files[i]->write_proc = NULL;";
337 s
.op
->newline() << "_stp_procfs_files[i]->data = spp;";
338 s
.op
->newline(-1) << "}"; // for loop
343 procfs_derived_probe_group::emit_module_exit (systemtap_session
& s
)
345 if (probes_by_path
.empty())
348 s
.op
->newline() << "_stp_close_procfs();";
353 procfs_var_expanding_visitor::visit_target_symbol (target_symbol
* e
)
355 assert(e
->base_name
.size() > 0 && e
->base_name
[0] == '$');
357 if (e
->base_name
!= "$value")
358 throw semantic_error ("invalid target symbol for procfs probe, $value expected",
361 e
->assert_no_components("procfs");
363 bool lvalue
= is_active_lvalue(e
);
364 if (write_probe
&& lvalue
)
365 throw semantic_error("procfs $value variable is read-only in a procfs write probe", e
->tok
);
366 else if (! write_probe
&& ! lvalue
)
367 throw semantic_error("procfs $value variable cannot be read in a procfs read probe", e
->tok
);
370 throw semantic_error("cannot take address of procfs variable", e
->tok
);
372 // Remember that we've seen a target variable.
373 target_symbol_seen
= true;
375 // Synthesize a function.
376 functiondecl
*fdecl
= new functiondecl
;
378 embeddedcode
*ec
= new embeddedcode
;
381 string fname
= (string(lvalue
? "_procfs_value_set" : "_procfs_value_get")
382 + "_" + lex_cast(tick
++));
383 string locvalue
= "CONTEXT->data";
386 ec
->code
= string(" struct _stp_procfs_data *data = (struct _stp_procfs_data *)(") + locvalue
+ string("); /* pure */\n")
388 + string(" _stp_copy_from_user(THIS->__retvalue, data->buffer, data->count);\n")
389 + string(" THIS->__retvalue[data->count] = '\\0';\n");
391 ec
->code
= string("int bytes = 0;\n")
392 + string(" struct _stp_procfs_data *data = (struct _stp_procfs_data *)(") + locvalue
+ string(");\n")
393 + string(" bytes = strnlen(THIS->value, MAXSTRINGLEN - 1);\n")
394 + string(" if (data->off >= bytes)\n")
395 + string(" bytes = 0;\n")
396 + string(" else {\n")
397 + string(" bytes -= data->off;\n")
398 + string(" if (bytes > data->count)\n")
399 + string(" bytes = data->count;\n")
400 + string(" memcpy((void *)data->buffer, THIS->value + data->off, bytes);\n")
402 + string(" data->count = bytes;\n");
406 fdecl
->type
= pe_string
;
410 // Modify the fdecl so it carries a single pe_string formal
411 // argument called "value".
413 vardecl
*v
= new vardecl
;
417 fdecl
->formal_args
.push_back(v
);
419 sess
.functions
[fdecl
->name
]=fdecl
;
421 // Synthesize a functioncall.
422 functioncall
* n
= new functioncall
;
425 n
->referent
= 0; // NB: must not resolve yet, to ensure inclusion in session
429 // Provide the functioncall to our parent, so that it can be
430 // used to substitute for the assignment node immediately above
432 assert(!target_symbol_setter_functioncalls
.empty());
433 *(target_symbol_setter_functioncalls
.top()) = n
;
440 struct procfs_builder
: public derived_probe_builder
443 virtual void build(systemtap_session
& sess
,
445 probe_point
* location
,
446 literal_map_t
const & parameters
,
447 vector
<derived_probe
*> & finished_results
);
452 procfs_builder::build(systemtap_session
& sess
,
454 probe_point
* location
,
455 literal_map_t
const & parameters
,
456 vector
<derived_probe
*> & finished_results
)
459 bool has_procfs
= get_param(parameters
, TOK_PROCFS
, path
);
460 bool has_read
= (parameters
.find(TOK_READ
) != parameters
.end());
461 bool has_write
= (parameters
.find(TOK_WRITE
) != parameters
.end());
463 // If no procfs path, default to "command". The runtime will do
464 // this for us, but if we don't do it here, we'll think the
465 // following 2 probes are attached to different paths:
467 // probe procfs("command").read {}"
468 // probe procfs.write {}
472 // If we have a path, we need to validate it.
475 string::size_type start_pos
, end_pos
;
478 while ((end_pos
= path
.find('/', start_pos
)) != string::npos
)
480 // Make sure it doesn't start with '/'.
482 throw semantic_error ("procfs path cannot start with a '/'",
483 location
->components
.front()->tok
);
485 component
= path
.substr(start_pos
, end_pos
- start_pos
);
486 // Make sure it isn't empty.
487 if (component
.size() == 0)
488 throw semantic_error ("procfs path component cannot be empty",
489 location
->components
.front()->tok
);
490 // Make sure it isn't relative.
491 else if (component
== "." || component
== "..")
492 throw semantic_error ("procfs path cannot be relative (and contain '.' or '..')", location
->components
.front()->tok
);
494 start_pos
= end_pos
+ 1;
496 component
= path
.substr(start_pos
);
497 // Make sure it doesn't end with '/'.
498 if (component
.size() == 0)
499 throw semantic_error ("procfs path cannot end with a '/'", location
->components
.front()->tok
);
500 // Make sure it isn't relative.
501 else if (component
== "." || component
== "..")
502 throw semantic_error ("procfs path cannot be relative (and contain '.' or '..')", location
->components
.front()->tok
);
505 if (!(has_read
^ has_write
))
506 throw semantic_error ("need read/write component", location
->components
.front()->tok
);
508 finished_results
.push_back(new procfs_derived_probe(sess
, base
, location
,
514 register_tapset_procfs(systemtap_session
& s
)
516 match_node
* root
= s
.pattern_root
;
517 derived_probe_builder
*builder
= new procfs_builder();
519 root
->bind(TOK_PROCFS
)->bind(TOK_READ
)->bind(builder
);
520 root
->bind_str(TOK_PROCFS
)->bind(TOK_READ
)->bind(builder
);
521 root
->bind(TOK_PROCFS
)->bind(TOK_WRITE
)->bind(builder
);
522 root
->bind_str(TOK_PROCFS
)->bind(TOK_WRITE
)->bind(builder
);
527 /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */