LCOV - code coverage report
Current view: top level - mnt/wasteland/wcohen/systemtap_write/systemtap - tapset-procfs.cxx (source / functions) Hit Total Coverage
Test: stap.info Lines: 281 291 96.6 %
Date: 2013-03-08 Functions: 16 23 69.6 %
Branches: 366 690 53.0 %

           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 : */

Generated by: LCOV version 1.9