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