// See the file "COPYING" in the main distribution directory for copyright. #pragma once #include #include #include #include #include #include #include "zeek/BifReturnVal.h" #include "zeek/Obj.h" #include "zeek/Scope.h" #include "zeek/Stmt.h" #include "zeek/TraverseTypes.h" #include "zeek/Type.h" /* for function_flavor */ #include "zeek/ZeekArgs.h" #include "zeek/ZeekList.h" namespace broker { class data; using vector = std::vector; template class expected; } namespace zeek { class Val; class FuncType; namespace detail { class Scope; class Stmt; class CallExpr; class ID; class Frame; using ScopePtr = IntrusivePtr; using IDPtr = IntrusivePtr; using StmtPtr = IntrusivePtr; class ScriptFunc; } // namespace detail class EventGroup; using EventGroupPtr = std::shared_ptr; class Func; using FuncPtr = IntrusivePtr; class Func : public Obj { public: static inline const FuncPtr nil; enum Kind { SCRIPT_FUNC, BUILTIN_FUNC }; explicit Func(Kind arg_kind) : kind(arg_kind) { } virtual bool IsPure() const = 0; FunctionFlavor Flavor() const { return GetType()->Flavor(); } struct Body { detail::StmtPtr stmts; int priority; std::set groups; // If any of the groups are disabled, this body is disabled. // The disabled field is updated from EventGroup instances. bool disabled = false; bool operator<(const Body& other) const { return priority > other.priority; } // reverse sort }; const std::vector& GetBodies() const { return bodies; } bool HasBodies() const { return ! bodies.empty(); } /** * Are there bodies and is any one of them enabled? * * @return true if bodies exist and at least one is enabled. */ bool HasEnabledBodies() const { return ! bodies.empty() && has_enabled_bodies; }; /** * Calls a Zeek function. * @param args the list of arguments to the function call. * @param parent the frame from which the function is being called. * @return the return value of the function call. */ virtual ValPtr Invoke(zeek::Args* args, detail::Frame* parent = nullptr) const = 0; /** * A version of Invoke() taking a variable number of individual arguments. */ template std::enable_if_t>, ValPtr>, ValPtr> Invoke(Args&&... args) const { auto zargs = zeek::Args{std::forward(args)...}; return Invoke(&zargs); } // Add a new event handler to an existing function (event). virtual void AddBody(detail::StmtPtr new_body, const std::vector& new_inits, size_t new_frame_size, int priority, const std::set& groups); // Add a new event handler to an existing function (event). virtual void AddBody(detail::StmtPtr new_body, const std::vector& new_inits, size_t new_frame_size, int priority = 0); virtual void SetScope(detail::ScopePtr newscope); virtual detail::ScopePtr GetScope() const { return scope; } const FuncTypePtr& GetType() const { return type; } Kind GetKind() const { return kind; } const char* Name() const { return name.c_str(); } void SetName(const char* arg_name) { name = arg_name; } void Describe(ODesc* d) const override = 0; virtual void DescribeDebug(ODesc* d, const zeek::Args* args) const; virtual FuncPtr DoClone(); virtual detail::TraversalCode Traverse(detail::TraversalCallback* cb) const; protected: Func() = default; // Copies this function's state into other. void CopyStateInto(Func* other) const; // Helper function for checking result of plugin hook. void CheckPluginResult(bool handled, const ValPtr& hook_result, FunctionFlavor flavor) const; std::vector bodies; detail::ScopePtr scope; Kind kind = SCRIPT_FUNC; FuncTypePtr type; std::string name; private: // EventGroup updates Func::Body.disabled and has_enabled_bodies. // This is friend/private with EventGroup here so that we do not // expose accessors in the zeek:: public interface. friend class EventGroup; bool has_enabled_bodies = true; }; namespace detail { class ScriptFunc : public Func { public: ScriptFunc(const IDPtr& id); // For compiled scripts. ScriptFunc(std::string name, FuncTypePtr ft, std::vector bodies, std::vector priorities); ~ScriptFunc() override; bool IsPure() const override; ValPtr Invoke(zeek::Args* args, Frame* parent) const override; /** * Creates a separate frame for captures and initializes its * elements. The list of captures comes from the ScriptFunc's * type, so doesn't need to be passed in, just the frame to * use in evaluating the identifiers. * * @param f the frame used for evaluating the captured identifiers */ void CreateCaptures(Frame* f); /** * Returns the frame associated with this function for tracking * captures, or nil if there isn't one. * * @return internal frame kept by the function for persisting captures */ Frame* GetCapturesFrame() const { return captures_frame; } // Same definition as in Frame.h. using OffsetMap = std::unordered_map; /** * Returns the mapping of captures to slots in the captures frame. * * @return pointer to mapping of captures to slots */ const OffsetMap* GetCapturesOffsetMap() const { return captures_offset_mapping; } /** * Serializes this function's capture frame. * * @return a serialized version of the function's capture frame. */ virtual broker::expected SerializeCaptures() const; /** * Sets the captures frame to one built from *data*. * * @param data a serialized frame */ bool DeserializeCaptures(const broker::vector& data); using Func::AddBody; void AddBody(detail::StmtPtr new_body, const std::vector& new_inits, size_t new_frame_size, int priority, const std::set& groups) override; /** * Replaces the given current instance of a function body with * a new one. If new_body is nil then the current instance is * deleted with no replacement. * * @param old_body Body to replace. * @param new_body New body to use; can be nil. */ void ReplaceBody(const detail::StmtPtr& old_body, detail::StmtPtr new_body); StmtPtr CurrentBody() const { return current_body; } int CurrentPriority() const { return current_priority; } /** * Returns the function's frame size. * @return The number of ValPtr slots in the function's frame. */ int FrameSize() const { return frame_size; } /** * Changes the function's frame size to a new size - used for * script optimization/compilation. * * @param new_size The frame size the function should use. */ void SetFrameSize(int new_size) { frame_size = new_size; } /** Sets this function's outer_id list. */ void SetOuterIDs(IDPList ids) { outer_ids = std::move(ids); } void Describe(ODesc* d) const override; protected: ScriptFunc() : Func(SCRIPT_FUNC) { } StmtPtr AddInits(StmtPtr body, const std::vector& inits); /** * Clones this function along with its captures. */ FuncPtr DoClone() override; /** * Uses the given frame for captures, and generates the * mapping from captured variables to offsets in the frame. * * @param f the frame holding the values of capture variables */ virtual void SetCaptures(Frame* f); private: size_t frame_size = 0; // List of the outer IDs used in the function. IDPList outer_ids; // Frame for (capture-by-copy) closures. These persist over the // function's lifetime, providing quasi-globals that maintain // state across individual calls to the function. Frame* captures_frame = nullptr; OffsetMap* captures_offset_mapping = nullptr; // The most recently added/updated body ... StmtPtr current_body; // ... and its priority. int current_priority = 0; }; using built_in_func = BifReturnVal (*)(Frame* frame, const Args* args); class BuiltinFunc final : public Func { public: BuiltinFunc(built_in_func func, const char* name, bool is_pure); ~BuiltinFunc() override; bool IsPure() const override; ValPtr Invoke(zeek::Args* args, Frame* parent) const override; built_in_func TheFunc() const { return func; } void Describe(ODesc* d) const override; protected: BuiltinFunc() { func = nullptr; is_pure = 0; } built_in_func func; bool is_pure; }; extern bool check_built_in_call(BuiltinFunc* f, CallExpr* call); struct CallInfo { const CallExpr* call; const Func* func; const zeek::Args& args; }; // Struct that collects all the specifics defining a Func. Used for ScriptFuncs // with closures. class FunctionIngredients { public: // Gathers all of the information from a scope and a function body needed // to build a function. FunctionIngredients(ScopePtr scope, StmtPtr body, const std::string& module_name); const IDPtr& GetID() const { return id; } const StmtPtr& Body() const { return body; } void SetBody(StmtPtr _body) { body = std::move(_body); } const auto& Inits() const { return inits; } size_t FrameSize() const { return frame_size; } int Priority() const { return priority; } const ScopePtr& Scope() const { return scope; } const auto& Groups() const { return groups; } private: IDPtr id; StmtPtr body; std::vector inits; size_t frame_size = 0; int priority = 0; ScopePtr scope; std::set groups; }; extern std::vector call_stack; // This is set to true after the built-in functions have been initialized. extern bool did_builtin_init; extern std::vector bif_initializers; extern void init_primary_bifs(); inline void run_bif_initializers() { for ( const auto& bi : bif_initializers ) bi(); bif_initializers = {}; } extern void emit_builtin_exception(const char* msg); extern void emit_builtin_exception(const char* msg, const ValPtr& arg); extern void emit_builtin_exception(const char* msg, Obj* arg); } // namespace detail extern std::string render_call_stack(); // These methods are used by BIFs, so they're in the public namespace. extern void emit_builtin_error(const char* msg); extern void emit_builtin_error(const char* msg, const ValPtr&); extern void emit_builtin_error(const char* msg, Obj* arg); } // namespace zeek