zeek/src/plugin/Plugin.cc
Arne Welzel 993cdd03e0 plugin: Add InitPreExecution()
Currently, plugins do not have a way to further inspect or even mutate
script functions after ZAM optimization ran. One use-case here is
zeek-perf-support [1]. This plugin wraps Stmt instances of functions,
events and hooks hooks with a small assembly stub to support JIT map
files [2] and for integration with perf tools.

This change introduces a new InitPreExecution() hook that runs after
ZAM optimization completed, just before the zeek_init() event is enqueued.

Additionally, remove the existing CPP_activation_hook. It doesn't seem
to be used. If it becomes necessary in the future, the new
InitPreExecution() hook can be leveraged instead.

[1] https://github.com/zeek/zeek-perf-support
[2] https://github.com/torvalds/linux/blob/master/tools/perf/Documentation/jit-interface.txt
2024-11-18 13:53:56 +01:00

421 lines
11 KiB
C++

// See the file "COPYING" in the main distribution directory for copyright.
#include "zeek/plugin/Plugin.h"
#include <cassert>
#include "zeek/Conn.h"
#include "zeek/Desc.h"
#include "zeek/Event.h"
#include "zeek/Func.h"
#include "zeek/Val.h"
#include "zeek/input.h"
#include "zeek/plugin/Component.h"
#include "zeek/plugin/Manager.h"
#include "zeek/threading/SerialTypes.h"
namespace zeek::plugin {
const char* hook_name(HookType h) {
static constexpr const char* hook_names[int(NUM_HOOKS) + 1] = {
// Order must match that of HookType.
"LoadFile",
"LoadFileExtended",
"CallFunction",
"QueueEvent",
"DrainEvents",
"UpdateNetworkTime",
"SetupAnalyzerTree",
"LogInit",
"LogWrite",
"Reporter",
"UnprocessedPacket",
"ObjDtor",
// MetaHooks
"MetaHookPre",
"MetaHookPost",
// End marker.
"<end>",
};
return hook_names[int(h)];
}
BifItem::BifItem(const std::string& arg_id, Type arg_type) {
id = arg_id;
type = arg_type;
}
BifItem::BifItem(const BifItem& other) {
id = other.id;
type = other.type;
}
BifItem& BifItem::operator=(const BifItem& other) {
if ( this != &other ) {
id = other.id;
type = other.type;
}
return *this;
}
void HookArgument::Describe(ODesc* d) const {
switch ( type ) {
case BOOL: d->Add(arg.bool_ ? "true" : "false"); break;
case DOUBLE: d->Add(arg.double_); break;
case EVENT:
if ( arg.event ) {
d->Add(arg.event->Handler()->Name());
d->Add("(");
describe_vals(arg.event->Args(), d);
d->Add(")");
}
else
d->Add("<null>");
break;
case CONN:
if ( arg.conn )
arg.conn->Describe(d);
break;
case FUNC_RESULT:
if ( func_result.first ) {
if ( func_result.second )
func_result.second->Describe(d);
else
d->Add("<null>");
}
else
d->Add("<no result>");
break;
case FRAME:
if ( arg.frame )
d->Add("<frame>");
else
d->Add("<null>");
break;
case FUNC:
if ( arg.func )
d->Add(arg.func->GetName());
else
d->Add("<null>");
break;
case INT: d->Add(arg.int_); break;
case STRING: d->Add(arg_string); break;
case VAL:
if ( arg.val )
arg.val->Describe(d);
else
d->Add("<null>");
break;
case VAL_LIST:
if ( arg.vals ) {
d->Add("(");
describe_vals(arg.vals, d);
d->Add(")");
}
else
d->Add("<null>");
break;
case ARG_LIST:
if ( arg.args ) {
d->Add("(");
describe_vals(*arg.args, d);
d->Add(")");
}
else
d->Add("<null>");
break;
case VOID: d->Add("<void>"); break;
case VOIDP: d->Add("<void ptr>"); break;
case WRITER_INFO: {
d->Add(arg.winfo->path);
d->Add("(");
d->Add(arg.winfo->network_time);
d->Add(",");
d->Add(arg.winfo->rotation_interval);
d->Add(",");
d->Add(arg.winfo->rotation_base);
if ( arg.winfo->config.size() > 0 ) {
bool first = true;
d->Add("config: {");
for ( auto& v : arg.winfo->config ) {
if ( ! first )
d->Add(", ");
d->Add(v.first);
d->Add(": ");
d->Add(v.second);
first = false;
}
d->Add("}");
}
d->Add(")");
} break;
case THREAD_FIELDS: {
d->Add("{");
for ( int i = 0; i < tfields.first; i++ ) {
const threading::Field* f = tfields.second[i];
if ( i > 0 )
d->Add(", ");
d->Add(f->name);
d->Add(" (");
d->Add(f->TypeName());
d->Add(")");
}
d->Add("}");
} break;
case LOCATION:
if ( arg.loc ) {
arg.loc->Describe(d);
}
else {
d->Add("<no location>");
}
break;
case INPUT_FILE: {
d->Add("(");
d->Add(input_file.first);
d->Add(", ");
if ( input_file.second )
d->Add(input_file.second->substr(0, 20)); // cut content off
else
d->Add("<no content>");
d->Add(")");
break;
}
case PACKET: d->Add("<packet>"); break;
}
}
Plugin::Plugin() {
dynamic = false;
Manager::RegisterPlugin(this);
}
Plugin::~Plugin() { Done(); }
void Plugin::DoConfigure() { config = Configure(); }
const std::string& Plugin::Name() const { return config.name; }
const std::string& Plugin::Description() const { return config.description; }
VersionNumber Plugin::Version() const { return config.version; }
bool Plugin::DynamicPlugin() const { return dynamic; }
const std::string& Plugin::PluginDirectory() const { return base_dir; }
const std::string& Plugin::PluginPath() const { return sopath; }
void Plugin::SetPluginLocation(const std::string& arg_dir, const std::string& arg_sopath) {
base_dir = arg_dir;
sopath = arg_sopath;
}
void Plugin::SetDynamic(bool is_dynamic) { dynamic = is_dynamic; }
void Plugin::InitPreScript() {}
void Plugin::InitPostScript() {}
void Plugin::InitPreExecution() {}
Plugin::bif_item_list Plugin::BifItems() const { return bif_items; }
void Plugin::Done() {
for ( component_list::const_iterator i = components.begin(); i != components.end(); i++ )
delete *i;
components.clear();
}
Plugin::component_list Plugin::Components() const { return components; }
static bool component_cmp(const Component* a, const Component* b) { return a->Name() < b->Name(); }
bool Plugin::LoadZeekFile(const std::string& file) {
::add_input_file(file.c_str());
return true;
}
void Plugin::AddBifItem(const std::string& name, BifItem::Type type) {
BifItem bi(name, (BifItem::Type)type);
bif_items.push_back(bi);
}
void Plugin::AddComponent(Component* c) {
components.push_back(c);
// Sort components by name to make sure we have a deterministic
// order.
components.sort(component_cmp);
}
Plugin::hook_list Plugin::EnabledHooks() const { return plugin_mgr->HooksEnabledForPlugin(this); }
void Plugin::EnableHook(HookType hook, int priority) { plugin_mgr->EnableHook(hook, this, priority); }
void Plugin::DisableHook(HookType hook) { plugin_mgr->DisableHook(hook, this); }
void Plugin::RequestEvent(EventHandlerPtr handler) { plugin_mgr->RequestEvent(handler, this); }
void Plugin::RequestObjDtor(Obj* obj) { plugin_mgr->RequestObjDtor(obj, this); }
int Plugin::HookLoadFile(const LoadType type, const std::string& file, const std::string& resolved) { return -1; }
std::pair<int, std::optional<std::string>> Plugin::HookLoadFileExtended(const LoadType type, const std::string& file,
const std::string& resolved) {
return std::make_pair(-1, std::nullopt);
}
std::pair<bool, ValPtr> Plugin::HookFunctionCall(const Func* func, zeek::detail::Frame* parent, Args* args) {
return {false, nullptr};
}
bool Plugin::HookQueueEvent(Event* event) { return false; }
void Plugin::HookDrainEvents() {}
void Plugin::HookUpdateNetworkTime(double network_time) {}
void Plugin::HookSetupAnalyzerTree(Connection* conn) {}
void Plugin::HookObjDtor(void* obj) {}
void Plugin::HookLogInit(const std::string& writer, const std::string& instantiating_filter, bool local, bool remote,
const logging::WriterBackend::WriterInfo& info, int num_fields,
const threading::Field* const* fields) {}
bool Plugin::HookLogWrite(const std::string& writer, const std::string& filter,
const logging::WriterBackend::WriterInfo& info, int num_fields,
const threading::Field* const* fields, threading::Value** vals) {
return true;
}
bool Plugin::HookReporter(const std::string& prefix, const EventHandlerPtr event, const Connection* conn,
const ValPList* addl, bool location, const zeek::detail::Location* location1,
const zeek::detail::Location* location2, bool time, const std::string& message) {
return true;
}
void Plugin::HookUnprocessedPacket(const Packet* packet) {}
void Plugin::MetaHookPre(HookType hook, const HookArgumentList& args) {}
void Plugin::MetaHookPost(HookType hook, const HookArgumentList& args, HookArgument result) {}
void Plugin::InitializeComponents() {
for ( component_list::const_iterator i = components.begin(); i != components.end(); i++ )
(*i)->Initialize();
}
void Plugin::Describe(ODesc* d) const {
d->Add(config.name);
if ( config.description.size() ) {
d->Add(" - ");
d->Add(config.description);
}
if ( dynamic ) {
d->Add(" (dynamic, ");
if ( config.version ) {
d->Add("version ");
d->Add(config.version.major);
d->Add(".");
d->Add(config.version.minor);
d->Add(".");
d->Add(config.version.patch);
d->Add(")");
}
else
d->Add("no version information)");
}
else
d->Add(" (built-in)");
d->Add("\n");
if ( d->IsShort() )
return;
for ( component_list::const_iterator i = components.begin(); i != components.end(); i++ ) {
(*i)->Describe(d);
d->Add("\n");
}
bif_item_list items = BifItems();
for ( bif_item_list::const_iterator i = items.begin(); i != items.end(); i++ ) {
const char* type = nullptr;
switch ( (*i).GetType() ) {
case BifItem::FUNCTION: type = "Function"; break;
case BifItem::EVENT: type = "Event"; break;
case BifItem::CONSTANT: type = "Constant"; break;
case BifItem::GLOBAL: type = "Global"; break;
case BifItem::TYPE: type = "Type"; break;
default: type = "<unknown>";
}
d->Add(" ");
d->Add("[");
d->Add(type);
d->Add("] ");
d->Add((*i).GetID());
d->Add("\n");
}
hook_list hooks = EnabledHooks();
for ( hook_list::iterator i = hooks.begin(); i != hooks.end(); i++ ) {
HookType hook = (*i).first;
int prio = (*i).second;
d->Add(" Implements ");
d->Add(hook_name(hook));
d->Add(" (priority ");
d->Add(prio);
d->Add(")\n");
}
}
} // namespace zeek::plugin