diff options
author | Josh Stone <jistone@redhat.com> | 2009-05-07 16:17:11 -0700 |
---|---|---|
committer | Josh Stone <jistone@redhat.com> | 2009-05-07 16:17:11 -0700 |
commit | 93646f4d5ccaa051cd996cc2ab6a2b4a21418714 (patch) | |
tree | 38a0ed4ae4871ec2574778dd812b5e388d548185 | |
parent | dd0e4fa70fd7589ff80618305bd3d24e98a5d73b (diff) | |
download | systemtap-steved-93646f4d5ccaa051cd996cc2ab6a2b4a21418714.tar.gz systemtap-steved-93646f4d5ccaa051cd996cc2ab6a2b4a21418714.tar.xz systemtap-steved-93646f4d5ccaa051cd996cc2ab6a2b4a21418714.zip |
Separate task_finder and the itrace tapset
-rw-r--r-- | Makefile.am | 3 | ||||
-rw-r--r-- | Makefile.in | 34 | ||||
-rw-r--r-- | tapset-itrace.cxx | 337 | ||||
-rw-r--r-- | tapsets.cxx | 389 | ||||
-rw-r--r-- | tapsets.h | 3 | ||||
-rw-r--r-- | task_finder.cxx | 103 | ||||
-rw-r--r-- | task_finder.h | 20 |
7 files changed, 501 insertions, 388 deletions
diff --git a/Makefile.am b/Makefile.am index e65d1535..4b2d724d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -39,7 +39,8 @@ stap_SOURCES = main.cxx \ tapsets.cxx buildrun.cxx loc2c.c hash.cxx mdfour.c \ cache.cxx util.cxx coveragedb.cxx dwarf_wrappers.cxx \ tapset-been.cxx tapset-procfs.cxx tapset-timers.cxx \ - tapset-perfmon.cxx tapset-mark.cxx + tapset-perfmon.cxx tapset-mark.cxx tapset-itrace.cxx \ + task_finder.cxx stap_LDADD = @stap_LIBS@ @sqlite3_LIBS@ BUILT_SOURCES = diff --git a/Makefile.in b/Makefile.in index 0e0aee9a..baaed3dd 100644 --- a/Makefile.in +++ b/Makefile.in @@ -124,6 +124,7 @@ am_stap_OBJECTS = stap-main.$(OBJEXT) stap-parse.$(OBJEXT) \ stap-dwarf_wrappers.$(OBJEXT) stap-tapset-been.$(OBJEXT) \ stap-tapset-procfs.$(OBJEXT) stap-tapset-timers.$(OBJEXT) \ stap-tapset-perfmon.$(OBJEXT) stap-tapset-mark.$(OBJEXT) \ + stap-tapset-itrace.$(OBJEXT) stap-task_finder.$(OBJEXT) \ $(am__objects_1) stap_OBJECTS = $(am_stap_OBJECTS) stap_LINK = $(CXXLD) $(stap_CXXFLAGS) $(CXXFLAGS) $(stap_LDFLAGS) \ @@ -331,7 +332,8 @@ stap_SOURCES = main.cxx parse.cxx staptree.cxx elaborate.cxx \ translate.cxx tapsets.cxx buildrun.cxx loc2c.c hash.cxx \ mdfour.c cache.cxx util.cxx coveragedb.cxx dwarf_wrappers.cxx \ tapset-been.cxx tapset-procfs.cxx tapset-timers.cxx \ - tapset-perfmon.cxx tapset-mark.cxx $(am__append_4) + tapset-perfmon.cxx tapset-mark.cxx tapset-itrace.cxx \ + task_finder.cxx $(am__append_4) stap_LDADD = @stap_LIBS@ @sqlite3_LIBS@ $(am__append_6) # Arrange for git_version.h to be regenerated at every "make". @@ -606,11 +608,13 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-parse.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-staptree.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-tapset-been.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-tapset-itrace.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-tapset-mark.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-tapset-perfmon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-tapset-procfs.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-tapset-timers.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-tapsets.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-task_finder.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-translate.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-util.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap_client_connect-stap-client-connect.Po@am__quote@ @@ -1160,6 +1164,34 @@ stap-tapset-mark.obj: tapset-mark.cxx @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -c -o stap-tapset-mark.obj `if test -f 'tapset-mark.cxx'; then $(CYGPATH_W) 'tapset-mark.cxx'; else $(CYGPATH_W) '$(srcdir)/tapset-mark.cxx'; fi` +stap-tapset-itrace.o: tapset-itrace.cxx +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -MT stap-tapset-itrace.o -MD -MP -MF $(DEPDIR)/stap-tapset-itrace.Tpo -c -o stap-tapset-itrace.o `test -f 'tapset-itrace.cxx' || echo '$(srcdir)/'`tapset-itrace.cxx +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/stap-tapset-itrace.Tpo $(DEPDIR)/stap-tapset-itrace.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tapset-itrace.cxx' object='stap-tapset-itrace.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -c -o stap-tapset-itrace.o `test -f 'tapset-itrace.cxx' || echo '$(srcdir)/'`tapset-itrace.cxx + +stap-tapset-itrace.obj: tapset-itrace.cxx +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -MT stap-tapset-itrace.obj -MD -MP -MF $(DEPDIR)/stap-tapset-itrace.Tpo -c -o stap-tapset-itrace.obj `if test -f 'tapset-itrace.cxx'; then $(CYGPATH_W) 'tapset-itrace.cxx'; else $(CYGPATH_W) '$(srcdir)/tapset-itrace.cxx'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/stap-tapset-itrace.Tpo $(DEPDIR)/stap-tapset-itrace.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tapset-itrace.cxx' object='stap-tapset-itrace.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -c -o stap-tapset-itrace.obj `if test -f 'tapset-itrace.cxx'; then $(CYGPATH_W) 'tapset-itrace.cxx'; else $(CYGPATH_W) '$(srcdir)/tapset-itrace.cxx'; fi` + +stap-task_finder.o: task_finder.cxx +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -MT stap-task_finder.o -MD -MP -MF $(DEPDIR)/stap-task_finder.Tpo -c -o stap-task_finder.o `test -f 'task_finder.cxx' || echo '$(srcdir)/'`task_finder.cxx +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/stap-task_finder.Tpo $(DEPDIR)/stap-task_finder.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='task_finder.cxx' object='stap-task_finder.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -c -o stap-task_finder.o `test -f 'task_finder.cxx' || echo '$(srcdir)/'`task_finder.cxx + +stap-task_finder.obj: task_finder.cxx +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -MT stap-task_finder.obj -MD -MP -MF $(DEPDIR)/stap-task_finder.Tpo -c -o stap-task_finder.obj `if test -f 'task_finder.cxx'; then $(CYGPATH_W) 'task_finder.cxx'; else $(CYGPATH_W) '$(srcdir)/task_finder.cxx'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/stap-task_finder.Tpo $(DEPDIR)/stap-task_finder.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='task_finder.cxx' object='stap-task_finder.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -c -o stap-task_finder.obj `if test -f 'task_finder.cxx'; then $(CYGPATH_W) 'task_finder.cxx'; else $(CYGPATH_W) '$(srcdir)/task_finder.cxx'; fi` + stap-modsign.o: modsign.cxx @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -MT stap-modsign.o -MD -MP -MF $(DEPDIR)/stap-modsign.Tpo -c -o stap-modsign.o `test -f 'modsign.cxx' || echo '$(srcdir)/'`modsign.cxx @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/stap-modsign.Tpo $(DEPDIR)/stap-modsign.Po diff --git a/tapset-itrace.cxx b/tapset-itrace.cxx new file mode 100644 index 00000000..38304a98 --- /dev/null +++ b/tapset-itrace.cxx @@ -0,0 +1,337 @@ +// tapset for timers +// Copyright (C) 2005-2009 Red Hat Inc. +// Copyright (C) 2005-2007 Intel Corporation. +// Copyright (C) 2008 James.Bottomley@HansenPartnership.com +// +// This file is part of systemtap, and is free software. You can +// redistribute it and/or modify it under the terms of the GNU General +// Public License (GPL); either version 2, or (at your option) any +// later version. + + +#include "session.h" +#include "tapsets.h" +#include "task_finder.h" +#include "translate.h" +#include "util.h" + +#include <cstring> +#include <string> + + +using namespace std; +using namespace __gnu_cxx; + + +static string TOK_PROCESS("process"); +static string TOK_INSN("insn"); +static string TOK_BLOCK("block"); + + +// ------------------------------------------------------------------------ +// itrace user-space probes +// ------------------------------------------------------------------------ + + +struct itrace_derived_probe: public derived_probe +{ + bool has_path; + string path; + int64_t pid; + int single_step; + + itrace_derived_probe (systemtap_session &s, probe* p, probe_point* l, + bool hp, string &pn, int64_t pd, int ss + ); + void join_group (systemtap_session& s); +}; + + +struct itrace_derived_probe_group: public generic_dpg<itrace_derived_probe> +{ +private: + map<string, vector<itrace_derived_probe*> > probes_by_path; + typedef map<string, vector<itrace_derived_probe*> >::iterator p_b_path_iterator; + map<int64_t, vector<itrace_derived_probe*> > probes_by_pid; + typedef map<int64_t, vector<itrace_derived_probe*> >::iterator p_b_pid_iterator; + unsigned num_probes; + + void emit_probe_decl (systemtap_session& s, itrace_derived_probe *p); + +public: + itrace_derived_probe_group(): num_probes(0) { } + + void enroll (itrace_derived_probe* probe); + void emit_module_decls (systemtap_session& s); + void emit_module_init (systemtap_session& s); + void emit_module_exit (systemtap_session& s); +}; + + +itrace_derived_probe::itrace_derived_probe (systemtap_session &s, + probe* p, probe_point* l, + bool hp, string &pn, int64_t pd, + int ss + ): + derived_probe(p, l), has_path(hp), path(pn), pid(pd), single_step(ss) +{ +} + + +void +itrace_derived_probe::join_group (systemtap_session& s) +{ + if (! s.itrace_derived_probes) + s.itrace_derived_probes = new itrace_derived_probe_group (); + + s.itrace_derived_probes->enroll (this); + + enable_task_finder(s); +} + +struct itrace_builder: public derived_probe_builder +{ + itrace_builder() {} + virtual void build(systemtap_session & sess, + probe * base, + probe_point * location, + std::map<std::string, literal *> const & parameters, + vector<derived_probe *> & finished_results) + { + string path; + int64_t pid = 0; + int single_step; + + bool has_path = get_param (parameters, TOK_PROCESS, path); + bool has_pid = get_param (parameters, TOK_PROCESS, pid); + // XXX: PR 6445 needs !has_path && !has_pid support + assert (has_path || has_pid); + + single_step = ! has_null_param (parameters, TOK_BLOCK); + + // If we have a path, we need to validate it. + if (has_path) + path = find_executable (path); + + finished_results.push_back(new itrace_derived_probe(sess, base, location, + has_path, path, pid, + single_step + )); + } +}; + + +void +itrace_derived_probe_group::enroll (itrace_derived_probe* p) +{ + if (p->has_path) + probes_by_path[p->path].push_back(p); + else + probes_by_pid[p->pid].push_back(p); + num_probes++; + + // XXX: multiple exec probes (for instance) for the same path (or + // pid) should all share a itrace report function, and have their + // handlers executed sequentially. +} + + +void +itrace_derived_probe_group::emit_probe_decl (systemtap_session& s, + itrace_derived_probe *p) +{ + s.op->newline() << "{"; + s.op->line() << " .tgt={"; + + if (p->has_path) + { + s.op->line() << " .pathname=\"" << p->path << "\","; + s.op->line() << " .pid=0,"; + } + else + { + s.op->line() << " .pathname=NULL,"; + s.op->line() << " .pid=" << p->pid << ","; + } + + s.op->line() << " .callback=&_stp_itrace_probe_cb,"; + s.op->line() << " },"; + s.op->line() << " .pp=" << lex_cast_qstring (*p->sole_location()) << ","; + s.op->line() << " .single_step=" << p->single_step << ","; + s.op->line() << " .ph=&" << p->name << ","; + + s.op->line() << " },"; +} + + +void +itrace_derived_probe_group::emit_module_decls (systemtap_session& s) +{ + if (probes_by_path.empty() && probes_by_pid.empty()) + return; + + s.op->newline(); + s.op->newline() << "/* ---- itrace probes ---- */"; + + s.op->newline() << "struct stap_itrace_probe {"; + s.op->indent(1); + s.op->newline() << "struct stap_task_finder_target tgt;"; + s.op->newline() << "const char *pp;"; + s.op->newline() << "void (*ph) (struct context*);"; + s.op->newline() << "int single_step;"; + s.op->newline(-1) << "};"; + s.op->newline() << "static void enter_itrace_probe(struct stap_itrace_probe *p, struct pt_regs *regs, void *data);"; + s.op->newline() << "#include \"itrace.c\""; + + // output routine to call itrace probe + s.op->newline() << "static void enter_itrace_probe(struct stap_itrace_probe *p, struct pt_regs *regs, void *data) {"; + s.op->indent(1); + + common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "p->pp"); + s.op->newline() << "c->regs = regs;"; + s.op->newline() << "c->data = data;"; + + // call probe function + s.op->newline() << "(*p->ph) (c);"; + common_probe_entryfn_epilogue (s.op); + + s.op->newline() << "return;"; + s.op->newline(-1) << "}"; + + // Output task finder callback routine that gets called for all + // itrace probe types. + s.op->newline() << "static int _stp_itrace_probe_cb(struct stap_task_finder_target *tgt, struct task_struct *tsk, int register_p, int process_p) {"; + s.op->indent(1); + s.op->newline() << "int rc = 0;"; + s.op->newline() << "struct stap_itrace_probe *p = container_of(tgt, struct stap_itrace_probe, tgt);"; + + s.op->newline() << "if (register_p) "; + s.op->indent(1); + + s.op->newline() << "rc = usr_itrace_init(p->single_step, tsk->pid, p);"; + s.op->newline(-1) << "else"; + s.op->newline(1) << "remove_usr_itrace_info(find_itrace_info(p->tgt.pid));"; + s.op->newline(-1) << "return rc;"; + s.op->newline(-1) << "}"; + + // Emit vma callbacks. + s.op->newline() << "#ifdef STP_NEED_VMA_TRACKER"; + s.op->newline() << "static struct stap_task_finder_target stap_itrace_vmcbs[] = {"; + s.op->indent(1); + if (! probes_by_path.empty()) + { + for (p_b_path_iterator it = probes_by_path.begin(); + it != probes_by_path.end(); it++) + emit_vma_callback_probe_decl (s, it->first, (int64_t)0); + } + if (! probes_by_pid.empty()) + { + for (p_b_pid_iterator it = probes_by_pid.begin(); + it != probes_by_pid.end(); it++) + emit_vma_callback_probe_decl (s, "", it->first); + } + s.op->newline(-1) << "};"; + s.op->newline() << "#endif"; + + s.op->newline() << "static struct stap_itrace_probe stap_itrace_probes[] = {"; + s.op->indent(1); + + // Set up 'process(PATH)' probes + if (! probes_by_path.empty()) + { + for (p_b_path_iterator it = probes_by_path.begin(); + it != probes_by_path.end(); it++) + { + for (unsigned i = 0; i < it->second.size(); i++) + { + itrace_derived_probe *p = it->second[i]; + emit_probe_decl(s, p); + } + } + } + + // Set up 'process(PID)' probes + if (! probes_by_pid.empty()) + { + for (p_b_pid_iterator it = probes_by_pid.begin(); + it != probes_by_pid.end(); it++) + { + for (unsigned i = 0; i < it->second.size(); i++) + { + itrace_derived_probe *p = it->second[i]; + emit_probe_decl(s, p); + } + } + } + s.op->newline(-1) << "};"; +} + + +void +itrace_derived_probe_group::emit_module_init (systemtap_session& s) +{ + if (probes_by_path.empty() && probes_by_pid.empty()) + return; + + s.op->newline(); + s.op->newline() << "#ifdef STP_NEED_VMA_TRACKER"; + s.op->newline() << "_stp_sym_init();"; + s.op->newline() << "/* ---- itrace vma callbacks ---- */"; + s.op->newline() << "for (i=0; i<ARRAY_SIZE(stap_itrace_vmcbs); i++) {"; + s.op->indent(1); + s.op->newline() << "struct stap_task_finder_target *r = &stap_itrace_vmcbs[i];"; + s.op->newline() << "rc = stap_register_task_finder_target(r);"; + s.op->newline(-1) << "}"; + s.op->newline() << "#endif"; + + s.op->newline(); + s.op->newline() << "/* ---- itrace probes ---- */"; + + s.op->newline() << "for (i=0; i<" << num_probes << "; i++) {"; + s.op->indent(1); + s.op->newline() << "struct stap_itrace_probe *p = &stap_itrace_probes[i];"; + + // 'arch_has_single_step' needs to be defined for either single step mode + // or branch mode. + s.op->newline() << "if (!arch_has_single_step()) {"; + s.op->indent(1); + s.op->newline() << "_stp_error (\"insn probe init: arch does not support step mode\");"; + s.op->newline() << "rc = -EPERM;"; + s.op->newline() << "break;"; + s.op->newline(-1) << "}"; + s.op->newline() << "if (!p->single_step && !arch_has_block_step()) {"; + s.op->indent(1); + s.op->newline() << "_stp_error (\"insn probe init: arch does not support block step mode\");"; + s.op->newline() << "rc = -EPERM;"; + s.op->newline() << "break;"; + s.op->newline(-1) << "}"; + + s.op->newline() << "rc = stap_register_task_finder_target(&p->tgt);"; + s.op->newline(-1) << "}"; +} + + +void +itrace_derived_probe_group::emit_module_exit (systemtap_session& s) +{ + if (probes_by_path.empty() && probes_by_pid.empty()) return; + s.op->newline(); + s.op->newline() << "/* ---- itrace probes ---- */"; + s.op->newline() << "cleanup_usr_itrace();"; +} + +void +register_tapset_itrace(systemtap_session& s) +{ + match_node* root = s.pattern_root; + derived_probe_builder *builder = new itrace_builder(); + + root->bind_str(TOK_PROCESS)->bind(TOK_INSN)->bind(builder); + root->bind_num(TOK_PROCESS)->bind(TOK_INSN)->bind(builder); + root->bind_str(TOK_PROCESS)->bind(TOK_INSN)->bind(TOK_BLOCK)->bind(builder); + root->bind_num(TOK_PROCESS)->bind(TOK_INSN)->bind(TOK_BLOCK)->bind(builder); +} + + + +/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */ diff --git a/tapsets.cxx b/tapsets.cxx index 3ea94a73..6a4d41b6 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -12,6 +12,7 @@ #include "staptree.h" #include "elaborate.h" #include "tapsets.h" +#include "task_finder.h" #include "translate.h" #include "session.h" #include "util.h" @@ -6150,379 +6151,6 @@ module_info::~module_info() delete sym_table; } -// Helper function to emit vma tracker callbacks. -static void -emit_vma_callback_probe_decl (systemtap_session& s, - string path, - int64_t pid) -{ - s.op->newline() << "{"; - if (pid == 0) - { - s.op->line() << " .pathname=\"" << path << "\","; - s.op->line() << " .pid=0,"; - } - else - { - s.op->line() << " .pathname=NULL,"; - s.op->line() << " .pid=" << pid << ","; - } - s.op->line() << " .callback=NULL,"; - s.op->line() << " .mmap_callback=&_stp_tf_mmap_cb,"; - s.op->line() << " .munmap_callback=&_stp_tf_munmap_cb,"; - s.op->line() << " .mprotect_callback=NULL,"; - s.op->line() << " },"; -} - -// ------------------------------------------------------------------------ -// task_finder derived 'probes': These don't really exist. The whole -// purpose of the task_finder_derived_probe_group is to make sure that -// stap_start_task_finder()/stap_stop_task_finder() get called only -// once and in the right place. -// ------------------------------------------------------------------------ - -struct task_finder_derived_probe: public derived_probe -{ - // Dummy constructor for gcc 3.4 compatibility - task_finder_derived_probe (): derived_probe (0) { assert(0); } -}; - - -struct task_finder_derived_probe_group: public generic_dpg<task_finder_derived_probe> -{ -public: - static void create_session_group (systemtap_session& s); - - void emit_module_decls (systemtap_session& ) { } - void emit_module_init (systemtap_session& s); - void emit_module_exit (systemtap_session& s); -}; - - -void -task_finder_derived_probe_group::create_session_group (systemtap_session& s) -{ - if (! s.task_finder_derived_probes) - s.task_finder_derived_probes = new task_finder_derived_probe_group(); -} - - -void -task_finder_derived_probe_group::emit_module_init (systemtap_session& s) -{ - s.op->newline(); - s.op->newline() << "/* ---- task finder ---- */"; - s.op->newline() << "rc = stap_start_task_finder();"; - - s.op->newline() << "if (rc) {"; - s.op->newline(1) << "stap_stop_task_finder();"; - s.op->newline(-1) << "}"; -} - - -void -task_finder_derived_probe_group::emit_module_exit (systemtap_session& s) -{ - s.op->newline(); - s.op->newline() << "/* ---- task finder ---- */"; - s.op->newline() << "stap_stop_task_finder();"; -} - -// ------------------------------------------------------------------------ -// itrace user-space probes -// ------------------------------------------------------------------------ - - -static string TOK_INSN("insn"); -static string TOK_BLOCK("block"); - -struct itrace_derived_probe: public derived_probe -{ - bool has_path; - string path; - int64_t pid; - int single_step; - - itrace_derived_probe (systemtap_session &s, probe* p, probe_point* l, - bool hp, string &pn, int64_t pd, int ss - ); - void join_group (systemtap_session& s); -}; - - -struct itrace_derived_probe_group: public generic_dpg<itrace_derived_probe> -{ -private: - map<string, vector<itrace_derived_probe*> > probes_by_path; - typedef map<string, vector<itrace_derived_probe*> >::iterator p_b_path_iterator; - map<int64_t, vector<itrace_derived_probe*> > probes_by_pid; - typedef map<int64_t, vector<itrace_derived_probe*> >::iterator p_b_pid_iterator; - unsigned num_probes; - - void emit_probe_decl (systemtap_session& s, itrace_derived_probe *p); - -public: - itrace_derived_probe_group(): num_probes(0) { } - - void enroll (itrace_derived_probe* probe); - void emit_module_decls (systemtap_session& s); - void emit_module_init (systemtap_session& s); - void emit_module_exit (systemtap_session& s); -}; - - -itrace_derived_probe::itrace_derived_probe (systemtap_session &s, - probe* p, probe_point* l, - bool hp, string &pn, int64_t pd, - int ss - ): - derived_probe(p, l), has_path(hp), path(pn), pid(pd), single_step(ss) -{ -} - - -void -itrace_derived_probe::join_group (systemtap_session& s) -{ - if (! s.itrace_derived_probes) - s.itrace_derived_probes = new itrace_derived_probe_group (); - - s.itrace_derived_probes->enroll (this); - - task_finder_derived_probe_group::create_session_group (s); -} - -struct itrace_builder: public derived_probe_builder -{ - itrace_builder() {} - virtual void build(systemtap_session & sess, - probe * base, - probe_point * location, - std::map<std::string, literal *> const & parameters, - vector<derived_probe *> & finished_results) - { - string path; - int64_t pid = 0; - int single_step; - - bool has_path = get_param (parameters, TOK_PROCESS, path); - bool has_pid = get_param (parameters, TOK_PROCESS, pid); - // XXX: PR 6445 needs !has_path && !has_pid support - assert (has_path || has_pid); - - single_step = ! has_null_param (parameters, TOK_BLOCK); - - // If we have a path, we need to validate it. - if (has_path) - path = find_executable (path); - - finished_results.push_back(new itrace_derived_probe(sess, base, location, - has_path, path, pid, - single_step - )); - } -}; - - -void -itrace_derived_probe_group::enroll (itrace_derived_probe* p) -{ - if (p->has_path) - probes_by_path[p->path].push_back(p); - else - probes_by_pid[p->pid].push_back(p); - num_probes++; - - // XXX: multiple exec probes (for instance) for the same path (or - // pid) should all share a itrace report function, and have their - // handlers executed sequentially. -} - - -void -itrace_derived_probe_group::emit_probe_decl (systemtap_session& s, - itrace_derived_probe *p) -{ - s.op->newline() << "{"; - s.op->line() << " .tgt={"; - - if (p->has_path) - { - s.op->line() << " .pathname=\"" << p->path << "\","; - s.op->line() << " .pid=0,"; - } - else - { - s.op->line() << " .pathname=NULL,"; - s.op->line() << " .pid=" << p->pid << ","; - } - - s.op->line() << " .callback=&_stp_itrace_probe_cb,"; - s.op->line() << " },"; - s.op->line() << " .pp=" << lex_cast_qstring (*p->sole_location()) << ","; - s.op->line() << " .single_step=" << p->single_step << ","; - s.op->line() << " .ph=&" << p->name << ","; - - s.op->line() << " },"; -} - - -void -itrace_derived_probe_group::emit_module_decls (systemtap_session& s) -{ - if (probes_by_path.empty() && probes_by_pid.empty()) - return; - - s.op->newline(); - s.op->newline() << "/* ---- itrace probes ---- */"; - - s.op->newline() << "struct stap_itrace_probe {"; - s.op->indent(1); - s.op->newline() << "struct stap_task_finder_target tgt;"; - s.op->newline() << "const char *pp;"; - s.op->newline() << "void (*ph) (struct context*);"; - s.op->newline() << "int single_step;"; - s.op->newline(-1) << "};"; - s.op->newline() << "static void enter_itrace_probe(struct stap_itrace_probe *p, struct pt_regs *regs, void *data);"; - s.op->newline() << "#include \"itrace.c\""; - - // output routine to call itrace probe - s.op->newline() << "static void enter_itrace_probe(struct stap_itrace_probe *p, struct pt_regs *regs, void *data) {"; - s.op->indent(1); - - common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "p->pp"); - s.op->newline() << "c->regs = regs;"; - s.op->newline() << "c->data = data;"; - - // call probe function - s.op->newline() << "(*p->ph) (c);"; - common_probe_entryfn_epilogue (s.op); - - s.op->newline() << "return;"; - s.op->newline(-1) << "}"; - - // Output task finder callback routine that gets called for all - // itrace probe types. - s.op->newline() << "static int _stp_itrace_probe_cb(struct stap_task_finder_target *tgt, struct task_struct *tsk, int register_p, int process_p) {"; - s.op->indent(1); - s.op->newline() << "int rc = 0;"; - s.op->newline() << "struct stap_itrace_probe *p = container_of(tgt, struct stap_itrace_probe, tgt);"; - - s.op->newline() << "if (register_p) "; - s.op->indent(1); - - s.op->newline() << "rc = usr_itrace_init(p->single_step, tsk->pid, p);"; - s.op->newline(-1) << "else"; - s.op->newline(1) << "remove_usr_itrace_info(find_itrace_info(p->tgt.pid));"; - s.op->newline(-1) << "return rc;"; - s.op->newline(-1) << "}"; - - // Emit vma callbacks. - s.op->newline() << "#ifdef STP_NEED_VMA_TRACKER"; - s.op->newline() << "static struct stap_task_finder_target stap_itrace_vmcbs[] = {"; - s.op->indent(1); - if (! probes_by_path.empty()) - { - for (p_b_path_iterator it = probes_by_path.begin(); - it != probes_by_path.end(); it++) - emit_vma_callback_probe_decl (s, it->first, (int64_t)0); - } - if (! probes_by_pid.empty()) - { - for (p_b_pid_iterator it = probes_by_pid.begin(); - it != probes_by_pid.end(); it++) - emit_vma_callback_probe_decl (s, "", it->first); - } - s.op->newline(-1) << "};"; - s.op->newline() << "#endif"; - - s.op->newline() << "static struct stap_itrace_probe stap_itrace_probes[] = {"; - s.op->indent(1); - - // Set up 'process(PATH)' probes - if (! probes_by_path.empty()) - { - for (p_b_path_iterator it = probes_by_path.begin(); - it != probes_by_path.end(); it++) - { - for (unsigned i = 0; i < it->second.size(); i++) - { - itrace_derived_probe *p = it->second[i]; - emit_probe_decl(s, p); - } - } - } - - // Set up 'process(PID)' probes - if (! probes_by_pid.empty()) - { - for (p_b_pid_iterator it = probes_by_pid.begin(); - it != probes_by_pid.end(); it++) - { - for (unsigned i = 0; i < it->second.size(); i++) - { - itrace_derived_probe *p = it->second[i]; - emit_probe_decl(s, p); - } - } - } - s.op->newline(-1) << "};"; -} - - -void -itrace_derived_probe_group::emit_module_init (systemtap_session& s) -{ - if (probes_by_path.empty() && probes_by_pid.empty()) - return; - - s.op->newline(); - s.op->newline() << "#ifdef STP_NEED_VMA_TRACKER"; - s.op->newline() << "_stp_sym_init();"; - s.op->newline() << "/* ---- itrace vma callbacks ---- */"; - s.op->newline() << "for (i=0; i<ARRAY_SIZE(stap_itrace_vmcbs); i++) {"; - s.op->indent(1); - s.op->newline() << "struct stap_task_finder_target *r = &stap_itrace_vmcbs[i];"; - s.op->newline() << "rc = stap_register_task_finder_target(r);"; - s.op->newline(-1) << "}"; - s.op->newline() << "#endif"; - - s.op->newline(); - s.op->newline() << "/* ---- itrace probes ---- */"; - - s.op->newline() << "for (i=0; i<" << num_probes << "; i++) {"; - s.op->indent(1); - s.op->newline() << "struct stap_itrace_probe *p = &stap_itrace_probes[i];"; - - // 'arch_has_single_step' needs to be defined for either single step mode - // or branch mode. - s.op->newline() << "if (!arch_has_single_step()) {"; - s.op->indent(1); - s.op->newline() << "_stp_error (\"insn probe init: arch does not support step mode\");"; - s.op->newline() << "rc = -EPERM;"; - s.op->newline() << "break;"; - s.op->newline(-1) << "}"; - s.op->newline() << "if (!p->single_step && !arch_has_block_step()) {"; - s.op->indent(1); - s.op->newline() << "_stp_error (\"insn probe init: arch does not support block step mode\");"; - s.op->newline() << "rc = -EPERM;"; - s.op->newline() << "break;"; - s.op->newline(-1) << "}"; - - s.op->newline() << "rc = stap_register_task_finder_target(&p->tgt);"; - s.op->newline(-1) << "}"; -} - - -void -itrace_derived_probe_group::emit_module_exit (systemtap_session& s) -{ - if (probes_by_path.empty() && probes_by_pid.empty()) return; - s.op->newline(); - s.op->newline() << "/* ---- itrace probes ---- */"; - s.op->newline() << "cleanup_usr_itrace();"; -} - // ------------------------------------------------------------------------ // utrace user-space probes // ------------------------------------------------------------------------ @@ -6687,7 +6315,7 @@ utrace_derived_probe::join_group (systemtap_session& s) } s.utrace_derived_probes->enroll (this); - task_finder_derived_probe_group::create_session_group (s); + enable_task_finder(s); } @@ -7678,7 +7306,7 @@ uprobe_derived_probe::join_group (systemtap_session& s) if (! s.uprobe_derived_probes) s.uprobe_derived_probes = new uprobe_derived_probe_group (); s.uprobe_derived_probes->enroll (this); - task_finder_derived_probe_group::create_session_group (s); + enable_task_finder(s); // Ask buildrun.cxx to build extra module if needed, and // signal staprun to load that module @@ -9338,6 +8966,7 @@ void register_standard_tapsets(systemtap_session & s) { register_tapset_been(s); + register_tapset_itrace(s); register_tapset_mark(s); register_tapset_perfmon(s); register_tapset_procfs(s); @@ -9393,16 +9022,6 @@ register_standard_tapsets(systemtap_session & s) s.pattern_root->bind(TOK_PROCESS)->bind(TOK_SYSCALL)->bind(TOK_RETURN) ->bind(new utrace_builder ()); - // itrace user-space probes - s.pattern_root->bind_str(TOK_PROCESS)->bind(TOK_INSN) - ->bind(new itrace_builder ()); - s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_INSN) - ->bind(new itrace_builder ()); - s.pattern_root->bind_str(TOK_PROCESS)->bind(TOK_INSN)->bind(TOK_BLOCK) - ->bind(new itrace_builder ()); - s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_INSN)->bind(TOK_BLOCK) - ->bind(new itrace_builder ()); - // kernel tracepoint probes s.pattern_root->bind(TOK_KERNEL)->bind_str(TOK_TRACE) ->bind(new tracepoint_builder()); @@ -1,5 +1,5 @@ // -*- C++ -*- -// Copyright (C) 2005 Red Hat Inc. +// Copyright (C) 2005, 2009 Red Hat Inc. // // This file is part of systemtap, and is free software. You can // redistribute it and/or modify it under the terms of the GNU General @@ -21,6 +21,7 @@ void common_probe_entryfn_prologue (translator_output* o, std::string statestr, void common_probe_entryfn_epilogue (translator_output* o, bool overload_processing = true); void register_tapset_been(systemtap_session& sess); +void register_tapset_itrace(systemtap_session& sess); void register_tapset_mark(systemtap_session& sess); void register_tapset_perfmon(systemtap_session& sess); void register_tapset_procfs(systemtap_session& sess); diff --git a/task_finder.cxx b/task_finder.cxx new file mode 100644 index 00000000..de1c2208 --- /dev/null +++ b/task_finder.cxx @@ -0,0 +1,103 @@ +// task finder for user tapsets +// Copyright (C) 2005-2009 Red Hat Inc. +// Copyright (C) 2005-2007 Intel Corporation. +// Copyright (C) 2008 James.Bottomley@HansenPartnership.com +// +// This file is part of systemtap, and is free software. You can +// redistribute it and/or modify it under the terms of the GNU General +// Public License (GPL); either version 2, or (at your option) any +// later version. + + +#include "session.h" +#include "tapsets.h" +#include "task_finder.h" +#include "translate.h" +#include "util.h" + +#include <cstring> +#include <string> + + +using namespace std; +using namespace __gnu_cxx; + + +// ------------------------------------------------------------------------ +// task_finder derived 'probes': These don't really exist. The whole +// purpose of the task_finder_derived_probe_group is to make sure that +// stap_start_task_finder()/stap_stop_task_finder() get called only +// once and in the right place. +// ------------------------------------------------------------------------ + +struct task_finder_derived_probe: public derived_probe +{ + // Dummy constructor for gcc 3.4 compatibility + task_finder_derived_probe (): derived_probe (0) { assert(0); } +}; + + +struct task_finder_derived_probe_group: public generic_dpg<task_finder_derived_probe> +{ +public: + void emit_module_decls (systemtap_session& ) { } + void emit_module_init (systemtap_session& s); + void emit_module_exit (systemtap_session& s); +}; + + +void +task_finder_derived_probe_group::emit_module_init (systemtap_session& s) +{ + s.op->newline(); + s.op->newline() << "/* ---- task finder ---- */"; + s.op->newline() << "rc = stap_start_task_finder();"; + + s.op->newline() << "if (rc) {"; + s.op->newline(1) << "stap_stop_task_finder();"; + s.op->newline(-1) << "}"; +} + + +void +task_finder_derived_probe_group::emit_module_exit (systemtap_session& s) +{ + s.op->newline(); + s.op->newline() << "/* ---- task finder ---- */"; + s.op->newline() << "stap_stop_task_finder();"; +} + + +// Declare that task_finder is needed in this session +void +enable_task_finder(systemtap_session& s) +{ + if (! s.task_finder_derived_probes) + s.task_finder_derived_probes = new task_finder_derived_probe_group(); +} + +// Helper function to emit vma tracker callbacks. +void +emit_vma_callback_probe_decl (systemtap_session& s, + string path, + int64_t pid) +{ + s.op->newline() << "{"; + if (pid == 0) + { + s.op->line() << " .pathname=\"" << path << "\","; + s.op->line() << " .pid=0,"; + } + else + { + s.op->line() << " .pathname=NULL,"; + s.op->line() << " .pid=" << pid << ","; + } + s.op->line() << " .callback=NULL,"; + s.op->line() << " .mmap_callback=&_stp_tf_mmap_cb,"; + s.op->line() << " .munmap_callback=&_stp_tf_munmap_cb,"; + s.op->line() << " .mprotect_callback=NULL,"; + s.op->line() << " },"; +} + +/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */ diff --git a/task_finder.h b/task_finder.h new file mode 100644 index 00000000..99419e32 --- /dev/null +++ b/task_finder.h @@ -0,0 +1,20 @@ +// -*- C++ -*- +// Copyright (C) 2009 Red Hat Inc. +// +// This file is part of systemtap, and is free software. You can +// redistribute it and/or modify it under the terms of the GNU General +// Public License (GPL); either version 2, or (at your option) any +// later version. + +#ifndef TASK_FINDER_H +#define TASK_FINDER_H + +// Declare that task_finder is needed in this session +void enable_task_finder(systemtap_session& s); + +// Helper function to emit vma tracker callbacks. +void emit_vma_callback_probe_decl (systemtap_session& s, std::string path, int64_t pid); + +#endif // TASK_FINDER_H + +/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */ |