LTP GCOV extension - code coverage report
Current view: directory - src - hash.cxx
Test: stap.info
Date: 2008-03-12 Instrumented lines: 59
Code covered: 86.4 % Executed lines: 51

       1                 : // Copyright (C) Andrew Tridgell 2002 (original file)
       2                 : // Copyright (C) 2006-2007 Red Hat Inc. (systemtap changes)
       3                 : // 
       4                 : // This program is free software; you can redistribute it and/or modify
       5                 : // it under the terms of the GNU General Public License as published by
       6                 : // the Free Software Foundation; either version 2 of the License, or
       7                 : // (at your option) any later version.
       8                 : // 
       9                 : // This program is distributed in the hope that it will be useful,
      10                 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      11                 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12                 : // GNU General Public License for more details.
      13                 : // 
      14                 : // You should have received a copy of the GNU General Public License
      15                 : // along with this program; if not, write to the Free Software
      16                 : // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
      17                 : 
      18                 : #include "config.h"
      19                 : #include "session.h"
      20                 : #include "hash.h"
      21                 : #include "util.h"
      22                 : 
      23                 : #include <cstdlib>
      24                 : #include <sstream>
      25                 : #include <iomanip>
      26                 : #include <cerrno>
      27                 : 
      28                 : extern "C" {
      29                 : #include <sys/types.h>
      30                 : #include <sys/stat.h>
      31                 : #include <unistd.h>
      32                 : }
      33                 : 
      34                 : using namespace std;
      35                 : 
      36                 : void
      37             347 : hash::start()
      38                 : {
      39             347 :   mdfour_begin(&md4);
      40             347 : }
      41                 : 
      42                 : 
      43                 : void
      44            4900 : hash::add(const unsigned char *buffer, size_t size)
      45                 : {
      46            4900 :   mdfour_update(&md4, buffer, size);
      47            4900 : }
      48                 : 
      49                 : 
      50                 : void
      51             347 : hash::result(string& r)
      52                 : {
      53             347 :   ostringstream rstream;
      54                 :   unsigned char sum[16];
      55                 : 
      56             347 :   mdfour_update(&md4, NULL, 0);
      57             347 :   mdfour_result(&md4, sum);
      58                 : 
      59            5899 :   for (int i=0; i<16; i++)
      60                 :     {
      61            5552 :       rstream << hex << setfill('0') << setw(2) << (unsigned)sum[i];
      62                 :     }
      63             347 :   rstream << "_" << setw(0) << dec << (unsigned)md4.totalN;
      64             347 :   r = rstream.str();
      65             347 : }
      66                 : 
      67                 : 
      68                 : void
      69             347 : find_hash (systemtap_session& s, const string& script)
      70                 : {
      71             347 :   hash h;
      72             347 :   int nlevels = 1;
      73                 :   struct stat st;
      74                 : 
      75                 :   // We use a N level subdir for the cache path.  Let N be adjustable.
      76                 :   const char *s_n;
      77             347 :   if ((s_n = getenv("SYSTEMTAP_NLEVELS")))
      78                 :     {
      79               0 :       nlevels = atoi(s_n);
      80               0 :       if (nlevels < 1) nlevels = 1;
      81               0 :       if (nlevels > 8) nlevels = 8;
      82                 :     }
      83                 : 
      84                 :   // Hash getuid.  This really shouldn't be necessary (since who you
      85                 :   // are doesn't change the generated output), but the hash gets used
      86                 :   // as the module name.  If two different users try to run the same
      87                 :   // script at the same time, we need something to differentiate the
      88                 :   // module name.
      89             347 :   h.add(getuid());
      90                 : 
      91                 :   // Hash kernel release and arch.
      92             347 :   h.add(s.kernel_release);
      93             347 :   h.add(s.architecture);
      94                 : 
      95                 :   // Hash user-specified arguments (that change the generated module).
      96             347 :   h.add(s.bulk_mode);                   // '-b'
      97             347 :   h.add(s.merge);                       // '-M'
      98             347 :   h.add(s.timing);                      // '-t'
      99             347 :   h.add(s.prologue_searching);          // '-P'
     100             389 :   for (unsigned i = 0; i < s.macros.size(); i++)
     101              42 :     h.add(s.macros[i]);
     102                 : 
     103                 :   // Hash runtime path (that gets added in as "-I path").
     104             347 :   h.add(s.runtime_path);
     105                 : 
     106                 :   // Hash compiler path, size, and mtime.  We're just going to assume
     107                 :   // we'll be using gcc, which should be correct most of the time.
     108             347 :   string gcc_path;
     109             347 :   if (find_executable("gcc", gcc_path))
     110                 :     {
     111             347 :       if (stat(gcc_path.c_str(), &st) == 0)
     112                 :         {
     113             347 :           h.add(gcc_path);
     114             347 :           h.add(st.st_size);
     115             347 :           h.add(st.st_mtime);
     116                 :         }
     117                 :     }
     118                 : 
     119                 :   // Hash the systemtap size and mtime.  We could use VERSION/DATE,
     120                 :   // but when developing systemtap that doesn't work well (since you
     121                 :   // can compile systemtap multiple times in 1 day).  Since we don't
     122                 :   // know exactly where we're getting run from, we'll use
     123                 :   // /proc/self/exe.
     124             347 :   if (stat("/proc/self/exe", &st) == 0)
     125                 :   {
     126             347 :       h.add(st.st_size);
     127             347 :       h.add(st.st_mtime);
     128                 :   }
     129                 : 
     130                 :   // Add in pass 2 script output.
     131             347 :   h.add(script);
     132                 : 
     133                 :   // Use a N level subdir for the cache path to reduce the impact on
     134                 :   // filesystems which are slow for large directories.
     135             347 :   string hashdir = s.cache_path;
     136             347 :   string result;
     137             347 :   h.result(result);
     138                 : 
     139             694 :   for (int i = 0; i < nlevels; i++)
     140                 :     {
     141             347 :       hashdir += string("/") + result[i*2] + result[i*2 + 1];
     142             694 :       if (create_dir(hashdir.c_str()) != 0)
     143                 :         {
     144                 :           cerr << "Warning: failed to create cache directory (\""
     145               0 :                << hashdir + "\"): " << strerror(errno) << endl;
     146               0 :           cerr << "Disabling cache support." << endl;
     147               0 :           s.use_cache = false;
     148               0 :           return;
     149                 :         }
     150                 :     }
     151                 : 
     152                 :   // Update module name to be 'stap_{hash start}'.  '{hash start}'
     153                 :   // must not be too long.  This shouldn't happen, since the maximum
     154                 :   // size of a hash is 32 fixed chars + 1 (for the '_') + a max of 11.
     155             347 :   s.module_name = "stap_" + result;
     156             347 :   if (s.module_name.size() >= (MODULE_NAME_LEN - 1))
     157               0 :     s.module_name.resize(MODULE_NAME_LEN - 1);
     158                 : 
     159                 :   // 'ccache' would use a hash path of something like:
     160                 :   //    s.hash_path = hashdir + "/" + result.substr(nlevels);
     161                 :   // which would look like:
     162                 :   //    ~/.stap_cache/A/B/CDEFGHIJKLMNOPQRSTUVWXYZABCDEF_XXX
     163                 :   //
     164                 :   // We're using the following so that the module can be used straight
     165                 :   // from the cache if desired.  This ends up looking like this:
     166                 :   //    ~/.stap_cache/A/B/stap_ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEF_XXX.ko
     167             347 :   s.hash_path = hashdir + "/" + s.module_name + ".ko";
     168                 : 
     169                 :   // Update C source name with new module_name.
     170             347 :   s.translated_source = string(s.tmpdir) + "/" + s.module_name + ".c";
     171            2188 : }

Generated by: LTP GCOV extension version 1.5