mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
Merge remote-tracking branch 'origin/topic/vern/event-trace'
* origin/topic/vern/event-trace: low-level style tweaks --event-trace / -E option to generate event trace hooks to support event tracing classes providing event-tracing/dumping functionality provide access to Val internals for event tracing purposes set_network_time() BiF in support of event replaying low-level naming tweaks / comments / const-ified accessor
This commit is contained in:
commit
fe935a572f
15 changed files with 1646 additions and 19 deletions
12
CHANGES
12
CHANGES
|
@ -1,3 +1,15 @@
|
||||||
|
5.0.0-dev.204 | 2022-03-25 15:31:21 -0700
|
||||||
|
|
||||||
|
* --event-trace / -E option to generate event trace (Vern Paxson, Corelight)
|
||||||
|
|
||||||
|
* hooks to support event tracing (Vern Paxson, Corelight)
|
||||||
|
|
||||||
|
* classes providing event-tracing/dumping functionality (Vern Paxson, Corelight)
|
||||||
|
|
||||||
|
* provide access to Val internals for event tracing purposes (Vern Paxson, Corelight)
|
||||||
|
|
||||||
|
* set_network_time() BiF in support of event replaying (Vern Paxson, Corelight)
|
||||||
|
|
||||||
5.0.0-dev.195 | 2022-03-24 11:01:28 -0700
|
5.0.0-dev.195 | 2022-03-24 11:01:28 -0700
|
||||||
|
|
||||||
* switch variable initialization over to being expression-based (Vern Paxson, Corelight)
|
* switch variable initialization over to being expression-based (Vern Paxson, Corelight)
|
||||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
||||||
5.0.0-dev.195
|
5.0.0-dev.204
|
||||||
|
|
|
@ -313,6 +313,7 @@ set(MAIN_SRCS
|
||||||
EventHandler.cc
|
EventHandler.cc
|
||||||
EventLauncher.cc
|
EventLauncher.cc
|
||||||
EventRegistry.cc
|
EventRegistry.cc
|
||||||
|
EventTrace.cc
|
||||||
Expr.cc
|
Expr.cc
|
||||||
File.cc
|
File.cc
|
||||||
Flare.cc
|
Flare.cc
|
||||||
|
|
|
@ -20,7 +20,7 @@ class EventHandler
|
||||||
public:
|
public:
|
||||||
explicit EventHandler(std::string name);
|
explicit EventHandler(std::string name);
|
||||||
|
|
||||||
const char* Name() { return name.data(); }
|
const char* Name() const { return name.data(); }
|
||||||
|
|
||||||
const FuncPtr& GetFunc() { return local; }
|
const FuncPtr& GetFunc() { return local; }
|
||||||
|
|
||||||
|
|
1079
src/EventTrace.cc
Normal file
1079
src/EventTrace.cc
Normal file
File diff suppressed because it is too large
Load diff
464
src/EventTrace.h
Normal file
464
src/EventTrace.h
Normal file
|
@ -0,0 +1,464 @@
|
||||||
|
// Classes for tracing/dumping Zeek events.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "zeek/Val.h"
|
||||||
|
|
||||||
|
namespace zeek::detail
|
||||||
|
{
|
||||||
|
|
||||||
|
class ValTrace;
|
||||||
|
class ValTraceMgr;
|
||||||
|
|
||||||
|
// Abstract class for capturing a single difference between two script-level
|
||||||
|
// values. Includes notions of inserting, changing, or deleting a value.
|
||||||
|
class ValDelta
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ValDelta(const ValTrace* _vt) : vt(_vt) { }
|
||||||
|
virtual ~ValDelta() { }
|
||||||
|
|
||||||
|
// Return a string that performs the update operation, expressed
|
||||||
|
// as Zeek scripting. Does not include a terminating semicolon.
|
||||||
|
virtual std::string Generate(ValTraceMgr* vtm) const;
|
||||||
|
|
||||||
|
// Whether the generated string needs the affected value to
|
||||||
|
// explicitly appear on the left-hand-side. Note that this
|
||||||
|
// might not be as a simple "LHS = RHS" assignment, but instead
|
||||||
|
// as "LHS$field = RHS" or "LHS[index] = RHS".
|
||||||
|
//
|
||||||
|
// Returns false for generated strings like "delete LHS[index]".
|
||||||
|
virtual bool NeedsLHS() const { return true; }
|
||||||
|
|
||||||
|
const ValTrace* GetValTrace() const { return vt; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const ValTrace* vt;
|
||||||
|
};
|
||||||
|
|
||||||
|
using DeltaVector = std::vector<std::unique_ptr<ValDelta>>;
|
||||||
|
|
||||||
|
// Tracks the elements of a value as seen at a given point in execution.
|
||||||
|
// For non-aggregates, this is simply the Val object, but for aggregates
|
||||||
|
// it is (recursively) each of the sub-elements, in a manner that can then
|
||||||
|
// be readily compared against future instances.
|
||||||
|
class ValTrace
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ValTrace(const ValPtr& v);
|
||||||
|
~ValTrace();
|
||||||
|
|
||||||
|
const ValPtr& GetVal() const { return v; }
|
||||||
|
const TypePtr& GetType() const { return t; }
|
||||||
|
const auto& GetElems() const { return elems; }
|
||||||
|
|
||||||
|
// Returns true if this trace and the given one represent the
|
||||||
|
// same underlying value. Can involve subelement-by-subelement
|
||||||
|
// (recursive) comparisons.
|
||||||
|
bool operator==(const ValTrace& vt) const;
|
||||||
|
bool operator!=(const ValTrace& vt) const { return ! ((*this) == vt); }
|
||||||
|
|
||||||
|
// Computes the deltas between a previous ValTrace and this one.
|
||||||
|
// If "prev" is nil then we're creating this value from scratch
|
||||||
|
// (though if it's an aggregate, we may reuse existing values
|
||||||
|
// for some of its components).
|
||||||
|
//
|
||||||
|
// Returns the accumulated differences in "deltas". If on return
|
||||||
|
// nothing was added to "deltas" then the two ValTrace's are equivalent
|
||||||
|
// (no changes between them).
|
||||||
|
void ComputeDelta(const ValTrace* prev, DeltaVector& deltas) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Methods for tracing different types of aggregate values.
|
||||||
|
void TraceList(const ListValPtr& lv);
|
||||||
|
void TraceRecord(const RecordValPtr& rv);
|
||||||
|
void TraceTable(const TableValPtr& tv);
|
||||||
|
void TraceVector(const VectorValPtr& vv);
|
||||||
|
|
||||||
|
// Predicates for comparing different types of aggregates for equality.
|
||||||
|
bool SameList(const ValTrace& vt) const;
|
||||||
|
bool SameRecord(const ValTrace& vt) const;
|
||||||
|
bool SameTable(const ValTrace& vt) const;
|
||||||
|
bool SameVector(const ValTrace& vt) const;
|
||||||
|
|
||||||
|
// Helper function that knows about the internal vector-of-subelements
|
||||||
|
// we use for aggregates.
|
||||||
|
bool SameElems(const ValTrace& vt) const;
|
||||||
|
|
||||||
|
// True if this value is a singleton and it's the same value as
|
||||||
|
// represented in "vt".
|
||||||
|
bool SameSingleton(const ValTrace& vt) const;
|
||||||
|
|
||||||
|
// Add to "deltas" the differences needed to turn a previous instance
|
||||||
|
// of the given type of aggregate to the current instance.
|
||||||
|
void ComputeRecordDelta(const ValTrace* prev, DeltaVector& deltas) const;
|
||||||
|
void ComputeTableDelta(const ValTrace* prev, DeltaVector& deltas) const;
|
||||||
|
void ComputeVectorDelta(const ValTrace* prev, DeltaVector& deltas) const;
|
||||||
|
|
||||||
|
// Holds sub-elements for aggregates.
|
||||||
|
std::vector<std::shared_ptr<ValTrace>> elems;
|
||||||
|
|
||||||
|
// A parallel vector used for the yield values of tables.
|
||||||
|
std::vector<std::shared_ptr<ValTrace>> elems2;
|
||||||
|
|
||||||
|
ValPtr v;
|
||||||
|
TypePtr t; // v's type, for convenience
|
||||||
|
};
|
||||||
|
|
||||||
|
// Captures the basic notion of a new, non-equivalent value being assigned.
|
||||||
|
class DeltaReplaceValue : public ValDelta
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DeltaReplaceValue(const ValTrace* _vt, ValPtr _new_val)
|
||||||
|
: ValDelta(_vt), new_val(std::move(_new_val))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Generate(ValTraceMgr* vtm) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ValPtr new_val;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Captures the notion of setting a record field.
|
||||||
|
class DeltaSetField : public ValDelta
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DeltaSetField(const ValTrace* _vt, int _field, ValPtr _new_val)
|
||||||
|
: ValDelta(_vt), field(_field), new_val(std::move(_new_val))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Generate(ValTraceMgr* vtm) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int field;
|
||||||
|
ValPtr new_val;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Captures the notion of deleting a record field.
|
||||||
|
class DeltaRemoveField : public ValDelta
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DeltaRemoveField(const ValTrace* _vt, int _field) : ValDelta(_vt), field(_field) { }
|
||||||
|
|
||||||
|
std::string Generate(ValTraceMgr* vtm) const override;
|
||||||
|
bool NeedsLHS() const override { return false; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
int field;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Captures the notion of creating a record from scratch.
|
||||||
|
class DeltaRecordCreate : public ValDelta
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DeltaRecordCreate(const ValTrace* _vt) : ValDelta(_vt) { }
|
||||||
|
|
||||||
|
std::string Generate(ValTraceMgr* vtm) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Captures the notion of adding an element to a set. Use DeltaRemoveTableEntry to
|
||||||
|
// delete values.
|
||||||
|
class DeltaSetSetEntry : public ValDelta
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DeltaSetSetEntry(const ValTrace* _vt, ValPtr _index) : ValDelta(_vt), index(_index) { }
|
||||||
|
|
||||||
|
std::string Generate(ValTraceMgr* vtm) const override;
|
||||||
|
bool NeedsLHS() const override { return false; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
ValPtr index;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Captures the notion of setting a table entry (which includes both changing
|
||||||
|
// an existing one and adding a new one). Use DeltaRemoveTableEntry to
|
||||||
|
// delete values.
|
||||||
|
class DeltaSetTableEntry : public ValDelta
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DeltaSetTableEntry(const ValTrace* _vt, ValPtr _index, ValPtr _new_val)
|
||||||
|
: ValDelta(_vt), index(_index), new_val(std::move(_new_val))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Generate(ValTraceMgr* vtm) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ValPtr index;
|
||||||
|
ValPtr new_val;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Captures the notion of removing a table/set entry.
|
||||||
|
class DeltaRemoveTableEntry : public ValDelta
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DeltaRemoveTableEntry(const ValTrace* _vt, ValPtr _index)
|
||||||
|
: ValDelta(_vt), index(std::move(_index))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Generate(ValTraceMgr* vtm) const override;
|
||||||
|
bool NeedsLHS() const override { return false; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
ValPtr index;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Captures the notion of creating a set from scratch.
|
||||||
|
class DeltaSetCreate : public ValDelta
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DeltaSetCreate(const ValTrace* _vt) : ValDelta(_vt) { }
|
||||||
|
|
||||||
|
std::string Generate(ValTraceMgr* vtm) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Captures the notion of creating a table from scratch.
|
||||||
|
class DeltaTableCreate : public ValDelta
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DeltaTableCreate(const ValTrace* _vt) : ValDelta(_vt) { }
|
||||||
|
|
||||||
|
std::string Generate(ValTraceMgr* vtm) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Captures the notion of changing an element of a vector.
|
||||||
|
class DeltaVectorSet : public ValDelta
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DeltaVectorSet(const ValTrace* _vt, int _index, ValPtr _elem)
|
||||||
|
: ValDelta(_vt), index(_index), elem(std::move(_elem))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Generate(ValTraceMgr* vtm) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int index;
|
||||||
|
ValPtr elem;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Captures the notion of adding an entry to the end of a vector.
|
||||||
|
class DeltaVectorAppend : public ValDelta
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DeltaVectorAppend(const ValTrace* _vt, int _index, ValPtr _elem)
|
||||||
|
: ValDelta(_vt), index(_index), elem(std::move(_elem))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Generate(ValTraceMgr* vtm) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int index;
|
||||||
|
ValPtr elem;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Captures the notion of replacing a vector wholesale.
|
||||||
|
class DeltaVectorCreate : public ValDelta
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DeltaVectorCreate(const ValTrace* _vt) : ValDelta(_vt) { }
|
||||||
|
|
||||||
|
std::string Generate(ValTraceMgr* vtm) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
|
||||||
|
// Manages the changes to (or creation of) a variable used to represent
|
||||||
|
// a value.
|
||||||
|
class DeltaGen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DeltaGen(ValPtr _val, std::string _rhs, bool _needs_lhs, bool _is_first_def)
|
||||||
|
: val(std::move(_val)), rhs(std::move(_rhs)), needs_lhs(_needs_lhs),
|
||||||
|
is_first_def(_is_first_def)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const ValPtr& GetVal() const { return val; }
|
||||||
|
const std::string& RHS() const { return rhs; }
|
||||||
|
bool NeedsLHS() const { return needs_lhs; }
|
||||||
|
bool IsFirstDef() const { return is_first_def; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
ValPtr val;
|
||||||
|
|
||||||
|
// The expression to set the variable to.
|
||||||
|
std::string rhs;
|
||||||
|
|
||||||
|
// Whether that expression needs the variable explicitly provides
|
||||||
|
// on the lefthand side.
|
||||||
|
bool needs_lhs;
|
||||||
|
|
||||||
|
// Whether this is the first definition of the variable (in which
|
||||||
|
// case we also need to declare the variable).
|
||||||
|
bool is_first_def;
|
||||||
|
};
|
||||||
|
|
||||||
|
using DeltaGenVec = std::vector<DeltaGen>;
|
||||||
|
|
||||||
|
// Tracks a single event.
|
||||||
|
class EventTrace
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Constructed in terms of the associated script function, "network
|
||||||
|
// time" when the event occurred, and the position of this event
|
||||||
|
// within all of those being traced.
|
||||||
|
EventTrace(const ScriptFunc* _ev, double _nt, int event_num);
|
||||||
|
|
||||||
|
// Sets a string representation of the arguments (values) being
|
||||||
|
// passed to the event.
|
||||||
|
void SetArgs(std::string _args) { args = std::move(_args); }
|
||||||
|
|
||||||
|
// Adds to the trace an update for the given value.
|
||||||
|
void AddDelta(ValPtr val, std::string rhs, bool needs_lhs, bool is_first_def)
|
||||||
|
{
|
||||||
|
auto& d = is_post ? post_deltas : deltas;
|
||||||
|
d.emplace_back(DeltaGen(val, rhs, needs_lhs, is_first_def));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initially we analyze events pre-execution. When this flag
|
||||||
|
// is set, we switch to instead analyzing post-execution. The
|
||||||
|
// difference allows us to annotate the output with "# from script"
|
||||||
|
// comments that flag changes created by script execution rather
|
||||||
|
// than event engine activity.
|
||||||
|
void SetDoingPost() { is_post = true; }
|
||||||
|
|
||||||
|
const char* GetName() const { return name.c_str(); }
|
||||||
|
|
||||||
|
// Generates an internal event handler that sets up the values
|
||||||
|
// associated with the traced event, followed by queueing the traced
|
||||||
|
// event, and then queueing the successor internal event handler,
|
||||||
|
// if any.
|
||||||
|
//
|
||||||
|
// "predecessor", if non-nil, gives the event that came just before
|
||||||
|
// this one (used for "# from script" annotations"). "successor",
|
||||||
|
// if not empty, gives the name of the successor internal event.
|
||||||
|
void Generate(FILE* f, ValTraceMgr& vtm, const EventTrace* predecessor,
|
||||||
|
std::string successor) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// "dvec" is either just our deltas, or the "post_deltas" of our
|
||||||
|
// predecessor plus our deltas.
|
||||||
|
void Generate(FILE* f, ValTraceMgr& vtm, const DeltaGenVec& dvec, std::string successor,
|
||||||
|
int num_pre = 0) const;
|
||||||
|
|
||||||
|
const ScriptFunc* ev;
|
||||||
|
double nt;
|
||||||
|
bool is_post = false;
|
||||||
|
|
||||||
|
// The deltas needed to construct the values associated with this
|
||||||
|
// event prior to its execution.
|
||||||
|
DeltaGenVec deltas;
|
||||||
|
|
||||||
|
// The deltas capturing any changes to the original values as induced
|
||||||
|
// by executing its event handlers.
|
||||||
|
DeltaGenVec post_deltas;
|
||||||
|
|
||||||
|
// The event's name and a string representation of its arguments.
|
||||||
|
std::string name;
|
||||||
|
std::string args;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Manages all of the events and associated values seen during the execution.
|
||||||
|
class ValTraceMgr
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Invoked to trace a new event with the associated arguments.
|
||||||
|
void TraceEventValues(std::shared_ptr<EventTrace> et, const zeek::Args* args);
|
||||||
|
|
||||||
|
// Invoked when the current event finishes execution. The arguments
|
||||||
|
// are again provided, for convenience so we don't have to remember
|
||||||
|
// them from the previous method.
|
||||||
|
void FinishCurrentEvent(const zeek::Args* args);
|
||||||
|
|
||||||
|
// Returns the name of the script variable associated with the
|
||||||
|
// given value.
|
||||||
|
const std::string& ValName(const ValPtr& v);
|
||||||
|
const std::string& ValName(const ValTrace* vt) { return ValName(vt->GetVal()); }
|
||||||
|
|
||||||
|
// Returns true if the script variable associated with the given value
|
||||||
|
// needs to be global (because it's used across multiple events).
|
||||||
|
bool IsGlobal(const ValPtr& v) const { return globals.count(v.get()) > 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Traces the given value, which we may-or-may-not have seen before.
|
||||||
|
void AddVal(ValPtr v);
|
||||||
|
|
||||||
|
// Creates a new value, associating a script variable with it.
|
||||||
|
void NewVal(ValPtr v);
|
||||||
|
|
||||||
|
// Called when the given value is used in an expression that sets
|
||||||
|
// or updates another value. This lets us track which values are
|
||||||
|
// used across multiple events, and thus need to be global.
|
||||||
|
void ValUsed(const ValPtr& v);
|
||||||
|
|
||||||
|
// Compares the two value traces to build up deltas capturing
|
||||||
|
// the difference between the previous one and the current one.
|
||||||
|
void AssessChange(const ValTrace* vt, const ValTrace* prev_vt);
|
||||||
|
|
||||||
|
// Create and track a script variable associated with the given value.
|
||||||
|
void TrackVar(const Val* vt);
|
||||||
|
|
||||||
|
// Maps values to their associated traces.
|
||||||
|
std::unordered_map<const Val*, std::shared_ptr<ValTrace>> val_map;
|
||||||
|
|
||||||
|
// Maps values to the "names" we associated with them. For simple
|
||||||
|
// values, the name is just a Zeek script constant. For aggregates,
|
||||||
|
// it's a dedicated script variable.
|
||||||
|
std::unordered_map<const Val*, std::string> val_names;
|
||||||
|
int num_vars = 0; // the number of dedicated script variables
|
||||||
|
|
||||||
|
// Tracks which values we've processed up through the preceding event.
|
||||||
|
// Any re-use we then see for the current event (via a ValUsed() call)
|
||||||
|
// then tells us that the value is used across events, and thus its
|
||||||
|
// associated script variable needs to be global.
|
||||||
|
std::unordered_set<const Val*> processed_vals;
|
||||||
|
|
||||||
|
// Tracks which values have associated script variables that need
|
||||||
|
// to be global.
|
||||||
|
std::unordered_set<const Val*> globals;
|
||||||
|
|
||||||
|
// The event we're currently tracing.
|
||||||
|
std::shared_ptr<EventTrace> curr_ev;
|
||||||
|
|
||||||
|
// Hang on to values we're tracking to make sure the pointers don't
|
||||||
|
// get reused when the main use of the value ends.
|
||||||
|
std::vector<ValPtr> vals;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Manages tracing of all of the events seen during execution, including
|
||||||
|
// the final generation of the trace script.
|
||||||
|
class EventTraceMgr
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
EventTraceMgr(const std::string& trace_file);
|
||||||
|
~EventTraceMgr();
|
||||||
|
|
||||||
|
// Called at the beginning of invoking an event's handlers.
|
||||||
|
void StartEvent(const ScriptFunc* ev, const zeek::Args* args);
|
||||||
|
|
||||||
|
// Called after finishing with invoking an event's handlers.
|
||||||
|
void EndEvent(const ScriptFunc* ev, const zeek::Args* args);
|
||||||
|
|
||||||
|
// Used to track events generated at script-level.
|
||||||
|
void ScriptEventQueued(const EventHandlerPtr& h);
|
||||||
|
|
||||||
|
private:
|
||||||
|
FILE* f = nullptr;
|
||||||
|
ValTraceMgr vtm;
|
||||||
|
|
||||||
|
// All of the events we've traced so far.
|
||||||
|
std::vector<std::shared_ptr<EventTrace>> events;
|
||||||
|
|
||||||
|
// The names of all of the script events that have been generated.
|
||||||
|
std::unordered_set<std::string> script_events;
|
||||||
|
};
|
||||||
|
|
||||||
|
// If non-nil then we're doing event tracing.
|
||||||
|
extern std::unique_ptr<EventTraceMgr> etm;
|
||||||
|
|
||||||
|
} // namespace zeek::detail
|
15
src/Expr.cc
15
src/Expr.cc
|
@ -8,6 +8,7 @@
|
||||||
#include "zeek/Desc.h"
|
#include "zeek/Desc.h"
|
||||||
#include "zeek/Event.h"
|
#include "zeek/Event.h"
|
||||||
#include "zeek/EventRegistry.h"
|
#include "zeek/EventRegistry.h"
|
||||||
|
#include "zeek/EventTrace.h"
|
||||||
#include "zeek/Frame.h"
|
#include "zeek/Frame.h"
|
||||||
#include "zeek/Func.h"
|
#include "zeek/Func.h"
|
||||||
#include "zeek/Hash.h"
|
#include "zeek/Hash.h"
|
||||||
|
@ -4322,7 +4323,14 @@ ValPtr ScheduleExpr::Eval(Frame* f) const
|
||||||
auto args = eval_list(f, event->Args());
|
auto args = eval_list(f, event->Args());
|
||||||
|
|
||||||
if ( args )
|
if ( args )
|
||||||
timer_mgr->Add(new ScheduleTimer(event->Handler(), std::move(*args), dt));
|
{
|
||||||
|
auto handler = event->Handler();
|
||||||
|
|
||||||
|
if ( etm )
|
||||||
|
etm->ScriptEventQueued(handler);
|
||||||
|
|
||||||
|
timer_mgr->Add(new ScheduleTimer(handler, std::move(*args), dt));
|
||||||
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -4861,7 +4869,12 @@ ValPtr EventExpr::Eval(Frame* f) const
|
||||||
auto v = eval_list(f, args.get());
|
auto v = eval_list(f, args.get());
|
||||||
|
|
||||||
if ( handler )
|
if ( handler )
|
||||||
|
{
|
||||||
|
if ( etm )
|
||||||
|
etm->ScriptEventQueued(handler);
|
||||||
|
|
||||||
event_mgr.Enqueue(handler, std::move(*v));
|
event_mgr.Enqueue(handler, std::move(*v));
|
||||||
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include "zeek/Debug.h"
|
#include "zeek/Debug.h"
|
||||||
#include "zeek/Desc.h"
|
#include "zeek/Desc.h"
|
||||||
#include "zeek/Event.h"
|
#include "zeek/Event.h"
|
||||||
|
#include "zeek/EventTrace.h"
|
||||||
#include "zeek/Expr.h"
|
#include "zeek/Expr.h"
|
||||||
#include "zeek/File.h"
|
#include "zeek/File.h"
|
||||||
#include "zeek/Frame.h"
|
#include "zeek/Frame.h"
|
||||||
|
@ -401,6 +402,9 @@ ValPtr ScriptFunc::Invoke(zeek::Args* args, Frame* parent) const
|
||||||
const CallExpr* call_expr = parent ? parent->GetCall() : nullptr;
|
const CallExpr* call_expr = parent ? parent->GetCall() : nullptr;
|
||||||
call_stack.emplace_back(CallInfo{call_expr, this, *args});
|
call_stack.emplace_back(CallInfo{call_expr, this, *args});
|
||||||
|
|
||||||
|
if ( etm && Flavor() == FUNC_FLAVOR_EVENT )
|
||||||
|
etm->StartEvent(this, args);
|
||||||
|
|
||||||
if ( g_trace_state.DoTrace() )
|
if ( g_trace_state.DoTrace() )
|
||||||
{
|
{
|
||||||
ODesc d;
|
ODesc d;
|
||||||
|
@ -481,6 +485,9 @@ ValPtr ScriptFunc::Invoke(zeek::Args* args, Frame* parent) const
|
||||||
result = val_mgr->True();
|
result = val_mgr->True();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if ( etm && Flavor() == FUNC_FLAVOR_EVENT )
|
||||||
|
etm->EndEvent(this, args);
|
||||||
|
|
||||||
// Warn if the function returns something, but we returned from
|
// Warn if the function returns something, but we returned from
|
||||||
// the function without an explicit return, or without a value.
|
// the function without an explicit return, or without a value.
|
||||||
else if ( GetType()->Yield() && GetType()->Yield()->Tag() != TYPE_VOID &&
|
else if ( GetType()->Yield() && GetType()->Yield()->Tag() != TYPE_VOID &&
|
||||||
|
|
|
@ -114,6 +114,8 @@ void usage(const char* prog, int code)
|
||||||
#endif
|
#endif
|
||||||
fprintf(stderr, " -C|--no-checksums | ignore checksums\n");
|
fprintf(stderr, " -C|--no-checksums | ignore checksums\n");
|
||||||
fprintf(stderr, " -D|--deterministic | initialize random seeds to zero\n");
|
fprintf(stderr, " -D|--deterministic | initialize random seeds to zero\n");
|
||||||
|
fprintf(stderr, " -E|--event-trace <file> | generate a replayable event trace to "
|
||||||
|
"the given file\n");
|
||||||
fprintf(stderr, " -F|--force-dns | force DNS\n");
|
fprintf(stderr, " -F|--force-dns | force DNS\n");
|
||||||
fprintf(stderr, " -G|--load-seeds <file> | load seeds from given file\n");
|
fprintf(stderr, " -G|--load-seeds <file> | load seeds from given file\n");
|
||||||
fprintf(stderr, " -H|--save-seeds <file> | save seeds to given file\n");
|
fprintf(stderr, " -H|--save-seeds <file> | save seeds to given file\n");
|
||||||
|
@ -380,6 +382,7 @@ Options parse_cmdline(int argc, char** argv)
|
||||||
{"no-checksums", no_argument, nullptr, 'C'},
|
{"no-checksums", no_argument, nullptr, 'C'},
|
||||||
{"force-dns", no_argument, nullptr, 'F'},
|
{"force-dns", no_argument, nullptr, 'F'},
|
||||||
{"deterministic", no_argument, nullptr, 'D'},
|
{"deterministic", no_argument, nullptr, 'D'},
|
||||||
|
{"event-trace", required_argument, nullptr, 'E'},
|
||||||
{"load-seeds", required_argument, nullptr, 'G'},
|
{"load-seeds", required_argument, nullptr, 'G'},
|
||||||
{"save-seeds", required_argument, nullptr, 'H'},
|
{"save-seeds", required_argument, nullptr, 'H'},
|
||||||
{"print-plugins", no_argument, nullptr, 'N'},
|
{"print-plugins", no_argument, nullptr, 'N'},
|
||||||
|
@ -400,7 +403,7 @@ Options parse_cmdline(int argc, char** argv)
|
||||||
{"mem-profile", no_argument, nullptr, 'M'},
|
{"mem-profile", no_argument, nullptr, 'M'},
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
{"pseudo-realtime", optional_argument, nullptr, 'E'},
|
{"pseudo-realtime", optional_argument, nullptr, '~'},
|
||||||
{"jobs", optional_argument, nullptr, 'j'},
|
{"jobs", optional_argument, nullptr, 'j'},
|
||||||
{"test", no_argument, nullptr, '#'},
|
{"test", no_argument, nullptr, '#'},
|
||||||
|
|
||||||
|
@ -408,7 +411,7 @@ Options parse_cmdline(int argc, char** argv)
|
||||||
};
|
};
|
||||||
|
|
||||||
char opts[256];
|
char opts[256];
|
||||||
util::safe_strncpy(opts, "B:c:e:f:G:H:I:i:j::n:O:0:o:p:r:s:T:t:U:w:X:CDFMNPQSWabdhmuv",
|
util::safe_strncpy(opts, "B:c:E:e:f:G:H:I:i:j::n:O:0:o:p:r:s:T:t:U:w:X:CDFMNPQSWabdhmuv",
|
||||||
sizeof(opts));
|
sizeof(opts));
|
||||||
|
|
||||||
int op;
|
int op;
|
||||||
|
@ -523,9 +526,7 @@ Options parse_cmdline(int argc, char** argv)
|
||||||
rval.deterministic_mode = true;
|
rval.deterministic_mode = true;
|
||||||
break;
|
break;
|
||||||
case 'E':
|
case 'E':
|
||||||
rval.pseudo_realtime = 1.0;
|
rval.event_trace_file = optarg;
|
||||||
if ( optarg )
|
|
||||||
rval.pseudo_realtime = atof(optarg);
|
|
||||||
break;
|
break;
|
||||||
case 'F':
|
case 'F':
|
||||||
if ( rval.dns_mode != detail::DNS_DEFAULT )
|
if ( rval.dns_mode != detail::DNS_DEFAULT )
|
||||||
|
@ -586,6 +587,12 @@ Options parse_cmdline(int argc, char** argv)
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
case '~':
|
||||||
|
rval.pseudo_realtime = 1.0;
|
||||||
|
if ( optarg )
|
||||||
|
rval.pseudo_realtime = atof(optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
case '#':
|
case '#':
|
||||||
fprintf(stderr, "ERROR: --test only allowed as first argument.\n");
|
fprintf(stderr, "ERROR: --test only allowed as first argument.\n");
|
||||||
usage(zargs[0], 1);
|
usage(zargs[0], 1);
|
||||||
|
|
|
@ -73,6 +73,7 @@ struct Options
|
||||||
std::optional<std::string> process_status_file;
|
std::optional<std::string> process_status_file;
|
||||||
std::optional<std::string> zeekygen_config_file;
|
std::optional<std::string> zeekygen_config_file;
|
||||||
std::optional<std::string> unprocessed_output_file;
|
std::optional<std::string> unprocessed_output_file;
|
||||||
|
std::optional<std::string> event_trace_file;
|
||||||
|
|
||||||
std::set<std::string> plugins_to_load;
|
std::set<std::string> plugins_to_load;
|
||||||
std::vector<std::string> scripts_to_load;
|
std::vector<std::string> scripts_to_load;
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "zeek/Debug.h"
|
#include "zeek/Debug.h"
|
||||||
#include "zeek/Desc.h"
|
#include "zeek/Desc.h"
|
||||||
#include "zeek/Event.h"
|
#include "zeek/Event.h"
|
||||||
|
#include "zeek/EventTrace.h"
|
||||||
#include "zeek/Expr.h"
|
#include "zeek/Expr.h"
|
||||||
#include "zeek/File.h"
|
#include "zeek/File.h"
|
||||||
#include "zeek/Frame.h"
|
#include "zeek/Frame.h"
|
||||||
|
@ -1076,11 +1077,17 @@ EventStmt::EventStmt(EventExprPtr arg_e) : ExprStmt(STMT_EVENT, arg_e), event_ex
|
||||||
ValPtr EventStmt::Exec(Frame* f, StmtFlowType& flow)
|
ValPtr EventStmt::Exec(Frame* f, StmtFlowType& flow)
|
||||||
{
|
{
|
||||||
RegisterAccess();
|
RegisterAccess();
|
||||||
|
|
||||||
auto args = eval_list(f, event_expr->Args());
|
auto args = eval_list(f, event_expr->Args());
|
||||||
auto h = event_expr->Handler();
|
auto h = event_expr->Handler();
|
||||||
|
|
||||||
if ( args && h )
|
if ( args && h )
|
||||||
|
{
|
||||||
|
if ( etm )
|
||||||
|
etm->ScriptEventQueued(h);
|
||||||
|
|
||||||
event_mgr.Enqueue(h, std::move(*args));
|
event_mgr.Enqueue(h, std::move(*args));
|
||||||
|
}
|
||||||
|
|
||||||
flow = FLOW_NEXT;
|
flow = FLOW_NEXT;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
13
src/Val.h
13
src/Val.h
|
@ -47,6 +47,7 @@ class PrefixTable;
|
||||||
class CompositeHash;
|
class CompositeHash;
|
||||||
class HashKey;
|
class HashKey;
|
||||||
|
|
||||||
|
class ValTrace;
|
||||||
class ZBody;
|
class ZBody;
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
@ -1380,6 +1381,7 @@ public:
|
||||||
static void DoneParsing();
|
static void DoneParsing();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
friend class zeek::detail::ValTrace;
|
||||||
friend class zeek::detail::ZBody;
|
friend class zeek::detail::ZBody;
|
||||||
|
|
||||||
RecordValPtr DoCoerceTo(RecordTypePtr other, bool allow_orphaning) const;
|
RecordValPtr DoCoerceTo(RecordTypePtr other, bool allow_orphaning) const;
|
||||||
|
@ -1401,9 +1403,9 @@ protected:
|
||||||
record_val->emplace_back(std::nullopt);
|
record_val->emplace_back(std::nullopt);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For use by low-level ZAM instructions. Caller assumes
|
// For internal use by low-level ZAM instructions and event tracing.
|
||||||
// responsibility for memory management. The first version
|
// Caller assumes responsibility for memory management. The first
|
||||||
// allows manipulation of whether the field is present at all.
|
// version allows manipulation of whether the field is present at all.
|
||||||
// The second version ensures that the optional value is present.
|
// The second version ensures that the optional value is present.
|
||||||
std::optional<ZVal>& RawOptField(int field) { return (*record_val)[field]; }
|
std::optional<ZVal>& RawOptField(int field) { return (*record_val)[field]; }
|
||||||
|
|
||||||
|
@ -1614,10 +1616,13 @@ public:
|
||||||
}
|
}
|
||||||
const String* StringAt(unsigned int index) const { return StringValAt(index)->AsString(); }
|
const String* StringAt(unsigned int index) const { return StringValAt(index)->AsString(); }
|
||||||
|
|
||||||
// Only intended for low-level access by compiled code.
|
// Only intended for low-level access by internal or compiled code.
|
||||||
const auto& RawVec() const { return vector_val; }
|
const auto& RawVec() const { return vector_val; }
|
||||||
auto& RawVec() { return vector_val; }
|
auto& RawVec() { return vector_val; }
|
||||||
|
|
||||||
|
const auto& RawYieldType() const { return yield_type; }
|
||||||
|
const auto& RawYieldTypes() const { return yield_types; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* Returns the element at a given index or nullptr if it does not exist.
|
* Returns the element at a given index or nullptr if it does not exist.
|
||||||
|
|
|
@ -605,6 +605,8 @@ public:
|
||||||
* use this method to attach additional data to the connections. A
|
* use this method to attach additional data to the connections. A
|
||||||
* call to BuildConnVal() will in turn trigger a call to
|
* call to BuildConnVal() will in turn trigger a call to
|
||||||
* UpdateConnVal().
|
* UpdateConnVal().
|
||||||
|
* TODO: The above comment needs updating, there's no BuildConnVal()
|
||||||
|
* anymore -VP
|
||||||
*
|
*
|
||||||
* @param conn_val The connenction value being updated.
|
* @param conn_val The connenction value being updated.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "zeek/Desc.h"
|
#include "zeek/Desc.h"
|
||||||
#include "zeek/Event.h"
|
#include "zeek/Event.h"
|
||||||
#include "zeek/EventRegistry.h"
|
#include "zeek/EventRegistry.h"
|
||||||
|
#include "zeek/EventTrace.h"
|
||||||
#include "zeek/File.h"
|
#include "zeek/File.h"
|
||||||
#include "zeek/Frag.h"
|
#include "zeek/Frag.h"
|
||||||
#include "zeek/Frame.h"
|
#include "zeek/Frame.h"
|
||||||
|
@ -281,13 +282,13 @@ static void done_with_network()
|
||||||
ZEEK_LSAN_DISABLE();
|
ZEEK_LSAN_DISABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void terminate_bro()
|
static void terminate_zeek()
|
||||||
{
|
{
|
||||||
util::detail::set_processing_status("TERMINATING", "terminate_bro");
|
util::detail::set_processing_status("TERMINATING", "terminate_zeek");
|
||||||
|
|
||||||
run_state::terminating = true;
|
run_state::terminating = true;
|
||||||
|
|
||||||
iosource_mgr->Wakeup("terminate_bro");
|
iosource_mgr->Wakeup("terminate_zeek");
|
||||||
|
|
||||||
// File analysis termination may produce events, so do it early on in
|
// File analysis termination may produce events, so do it early on in
|
||||||
// the termination process.
|
// the termination process.
|
||||||
|
@ -299,8 +300,19 @@ static void terminate_bro()
|
||||||
event_mgr.Enqueue(zeek_done, Args{});
|
event_mgr.Enqueue(zeek_done, Args{});
|
||||||
|
|
||||||
timer_mgr->Expire();
|
timer_mgr->Expire();
|
||||||
|
|
||||||
|
// Drain() limits how many "generations" of newly created events
|
||||||
|
// it will process. When we're terminating, however, we're okay
|
||||||
|
// with long chains of events, and this makes the workings of
|
||||||
|
// event-tracing simpler.
|
||||||
|
//
|
||||||
|
// That said, we also need to ensure that it runs at least once,
|
||||||
|
// as it has side effects such as tickling triggers.
|
||||||
event_mgr.Drain();
|
event_mgr.Drain();
|
||||||
|
|
||||||
|
while ( event_mgr.HasEvents() )
|
||||||
|
event_mgr.Drain();
|
||||||
|
|
||||||
if ( profiling_logger )
|
if ( profiling_logger )
|
||||||
{
|
{
|
||||||
// FIXME: There are some occasional crashes in the memory
|
// FIXME: There are some occasional crashes in the memory
|
||||||
|
@ -658,6 +670,9 @@ SetupResult setup(int argc, char** argv, Options* zopts)
|
||||||
};
|
};
|
||||||
auto ipbb = make_intrusive<BuiltinFunc>(init_bifs, ipbid->Name(), false);
|
auto ipbb = make_intrusive<BuiltinFunc>(init_bifs, ipbid->Name(), false);
|
||||||
|
|
||||||
|
if ( options.event_trace_file )
|
||||||
|
etm = make_unique<EventTraceMgr>(*options.event_trace_file);
|
||||||
|
|
||||||
run_state::is_parsing = true;
|
run_state::is_parsing = true;
|
||||||
yyparse();
|
yyparse();
|
||||||
run_state::is_parsing = false;
|
run_state::is_parsing = false;
|
||||||
|
@ -943,7 +958,7 @@ int cleanup(bool did_run_loop)
|
||||||
done_with_network();
|
done_with_network();
|
||||||
|
|
||||||
run_state::detail::delete_run();
|
run_state::detail::delete_run();
|
||||||
terminate_bro();
|
terminate_zeek();
|
||||||
|
|
||||||
sqlite3_shutdown();
|
sqlite3_shutdown();
|
||||||
|
|
||||||
|
@ -974,7 +989,7 @@ void zeek_terminate_loop(const char* reason)
|
||||||
zeek::detail::done_with_network();
|
zeek::detail::done_with_network();
|
||||||
delete_run();
|
delete_run();
|
||||||
|
|
||||||
zeek::detail::terminate_bro();
|
zeek::detail::terminate_zeek();
|
||||||
|
|
||||||
// Close files after net_delete(), because net_delete()
|
// Close files after net_delete(), because net_delete()
|
||||||
// might write to connection content files.
|
// might write to connection content files.
|
||||||
|
|
18
src/zeek.bif
18
src/zeek.bif
|
@ -321,7 +321,7 @@ static int next_fmt(const char*& fmt, const zeek::Args* args, zeek::ODesc* d, in
|
||||||
##
|
##
|
||||||
## Returns: The wall-clock time.
|
## Returns: The wall-clock time.
|
||||||
##
|
##
|
||||||
## .. zeek:see:: network_time
|
## .. zeek:see:: network_time set_network_time
|
||||||
function current_time%(%): time
|
function current_time%(%): time
|
||||||
%{
|
%{
|
||||||
return zeek::make_intrusive<zeek::TimeVal>(zeek::util::current_time());
|
return zeek::make_intrusive<zeek::TimeVal>(zeek::util::current_time());
|
||||||
|
@ -333,12 +333,26 @@ function current_time%(%): time
|
||||||
##
|
##
|
||||||
## Returns: The timestamp of the packet processed.
|
## Returns: The timestamp of the packet processed.
|
||||||
##
|
##
|
||||||
## .. zeek:see:: current_time
|
## .. zeek:see:: current_time set_network_time
|
||||||
function network_time%(%): time
|
function network_time%(%): time
|
||||||
%{
|
%{
|
||||||
return zeek::make_intrusive<zeek::TimeVal>(zeek::run_state::network_time);
|
return zeek::make_intrusive<zeek::TimeVal>(zeek::run_state::network_time);
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
## Sets the timestamp associated with the last packet processed. Used for
|
||||||
|
## event replaying.
|
||||||
|
##
|
||||||
|
## nt: The time to which to set "network time".
|
||||||
|
##
|
||||||
|
## Returns: The timestamp of the packet processed.
|
||||||
|
##
|
||||||
|
## .. zeek:see:: current_time network_time
|
||||||
|
function set_network_time%(nt: time%): bool
|
||||||
|
%{
|
||||||
|
zeek::run_state::network_time = nt;
|
||||||
|
return zeek::val_mgr->True();
|
||||||
|
%}
|
||||||
|
|
||||||
## Returns a system environment variable.
|
## Returns a system environment variable.
|
||||||
##
|
##
|
||||||
## var: The name of the variable whose value to request.
|
## var: The name of the variable whose value to request.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue