]> sourceware.org Git - systemtap.git/blame - tapset-procfs.cxx
update copyrights
[systemtap.git] / tapset-procfs.cxx
CommitLineData
7a212aa8 1// tapset for procfs
ef36f781 2// Copyright (C) 2005-2014 Red Hat Inc.
7a212aa8 3// Copyright (C) 2005-2007 Intel Corporation.
7a212aa8
JS
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
20using namespace std;
21using namespace __gnu_cxx;
22
23
4627ed58
JS
24static const string TOK_PROCFS("procfs");
25static const string TOK_READ("read");
26static const string TOK_WRITE("write");
38975255 27static const string TOK_MAXSIZE("maxsize");
c243f608 28static const string TOK_UMASK("umask");
7a212aa8
JS
29
30
31// ------------------------------------------------------------------------
32// procfs file derived probes
33// ------------------------------------------------------------------------
34
35
36struct procfs_derived_probe: public derived_probe
37{
38 string path;
39 bool write;
40 bool target_symbol_seen;
38975255 41 int64_t maxsize_val;
c243f608 42 int64_t umask;
7a212aa8 43
c243f608
LB
44
45 procfs_derived_probe (systemtap_session &, probe* p, probe_point* l, string ps, bool w, int64_t m, int64_t umask);
7a212aa8
JS
46 void join_group (systemtap_session& s);
47};
48
49
50struct procfs_probe_set
51{
52 procfs_derived_probe* read_probe;
53 procfs_derived_probe* write_probe;
54
c243f608 55 procfs_probe_set () : read_probe (NULL), write_probe (NULL) {}
7a212aa8
JS
56};
57
58
59struct procfs_derived_probe_group: public generic_dpg<procfs_derived_probe>
60{
61private:
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
67public:
68 procfs_derived_probe_group () :
c243f608 69 has_read_probes(false), has_write_probes(false) {}
7a212aa8
JS
70
71 void enroll (procfs_derived_probe* probe);
be66b6e1
DS
72 void emit_kernel_module_init (systemtap_session& s);
73 void emit_kernel_module_exit (systemtap_session& s);
7a212aa8
JS
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
80struct procfs_var_expanding_visitor: public var_expanding_visitor
81{
82 procfs_var_expanding_visitor(systemtap_session& s, const string& pn,
a50de939 83 string path, bool write_probe);
7a212aa8
JS
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
95procfs_derived_probe::procfs_derived_probe (systemtap_session &s, probe* p,
38975255 96 probe_point* l, string ps, bool w,
c243f608 97 int64_t m, int64_t umask):
38975255 98 derived_probe(p, l), path(ps), write(w), target_symbol_seen(false),
c243f608 99 maxsize_val(m), umask(umask)
7a212aa8
JS
100{
101 // Expand local variables in the probe body
c243f608 102 procfs_var_expanding_visitor v (s, name, path, write);
8b095b45 103 v.replace (this->body);
7a212aa8
JS
104 target_symbol_seen = v.target_symbol_seen;
105}
106
107
108void
109procfs_derived_probe::join_group (systemtap_session& s)
110{
111 if (! s.procfs_derived_probes)
8e0049e8
DS
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")
23b7dbfa 119 + string(" char *buffer;\n")
38975255
DS
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");
8e0049e8
DS
126 s.embeds.push_back(ec);
127 }
7a212aa8
JS
128 s.procfs_derived_probes->enroll (this);
129}
130
131
132void
133procfs_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)
dc09353a 148 throw SEMANTIC_ERROR(_("only one write procfs probe can exist for procfs path \"") + p->path + "\"");
7a212aa8 149 else if (! p->write && pset->read_probe != NULL)
dc09353a 150 throw SEMANTIC_ERROR(_("only one read procfs probe can exist for procfs path \"") + p->path + "\"");
7a212aa8
JS
151
152 // XXX: multiple writes should be acceptable
153 }
154
155 if (p->write)
38975255
DS
156 {
157 pset->write_probe = p;
158 has_write_probes = true;
159 }
7a212aa8 160 else
38975255
DS
161 {
162 pset->read_probe = p;
163 has_read_probes = true;
164 }
7a212aa8
JS
165}
166
167
be66b6e1
DS
168void
169procfs_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
177void
178procfs_derived_probe_group::emit_kernel_module_exit (systemtap_session& s)
179{
180 if (probes_by_path.empty())
181 return;
b85e750d
DS
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)";
be66b6e1 186 s.op->newline() << "_stp_rmdir_proc_module();";
b85e750d 187 s.op->newline() << "#endif";
be66b6e1
DS
188}
189
190
7a212aa8
JS
191void
192procfs_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\"";
23b7dbfa 199 s.op->newline() << "#include \"procfs-probes.c\"";
7a212aa8 200
38975255
DS
201 // Emit the procfs probe buffer structure
202 s.op->newline() << "static struct stap_procfs_probe_buffer {";
203 s.op->indent(1);
9a5fa202 204 unsigned buf_index = 0; // used for buffer naming
38975255
DS
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;
9a5fa202 209 s.op->newline() << "char buf_" << buf_index++;
38975255
DS
210
211 if (pset->read_probe != NULL)
212 {
213 if (pset->read_probe->maxsize_val == 0)
9a5fa202 214 s.op->line() << "[STP_PROCFS_BUFSIZE];";
38975255 215 else
9a5fa202 216 s.op->line() << "[" << pset->read_probe->maxsize_val << "];";
38975255
DS
217 }
218 else
9a5fa202 219 s.op->line() << "[MAXSTRINGLEN];";
38975255
DS
220 }
221 s.op->newline(-1) << "} stap_procfs_probe_buffers;";
222
7a212aa8 223 // Emit the procfs probe data list
23b7dbfa 224 s.op->newline() << "static struct stap_procfs_probe stap_procfs_probes[] = {";
7a212aa8
JS
225 s.op->indent(1);
226
9a5fa202 227 buf_index = 0;
7a212aa8
JS
228 for (p_b_p_iterator it = probes_by_path.begin(); it != probes_by_path.end();
229 it++)
38975255 230 {
7a212aa8
JS
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)
faea5e16 237 s.op->line() << " .read_probe=" << common_probe_init (pset->read_probe) << ",";
7a212aa8
JS
238
239 if (pset->write_probe != NULL)
faea5e16 240 s.op->line() << " .write_probe=" << common_probe_init (pset->write_probe) << ",";
38975255 241
9a5fa202 242 s.op->line() << " .buffer=stap_procfs_probe_buffers.buf_" << buf_index++ << ",";
38975255 243 if (pset->read_probe != NULL)
9a5fa202 244 {
38975255
DS
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
9a5fa202
JS
252 s.op->line() << " .bufsize=MAXSTRINGLEN,";
253
c243f608
LB
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 << ",";
38975255 259
7a212aa8 260 s.op->line() << " },";
38975255 261 }
7a212aa8
JS
262 s.op->newline(-1) << "};";
263
23b7dbfa
DS
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);
7a212aa8
JS
271 if (has_read_probes)
272 {
8e0049e8 273 s.op->newline() << "struct _stp_procfs_data pdata;";
7a212aa8 274
71db462b 275 common_probe_entryfn_prologue (s, "STAP_SESSION_RUNNING",
6eefe942 276 "spp->read_probe",
cda141c2 277 "stp_probe_type_procfs");
7a212aa8 278
23b7dbfa 279 s.op->newline() << "pdata.buffer = spp->buffer;";
38975255 280 s.op->newline() << "pdata.bufsize = spp->bufsize;";
6dceb5c9
MW
281 s.op->newline() << "if (c->ips.procfs_data == NULL)";
282 s.op->newline(1) << "c->ips.procfs_data = &pdata;";
7a212aa8
JS
283 s.op->newline(-1) << "else {";
284
065d5567
JS
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);";
7a212aa8
JS
287 s.op->newline() << "_stp_exit ();";
288 s.op->newline(-1) << "}";
7a212aa8
JS
289 s.op->newline() << "goto probe_epilogue;";
290 s.op->newline(-1) << "}";
291
8e0049e8 292 // call probe function
26e63673 293 s.op->newline() << "(*spp->read_probe->ph) (c);";
7a212aa8 294
23b7dbfa 295 // Note that _procfs_value_set copied string data into spp->buffer
6dceb5c9 296 s.op->newline() << "c->ips.procfs_data = NULL;";
23b7dbfa
DS
297 s.op->newline() << "spp->needs_fill = 0;";
298 s.op->newline() << "spp->count = strlen(spp->buffer);";
299
f887a8c9 300 common_probe_entryfn_epilogue (s, true);
7a212aa8 301
23b7dbfa
DS
302 s.op->newline() << "if (spp->needs_fill) {";
303 s.op->newline(1) << "spp->needs_fill = 0;";
304 s.op->newline() << "return -EIO;";
7a212aa8
JS
305 s.op->newline(-1) << "}";
306 }
23b7dbfa
DS
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;";
7a212aa8
JS
316 if (has_write_probes)
317 {
8e0049e8 318 s.op->newline() << "struct _stp_procfs_data pdata;";
7a212aa8 319
71db462b 320 common_probe_entryfn_prologue (s, "STAP_SESSION_RUNNING",
6eefe942 321 "spp->write_probe",
cda141c2 322 "stp_probe_type_procfs");
7a212aa8 323
38975255
DS
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).
23b7dbfa 327 s.op->newline() << "if (count >= MAXSTRINGLEN)";
7a212aa8 328 s.op->newline(1) << "count = MAXSTRINGLEN - 1;";
8e0049e8 329 s.op->indent(-1);
38975255
DS
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
23b7dbfa 335 s.op->newline() << "pdata.buffer = (char *)buf;";
8e0049e8 336 s.op->newline() << "pdata.count = count;";
7a212aa8 337
6dceb5c9
MW
338 s.op->newline() << "if (c->ips.procfs_data == NULL)";
339 s.op->newline(1) << "c->ips.procfs_data = &pdata;";
7a212aa8
JS
340 s.op->newline(-1) << "else {";
341
065d5567
JS
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);";
7a212aa8
JS
344 s.op->newline() << "_stp_exit ();";
345 s.op->newline(-1) << "}";
7a212aa8
JS
346 s.op->newline() << "goto probe_epilogue;";
347 s.op->newline(-1) << "}";
348
8e0049e8 349 // call probe function
26e63673 350 s.op->newline() << "(*spp->write_probe->ph) (c);";
7a212aa8 351
6dceb5c9 352 s.op->newline() << "c->ips.procfs_data = NULL;";
23b7dbfa
DS
353 s.op->newline() << "if (c->last_error == 0) {";
354 s.op->newline(1) << "retval = count;";
7a212aa8 355 s.op->newline(-1) << "}";
23b7dbfa 356
f887a8c9 357 common_probe_entryfn_epilogue (s, true);
7a212aa8 358 }
c243f608 359
23b7dbfa
DS
360 s.op->newline() << "return retval;";
361 s.op->newline(-1) << "}";
7a212aa8
JS
362}
363
364
365void
366procfs_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
26e63673
JS
374 s.op->newline() << "if (spp->read_probe)";
375 s.op->newline(1) << "probe_point = spp->read_probe->pp;";
7a212aa8 376 s.op->newline(-1) << "else";
26e63673 377 s.op->newline(1) << "probe_point = spp->write_probe->pp;";
23b7dbfa 378 s.op->indent(-1);
7a212aa8 379
bfbbb76e 380 s.op->newline() << "_spp_init(spp);";
b85e750d 381 s.op->newline() << "rc = _stp_create_procfs(spp->path, i, &_stp_proc_fops, spp->permissions, spp);";
7a212aa8
JS
382
383 s.op->newline() << "if (rc) {";
384 s.op->newline(1) << "_stp_close_procfs();";
23b7dbfa
DS
385
386 s.op->newline() << "for (i = 0; i < " << probes_by_path.size() << "; i++) {";
387 s.op->newline(1) << "spp = &stap_procfs_probes[i];";
bfbbb76e 388 s.op->newline() << "_spp_shutdown(spp);";
23b7dbfa 389 s.op->newline(-1) << "}";
7a212aa8
JS
390 s.op->newline() << "break;";
391 s.op->newline(-1) << "}";
7a212aa8
JS
392 s.op->newline(-1) << "}"; // for loop
393}
394
395
396void
397procfs_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();";
23b7dbfa
DS
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];";
bfbbb76e 405 s.op->newline() << "_spp_shutdown(spp);";
23b7dbfa 406 s.op->newline(-1) << "}";
7a212aa8
JS
407}
408
409
a50de939
DS
410procfs_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
7a212aa8
JS
422void
423procfs_var_expanding_visitor::visit_target_symbol (target_symbol* e)
424{
c69a87e0
FCE
425 try
426 {
277c21bc 427 assert(e->name.size() > 0 && e->name[0] == '$');
c69a87e0 428
277c21bc 429 if (e->name != "$value")
dc09353a 430 throw SEMANTIC_ERROR (_("invalid target symbol for procfs probe, $value expected"),
c69a87e0 431 e->tok);
f8809d54 432
c69a87e0 433 e->assert_no_components("procfs");
f8809d54 434
c69a87e0
FCE
435 bool lvalue = is_active_lvalue(e);
436 if (write_probe && lvalue)
dc09353a 437 throw SEMANTIC_ERROR(_("procfs $value variable is read-only in a procfs write probe"), e->tok);
7a212aa8 438 else if (! write_probe && ! lvalue)
dc09353a 439 throw SEMANTIC_ERROR(_("procfs $value variable cannot be read in a procfs read probe"), e->tok);
f8809d54 440
c69a87e0 441 if (e->addressof)
dc09353a 442 throw SEMANTIC_ERROR(_("cannot take address of procfs variable"), e->tok);
f8809d54 443
c69a87e0
FCE
444 // Remember that we've seen a target variable.
445 target_symbol_seen = true;
f8809d54 446
c69a87e0
FCE
447 // Synthesize a function.
448 functiondecl *fdecl = new functiondecl;
59de45f1 449 fdecl->synthetic = true;
c69a87e0
FCE
450 fdecl->tok = e->tok;
451 embeddedcode *ec = new embeddedcode;
452 ec->tok = e->tok;
f8809d54 453
c69a87e0 454 string fname;
6dceb5c9 455 string locvalue = "CONTEXT->ips.procfs_data";
f8809d54 456
c69a87e0 457 if (! lvalue)
a50de939 458 {
c69a87e0
FCE
459 fname = "_procfs_value_get";
460 ec->code = string(" struct _stp_procfs_data *data = (struct _stp_procfs_data *)(") + locvalue + string("); /* pure */\n")
f8809d54 461
7d860223
DS
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");
c69a87e0
FCE
466 }
467 else // lvalue
a50de939 468 {
c69a87e0
FCE
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")
0386bbcf 473 + string(" strlcpy(data->buffer, STAP_ARG_value, data->bufsize);\n")
c69a87e0
FCE
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")
0386bbcf 480 + string(" strlcat(data->buffer, STAP_ARG_value, data->bufsize);\n")
c69a87e0
FCE
481 + string(" data->count = strlen(data->buffer);\n");
482 }
483 else
484 {
dc09353a 485 throw SEMANTIC_ERROR (_("Only the following assign operators are"
c69a87e0 486 " implemented on procfs read target variables:"
efee9a98 487 " '=', '.='"), e->tok);
c69a87e0
FCE
488 }
489 }
f8809d54
JS
490 fname += lex_cast(++tick);
491
c69a87e0
FCE
492 fdecl->name = fname;
493 fdecl->body = ec;
494 fdecl->type = pe_string;
f8809d54 495
c69a87e0 496 if (lvalue)
a50de939 497 {
c69a87e0
FCE
498 // Modify the fdecl so it carries a single pe_string formal
499 // argument called "value".
f8809d54 500
c69a87e0
FCE
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 }
f8809d54
JS
507 fdecl->join (sess);
508
c69a87e0
FCE
509 // Synthesize a functioncall.
510 functioncall* n = new functioncall;
511 n->tok = e->tok;
512 n->function = fname;
f8809d54 513
c69a87e0
FCE
514 if (lvalue)
515 {
516 // Provide the functioncall to our parent, so that it can be
517 // used to substitute for the assignment node immediately above
518 // us.
519 assert(!target_symbol_setter_functioncalls.empty());
520 *(target_symbol_setter_functioncalls.top()) = n;
521 }
f8809d54 522
c69a87e0 523 provide (n);
7a212aa8 524 }
c69a87e0 525 catch (const semantic_error &er)
7a212aa8 526 {
1af1e62d 527 e->chain (er);
c69a87e0 528 provide (e);
7a212aa8 529 }
7a212aa8
JS
530}
531
532
533struct procfs_builder: public derived_probe_builder
534{
535 procfs_builder() {}
536 virtual void build(systemtap_session & sess,
537 probe * base,
538 probe_point * location,
539 literal_map_t const & parameters,
540 vector<derived_probe *> & finished_results);
541};
542
543
544void
545procfs_builder::build(systemtap_session & sess,
546 probe * base,
547 probe_point * location,
548 literal_map_t const & parameters,
549 vector<derived_probe *> & finished_results)
550{
551 string path;
552 bool has_procfs = get_param(parameters, TOK_PROCFS, path);
553 bool has_read = (parameters.find(TOK_READ) != parameters.end());
554 bool has_write = (parameters.find(TOK_WRITE) != parameters.end());
c243f608 555 bool has_umask = (parameters.find(TOK_UMASK) != parameters.end());
38975255 556 int64_t maxsize_val = 0;
c243f608
LB
557 int64_t umask_val;
558 if(has_umask)
559 get_param(parameters, TOK_UMASK, umask_val);
560 else /* no .umask */
561 {
562 if(has_read)
563 umask_val = 0044;
564 else if(has_write)
565 umask_val = 0022;
566 else
567 assert(0);
568 }
38975255
DS
569 // Validate '.maxsize(NNN)', if it exists.
570 if (get_param(parameters, TOK_MAXSIZE, maxsize_val))
571 {
572 if (maxsize_val <= 0)
dc09353a 573 throw SEMANTIC_ERROR (_("maxsize must be greater than 0"));
38975255 574 }
7a212aa8
JS
575
576 // If no procfs path, default to "command". The runtime will do
577 // this for us, but if we don't do it here, we'll think the
578 // following 2 probes are attached to different paths:
579 //
580 // probe procfs("command").read {}"
581 // probe procfs.write {}
582
583 if (! has_procfs)
584 path = "command";
585 // If we have a path, we need to validate it.
586 else
587 {
588 string::size_type start_pos, end_pos;
589 string component;
590 start_pos = 0;
591 while ((end_pos = path.find('/', start_pos)) != string::npos)
592 {
593 // Make sure it doesn't start with '/'.
594 if (end_pos == 0)
dc09353a 595 throw SEMANTIC_ERROR (_("procfs path cannot start with a '/'"),
f1a0157a 596 location->components.front()->tok);
7a212aa8
JS
597
598 component = path.substr(start_pos, end_pos - start_pos);
599 // Make sure it isn't empty.
600 if (component.size() == 0)
dc09353a 601 throw SEMANTIC_ERROR (_("procfs path component cannot be empty"),
f1a0157a 602 location->components.front()->tok);
7a212aa8
JS
603 // Make sure it isn't relative.
604 else if (component == "." || component == "..")
dc09353a 605 throw SEMANTIC_ERROR (_("procfs path cannot be relative (and contain '.' or '..')"), location->components.front()->tok);
7a212aa8
JS
606
607 start_pos = end_pos + 1;
608 }
609 component = path.substr(start_pos);
610 // Make sure it doesn't end with '/'.
611 if (component.size() == 0)
dc09353a 612 throw SEMANTIC_ERROR (_("procfs path cannot end with a '/'"), location->components.front()->tok);
7a212aa8
JS
613 // Make sure it isn't relative.
614 else if (component == "." || component == "..")
dc09353a 615 throw SEMANTIC_ERROR (_("procfs path cannot be relative (and contain '.' or '..')"), location->components.front()->tok);
7a212aa8
JS
616 }
617
618 if (!(has_read ^ has_write))
dc09353a 619 throw SEMANTIC_ERROR (_("need read/write component"), location->components.front()->tok);
7a212aa8
JS
620
621 finished_results.push_back(new procfs_derived_probe(sess, base, location,
38975255 622 path, has_write,
c243f608 623 maxsize_val, umask_val));
7a212aa8
JS
624}
625
626
627void
628register_tapset_procfs(systemtap_session& s)
629{
630 match_node* root = s.pattern_root;
631 derived_probe_builder *builder = new procfs_builder();
632
633 root->bind(TOK_PROCFS)->bind(TOK_READ)->bind(builder);
c243f608 634 root->bind(TOK_PROCFS)->bind_num(TOK_UMASK)->bind(TOK_READ)->bind(builder);
38975255 635 root->bind(TOK_PROCFS)->bind(TOK_READ)->bind_num(TOK_MAXSIZE)->bind(builder);
c243f608 636 root->bind(TOK_PROCFS)->bind_num(TOK_UMASK)->bind(TOK_READ)->bind_num(TOK_MAXSIZE)->bind(builder);
7a212aa8 637 root->bind_str(TOK_PROCFS)->bind(TOK_READ)->bind(builder);
c243f608 638 root->bind_str(TOK_PROCFS)->bind_num(TOK_UMASK)->bind(TOK_READ)->bind(builder);
38975255 639 root->bind_str(TOK_PROCFS)->bind(TOK_READ)->bind_num(TOK_MAXSIZE)->bind(builder);
c243f608 640 root->bind_str(TOK_PROCFS)->bind_num(TOK_UMASK)->bind(TOK_READ)->bind_num(TOK_MAXSIZE)->bind(builder);
38975255 641
7a212aa8 642 root->bind(TOK_PROCFS)->bind(TOK_WRITE)->bind(builder);
c243f608 643 root->bind(TOK_PROCFS)->bind_num(TOK_UMASK)->bind(TOK_WRITE)->bind(builder);
7a212aa8 644 root->bind_str(TOK_PROCFS)->bind(TOK_WRITE)->bind(builder);
c243f608 645 root->bind_str(TOK_PROCFS)->bind_num(TOK_UMASK)->bind(TOK_WRITE)->bind(builder);
7a212aa8
JS
646}
647
648
649
650/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
This page took 0.197722 seconds and 5 git commands to generate.