// See the file "COPYING" in the main distribution directory for copyright. // Run-time support for (non-vector) operations in C++-compiled scripts. #pragma once #include "zeek/Frame.h" #include "zeek/OpaqueVal.h" #include "zeek/script_opt/CPP/Func.h" namespace zeek { using IntVec = std::vector; using ValVec = std::vector; using SubNetValPtr = IntrusivePtr; namespace detail { class CPPRuntime { public: static auto& RawOptField(const RecordValPtr& rv, int field) { return rv->RawOptField(field); } static auto& RawOptField(RecordVal* rv, int field) { return rv->RawOptField(field); } static const auto& GetCreationInits(const RecordType* rt) { return rt->CreationInits(); } static RecordVal* BuildRecordVal(RecordTypePtr t, std::vector> init_vals) { return new RecordVal(std::move(t), std::move(init_vals)); } }; // Returns the concatenation of the given strings. extern StringValPtr str_concat__CPP(const String* s1, const String* s2); // Returns true if string "s2" is in string "s1". extern bool str_in__CPP(const String* s1, const String* s2); // Converts a vector of individual ValPtr's into a single ListValPtr // suitable for indexing an aggregate. extern ListValPtr index_val__CPP(ValVec indices); // Returns the value corresponding to indexing the given table/vector/string // with the given set of indices. These are functions rather than something // generated directly so that they can package up the error handling for // the case where there's no such index. "patstr" refers to indexing a // table[pattern] of X with a string value. extern ValPtr index_table__CPP(const TableValPtr& t, ValVec indices); extern ValPtr index_patstr_table__CPP(const TableValPtr& t, ValVec indices); extern ValPtr index_vec__CPP(const VectorValPtr& vec, int index); extern ValPtr index_string__CPP(const StringValPtr& svp, ValVec indices); // The same, but for indexing happening inside a "when" clause. extern ValPtr when_index_table__CPP(const TableValPtr& t, ValVec indices); extern ValPtr when_index_patstr__CPP(const TableValPtr& t, ValVec indices); extern ValPtr when_index_vec__CPP(const VectorValPtr& vec, int index); // For vector slices, we use the existing index_slice(), but we need a // custom one for those occurring inside a "when" clause. extern ValPtr when_index_slice__CPP(VectorVal* vec, const ListVal* lv); // Calls out to the given script or BiF function, which does not return // a value. inline ValPtr invoke_void__CPP(Func* f, ValVec args, Frame* frame) { return f->Invoke(&args, frame); } // Used for error propagation by failed calls. class CPPInterpreterException : public InterpreterException {}; // Calls out to the given script or BiF function. A separate function because // of the need to (1) construct the "args" vector using {} initializers, // but (2) needing to have the address of that vector. inline ValPtr invoke__CPP(Func* f, ValVec args, Frame* frame) { auto v = f->Invoke(&args, frame); if ( ! v ) throw CPPInterpreterException(); return v; } // The same, but raises an interpreter exception if the function does // not return a value. Used for calls inside "when" conditions. The // last argument is the address of the calling function; we just need // it to be distinct to the call, so we can associate a Trigger cache // with it. extern ValPtr when_invoke__CPP(Func* f, ValVec args, Frame* frame, void* caller_addr); // Thrown when a call inside a "when" delays. class CPPDelayedCallException : public InterpreterException {}; // Assigns the given value to the given global. A separate function because // we also need to return the value, for use in assignment cascades. inline ValPtr set_global__CPP(IDPtr g, ValPtr v) { g->SetVal(v); return v; } // Assigns the given global to the given value, which corresponds to an // event handler. extern ValPtr set_event__CPP(IDPtr g, ValPtr v, EventHandlerPtr& gh); // Convert (in terms of the Zeek language) the given value to the given type. // A separate function in order to package up the error handling. extern ValPtr cast_value_to_type__CPP(const ValPtr& v, const TypePtr& t); // Convert a value of type "any" to the given concrete type. A separate // function in order to package up the error handling. extern ValPtr from_any__CPP(const ValPtr& v, const TypePtr& t); // Convert a vector-of-any to a vector-of-t. A separate function in order // to package up the error handling. extern ValPtr from_any_vec__CPP(const ValPtr& v, const TypePtr& t); // Returns the subnet corresponding to the given mask of the given address. // A separate function in order to package up the error handling. extern SubNetValPtr addr_mask__CPP(const IPAddr& a, uint32_t mask); // Assigns the given field in the given record to the given value. A // separate function to allow for assignment cascades. inline ValPtr assign_field__CPP(RecordValPtr rec, int field, ValPtr v) { rec->Assign(field, v); return v; } // Returns the given field in the given record. A separate function to // support error handling. inline ValPtr field_access__CPP(const RecordValPtr& rec, int field) { auto v = rec->GetFieldOrDefault(field); if ( ! v ) reporter->CPPRuntimeError("field value missing"); return v; } #define NATIVE_FIELD_ACCESS(type, zaccessor, vaccessor) \ inline type field_access_##type##__CPP(const RecordValPtr& r, int field) { \ auto& rv = CPPRuntime::RawOptField(r, field); \ if ( rv.IsSet() ) \ return rv.GetZVal().zaccessor(); \ return field_access__CPP(r, field)->vaccessor(); \ } NATIVE_FIELD_ACCESS(bool, AsInt, AsBool) NATIVE_FIELD_ACCESS(int, AsInt, AsInt) NATIVE_FIELD_ACCESS(zeek_int_t, AsInt, AsInt) NATIVE_FIELD_ACCESS(zeek_uint_t, AsCount, AsCount) NATIVE_FIELD_ACCESS(double, AsDouble, AsDouble) #define VP_FIELD_ACCESS(type, zaccessor) \ inline type##Ptr field_access_##type##__CPP(const RecordValPtr& r, int field) { \ auto& rv = CPPRuntime::RawOptField(r, field); \ if ( rv.IsSet() ) \ return {NewRef{}, rv.GetZVal().zaccessor()}; \ return cast_intrusive(field_access__CPP(r, field)); \ } VP_FIELD_ACCESS(StringVal, AsString) VP_FIELD_ACCESS(AddrVal, AsAddr) VP_FIELD_ACCESS(SubNetVal, AsSubNet) VP_FIELD_ACCESS(ListVal, AsList) VP_FIELD_ACCESS(OpaqueVal, AsOpaque) VP_FIELD_ACCESS(PatternVal, AsPattern) VP_FIELD_ACCESS(TableVal, AsTable) VP_FIELD_ACCESS(RecordVal, AsRecord) VP_FIELD_ACCESS(VectorVal, AsVector) VP_FIELD_ACCESS(TypeVal, AsType) VP_FIELD_ACCESS(Val, AsAny) // Each of the following executes the assignment "v1[v2] = v3" for // tables/vectors/strings. extern ValPtr assign_to_index__CPP(TableValPtr v1, ValPtr v2, ValPtr v3); extern ValPtr assign_to_index__CPP(VectorValPtr v1, ValPtr v2, ValPtr v3); extern ValPtr assign_to_index__CPP(StringValPtr v1, ValPtr v2, ValPtr v3); // Executes an "add" statement for the given set. extern void add_element__CPP(TableValPtr aggr, ListValPtr indices); // Executes a "delete" statement for the given set. extern void remove_element__CPP(TableValPtr aggr, ListValPtr indices); // Returns the given table/set (which should be empty) coerced to // the given Zeek type. A separate function in order to deal with // error handling. Inlined because this gets invoked a lot. inline TableValPtr table_coerce__CPP(const ValPtr& v, const TypePtr& t) { TableVal* tv = v->AsTableVal(); if ( tv->Size() > 0 ) reporter->CPPRuntimeError("coercion of non-empty table/set"); return make_intrusive(cast_intrusive(t), tv->GetAttrs()); } // For tables, executes t1 += t2. inline TableValPtr table_append__CPP(const TableValPtr& t1, const TableValPtr& t2) { t2->AddTo(t1.get(), false); return t1; } // For tables, executes t1 -= t2. inline TableValPtr table_remove_from__CPP(const TableValPtr& t1, const TableValPtr& t2) { if ( t2->Size() > 0 ) t2->RemoveFrom(t1.get()); return t1; } // The same, for an empty record. inline VectorValPtr vector_coerce__CPP(const ValPtr& v, const TypePtr& t) { VectorVal* vv = v->AsVectorVal(); if ( vv->Size() > 0 ) reporter->CPPRuntimeError("coercion of non-empty vector"); return make_intrusive(cast_intrusive(t)); } // Takes parallel vectors of attribute tags and values and returns a // collective AttributesPtr corresponding to those instantiated attributes. // For attributes that don't have associated expressions, the corresponding // value should be nil. extern AttributesPtr build_attrs__CPP(IntVec attr_tags, std::vector attr_vals); // Constructs a set of the given type, containing the given elements, and // with the associated attributes. extern TableValPtr set_constructor__CPP(ValVec elements, TableTypePtr t, IntVec attr_tags, ValVec attr_vals); // Constructs a table of the given type, containing the given elements // (specified as parallel index/value vectors), and with the associated // attributes. extern TableValPtr table_constructor__CPP(ValVec indices, ValVec vals, TableTypePtr t, IntVec attr_tags, ValVec attr_vals); // Assigns a set of attributes to an identifier. extern void assign_attrs__CPP(IDPtr id, IntVec attr_tags, ValVec attr_vals); // Constructs a record of the given type, whose (ordered) fields are // assigned to the corresponding elements of the given vector of values. extern RecordValPtr record_constructor__CPP(ValVec vals, RecordTypePtr t); // Same, but with a map when using a named constructor. extern RecordValPtr record_constructor_map__CPP(ValVec vals, IntVec map, RecordTypePtr t); // Constructs a vector of the given type, populated with the given values. extern VectorValPtr vector_constructor__CPP(ValVec vals, VectorTypePtr t); // For patterns, executes p1 += p2. inline PatternValPtr re_append__CPP(const PatternValPtr& p1, const PatternValPtr& p2) { p2->AddTo(p1.get(), false); return p1; } // Schedules an event to occur at the given absolute time, parameterized // with the given set of values. A separate function to facilitate avoiding // the scheduling if Zeek is terminating. extern ValPtr schedule__CPP(double dt, EventHandlerPtr event, ValVec args); // Simple helper functions for supporting absolute value. inline zeek_uint_t iabs__CPP(zeek_int_t v) { return v < 0 ? -v : v; } inline double fabs__CPP(double v) { return v < 0.0 ? -v : v; } // The following operations are provided using functions to support // error checking/reporting. inline zeek_int_t idiv__CPP(zeek_int_t v1, zeek_int_t v2) { if ( v2 == 0 ) reporter->CPPRuntimeError("division by zero"); return v1 / v2; } inline zeek_int_t imod__CPP(zeek_int_t v1, zeek_int_t v2) { if ( v2 == 0 ) reporter->CPPRuntimeError("modulo by zero"); return v1 % v2; } inline zeek_uint_t udiv__CPP(zeek_uint_t v1, zeek_uint_t v2) { if ( v2 == 0 ) reporter->CPPRuntimeError("division by zero"); return v1 / v2; } inline zeek_uint_t umod__CPP(zeek_uint_t v1, zeek_uint_t v2) { if ( v2 == 0 ) reporter->CPPRuntimeError("modulo by zero"); return v1 % v2; } inline double fdiv__CPP(double v1, double v2) { if ( v2 == 0.0 ) reporter->CPPRuntimeError("division by zero"); return v1 / v2; } } // namespace detail } // namespace zeek