From 912e8c5926abb587638f8e482c7f714bc5cda758 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 6 May 2009 16:43:51 -0700 Subject: Separate built-in timer tapsets All of the timer.* tapsets are now built and handled in their own tapset-timers.cxx, as the first step of many to pare down the current monolithic tapsets.cxx. --- tapsets.cxx | 623 +----------------------------------------------------------- 1 file changed, 8 insertions(+), 615 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index db14a787..9b6ad713 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -66,19 +66,6 @@ extern "C" { using namespace std; using namespace __gnu_cxx; -// ------------------------------------------------------------------------ -// Generic derived_probe_group: contains an ordinary vector of the -// given type. It provides only the enrollment function. - -template struct generic_dpg: public derived_probe_group -{ -protected: - vector probes; -public: - generic_dpg () {} - void enroll (DP* probe) { probes.push_back (probe); } -}; - // ------------------------------------------------------------------------ @@ -160,7 +147,7 @@ be_derived_probe::join_group (systemtap_session& s) void common_probe_entryfn_prologue (translator_output* o, string statestr, string new_pp, - bool overload_processing = true) + bool overload_processing) { o->newline() << "struct context* __restrict__ c;"; o->newline() << "#if !INTERRUPTIBLE"; @@ -261,7 +248,7 @@ common_probe_entryfn_prologue (translator_output* o, string statestr, void common_probe_entryfn_epilogue (translator_output* o, - bool overload_processing = true) + bool overload_processing) { if (overload_processing) o->newline() << "#if defined(STP_TIMING) || defined(STP_OVERLOAD)"; @@ -8752,295 +8739,6 @@ kprobe_builder::build(systemtap_session & sess, } -// ------------------------------------------------------------------------ -// timer derived probes -// ------------------------------------------------------------------------ - - -static string TOK_TIMER("timer"); - -struct timer_derived_probe: public derived_probe -{ - int64_t interval, randomize; - bool time_is_msecs; // NB: hrtimers get ms-based probes on modern kernels instead - timer_derived_probe (probe* p, probe_point* l, int64_t i, int64_t r, bool ms=false); - virtual void join_group (systemtap_session& s); -}; - - -struct timer_derived_probe_group: public generic_dpg -{ - void emit_interval (translator_output* o); -public: - void emit_module_decls (systemtap_session& s); - void emit_module_init (systemtap_session& s); - void emit_module_exit (systemtap_session& s); -}; - - -timer_derived_probe::timer_derived_probe (probe* p, probe_point* l, int64_t i, int64_t r, bool ms): - derived_probe (p, l), interval (i), randomize (r), time_is_msecs(ms) -{ - if (interval <= 0 || interval > 1000000) // make i and r fit into plain ints - throw semantic_error ("invalid interval for jiffies timer"); - // randomize = 0 means no randomization - if (randomize < 0 || randomize > interval) - throw semantic_error ("invalid randomize for jiffies timer"); - - if (locations.size() != 1) - throw semantic_error ("expect single probe point"); - // so we don't have to loop over them in the other functions -} - - -void -timer_derived_probe::join_group (systemtap_session& s) -{ - if (! s.timer_derived_probes) - s.timer_derived_probes = new timer_derived_probe_group (); - s.timer_derived_probes->enroll (this); -} - - -void -timer_derived_probe_group::emit_interval (translator_output* o) -{ - o->line() << "({"; - o->newline(1) << "unsigned i = stp->intrv;"; - o->newline() << "if (stp->rnd != 0)"; - o->newline(1) << "i += _stp_random_pm(stp->rnd);"; - o->newline(-1) << "stp->ms ? msecs_to_jiffies(i) : i;"; - o->newline(-1) << "})"; -} - - -void -timer_derived_probe_group::emit_module_decls (systemtap_session& s) -{ - if (probes.empty()) return; - - s.op->newline() << "/* ---- timer probes ---- */"; - - s.op->newline() << "static struct stap_timer_probe {"; - s.op->newline(1) << "struct timer_list timer_list;"; - s.op->newline() << "const char *pp;"; - s.op->newline() << "void (*ph) (struct context*);"; - s.op->newline() << "unsigned intrv, ms, rnd;"; - s.op->newline(-1) << "} stap_timer_probes [" << probes.size() << "] = {"; - s.op->indent(1); - for (unsigned i=0; i < probes.size(); i++) - { - s.op->newline () << "{"; - s.op->line() << " .pp=" - << lex_cast_qstring (*probes[i]->sole_location()) << ","; - s.op->line() << " .ph=&" << probes[i]->name << ","; - s.op->line() << " .intrv=" << probes[i]->interval << ","; - s.op->line() << " .ms=" << probes[i]->time_is_msecs << ","; - s.op->line() << " .rnd=" << probes[i]->randomize; - s.op->line() << " },"; - } - s.op->newline(-1) << "};"; - s.op->newline(); - - s.op->newline() << "static void enter_timer_probe (unsigned long val) {"; - s.op->newline(1) << "struct stap_timer_probe* stp = & stap_timer_probes [val];"; - s.op->newline() << "if ((atomic_read (&session_state) == STAP_SESSION_STARTING) ||"; - s.op->newline() << " (atomic_read (&session_state) == STAP_SESSION_RUNNING))"; - s.op->newline(1) << "mod_timer (& stp->timer_list, jiffies + "; - emit_interval (s.op); - s.op->line() << ");"; - s.op->newline(-1) << "{"; - s.op->indent(1); - common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "stp->pp"); - s.op->newline() << "(*stp->ph) (c);"; - common_probe_entryfn_epilogue (s.op); - s.op->newline(-1) << "}"; - s.op->newline(-1) << "}"; -} - - -void -timer_derived_probe_group::emit_module_init (systemtap_session& s) -{ - if (probes.empty()) return; - - s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {"; - s.op->newline(1) << "struct stap_timer_probe* stp = & stap_timer_probes [i];"; - s.op->newline() << "probe_point = stp->pp;"; - s.op->newline() << "init_timer (& stp->timer_list);"; - s.op->newline() << "stp->timer_list.function = & enter_timer_probe;"; - s.op->newline() << "stp->timer_list.data = i;"; // NB: important! - // copy timer renew calculations from above :-( - s.op->newline() << "stp->timer_list.expires = jiffies + "; - emit_interval (s.op); - s.op->line() << ";"; - s.op->newline() << "add_timer (& stp->timer_list);"; - // note: no partial failure rollback is needed: add_timer cannot fail. - s.op->newline(-1) << "}"; // for loop -} - - -void -timer_derived_probe_group::emit_module_exit (systemtap_session& s) -{ - if (probes.empty()) return; - - s.op->newline() << "for (i=0; i<" << probes.size() << "; i++)"; - s.op->newline(1) << "del_timer_sync (& stap_timer_probes[i].timer_list);"; - s.op->indent(-1); -} - - - -// ------------------------------------------------------------------------ -// profile derived probes -// ------------------------------------------------------------------------ -// On kernels < 2.6.10, this uses the register_profile_notifier API to -// generate the timed events for profiling; on kernels >= 2.6.10 this -// uses the register_timer_hook API. The latter doesn't currently allow -// simultaneous users, so insertion will fail if the profiler is busy. -// (Conflicting users may include OProfile, other SystemTap probes, etc.) - - -struct profile_derived_probe: public derived_probe -{ - profile_derived_probe (systemtap_session &s, probe* p, probe_point* l); - void join_group (systemtap_session& s); -}; - - -struct profile_derived_probe_group: public generic_dpg -{ -public: - void emit_module_decls (systemtap_session& s); - void emit_module_init (systemtap_session& s); - void emit_module_exit (systemtap_session& s); -}; - - -profile_derived_probe::profile_derived_probe (systemtap_session &, probe* p, probe_point* l): - derived_probe(p, l) -{ -} - - -void -profile_derived_probe::join_group (systemtap_session& s) -{ - if (! s.profile_derived_probes) - s.profile_derived_probes = new profile_derived_probe_group (); - s.profile_derived_probes->enroll (this); -} - - -struct profile_builder: public derived_probe_builder -{ - profile_builder() {} - virtual void build(systemtap_session & sess, - probe * base, - probe_point * location, - literal_map_t const &, - vector & finished_results) - { - sess.unwindsym_modules.insert ("kernel"); - finished_results.push_back(new profile_derived_probe(sess, base, location)); - } -}; - - -// timer.profile probe handlers are hooked up in an entertaining way -// to the underlying kernel facility. The fact that 2.6.11+ era -// "register_timer_hook" API allows only one consumer *system-wide* -// will give a hint. We will have a single entry function (and thus -// trivial registration / unregistration), and it will call all probe -// handler functions in sequence. - -void -profile_derived_probe_group::emit_module_decls (systemtap_session& s) -{ - if (probes.empty()) return; - - // kernels < 2.6.10: use register_profile_notifier API - // kernels >= 2.6.10: use register_timer_hook API - s.op->newline() << "/* ---- profile probes ---- */"; - - // This function calls all the profiling probe handlers in sequence. - // The only tricky thing is that the context will be reused amongst - // them. While a simple sequence of calls to the individual probe - // handlers is unlikely to go terribly wrong (with c->last_error - // being set causing an early return), but for extra assurance, we - // open-code the same logic here. - - s.op->newline() << "static void enter_all_profile_probes (struct pt_regs *regs) {"; - s.op->indent(1); - string pp = lex_cast_qstring("timer.profile"); // hard-coded for convenience - common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", pp); - s.op->newline() << "c->regs = regs;"; - - for (unsigned i=0; i 0) - { - // Some lightweight inter-probe context resetting - // XXX: not quite right: MAXERRORS not respected - s.op->newline() << "c->actionremaining = MAXACTION;"; - } - s.op->newline() << "if (c->last_error == NULL) " << probes[i]->name << " (c);"; - } - common_probe_entryfn_epilogue (s.op); - s.op->newline(-1) << "}"; - - s.op->newline() << "#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)"; // == using_rpn of yore - - s.op->newline() << "static int enter_profile_probes (struct notifier_block *self," - << " unsigned long val, void *data) {"; - s.op->newline(1) << "(void) self; (void) val;"; - s.op->newline() << "enter_all_profile_probes ((struct pt_regs *) data);"; - s.op->newline() << "return 0;"; - s.op->newline(-1) << "}"; - s.op->newline() << "struct notifier_block stap_profile_notifier = {" - << " .notifier_call = & enter_profile_probes };"; - - s.op->newline() << "#else"; - - s.op->newline() << "static int enter_profile_probes (struct pt_regs *regs) {"; - s.op->newline(1) << "enter_all_profile_probes (regs);"; - s.op->newline() << "return 0;"; - s.op->newline(-1) << "}"; - - s.op->newline() << "#endif"; -} - - -void -profile_derived_probe_group::emit_module_init (systemtap_session& s) -{ - if (probes.empty()) return; - - s.op->newline() << "probe_point = \"timer.profile\";"; // NB: hard-coded for convenience - s.op->newline() << "#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)"; // == using_rpn of yore - s.op->newline() << "rc = register_profile_notifier (& stap_profile_notifier);"; - s.op->newline() << "#else"; - s.op->newline() << "rc = register_timer_hook (& enter_profile_probes);"; - s.op->newline() << "#endif"; -} - - -void -profile_derived_probe_group::emit_module_exit (systemtap_session& s) -{ - if (probes.empty()) return; - - s.op->newline() << "for (i=0; i<" << probes.size() << "; i++)"; - s.op->newline(1) << "#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)"; // == using_rpn of yore - s.op->newline() << "unregister_profile_notifier (& stap_profile_notifier);"; - s.op->newline() << "#else"; - s.op->newline() << "unregister_timer_hook (& enter_profile_probes);"; - s.op->newline() << "#endif"; - s.op->indent(-1); -} - - // ------------------------------------------------------------------------ // procfs file derived probes @@ -11048,314 +10746,6 @@ tracepoint_builder::build(systemtap_session& s, -// ------------------------------------------------------------------------ -// hrtimer derived probes -// ------------------------------------------------------------------------ -// This is a new timer interface that provides more flexibility in specifying -// intervals, and uses the hrtimer APIs when available for greater precision. -// While hrtimers were added in 2.6.16, the API's weren't exported until -// 2.6.17, so we must check this kernel version before attempting to use -// hrtimers. -// -// * hrtimer_derived_probe: creates a probe point based on the hrtimer APIs. - - -struct hrtimer_derived_probe: public derived_probe -{ - // set a (generous) maximum of one day in ns - static const int64_t max_ns_interval = 1000000000LL * 60LL * 60LL * 24LL; - - // 100us seems like a reasonable minimum - static const int64_t min_ns_interval = 100000LL; - - int64_t interval, randomize; - - hrtimer_derived_probe (probe* p, probe_point* l, int64_t i, int64_t r, - int64_t scale): - derived_probe (p, l), interval (i), randomize (r) - { - if ((i < min_ns_interval) || (i > max_ns_interval)) - throw semantic_error(string("interval value out of range (") - + lex_cast(scale < min_ns_interval - ? min_ns_interval/scale : 1) - + "," - + lex_cast(max_ns_interval/scale) + ")"); - - // randomize = 0 means no randomization - if ((r < 0) || (r > i)) - throw semantic_error("randomization value out of range"); - } - - void join_group (systemtap_session& s); -}; - - -struct hrtimer_derived_probe_group: public generic_dpg -{ - void emit_interval (translator_output* o); -public: - void emit_module_decls (systemtap_session& s); - void emit_module_init (systemtap_session& s); - void emit_module_exit (systemtap_session& s); -}; - - -void -hrtimer_derived_probe::join_group (systemtap_session& s) -{ - if (! s.hrtimer_derived_probes) - s.hrtimer_derived_probes = new hrtimer_derived_probe_group (); - s.hrtimer_derived_probes->enroll (this); -} - - -void -hrtimer_derived_probe_group::emit_interval (translator_output* o) -{ - o->line() << "({"; - o->newline(1) << "unsigned long nsecs;"; - o->newline() << "int64_t i = stp->intrv;"; - o->newline() << "if (stp->rnd != 0) {"; - // XXX: why not use stp_random_pm instead of this? - o->newline(1) << "int64_t r;"; - o->newline() << "get_random_bytes(&r, sizeof(r));"; - // ensure that r is positive - o->newline() << "r &= ((uint64_t)1 << (8*sizeof(r) - 1)) - 1;"; - o->newline() << "r = _stp_mod64(NULL, r, (2*stp->rnd+1));"; - o->newline() << "r -= stp->rnd;"; - o->newline() << "i += r;"; - o->newline(-1) << "}"; - o->newline() << "if (unlikely(i < stap_hrtimer_resolution))"; - o->newline(1) << "i = stap_hrtimer_resolution;"; - o->indent(-1); - o->newline() << "nsecs = do_div(i, NSEC_PER_SEC);"; - o->newline() << "ktime_set(i, nsecs);"; - o->newline(-1) << "})"; -} - - -void -hrtimer_derived_probe_group::emit_module_decls (systemtap_session& s) -{ - if (probes.empty()) return; - - s.op->newline() << "/* ---- hrtimer probes ---- */"; - - s.op->newline() << "static unsigned long stap_hrtimer_resolution;"; // init later - s.op->newline() << "static struct stap_hrtimer_probe {"; - s.op->newline(1) << "struct hrtimer hrtimer;"; - s.op->newline() << "const char *pp;"; - s.op->newline() << "void (*ph) (struct context*);"; - s.op->newline() << "int64_t intrv, rnd;"; - s.op->newline(-1) << "} stap_hrtimer_probes [" << probes.size() << "] = {"; - s.op->indent(1); - for (unsigned i=0; i < probes.size(); i++) - { - s.op->newline () << "{"; - s.op->line() << " .pp=" << lex_cast_qstring (*probes[i]->sole_location()) << ","; - s.op->line() << " .ph=&" << probes[i]->name << ","; - s.op->line() << " .intrv=" << probes[i]->interval << "LL,"; - s.op->line() << " .rnd=" << probes[i]->randomize << "LL"; - s.op->line() << " },"; - } - s.op->newline(-1) << "};"; - s.op->newline(); - - // autoconf: add get/set expires if missing (pre 2.6.28-rc1) - s.op->newline() << "#ifndef STAPCONF_HRTIMER_GETSET_EXPIRES"; - s.op->newline() << "#define hrtimer_get_expires(timer) ((timer)->expires)"; - s.op->newline() << "#define hrtimer_set_expires(timer, time) (void)((timer)->expires = (time))"; - s.op->newline() << "#endif"; - - // autoconf: adapt to HRTIMER_REL -> HRTIMER_MODE_REL renaming near 2.6.21 - s.op->newline() << "#ifdef STAPCONF_HRTIMER_REL"; - s.op->newline() << "#define HRTIMER_MODE_REL HRTIMER_REL"; - s.op->newline() << "#endif"; - - // The function signature changed in 2.6.21. - s.op->newline() << "#ifdef STAPCONF_HRTIMER_REL"; - s.op->newline() << "static int "; - s.op->newline() << "#else"; - s.op->newline() << "static enum hrtimer_restart "; - s.op->newline() << "#endif"; - s.op->newline() << "enter_hrtimer_probe (struct hrtimer *timer) {"; - - s.op->newline(1) << "int rc = HRTIMER_NORESTART;"; - s.op->newline() << "struct stap_hrtimer_probe *stp = container_of(timer, struct stap_hrtimer_probe, hrtimer);"; - s.op->newline() << "if ((atomic_read (&session_state) == STAP_SESSION_STARTING) ||"; - s.op->newline() << " (atomic_read (&session_state) == STAP_SESSION_RUNNING)) {"; - // Compute next trigger time - s.op->newline(1) << "hrtimer_set_expires(timer, ktime_add (hrtimer_get_expires(timer),"; - emit_interval (s.op); - s.op->line() << "));"; - s.op->newline() << "rc = HRTIMER_RESTART;"; - s.op->newline(-1) << "}"; - s.op->newline() << "{"; - s.op->indent(1); - common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "stp->pp"); - s.op->newline() << "(*stp->ph) (c);"; - common_probe_entryfn_epilogue (s.op); - s.op->newline(-1) << "}"; - s.op->newline() << "return rc;"; - s.op->newline(-1) << "}"; -} - - -void -hrtimer_derived_probe_group::emit_module_init (systemtap_session& s) -{ - if (probes.empty()) return; - - s.op->newline() << "{"; - s.op->newline(1) << "struct timespec res;"; - s.op->newline() << "hrtimer_get_res (CLOCK_MONOTONIC, &res);"; - s.op->newline() << "stap_hrtimer_resolution = timespec_to_ns (&res);"; - s.op->newline(-1) << "}"; - - s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {"; - s.op->newline(1) << "struct stap_hrtimer_probe* stp = & stap_hrtimer_probes [i];"; - s.op->newline() << "probe_point = stp->pp;"; - s.op->newline() << "hrtimer_init (& stp->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);"; - s.op->newline() << "stp->hrtimer.function = & enter_hrtimer_probe;"; - // There is no hrtimer field to identify *this* (i-th) probe handler - // callback. So instead we'll deduce it at entry time. - s.op->newline() << "(void) hrtimer_start (& stp->hrtimer, "; - emit_interval (s.op); - s.op->line() << ", HRTIMER_MODE_REL);"; - // Note: no partial failure rollback is needed: hrtimer_start only - // "fails" if the timer was already active, which cannot be. - s.op->newline(-1) << "}"; // for loop -} - - -void -hrtimer_derived_probe_group::emit_module_exit (systemtap_session& s) -{ - if (probes.empty()) return; - - s.op->newline() << "for (i=0; i<" << probes.size() << "; i++)"; - s.op->newline(1) << "hrtimer_cancel (& stap_hrtimer_probes[i].hrtimer);"; - s.op->indent(-1); -} - - - -struct timer_builder: public derived_probe_builder -{ - virtual void build(systemtap_session & sess, - probe * base, probe_point * location, - literal_map_t const & parameters, - vector & finished_results); - - static void register_patterns(systemtap_session& s); -}; - -void -timer_builder::build(systemtap_session & sess, - probe * base, - probe_point * location, - literal_map_t const & parameters, - vector & finished_results) -{ - int64_t scale=1, period, rand=0; - - if (!get_param(parameters, "randomize", rand)) - rand = 0; - - if (get_param(parameters, "jiffies", period)) - { - // always use basic timers for jiffies - finished_results.push_back( - new timer_derived_probe(base, location, period, rand, false)); - return; - } - else if (get_param(parameters, "hz", period)) - { - if (period <= 0) - throw semantic_error ("frequency must be greater than 0"); - period = (1000000000 + period - 1)/period; - } - else if (get_param(parameters, "s", period) - || get_param(parameters, "sec", period)) - { - scale = 1000000000; - period *= scale; - rand *= scale; - } - else if (get_param(parameters, "ms", period) - || get_param(parameters, "msec", period)) - { - scale = 1000000; - period *= scale; - rand *= scale; - } - else if (get_param(parameters, "us", period) - || get_param(parameters, "usec", period)) - { - scale = 1000; - period *= scale; - rand *= scale; - } - else if (get_param(parameters, "ns", period) - || get_param(parameters, "nsec", period)) - { - // ok - } - else - throw semantic_error ("unrecognized timer variant"); - - // Redirect wallclock-time based probes to hrtimer code on recent - // enough kernels. - if (strverscmp(sess.kernel_base_release.c_str(), "2.6.17") < 0) - { - // hrtimers didn't exist, so use the old-school timers - period = (period + 1000000 - 1)/1000000; - rand = (rand + 1000000 - 1)/1000000; - - finished_results.push_back( - new timer_derived_probe(base, location, period, rand, true)); - } - else - finished_results.push_back( - new hrtimer_derived_probe(base, location, period, rand, scale)); -} - -void -timer_builder::register_patterns(systemtap_session& s) -{ - match_node* root = s.pattern_root; - derived_probe_builder *builder = new timer_builder(); - - root = root->bind(TOK_TIMER); - - root->bind_num("s")->bind(builder); - root->bind_num("s")->bind_num("randomize")->bind(builder); - root->bind_num("sec")->bind(builder); - root->bind_num("sec")->bind_num("randomize")->bind(builder); - - root->bind_num("ms")->bind(builder); - root->bind_num("ms")->bind_num("randomize")->bind(builder); - root->bind_num("msec")->bind(builder); - root->bind_num("msec")->bind_num("randomize")->bind(builder); - - root->bind_num("us")->bind(builder); - root->bind_num("us")->bind_num("randomize")->bind(builder); - root->bind_num("usec")->bind(builder); - root->bind_num("usec")->bind_num("randomize")->bind(builder); - - root->bind_num("ns")->bind(builder); - root->bind_num("ns")->bind_num("randomize")->bind(builder); - root->bind_num("nsec")->bind(builder); - root->bind_num("nsec")->bind_num("randomize")->bind(builder); - - root->bind_num("jiffies")->bind(builder); - root->bind_num("jiffies")->bind_num("randomize")->bind(builder); - - root->bind_num("hz")->bind(builder); -} - - - // ------------------------------------------------------------------------ // perfmon derived probes // ------------------------------------------------------------------------ @@ -11787,6 +11177,8 @@ perfmon_derived_probe_group::emit_module_init (translator_output* o) void register_standard_tapsets(systemtap_session & s) { + register_tapset_timers(s); + s.pattern_root->bind(TOK_BEGIN)->bind(new be_builder(BEGIN)); s.pattern_root->bind_num(TOK_BEGIN)->bind(new be_builder(BEGIN)); s.pattern_root->bind(TOK_END)->bind(new be_builder(END)); @@ -11796,8 +11188,6 @@ register_standard_tapsets(systemtap_session & s) s.pattern_root->bind(TOK_NEVER)->bind(new never_builder()); - timer_builder::register_patterns(s); - s.pattern_root->bind(TOK_TIMER)->bind("profile")->bind(new profile_builder()); s.pattern_root->bind("perfmon")->bind_str("counter") ->bind(new perfmon_builder()); @@ -11901,7 +11291,10 @@ vector all_session_groups(systemtap_session& s) { vector g; -#define DOONE(x) if (s. x##_derived_probes) g.push_back (s. x##_derived_probes) + +#define DOONE(x) \ + if (s. x##_derived_probes) \ + g.push_back ((derived_probe_group*)(s. x##_derived_probes)) // Note that order *is* important here. We want to make sure we // register (actually run) begin probes before any other probe type -- cgit From 47e0478e7dad2c5321dbcc0f4c69f88aba38812b Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 6 May 2009 17:40:36 -0700 Subject: Separate the begin/end/error/never tapsets --- tapsets.cxx | 205 +----------------------------------------------------------- 1 file changed, 3 insertions(+), 202 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 9b6ad713..e6d641bd 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -68,81 +68,6 @@ using namespace __gnu_cxx; -// ------------------------------------------------------------------------ -// begin/end/error probes are run right during registration / deregistration -// ------------------------------------------------------------------------ - -static string TOK_BEGIN("begin"); -static string TOK_END("end"); -static string TOK_ERROR("error"); - -enum be_t { BEGIN, END, ERROR }; - -struct be_derived_probe: public derived_probe -{ - be_t type; - int64_t priority; - - be_derived_probe (probe* p, probe_point* l, be_t t, int64_t pr): - derived_probe (p, l), type (t), priority (pr) {} - - void join_group (systemtap_session& s); - - static inline bool comp(be_derived_probe const *a, - be_derived_probe const *b) - { - // This allows the BEGIN/END/ERROR probes to intermingle. - // But that's OK - they're always treversed with a nested - // "if (type==FOO)" conditional. - return a->priority < b->priority; - } - - bool needs_global_locks () { return false; } - // begin/end probes don't need locks around global variables, since - // they aren't run concurrently with any other probes -}; - - -struct be_derived_probe_group: public generic_dpg -{ -public: - void emit_module_decls (systemtap_session& s); - void emit_module_init (systemtap_session& s); - void emit_module_exit (systemtap_session& s); -}; - -struct be_builder: public derived_probe_builder -{ - be_t type; - - be_builder(be_t t) : type(t) {} - - virtual void build(systemtap_session &, - probe * base, - probe_point * location, - literal_map_t const & parameters, - vector & finished_results) - { - int64_t priority; - if ((type == BEGIN && !get_param(parameters, TOK_BEGIN, priority)) || - (type == END && !get_param(parameters, TOK_END, priority)) || - (type == ERROR && !get_param(parameters, TOK_ERROR, priority))) - priority = 0; - finished_results.push_back( - new be_derived_probe(base, location, type, priority)); - } -}; - - -void -be_derived_probe::join_group (systemtap_session& s) -{ - if (! s.be_derived_probes) - s.be_derived_probes = new be_derived_probe_group (); - s.be_derived_probes->enroll (this); -} - - // ------------------------------------------------------------------------ void common_probe_entryfn_prologue (translator_output* o, string statestr, @@ -334,124 +259,6 @@ common_probe_entryfn_epilogue (translator_output* o, // ------------------------------------------------------------------------ -void -be_derived_probe_group::emit_module_decls (systemtap_session& s) -{ - if (probes.empty()) return; - - s.op->newline() << "/* ---- begin/end probes ---- */"; - s.op->newline() << "static void enter_begin_probe (void (*fn)(struct context*), const char* pp) {"; - s.op->indent(1); - common_probe_entryfn_prologue (s.op, "STAP_SESSION_STARTING", "pp", false); - s.op->newline() << "(*fn) (c);"; - common_probe_entryfn_epilogue (s.op, false); - s.op->newline(-1) << "}"; - - s.op->newline() << "static void enter_end_probe (void (*fn)(struct context*), const char* pp) {"; - s.op->indent(1); - common_probe_entryfn_prologue (s.op, "STAP_SESSION_STOPPING", "pp", false); - s.op->newline() << "(*fn) (c);"; - common_probe_entryfn_epilogue (s.op, false); - s.op->newline(-1) << "}"; - - s.op->newline() << "static void enter_error_probe (void (*fn)(struct context*), const char* pp) {"; - s.op->indent(1); - common_probe_entryfn_prologue (s.op, "STAP_SESSION_ERROR", "pp", false); - s.op->newline() << "(*fn) (c);"; - common_probe_entryfn_epilogue (s.op, false); - s.op->newline(-1) << "}"; - - s.op->newline() << "static struct stap_be_probe {"; - s.op->newline(1) << "void (*ph)(struct context*);"; - s.op->newline() << "const char* pp;"; - s.op->newline() << "int type;"; - s.op->newline(-1) << "} stap_be_probes[] = {"; - s.op->indent(1); - - // NB: We emit the table in sorted order here, so we don't have to - // store the priority numbers as integers and sort at run time. - - sort(probes.begin(), probes.end(), be_derived_probe::comp); - - for (unsigned i=0; i < probes.size(); i++) - { - s.op->newline () << "{"; - s.op->line() << " .pp=" - << lex_cast_qstring (*probes[i]->sole_location()) << ","; - s.op->line() << " .ph=&" << probes[i]->name << ","; - s.op->line() << " .type=" << probes[i]->type; - s.op->line() << " },"; - } - s.op->newline(-1) << "};"; -} - -void -be_derived_probe_group::emit_module_init (systemtap_session& s) -{ - if (probes.empty()) return; - - s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {"; - s.op->newline(1) << "struct stap_be_probe* stp = & stap_be_probes [i];"; - s.op->newline() << "if (stp->type != " << BEGIN << ") continue;"; - s.op->newline() << "enter_begin_probe (stp->ph, stp->pp);"; - s.op->newline() << "/* rc = 0; */"; - // NB: begin probes that cause errors do not constitute registration - // failures. An error message will probably get printed and if - // MAXERRORS was left at 1, we'll get an stp_exit. The - // error-handling probes will be run during the ordinary - // unregistration phase. - s.op->newline(-1) << "}"; -} - -void -be_derived_probe_group::emit_module_exit (systemtap_session& s) -{ - if (probes.empty()) return; - - s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {"; - s.op->newline(1) << "struct stap_be_probe* stp = & stap_be_probes [i];"; - s.op->newline() << "if (stp->type != " << END << ") continue;"; - s.op->newline() << "enter_end_probe (stp->ph, stp->pp);"; - s.op->newline(-1) << "}"; - - s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {"; - s.op->newline(1) << "struct stap_be_probe* stp = & stap_be_probes [i];"; - s.op->newline() << "if (stp->type != " << ERROR << ") continue;"; - s.op->newline() << "enter_error_probe (stp->ph, stp->pp);"; - s.op->newline(-1) << "}"; -} - - - -// ------------------------------------------------------------------------ -// never probes are never run -// ------------------------------------------------------------------------ - -static string TOK_NEVER("never"); - -struct never_derived_probe: public derived_probe -{ - never_derived_probe (probe* p): derived_probe (p) {} - never_derived_probe (probe* p, probe_point* l): derived_probe (p, l) {} - void join_group (systemtap_session&) { /* thus no probe_group */ } -}; - - -struct never_builder: public derived_probe_builder -{ - never_builder() {} - virtual void build(systemtap_session &, - probe * base, - probe_point * location, - literal_map_t const &, - vector & finished_results) - { - finished_results.push_back(new never_derived_probe(base, location)); - } -}; - - - // ------------------------------------------------------------------------ // Dwarf derived probes. "We apologize for the inconvience." // ------------------------------------------------------------------------ @@ -6796,6 +6603,8 @@ itrace_derived_probe_group::emit_module_exit (systemtap_session& s) // utrace user-space probes // ------------------------------------------------------------------------ +static string TOK_BEGIN("begin"); +static string TOK_END("end"); static string TOK_THREAD("thread"); static string TOK_SYSCALL("syscall"); @@ -11177,17 +10986,9 @@ perfmon_derived_probe_group::emit_module_init (translator_output* o) void register_standard_tapsets(systemtap_session & s) { + register_tapset_been(s); register_tapset_timers(s); - s.pattern_root->bind(TOK_BEGIN)->bind(new be_builder(BEGIN)); - s.pattern_root->bind_num(TOK_BEGIN)->bind(new be_builder(BEGIN)); - s.pattern_root->bind(TOK_END)->bind(new be_builder(END)); - s.pattern_root->bind_num(TOK_END)->bind(new be_builder(END)); - s.pattern_root->bind(TOK_ERROR)->bind(new be_builder(ERROR)); - s.pattern_root->bind_num(TOK_ERROR)->bind(new be_builder(ERROR)); - - s.pattern_root->bind(TOK_NEVER)->bind(new never_builder()); - s.pattern_root->bind("perfmon")->bind_str("counter") ->bind(new perfmon_builder()); -- cgit From 7a212aa8e893ad29acca3e80e1af01de0b894305 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 6 May 2009 18:52:46 -0700 Subject: Separate the procfs tapset --- tapsets.cxx | 500 +----------------------------------------------------------- 1 file changed, 1 insertion(+), 499 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index e6d641bd..86b2aa53 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -4270,15 +4270,6 @@ dwflpp::query_modules(base_query *q) iterate_over_modules(&query_module, q); } -struct var_expanding_visitor: public update_visitor -{ - static unsigned tick; - stack target_symbol_setter_functioncalls; - - var_expanding_visitor() {} - void visit_assignment (assignment* e); -}; - struct dwarf_var_expanding_visitor: public var_expanding_visitor { @@ -8549,488 +8540,6 @@ kprobe_builder::build(systemtap_session & sess, -// ------------------------------------------------------------------------ -// procfs file derived probes -// ------------------------------------------------------------------------ - - -static string TOK_PROCFS("procfs"); -static string TOK_READ("read"); -static string TOK_WRITE("write"); - -struct procfs_derived_probe: public derived_probe -{ - string path; - bool write; - bool target_symbol_seen; - - procfs_derived_probe (systemtap_session &, probe* p, probe_point* l, string ps, bool w); - void join_group (systemtap_session& s); -}; - - -struct procfs_probe_set -{ - procfs_derived_probe* read_probe; - procfs_derived_probe* write_probe; - - procfs_probe_set () : read_probe (NULL), write_probe (NULL) {} -}; - - -struct procfs_derived_probe_group: public generic_dpg -{ -private: - map probes_by_path; - typedef map::iterator p_b_p_iterator; - bool has_read_probes; - bool has_write_probes; - -public: - procfs_derived_probe_group () : - has_read_probes(false), has_write_probes(false) {} - - void enroll (procfs_derived_probe* probe); - void emit_module_decls (systemtap_session& s); - void emit_module_init (systemtap_session& s); - void emit_module_exit (systemtap_session& s); -}; - - -struct procfs_var_expanding_visitor: public var_expanding_visitor -{ - procfs_var_expanding_visitor(systemtap_session& s, const string& pn, - string path, bool write_probe): - sess (s), probe_name (pn), path (path), write_probe (write_probe), - target_symbol_seen (false) {} - - systemtap_session& sess; - string probe_name; - string path; - bool write_probe; - bool target_symbol_seen; - - void visit_target_symbol (target_symbol* e); -}; - - -procfs_derived_probe::procfs_derived_probe (systemtap_session &s, probe* p, - probe_point* l, string ps, bool w): - derived_probe(p, l), path(ps), write(w), target_symbol_seen(false) -{ - // Expand local variables in the probe body - procfs_var_expanding_visitor v (s, name, path, write); - this->body = v.require (this->body); - target_symbol_seen = v.target_symbol_seen; -} - - -void -procfs_derived_probe::join_group (systemtap_session& s) -{ - if (! s.procfs_derived_probes) - s.procfs_derived_probes = new procfs_derived_probe_group (); - s.procfs_derived_probes->enroll (this); -} - - -void -procfs_derived_probe_group::enroll (procfs_derived_probe* p) -{ - procfs_probe_set *pset; - - if (probes_by_path.count(p->path) == 0) - { - pset = new procfs_probe_set; - probes_by_path[p->path] = pset; - } - else - { - pset = probes_by_path[p->path]; - - // You can only specify 1 read and 1 write probe. - if (p->write && pset->write_probe != NULL) - throw semantic_error("only one write procfs probe can exist for procfs path \"" + p->path + "\""); - else if (! p->write && pset->read_probe != NULL) - throw semantic_error("only one read procfs probe can exist for procfs path \"" + p->path + "\""); - - // XXX: multiple writes should be acceptable - } - - if (p->write) - { - pset->write_probe = p; - has_write_probes = true; - } - else - { - pset->read_probe = p; - has_read_probes = true; - } -} - - -void -procfs_derived_probe_group::emit_module_decls (systemtap_session& s) -{ - if (probes_by_path.empty()) - return; - - s.op->newline() << "/* ---- procfs probes ---- */"; - s.op->newline() << "#include \"procfs.c\""; - - // Emit the procfs probe data list - s.op->newline() << "static struct stap_procfs_probe {"; - s.op->newline(1)<< "const char *path;"; - s.op->newline() << "const char *read_pp;"; - s.op->newline() << "void (*read_ph) (struct context*);"; - s.op->newline() << "const char *write_pp;"; - s.op->newline() << "void (*write_ph) (struct context*);"; - s.op->newline(-1) << "} stap_procfs_probes[] = {"; - s.op->indent(1); - - for (p_b_p_iterator it = probes_by_path.begin(); it != probes_by_path.end(); - it++) - { - procfs_probe_set *pset = it->second; - - s.op->newline() << "{"; - s.op->line() << " .path=" << lex_cast_qstring (it->first) << ","; - - if (pset->read_probe != NULL) - { - s.op->line() << " .read_pp=" - << lex_cast_qstring (*pset->read_probe->sole_location()) - << ","; - s.op->line() << " .read_ph=&" << pset->read_probe->name << ","; - } - else - { - s.op->line() << " .read_pp=NULL,"; - s.op->line() << " .read_ph=NULL,"; - } - - if (pset->write_probe != NULL) - { - s.op->line() << " .write_pp=" - << lex_cast_qstring (*pset->write_probe->sole_location()) - << ","; - s.op->line() << " .write_ph=&" << pset->write_probe->name; - } - else - { - s.op->line() << " .write_pp=NULL,"; - s.op->line() << " .write_ph=NULL"; - } - s.op->line() << " },"; - } - s.op->newline(-1) << "};"; - - if (has_read_probes) - { - // Output routine to fill in 'page' with our data. - s.op->newline(); - - s.op->newline() << "static int _stp_procfs_read(char *page, char **start, off_t off, int count, int *eof, void *data) {"; - - s.op->newline(1) << "struct stap_procfs_probe *spp = (struct stap_procfs_probe *)data;"; - s.op->newline() << "int bytes = 0;"; - s.op->newline() << "string_t strdata = {'\\0'};"; - - common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "spp->read_pp"); - - s.op->newline() << "if (c->data == NULL)"; - s.op->newline(1) << "c->data = &strdata;"; - s.op->newline(-1) << "else {"; - - s.op->newline(1) << "if (unlikely (atomic_inc_return (& skipped_count) > MAXSKIPPED)) {"; - s.op->newline(1) << "atomic_set (& session_state, STAP_SESSION_ERROR);"; - s.op->newline() << "_stp_exit ();"; - s.op->newline(-1) << "}"; - s.op->newline() << "atomic_dec (& c->busy);"; - s.op->newline() << "goto probe_epilogue;"; - s.op->newline(-1) << "}"; - - // call probe function (which copies data into strdata) - s.op->newline() << "(*spp->read_ph) (c);"; - - // copy string data into 'page' - s.op->newline() << "c->data = NULL;"; - s.op->newline() << "bytes = strnlen(strdata, MAXSTRINGLEN - 1);"; - s.op->newline() << "if (off >= bytes)"; - s.op->newline(1) << "*eof = 1;"; - s.op->newline(-1) << "else {"; - s.op->newline(1) << "bytes -= off;"; - s.op->newline() << "if (bytes > count)"; - s.op->newline(1) << "bytes = count;"; - s.op->newline(-1) << "memcpy(page, strdata + off, bytes);"; - s.op->newline() << "*start = page;"; - s.op->newline(-1) << "}"; - - common_probe_entryfn_epilogue (s.op); - s.op->newline() << "return bytes;"; - - s.op->newline(-1) << "}"; - } - if (has_write_probes) - { - s.op->newline() << "static int _stp_procfs_write(struct file *file, const char *buffer, unsigned long count, void *data) {"; - - s.op->newline(1) << "struct stap_procfs_probe *spp = (struct stap_procfs_probe *)data;"; - s.op->newline() << "string_t strdata = {'\\0'};"; - - common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "spp->write_pp"); - - s.op->newline() << "if (count > (MAXSTRINGLEN - 1))"; - s.op->newline(1) << "count = MAXSTRINGLEN - 1;"; - s.op->newline(-1) << "_stp_copy_from_user(strdata, buffer, count);"; - - s.op->newline() << "if (c->data == NULL)"; - s.op->newline(1) << "c->data = &strdata;"; - s.op->newline(-1) << "else {"; - - s.op->newline(1) << "if (unlikely (atomic_inc_return (& skipped_count) > MAXSKIPPED)) {"; - s.op->newline(1) << "atomic_set (& session_state, STAP_SESSION_ERROR);"; - s.op->newline() << "_stp_exit ();"; - s.op->newline(-1) << "}"; - s.op->newline() << "atomic_dec (& c->busy);"; - s.op->newline() << "goto probe_epilogue;"; - s.op->newline(-1) << "}"; - - // call probe function (which copies data out of strdata) - s.op->newline() << "(*spp->write_ph) (c);"; - - s.op->newline() << "c->data = NULL;"; - common_probe_entryfn_epilogue (s.op); - - s.op->newline() << "return count;"; - s.op->newline(-1) << "}"; - } -} - - -void -procfs_derived_probe_group::emit_module_init (systemtap_session& s) -{ - if (probes_by_path.empty()) - return; - - s.op->newline() << "for (i = 0; i < " << probes_by_path.size() << "; i++) {"; - s.op->newline(1) << "struct stap_procfs_probe *spp = &stap_procfs_probes[i];"; - - s.op->newline() << "if (spp->read_pp)"; - s.op->newline(1) << "probe_point = spp->read_pp;"; - s.op->newline(-1) << "else"; - s.op->newline(1) << "probe_point = spp->write_pp;"; - - s.op->newline(-1) << "rc = _stp_create_procfs(spp->path, i);"; - - s.op->newline() << "if (rc) {"; - s.op->newline(1) << "_stp_close_procfs();"; - s.op->newline() << "break;"; - s.op->newline(-1) << "}"; - - if (has_read_probes) - { - s.op->newline() << "if (spp->read_pp)"; - s.op->newline(1) << "_stp_procfs_files[i]->read_proc = &_stp_procfs_read;"; - s.op->newline(-1) << "else"; - s.op->newline(1) << "_stp_procfs_files[i]->read_proc = NULL;"; - s.op->indent(-1); - } - else - s.op->newline() << "_stp_procfs_files[i]->read_proc = NULL;"; - - if (has_write_probes) - { - s.op->newline() << "if (spp->write_pp)"; - s.op->newline(1) << "_stp_procfs_files[i]->write_proc = &_stp_procfs_write;"; - s.op->newline(-1) << "else"; - s.op->newline(1) << "_stp_procfs_files[i]->write_proc = NULL;"; - s.op->indent(-1); - } - else - s.op->newline() << "_stp_procfs_files[i]->write_proc = NULL;"; - - s.op->newline() << "_stp_procfs_files[i]->data = spp;"; - s.op->newline(-1) << "}"; // for loop -} - - -void -procfs_derived_probe_group::emit_module_exit (systemtap_session& s) -{ - if (probes_by_path.empty()) - return; - - s.op->newline() << "_stp_close_procfs();"; -} - - -void -procfs_var_expanding_visitor::visit_target_symbol (target_symbol* e) -{ - assert(e->base_name.size() > 0 && e->base_name[0] == '$'); - - if (e->base_name != "$value") - throw semantic_error ("invalid target symbol for procfs probe, $value expected", - e->tok); - - if (e->components.size() > 0) - { - switch (e->components[0].first) - { - case target_symbol::comp_literal_array_index: - throw semantic_error("procfs target variable '$value' may not be used as array", - e->tok); - break; - case target_symbol::comp_struct_member: - throw semantic_error("procfs target variable '$value' may not be used as a structure", - e->tok); - break; - default: - throw semantic_error ("invalid use of procfs target variable '$value'", - e->tok); - break; - } - } - - bool lvalue = is_active_lvalue(e); - if (write_probe && lvalue) - throw semantic_error("procfs $value variable is read-only in a procfs write probe", e->tok); - else if (! write_probe && ! lvalue) - throw semantic_error("procfs $value variable cannot be read in a procfs read probe", e->tok); - - // Remember that we've seen a target variable. - target_symbol_seen = true; - - // Synthesize a function. - functiondecl *fdecl = new functiondecl; - fdecl->tok = e->tok; - embeddedcode *ec = new embeddedcode; - ec->tok = e->tok; - - string fname = (string(lvalue ? "_procfs_value_set" : "_procfs_value_get") - + "_" + lex_cast(tick++)); - string locvalue = "CONTEXT->data"; - - if (! lvalue) - ec->code = string("strlcpy (THIS->__retvalue, ") + locvalue - + string(", MAXSTRINGLEN); /* pure */"); - else - ec->code = string("strlcpy (") + locvalue - + string(", THIS->value, MAXSTRINGLEN);"); - - fdecl->name = fname; - fdecl->body = ec; - fdecl->type = pe_string; - - if (lvalue) - { - // Modify the fdecl so it carries a single pe_string formal - // argument called "value". - - vardecl *v = new vardecl; - v->type = pe_string; - v->name = "value"; - v->tok = e->tok; - fdecl->formal_args.push_back(v); - } - sess.functions[fdecl->name]=fdecl; - - // Synthesize a functioncall. - functioncall* n = new functioncall; - n->tok = e->tok; - n->function = fname; - n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session - - if (lvalue) - { - // Provide the functioncall to our parent, so that it can be - // used to substitute for the assignment node immediately above - // us. - assert(!target_symbol_setter_functioncalls.empty()); - *(target_symbol_setter_functioncalls.top()) = n; - } - - provide (n); -} - - -struct procfs_builder: public derived_probe_builder -{ - procfs_builder() {} - virtual void build(systemtap_session & sess, - probe * base, - probe_point * location, - literal_map_t const & parameters, - vector & finished_results); -}; - - -void -procfs_builder::build(systemtap_session & sess, - probe * base, - probe_point * location, - literal_map_t const & parameters, - vector & finished_results) -{ - string path; - bool has_procfs = get_param(parameters, TOK_PROCFS, path); - bool has_read = (parameters.find(TOK_READ) != parameters.end()); - bool has_write = (parameters.find(TOK_WRITE) != parameters.end()); - - // If no procfs path, default to "command". The runtime will do - // this for us, but if we don't do it here, we'll think the - // following 2 probes are attached to different paths: - // - // probe procfs("command").read {}" - // probe procfs.write {} - - if (! has_procfs) - path = "command"; - // If we have a path, we need to validate it. - else - { - string::size_type start_pos, end_pos; - string component; - start_pos = 0; - while ((end_pos = path.find('/', start_pos)) != string::npos) - { - // Make sure it doesn't start with '/'. - if (end_pos == 0) - throw semantic_error ("procfs path cannot start with a '/'", - location->tok); - - component = path.substr(start_pos, end_pos - start_pos); - // Make sure it isn't empty. - if (component.size() == 0) - throw semantic_error ("procfs path component cannot be empty", - location->tok); - // Make sure it isn't relative. - else if (component == "." || component == "..") - throw semantic_error ("procfs path cannot be relative (and contain '.' or '..')", location->tok); - - start_pos = end_pos + 1; - } - component = path.substr(start_pos); - // Make sure it doesn't end with '/'. - if (component.size() == 0) - throw semantic_error ("procfs path cannot end with a '/'", location->tok); - // Make sure it isn't relative. - else if (component == "." || component == "..") - throw semantic_error ("procfs path cannot be relative (and contain '.' or '..')", location->tok); - } - - if (!(has_read ^ has_write)) - throw semantic_error ("need read/write component", location->tok); - - finished_results.push_back(new procfs_derived_probe(sess, base, location, - path, has_write)); -} - - - // ------------------------------------------------------------------------ // statically inserted macro-based derived probes // ------------------------------------------------------------------------ @@ -10987,6 +10496,7 @@ void register_standard_tapsets(systemtap_session & s) { register_tapset_been(s); + register_tapset_procfs(s); register_tapset_timers(s); s.pattern_root->bind("perfmon")->bind_str("counter") @@ -11061,14 +10571,6 @@ register_standard_tapsets(systemtap_session & s) s.pattern_root->bind(TOK_KERNEL)->bind_str(TOK_TRACE) ->bind(new tracepoint_builder()); - // procfs parts - s.pattern_root->bind(TOK_PROCFS)->bind(TOK_READ)->bind(new procfs_builder()); - s.pattern_root->bind_str(TOK_PROCFS)->bind(TOK_READ) - ->bind(new procfs_builder()); - s.pattern_root->bind(TOK_PROCFS)->bind(TOK_WRITE)->bind(new procfs_builder()); - s.pattern_root->bind_str(TOK_PROCFS)->bind(TOK_WRITE) - ->bind(new procfs_builder()); - // Kprobe based probe s.pattern_root->bind(TOK_KPROBE)->bind_str(TOK_FUNCTION) ->bind(new kprobe_builder()); -- cgit From bae55db94d702c373cf66006d6736fb6adb69f23 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 7 May 2009 11:44:13 -0700 Subject: Group all kprobe_derived_FOO together --- tapsets.cxx | 92 +++++++++++++++++++++++-------------------------------------- 1 file changed, 35 insertions(+), 57 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 86b2aa53..a943163e 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -2429,41 +2429,6 @@ struct uprobe_derived_probe: public derived_probe void join_group (systemtap_session& s); }; -struct kprobe_derived_probe: public derived_probe -{ - kprobe_derived_probe (probe *base, - probe_point *location, - const string& name, - int64_t stmt_addr, - bool has_return, - bool has_statement, - bool has_maxactive, - long maxactive_val - ); - string symbol_name; - Dwarf_Addr addr; - bool has_return; - bool has_statement; - bool has_maxactive; - long maxactive_val; - bool access_var; - void printsig (std::ostream &o) const; - void join_group (systemtap_session& s); -}; - -struct kprobe_derived_probe_group: public derived_probe_group -{ -private: - multimap probes_by_module; - typedef multimap::iterator p_b_m_iterator; - -public: - void enroll (kprobe_derived_probe* probe); - void emit_module_decls (systemtap_session& s); - void emit_module_init (systemtap_session& s); - void emit_module_exit (systemtap_session& s); -}; - struct dwarf_derived_probe_group: public derived_probe_group { private: @@ -5372,24 +5337,6 @@ dwarf_derived_probe_group::enroll (dwarf_derived_probe* p) // sequentially. } -/* -void -dwarf_derived_probe_group::enroll (kprobe_derived_probe* p) -{ - dwarf_derived_probe *dw_probe = new dwarf_derived_probe (p->symbol_name, - "",0, - p->module_name, - p->section_name, - 0,0, - p->q,NULL); - probes_by_module.insert (make_pair (p->module, p)); - - // XXX: probes put at the same address should all share a - // single kprobe/kretprobe, and have their handlers executed - // sequentially. -} -*/ - void dwarf_derived_probe_group::emit_module_decls (systemtap_session& s) { @@ -8133,6 +8080,41 @@ uprobe_derived_probe_group::emit_module_exit (systemtap_session& s) static string TOK_KPROBE("kprobe"); +struct kprobe_derived_probe: public derived_probe +{ + kprobe_derived_probe (probe *base, + probe_point *location, + const string& name, + int64_t stmt_addr, + bool has_return, + bool has_statement, + bool has_maxactive, + long maxactive_val + ); + string symbol_name; + Dwarf_Addr addr; + bool has_return; + bool has_statement; + bool has_maxactive; + long maxactive_val; + bool access_var; + void printsig (std::ostream &o) const; + void join_group (systemtap_session& s); +}; + +struct kprobe_derived_probe_group: public derived_probe_group +{ +private: + multimap probes_by_module; + typedef multimap::iterator p_b_m_iterator; + +public: + void enroll (kprobe_derived_probe* probe); + void emit_module_decls (systemtap_session& s); + void emit_module_init (systemtap_session& s); + void emit_module_exit (systemtap_session& s); +}; + kprobe_derived_probe::kprobe_derived_probe (probe *base, probe_point *location, const string& name, @@ -10483,10 +10465,6 @@ perfmon_derived_probe_group::emit_module_init (translator_output* o) } #endif -// ------------------------------------------------------------------------ -// kprobes-based probes,which postpone symbol resolution until runtime. -// ------------------------------------------------------------------------ - // ------------------------------------------------------------------------ // Standard tapset registry. -- cgit From 01c2eefe76e5a0eb8dd5a9504b522cdcb11f2665 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 7 May 2009 14:49:08 -0700 Subject: Separate the permon tapset --- tapsets.cxx | 437 +----------------------------------------------------------- 1 file changed, 1 insertion(+), 436 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index a943163e..b4b58292 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -58,11 +58,6 @@ extern "C" { } -#ifdef PERFMON -#include -#include -#endif - using namespace std; using namespace __gnu_cxx; @@ -86,15 +81,6 @@ common_probe_entryfn_prologue (translator_output* o, string statestr, o->newline() << "cycles_t cycles_atstart = get_cycles ();"; o->newline() << "#endif"; -#if 0 /* XXX: PERFMON */ - o->newline() << "static struct pfarg_ctx _pfm_context;"; - o->newline() << "static void *_pfm_desc;"; - o->newline() << "static struct pfarg_pmc *_pfm_pmc_x;"; - o->newline() << "static int _pfm_num_pmc_x;"; - o->newline() << "static struct pfarg_pmd *_pfm_pmd_x;"; - o->newline() << "static int _pfm_num_pmd_x;"; -#endif - o->newline() << "#if INTERRUPTIBLE"; o->newline() << "preempt_disable ();"; o->newline() << "#else"; @@ -10046,426 +10032,6 @@ tracepoint_builder::build(systemtap_session& s, -// ------------------------------------------------------------------------ -// perfmon derived probes -// ------------------------------------------------------------------------ -// This is a new interface to the perfmon hw. -// - - -struct perfmon_var_expanding_visitor: public var_expanding_visitor -{ - systemtap_session & sess; - unsigned counter_number; - perfmon_var_expanding_visitor(systemtap_session & s, unsigned c): - sess(s), counter_number(c) {} - void visit_target_symbol (target_symbol* e); -}; - - -void -perfmon_var_expanding_visitor::visit_target_symbol (target_symbol *e) -{ - assert(e->base_name.size() > 0 && e->base_name[0] == '$'); - - // Synthesize a function. - functiondecl *fdecl = new functiondecl; - fdecl->tok = e->tok; - embeddedcode *ec = new embeddedcode; - ec->tok = e->tok; - bool lvalue = is_active_lvalue(e); - - if (lvalue ) - throw semantic_error("writes to $counter not permitted"); - - string fname = string("_perfmon_tvar_get") - + "_" + e->base_name.substr(1) - + "_" + lex_cast(counter_number); - - if (e->base_name != "$counter") - throw semantic_error ("target variables not available to perfmon probes"); - - if (e->components.size() > 0) - { - switch (e->components[0].first) - { - case target_symbol::comp_literal_array_index: - throw semantic_error("perfmon probe '$counter' variable may not be used as array", - e->tok); - break; - case target_symbol::comp_struct_member: - throw semantic_error("perfmon probe '$counter' variable may not be used as a structure", - e->tok); - break; - default: - throw semantic_error ("invalid use of perfmon probe '$counter' variable", - e->tok); - break; - } - } - - ec->code = "THIS->__retvalue = _pfm_pmd_x[" + - lex_cast(counter_number) + "].reg_num;"; - ec->code += "/* pure */"; - fdecl->name = fname; - fdecl->body = ec; - fdecl->type = pe_long; - sess.functions[fdecl->name]=fdecl; - - // Synthesize a functioncall. - functioncall* n = new functioncall; - n->tok = e->tok; - n->function = fname; - n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session - - provide (n); -} - - -enum perfmon_mode -{ - perfmon_count, - perfmon_sample -}; - - -struct perfmon_derived_probe: public derived_probe -{ -protected: - static unsigned probes_allocated; - -public: - systemtap_session & sess; - string event; - perfmon_mode mode; - - perfmon_derived_probe (probe* p, probe_point* l, systemtap_session &s, - string e, perfmon_mode m); - virtual void join_group (systemtap_session& s); -}; - - -struct perfmon_derived_probe_group: public generic_dpg -{ -public: - void emit_module_decls (systemtap_session&) {} - void emit_module_init (systemtap_session&) {} - void emit_module_exit (systemtap_session&) {} -}; - - -struct perfmon_builder: public derived_probe_builder -{ - perfmon_builder() {} - virtual void build(systemtap_session & sess, - probe * base, - probe_point * location, - literal_map_t const & parameters, - vector & finished_results) - { - string event; - if (!get_param (parameters, "counter", event)) - throw semantic_error("perfmon requires an event"); - - sess.perfmon++; - - // XXX: need to revise when doing sampling - finished_results.push_back(new perfmon_derived_probe(base, location, - sess, event, - perfmon_count)); - } -}; - - -unsigned perfmon_derived_probe::probes_allocated; - -perfmon_derived_probe::perfmon_derived_probe (probe* p, probe_point* l, - systemtap_session &s, - string e, perfmon_mode m) - : derived_probe (p, l), sess(s), event(e), mode(m) -{ - ++probes_allocated; - - // Now expand the local variables in the probe body - perfmon_var_expanding_visitor v (sess, probes_allocated-1); - this->body = v.require (this->body); - - if (sess.verbose > 1) - clog << "perfmon-based probe" << endl; -} - - -void -perfmon_derived_probe::join_group (systemtap_session& s) -{ - throw semantic_error ("incomplete", this->tok); - - if (! s.perfmon_derived_probes) - s.perfmon_derived_probes = new perfmon_derived_probe_group (); - s.perfmon_derived_probes->enroll (this); -} - - -#if 0 -void -perfmon_derived_probe::emit_registrations_start (translator_output* o, - unsigned index) -{ - for (unsigned i=0; inewline() << "enter_" << name << "_" << i << " ();"; -} - - -void -perfmon_derived_probe::emit_registrations_end (translator_output * o, - unsigned index) -{ -} - - -void -perfmon_derived_probe::emit_deregistrations (translator_output * o) -{ -} - - -void -perfmon_derived_probe::emit_probe_entries (translator_output * o) -{ - o->newline() << "#ifdef STP_TIMING"; - // NB: This variable may be multiply (but identically) defined. - o->newline() << "static __cacheline_aligned Stat " << "time_" << basest()->name << ";"; - o->newline() << "#endif"; - - for (unsigned i=0; inewline() << "/* location " << i << ": " << *l << " */"; - o->newline() << "static void enter_" << name << "_" << i << " (void) {"; - - o->indent(1); - o->newline() << "const char* probe_point = " - << lex_cast_qstring(*l) << ";"; - emit_probe_prologue (o, - (mode == perfmon_count ? - "STAP_SESSION_STARTING" : - "STAP_SESSION_RUNNING"), - "probe_point"); - - // NB: locals are initialized by probe function itself - o->newline() << name << " (c);"; - - emit_probe_epilogue (o); - - o->newline(-1) << "}\n"; - } -} -#endif - - -#if 0 -void no_pfm_event_error (string s) -{ - string msg(string("Cannot find event:" + s)); - throw semantic_error(msg); -} - - -void no_pfm_mask_error (string s) -{ - string msg(string("Cannot find mask:" + s)); - throw semantic_error(msg); -} - - -void -split(const string& s, vector& v, const string & separator) -{ - string::size_type last_pos = s.find_first_not_of(separator, 0); - string::size_type pos = s.find_first_of(separator, last_pos); - - while (string::npos != pos || string::npos != last_pos) { - v.push_back(s.substr(last_pos, pos - last_pos)); - last_pos = s.find_first_not_of(separator, pos); - pos = s.find_first_of(separator, last_pos); - } -} - - -void -perfmon_derived_probe_group::emit_probes (translator_output* op, unparser* up) -{ - for (unsigned i=0; i < probes.size(); i++) - { - op->newline (); - up->emit_probe (probes[i]); - } -} - - -void -perfmon_derived_probe_group::emit_module_init (translator_output* o) -{ - int ret; - pfmlib_input_param_t inp; - pfmlib_output_param_t outp; - pfarg_pmd_t pd[PFMLIB_MAX_PMDS]; - pfarg_pmc_t pc[PFMLIB_MAX_PMCS]; - pfarg_ctx_t ctx; - pfarg_load_t load_args; - pfmlib_options_t pfmlib_options; - unsigned int max_counters; - - if ( probes.size() == 0) - return; - ret = pfm_initialize(); - if (ret != PFMLIB_SUCCESS) - throw semantic_error("Unable to generate performance monitoring events (no libpfm)"); - - pfm_get_num_counters(&max_counters); - - memset(&pfmlib_options, 0, sizeof(pfmlib_options)); - pfmlib_options.pfm_debug = 0; /* set to 1 for debug */ - pfmlib_options.pfm_verbose = 0; /* set to 1 for debug */ - pfm_set_options(&pfmlib_options); - - memset(pd, 0, sizeof(pd)); - memset(pc, 0, sizeof(pc)); - memset(&ctx, 0, sizeof(ctx)); - memset(&load_args, 0, sizeof(load_args)); - - /* - * prepare parameters to library. - */ - memset(&inp,0, sizeof(inp)); - memset(&outp,0, sizeof(outp)); - - /* figure out the events */ - for (unsigned i=0; ievent == "cycles") { - if (pfm_get_cycle_event( &inp.pfp_events[i].event) != PFMLIB_SUCCESS) - no_pfm_event_error(probes[i]->event); - } else if (probes[i]->event == "instructions") { - if (pfm_get_inst_retired_event( &inp.pfp_events[i].event) != - PFMLIB_SUCCESS) - no_pfm_event_error(probes[i]->event); - } else { - unsigned int event_id = 0; - unsigned int mask_id = 0; - vector event_spec; - split(probes[i]->event, event_spec, ":"); - int num = event_spec.size(); - int masks = num - 1; - - if (num == 0) - throw semantic_error("No events found"); - - /* setup event */ - if (pfm_find_event(event_spec[0].c_str(), &event_id) != PFMLIB_SUCCESS) - no_pfm_event_error(event_spec[0]); - inp.pfp_events[i].event = event_id; - - /* set up masks */ - if (masks > PFMLIB_MAX_MASKS_PER_EVENT) - throw semantic_error("Too many unit masks specified"); - - for (int j=0; j < masks; j++) { - if (pfm_find_event_mask(event_id, event_spec[j+1].c_str(), - &mask_id) != PFMLIB_SUCCESS) - no_pfm_mask_error(string(event_spec[j+1])); - inp.pfp_events[i].unit_masks[j] = mask_id; - } - inp.pfp_events[i].num_masks = masks; - } - } - - /* number of counters in use */ - inp.pfp_event_count = probes.size(); - - // XXX: no elimination of duplicated counters - if (inp.pfp_event_count>max_counters) - throw semantic_error("Too many performance monitoring events."); - - /* count events both in kernel and user-space */ - inp.pfp_dfl_plm = PFM_PLM0 | PFM_PLM3; - - /* XXX: some cases a perfmon register might be used of watch dog - this code doesn't handle that case */ - - /* figure out the pmcs for the events */ - if ((ret=pfm_dispatch_events(&inp, NULL, &outp, NULL)) != PFMLIB_SUCCESS) - throw semantic_error("Cannot configure events"); - - for (unsigned i=0; i < outp.pfp_pmc_count; i++) { - pc[i].reg_num = outp.pfp_pmcs[i].reg_num; - pc[i].reg_value = outp.pfp_pmcs[i].reg_value; - } - - /* - * There could be more pmc settings than pmd. - * Figure out the actual pmds to use. - */ - for (unsigned i=0, j=0; i < inp.pfp_event_count; i++) { - pd[i].reg_num = outp.pfp_pmcs[j].reg_pmd_num; - for(; j < outp.pfp_pmc_count; j++) - if (outp.pfp_pmcs[j].reg_evt_idx != i) break; - } - - // Output the be probes create function - o->newline() << "static int register_perfmon_probes (void) {"; - o->newline(1) << "int rc = 0;"; - - o->newline() << "/* data for perfmon */"; - o->newline() << "static int _pfm_num_pmc = " << outp.pfp_pmc_count << ";"; - o->newline() << "static struct pfarg_pmc _pfm_pmc[" << outp.pfp_pmc_count - << "] = {"; - /* output the needed bits for pmc here */ - for (unsigned i=0; i < outp.pfp_pmc_count; i++) { - o->newline() << "{.reg_num=" << pc[i].reg_num << ", " - << ".reg_value=" << lex_cast_hex(pc[i].reg_value) - << "},"; - } - - o->newline() << "};"; - o->newline() << "static int _pfm_num_pmd = " << inp.pfp_event_count << ";"; - o->newline() << "static struct pfarg_pmd _pfm_pmd[" << inp.pfp_event_count - << "] = {"; - /* output the needed bits for pmd here */ - for (unsigned i=0; i < inp.pfp_event_count; i++) { - o->newline() << "{.reg_num=" << pd[i].reg_num << ", " - << ".reg_value=" << pd[i].reg_value << "},"; - } - o->newline() << "};"; - o->newline(); - - o->newline() << "_pfm_pmc_x=_pfm_pmc;"; - o->newline() << "_pfm_num_pmc_x=_pfm_num_pmc;"; - o->newline() << "_pfm_pmd_x=_pfm_pmd;"; - o->newline() << "_pfm_num_pmd_x=_pfm_num_pmd;"; - - // call all the function bodies associated with perfcounters - for (unsigned i=0; i < probes.size (); i++) - probes[i]->emit_registrations_start (o,i); - - /* generate call to turn on instrumentation */ - o->newline() << "_pfm_context.ctx_flags |= PFM_FL_SYSTEM_WIDE;"; - o->newline() << "rc = rc || _stp_perfmon_setup(&_pfm_desc, &_pfm_context,"; - o->newline(1) << "_pfm_pmc, _pfm_num_pmc,"; - o->newline() << "_pfm_pmd, _pfm_num_pmd);"; - o->newline(-1); - - o->newline() << "return rc;"; - o->newline(-1) << "}\n"; - - // Output the be probes destroy function - o->newline() << "static void unregister_perfmon_probes (void) {"; - o->newline(1) << "_stp_perfmon_shutdown(_pfm_desc);"; - o->newline(-1) << "}\n"; -} -#endif - - // ------------------------------------------------------------------------ // Standard tapset registry. // ------------------------------------------------------------------------ @@ -10474,11 +10040,10 @@ void register_standard_tapsets(systemtap_session & s) { register_tapset_been(s); + register_tapset_perfmon(s); register_tapset_procfs(s); register_tapset_timers(s); - s.pattern_root->bind("perfmon")->bind_str("counter") - ->bind(new perfmon_builder()); // dwarf-based kprobe/uprobe parts dwarf_derived_probe::register_patterns(s); -- cgit From dd0e4fa70fd7589ff80618305bd3d24e98a5d73b Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 7 May 2009 15:15:29 -0700 Subject: Separate the kernel.mark tapset --- tapsets.cxx | 709 +----------------------------------------------------------- 1 file changed, 1 insertion(+), 708 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index b4b58292..3ea94a73 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -8508,708 +8508,6 @@ kprobe_builder::build(systemtap_session & sess, -// ------------------------------------------------------------------------ -// statically inserted macro-based derived probes -// ------------------------------------------------------------------------ - -static string TOK_FORMAT("format"); - -struct mark_arg -{ - bool str; - string c_type; - exp_type stp_type; -}; - -struct mark_derived_probe: public derived_probe -{ - mark_derived_probe (systemtap_session &s, - const string& probe_name, const string& probe_format, - probe* base_probe, probe_point* location); - - systemtap_session& sess; - string probe_name, probe_format; - vector mark_args; - bool target_symbol_seen; - - void join_group (systemtap_session& s); - void print_dupe_stamp (ostream& o); - void emit_probe_context_vars (translator_output* o); - void initialize_probe_context_vars (translator_output* o); - void printargs (std::ostream &o) const; - - void parse_probe_format (); -}; - - -struct mark_derived_probe_group: public generic_dpg -{ -public: - void emit_module_decls (systemtap_session& s); - void emit_module_init (systemtap_session& s); - void emit_module_exit (systemtap_session& s); -}; - - -struct mark_var_expanding_visitor: public var_expanding_visitor -{ - mark_var_expanding_visitor(systemtap_session& s, const string& pn, - vector &mark_args): - sess (s), probe_name (pn), mark_args (mark_args), - target_symbol_seen (false) {} - systemtap_session& sess; - string probe_name; - vector &mark_args; - bool target_symbol_seen; - - void visit_target_symbol (target_symbol* e); - void visit_target_symbol_arg (target_symbol* e); - void visit_target_symbol_context (target_symbol* e); -}; - - -void -hex_dump(unsigned char *data, size_t len) -{ - // Dump data - size_t idx = 0; - while (idx < len) - { - string char_rep; - - clog << " 0x" << setfill('0') << setw(8) << hex << internal << idx; - - for (int i = 0; i < 4; i++) - { - clog << " "; - size_t limit = idx + 4; - while (idx < len && idx < limit) - { - clog << setfill('0') << setw(2) - << ((unsigned) *((unsigned char *)data + idx)); - if (isprint(*((char *)data + idx))) - char_rep += *((char *)data + idx); - else - char_rep += '.'; - idx++; - } - while (idx < limit) - { - clog << " "; - idx++; - } - } - clog << " " << char_rep << dec << setfill(' ') << endl; - } -} - - -void -mark_var_expanding_visitor::visit_target_symbol_arg (target_symbol* e) -{ - string argnum_s = e->base_name.substr(4,e->base_name.length()-4); - int argnum = atoi (argnum_s.c_str()); - - if (argnum < 1 || argnum > (int)mark_args.size()) - throw semantic_error ("invalid marker argument number", e->tok); - - if (is_active_lvalue (e)) - throw semantic_error("write to marker parameter not permitted", e->tok); - - if (e->components.size() > 0) - { - switch (e->components[0].first) - { - case target_symbol::comp_literal_array_index: - throw semantic_error("marker argument may not be used as array", - e->tok); - break; - case target_symbol::comp_struct_member: - throw semantic_error("marker argument may not be used as a structure", - e->tok); - break; - default: - throw semantic_error ("invalid marker argument use", e->tok); - break; - } - } - - // Remember that we've seen a target variable. - target_symbol_seen = true; - - e->probe_context_var = "__mark_arg" + lex_cast(argnum); - e->type = mark_args[argnum-1]->stp_type; - provide (e); -} - - -void -mark_var_expanding_visitor::visit_target_symbol_context (target_symbol* e) -{ - string sname = e->base_name; - - if (is_active_lvalue (e)) - throw semantic_error("write to marker '" + sname + "' not permitted", e->tok); - - if (e->components.size() > 0) - { - switch (e->components[0].first) - { - case target_symbol::comp_literal_array_index: - throw semantic_error("marker '" + sname + "' may not be used as array", - e->tok); - break; - case target_symbol::comp_struct_member: - throw semantic_error("marker '" + sname + "' may not be used as a structure", - e->tok); - break; - default: - throw semantic_error ("invalid marker '" + sname + "' use", e->tok); - break; - } - } - - string fname; - if (e->base_name == "$format") { - fname = string("_mark_format_get"); - } else { - fname = string("_mark_name_get"); - } - - // Synthesize a functioncall. - functioncall* n = new functioncall; - n->tok = e->tok; - n->function = fname; - n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session - provide (n); -} - -void -mark_var_expanding_visitor::visit_target_symbol (target_symbol* e) -{ - assert(e->base_name.size() > 0 && e->base_name[0] == '$'); - - if (e->base_name.substr(0,4) == "$arg") - visit_target_symbol_arg (e); - else if (e->base_name == "$format" || e->base_name == "$name") - visit_target_symbol_context (e); - else - throw semantic_error ("invalid target symbol for marker, $argN, $name or $format expected", - e->tok); -} - - - -mark_derived_probe::mark_derived_probe (systemtap_session &s, - const string& p_n, - const string& p_f, - probe* base, probe_point* loc): - derived_probe (base, new probe_point(*loc) /* .components soon rewritten */), - sess (s), probe_name (p_n), probe_format (p_f), - target_symbol_seen (false) -{ - // create synthetic probe point name; preserve condition - vector comps; - comps.push_back (new probe_point::component (TOK_KERNEL)); - comps.push_back (new probe_point::component (TOK_MARK, new literal_string (probe_name))); - comps.push_back (new probe_point::component (TOK_FORMAT, new literal_string (probe_format))); - this->sole_location()->components = comps; - - // expand the marker format - parse_probe_format(); - - // Now expand the local variables in the probe body - mark_var_expanding_visitor v (sess, name, mark_args); - this->body = v.require (this->body); - target_symbol_seen = v.target_symbol_seen; - - if (sess.verbose > 2) - clog << "marker-based " << name << " mark=" << probe_name - << " fmt='" << probe_format << "'" << endl; -} - - -static int -skip_atoi(const char **s) -{ - int i = 0; - while (isdigit(**s)) - i = i * 10 + *((*s)++) - '0'; - return i; -} - - -void -mark_derived_probe::parse_probe_format() -{ - const char *fmt = probe_format.c_str(); - int qualifier; // 'h', 'l', or 'L' for integer fields - mark_arg *arg; - - for (; *fmt ; ++fmt) - { - if (*fmt != '%') - { - /* Skip text */ - continue; - } - -repeat: - ++fmt; - - // skip conversion flags (if present) - switch (*fmt) - { - case '-': - case '+': - case ' ': - case '#': - case '0': - goto repeat; - } - - // skip minimum field witdh (if present) - if (isdigit(*fmt)) - skip_atoi(&fmt); - - // skip precision (if present) - if (*fmt == '.') - { - ++fmt; - if (isdigit(*fmt)) - skip_atoi(&fmt); - } - - // get the conversion qualifier (if present) - qualifier = -1; - if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') - { - qualifier = *fmt; - ++fmt; - if (qualifier == 'l' && *fmt == 'l') - { - qualifier = 'L'; - ++fmt; - } - } - - // get the conversion type - switch (*fmt) - { - case 'c': - arg = new mark_arg; - arg->str = false; - arg->c_type = "int"; - arg->stp_type = pe_long; - mark_args.push_back(arg); - continue; - - case 's': - arg = new mark_arg; - arg->str = true; - arg->c_type = "char *"; - arg->stp_type = pe_string; - mark_args.push_back(arg); - continue; - - case 'p': - arg = new mark_arg; - arg->str = false; - // This should really be 'void *'. But, then we'll get a - // compile error when we assign the void pointer to an - // integer without a cast. So, we use 'long' instead, since - // it should have the same size as 'void *'. - arg->c_type = "long"; - arg->stp_type = pe_long; - mark_args.push_back(arg); - continue; - - case '%': - continue; - - case 'o': - case 'X': - case 'x': - case 'd': - case 'i': - case 'u': - // fall through... - break; - - default: - if (!*fmt) - --fmt; - continue; - } - - arg = new mark_arg; - arg->str = false; - arg->stp_type = pe_long; - switch (qualifier) - { - case 'L': - arg->c_type = "long long"; - break; - - case 'l': - arg->c_type = "long"; - break; - - case 'h': - arg->c_type = "short"; - break; - - default: - arg->c_type = "int"; - break; - } - mark_args.push_back(arg); - } -} - - -void -mark_derived_probe::join_group (systemtap_session& s) -{ - if (! s.mark_derived_probes) - { - s.mark_derived_probes = new mark_derived_probe_group (); - - // Make sure is included early. - embeddedcode *ec = new embeddedcode; - ec->tok = NULL; - ec->code = string("#if ! defined(CONFIG_MARKERS)\n") - + string("#error \"Need CONFIG_MARKERS!\"\n") - + string("#endif\n") - + string("#include \n"); - - s.embeds.push_back(ec); - } - s.mark_derived_probes->enroll (this); -} - - -void -mark_derived_probe::print_dupe_stamp (ostream& o) -{ - if (target_symbol_seen) - for (unsigned i = 0; i < mark_args.size(); i++) - o << mark_args[i]->c_type << " __mark_arg" << (i+1) << endl; -} - - -void -mark_derived_probe::emit_probe_context_vars (translator_output* o) -{ - // If we haven't seen a target symbol for this probe, quit. - if (! target_symbol_seen) - return; - - for (unsigned i = 0; i < mark_args.size(); i++) - { - string localname = "__mark_arg" + lex_cast(i+1); - switch (mark_args[i]->stp_type) - { - case pe_long: - o->newline() << "int64_t " << localname << ";"; - break; - case pe_string: - o->newline() << "string_t " << localname << ";"; - break; - default: - throw semantic_error ("cannot expand unknown type"); - break; - } - } -} - - -void -mark_derived_probe::initialize_probe_context_vars (translator_output* o) -{ - // If we haven't seen a target symbol for this probe, quit. - if (! target_symbol_seen) - return; - - bool deref_fault_needed = false; - for (unsigned i = 0; i < mark_args.size(); i++) - { - string localname = "l->__mark_arg" + lex_cast(i+1); - switch (mark_args[i]->stp_type) - { - case pe_long: - o->newline() << localname << " = va_arg(*c->mark_va_list, " - << mark_args[i]->c_type << ");"; - break; - - case pe_string: - // We're assuming that this is a kernel string (this code is - // basically the guts of kernel_string), not a user string. - o->newline() << "{ " << mark_args[i]->c_type - << " tmp_str = va_arg(*c->mark_va_list, " - << mark_args[i]->c_type << ");"; - o->newline() << "deref_string (" << localname - << ", tmp_str, MAXSTRINGLEN); }"; - deref_fault_needed = true; - break; - - default: - throw semantic_error ("cannot expand unknown type"); - break; - } - } - if (deref_fault_needed) - // Need to report errors? - o->newline() << "deref_fault: ;"; -} - -void -mark_derived_probe::printargs(std::ostream &o) const -{ - for (unsigned i = 0; i < mark_args.size(); i++) - { - string localname = "$arg" + lex_cast(i+1); - switch (mark_args[i]->stp_type) - { - case pe_long: - o << " " << localname << ":long"; - break; - case pe_string: - o << " " << localname << ":string"; - break; - default: - o << " " << localname << ":unknown"; - break; - } - } -} - - -void -mark_derived_probe_group::emit_module_decls (systemtap_session& s) -{ - if (probes.empty()) - return; - - s.op->newline() << "/* ---- marker probes ---- */"; - - s.op->newline() << "static struct stap_marker_probe {"; - s.op->newline(1) << "const char * const name;"; - s.op->newline() << "const char * const format;"; - s.op->newline() << "const char * const pp;"; - s.op->newline() << "void (* const ph) (struct context *);"; - - s.op->newline(-1) << "} stap_marker_probes [" << probes.size() << "] = {"; - s.op->indent(1); - for (unsigned i=0; i < probes.size(); i++) - { - s.op->newline () << "{"; - s.op->line() << " .name=" << lex_cast_qstring(probes[i]->probe_name) - << ","; - s.op->line() << " .format=" << lex_cast_qstring(probes[i]->probe_format) - << ","; - s.op->line() << " .pp=" << lex_cast_qstring (*probes[i]->sole_location()) - << ","; - s.op->line() << " .ph=&" << probes[i]->name; - s.op->line() << " },"; - } - s.op->newline(-1) << "};"; - s.op->newline(); - - - // Emit the marker callback function - s.op->newline(); - s.op->newline() << "static void enter_marker_probe (void *probe_data, void *call_data, const char *fmt, va_list *args) {"; - s.op->newline(1) << "struct stap_marker_probe *smp = (struct stap_marker_probe *)probe_data;"; - common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "smp->pp"); - s.op->newline() << "c->marker_name = smp->name;"; - s.op->newline() << "c->marker_format = smp->format;"; - s.op->newline() << "c->mark_va_list = args;"; - s.op->newline() << "(*smp->ph) (c);"; - s.op->newline() << "c->mark_va_list = NULL;"; - s.op->newline() << "c->data = NULL;"; - - common_probe_entryfn_epilogue (s.op); - s.op->newline(-1) << "}"; - - return; -} - - -void -mark_derived_probe_group::emit_module_init (systemtap_session &s) -{ - if (probes.size () == 0) - return; - - s.op->newline() << "/* init marker probes */"; - s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {"; - s.op->newline(1) << "struct stap_marker_probe *smp = &stap_marker_probes[i];"; - s.op->newline() << "probe_point = smp->pp;"; - s.op->newline() << "rc = marker_probe_register(smp->name, smp->format, enter_marker_probe, smp);"; - s.op->newline() << "if (rc) {"; - s.op->newline(1) << "for (j=i-1; j>=0; j--) {"; // partial rollback - s.op->newline(1) << "struct stap_marker_probe *smp2 = &stap_marker_probes[j];"; - s.op->newline() << "marker_probe_unregister(smp2->name, enter_marker_probe, smp2);"; - s.op->newline(-1) << "}"; - s.op->newline() << "break;"; // don't attempt to register any more probes - s.op->newline(-1) << "}"; - s.op->newline(-1) << "}"; // for loop -} - - -void -mark_derived_probe_group::emit_module_exit (systemtap_session& s) -{ - if (probes.empty()) - return; - - s.op->newline() << "/* deregister marker probes */"; - s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {"; - s.op->newline(1) << "struct stap_marker_probe *smp = &stap_marker_probes[i];"; - s.op->newline() << "marker_probe_unregister(smp->name, enter_marker_probe, smp);"; - s.op->newline(-1) << "}"; // for loop -} - - -struct mark_builder: public derived_probe_builder -{ -private: - bool cache_initialized; - typedef multimap mark_cache_t; - typedef multimap::const_iterator mark_cache_const_iterator_t; - typedef pair - mark_cache_const_iterator_pair_t; - mark_cache_t mark_cache; - -public: - mark_builder(): cache_initialized(false) {} - - void build_no_more (systemtap_session &s) - { - if (! mark_cache.empty()) - { - if (s.verbose > 3) - clog << "mark_builder releasing cache" << endl; - mark_cache.clear(); - } - } - - void build(systemtap_session & sess, - probe * base, - probe_point * location, - literal_map_t const & parameters, - vector & finished_results); -}; - - -void -mark_builder::build(systemtap_session & sess, - probe * base, - probe_point *loc, - literal_map_t const & parameters, - vector & finished_results) -{ - string mark_str_val; - bool has_mark_str = get_param (parameters, TOK_MARK, mark_str_val); - string mark_format_val; - bool has_mark_format = get_param (parameters, TOK_FORMAT, mark_format_val); - assert (has_mark_str); - (void) has_mark_str; - - if (! cache_initialized) - { - cache_initialized = true; - string module_markers_path = sess.kernel_build_tree + "/Module.markers"; - - ifstream module_markers; - module_markers.open(module_markers_path.c_str(), ifstream::in); - if (! module_markers) - { - if (sess.verbose>3) - clog << module_markers_path << " cannot be opened: " - << strerror(errno) << endl; - return; - } - - string name, module, format; - do - { - module_markers >> name >> module; - getline(module_markers, format); - - // trim leading whitespace - string::size_type notwhite = format.find_first_not_of(" \t"); - format.erase(0, notwhite); - - // If the format is empty, make sure we add back a space - // character, which is what MARK_NOARGS expands to. - if (format.length() == 0) - format = " "; - - if (sess.verbose>3) - clog << "'" << name << "' '" << module << "' '" << format - << "'" << endl; - - if (mark_cache.count(name) > 0) - { - // If we have 2 markers with the same we've got 2 cases: - // different format strings or duplicate format strings. - // If an existing marker in the cache doesn't have the - // same format string, add this marker. - mark_cache_const_iterator_pair_t ret; - mark_cache_const_iterator_t it; - bool matching_format_string = false; - - ret = mark_cache.equal_range(name); - for (it = ret.first; it != ret.second; ++it) - { - if (format == it->second) - { - matching_format_string = true; - break; - } - } - - if (! matching_format_string) - mark_cache.insert(pair(name, format)); - } - else - mark_cache.insert(pair(name, format)); - } - while (! module_markers.eof()); - module_markers.close(); - } - - // Search marker list for matching markers - for (mark_cache_const_iterator_t it = mark_cache.begin(); - it != mark_cache.end(); it++) - { - // Below, "rc" has negative polarity: zero iff matching. - int rc = fnmatch(mark_str_val.c_str(), it->first.c_str(), 0); - if (! rc) - { - bool add_result = true; - - // Match format strings (if the user specified one) - if (has_mark_format && fnmatch(mark_format_val.c_str(), - it->second.c_str(), 0)) - add_result = false; - - if (add_result) - { - derived_probe *dp - = new mark_derived_probe (sess, - it->first, it->second, - base, loc); - finished_results.push_back (dp); - } - } - } -} - - - // ------------------------------------------------------------------------ // statically inserted kernel-tracepoint derived probes // ------------------------------------------------------------------------ @@ -10040,6 +9338,7 @@ void register_standard_tapsets(systemtap_session & s) { register_tapset_been(s); + register_tapset_mark(s); register_tapset_perfmon(s); register_tapset_procfs(s); register_tapset_timers(s); @@ -10104,12 +9403,6 @@ register_standard_tapsets(systemtap_session & s) s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_INSN)->bind(TOK_BLOCK) ->bind(new itrace_builder ()); - // marker-based parts - s.pattern_root->bind(TOK_KERNEL)->bind_str(TOK_MARK) - ->bind(new mark_builder()); - s.pattern_root->bind(TOK_KERNEL)->bind_str(TOK_MARK)->bind_str(TOK_FORMAT) - ->bind(new mark_builder()); - // kernel tracepoint probes s.pattern_root->bind(TOK_KERNEL)->bind_str(TOK_TRACE) ->bind(new tracepoint_builder()); -- cgit From 93646f4d5ccaa051cd996cc2ab6a2b4a21418714 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 7 May 2009 16:17:11 -0700 Subject: Separate task_finder and the itrace tapset --- tapsets.cxx | 389 +----------------------------------------------------------- 1 file changed, 4 insertions(+), 385 deletions(-) (limited to 'tapsets.cxx') 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 -{ -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 -{ -private: - map > probes_by_path; - typedef map >::iterator p_b_path_iterator; - map > probes_by_pid; - typedef map >::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 const & parameters, - vector & 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; iindent(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()); -- cgit From b84779a5a4e19d2a4d8bbf9eabb96e43b2aecdee Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 7 May 2009 16:41:16 -0700 Subject: Separate the utrace tapset --- tapsets.cxx | 1049 +---------------------------------------------------------- 1 file changed, 1 insertion(+), 1048 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 6a4d41b6..f0002073 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -6151,1016 +6151,6 @@ module_info::~module_info() delete sym_table; } -// ------------------------------------------------------------------------ -// utrace user-space probes -// ------------------------------------------------------------------------ - -static string TOK_BEGIN("begin"); -static string TOK_END("end"); -static string TOK_THREAD("thread"); -static string TOK_SYSCALL("syscall"); - -// Note that these flags don't match up exactly with UTRACE_EVENT -// flags (and that's OK). -enum utrace_derived_probe_flags { - UDPF_NONE, - UDPF_BEGIN, // process begin - UDPF_END, // process end - UDPF_THREAD_BEGIN, // thread begin - UDPF_THREAD_END, // thread end - UDPF_SYSCALL, // syscall entry - UDPF_SYSCALL_RETURN, // syscall exit - UDPF_NFLAGS -}; - -struct utrace_derived_probe: public derived_probe -{ - bool has_path; - string path; - int64_t pid; - enum utrace_derived_probe_flags flags; - bool target_symbol_seen; - - utrace_derived_probe (systemtap_session &s, probe* p, probe_point* l, - bool hp, string &pn, int64_t pd, - enum utrace_derived_probe_flags f); - void join_group (systemtap_session& s); -}; - - -struct utrace_derived_probe_group: public generic_dpg -{ -private: - map > probes_by_path; - typedef map >::iterator p_b_path_iterator; - map > probes_by_pid; - typedef map >::iterator p_b_pid_iterator; - unsigned num_probes; - bool flags_seen[UDPF_NFLAGS]; - - void emit_probe_decl (systemtap_session& s, utrace_derived_probe *p); - -public: - utrace_derived_probe_group(): num_probes(0), flags_seen() { } - - void enroll (utrace_derived_probe* probe); - void emit_module_decls (systemtap_session& s); - void emit_module_init (systemtap_session& s); - void emit_module_exit (systemtap_session& s); -}; - - -struct utrace_var_expanding_visitor: public var_expanding_visitor -{ - utrace_var_expanding_visitor(systemtap_session& s, probe_point* l, - const string& pn, - enum utrace_derived_probe_flags f): - sess (s), base_loc (l), probe_name (pn), flags (f), - target_symbol_seen (false), add_block(NULL), add_probe(NULL) {} - - systemtap_session& sess; - probe_point* base_loc; - string probe_name; - enum utrace_derived_probe_flags flags; - bool target_symbol_seen; - block *add_block; - probe *add_probe; - std::map return_ts_map; - - void visit_target_symbol_arg (target_symbol* e); - void visit_target_symbol_context (target_symbol* e); - void visit_target_symbol_cached (target_symbol* e); - void visit_target_symbol (target_symbol* e); -}; - - - -utrace_derived_probe::utrace_derived_probe (systemtap_session &s, - probe* p, probe_point* l, - bool hp, string &pn, int64_t pd, - enum utrace_derived_probe_flags f): - derived_probe (p, new probe_point (*l) /* .components soon rewritten */ ), - has_path(hp), path(pn), pid(pd), flags(f), - target_symbol_seen(false) -{ - // Expand local variables in the probe body - utrace_var_expanding_visitor v (s, l, name, flags); - this->body = v.require (this->body); - target_symbol_seen = v.target_symbol_seen; - - // If during target-variable-expanding the probe, we added a new block - // of code, add it to the start of the probe. - if (v.add_block) - this->body = new block(v.add_block, this->body); - // If when target-variable-expanding the probe, we added a new - // probe, add it in a new file to the list of files to be processed. - if (v.add_probe) - { - stapfile *f = new stapfile; - f->probes.push_back(v.add_probe); - s.files.push_back(f); - } - - // Reset the sole element of the "locations" vector as a - // "reverse-engineered" form of the incoming (q.base_loc) probe - // point. This allows a user to see what program etc. - // number any particular match of the wildcards. - - vector comps; - if (hp) - comps.push_back (new probe_point::component(TOK_PROCESS, new literal_string(path))); - else if (pid != 0) - comps.push_back (new probe_point::component(TOK_PROCESS, new literal_number(pid))); - else - comps.push_back (new probe_point::component(TOK_PROCESS)); - - switch (flags) - { - case UDPF_THREAD_BEGIN: - comps.push_back (new probe_point::component(TOK_THREAD)); - comps.push_back (new probe_point::component(TOK_BEGIN)); - break; - case UDPF_THREAD_END: - comps.push_back (new probe_point::component(TOK_THREAD)); - comps.push_back (new probe_point::component(TOK_END)); - break; - case UDPF_SYSCALL: - comps.push_back (new probe_point::component(TOK_SYSCALL)); - break; - case UDPF_SYSCALL_RETURN: - comps.push_back (new probe_point::component(TOK_SYSCALL)); - comps.push_back (new probe_point::component(TOK_RETURN)); - break; - case UDPF_BEGIN: - comps.push_back (new probe_point::component(TOK_BEGIN)); - break; - case UDPF_END: - comps.push_back (new probe_point::component(TOK_END)); - break; - default: - assert (0); - } - - // Overwrite it. - this->sole_location()->components = comps; -} - - -void -utrace_derived_probe::join_group (systemtap_session& s) -{ - if (! s.utrace_derived_probes) - { - s.utrace_derived_probes = new utrace_derived_probe_group (); - } - s.utrace_derived_probes->enroll (this); - - enable_task_finder(s); -} - - -void -utrace_var_expanding_visitor::visit_target_symbol_cached (target_symbol* e) -{ - // Get the full name of the target symbol. - stringstream ts_name_stream; - e->print(ts_name_stream); - string ts_name = ts_name_stream.str(); - - // Check and make sure we haven't already seen this target - // variable in this return probe. If we have, just return our - // last replacement. - map::iterator i = return_ts_map.find(ts_name); - if (i != return_ts_map.end()) - { - provide (i->second); - return; - } - - // We've got to do several things here to handle target - // variables in return probes. - - // (1) Synthesize a global array which is the cache of the - // target variable value. We don't need a nesting level counter - // like the dwarf_var_expanding_visitor::visit_target_symbol() - // does since a particular thread can only be in one system - // calls at a time. The array will look like this: - // - // _utrace_tvar_{name}_{num} - string aname = (string("_utrace_tvar_") - + e->base_name.substr(1) - + "_" + lex_cast(tick++)); - vardecl* vd = new vardecl; - vd->name = aname; - vd->tok = e->tok; - sess.globals.push_back (vd); - - // (2) Create a new code block we're going to insert at the - // beginning of this probe to get the cached value into a - // temporary variable. We'll replace the target variable - // reference with the temporary variable reference. The code - // will look like this: - // - // _utrace_tvar_tid = tid() - // _utrace_tvar_{name}_{num}_tmp - // = _utrace_tvar_{name}_{num}[_utrace_tvar_tid] - // delete _utrace_tvar_{name}_{num}[_utrace_tvar_tid] - - // (2a) Synthesize the tid temporary expression, which will look - // like this: - // - // _utrace_tvar_tid = tid() - symbol* tidsym = new symbol; - tidsym->name = string("_utrace_tvar_tid"); - tidsym->tok = e->tok; - - if (add_block == NULL) - { - add_block = new block; - add_block->tok = e->tok; - - // Synthesize a functioncall to grab the thread id. - functioncall* fc = new functioncall; - fc->tok = e->tok; - fc->function = string("tid"); - - // Assign the tid to '_utrace_tvar_tid'. - assignment* a = new assignment; - a->tok = e->tok; - a->op = "="; - a->left = tidsym; - a->right = fc; - - expr_statement* es = new expr_statement; - es->tok = e->tok; - es->value = a; - add_block->statements.push_back (es); - } - - // (2b) Synthesize an array reference and assign it to a - // temporary variable (that we'll use as replacement for the - // target variable reference). It will look like this: - // - // _utrace_tvar_{name}_{num}_tmp - // = _utrace_tvar_{name}_{num}[_utrace_tvar_tid] - - arrayindex* ai_tvar = new arrayindex; - ai_tvar->tok = e->tok; - - symbol* sym = new symbol; - sym->name = aname; - sym->tok = e->tok; - ai_tvar->base = sym; - - ai_tvar->indexes.push_back(tidsym); - - symbol* tmpsym = new symbol; - tmpsym->name = aname + "_tmp"; - tmpsym->tok = e->tok; - - assignment* a = new assignment; - a->tok = e->tok; - a->op = "="; - a->left = tmpsym; - a->right = ai_tvar; - - expr_statement* es = new expr_statement; - es->tok = e->tok; - es->value = a; - - add_block->statements.push_back (es); - - // (2c) Delete the array value. It will look like this: - // - // delete _utrace_tvar_{name}_{num}[_utrace_tvar_tid] - - delete_statement* ds = new delete_statement; - ds->tok = e->tok; - ds->value = ai_tvar; - add_block->statements.push_back (ds); - - // (3) We need an entry probe that saves the value for us in the - // global array we created. Create the entry probe, which will - // look like this: - // - // probe process(PATH_OR_PID).syscall { - // _utrace_tvar_tid = tid() - // _utrace_tvar_{name}_{num}[_utrace_tvar_tid] = ${param} - // } - // - // Why the temporary for tid()? If we end up caching more - // than one target variable, we can reuse the temporary instead - // of calling tid() multiple times. - - if (add_probe == NULL) - { - add_probe = new probe; - add_probe->tok = e->tok; - - // We need the name of the current probe point, minus the - // ".return". Create a new probe point, copying all the - // components, stopping when we see the ".return" - // component. - probe_point* pp = new probe_point; - for (unsigned c = 0; c < base_loc->components.size(); c++) - { - if (base_loc->components[c]->functor == "return") - break; - else - pp->components.push_back(base_loc->components[c]); - } - pp->tok = e->tok; - pp->optional = base_loc->optional; - add_probe->locations.push_back(pp); - - add_probe->body = new block; - add_probe->body->tok = e->tok; - - // Synthesize a functioncall to grab the thread id. - functioncall* fc = new functioncall; - fc->tok = e->tok; - fc->function = string("tid"); - - // Assign the tid to '_utrace_tvar_tid'. - assignment* a = new assignment; - a->tok = e->tok; - a->op = "="; - a->left = tidsym; - a->right = fc; - - expr_statement* es = new expr_statement; - es->tok = e->tok; - es->value = a; - add_probe->body = new block(add_probe->body, es); - - vardecl* vd = new vardecl; - vd->tok = e->tok; - vd->name = tidsym->name; - vd->type = pe_long; - vd->set_arity(0); - add_probe->locals.push_back(vd); - } - - // Save the value, like this: - // - // _utrace_tvar_{name}_{num}[_utrace_tvar_tid] = ${param} - a = new assignment; - a->tok = e->tok; - a->op = "="; - a->left = ai_tvar; - a->right = e; - - es = new expr_statement; - es->tok = e->tok; - es->value = a; - - add_probe->body = new block(add_probe->body, es); - - // (4) Provide the '_utrace_tvar_{name}_{num}_tmp' variable to - // our parent so it can be used as a substitute for the target - // symbol. - provide (tmpsym); - - // (5) Remember this replacement since we might be able to reuse - // it later if the same return probe references this target - // symbol again. - return_ts_map[ts_name] = tmpsym; - return; -} - - -void -utrace_var_expanding_visitor::visit_target_symbol_arg (target_symbol* e) -{ - string argnum_s = e->base_name.substr(4,e->base_name.length()-4); - int argnum = lex_cast(argnum_s); - - if (flags != UDPF_SYSCALL) - throw semantic_error ("only \"process(PATH_OR_PID).syscall\" support $argN.", e->tok); - - if (e->components.size() > 0) - { - switch (e->components[0].first) - { - case target_symbol::comp_literal_array_index: - throw semantic_error("utrace target variable '$argN' may not be used as array", - e->tok); - break; - case target_symbol::comp_struct_member: - throw semantic_error("utrace target variable '$argN' may not be used as a structure", - e->tok); - break; - default: - throw semantic_error ("invalid use of utrace target variable '$argN'", - e->tok); - break; - } - } - - // FIXME: max argnument number should not be hardcoded. - if (argnum < 1 || argnum > 6) - throw semantic_error ("invalid syscall argument number (1-6)", e->tok); - - bool lvalue = is_active_lvalue(e); - if (lvalue) - throw semantic_error("utrace '$argN' variable is read-only", e->tok); - - // Remember that we've seen a target variable. - target_symbol_seen = true; - - // We're going to substitute a synthesized '_utrace_syscall_arg' - // function call for the '$argN' reference. - functioncall* n = new functioncall; - n->tok = e->tok; - n->function = "_utrace_syscall_arg"; - n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session - - literal_number *num = new literal_number(argnum - 1); - num->tok = e->tok; - n->args.push_back(num); - - provide (n); -} - -void -utrace_var_expanding_visitor::visit_target_symbol_context (target_symbol* e) -{ - string sname = e->base_name; - - if (e->components.size() > 0) - { - switch (e->components[0].first) - { - case target_symbol::comp_literal_array_index: - throw semantic_error("utrace target variable '" + sname + "' may not be used as array", - e->tok); - break; - case target_symbol::comp_struct_member: - throw semantic_error("utrace target variable '" + sname + "' may not be used as a structure", - e->tok); - break; - default: - throw semantic_error ("invalid use of utrace target variable '" + sname + "'", - e->tok); - break; - } - } - - bool lvalue = is_active_lvalue(e); - if (lvalue) - throw semantic_error("utrace '" + sname + "' variable is read-only", e->tok); - - string fname; - if (sname == "$return") - { - if (flags != UDPF_SYSCALL_RETURN) - throw semantic_error ("only \"process(PATH_OR_PID).syscall.return\" support $return.", e->tok); - fname = "_utrace_syscall_return"; - } - else if (sname == "$syscall") - { - // If we've got a syscall entry probe, we can just call the - // right function. - if (flags == UDPF_SYSCALL) { - fname = "_utrace_syscall_nr"; - } - // If we're in a syscal return probe, we can't really access - // $syscall. So, similar to what - // dwarf_var_expanding_visitor::visit_target_symbol() does, - // we'll create an syscall entry probe to cache $syscall, then - // we'll access the cached value in the syscall return probe. - else { - visit_target_symbol_cached (e); - - // Remember that we've seen a target variable. - target_symbol_seen = true; - return; - } - } - else - { - throw semantic_error ("unknown target variable", e->tok); - } - - // Remember that we've seen a target variable. - target_symbol_seen = true; - - // We're going to substitute a synthesized '_utrace_syscall_nr' - // function call for the '$syscall' reference. - functioncall* n = new functioncall; - n->tok = e->tok; - n->function = fname; - n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session - - provide (n); -} - -void -utrace_var_expanding_visitor::visit_target_symbol (target_symbol* e) -{ - assert(e->base_name.size() > 0 && e->base_name[0] == '$'); - - if (flags != UDPF_SYSCALL && flags != UDPF_SYSCALL_RETURN) - throw semantic_error ("only \"process(PATH_OR_PID).syscall\" and \"process(PATH_OR_PID).syscall.return\" probes support target symbols", - e->tok); - - if (e->base_name.substr(0,4) == "$arg") - visit_target_symbol_arg(e); - else if (e->base_name == "$syscall" || e->base_name == "$return") - visit_target_symbol_context(e); - else - throw semantic_error ("invalid target symbol for utrace probe, $syscall, $return or $argN expected", - e->tok); -} - - -struct utrace_builder: public derived_probe_builder -{ - utrace_builder() {} - virtual void build(systemtap_session & sess, - probe * base, - probe_point * location, - literal_map_t const & parameters, - vector & finished_results) - { - string path; - int64_t pid; - - bool has_path = get_param (parameters, TOK_PROCESS, path); - bool has_pid = get_param (parameters, TOK_PROCESS, pid); - enum utrace_derived_probe_flags flags = UDPF_NONE; - - if (has_null_param (parameters, TOK_THREAD)) - { - if (has_null_param (parameters, TOK_BEGIN)) - flags = UDPF_THREAD_BEGIN; - else if (has_null_param (parameters, TOK_END)) - flags = UDPF_THREAD_END; - } - else if (has_null_param (parameters, TOK_SYSCALL)) - { - if (has_null_param (parameters, TOK_RETURN)) - flags = UDPF_SYSCALL_RETURN; - else - flags = UDPF_SYSCALL; - } - else if (has_null_param (parameters, TOK_BEGIN)) - flags = UDPF_BEGIN; - else if (has_null_param (parameters, TOK_END)) - flags = UDPF_END; - - // If we didn't get a path or pid, this means to probe everything. - // Convert this to a pid-based probe. - if (! has_path && ! has_pid) - { - has_path = false; - path.clear(); - has_pid = true; - pid = 0; - } - else if (has_path) - { - path = find_executable (path); - sess.unwindsym_modules.insert (path); - } - else if (has_pid) - { - // We can't probe 'init' (pid 1). XXX: where does this limitation come from? - if (pid < 2) - throw semantic_error ("process pid must be greater than 1", - location->tok); - - // XXX: could we use /proc/$pid/exe in unwindsym_modules and elsewhere? - } - - finished_results.push_back(new utrace_derived_probe(sess, base, location, - has_path, path, pid, - flags)); - } -}; - - -void -utrace_derived_probe_group::enroll (utrace_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++; - flags_seen[p->flags] = true; - - // XXX: multiple exec probes (for instance) for the same path (or - // pid) should all share a utrace report function, and have their - // handlers executed sequentially. -} - - -void -utrace_derived_probe_group::emit_probe_decl (systemtap_session& s, - utrace_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_utrace_probe_cb,"; - s.op->line() << " .mmap_callback=NULL,"; - s.op->line() << " .munmap_callback=NULL,"; - s.op->line() << " .mprotect_callback=NULL,"; - s.op->line() << " },"; - s.op->line() << " .pp=" << lex_cast_qstring (*p->sole_location()) << ","; - s.op->line() << " .ph=&" << p->name << ","; - - // Handle flags - switch (p->flags) - { - // Notice that we'll just call the probe directly when we get - // notified, since the task_finder layer stops the thread for us. - case UDPF_BEGIN: // process begin - s.op->line() << " .flags=(UDPF_BEGIN),"; - break; - case UDPF_THREAD_BEGIN: // thread begin - s.op->line() << " .flags=(UDPF_THREAD_BEGIN),"; - break; - - // Notice we're not setting up a .ops/.report_death handler for - // either UDPF_END or UDPF_THREAD_END. Instead, we'll just call - // the probe directly when we get notified. - case UDPF_END: // process end - s.op->line() << " .flags=(UDPF_END),"; - break; - case UDPF_THREAD_END: // thread end - s.op->line() << " .flags=(UDPF_THREAD_END),"; - break; - - // For UDPF_SYSCALL/UDPF_SYSCALL_RETURN probes, the .report_death - // handler isn't strictly necessary. However, it helps to keep - // our attaches/detaches symmetrical. Since the task_finder layer - // stops the thread, that works around bug 6841. - case UDPF_SYSCALL: - s.op->line() << " .flags=(UDPF_SYSCALL),"; - s.op->line() << " .ops={ .report_syscall_entry=stap_utrace_probe_syscall, .report_death=stap_utrace_task_finder_report_death },"; - s.op->line() << " .events=(UTRACE_EVENT(SYSCALL_ENTRY)|UTRACE_EVENT(DEATH)),"; - break; - case UDPF_SYSCALL_RETURN: - s.op->line() << " .flags=(UDPF_SYSCALL_RETURN),"; - s.op->line() << " .ops={ .report_syscall_exit=stap_utrace_probe_syscall, .report_death=stap_utrace_task_finder_report_death },"; - s.op->line() << " .events=(UTRACE_EVENT(SYSCALL_EXIT)|UTRACE_EVENT(DEATH)),"; - break; - - case UDPF_NONE: - s.op->line() << " .flags=(UDPF_NONE),"; - s.op->line() << " .ops={ },"; - s.op->line() << " .events=0,"; - break; - default: - throw semantic_error ("bad utrace probe flag"); - break; - } - s.op->line() << " .engine_attached=0,"; - s.op->line() << " },"; -} - - -void -utrace_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() << "/* ---- utrace probes ---- */"; - - s.op->newline() << "enum utrace_derived_probe_flags {"; - s.op->indent(1); - s.op->newline() << "UDPF_NONE,"; - s.op->newline() << "UDPF_BEGIN,"; - s.op->newline() << "UDPF_END,"; - s.op->newline() << "UDPF_THREAD_BEGIN,"; - s.op->newline() << "UDPF_THREAD_END,"; - s.op->newline() << "UDPF_SYSCALL,"; - s.op->newline() << "UDPF_SYSCALL_RETURN,"; - s.op->newline() << "UDPF_NFLAGS"; - s.op->newline(-1) << "};"; - - s.op->newline() << "struct stap_utrace_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() << "enum utrace_derived_probe_flags flags;"; - s.op->newline() << "struct utrace_engine_ops ops;"; - s.op->newline() << "unsigned long events;"; - s.op->newline() << "int engine_attached;"; - s.op->newline(-1) << "};"; - - - // Output handler function for UDPF_BEGIN, UDPF_THREAD_BEGIN, - // UDPF_END, and UDPF_THREAD_END - if (flags_seen[UDPF_BEGIN] || flags_seen[UDPF_THREAD_BEGIN] - || flags_seen[UDPF_END] || flags_seen[UDPF_THREAD_END]) - { - s.op->newline() << "static void stap_utrace_probe_handler(struct task_struct *tsk, struct stap_utrace_probe *p) {"; - s.op->indent(1); - - common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "p->pp"); - - // call probe function - s.op->newline() << "(*p->ph) (c);"; - common_probe_entryfn_epilogue (s.op); - - s.op->newline() << "return;"; - s.op->newline(-1) << "}"; - } - - // Output handler function for SYSCALL_ENTRY and SYSCALL_EXIT events - if (flags_seen[UDPF_SYSCALL] || flags_seen[UDPF_SYSCALL_RETURN]) - { - s.op->newline() << "#ifdef UTRACE_ORIG_VERSION"; - s.op->newline() << "static u32 stap_utrace_probe_syscall(struct utrace_attached_engine *engine, struct task_struct *tsk, struct pt_regs *regs) {"; - s.op->newline() << "#else"; - s.op->newline() << "static u32 stap_utrace_probe_syscall(enum utrace_resume_action action, struct utrace_attached_engine *engine, struct task_struct *tsk, struct pt_regs *regs) {"; - s.op->newline() << "#endif"; - - s.op->indent(1); - s.op->newline() << "struct stap_utrace_probe *p = (struct stap_utrace_probe *)engine->data;"; - - common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "p->pp"); - s.op->newline() << "c->regs = regs;"; - - // call probe function - s.op->newline() << "(*p->ph) (c);"; - common_probe_entryfn_epilogue (s.op); - - s.op->newline() << "if ((atomic_read (&session_state) != STAP_SESSION_STARTING) && (atomic_read (&session_state) != STAP_SESSION_RUNNING)) {"; - s.op->indent(1); - s.op->newline() << "debug_task_finder_detach();"; - s.op->newline() << "return UTRACE_DETACH;"; - s.op->newline(-1) << "}"; - s.op->newline() << "return UTRACE_RESUME;"; - s.op->newline(-1) << "}"; - } - - // Output task_finder callback routine that gets called for all - // utrace probe types. - s.op->newline() << "static int _stp_utrace_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_utrace_probe *p = container_of(tgt, struct stap_utrace_probe, tgt);"; - s.op->newline() << "struct utrace_attached_engine *engine;"; - - s.op->newline() << "if (register_p) {"; - s.op->indent(1); - - s.op->newline() << "switch (p->flags) {"; - s.op->indent(1); - - // When receiving a UTRACE_EVENT(CLONE) event, we can't call the - // begin/thread.begin probe directly. So, we'll just attach an - // engine that waits for the thread to quiesce. When the thread - // quiesces, then call the probe. - if (flags_seen[UDPF_BEGIN]) - { - s.op->newline() << "case UDPF_BEGIN:"; - s.op->indent(1); - s.op->newline() << "if (process_p) {"; - s.op->indent(1); - s.op->newline() << "stap_utrace_probe_handler(tsk, p);"; - s.op->newline(-1) << "}"; - s.op->newline() << "break;"; - s.op->indent(-1); - } - if (flags_seen[UDPF_THREAD_BEGIN]) - { - s.op->newline() << "case UDPF_THREAD_BEGIN:"; - s.op->indent(1); - s.op->newline() << "if (! process_p) {"; - s.op->indent(1); - s.op->newline() << "stap_utrace_probe_handler(tsk, p);"; - s.op->newline(-1) << "}"; - s.op->newline() << "break;"; - s.op->indent(-1); - } - - // For end/thread_end probes, do nothing at registration time. - // We'll handle these in the 'register_p == 0' case. - if (flags_seen[UDPF_END] || flags_seen[UDPF_THREAD_END]) - { - s.op->newline() << "case UDPF_END:"; - s.op->newline() << "case UDPF_THREAD_END:"; - s.op->indent(1); - s.op->newline() << "break;"; - s.op->indent(-1); - } - - // Attach an engine for SYSCALL_ENTRY and SYSCALL_EXIT events. - if (flags_seen[UDPF_SYSCALL] || flags_seen[UDPF_SYSCALL_RETURN]) - { - s.op->newline() << "case UDPF_SYSCALL:"; - s.op->newline() << "case UDPF_SYSCALL_RETURN:"; - s.op->indent(1); - s.op->newline() << "rc = stap_utrace_attach(tsk, &p->ops, p, p->events);"; - s.op->newline() << "if (rc == 0) {"; - s.op->indent(1); - s.op->newline() << "p->engine_attached = 1;"; - s.op->newline(-1) << "}"; - s.op->newline() << "break;"; - s.op->indent(-1); - } - - s.op->newline() << "default:"; - s.op->indent(1); - s.op->newline() << "_stp_error(\"unhandled flag value %d at %s:%d\", p->flags, __FUNCTION__, __LINE__);"; - s.op->newline() << "break;"; - s.op->indent(-1); - s.op->newline(-1) << "}"; - s.op->newline(-1) << "}"; - - // Since this engine could be attached to multiple threads, don't - // call stap_utrace_detach_ops() here, only call - // stap_utrace_detach() as necessary. - s.op->newline() << "else {"; - s.op->indent(1); - s.op->newline() << "switch (p->flags) {"; - s.op->indent(1); - // For end probes, go ahead and call the probe directly. - if (flags_seen[UDPF_END]) - { - s.op->newline() << "case UDPF_END:"; - s.op->indent(1); - s.op->newline() << "if (process_p) {"; - s.op->indent(1); - s.op->newline() << "stap_utrace_probe_handler(tsk, p);"; - s.op->newline(-1) << "}"; - s.op->newline() << "break;"; - s.op->indent(-1); - } - if (flags_seen[UDPF_THREAD_END]) - { - s.op->newline() << "case UDPF_THREAD_END:"; - s.op->indent(1); - s.op->newline() << "if (! process_p) {"; - s.op->indent(1); - s.op->newline() << "stap_utrace_probe_handler(tsk, p);"; - s.op->newline(-1) << "}"; - s.op->newline() << "break;"; - s.op->indent(-1); - } - - // For begin/thread_begin probes, we don't need to do anything. - if (flags_seen[UDPF_BEGIN] || flags_seen[UDPF_THREAD_BEGIN]) - { - s.op->newline() << "case UDPF_BEGIN:"; - s.op->newline() << "case UDPF_THREAD_BEGIN:"; - s.op->indent(1); - s.op->newline() << "break;"; - s.op->indent(-1); - } - - if (flags_seen[UDPF_SYSCALL] || flags_seen[UDPF_SYSCALL_RETURN]) - { - s.op->newline() << "case UDPF_SYSCALL:"; - s.op->newline() << "case UDPF_SYSCALL_RETURN:"; - s.op->indent(1); - s.op->newline() << "stap_utrace_detach(tsk, &p->ops);"; - s.op->newline() << "break;"; - s.op->indent(-1); - } - - s.op->newline() << "default:"; - s.op->indent(1); - s.op->newline() << "_stp_error(\"unhandled flag value %d at %s:%d\", p->flags, __FUNCTION__, __LINE__);"; - s.op->newline() << "break;"; - s.op->indent(-1); - s.op->newline(-1) << "}"; - s.op->newline(-1) << "}"; - s.op->newline() << "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_utrace_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_utrace_probe stap_utrace_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++) - { - utrace_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++) - { - utrace_derived_probe *p = it->second[i]; - emit_probe_decl(s, p); - } - } - } - s.op->newline(-1) << "};"; -} - - -void -utrace_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() << "/* ---- utrace vma callbacks ---- */"; - s.op->newline() << "for (i=0; iindent(1); - s.op->newline() << "struct stap_task_finder_target *r = &stap_utrace_vmcbs[i];"; - s.op->newline() << "rc = stap_register_task_finder_target(r);"; - s.op->newline(-1) << "}"; - s.op->newline() << "#endif"; - - s.op->newline() << "/* ---- utrace probes ---- */"; - s.op->newline() << "for (i=0; iindent(1); - s.op->newline() << "struct stap_utrace_probe *p = &stap_utrace_probes[i];"; - s.op->newline() << "rc = stap_register_task_finder_target(&p->tgt);"; - s.op->newline(-1) << "}"; - - // rollback all utrace probes - s.op->newline() << "if (rc) {"; - s.op->indent(1); - s.op->newline() << "for (j=i-1; j>=0; j--) {"; - s.op->indent(1); - s.op->newline() << "struct stap_utrace_probe *p = &stap_utrace_probes[j];"; - - s.op->newline() << "if (p->engine_attached) {"; - s.op->indent(1); - s.op->newline() << "stap_utrace_detach_ops(&p->ops);"; - s.op->newline(-1) << "}"; - s.op->newline(-1) << "}"; - - s.op->newline(-1) << "}"; -} - - -void -utrace_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() << "/* ---- utrace probes ---- */"; - s.op->newline() << "for (i=0; iindent(1); - s.op->newline() << "struct stap_utrace_probe *p = &stap_utrace_probes[i];"; - - s.op->newline() << "if (p->engine_attached) {"; - s.op->indent(1); - s.op->newline() << "stap_utrace_detach_ops(&p->ops);"; - s.op->newline(-1) << "}"; - s.op->newline(-1) << "}"; -} - - // ------------------------------------------------------------------------ // user-space probes // ------------------------------------------------------------------------ @@ -8971,6 +7961,7 @@ register_standard_tapsets(systemtap_session & s) register_tapset_perfmon(s); register_tapset_procfs(s); register_tapset_timers(s); + register_tapset_utrace(s); // dwarf-based kprobe/uprobe parts @@ -8984,44 +7975,6 @@ register_standard_tapsets(systemtap_session & s) ->bind_num(TOK_STATEMENT)->bind(TOK_ABSOLUTE)->bind(TOK_RETURN) ->bind(new uprobe_builder ()); - // utrace user-space probes - s.pattern_root->bind_str(TOK_PROCESS)->bind(TOK_BEGIN) - ->bind(new utrace_builder ()); - s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_BEGIN) - ->bind(new utrace_builder ()); - s.pattern_root->bind(TOK_PROCESS)->bind(TOK_BEGIN) - ->bind(new utrace_builder ()); - s.pattern_root->bind_str(TOK_PROCESS)->bind(TOK_END) - ->bind(new utrace_builder ()); - s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_END) - ->bind(new utrace_builder ()); - s.pattern_root->bind(TOK_PROCESS)->bind(TOK_END) - ->bind(new utrace_builder ()); - s.pattern_root->bind_str(TOK_PROCESS)->bind(TOK_THREAD)->bind(TOK_BEGIN) - ->bind(new utrace_builder ()); - s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_THREAD)->bind(TOK_BEGIN) - ->bind(new utrace_builder ()); - s.pattern_root->bind(TOK_PROCESS)->bind(TOK_THREAD)->bind(TOK_BEGIN) - ->bind(new utrace_builder ()); - s.pattern_root->bind_str(TOK_PROCESS)->bind(TOK_THREAD)->bind(TOK_END) - ->bind(new utrace_builder ()); - s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_THREAD)->bind(TOK_END) - ->bind(new utrace_builder ()); - s.pattern_root->bind(TOK_PROCESS)->bind(TOK_THREAD)->bind(TOK_END) - ->bind(new utrace_builder ()); - s.pattern_root->bind_str(TOK_PROCESS)->bind(TOK_SYSCALL) - ->bind(new utrace_builder ()); - s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_SYSCALL) - ->bind(new utrace_builder ()); - s.pattern_root->bind(TOK_PROCESS)->bind(TOK_SYSCALL) - ->bind(new utrace_builder ()); - s.pattern_root->bind_str(TOK_PROCESS)->bind(TOK_SYSCALL)->bind(TOK_RETURN) - ->bind(new utrace_builder ()); - s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_SYSCALL)->bind(TOK_RETURN) - ->bind(new utrace_builder ()); - s.pattern_root->bind(TOK_PROCESS)->bind(TOK_SYSCALL)->bind(TOK_RETURN) - ->bind(new utrace_builder ()); - // kernel tracepoint probes s.pattern_root->bind(TOK_KERNEL)->bind_str(TOK_TRACE) ->bind(new tracepoint_builder()); -- cgit From 0730bfbd2665aef93d6fae287f3623a51f243540 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 8 May 2009 17:50:28 -0700 Subject: Refactor anonymous lookups in translate_components The previous code recursed the entirety of translate_components, and it seemed to be restarting the components list every time, so it would only work if the anonymous portion was the first component. Even then, examining the code output by semok/thirtythree revealed that it wasn't fully translating the locations when multiple anonymous pieces were involved. Instead, it now recurses in a separate function, find_struct_member, which does just enough to find the member die and return. It also builds a vector of the locations passed through, so translate_components can output code for the full chain of anonymity. The generated code for semok/thirtythree's $page->mapping now appears to match the offsets from my manual inspection of struct page. I also added a test for $page->first_page->mapping, which works now but would segfault the old code. --- tapsets.cxx | 207 +++++++++++++++++++++++++++--------------------------------- 1 file changed, 94 insertions(+), 113 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index f0002073..a3ad8436 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -1667,38 +1667,104 @@ struct dwflpp while (dwarf_tag (die) == DW_TAG_member) { const char *member = dwarf_diename_integrate (die) ; - - if ( member != NULL ) - - o << " " << member; + if ( member != NULL ) + o << " " << member; else - { - Dwarf_Die temp_die = *die; - Dwarf_Attribute temp_attr ; - - if (!dwarf_attr_integrate (&temp_die, DW_AT_type, &temp_attr)) - { - clog<<"\n Error in obtaining type attribute for " - <<(dwarf_diename(&temp_die)?:""); - return ; - } + { + Dwarf_Die temp_die = *die; + Dwarf_Attribute temp_attr ; - if ( ! dwarf_formref_die (&temp_attr,&temp_die)) - { - clog<<"\n Error in decoding type attribute for " - <<(dwarf_diename(&temp_die)?:""); - return ; - } - print_members(&temp_die,o); + if (!dwarf_attr_integrate (&temp_die, DW_AT_type, &temp_attr)) + { + clog << "\n Error in obtaining type attribute for " + << (dwarf_diename(&temp_die)?:""); + return; + } - } + if (!dwarf_formref_die (&temp_attr, &temp_die)) + { + clog << "\n Error in decoding type attribute for " + << (dwarf_diename(&temp_die)?:""); + return; + } + + print_members(&temp_die,o); + } if (dwarf_siblingof (die, &die_mem) != 0) break; } } + bool + find_struct_member(const string& member, + Dwarf_Die *parentdie, + const target_symbol *e, + Dwarf_Die *memberdie, + vector& locs) + { + Dwarf_Attribute attr; + Dwarf_Die die = *parentdie; + + switch (dwarf_child (&die, &die)) + { + case 0: /* First child found. */ + break; + case 1: /* No children. */ + return false; + case -1: /* Error. */ + default: /* Shouldn't happen */ + throw semantic_error (string (dwarf_tag(&die) == DW_TAG_union_type ? "union" : "struct") + + string (dwarf_diename_integrate (&die) ?: "") + + string (dwarf_errmsg (-1)), + e->tok); + } + + do + { + if (dwarf_tag(&die) != DW_TAG_member) + continue; + + const char *name = dwarf_diename_integrate(&die); + if (name == NULL) + { + // need to recurse for anonymous structs/unions + Dwarf_Die subdie; + + if (!dwarf_attr_integrate (&die, DW_AT_type, &attr) || + !dwarf_formref_die (&attr, &subdie)) + continue; + + if (find_struct_member(member, &subdie, e, memberdie, locs)) + goto success; + } + else if (name == member) + { + *memberdie = die; + goto success; + } + } + while (dwarf_siblingof (&die, &die) == 0); + + return false; + +success: + /* As we unwind the recursion, we need to build the chain of + * locations that got to the final answer. */ + if (dwarf_attr_integrate (&die, DW_AT_data_member_location, &attr)) + locs.insert(locs.begin(), attr); + + /* Union members don't usually have a location, + * but just use the containing union's location. */ + else if (dwarf_tag(parentdie) != DW_TAG_union_type) + throw semantic_error ("no location for field '" + member + + "': " + string(dwarf_errmsg (-1)), + e->tok); + + return true; + } + Dwarf_Die * translate_components(struct obstack *pool, struct location **tail, @@ -1709,8 +1775,6 @@ struct dwflpp Dwarf_Attribute *attr_mem) { Dwarf_Die *die = NULL; - Dwarf_Die struct_die; - Dwarf_Attribute temp_attr; unsigned i = 0; @@ -1720,11 +1784,6 @@ struct dwflpp if (e->components.empty()) return die_mem; - static unsigned int func_call_level ; - static unsigned int dwarf_error_flag ; // indicates current error is dwarf error - static unsigned int dwarf_error_count ; // keeps track of no of dwarf errors - static semantic_error saved_dwarf_error(""); - while (i < e->components.size()) { /* XXX: This would be desirable, but we don't get the target_symbol token, @@ -1771,7 +1830,6 @@ struct dwflpp case DW_TAG_structure_type: case DW_TAG_union_type: - struct_die = *die; if (dwarf_hasattr(die, DW_AT_declaration)) { Dwarf_Die *tmpdie = dwflpp::declaration_resolve(dwarf_diename(die)); @@ -1781,93 +1839,16 @@ struct dwflpp e->tok); *die_mem = *tmpdie; } - switch (dwarf_child (die, die_mem)) + { - case 1: /* No children. */ - return NULL; - case -1: /* Error. */ - default: /* Shouldn't happen */ - throw semantic_error (string (typetag == DW_TAG_union_type ? "union" : "struct") - + string (dwarf_diename_integrate (die) ?: "") - + string (dwarf_errmsg (-1)), - e->tok); - break; + vector locs; + if (!find_struct_member(e->components[i].second, die, e, die, locs)) + return NULL; - case 0: - break; + for (unsigned j = 0; j < locs.size(); ++j) + translate_location (pool, &locs[j], pc, NULL, tail, e); } - while (dwarf_tag (die) != DW_TAG_member - || ({ const char *member = dwarf_diename_integrate (die); - member == NULL || string(member) != e->components[i].second; })) - { - if ( dwarf_diename (die) == NULL ) // handling Anonymous structs/unions - { - Dwarf_Die temp_die = *die; - Dwarf_Die temp_die_2; - - try - { - if (!dwarf_attr_integrate (&temp_die, DW_AT_type, &temp_attr)) - { - dwarf_error_flag ++ ; - dwarf_error_count ++; - throw semantic_error(" Error in obtaining type attribute for "+ string(dwarf_diename(&temp_die)?:""), e->tok); - } - - if ( !dwarf_formref_die (&temp_attr, &temp_die)) - { - dwarf_error_flag ++ ; - dwarf_error_count ++; - throw semantic_error(" Error in decoding DW_AT_type attribute for " + string(dwarf_diename(&temp_die)?:""), e->tok); - } - - func_call_level ++ ; - - Dwarf_Die *result_die = translate_components(pool, tail, pc, e, &temp_die, &temp_die_2, &temp_attr); - - func_call_level -- ; - - if (result_die != NULL) - { - memcpy(die_mem, &temp_die_2, sizeof(Dwarf_Die)); - memcpy(attr_mem, &temp_attr, sizeof(Dwarf_Attribute)); - return die_mem; - } - } - catch (const semantic_error& e) - { - if ( !dwarf_error_flag ) //not a dwarf error - throw; - else - { - dwarf_error_flag = 0 ; - saved_dwarf_error = e ; - } - } - } - if (dwarf_siblingof (die, die_mem) != 0) - { - if ( func_call_level == 0 && dwarf_error_count ) // this is parent call & a dwarf error has been reported in a branch somewhere - throw semantic_error( saved_dwarf_error ); - else - return NULL; - } - } - - if (dwarf_attr_integrate (die, DW_AT_data_member_location, - attr_mem) == NULL) - { - /* Union members don't usually have a location, - but just use the containing union's location. */ - if (typetag != DW_TAG_union_type) - throw semantic_error ("no location for field '" - + e->components[i].second - + "' :" + string(dwarf_errmsg (-1)), - e->tok); - } - else - translate_location (pool, attr_mem, pc, NULL, tail, e); ++i; break; -- cgit From 56212da92dae36e5870ac6149c89d967fcab10f9 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 8 May 2009 18:32:17 -0700 Subject: PR10054: Unify the translate_components errors Since translate_components is the one that knows the details of its failures, it makes more sense to let it throw its own errors, instead of relying on each caller to do it. The function now always either returns successfully or throws an error. --- tapsets.cxx | 51 ++++++++++++--------------------------------------- 1 file changed, 12 insertions(+), 39 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index a3ad8436..1e0d9e6b 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -1843,7 +1843,18 @@ success: { vector locs; if (!find_struct_member(e->components[i].second, die, e, die, locs)) - return NULL; + { + string alternatives; + stringstream members; + print_members(die, members); + if (members.str().size() != 0) + alternatives = " (alternatives:" + members.str(); + throw semantic_error("unable to find member '" + + e->components[i].second + "' for struct " + + string(dwarf_diename_integrate(die) ?: "") + + alternatives, + e->tok); + } for (unsigned j = 0; j < locs.size(); ++j) translate_location (pool, &locs[j], pc, NULL, tail, e); @@ -2130,17 +2141,6 @@ success: Dwarf_Die die_mem, *die = dwarf_formref_die (&attr_mem, &die_mem); die = translate_components (&pool, &tail, pc, e, die, &die_mem, &attr_mem); - if(!die) - { - die = dwarf_formref_die (&attr_mem, &die_mem); - stringstream alternatives; - if (die != NULL) - print_members(die,alternatives); - throw semantic_error("unable to find local '" + local + "'" - + " near pc " + lex_cast_hex(pc) - + (alternatives.str() == "" ? "" : (" (alternatives:" + alternatives.str () + ")")), - e->tok); - } /* Translate the assignment part, either x = $foo->bar->baz[NN] @@ -2218,22 +2218,6 @@ success: Dwarf_Die die_mem, *die = dwarf_formref_die (&attr_mem, &die_mem); die = translate_components (&pool, &tail, pc, e, die, &die_mem, &attr_mem); - if(!die) - { - die = dwarf_formref_die (&attr_mem, &die_mem); - stringstream alternatives; - if (die != NULL) - print_members(die,alternatives); - throw semantic_error("unable to find return value" - " near pc " + lex_cast_hex(pc) - + " for " - + string(dwarf_diename(scope_die) ?: "") - + "(" + string(dwarf_diename(cu) ?: "") - + ")" - + (alternatives.str() == "" ? "" : (" (alternatives:" + alternatives.str () + ")")), - e->tok); - } - /* Translate the assignment part, either x = $return->bar->baz[NN] @@ -2277,17 +2261,6 @@ success: Dwarf_Die die_mem, *die = NULL; die = translate_components (&pool, &tail, 0, e, type_die, &die_mem, &attr_mem); - if(!die) - { - die = dwarf_formref_die (&attr_mem, &die_mem); - stringstream alternatives; - print_members(die ?: type_die, alternatives); - throw semantic_error("unable to find member for struct " - + string(dwarf_diename(die ?: type_die) ?: "") - + (alternatives.str() == "" ? "" : (" (alternatives:" + alternatives.str () + ")")), - e->tok); - } - /* Translate the assignment part, either x = (THIS->pointer)->bar->baz[NN] -- cgit From 946e1a48eb5b92dcf17a064b62157124da661869 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 8 May 2009 19:30:42 -0700 Subject: Allow @cast failures to get optimized away We have the saved_conversion_error field, but I wasn't using it. Now @cast errors are saved in that field, so they're only seen if the optimizer doesn't remove the @cast. --- tapsets.cxx | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 1e0d9e6b..ac43a222 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -4775,13 +4775,13 @@ dwarf_var_expanding_visitor::visit_cast_op (cast_op *e) struct dwarf_cast_query : public base_query { - const cast_op& e; + cast_op& e; const bool lvalue; exp_type& pe_type; string& code; - dwarf_cast_query(dwflpp& dw, const string& module, const cast_op& e, + dwarf_cast_query(dwflpp& dw, const string& module, cast_op& e, bool lvalue, exp_type& pe_type, string& code): base_query(dw, module), e(e), lvalue(lvalue), pe_type(pe_type), code(code) {} @@ -4819,11 +4819,15 @@ dwarf_cast_query::handle_query_cu(Dwarf_Die * cudie) code = dw.literal_stmt_for_pointer (type_die, &e, lvalue, pe_type); } - catch (const semantic_error& e) + catch (const semantic_error& er) { - // XXX might be better to save the error - // and try again in another CU - sess.print_error (e); + // XXX might be better to try again in another CU + // NB: we can have multiple errors, since a @cast + // may be expanded in several different contexts: + // function ("*") { @cast(...) } + semantic_error* new_er = new semantic_error(er); + new_er->chain = e.saved_conversion_error; + e.saved_conversion_error = new_er; } return DWARF_CB_ABORT; } @@ -4972,17 +4976,9 @@ void dwarf_cast_expanding_visitor::visit_cast_op (cast_op* e) if (code.empty()) { - // We generate an error message, and pass the unresolved - // cast_op to the next pass. We hope that this value ends - // up not being referenced after all, so it can be optimized out - // quietly. - string msg = "type definition '" + e->type + "' not found"; - semantic_error* er = new semantic_error (msg, e->tok); - // NB: we can have multiple errors, since a @cast - // may be expanded in several different contexts: - // function ("*") { @cast(...) } - er->chain = e->saved_conversion_error; - e->saved_conversion_error = er; + // We pass the unresolved cast_op to the next pass, and hope + // that this value ends up not being referenced after all, so + // it can be optimized out quietly. provide (e); return; } -- cgit From 5896cd059949413cf56678d7a7fa6c0788f576b5 Mon Sep 17 00:00:00 2001 From: Mark Wielaard Date: Sun, 10 May 2009 20:24:40 +0200 Subject: Get .probes section through dwarf debuginfo file if necessary. * tapsets.cxx (dwarf_builder::build): Add some comments, verbose log messages and get Elf through dwarf_getelf if it exists before searching for .probes section. --- tapsets.cxx | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index ac43a222..0e419e96 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -5617,6 +5617,9 @@ dwarf_builder::build(systemtap_session & sess, dw = user_dw[module_name]; } + if (sess.verbose > 3) + clog << "dwarf_builder::build for " << module_name << endl; + if (((probe_point::component*)(location->components[1]))->functor == TOK_MARK) { enum probe_types @@ -5628,9 +5631,13 @@ dwarf_builder::build(systemtap_session & sess, int probe_type = dwarf_no_probes; string probe_name = (char*) location->components[1]->arg->tok->content.c_str(); + if (sess.verbose > 3) + clog << "TOK_MARK: " << probe_name << endl; + __uint64_t probe_arg = 0; Dwarf_Addr bias; - Elf* elf = dwfl_module_getelf (dw->module, &bias); + Elf* elf = (dwarf_getelf (dwfl_module_getdwarf (dw->module, &bias)) + ?: dwfl_module_getelf (dw->module, &bias)); size_t shstrndx; Elf_Scn *probe_scn = NULL; @@ -5651,18 +5658,31 @@ dwarf_builder::build(systemtap_session & sess, } } + // We got our .probes section, extract data. if (probe_type == probes_and_dwarf) { + if (sess.verbose > 3) + clog << "probe_type == probes_and_dwarf, use statement addr" << endl; + Elf_Data *pdata = elf_getdata_rawchunk (elf, shdr->sh_offset, shdr->sh_size, ELF_T_BYTE); assert (pdata != NULL); size_t probe_scn_offset = 0; size_t probe_scn_addr = shdr->sh_addr; + if (sess.verbose > 4) + clog << "got .probes elf scn_addr@0x" << probe_scn_addr << dec + << ", size: " << pdata->d_size << endl; while (probe_scn_offset < pdata->d_size) { const int stap_sentinel = 0x31425250; probe_type = *((int*)((char*)pdata->d_buf + probe_scn_offset)); if (probe_type != stap_sentinel) { + // Unless this is a mangled .probes section, this happens + // because the name of the probe comes first, followed by + // the sentinel. + if (sess.verbose > 5) + clog << "got unknown probe_type: 0x" << hex << probe_type + << dec << endl; probe_scn_offset += sizeof(int); continue; } @@ -5675,6 +5695,10 @@ dwarf_builder::build(systemtap_session & sess, if (probe_scn_offset % (sizeof(__uint64_t))) probe_scn_offset += sizeof(__uint64_t) - (probe_scn_offset % sizeof(__uint64_t)); probe_arg = *((__uint64_t*)((char*)pdata->d_buf + probe_scn_offset)); + if (sess.verbose > 4) + clog << "saw .probes " << probe_name + << "@0x" << hex << probe_arg << dec << endl; + if (probe_scn_offset % (sizeof(__uint64_t)*2)) probe_scn_offset = (probe_scn_offset + sizeof(__uint64_t)*2) - (probe_scn_offset % (sizeof(__uint64_t)*2)); if ((strcmp (location->components[1]->arg->tok->content.c_str(), @@ -5684,6 +5708,9 @@ dwarf_builder::build(systemtap_session & sess, (probe_name.c_str(), location->components[1]->arg->tok->content.c_str()))) { + if (sess.verbose > 3) + clog << "found probe_name" << probe_name << " at 0x" + << hex << probe_arg << dec << endl; } else continue; @@ -5692,6 +5719,10 @@ dwarf_builder::build(systemtap_session & sess, location->components[1]->arg = new literal_number((long)probe_arg); location->components[1]->arg->tok = sv_tok; ((literal_map_t&)parameters)[TOK_STATEMENT] = location->components[1]->arg; + + if (sess.verbose > 3) + clog << "probe_type == probes_and_dwarf, use statement addr: 0x" + << hex << probe_arg << dec << endl; dwarf_query q(sess, base, location, *dw, parameters, finished_results); q.has_mark = true; @@ -5714,8 +5745,15 @@ dwarf_builder::build(systemtap_session & sess, location->components[2]->arg = new literal_string("_stapprobe1_" + probe_name); ((literal_map_t&)parameters).erase(TOK_MARK); ((literal_map_t&)parameters).insert(pair(TOK_LABEL, location->components[2]->arg)); + + if (sess.verbose > 3) + clog << "probe_type == dwarf_no_probes, use label name: " + << "_stapprobe1_" << probe_name << endl; } + else if (sess.verbose > 3) + clog << "probe_type == probes_no_dwarf" << endl; + dw->module = 0; } -- cgit