mirror of
https://github.com/zeek/zeek.git
synced 2025-10-14 12:38:20 +00:00
Merge remote-tracking branch 'origin/topic/timw/4553-combine-call-stacks'
Some checks are pending
pre-commit / pre-commit (push) Waiting to run
Some checks are pending
pre-commit / pre-commit (push) Waiting to run
* origin/topic/timw/4553-combine-call-stacks: Replace g_frame_stack with call_stack used by ScriptProfiler Clean up initialization in Func.h
This commit is contained in:
commit
5227e7ebb9
13 changed files with 135 additions and 116 deletions
18
CHANGES
18
CHANGES
|
@ -1,3 +1,21 @@
|
||||||
|
8.1.0-dev.676 | 2025-10-13 09:54:47 -0700
|
||||||
|
|
||||||
|
* Replace g_frame_stack with call_stack used by ScriptProfiler (Tim Wojtulewicz, Corelight)
|
||||||
|
|
||||||
|
* Clean up initialization in Func.h (Tim Wojtulewicz, Corelight)
|
||||||
|
|
||||||
|
* Bump spicy-format (Benjamin Bannier, Corelight)
|
||||||
|
|
||||||
|
This brings in two changes:
|
||||||
|
|
||||||
|
- proper indention for blocks starting with multiple comments
|
||||||
|
- switch the hook from `language: rust` to `language: python` to avoid
|
||||||
|
nonsense due to pre-commit ignore Rust lock files,
|
||||||
|
https://github.com/pre-commit/pre-commit/issues/3162.
|
||||||
|
|
||||||
|
The second one should help avoid future instances of the hook randomly
|
||||||
|
breaking as its dependencies accidentially break semver.
|
||||||
|
|
||||||
8.1.0-dev.671 | 2025-10-11 12:38:21 +0200
|
8.1.0-dev.671 | 2025-10-11 12:38:21 +0200
|
||||||
|
|
||||||
* ZValElement: s to o renaming (Arne Welzel, Corelight)
|
* ZValElement: s to o renaming (Arne Welzel, Corelight)
|
||||||
|
|
8
NEWS
8
NEWS
|
@ -26,6 +26,14 @@ Breaking Changes
|
||||||
to live in the ``auxil`` directory, after having moved there from an external plugin.
|
to live in the ``auxil`` directory, after having moved there from an external plugin.
|
||||||
It is now built as part of main Zeek build whenever building on Linux.
|
It is now built as part of main Zeek build whenever building on Linux.
|
||||||
|
|
||||||
|
- The global ``g_frame_stack`` C++ variable was removed. This variable was used to track
|
||||||
|
the current stack of script-function frames, mostly for the built-in script debugger. We
|
||||||
|
realized that we were also tracking this information in the global ``call_stack``
|
||||||
|
variable, used by the script profiler. These two have now been combined together into
|
||||||
|
``call_stack``. Plugins using ``g_frame_stack`` will need to be adapted to use the other
|
||||||
|
variable. We opted to not use a deprecation cycle for this due to the complication with
|
||||||
|
managing the data across both variables.
|
||||||
|
|
||||||
New Functionality
|
New Functionality
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
||||||
8.1.0-dev.671
|
8.1.0-dev.676
|
||||||
|
|
|
@ -303,17 +303,16 @@ void DbgBreakpoint::PrintHitMsg() {
|
||||||
case BP_FUNC:
|
case BP_FUNC:
|
||||||
case BP_LINE: {
|
case BP_LINE: {
|
||||||
ODesc d;
|
ODesc d;
|
||||||
Frame* f = g_frame_stack.back();
|
const auto& f = call_stack.back().frame;
|
||||||
const ScriptFunc* func = f->GetFunction();
|
|
||||||
|
|
||||||
if ( func )
|
if ( const Func* func = f->GetFunction() )
|
||||||
func->DescribeDebug(&d, f->GetFuncArgs());
|
func->DescribeDebug(&d, f->GetFuncArgs());
|
||||||
|
|
||||||
const Location* loc = at_stmt->GetLocationInfo();
|
const Location* loc = at_stmt->GetLocationInfo();
|
||||||
|
|
||||||
debug_msg("Breakpoint %d, %s at %s:%d\n", GetID(), d.Description(), loc->FileName(), loc->FirstLine());
|
debug_msg("Breakpoint %d, %s at %s:%d\n", GetID(), d.Description(), loc->FileName(), loc->FirstLine());
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
case BP_TIME: assert(false);
|
case BP_TIME: assert(false);
|
||||||
|
|
||||||
|
|
49
src/Debug.cc
49
src/Debug.cc
|
@ -143,15 +143,13 @@ int TraceState::LogTrace(const char* fmt, ...) {
|
||||||
const Stmt* stmt;
|
const Stmt* stmt;
|
||||||
Location loc;
|
Location loc;
|
||||||
|
|
||||||
if ( g_frame_stack.size() > 0 && g_frame_stack.back() ) {
|
if ( ! call_stack.empty() ) {
|
||||||
stmt = g_frame_stack.back()->GetNextStmt();
|
const auto& frame = call_stack.back().frame;
|
||||||
|
stmt = frame->GetNextStmt();
|
||||||
if ( stmt )
|
if ( stmt )
|
||||||
loc = *stmt->GetLocationInfo();
|
loc = *stmt->GetLocationInfo();
|
||||||
else {
|
else if ( const Func* f = frame->GetFunction() )
|
||||||
const ScriptFunc* f = g_frame_stack.back()->GetFunction();
|
loc = *f->GetLocationInfo();
|
||||||
if ( f )
|
|
||||||
loc = *f->GetLocationInfo();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ! loc.FileName() ) {
|
if ( ! loc.FileName() ) {
|
||||||
|
@ -163,7 +161,7 @@ int TraceState::LogTrace(const char* fmt, ...) {
|
||||||
fprintf(trace_file, "%s:%d", loc.FileName(), loc.LastLine());
|
fprintf(trace_file, "%s:%d", loc.FileName(), loc.LastLine());
|
||||||
|
|
||||||
// Each stack frame is indented.
|
// Each stack frame is indented.
|
||||||
for ( int i = 0; i < int(g_frame_stack.size()); ++i )
|
for ( const auto& call : call_stack )
|
||||||
fprintf(trace_file, "\t");
|
fprintf(trace_file, "\t");
|
||||||
|
|
||||||
retval = vfprintf(trace_file, fmt, args);
|
retval = vfprintf(trace_file, fmt, args);
|
||||||
|
@ -589,16 +587,18 @@ static int dbg_dispatch_cmd(DebugCmd cmd_code, const vector<string>& args) {
|
||||||
|
|
||||||
case dcQuit: debug_msg("Program Terminating\n"); exit(0);
|
case dcQuit: debug_msg("Program Terminating\n"); exit(0);
|
||||||
|
|
||||||
case dcNext:
|
case dcNext: {
|
||||||
g_frame_stack.back()->BreakBeforeNextStmt(true);
|
Frame* frame = call_stack.back().frame;
|
||||||
|
frame->BreakBeforeNextStmt(true);
|
||||||
step_or_next_pending = true;
|
step_or_next_pending = true;
|
||||||
last_frame = g_frame_stack.back();
|
last_frame = frame;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case dcStep:
|
case dcStep:
|
||||||
g_debugger_state.BreakBeforeNextStmt(true);
|
g_debugger_state.BreakBeforeNextStmt(true);
|
||||||
step_or_next_pending = true;
|
step_or_next_pending = true;
|
||||||
last_frame = g_frame_stack.back();
|
last_frame = call_stack.back().frame;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case dcContinue:
|
case dcContinue:
|
||||||
|
@ -607,7 +607,7 @@ static int dbg_dispatch_cmd(DebugCmd cmd_code, const vector<string>& args) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case dcFinish:
|
case dcFinish:
|
||||||
g_frame_stack.back()->BreakOnReturn(true);
|
call_stack.back().frame->BreakOnReturn(true);
|
||||||
g_debugger_state.BreakBeforeNextStmt(false);
|
g_debugger_state.BreakBeforeNextStmt(false);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -663,7 +663,7 @@ static char* get_prompt(bool reset_counter = false) {
|
||||||
|
|
||||||
string get_context_description(const Stmt* stmt, const Frame* frame) {
|
string get_context_description(const Stmt* stmt, const Frame* frame) {
|
||||||
ODesc d;
|
ODesc d;
|
||||||
const ScriptFunc* func = frame ? frame->GetFunction() : nullptr;
|
const Func* func = frame ? frame->GetFunction() : nullptr;
|
||||||
|
|
||||||
if ( func )
|
if ( func )
|
||||||
func->DescribeDebug(&d, frame->GetFuncArgs());
|
func->DescribeDebug(&d, frame->GetFuncArgs());
|
||||||
|
@ -698,9 +698,8 @@ int dbg_handle_debug_input() {
|
||||||
g_debugger_state.BreakFromSignal(false);
|
g_debugger_state.BreakFromSignal(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Frame* curr_frame = g_frame_stack.back();
|
auto curr_frame = call_stack.back().frame;
|
||||||
const ScriptFunc* func = curr_frame->GetFunction();
|
if ( const Func* func = curr_frame->GetFunction() )
|
||||||
if ( func )
|
|
||||||
current_module = extract_module_name(func->GetName().c_str());
|
current_module = extract_module_name(func->GetName().c_str());
|
||||||
else
|
else
|
||||||
current_module = GLOBAL_MODULE_NAME;
|
current_module = GLOBAL_MODULE_NAME;
|
||||||
|
@ -711,8 +710,8 @@ int dbg_handle_debug_input() {
|
||||||
|
|
||||||
const Location loc = *stmt->GetLocationInfo();
|
const Location loc = *stmt->GetLocationInfo();
|
||||||
|
|
||||||
if ( ! step_or_next_pending || g_frame_stack.back() != last_frame ) {
|
if ( ! step_or_next_pending || call_stack.back().frame != last_frame ) {
|
||||||
string context = get_context_description(stmt, g_frame_stack.back());
|
string context = get_context_description(stmt, call_stack.back().frame);
|
||||||
debug_msg("%s\n", context.c_str());
|
debug_msg("%s\n", context.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -848,16 +847,16 @@ ValPtr dbg_eval_expr(const char* expr) {
|
||||||
// Push the current frame's associated scope.
|
// Push the current frame's associated scope.
|
||||||
// Note: g_debugger_state.curr_frame_idx is the user-visible number,
|
// Note: g_debugger_state.curr_frame_idx is the user-visible number,
|
||||||
// while the array index goes in the opposite direction
|
// while the array index goes in the opposite direction
|
||||||
int frame_idx = (g_frame_stack.size() - 1) - g_debugger_state.curr_frame_idx;
|
int frame_idx = (call_stack.size() - 1) - g_debugger_state.curr_frame_idx;
|
||||||
|
|
||||||
if ( ! (frame_idx >= 0 && (unsigned)frame_idx < g_frame_stack.size()) )
|
if ( ! (frame_idx >= 0 && static_cast<size_t>(frame_idx) < call_stack.size()) )
|
||||||
reporter->InternalError("Assertion failed: frame_idx >= 0 && (unsigned) frame_idx < g_frame_stack.size()");
|
reporter->InternalError("Assertion failed: frame_idx >= 0 && (unsigned) frame_idx < call_stack.size()");
|
||||||
|
|
||||||
Frame* frame = g_frame_stack[frame_idx];
|
const auto& frame = call_stack[frame_idx].frame;
|
||||||
if ( ! (frame) )
|
if ( ! frame )
|
||||||
reporter->InternalError("Assertion failed: frame");
|
reporter->InternalError("Assertion failed: frame");
|
||||||
|
|
||||||
const ScriptFunc* func = frame->GetFunction();
|
const Func* func = frame->GetFunction();
|
||||||
if ( func )
|
if ( func )
|
||||||
push_existing_scope(func->GetScope());
|
push_existing_scope(func->GetScope());
|
||||||
|
|
||||||
|
|
|
@ -173,7 +173,7 @@ int find_all_matching_cmds(const string& prefix, const char* array_of_matches[])
|
||||||
|
|
||||||
// Start, end bounds of which frame numbers to print
|
// Start, end bounds of which frame numbers to print
|
||||||
static int dbg_backtrace_internal(int start, int end) {
|
static int dbg_backtrace_internal(int start, int end) {
|
||||||
if ( start < 0 || end < 0 || (unsigned)start >= g_frame_stack.size() || (unsigned)end >= g_frame_stack.size() )
|
if ( start < 0 || end < 0 || (unsigned)start >= call_stack.size() || (unsigned)end >= call_stack.size() )
|
||||||
reporter->InternalError("Invalid stack frame index in DbgBacktraceInternal\n");
|
reporter->InternalError("Invalid stack frame index in DbgBacktraceInternal\n");
|
||||||
|
|
||||||
if ( start < end ) {
|
if ( start < end ) {
|
||||||
|
@ -183,11 +183,11 @@ static int dbg_backtrace_internal(int start, int end) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( int i = start; i >= end; --i ) {
|
for ( int i = start; i >= end; --i ) {
|
||||||
const Frame* f = g_frame_stack[i];
|
const auto& f = call_stack[i].frame;
|
||||||
const Stmt* stmt = f ? f->GetNextStmt() : nullptr;
|
const Stmt* stmt = f ? f->GetNextStmt() : nullptr;
|
||||||
|
|
||||||
string context = get_context_description(stmt, f);
|
string context = get_context_description(stmt, f);
|
||||||
debug_msg("#%d %s\n", int(g_frame_stack.size() - 1 - i), context.c_str());
|
debug_msg("#%d %s\n", int(call_stack.size() - 1 - i), context.c_str());
|
||||||
};
|
};
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -196,7 +196,7 @@ static int dbg_backtrace_internal(int start, int end) {
|
||||||
// Returns 0 for illegal arguments, or 1 on success.
|
// Returns 0 for illegal arguments, or 1 on success.
|
||||||
int dbg_cmd_backtrace(DebugCmd cmd, const vector<string>& args) {
|
int dbg_cmd_backtrace(DebugCmd cmd, const vector<string>& args) {
|
||||||
assert(cmd == dcBacktrace);
|
assert(cmd == dcBacktrace);
|
||||||
assert(g_frame_stack.size() > 0);
|
assert(! call_stack.empty());
|
||||||
|
|
||||||
unsigned int start_iter;
|
unsigned int start_iter;
|
||||||
int end_iter;
|
int end_iter;
|
||||||
|
@ -210,20 +210,20 @@ int dbg_cmd_backtrace(DebugCmd cmd, const vector<string>& args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( how_many > 0 ) { // innermost N frames
|
if ( how_many > 0 ) { // innermost N frames
|
||||||
start_iter = g_frame_stack.size() - 1;
|
start_iter = call_stack.size() - 1;
|
||||||
end_iter = start_iter - how_many + 1;
|
end_iter = start_iter - how_many + 1;
|
||||||
if ( end_iter < 0 )
|
if ( end_iter < 0 )
|
||||||
end_iter = 0;
|
end_iter = 0;
|
||||||
}
|
}
|
||||||
else { // outermost N frames
|
else { // outermost N frames
|
||||||
start_iter = how_many - 1;
|
start_iter = how_many - 1;
|
||||||
if ( start_iter + 1 > g_frame_stack.size() )
|
if ( start_iter + 1 > call_stack.size() )
|
||||||
start_iter = g_frame_stack.size() - 1;
|
start_iter = call_stack.size() - 1;
|
||||||
end_iter = 0;
|
end_iter = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
start_iter = g_frame_stack.size() - 1;
|
start_iter = call_stack.size() - 1;
|
||||||
end_iter = 0;
|
end_iter = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,7 +248,7 @@ int dbg_cmd_frame(DebugCmd cmd, const vector<string>& args) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( idx < 0 || (unsigned int)idx >= g_frame_stack.size() ) {
|
if ( idx < 0 || (unsigned int)idx >= call_stack.size() ) {
|
||||||
debug_msg("No frame %d", idx);
|
debug_msg("No frame %d", idx);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -267,7 +267,7 @@ int dbg_cmd_frame(DebugCmd cmd, const vector<string>& args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
else if ( cmd == dcUp ) {
|
else if ( cmd == dcUp ) {
|
||||||
if ( (unsigned int)(g_debugger_state.curr_frame_idx + 1) == g_frame_stack.size() ) {
|
if ( (unsigned int)(g_debugger_state.curr_frame_idx + 1) == call_stack.size() ) {
|
||||||
debug_msg("Outermost frame already selected\n");
|
debug_msg("Outermost frame already selected\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -275,11 +275,11 @@ int dbg_cmd_frame(DebugCmd cmd, const vector<string>& args) {
|
||||||
++g_debugger_state.curr_frame_idx;
|
++g_debugger_state.curr_frame_idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
int user_frame_number = g_frame_stack.size() - 1 - g_debugger_state.curr_frame_idx;
|
int user_frame_number = call_stack.size() - 1 - g_debugger_state.curr_frame_idx;
|
||||||
|
|
||||||
// Set the current location to the new frame being looked at
|
// Set the current location to the new frame being looked at
|
||||||
// for 'list', 'break', etc.
|
// for 'list', 'break', etc.
|
||||||
const Stmt* stmt = g_frame_stack[user_frame_number]->GetNextStmt();
|
const Stmt* stmt = call_stack[user_frame_number].frame->GetNextStmt();
|
||||||
if ( ! stmt )
|
if ( ! stmt )
|
||||||
reporter->InternalError("Assertion failed: stmt is null");
|
reporter->InternalError("Assertion failed: stmt is null");
|
||||||
|
|
||||||
|
@ -310,9 +310,9 @@ int dbg_cmd_break(DebugCmd cmd, const vector<string>& args) {
|
||||||
int cond_index = -1; // at which argument pos. does bp condition start?
|
int cond_index = -1; // at which argument pos. does bp condition start?
|
||||||
|
|
||||||
if ( args.empty() || args[0] == "if" ) { // break on next stmt
|
if ( args.empty() || args[0] == "if" ) { // break on next stmt
|
||||||
int user_frame_number = g_frame_stack.size() - 1 - g_debugger_state.curr_frame_idx;
|
int user_frame_number = call_stack.size() - 1 - g_debugger_state.curr_frame_idx;
|
||||||
|
|
||||||
Stmt* stmt = g_frame_stack[user_frame_number]->GetNextStmt();
|
Stmt* stmt = call_stack[user_frame_number].frame->GetNextStmt();
|
||||||
if ( ! stmt )
|
if ( ! stmt )
|
||||||
reporter->InternalError("Assertion failed: stmt is null");
|
reporter->InternalError("Assertion failed: stmt is null");
|
||||||
|
|
||||||
|
|
22
src/Frame.cc
22
src/Frame.cc
|
@ -11,31 +11,25 @@
|
||||||
#include "zeek/Val.h"
|
#include "zeek/Val.h"
|
||||||
#include "zeek/broker/Data.h"
|
#include "zeek/broker/Data.h"
|
||||||
|
|
||||||
std::vector<zeek::detail::Frame*> g_frame_stack;
|
|
||||||
|
|
||||||
namespace zeek::detail {
|
namespace zeek::detail {
|
||||||
|
|
||||||
Frame::Frame(int arg_size, const ScriptFunc* func, const zeek::Args* fn_args) {
|
Frame::Frame(int arg_size, const Func* func, const zeek::Args* fn_args) {
|
||||||
size = arg_size;
|
size = arg_size;
|
||||||
frame = std::make_unique<Element[]>(size);
|
if ( size > 0 )
|
||||||
|
frame = std::make_unique<Element[]>(size);
|
||||||
function = func;
|
function = func;
|
||||||
func_args = fn_args;
|
func_args = fn_args;
|
||||||
|
|
||||||
next_stmt = nullptr;
|
|
||||||
break_before_next_stmt = false;
|
|
||||||
break_on_return = false;
|
|
||||||
|
|
||||||
call = nullptr;
|
|
||||||
delayed = false;
|
|
||||||
|
|
||||||
// We could Ref()/Unref() the captures frame, but there's really
|
// We could Ref()/Unref() the captures frame, but there's really
|
||||||
// no need because by definition this current frame exists to
|
// no need because by definition this current frame exists to
|
||||||
// enable execution of the function, and its captures frame won't
|
// enable execution of the function, and its captures frame won't
|
||||||
// go away until the function itself goes away, which can only be
|
// go away until the function itself goes away, which can only be
|
||||||
// after this frame does.
|
// after this frame does.
|
||||||
captures = function ? function->GetCapturesFrame() : nullptr;
|
if ( function && function->GetKind() == Func::SCRIPT_FUNC ) {
|
||||||
captures_offset_map = function ? function->GetCapturesOffsetMap() : nullptr;
|
auto* sf = static_cast<const ScriptFunc*>(function);
|
||||||
current_offset = 0;
|
captures = sf->GetCapturesFrame();
|
||||||
|
captures_offset_map = sf->GetCapturesOffsetMap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Frame::SetElement(int n, ValPtr v) {
|
void Frame::SetElement(int n, ValPtr v) {
|
||||||
|
|
28
src/Frame.h
28
src/Frame.h
|
@ -20,11 +20,11 @@ using ValPtr = IntrusivePtr<Val>;
|
||||||
|
|
||||||
class BrokerListView;
|
class BrokerListView;
|
||||||
class BrokerData;
|
class BrokerData;
|
||||||
|
class Func;
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
class CallExpr;
|
class CallExpr;
|
||||||
class ScriptFunc;
|
|
||||||
using IDPtr = IntrusivePtr<ID>;
|
using IDPtr = IntrusivePtr<ID>;
|
||||||
|
|
||||||
namespace trigger {
|
namespace trigger {
|
||||||
|
@ -47,7 +47,7 @@ public:
|
||||||
* @param func the function that is creating this frame
|
* @param func the function that is creating this frame
|
||||||
* @param fn_args the arguments being passed to that function.
|
* @param fn_args the arguments being passed to that function.
|
||||||
*/
|
*/
|
||||||
Frame(int size, const ScriptFunc* func, const zeek::Args* fn_args);
|
Frame(int size, const Func* func, const zeek::Args* fn_args);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the size of the frame.
|
* Returns the size of the frame.
|
||||||
|
@ -117,7 +117,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* @return the function that the frame is associated with.
|
* @return the function that the frame is associated with.
|
||||||
*/
|
*/
|
||||||
const ScriptFunc* GetFunction() const { return function; }
|
const Func* GetFunction() const { return function; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the arguments passed to the function that this frame
|
* @return the arguments passed to the function that this frame
|
||||||
|
@ -130,7 +130,7 @@ public:
|
||||||
*
|
*
|
||||||
* @param func the function for the frame to be associated with.
|
* @param func the function for the frame to be associated with.
|
||||||
*/
|
*/
|
||||||
void SetFunction(ScriptFunc* func) { function = func; }
|
void SetFunction(Func* func) { function = func; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the next statement to be executed in the context of the frame.
|
* Sets the next statement to be executed in the context of the frame.
|
||||||
|
@ -216,9 +216,9 @@ private:
|
||||||
/** The number of vals that can be stored in this frame. */
|
/** The number of vals that can be stored in this frame. */
|
||||||
int size;
|
int size;
|
||||||
|
|
||||||
bool break_before_next_stmt;
|
bool break_before_next_stmt = false;
|
||||||
bool break_on_return;
|
bool break_on_return = false;
|
||||||
bool delayed;
|
bool delayed = false;
|
||||||
|
|
||||||
/** Associates ID's offsets with values. */
|
/** Associates ID's offsets with values. */
|
||||||
std::unique_ptr<Element[]> frame;
|
std::unique_ptr<Element[]> frame;
|
||||||
|
@ -228,25 +228,25 @@ private:
|
||||||
* This is how we support inlined functions without having to
|
* This is how we support inlined functions without having to
|
||||||
* alter the offsets associated with their local variables.
|
* alter the offsets associated with their local variables.
|
||||||
*/
|
*/
|
||||||
int current_offset;
|
int current_offset = 0;
|
||||||
|
|
||||||
/** Frame used for lambda/when captures. */
|
/** Frame used for lambda/when captures. */
|
||||||
Frame* captures;
|
Frame* captures = nullptr;
|
||||||
|
|
||||||
/** Maps IDs to offsets into the "captures" frame. If the ID
|
/** Maps IDs to offsets into the "captures" frame. If the ID
|
||||||
* isn't present, then it's not a capture.
|
* isn't present, then it's not a capture.
|
||||||
*/
|
*/
|
||||||
const OffsetMap* captures_offset_map;
|
const OffsetMap* captures_offset_map = nullptr;
|
||||||
|
|
||||||
/** The function this frame is associated with. */
|
/** The function this frame is associated with. */
|
||||||
const ScriptFunc* function;
|
const Func* function = nullptr;
|
||||||
|
|
||||||
// The following is only needed for the debugger.
|
// The following is only needed for the debugger.
|
||||||
/** The arguments to the function that this Frame is associated with. */
|
/** The arguments to the function that this Frame is associated with. */
|
||||||
const zeek::Args* func_args;
|
const zeek::Args* func_args = nullptr;
|
||||||
|
|
||||||
/** The next statement to be evaluated in the context of this frame. */
|
/** The next statement to be evaluated in the context of this frame. */
|
||||||
Stmt* next_stmt;
|
Stmt* next_stmt = nullptr;
|
||||||
|
|
||||||
trigger::TriggerPtr trigger;
|
trigger::TriggerPtr trigger;
|
||||||
const CallExpr* call = nullptr;
|
const CallExpr* call = nullptr;
|
||||||
|
@ -266,4 +266,4 @@ private:
|
||||||
* DebugFrame which provides the information that the debugger uses. See:
|
* DebugFrame which provides the information that the debugger uses. See:
|
||||||
* https://stackoverflow.com/a/16211097
|
* https://stackoverflow.com/a/16211097
|
||||||
*/
|
*/
|
||||||
extern std::vector<zeek::detail::Frame*> g_frame_stack;
|
// extern std::vector<zeek::detail::Frame*> g_frame_stack;
|
||||||
|
|
59
src/Func.cc
59
src/Func.cc
|
@ -93,10 +93,11 @@ std::string render_call_stack() {
|
||||||
if ( lvl > 0 )
|
if ( lvl > 0 )
|
||||||
rval += " | ";
|
rval += " | ";
|
||||||
|
|
||||||
const auto& name = ci.func->GetName();
|
const auto& name = ci.frame->GetFunction()->GetName();
|
||||||
std::string arg_desc;
|
std::string arg_desc;
|
||||||
|
|
||||||
for ( const auto& arg : ci.args ) {
|
const auto& args = ci.frame->GetFuncArgs();
|
||||||
|
for ( const auto& arg : *args ) {
|
||||||
ODesc d;
|
ODesc d;
|
||||||
d.SetShort();
|
d.SetShort();
|
||||||
arg->Describe(&d);
|
arg->Describe(&d);
|
||||||
|
@ -331,17 +332,16 @@ ValPtr ScriptFunc::Invoke(zeek::Args* args, Frame* parent) const {
|
||||||
return Flavor() == FUNC_FLAVOR_HOOK ? val_mgr->True() : nullptr;
|
return Flavor() == FUNC_FLAVOR_HOOK ? val_mgr->True() : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto f = make_intrusive<Frame>(frame_size, this, args);
|
Frame f{static_cast<int>(frame_size), this, args};
|
||||||
|
|
||||||
// Hand down any trigger.
|
// Hand down any trigger.
|
||||||
if ( parent ) {
|
if ( parent ) {
|
||||||
f->SetTrigger({NewRef{}, parent->GetTrigger()});
|
f.SetTrigger({NewRef{}, parent->GetTrigger()});
|
||||||
f->SetTriggerAssoc(parent->GetTriggerAssoc());
|
f.SetTriggerAssoc(parent->GetTriggerAssoc());
|
||||||
}
|
}
|
||||||
|
|
||||||
g_frame_stack.push_back(f.get()); // used for backtracing
|
|
||||||
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(call_expr, &f);
|
||||||
|
|
||||||
// If a script function is ever invoked with more arguments than it has
|
// If a script function is ever invoked with more arguments than it has
|
||||||
// parameters log an error and return. Most likely a "variadic function"
|
// parameters log an error and return. Most likely a "variadic function"
|
||||||
|
@ -374,24 +374,23 @@ ValPtr ScriptFunc::Invoke(zeek::Args* args, Frame* parent) const {
|
||||||
for ( auto j = 0u; j < args->size(); ++j ) {
|
for ( auto j = 0u; j < args->size(); ++j ) {
|
||||||
const auto& arg = (*args)[j];
|
const auto& arg = (*args)[j];
|
||||||
|
|
||||||
if ( f->GetElement(j) != arg )
|
if ( f.GetElement(j) != arg )
|
||||||
// Either not yet set, or somebody reassigned the frame slot.
|
// Either not yet set, or somebody reassigned the frame slot.
|
||||||
f->SetElement(j, arg);
|
f.SetElement(j, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( spm )
|
if ( spm )
|
||||||
spm->StartInvocation(this, body.stmts);
|
spm->StartInvocation(this, body.stmts);
|
||||||
|
|
||||||
f->Reset(args->size());
|
f.Reset(args->size());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
result = body.stmts->Exec(f.get(), flow);
|
result = body.stmts->Exec(&f, flow);
|
||||||
}
|
}
|
||||||
|
|
||||||
catch ( InterpreterException& e ) {
|
catch ( InterpreterException& e ) {
|
||||||
// Already reported, but now determine whether to unwind further.
|
// Already reported, but now determine whether to unwind further.
|
||||||
if ( Flavor() == FUNC_FLAVOR_FUNCTION ) {
|
if ( Flavor() == FUNC_FLAVOR_FUNCTION ) {
|
||||||
g_frame_stack.pop_back();
|
|
||||||
call_stack.pop_back();
|
call_stack.pop_back();
|
||||||
// Result not set b/c exception was thrown
|
// Result not set b/c exception was thrown
|
||||||
throw;
|
throw;
|
||||||
|
@ -404,7 +403,7 @@ ValPtr ScriptFunc::Invoke(zeek::Args* args, Frame* parent) const {
|
||||||
if ( spm )
|
if ( spm )
|
||||||
spm->EndInvocation();
|
spm->EndInvocation();
|
||||||
|
|
||||||
if ( f->HasDelayed() ) {
|
if ( f.HasDelayed() ) {
|
||||||
assert(! result);
|
assert(! result);
|
||||||
assert(parent);
|
assert(parent);
|
||||||
parent->SetDelayed();
|
parent->SetDelayed();
|
||||||
|
@ -424,8 +423,6 @@ ValPtr ScriptFunc::Invoke(zeek::Args* args, Frame* parent) const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
call_stack.pop_back();
|
|
||||||
|
|
||||||
if ( Flavor() == FUNC_FLAVOR_HOOK ) {
|
if ( Flavor() == FUNC_FLAVOR_HOOK ) {
|
||||||
if ( ! result )
|
if ( ! result )
|
||||||
result = val_mgr->True();
|
result = val_mgr->True();
|
||||||
|
@ -438,7 +435,7 @@ ValPtr ScriptFunc::Invoke(zeek::Args* args, Frame* parent) const {
|
||||||
// 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 && ! GetType()->ExpressionlessReturnOkay() &&
|
else if ( GetType()->Yield() && GetType()->Yield()->Tag() != TYPE_VOID && ! GetType()->ExpressionlessReturnOkay() &&
|
||||||
(flow != FLOW_RETURN /* we fell off the end */ || ! result /* explicit return with no result */) &&
|
(flow != FLOW_RETURN /* we fell off the end */ || ! result /* explicit return with no result */) &&
|
||||||
! f->HasDelayed() )
|
! f.HasDelayed() )
|
||||||
reporter->Warning("non-void function returning without a value: %s", GetName().c_str());
|
reporter->Warning("non-void function returning without a value: %s", GetName().c_str());
|
||||||
|
|
||||||
if ( result && g_trace_state.DoTrace() ) {
|
if ( result && g_trace_state.DoTrace() ) {
|
||||||
|
@ -448,7 +445,7 @@ ValPtr ScriptFunc::Invoke(zeek::Args* args, Frame* parent) const {
|
||||||
g_trace_state.LogTrace("Function return: %s\n", d.Description());
|
g_trace_state.LogTrace("Function return: %s\n", d.Description());
|
||||||
}
|
}
|
||||||
|
|
||||||
g_frame_stack.pop_back();
|
call_stack.pop_back();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -733,8 +730,10 @@ ValPtr BuiltinFunc::Invoke(Args* args, Frame* parent) const {
|
||||||
g_trace_state.LogTrace("\tBuiltin Function called: %s\n", d.Description());
|
g_trace_state.LogTrace("\tBuiltin Function called: %s\n", d.Description());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Frame f{0, this, args};
|
||||||
|
|
||||||
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(call_expr, &f);
|
||||||
auto result = func(parent, args);
|
auto result = func(parent, args);
|
||||||
call_stack.pop_back();
|
call_stack.pop_back();
|
||||||
|
|
||||||
|
@ -937,15 +936,15 @@ zeek::VectorValPtr get_current_script_backtrace() {
|
||||||
auto cs_copy = zeek::detail::call_stack;
|
auto cs_copy = zeek::detail::call_stack;
|
||||||
|
|
||||||
for ( const auto& ci : std::ranges::reverse_view(cs_copy) ) {
|
for ( const auto& ci : std::ranges::reverse_view(cs_copy) ) {
|
||||||
if ( ! ci.func )
|
if ( ! ci.frame->GetFunction() )
|
||||||
// This happens for compiled code.
|
// This happens for compiled code and BIFs.
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const auto& params = ci.func->GetType()->Params();
|
const auto& params = ci.frame->GetFunction()->GetType()->Params();
|
||||||
auto args = MakeCallArgumentVector(ci.args, params);
|
auto args = MakeCallArgumentVector(*ci.frame->GetFuncArgs(), params);
|
||||||
|
|
||||||
auto elem =
|
auto elem = make_backtrace_element(ci.frame->GetFunction()->GetName(), std::move(args),
|
||||||
make_backtrace_element(ci.func->GetName(), std::move(args), ci.call ? ci.call->GetLocationInfo() : nullptr);
|
ci.call ? ci.call->GetLocationInfo() : nullptr);
|
||||||
rval->Append(std::move(elem));
|
rval->Append(std::move(elem));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -990,7 +989,7 @@ static void emit_builtin_error_common(const char* msg, Obj* arg, bool unwind) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto last_call = call_stack.back();
|
const auto& last_call = call_stack.back();
|
||||||
|
|
||||||
if ( call_stack.size() < 2 ) {
|
if ( call_stack.size() < 2 ) {
|
||||||
// Don't need to check for wrapper function like "<module>::__<func>"
|
// Don't need to check for wrapper function like "<module>::__<func>"
|
||||||
|
@ -998,10 +997,13 @@ static void emit_builtin_error_common(const char* msg, Obj* arg, bool unwind) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( ! last_call.frame->GetFunction() )
|
||||||
|
return;
|
||||||
|
|
||||||
auto starts_with_double_underscore = [](const std::string& name) -> bool {
|
auto starts_with_double_underscore = [](const std::string& name) -> bool {
|
||||||
return name.size() > 2 && name[0] == '_' && name[1] == '_';
|
return name.size() > 2 && name[0] == '_' && name[1] == '_';
|
||||||
};
|
};
|
||||||
const std::string& last_func = last_call.func->GetName();
|
const std::string& last_func = last_call.frame->GetFunction()->GetName();
|
||||||
|
|
||||||
auto pos = last_func.find_first_of("::");
|
auto pos = last_func.find_first_of("::");
|
||||||
std::string wrapper_func;
|
std::string wrapper_func;
|
||||||
|
@ -1027,7 +1029,10 @@ static void emit_builtin_error_common(const char* msg, Obj* arg, bool unwind) {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto parent_call = call_stack[call_stack.size() - 2];
|
auto parent_call = call_stack[call_stack.size() - 2];
|
||||||
const auto& parent_func = parent_call.func->GetName();
|
|
||||||
|
std::string parent_func;
|
||||||
|
if ( const auto* pcf = parent_call.frame->GetFunction() )
|
||||||
|
parent_func = pcf->GetName();
|
||||||
|
|
||||||
if ( wrapper_func == parent_func )
|
if ( wrapper_func == parent_func )
|
||||||
emit(parent_call.call);
|
emit(parent_call.call);
|
||||||
|
|
15
src/Func.h
15
src/Func.h
|
@ -339,21 +339,16 @@ public:
|
||||||
void Describe(ODesc* d) const override;
|
void Describe(ODesc* d) const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
BuiltinFunc() {
|
BuiltinFunc() = default;
|
||||||
func = nullptr;
|
built_in_func func = nullptr;
|
||||||
is_pure = false;
|
bool is_pure = false;
|
||||||
}
|
|
||||||
|
|
||||||
built_in_func func;
|
|
||||||
bool is_pure;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern bool check_built_in_call(BuiltinFunc* f, CallExpr* call);
|
extern bool check_built_in_call(BuiltinFunc* f, CallExpr* call);
|
||||||
|
|
||||||
struct CallInfo {
|
struct CallInfo {
|
||||||
const CallExpr* call;
|
const CallExpr* call = nullptr;
|
||||||
const Func* func;
|
Frame* frame = nullptr;
|
||||||
const zeek::Args& args;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Class that collects all the specifics defining a Func.
|
// Class that collects all the specifics defining a Func.
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#include "zeek/Desc.h"
|
#include "zeek/Desc.h"
|
||||||
#include "zeek/Expr.h"
|
#include "zeek/Expr.h"
|
||||||
|
#include "zeek/Frame.h"
|
||||||
#include "zeek/Func.h"
|
#include "zeek/Func.h"
|
||||||
#include "zeek/IntrusivePtr.h"
|
#include "zeek/IntrusivePtr.h"
|
||||||
#include "zeek/Reporter.h"
|
#include "zeek/Reporter.h"
|
||||||
|
@ -136,7 +137,7 @@ std::string_view determine_script_location() {
|
||||||
|
|
||||||
ssize_t sidx = static_cast<ssize_t>(zeek::detail::call_stack.size()) - 1;
|
ssize_t sidx = static_cast<ssize_t>(zeek::detail::call_stack.size()) - 1;
|
||||||
while ( sidx >= 0 ) {
|
while ( sidx >= 0 ) {
|
||||||
const auto* func = zeek::detail::call_stack[sidx].func;
|
const auto* func = zeek::detail::call_stack[sidx].frame->GetFunction();
|
||||||
const auto* ce = zeek::detail::call_stack[sidx].call;
|
const auto* ce = zeek::detail::call_stack[sidx].call;
|
||||||
|
|
||||||
// Cached?
|
// Cached?
|
||||||
|
|
|
@ -41,12 +41,12 @@ eval auto& v = $$;
|
||||||
|
|
||||||
internal-op Load-Capture
|
internal-op Load-Capture
|
||||||
class Vi
|
class Vi
|
||||||
eval $$ = Z_FRAME->GetFunction()->GetCapturesVec()[$1];
|
eval $$ = static_cast<const ScriptFunc*>(Z_FRAME->GetFunction())->GetCapturesVec()[$1];
|
||||||
|
|
||||||
internal-op Load-Managed-Capture
|
internal-op Load-Managed-Capture
|
||||||
class Vi
|
class Vi
|
||||||
eval auto& lhs = $$;
|
eval auto& lhs = $$;
|
||||||
auto& rhs = Z_FRAME->GetFunction()->GetCapturesVec()[$1];
|
auto& rhs = static_cast<const ScriptFunc*>(Z_FRAME->GetFunction())->GetCapturesVec()[$1];
|
||||||
zeek::Ref(rhs.ManagedVal());
|
zeek::Ref(rhs.ManagedVal());
|
||||||
ZVal::DeleteManagedType(lhs);
|
ZVal::DeleteManagedType(lhs);
|
||||||
lhs = rhs;
|
lhs = rhs;
|
||||||
|
@ -62,12 +62,12 @@ eval GlobalID($1)->SetVal(GlobalVal($1).ToVal(Z_TYPE));
|
||||||
internal-op Store-Capture
|
internal-op Store-Capture
|
||||||
op1-read
|
op1-read
|
||||||
class Vi
|
class Vi
|
||||||
eval Z_FRAME->GetFunction()->GetCapturesVec()[$2] = $1;
|
eval static_cast<const ScriptFunc*>(Z_FRAME->GetFunction())->GetCapturesVec()[$2] = $1;
|
||||||
|
|
||||||
internal-op Store-Managed-Capture
|
internal-op Store-Managed-Capture
|
||||||
op1-read
|
op1-read
|
||||||
class Vi
|
class Vi
|
||||||
eval auto& lhs = Z_FRAME->GetFunction()->GetCapturesVec()[$2];
|
eval auto& lhs = static_cast<const ScriptFunc*>(Z_FRAME->GetFunction())->GetCapturesVec()[$2];
|
||||||
auto& rhs = $1;
|
auto& rhs = $1;
|
||||||
zeek::Ref(rhs.ManagedVal());
|
zeek::Ref(rhs.ManagedVal());
|
||||||
ZVal::DeleteManagedType(lhs);
|
ZVal::DeleteManagedType(lhs);
|
||||||
|
|
|
@ -1054,7 +1054,7 @@ SetupResult setup(int argc, char** argv, Options* zopts) {
|
||||||
auto [body, scope] = get_global_stmts();
|
auto [body, scope] = get_global_stmts();
|
||||||
StmtFlowType flow;
|
StmtFlowType flow;
|
||||||
Frame f(scope->Length(), nullptr, nullptr);
|
Frame f(scope->Length(), nullptr, nullptr);
|
||||||
g_frame_stack.push_back(&f);
|
call_stack.emplace_back(nullptr, &f);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
body->Exec(&f, flow);
|
body->Exec(&f, flow);
|
||||||
|
@ -1062,7 +1062,7 @@ SetupResult setup(int argc, char** argv, Options* zopts) {
|
||||||
reporter->FatalError("failed to execute script statements at top-level scope");
|
reporter->FatalError("failed to execute script statements at top-level scope");
|
||||||
}
|
}
|
||||||
|
|
||||||
g_frame_stack.pop_back();
|
call_stack.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
clear_script_analysis();
|
clear_script_analysis();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue