buildrun.cxx - systemtap
Functions defined
Source code
#include "config.h"
#include "buildrun.h"
#include "session.h"
#include "util.h"
#include "hash.h"
#include "translate.h"
#include <cstdlib>
#include <fstream>
#include <sstream>
extern "C" {
#include <signal.h>
#include <sys/wait.h>
#include <pwd.h>
#include <grp.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/resource.h>
}
using namespace std;
static int
run_make_cmd(systemtap_session& s, vector<string>& make_cmd,
bool null_out=false, bool null_err=false)
{
assert_no_interrupts();
(void) setenv("CCACHE_DISABLE", "1", 0);
if (s.verbose > 2)
make_cmd.push_back("V=1");
else if (s.verbose > 1)
make_cmd.push_back("--no-print-directory");
else
{
make_cmd.push_back("-s");
make_cmd.push_back("--no-print-directory");
}
long smp = sysconf(_SC_NPROCESSORS_ONLN);
if (smp <= 0) smp = 1;
struct rlimit rlim;
int rlimit_rc = getrlimit(RLIMIT_NPROC, &rlim);
const unsigned int severely_limited = smp*30; bool nproc_limited = (rlimit_rc == 0 && (rlim.rlim_max <= severely_limited ||
rlim.rlim_cur <= severely_limited));
if (smp >= 1 && !nproc_limited)
make_cmd.push_back("-j" + lex_cast(smp+1));
if (strverscmp (s.kernel_base_release.c_str(), "2.6.29") < 0)
{
null_out = true;
}
int rc = stap_system (s.verbose, "kbuild", make_cmd, null_out, null_err);
if (rc != 0)
s.set_try_server ();
return rc;
}
static vector<string>
make_any_make_cmd(systemtap_session& s, const string& dir, const string& target)
{
vector<string> make_cmd;
make_cmd.push_back("env");
make_cmd.push_back("-uARCH");
make_cmd.push_back("-uKBUILD_EXTMOD");
make_cmd.push_back("-uCROSS_COMPILE");
make_cmd.push_back("-uKBUILD_IMAGE");
make_cmd.push_back("-uKCONFIG_CONFIG");
make_cmd.push_back("-uINSTALL_PATH");
string newpath = string("PATH=/usr/bin:/bin:") + (getenv("PATH") ?: "");
make_cmd.push_back(newpath.c_str());
make_cmd.push_back("make");
make_cmd.push_back("-C");
make_cmd.push_back(s.kernel_build_tree);
make_cmd.push_back("M=" + dir); make_cmd.push_back(target);
if (s.architecture != "powerpc" ||
(strverscmp (s.kernel_base_release.c_str(), "2.6.15") >= 0))
make_cmd.push_back("ARCH=" + s.architecture);
make_cmd.insert(make_cmd.end(), "CONFIG_DEBUG_INFO=");
make_cmd.insert(make_cmd.end(), s.kbuildflags.begin(), s.kbuildflags.end());
return make_cmd;
}
static vector<string>
make_make_cmd(systemtap_session& s, const string& dir)
{
return make_any_make_cmd(s, dir, "modules");
}
static vector<string>
make_make_objs_cmd(systemtap_session& s, const string& dir)
{
return make_any_make_cmd(s, dir, "_module_" + dir);
}
static void
output_autoconf(systemtap_session& s, ofstream& o, const char *autoconf_c,
const char *deftrue, const char *deffalse)
{
o << "\t";
if (s.verbose < 4)
o << "@";
o << "if $(CHECK_BUILD) $(SYSTEMTAP_RUNTIME)/linux/" << autoconf_c;
if (s.verbose < 5)
o << " > /dev/null 2>&1";
o << "; then ";
if (deftrue)
o << "echo \"#define " << deftrue << " 1\"";
if (deffalse)
o << "; else echo \"#define " << deffalse << " 1\"";
o << "; fi >> $@" << endl;
}
void output_exportconf(systemtap_session& s, ofstream& o, const char *symbol,
const char *deftrue)
{
o << "\t";
if (s.verbose < 4)
o << "@";
if (s.kernel_exports.find(symbol) != s.kernel_exports.end())
o << "echo \"#define " << deftrue << " 1\"";
o << ">> $@" << endl;
}
void output_dual_exportconf(systemtap_session& s, ofstream& o,
const char *symbol1, const char *symbol2,
const char *deftrue)
{
o << "\t";
if (s.verbose < 4)
o << "@";
if (s.kernel_exports.find(symbol1) != s.kernel_exports.end()
&& s.kernel_exports.find(symbol2) != s.kernel_exports.end())
o << "echo \"#define " << deftrue << " 1\"";
o << ">> $@" << endl;
}
void output_either_exportconf(systemtap_session& s, ofstream& o,
const char *symbol1, const char *symbol2,
const char *deftrue)
{
o << "\t";
if (s.verbose < 4)
o << "@";
if (s.kernel_exports.find(symbol1) != s.kernel_exports.end()
|| s.kernel_exports.find(symbol2) != s.kernel_exports.end())
o << "echo \"#define " << deftrue << " 1\"";
o << ">> $@" << endl;
}
static int
compile_dyninst (systemtap_session& s)
{
const string module = s.tmpdir + "/" + s.module_filename();
vector<string> cmd;
cmd.push_back("gcc");
cmd.push_back("--std=gnu99");
cmd.push_back("-Wall");
cmd.push_back("-Werror");
cmd.push_back("-Wno-unused");
cmd.push_back("-Wno-strict-aliasing");
if (s.architecture == "i386")
cmd.push_back("-march=i586");
cmd.push_back("-fvisibility=hidden");
cmd.push_back("-O2");
cmd.push_back("-I" + s.runtime_path);
cmd.push_back("-D__DYNINST__");
for (size_t i = 0; i < s.c_macros.size(); ++i)
cmd.push_back("-D" + s.c_macros[i]);
cmd.push_back(s.translated_source);
cmd.push_back("-pthread");
cmd.push_back("-lrt");
cmd.push_back("-fPIC");
cmd.push_back("-shared");
cmd.push_back("-o");
cmd.push_back(module);
if (s.verbose > 3)
{
cmd.push_back("-ftime-report");
cmd.push_back("-Q");
}
int rc = stap_system (s.verbose, cmd);
if (rc)
s.set_try_server ();
return rc;
}
int
compile_pass (systemtap_session& s)
{
if (s.runtime_usermode_p())
return compile_dyninst (s);
int rc = uprobes_pass (s);
if (rc)
{
s.set_try_server ();
return rc;
}
string makefile_nm = s.tmpdir + "/Makefile";
ofstream o (makefile_nm.c_str());
string superverbose;
if (s.verbose > 3)
superverbose = "set -x;";
string redirecterrors = "> /dev/null 2>&1";
if (s.verbose > 6)
redirecterrors = "";
o << "_KBUILD_CFLAGS := $(call flags,KBUILD_CFLAGS)" << endl;
o << "stap_check_gcc = $(shell " << superverbose << " if $(CC) $(1) -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo \"$(1)\"; else echo \"$(2)\"; fi)" << endl;
o << "CHECK_BUILD := $(CC) $(NOSTDINC_FLAGS) $(KBUILD_CPPFLAGS) $(CPPFLAGS) $(LINUXINCLUDE) $(_KBUILD_CFLAGS) $(CFLAGS_KERNEL) $(EXTRA_CFLAGS) $(CFLAGS) -DKBUILD_BASENAME=\\\"" << s.module_name << "\\\"" << (s.omit_werror ? "" : " -Werror") << " -S -o /dev/null -xc " << endl;
o << "stap_check_build = $(shell " << superverbose << " if $(CHECK_BUILD) $(1) " << redirecterrors << " ; then echo \"$(2)\"; else echo \"$(3)\"; fi)" << endl;
o << "SYSTEMTAP_RUNTIME = \"" << s.runtime_path << "\"" << endl;
o << "CONFIG_MODULE_SIG := n" << endl;
string module_cflags = "EXTRA_CFLAGS";
o << module_cflags << " :=" << endl;
XXX o << module_cflags << " += -Iinclude2/asm/mach-default" << endl;
if (s.kernel_source_tree != "")
o << module_cflags << " += -I" + s.kernel_source_tree << endl;
o << "STAPCONF_HEADER := " << s.tmpdir << "/" << s.stapconf_name << endl;
o << "$(STAPCONF_HEADER):" << endl;
o << "\t@echo -n > $@" << endl;
output_autoconf(s, o, "autoconf-hrtimer-rel.c", "STAPCONF_HRTIMER_REL", NULL);
output_autoconf(s, o, "autoconf-generated-compile.c", "STAPCONF_GENERATED_COMPILE", NULL);
output_autoconf(s, o, "autoconf-hrtimer-getset-expires.c", "STAPCONF_HRTIMER_GETSET_EXPIRES", NULL);
output_autoconf(s, o, "autoconf-inode-private.c", "STAPCONF_INODE_PRIVATE", NULL);
output_autoconf(s, o, "autoconf-constant-tsc.c", "STAPCONF_CONSTANT_TSC", NULL);
output_autoconf(s, o, "autoconf-ktime-get-real.c", "STAPCONF_KTIME_GET_REAL", NULL);
output_autoconf(s, o, "autoconf-x86-uniregs.c", "STAPCONF_X86_UNIREGS", NULL);
output_autoconf(s, o, "autoconf-nameidata.c", "STAPCONF_NAMEIDATA_CLEANUP", NULL);
output_dual_exportconf(s, o, "unregister_kprobes", "unregister_kretprobes", "STAPCONF_UNREGISTER_KPROBES");
output_autoconf(s, o, "autoconf-kprobe-symbol-name.c", "STAPCONF_KPROBE_SYMBOL_NAME", NULL);
output_autoconf(s, o, "autoconf-real-parent.c", "STAPCONF_REAL_PARENT", NULL);
output_autoconf(s, o, "autoconf-uaccess.c", "STAPCONF_LINUX_UACCESS_H", NULL);
output_autoconf(s, o, "autoconf-oneachcpu-retry.c", "STAPCONF_ONEACHCPU_RETRY", NULL);
output_autoconf(s, o, "autoconf-dpath-path.c", "STAPCONF_DPATH_PATH", NULL);
output_exportconf(s, o, "synchronize_kernel", "STAPCONF_SYNCHRONIZE_KERNEL");
output_exportconf(s, o, "synchronize_rcu", "STAPCONF_SYNCHRONIZE_RCU");
output_exportconf(s, o, "synchronize_sched", "STAPCONF_SYNCHRONIZE_SCHED");
output_autoconf(s, o, "autoconf-task-uid.c", "STAPCONF_TASK_UID", NULL);
output_autoconf(s, o, "autoconf-from_kuid_munged.c", "STAPCONF_FROM_KUID_MUNGED", NULL);
output_dual_exportconf(s, o, "alloc_vm_area", "free_vm_area", "STAPCONF_VM_AREA");
output_autoconf(s, o, "autoconf-procfs-owner.c", "STAPCONF_PROCFS_OWNER", NULL);
output_autoconf(s, o, "autoconf-alloc-percpu-align.c", "STAPCONF_ALLOC_PERCPU_ALIGN", NULL);
output_autoconf(s, o, "autoconf-x86-fs.c", "STAPCONF_X86_FS", NULL);
output_autoconf(s, o, "autoconf-x86-xfs.c", "STAPCONF_X86_XFS", NULL);
output_autoconf(s, o, "autoconf-x86-gs.c", "STAPCONF_X86_GS", NULL);
output_autoconf(s, o, "autoconf-grsecurity.c", "STAPCONF_GRSECURITY", NULL);
output_autoconf(s, o, "autoconf-trace-printk.c", "STAPCONF_TRACE_PRINTK", NULL);
output_autoconf(s, o, "autoconf-regset.c", "STAPCONF_REGSET", NULL);
output_autoconf(s, o, "autoconf-utrace-regset.c", "STAPCONF_UTRACE_REGSET", NULL);
output_autoconf(s, o, "autoconf-uprobe-get-pc.c", "STAPCONF_UPROBE_GET_PC", NULL);
output_autoconf(s, o, "autoconf-hlist-4args.c", "STAPCONF_HLIST_4ARGS", NULL);
output_exportconf(s, o, "tsc_khz", "STAPCONF_TSC_KHZ");
output_exportconf(s, o, "cpu_khz", "STAPCONF_CPU_KHZ");
output_exportconf(s, o, "__module_text_address", "STAPCONF_MODULE_TEXT_ADDRESS");
output_exportconf(s, o, "add_timer_on", "STAPCONF_ADD_TIMER_ON");
output_dual_exportconf(s, o, "probe_kernel_read", "probe_kernel_write", "STAPCONF_PROBE_KERNEL");
output_autoconf(s, o, "autoconf-hw_breakpoint_context.c",
"STAPCONF_HW_BREAKPOINT_CONTEXT", NULL);
output_autoconf(s, o, "autoconf-save-stack-trace.c",
"STAPCONF_KERNEL_STACKTRACE", NULL);
output_autoconf(s, o, "autoconf-save-stack-trace-no-bp.c",
"STAPCONF_KERNEL_STACKTRACE_NO_BP", NULL);
output_autoconf(s, o, "autoconf-asm-syscall.c",
"STAPCONF_ASM_SYSCALL_H", NULL);
output_autoconf(s, o, "autoconf-ring_buffer-flags.c", "STAPCONF_RING_BUFFER_FLAGS", NULL);
output_autoconf(s, o, "autoconf-ring_buffer_lost_events.c", "STAPCONF_RING_BUFFER_LOST_EVENTS", NULL);
output_autoconf(s, o, "autoconf-ring_buffer_read_prepare.c", "STAPCONF_RING_BUFFER_READ_PREPARE", NULL);
output_autoconf(s, o, "autoconf-kallsyms-on-each-symbol.c", "STAPCONF_KALLSYMS_ON_EACH_SYMBOL", NULL);
output_autoconf(s, o, "autoconf-walk-stack.c", "STAPCONF_WALK_STACK", NULL);
output_autoconf(s, o, "autoconf-stacktrace_ops-warning.c",
"STAPCONF_STACKTRACE_OPS_WARNING", NULL);
output_autoconf(s, o, "autoconf-mm-context-vdso.c", "STAPCONF_MM_CONTEXT_VDSO", NULL);
output_autoconf(s, o, "autoconf-mm-context-vdso-base.c", "STAPCONF_MM_CONTEXT_VDSO_BASE", NULL);
output_autoconf(s, o, "autoconf-blk-types.c", "STAPCONF_BLK_TYPES", NULL);
output_autoconf(s, o, "autoconf-perf-structpid.c", "STAPCONF_PERF_STRUCTPID", NULL);
output_autoconf(s, o, "perf_event_counter_context.c",
"STAPCONF_PERF_COUNTER_CONTEXT", NULL);
output_autoconf(s, o, "perf_probe_handler_nmi.c",
"STAPCONF_PERF_HANDLER_NMI", NULL);
output_exportconf(s, o, "path_lookup", "STAPCONF_PATH_LOOKUP");
output_exportconf(s, o, "kern_path_parent", "STAPCONF_KERN_PATH_PARENT");
output_exportconf(s, o, "vfs_path_lookup", "STAPCONF_VFS_PATH_LOOKUP");
output_exportconf(s, o, "kern_path", "STAPCONF_KERN_PATH");
output_exportconf(s, o, "proc_create_data", "STAPCONF_PROC_CREATE_DATA");
output_exportconf(s, o, "PDE_DATA", "STAPCONF_PDE_DATA");
output_autoconf(s, o, "autoconf-module-sect-attrs.c", "STAPCONF_MODULE_SECT_ATTRS", NULL);
output_autoconf(s, o, "autoconf-utrace-via-tracepoints.c", "STAPCONF_UTRACE_VIA_TRACEPOINTS", NULL);
output_autoconf(s, o, "autoconf-task_work-struct.c", "STAPCONF_TASK_WORK_STRUCT", NULL);
output_autoconf(s, o, "autoconf-vm-area-pte.c", "STAPCONF_VM_AREA_PTE", NULL);
output_autoconf(s, o, "autoconf-relay-umode_t.c", "STAPCONF_RELAY_UMODE_T", NULL);
output_autoconf(s, o, "autoconf-fs_supers-hlist.c", "STAPCONF_FS_SUPERS_HLIST", NULL);
output_autoconf(s, o, "autoconf-compat_sigaction.c", "STAPCONF_COMPAT_SIGACTION", NULL);
output_autoconf(s, o, "autoconf-netfilter.c", "STAPCONF_NETFILTER_V313", NULL);
output_autoconf(s, o, "autoconf-smpcall-5args.c", "STAPCONF_SMPCALL_5ARGS", NULL);
output_autoconf(s, o, "autoconf-smpcall-4args.c", "STAPCONF_SMPCALL_4ARGS", NULL);
output_exportconf(s, o, "cpu_clock", "STAPCONF_CPU_CLOCK");
output_exportconf(s, o, "local_clock", "STAPCONF_LOCAL_CLOCK");
output_either_exportconf(s, o, "uprobe_register", "register_uprobe",
"STAPCONF_UPROBE_REGISTER_EXPORTED");
output_either_exportconf(s, o, "uprobe_unregister", "unregister_uprobe",
"STAPCONF_UPROBE_UNREGISTER_EXPORTED");
output_autoconf(s, o, "autoconf-old-inode-uprobes.c", "STAPCONF_OLD_INODE_UPROBES", NULL);
output_autoconf(s, o, "autoconf-inode-uretprobes.c", "STAPCONF_INODE_URETPROBES", NULL);
output_exportconf(s, o, "uprobe_get_swbp_addr", "STAPCONF_UPROBE_GET_SWBP_ADDR_EXPORTED");
output_exportconf(s, o, "task_user_regset_view", "STAPCONF_TASK_USER_REGSET_VIEW_EXPORTED");
output_exportconf(s, o, "task_work_add", "STAPCONF_TASK_WORK_ADD_EXPORTED");
output_exportconf(s, o, "wake_up_state", "STAPCONF_WAKE_UP_STATE_EXPORTED");
output_exportconf(s, o, "try_to_wake_up", "STAPCONF_TRY_TO_WAKE_UP_EXPORTED");
output_exportconf(s, o, "signal_wake_up_state", "STAPCONF_SIGNAL_WAKE_UP_STATE_EXPORTED");
output_exportconf(s, o, "signal_wake_up", "STAPCONF_SIGNAL_WAKE_UP_EXPORTED");
output_exportconf(s, o, "__lock_task_sighand", "STAPCONF___LOCK_TASK_SIGHAND_EXPORTED");
output_autoconf(s, o, "autoconf-pagefault_disable.c", "STAPCONF_PAGEFAULT_DISABLE", NULL);
output_exportconf(s, o, "kallsyms_lookup_name", "STAPCONF_KALLSYMS");
output_autoconf(s, o, "autoconf-uidgid.c", "STAPCONF_LINUX_UIDGID_H", NULL);
output_exportconf(s, o, "sigset_from_compat", "STAPCONF_SIGSET_FROM_COMPAT_EXPORTED");
output_exportconf(s, o, "vzalloc", "STAPCONF_VZALLOC");
output_exportconf(s, o, "vzalloc_node", "STAPCONF_VZALLOC_NODE");
output_exportconf(s, o, "vmalloc_node", "STAPCONF_VMALLOC_NODE");
output_autoconf(s, o, "autoconf-tracepoint-strings.c", "STAPCONF_TRACEPOINT_STRINGS", NULL);
o << module_cflags << " += -include $(STAPCONF_HEADER)" << endl;
for (unsigned i=0; i<s.c_macros.size(); i++)
o << "EXTRA_CFLAGS += -D " << lex_cast_qstring(s.c_macros[i]) << endl; XXX
if (s.verbose > 3)
o << "EXTRA_CFLAGS += -ftime-report -Q" << endl;
XXX
o << "EXTRA_CFLAGS += -freorder-blocks" << endl;
o << "EXTRA_CFLAGS += -fasynchronous-unwind-tables" << endl;
XXX o << "EXTRA_CFLAGS += $(call cc-option,-Wframe-larger-than=512)" << endl;
o << "EXTRA_CFLAGS += -Wno-unused" << (s.omit_werror ? "" : " -Werror") << endl;
#if CHECK_POINTER_ARITH_PR5947
o << "EXTRA_CFLAGS += -Wpointer-arith" << endl;
#endif
o << "EXTRA_CFLAGS += -I\"" << s.runtime_path << "\"" << endl;
XXX o << "obj-m := " << s.module_name << ".o" << endl;
o << s.module_name << "-y := ";
for (unsigned i=0; i<s.auxiliary_outputs.size(); i++)
{
if (s.auxiliary_outputs[i]->trailer_p) continue;
string srcname = s.auxiliary_outputs[i]->filename;
assert (srcname != "" && srcname.rfind('/') != string::npos);
string objname = srcname.substr(srcname.rfind('/')+1); assert (objname != "" && objname[objname.size()-1] == 'c');
objname[objname.size()-1] = 'o'; o << " " + objname;
}
{
string srcname = s.translated_source;
assert (srcname != "" && srcname.rfind('/') != string::npos);
string objname = srcname.substr(srcname.rfind('/')+1); assert (objname != "" && objname[objname.size()-1] == 'c');
objname[objname.size()-1] = 'o'; o << " " + objname;
}
for (unsigned i=0; i<s.auxiliary_outputs.size(); i++)
{
if (! s.auxiliary_outputs[i]->trailer_p) continue;
string srcname = s.auxiliary_outputs[i]->filename;
assert (srcname != "" && srcname.rfind('/') != string::npos);
string objname = srcname.substr(srcname.rfind('/')+1); assert (objname != "" && objname[objname.size()-1] == 'c');
objname[objname.size()-1] = 'o'; o << " " + objname;
}
o << endl;
o << s.translated_source << ": $(STAPCONF_HEADER)" << endl;
for (unsigned i=0; i<s.auxiliary_outputs.size(); i++)
o << s.auxiliary_outputs[i]->filename << ": $(STAPCONF_HEADER)" << endl;
o.close ();
string module_dir = s.kernel_build_tree;
string module_dir_makefile = module_dir + "/Makefile";
struct stat st;
rc = stat(module_dir_makefile.c_str(), &st);
if (rc != 0)
{
clog << _F("Checking \" %s \" failed with error: %s\nEnsure kernel development headers & makefiles are installed.",
module_dir_makefile.c_str(), strerror(errno)) << endl;
s.set_try_server ();
return rc;
}
vector<string> make_cmd = make_make_cmd(s, s.tmpdir);
rc = run_make_cmd(s, make_cmd);
if (rc)
s.set_try_server ();
return rc;
}
static bool
kernel_built_uprobes (systemtap_session& s)
{
if (s.runtime_usermode_p())
return true;
return ((s.kernel_config["CONFIG_ARCH_SUPPORTS_UPROBES"] == "y" && s.kernel_config["CONFIG_UPROBES"] == "y") ||
(s.kernel_exports.find("unregister_uprobe") != s.kernel_exports.end()));
}
static int
make_uprobes (systemtap_session& s)
{
if (s.verbose > 1)
clog << _("Pass 4, preamble: (re)building SystemTap's version of uprobes.")
<< endl;
string dir(s.tmpdir + "/uprobes");
if (create_dir(dir.c_str()) != 0)
{
s.print_warning("failed to create directory for build uprobes.");
s.set_try_server ();
return 1;
}
string makefile(dir + "/Makefile");
ofstream omf(makefile.c_str());
omf << "obj-m := uprobes.o" << endl;
omf << "CONFIG_MODULE_SIG := n" << endl;
omf.close();
string runtimesourcefile(s.runtime_path + "/linux/uprobes/uprobes.c");
string sourcefile(dir + "/uprobes.c");
ofstream osrc(sourcefile.c_str());
osrc << "#include \"" << runtimesourcefile << "\"" << endl;
for (unsigned i = 0; i < s.modinfos.size(); i++)
{
const string& mi = s.modinfos[i];
size_t loc = mi.find('=');
string tag = mi.substr (0, loc);
string value = mi.substr (loc+1);
osrc << "MODULE_INFO(" << tag << "," << lex_cast_qstring(value) << ");" << endl;
}
osrc.close();
vector<string> make_cmd = make_make_cmd(s, dir);
int rc = run_make_cmd(s, make_cmd);
if (!rc && !copy_file(dir + "/Module.symvers",
s.tmpdir + "/Module.symvers"))
rc = -1;
if (s.verbose > 1)
clog << _("uprobes rebuild exit code: ") << rc << endl;
if (rc)
s.set_try_server ();
else
s.uprobes_path = dir + "/uprobes.ko";
return rc;
}
static bool
get_cached_uprobes(systemtap_session& s)
{
s.uprobes_hash = s.use_cache ? find_uprobes_hash(s) : "";
if (!s.uprobes_hash.empty())
{
string dir(s.tmpdir + "/uprobes");
if (create_dir(dir.c_str()) != 0)
return false;
string cacheko = s.uprobes_hash + ".ko";
string tmpko = dir + "/uprobes.ko";
string cachesyms = s.uprobes_hash + ".symvers";
string tmpsyms = s.tmpdir + "/Module.symvers";
if (get_file_size(cacheko) > 0 && copy_file(cacheko, tmpko) &&
get_file_size(cachesyms) > 0 && copy_file(cachesyms, tmpsyms))
{
s.uprobes_path = tmpko;
return true;
}
}
return false;
}
static void
set_cached_uprobes(systemtap_session& s)
{
if (s.use_cache && !s.uprobes_hash.empty())
{
string cacheko = s.uprobes_hash + ".ko";
string tmpko = s.tmpdir + "/uprobes/uprobes.ko";
copy_file(tmpko, cacheko);
string cachesyms = s.uprobes_hash + ".symvers";
string tmpsyms = s.tmpdir + "/uprobes/Module.symvers";
copy_file(tmpsyms, cachesyms);
}
}
int
uprobes_pass (systemtap_session& s)
{
if (!s.need_uprobes || kernel_built_uprobes(s))
return 0;
if (s.kernel_config["CONFIG_UTRACE"] != string("y"))
{
clog << _("user-space process-tracking facilities not available [man error::process-tracking]") << endl;
s.set_try_server ();
return 1;
}
int rc = 0;
if (!get_cached_uprobes(s))
{
rc = make_uprobes(s);
if (!rc)
set_cached_uprobes(s);
}
if (rc)
s.set_try_server ();
return rc;
}
static
vector<string>
make_dyninst_run_command (systemtap_session& s, const string& remotedir,
const string& version)
{
vector<string> cmd;
cmd.push_back(getenv("SYSTEMTAP_STAPDYN") ?: BINDIR "/stapdyn");
for (unsigned i=1; i<s.verbose; i++)
cmd.push_back("-v");
if (s.suppress_warnings)
cmd.push_back("-w");
if (!s.cmd.empty())
{
cmd.push_back("-c");
cmd.push_back(s.cmd);
}
if (s.target_pid)
{
cmd.push_back("-x");
cmd.push_back(lex_cast(s.target_pid));
}
if (!s.output_file.empty())
{
cmd.push_back("-o");
cmd.push_back(s.output_file);
}
if (s.color_mode != s.color_auto)
{
cmd.push_back("-C");
if (s.color_mode == s.color_always)
cmd.push_back("always");
else
cmd.push_back("never");
}
cmd.push_back((remotedir.empty() ? s.tmpdir : remotedir)
+ "/" + s.module_filename());
cmd.insert(cmd.end(), s.globalopts.begin(), s.globalopts.end());
return cmd;
}
vector<string>
make_run_command (systemtap_session& s, const string& remotedir,
const string& version)
{
if (s.runtime_usermode_p())
return make_dyninst_run_command(s, remotedir, version);
vector<string> staprun_cmd;
staprun_cmd.push_back(getenv("SYSTEMTAP_STAPRUN") ?: BINDIR "/staprun");
for (unsigned i=1; i<s.verbose; i++)
staprun_cmd.push_back("-v");
if (s.suppress_warnings)
staprun_cmd.push_back("-w");
if (!s.output_file.empty())
{
staprun_cmd.push_back("-o");
staprun_cmd.push_back(s.output_file);
}
if (!s.cmd.empty())
{
staprun_cmd.push_back("-c");
staprun_cmd.push_back(s.cmd);
}
if (s.target_pid)
{
staprun_cmd.push_back("-t");
staprun_cmd.push_back(lex_cast(s.target_pid));
}
if (s.buffer_size)
{
staprun_cmd.push_back("-b");
staprun_cmd.push_back(lex_cast(s.buffer_size));
}
if (s.need_uprobes && !kernel_built_uprobes(s))
{
string opt_u = "-u";
if (!s.uprobes_path.empty() &&
strverscmp("1.4", version.c_str()) <= 0)
{
if (remotedir.empty())
opt_u.append(s.uprobes_path);
else
opt_u.append(remotedir + "/" + basename(s.uprobes_path.c_str()));
}
staprun_cmd.push_back(opt_u);
}
if (s.load_only)
staprun_cmd.push_back(s.output_file.empty() ? "-L" : "-D");
if (!s.modname_given && (strverscmp("1.6", version.c_str()) <= 0)
&& s.mok_fingerprints.empty())
staprun_cmd.push_back("-R");
if (!s.size_option.empty())
{
staprun_cmd.push_back("-S");
staprun_cmd.push_back(s.size_option);
}
if (s.color_mode != s.color_auto)
{
staprun_cmd.push_back("-C");
if (s.color_mode == s.color_always)
staprun_cmd.push_back("always");
else
staprun_cmd.push_back("never");
}
staprun_cmd.push_back((remotedir.empty() ? s.tmpdir : remotedir)
+ "/" + s.module_filename());
staprun_cmd.insert(staprun_cmd.end(),
s.globalopts.begin(), s.globalopts.end());
return staprun_cmd;
}
map<string,string>
make_tracequeries(systemtap_session& s, const map<string,string>& contents)
{
static unsigned tick = 0;
string basename("tracequery_kmod_" + lex_cast(++tick));
map<string,string> objs;
string dir(s.tmpdir + "/" + basename);
if (create_dir(dir.c_str()) != 0)
{
s.print_warning("failed to create directory for querying tracepoints.");
s.set_try_server ();
return objs;
}
string makefile(dir + "/Makefile");
ofstream omf(makefile.c_str());
omf << "EXTRA_CFLAGS := -g -Wno-implicit-function-declaration" << (s.omit_werror ? "" : " -Werror") << endl;
omf << "CONFIG_MODULE_SIG := n" << endl;
if (s.kernel_source_tree != "")
omf << "EXTRA_CFLAGS += -I" + s.kernel_source_tree << endl;
omf << "obj-m := " << endl;
for (map<string,string>::const_iterator it = contents.begin(); it != contents.end(); it++)
{
string sbasename = basename + "_" + lex_cast(++tick);
string srcname = dir + "/" + sbasename + ".c";
string src = it->second;
ofstream osrc(srcname.c_str());
osrc << src;
osrc.close();
if (s.verbose > 2)
clog << _F("Processing tracepoint header %s with query %s",
it->first.c_str(), srcname.c_str())
<< endl;
omf << "obj-m += " + sbasename + ".o" << endl; objs[it->first] = dir + "/" + sbasename + ".o";
}
omf.close();
vector<string> make_cmd = make_make_objs_cmd(s, dir);
make_cmd.push_back ("-i"); bool quiet = (s.verbose < 4);
int rc = run_make_cmd(s, make_cmd, quiet, quiet);
if (rc)
s.set_try_server ();
return objs;
}
static int
make_typequery_kmod(systemtap_session& s, const vector<string>& headers, string& name)
{
static unsigned tick = 0;
string basename("typequery_kmod_" + lex_cast(++tick));
string dir(s.tmpdir + "/" + basename);
if (create_dir(dir.c_str()) != 0)
{
s.print_warning("failed to create directory for querying types.");
s.set_try_server ();
return 1;
}
name = dir + "/" + basename + ".ko";
string makefile(dir + "/Makefile");
ofstream omf(makefile.c_str());
omf << "EXTRA_CFLAGS := -g -fno-eliminate-unused-debug-types" << endl;
omf << "CONFIG_MODULE_SIG := n" << endl;
omf << "CFLAGS_" << basename << ".o :=";
for (size_t i = 0; i < headers.size(); ++i)
omf << " -include " << lex_cast_qstring(headers[i]); XXX omf << endl;
omf << "obj-m := " + basename + ".o" << endl;
omf.close();
string source(dir + "/" + basename + ".c");
ofstream osrc(source.c_str());
osrc.close();
vector<string> make_cmd = make_make_cmd(s, dir);
bool quiet = (s.verbose < 4);
int rc = run_make_cmd(s, make_cmd, quiet, quiet);
if (rc)
s.set_try_server ();
return rc;
}
static int
make_typequery_umod(systemtap_session& s, const vector<string>& headers, string& name)
{
static unsigned tick = 0;
name = s.tmpdir + "/typequery_umod_" + lex_cast(++tick) + ".so";
vector<string> cmd;
cmd.push_back("gcc");
cmd.push_back("-shared");
cmd.push_back("-g");
cmd.push_back("-fno-eliminate-unused-debug-types");
cmd.push_back("-xc");
cmd.push_back("/dev/null");
cmd.push_back("-o");
cmd.push_back(name);
for (size_t i = 0; i < headers.size(); ++i)
{
cmd.push_back("-include");
cmd.push_back(headers[i]);
}
bool quiet = (s.verbose < 4);
int rc = stap_system (s.verbose, cmd, quiet, quiet);
if (rc)
s.set_try_server ();
return rc;
}
int
make_typequery(systemtap_session& s, string& module)
{
int rc;
string new_module;
vector<string> headers;
bool kernel = startswith(module, "kernel");
for (size_t end, i = kernel ? 6 : 0; i < module.size(); i = end + 1)
{
if (module[i] != '<')
return -1;
end = module.find('>', ++i);
if (end == string::npos)
return -1;
string header = module.substr(i, end - i);
vector<string> matches;
if (regexp_match(header, "^[a-zA-Z0-9/_.+-]+$", matches))
s.print_warning("skipping malformed @cast header \""+ header + "\"");
else
headers.push_back(header);
}
if (headers.empty())
return -1;
if (kernel)
rc = make_typequery_kmod(s, headers, new_module);
else
rc = make_typequery_umod(s, headers, new_module);
if (!rc)
module = new_module;
return rc;
}