1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
|
// tapset for begin/end/error/never
// Copyright (C) 2005-2019 Red Hat Inc.
// Copyright (C) 2005-2007 Intel Corporation.
//
// This file is part of systemtap, and is free software. You can
// redistribute it and/or modify it under the terms of the GNU General
// Public License (GPL); either version 2, or (at your option) any
// later version.
#include "config.h"
#include "session.h"
#include "tapsets.h"
#include "translate.h"
#include "util.h"
#include <algorithm>
#include <string>
using namespace std;
using namespace __gnu_cxx;
static const string TOK_BEGIN("begin");
static const string TOK_END("end");
static const string TOK_ERROR("error");
static const string TOK_NEVER("never");
// ------------------------------------------------------------------------
// begin/end/error probes are run right during registration / deregistration
// ------------------------------------------------------------------------
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;
}
// No assertion need be emitted, since these probes are allowed for
// unprivileged users.
void emit_privilege_assertion (translator_output*) {}
void print_dupe_stamp(ostream& o) { print_dupe_stamp_unprivileged (o); }
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<be_derived_probe>
{
friend bool sort_for_bpf(systemtap_session& s,
be_derived_probe_group *be,
std::vector<derived_probe *> &begin_v,
std::vector<derived_probe *> &end_v,
std::vector<derived_probe *> &error_v);
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<derived_probe *> & finished_results)
{
int64_t priority = 0;
if (type == BEGIN)
get_param(parameters, TOK_BEGIN, priority);
else if (type == END)
get_param(parameters, TOK_END, priority);
else if (type == ERROR)
get_param(parameters, TOK_ERROR, priority);
finished_results.push_back
(new be_derived_probe(base, location, type, priority));
}
virtual string name() { return "begin/end builder"; }
};
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);
this->group = s.be_derived_probes;
}
void
be_derived_probe_group::emit_module_decls (systemtap_session& s)
{
if (probes.empty()) return;
map<be_t, const char *> states;
states[BEGIN] = "STAP_SESSION_STARTING";
states[END] = "STAP_SESSION_STOPPING";
states[ERROR] = "STAP_SESSION_ERROR";
s.op->newline() << "/* ---- begin/end/error probes ---- */";
// 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);
s.op->newline() << "static struct stap_be_probe {";
s.op->newline(1) << "const struct stap_probe * const probe;";
s.op->newline() << "int state, type;";
s.op->newline(-1) << "} stap_be_probes[] = {";
s.op->indent(1);
for (unsigned i=0; i < probes.size(); i++)
{
s.op->newline () << "{";
s.op->line() << " .probe=" << common_probe_init (probes[i]) << ",";
s.op->line() << " .state=" << states[probes[i]->type] << ",";
s.op->line() << " .type=" << probes[i]->type;
s.op->line() << " },";
}
s.op->newline(-1) << "};";
s.op->newline() << "static void enter_be_probe (struct stap_be_probe *stp) {";
s.op->indent(1);
common_probe_entryfn_prologue (s, "stp->state", "", "stp->probe",
"stp_probe_type_been", false);
s.op->newline() << "(*stp->probe->ph) (c);";
common_probe_entryfn_epilogue (s, false, otf_safe_context(s));
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 << ")";
s.op->newline(1) << "enter_be_probe (stp); /* 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(-2) << "}";
}
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 << ")";
s.op->newline(1) << "enter_be_probe (stp);";
s.op->newline(-2) << "}";
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 << ")";
s.op->newline(1) << "enter_be_probe (stp);";
s.op->newline(-2) << "}";
}
bool
sort_for_bpf(systemtap_session& s __attribute__ ((unused)),
be_derived_probe_group *be,
std::vector<derived_probe *> &begin_v,
std::vector<derived_probe *> &end_v,
std::vector<derived_probe *> &error_v)
{
if (!be || be->probes.empty())
return false;
sort(be->probes.begin(), be->probes.end(), be_derived_probe::comp);
for (auto i = be->probes.begin(); i != be->probes.end(); ++i)
{
be_derived_probe *p = *i;
if (p->type == BEGIN)
begin_v.push_back(p);
else if (p->type == END)
end_v.push_back(p);
else
error_v.push_back(p);
}
return true;
}
// ------------------------------------------------------------------------
// never probes are never run
// ------------------------------------------------------------------------
struct never_derived_probe: public derived_probe
{
never_derived_probe (probe* p, probe_point* l): derived_probe (p, l) {}
void join_group (systemtap_session&) { /* thus no probe_group */ }
void emit_privilege_assertion (translator_output*) {}
void print_dupe_stamp(ostream& o) { print_dupe_stamp_unprivileged (o); }
};
struct never_builder: public derived_probe_builder
{
never_builder() {}
virtual void build(systemtap_session &,
probe * base,
probe_point * location,
literal_map_t const &,
vector<derived_probe *> & finished_results)
{
finished_results.push_back(new never_derived_probe(base, location));
}
virtual string name() { return "never builder"; }
};
// ------------------------------------------------------------------------
// unified registration for begin/end/error/never
// ------------------------------------------------------------------------
void
register_tapset_been(systemtap_session& s)
{
match_node* root = s.pattern_root;
root->bind(TOK_BEGIN)
->bind_privilege(pr_all)
->bind(new be_builder(BEGIN));
root->bind_num(TOK_BEGIN)
->bind_privilege(pr_all)
->bind(new be_builder(BEGIN));
root->bind(TOK_END)
->bind_privilege(pr_all)
->bind(new be_builder(END));
root->bind_num(TOK_END)
->bind_privilege(pr_all)
->bind(new be_builder(END));
root->bind(TOK_ERROR)
->bind_privilege(pr_all)
->bind(new be_builder(ERROR));
root->bind_num(TOK_ERROR)
->bind_privilege(pr_all)
->bind(new be_builder(ERROR));
root->bind(TOK_NEVER)
->bind_privilege(pr_all)
->bind(new never_builder());
}
/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
|