LTP GCOV extension - code coverage report
Current view: directory - src - buildrun.cxx
Test: stap.info
Date: 2008-03-12 Instrumented lines: 106
Code covered: 59.4 % Executed lines: 63

       1                 : // build/run probes
       2                 : // Copyright (C) 2005-2007 Red Hat Inc.
       3                 : //
       4                 : // This file is part of systemtap, and is free software.  You can
       5                 : // redistribute it and/or modify it under the terms of the GNU General
       6                 : // Public License (GPL); either version 2, or (at your option) any
       7                 : // later version.
       8                 : 
       9                 : #include "config.h"
      10                 : #include "buildrun.h"
      11                 : #include "session.h"
      12                 : #include "util.h"
      13                 : 
      14                 : #include <cstdlib>
      15                 : #include <fstream>
      16                 : #include <sstream>
      17                 : 
      18                 : extern "C" {
      19                 : #include <signal.h>
      20                 : #include <sys/wait.h>
      21                 : #include <pwd.h>
      22                 : #include <sys/types.h>
      23                 : #include <sys/stat.h>
      24                 : #include <unistd.h>
      25                 : #include <string.h>
      26                 : #include <errno.h>
      27                 : }
      28                 : 
      29                 : 
      30                 : using namespace std;
      31                 : 
      32                 : static int uprobes_pass (systemtap_session& s);
      33                 : 
      34                 : /* Adjust and run make_cmd to build a kernel module. */
      35                 : static int
      36             270 : run_make_cmd(systemtap_session& s, string& make_cmd)
      37                 : {
      38                 :   // Before running make, fix up the environment a bit.  PATH should
      39                 :   // already be overridden.  Clean out a few variables that
      40                 :   // /lib/modules/${KVER}/build/Makefile uses.
      41                 :   int rc = unsetenv("ARCH") || unsetenv("KBUILD_EXTMOD")
      42                 :       || unsetenv("CROSS_COMPILE") || unsetenv("KBUILD_IMAGE")
      43             270 :       || unsetenv("KCONFIG_CONFIG") || unsetenv("INSTALL_PATH");
      44             270 :   if (rc)
      45                 :     {
      46               0 :       const char* e = strerror (errno);
      47               0 :       cerr << "unsetenv failed: " << e << endl;
      48                 :     }
      49                 : 
      50             270 :   if (s.verbose > 2)
      51               0 :     make_cmd += " V=1";
      52             270 :   else if (s.verbose > 1)
      53               0 :     make_cmd += " >/dev/null";
      54                 :   else
      55             270 :     make_cmd += " -s >/dev/null 2>&1";
      56                 :   
      57             270 :   if (s.verbose > 1) clog << "Running " << make_cmd << endl;
      58             270 :   rc = system (make_cmd.c_str());
      59                 :   
      60             270 :   return rc;
      61                 : }
      62                 : 
      63                 : int
      64             270 : compile_pass (systemtap_session& s)
      65                 : {
      66             270 :   int rc = uprobes_pass (s);
      67             270 :   if (rc)
      68               0 :     return rc;
      69                 : 
      70                 :   // fill in a quick Makefile
      71             270 :   string makefile_nm = s.tmpdir + "/Makefile";
      72             270 :   ofstream o (makefile_nm.c_str());
      73                 : 
      74                 :   // Create makefile
      75                 : 
      76                 :   // Clever hacks copied from vmware modules
      77             270 :   o << "stap_check_gcc = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo \"$(1)\"; else echo \"$(2)\"; fi)" << endl;
      78             270 :   o << "stap_check_build = $(shell if $(CC) $(KBUILD_CPPFLAGS) $(CPPFLAGS) $(KBUILD_CFLAGS) $(CFLAGS_KERNEL) $(EXTRA_CFLAGS) $(CFLAGS) -DKBUILD_BASENAME=\\\"" << s.module_name << "\\\" -Werror -S -o /dev/null -xc $(1) > /dev/null 2>&1 ; then echo \"$(2)\"; else echo \"$(3)\"; fi)" << endl;
      79                 : 
      80                 : 
      81             270 :   o << "SYSTEMTAP_RUNTIME = \"" << s.runtime_path << "\"" << endl;
      82                 : 
      83                 :   // "autoconf" options go here
      84                 : 
      85                 :   // enum hrtimer_mode renaming near 2.6.21; see tapsets.cxx hrtimer_derived_probe_group::emit_module_decls
      86             270 :   string module_cflags = "CFLAGS_" + s.module_name + ".o";
      87             270 :   o << module_cflags << " :=" << endl;
      88             270 :   o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-hrtimer-rel.c, -DSTAPCONF_HRTIMER_REL,)" << endl;
      89             270 :   o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-inode-private.c, -DSTAPCONF_INODE_PRIVATE,)" << endl;
      90             270 :   o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-constant-tsc.c, -DSTAPCONF_CONSTANT_TSC,)" << endl;
      91             270 :   o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-tsc-khz.c, -DSTAPCONF_TSC_KHZ,)" << endl;
      92             270 :   o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-ktime-get-real.c, -DSTAPCONF_KTIME_GET_REAL,)" << endl;
      93             270 :   o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-x86-uniregs.c, -DSTAPCONF_X86_UNIREGS,)" << endl;
      94                 : 
      95             270 :   o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-nameidata.c, -DSTAPCONF_NAMEIDATA_CLEANUP,)" << endl;
      96                 : 
      97             311 :   for (unsigned i=0; i<s.macros.size(); i++)
      98              41 :     o << "EXTRA_CFLAGS += -D " << lex_cast_qstring(s.macros[i]) << endl;
      99                 : 
     100             270 :   if (s.verbose > 3)
     101               0 :     o << "EXTRA_CFLAGS += -ftime-report -Q" << endl;
     102                 : 
     103                 :   // XXX: unfortunately, -save-temps can't work since linux kbuild cwd
     104                 :   // is not writeable.
     105                 :   //
     106                 :   // if (s.keep_tmpdir)
     107                 :   // o << "CFLAGS += -fverbose-asm -save-temps" << endl;
     108                 : 
     109             270 :   o << "EXTRA_CFLAGS += -freorder-blocks" << endl; // improve on -Os
     110                 : 
     111                 :   // o << "CFLAGS += -fno-unit-at-a-time" << endl;
     112                 :     
     113                 :   // Assumes linux 2.6 kbuild
     114             270 :   o << "EXTRA_CFLAGS += -Wno-unused -Werror" << endl;
     115             270 :   o << "EXTRA_CFLAGS += -I\"" << s.runtime_path << "\"" << endl;
     116                 :   // XXX: this may help ppc toc overflow
     117                 :   // o << "CFLAGS := $(subst -Os,-O2,$(CFLAGS)) -fminimal-toc" << endl;
     118             270 :   o << "obj-m := " << s.module_name << ".o" << endl;
     119                 : 
     120             270 :   o.close ();
     121                 : 
     122                 :   // Generate module directory pathname and make sure it exists.
     123                 :   string module_dir = string("/lib/modules/")
     124             270 :     + s.kernel_release + "/build";
     125                 :   struct stat st;
     126             540 :   rc = stat(module_dir.c_str(), &st);
     127             270 :   if (rc != 0)
     128                 :     {
     129                 :         clog << "Module directory " << module_dir << " check failed: "
     130                 :              << strerror(errno) << endl
     131               0 :              << "Make sure kernel devel is installed." << endl;
     132             270 :         return rc;
     133                 :     }  
     134                 : 
     135                 :   // Run make
     136                 :   string make_cmd = string("make")
     137             270 :     + string (" -C \"") + module_dir + string("\"");
     138             540 :   make_cmd += string(" M=\"") + s.tmpdir + string("\" modules");
     139                 : 
     140             540 :   rc = run_make_cmd(s, make_cmd);
     141                 :   
     142             270 :   return rc;
     143                 : }
     144                 : 
     145            2188 : static const string uprobes_home = string(PKGDATADIR "/runtime/uprobes");
     146                 : 
     147                 : /*
     148                 :  * If uprobes was built as part of the kernel build (either built-in
     149                 :  * or as a module), the uprobes exports should show up in
     150                 :  * /lib/modules/`uname -r`/build/Module.symvers.  Return true if so.
     151                 :  */
     152                 : static bool
     153               0 : kernel_built_uprobes (systemtap_session& s)
     154                 : {
     155                 :   string grep_cmd = string ("/bin/grep -q unregister_uprobe /lib/modules/")
     156               0 :     + s.kernel_release + string ("/build/Module.symvers");
     157               0 :   int rc = system (grep_cmd.c_str());
     158               0 :   return (rc == 0);
     159                 : }
     160                 : 
     161                 : static bool
     162               0 : verify_uprobes_uptodate (systemtap_session& s)
     163                 : {
     164               0 :   if (s.verbose)
     165                 :     clog << "Pass 4, preamble: "
     166                 :          << "verifying that SystemTap's version of uprobes is up to date."
     167               0 :          << endl;
     168                 : 
     169                 :   string make_cmd = string("make -q -C ") + uprobes_home
     170               0 :     + string(" uprobes.ko");
     171               0 :   int rc = run_make_cmd(s, make_cmd);
     172               0 :   if (rc) {
     173               0 :     clog << "SystemTap's version of uprobes is out of date." << endl;
     174               0 :     clog << "As root, run \"make\" in " << uprobes_home << "." << endl;
     175                 :   }
     176                 : 
     177               0 :   return rc;
     178                 : }
     179                 : 
     180                 : static int
     181               0 : make_uprobes (systemtap_session& s)
     182                 : {
     183               0 :   if (s.verbose)
     184                 :     clog << "Pass 4, preamble: "
     185                 :          << "(re)building SystemTap's version of uprobes."
     186               0 :          << endl;
     187                 : 
     188               0 :   string make_cmd = string("make -C ") + uprobes_home;
     189               0 :   int rc = run_make_cmd(s, make_cmd);
     190               0 :   if (s.verbose) {
     191               0 :     if (rc)
     192               0 :       clog << "Uprobes (re)build failed." << endl;
     193                 :     else
     194               0 :       clog << "Uprobes (re)build complete." << endl;
     195                 :   }
     196                 : 
     197               0 :   return rc;
     198                 : }
     199                 : 
     200                 : /*
     201                 :  * Copy uprobes' exports (in Module.symvers) into the temporary directory
     202                 :  * so the script-module build can find them.
     203                 :  */
     204                 : static int
     205               0 : copy_uprobes_symbols (systemtap_session& s)
     206                 : {
     207                 :   string cp_cmd = string("/bin/cp ") + uprobes_home +
     208               0 :     string("/Module.symvers ") + s.tmpdir;
     209               0 :   int rc = system (cp_cmd.c_str());
     210               0 :   return rc;
     211                 : }
     212                 : 
     213                 : static int
     214             270 : uprobes_pass (systemtap_session& s)
     215                 : {
     216             270 :   if (!s.need_uprobes || kernel_built_uprobes(s))
     217             270 :     return 0;
     218                 :   /*
     219                 :    * We need to use the version of uprobes that comes with SystemTap, so
     220                 :    * we may need to rebuild uprobes.ko there.  Unfortunately, this is
     221                 :    * never a no-op; e.g., the modpost step gets run every time.  We don't
     222                 :    * want non-root users modifying uprobes, so we keep the uprobes
     223                 :    * directory writable only by root.  But that means a non-root member
     224                 :    * of group stapdev can't run the make even if everything's up to date.
     225                 :    *
     226                 :    * So for non-root users, we just use "make -q" with a fake target to
     227                 :    * verify that uprobes doesn't need to be rebuilt.  If that's not so,
     228                 :    * stap must fail.
     229                 :    */
     230                 :   int rc;
     231               0 :   if (geteuid() == 0) {
     232               0 :     rc = make_uprobes(s);
     233               0 :     if (rc == 0)
     234               0 :       rc = copy_uprobes_symbols(s);
     235                 :   } else
     236               0 :     rc = verify_uprobes_uptodate(s);
     237               0 :   return rc;
     238                 : }
     239                 : 
     240                 : int
     241             204 : run_pass (systemtap_session& s)
     242                 : {
     243             204 :   int rc = 0;
     244                 : 
     245             204 :   struct passwd *pw = getpwuid(getuid());
     246             204 :   string username = string(pw->pw_name);
     247                 : 
     248                 :   // for now, just spawn staprun
     249                 :   string staprun_cmd = string(BINDIR) + "/staprun "
     250                 :     + (s.verbose>1 ? "-v " : "")
     251                 :     + (s.verbose>2 ? "-v " : "")
     252             408 :     + (s.output_file.empty() ? "" : "-o " + s.output_file + " ");
     253                 :   
     254             204 :   staprun_cmd += "-d " + stringify(getpid()) + " ";
     255                 :   
     256             204 :   if (s.cmd != "")
     257              68 :     staprun_cmd += "-c " + cmdstr_quoted(s.cmd) + " ";
     258                 :   
     259             204 :   if (s.target_pid)
     260               0 :     staprun_cmd += "-t " + stringify(s.target_pid) + " ";
     261                 :   
     262             204 :   if (s.buffer_size)
     263               0 :     staprun_cmd += "-b " + stringify(s.buffer_size) + " ";
     264                 :   
     265             204 :   if (s.need_uprobes)
     266               0 :     staprun_cmd += "-u ";
     267                 : 
     268             204 :   staprun_cmd += s.tmpdir + "/" + s.module_name + ".ko";
     269                 :   
     270             204 :   if (s.verbose>1) clog << "Running " << staprun_cmd << endl;
     271                 :   
     272             204 :   rc = system (staprun_cmd.c_str ());
     273             204 :   return rc;
     274            2188 : }

Generated by: LTP GCOV extension version 1.5