Commit a4c1a0e8 a4c1a0e88bdeb8372ae66e27da4009a49b0f8009 by Sergey Poznyakoff

sieve: provide a separate stream for debugging output

* include/mailutils/sieve.h (MU_SIEVE_DEBUG_TRACE)
(MU_SIEVE_DEBUG_INSTR,MU_SIEVE_DEBUG_DISAS)
(MU_SIEVE_DRY_RUN): Remove.
(mu_sieve_machine_init_ex): Remove proto.
(mu_sieve_set_dbg_stream,mu_sieve_get_dbg_stream)
(mu_sieve_stream_save)
(mu_sieve_stream_restore): New protos.
* libmu_sieve/runtime.c (INSTR_DISASS,INSTR_DEBUG): Reimplement.
* libmu_sieve/sieve-priv.h (MU_SV_SAVED_ERR_STATE)
(MU_SV_SAVED_DBG_STATE,MU_SV_SAVED_STATE): New bitflags.
(mu_sieve_state_disass): New constant.
(mu_sieve_machine)<state_flags, err_mode>
<err_locus,dbg_mode,dbg_locus>: New members.
<dbgstream>: New member.
* libmu_sieve/sieve.y (mu_sieve_machine_init_ex): Remove.
(mu_sieve_machine_dup, mu_sieve_machine_inherit): Fix.
(mu_sieve_set_dbg_stream)
(mu_sieve_get_dbg_stream): New functions.
(mu_sieve_machine_destroy): Destroy dbgstream.
(with_machine): Preserve stream state (mode & locus).
* libmu_sieve/util.c (mu_i_sv_debug,mu_i_sv_debug_command): Use ioctl
instead of format strings.
(mu_sieve_stream_save, mu_sieve_stream_restore): New functions.
* python/libmu_py/sieve.c (api_sieve_machine_init): Use
mu_sieve_machine_init.
* sieve/sieve.c: Improve help output.
(main): Dump disassembled code to standard output.
1 parent d282d8e7
......@@ -116,12 +116,6 @@ typedef struct
#define MU_SIEVE_MATCH_EQ 5
#define MU_SIEVE_MATCH_LAST 6
/* Debugging levels */
#define MU_SIEVE_DEBUG_TRACE 0x0001
#define MU_SIEVE_DEBUG_INSTR 0x0002
#define MU_SIEVE_DEBUG_DISAS 0x0004
#define MU_SIEVE_DRY_RUN 0x0008
extern mu_debug_handle_t mu_sieve_debug_handle;
extern mu_list_t mu_sieve_include_path;
extern mu_list_t mu_sieve_library_path;
......@@ -212,9 +206,6 @@ int mu_sieve_vlist_compare (mu_sieve_value_t * a, mu_sieve_value_t * b,
/* Functions to create and destroy sieve machine */
int mu_sieve_machine_init (mu_sieve_machine_t *mach);
int mu_sieve_machine_init_ex (mu_sieve_machine_t *pmach,
void *data,
mu_stream_t errstream);
int mu_sieve_machine_dup (mu_sieve_machine_t const in,
mu_sieve_machine_t *out);
int mu_sieve_machine_inherit (mu_sieve_machine_t const in,
......@@ -227,6 +218,9 @@ int mu_sieve_machine_add_destructor (mu_sieve_machine_t mach,
void mu_sieve_get_diag_stream (mu_sieve_machine_t mach, mu_stream_t *pstr);
void mu_sieve_set_diag_stream (mu_sieve_machine_t mach, mu_stream_t str);
void mu_sieve_set_dbg_stream (mu_sieve_machine_t mach, mu_stream_t str);
void mu_sieve_get_dbg_stream (mu_sieve_machine_t mach, mu_stream_t *pstr);
void *mu_sieve_get_data (mu_sieve_machine_t mach);
void mu_sieve_set_data (mu_sieve_machine_t mach, void *);
mu_message_t mu_sieve_get_message (mu_sieve_machine_t mach);
......@@ -247,6 +241,10 @@ void mu_sieve_set_daemon_email (mu_sieve_machine_t mach, const char *email);
int mu_sieve_get_message_sender (mu_message_t msg, char **ptext);
/* Stream state saving & restoring */
void mu_sieve_stream_save (mu_sieve_machine_t mach);
void mu_sieve_stream_restore (mu_sieve_machine_t mach);
/* Logging and diagnostic functions */
void mu_sieve_error (mu_sieve_machine_t mach, const char *fmt, ...)
......
......@@ -27,10 +27,9 @@
#define SIEVE_ARG(m,n,t) ((m)->prog[(m)->pc+(n)].t)
#define SIEVE_ADJUST(m,n) (m)->pc+=(n)
#define INSTR_DISASS(m) ((m)->state == mu_sieve_state_disass)
#define INSTR_DEBUG(m) \
(mu_debug_level_p (mu_sieve_debug_handle, MU_DEBUG_TRACE9))
#define INSTR_DISASS(m) \
(mu_debug_level_p (mu_sieve_debug_handle, MU_DEBUG_TRACE8))
(INSTR_DISASS(m) || mu_debug_level_p (mu_sieve_debug_handle, MU_DEBUG_TRACE9))
void
_mu_i_sv_instr_source (mu_sieve_machine_t mach)
......@@ -83,7 +82,7 @@ _mu_i_sv_instr_action (mu_sieve_machine_t mach)
{
mach->identifier = SIEVE_ARG (mach, 3, string);
mach->action_count++;
instr_run (mach, "action");
instr_run (mach, "ACTION");
mach->identifier = NULL;
}
......@@ -91,7 +90,7 @@ void
_mu_i_sv_instr_test (mu_sieve_machine_t mach)
{
mach->identifier = SIEVE_ARG (mach, 3, string);
mach->reg = instr_run (mach, "test");
mach->reg = instr_run (mach, "TEST");
mach->identifier = NULL;
}
......@@ -99,11 +98,9 @@ void
_mu_i_sv_instr_push (mu_sieve_machine_t mach)
{
if (INSTR_DEBUG (mach))
{
mu_i_sv_debug (mach, mach->pc - 1, "PUSH");
if (INSTR_DISASS (mach))
return;
}
if (!mach->stack && mu_list_create (&mach->stack))
{
......@@ -117,11 +114,9 @@ void
_mu_i_sv_instr_pop (mu_sieve_machine_t mach)
{
if (INSTR_DEBUG (mach))
{
mu_i_sv_debug (mach, mach->pc - 1, "POP");
if (INSTR_DISASS (mach))
return;
}
if (!mach->stack || mu_list_is_empty (mach->stack))
{
......@@ -135,11 +130,9 @@ void
_mu_i_sv_instr_not (mu_sieve_machine_t mach)
{
if (INSTR_DEBUG (mach))
{
mu_i_sv_debug (mach, mach->pc - 1, "NOT");
if (INSTR_DISASS (mach))
return;
}
mach->reg = !mach->reg;
}
......@@ -150,12 +143,10 @@ _mu_i_sv_instr_branch (mu_sieve_machine_t mach)
SIEVE_ADJUST (mach, 1);
if (INSTR_DEBUG (mach))
{
mu_i_sv_debug (mach, mach->pc - 2, "BRANCH %lu",
(unsigned long)(mach->pc + num));
if (INSTR_DISASS (mach))
return;
}
mach->pc += num;
}
......@@ -167,12 +158,10 @@ _mu_i_sv_instr_brz (mu_sieve_machine_t mach)
SIEVE_ADJUST (mach, 1);
if (INSTR_DEBUG (mach))
{
mu_i_sv_debug (mach, mach->pc - 2, "BRZ %lu",
(unsigned long)(mach->pc + num));
if (INSTR_DISASS (mach))
return;
}
if (!mach->reg)
mach->pc += num;
......@@ -185,12 +174,10 @@ _mu_i_sv_instr_brnz (mu_sieve_machine_t mach)
SIEVE_ADJUST (mach, 1);
if (INSTR_DEBUG (mach))
{
mu_i_sv_debug (mach, mach->pc - 2, "BRNZ %lu",
(unsigned long)(mach->pc + num));
if (INSTR_DISASS (mach))
return;
}
if (mach->reg)
mach->pc += num;
......@@ -262,9 +249,13 @@ mu_sieve_set_dry_run (mu_sieve_machine_t mach, int val)
int
sieve_run (mu_sieve_machine_t mach)
{
if (setjmp (mach->errbuf))
return 1;
int rc;
mu_sieve_stream_save (mach);
rc = setjmp (mach->errbuf);
if (rc == 0)
{
mach->action_count = 0;
for (mach->pc = 1; mach->prog[mach->pc].handler; )
......@@ -275,22 +266,23 @@ sieve_run (mu_sieve_machine_t mach)
if (INSTR_DEBUG (mach))
mu_i_sv_debug (mach, mach->pc, "STOP");
}
return 0;
mu_sieve_stream_restore (mach);
return rc;
}
int
mu_sieve_disass (mu_sieve_machine_t mach)
{
mu_debug_level_t lev;
int rc;
mu_debug_get_category_level (mu_sieve_debug_handle, &lev);
mu_debug_set_category_level (mu_sieve_debug_handle,
MU_DEBUG_LEVEL_MASK(MU_DEBUG_TRACE8)
| MU_DEBUG_LEVEL_MASK(MU_DEBUG_TRACE9));
if (mach->state != mu_sieve_state_compiled)
return EINVAL; /* FIXME: Error code */
mach->state = mu_sieve_state_disass;
rc = sieve_run (mach);
mu_debug_set_category_level (mu_sieve_debug_handle, lev);
mach->state = mu_sieve_state_compiled;
return rc;
}
......
......@@ -45,12 +45,17 @@ struct mu_locus_range
#define YYLTYPE struct mu_locus_range
#define MU_SV_SAVED_ERR_STATE 0x01
#define MU_SV_SAVED_DBG_STATE 0x02
#define MU_SV_SAVED_STATE 0x80
enum mu_sieve_state
{
mu_sieve_state_init,
mu_sieve_state_error,
mu_sieve_state_compiled,
mu_sieve_state_running
mu_sieve_state_running,
mu_sieve_state_disass
};
struct mu_sieve_machine
......@@ -86,8 +91,16 @@ struct mu_sieve_machine
mu_message_t msg; /* Current message */
int action_count; /* Number of actions executed over this message */
/* Stream state info */
int state_flags;
int err_mode;
struct mu_locus err_locus;
int dbg_mode;
struct mu_locus dbg_locus;
/* User supplied data */
mu_stream_t errstream;
mu_stream_t dbgstream;
mu_sieve_action_log_t logger;
......
......@@ -994,8 +994,7 @@ mu_i_sv_error (mu_sieve_machine_t mach)
}
int
mu_sieve_machine_init_ex (mu_sieve_machine_t *pmach,
void *data, mu_stream_t errstream)
mu_sieve_machine_init (mu_sieve_machine_t *pmach)
{
int rc;
mu_sieve_machine_t mach;
......@@ -1022,33 +1021,46 @@ mu_sieve_machine_init_ex (mu_sieve_machine_t *pmach,
mach->source_list = NULL;
mach->data = data;
mach->errstream = errstream;
mu_stream_ref (errstream);
mach->data = NULL;
mu_sieve_set_diag_stream (mach, mu_strerr);
mu_sieve_set_dbg_stream (mach, mu_strerr);
*pmach = mach;
return 0;
}
int
mu_sieve_machine_init (mu_sieve_machine_t *pmach)
{
return mu_sieve_machine_init_ex (pmach, NULL, mu_strerr);
}
int
mu_sieve_machine_inherit (mu_sieve_machine_t const parent,
mu_sieve_machine_t *pmach)
{
mu_sieve_machine_t child;
int rc;
rc = mu_sieve_machine_init_ex (&child, parent->data, parent->errstream);
if (!parent || parent->state == mu_sieve_state_error)
return EINVAL;
rc = mu_sieve_machine_init (&child);
if (rc)
return rc;
child->logger = parent->logger;
child->dry_run = parent->dry_run;
child->state_flags = parent->state_flags;
child->err_mode = parent->err_mode;
child->err_locus = parent->err_locus;
child->dbg_mode = parent->dbg_mode;
child->dbg_locus = parent->dbg_locus;
child->errstream = parent->errstream;
mu_stream_ref (child->errstream);
child->dbgstream = parent->dbgstream;
mu_stream_ref (child->dbgstream);
child->data = parent->data;
child->logger = parent->logger;
child->daemon_email = parent->daemon_email;
*pmach = child;
return 0;
}
......@@ -1059,6 +1071,8 @@ mu_sieve_machine_dup (mu_sieve_machine_t const in, mu_sieve_machine_t *out)
int rc;
mu_sieve_machine_t mach;
if (!in || in->state == mu_sieve_state_error)
return EINVAL;
mach = malloc (sizeof (*mach));
if (!mach)
return ENOMEM;
......@@ -1077,15 +1091,33 @@ mu_sieve_machine_dup (mu_sieve_machine_t const in, mu_sieve_machine_t *out)
mach->progsize = in->progsize;
mach->prog = in->prog;
switch (in->state)
{
case mu_sieve_state_running:
case mu_sieve_state_disass:
mach->state = mu_sieve_state_compiled;
break;
default:
mach->state = in->state;
}
mach->pc = 0;
mach->reg = 0;
mach->stack = NULL;
mach->dry_run = in->dry_run;
mach->state_flags = in->state_flags;
mach->err_mode = in->err_mode;
mach->err_locus = in->err_locus;
mach->dbg_mode = in->dbg_mode;
mach->dbg_locus = in->dbg_locus;
mach->errstream = in->errstream;
mu_stream_ref (mach->errstream);
mach->dbgstream = in->dbgstream;
mu_stream_ref (mach->dbgstream);
mach->data = in->data;
mach->logger = in->logger;
......@@ -1111,6 +1143,21 @@ mu_sieve_set_diag_stream (mu_sieve_machine_t mach, mu_stream_t str)
}
void
mu_sieve_set_dbg_stream (mu_sieve_machine_t mach, mu_stream_t str)
{
mu_stream_unref (mach->dbgstream);
mach->dbgstream = str;
mu_stream_ref (mach->dbgstream);
}
void
mu_sieve_get_dbg_stream (mu_sieve_machine_t mach, mu_stream_t *pstr)
{
*pstr = mach->dbgstream;
mu_stream_ref (*pstr);
}
void
mu_sieve_set_logger (mu_sieve_machine_t mach, mu_sieve_action_log_t logger)
{
mach->logger = logger;
......@@ -1215,10 +1262,9 @@ void
mu_sieve_machine_destroy (mu_sieve_machine_t *pmach)
{
mu_sieve_machine_t mach = *pmach;
/* FIXME: Restore stream state (locus & mode) */
mu_stream_ioctl (mach->errstream, MU_IOCTL_LOGSTREAM,
MU_IOCTL_LOGSTREAM_SET_LOCUS, NULL);
mu_stream_destroy (&mach->errstream);
mu_stream_destroy (&mach->dbgstream);
mu_mailer_destroy (&mach->mailer);
mu_list_foreach (mach->destr_list, _run_destructor, NULL);
mu_list_destroy (&mach->destr_list);
......@@ -1232,37 +1278,26 @@ mu_sieve_machine_destroy (mu_sieve_machine_t *pmach)
*pmach = NULL;
}
static void
sieve_machine_begin (mu_sieve_machine_t mach, const char *file)
{
mu_i_sv_register_standard_actions (mach);
mu_i_sv_register_standard_tests (mach);
mu_i_sv_register_standard_comparators (mach);
mu_sieve_machine = mach;
}
static void
sieve_machine_finish (void)
{
//nothing
}
int
with_machine (mu_sieve_machine_t mach, char const *name,
int (*thunk) (void *), void *data)
{
int rc = 0;
mu_stream_t save_errstr = mu_strerr;
mu_stream_t save_errstr;
save_errstr = mu_strerr;
mu_stream_ref (save_errstr);
mu_strerr = mach->errstream;
mu_stream_ref (mu_strerr);
sieve_machine_begin (mach, name);
mu_i_sv_register_standard_actions (mach);
mu_i_sv_register_standard_tests (mach);
mu_i_sv_register_standard_comparators (mach);
mu_sieve_machine = mach;
mu_sieve_stream_save (mach);
rc = thunk (data);
sieve_machine_finish ();
mu_sieve_stream_restore (mach);
mu_stream_unref (save_errstr);
mu_strerr = save_errstr;
......
......@@ -267,17 +267,24 @@ mu_i_sv_debug (mu_sieve_machine_t mach, size_t pc, const char *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
mu_stream_printf (mach->errstream, "\033s<%d>", MU_LOG_DEBUG);
if (mach->state_flags & MU_SV_SAVED_DBG_STATE)
{
unsigned severity = MU_LOG_DEBUG;
mu_stream_ioctl (mach->dbgstream, MU_IOCTL_LOGSTREAM,
MU_IOCTL_LOGSTREAM_SET_SEVERITY, &severity);
if (mach->locus.mu_file)
mu_stream_printf (mach->errstream, "\033O<%d>\033f<%u>%s\033l<%u>",
MU_LOGMODE_LOCUS,
(unsigned) strlen (mach->locus.mu_file),
mach->locus.mu_file,
mach->locus.mu_line);
mu_stream_printf (mach->errstream, "%4zu: ", pc);
mu_stream_vprintf (mach->errstream, fmt, ap);
mu_stream_write (mach->errstream, "\n", 1, NULL);
{
int mode = mach->dbg_mode | MU_LOGMODE_LOCUS;
mu_stream_ioctl (mach->dbgstream, MU_IOCTL_LOGSTREAM,
MU_IOCTL_LOGSTREAM_SET_LOCUS, &mach->locus);
mu_stream_ioctl (mach->dbgstream, MU_IOCTL_LOGSTREAM,
MU_IOCTL_LOGSTREAM_SET_MODE, &mode);
}
}
va_start (ap, fmt);
mu_stream_printf (mach->dbgstream, "%4zu: ", pc);
mu_stream_vprintf (mach->dbgstream, fmt, ap);
mu_stream_write (mach->dbgstream, "\n", 1, NULL);
va_end (ap);
}
......@@ -287,18 +294,25 @@ mu_i_sv_debug_command (mu_sieve_machine_t mach,
char const *what,
mu_list_t taglist, mu_list_t arglist)
{
mu_stream_printf (mach->errstream, "\033s<%d>", MU_LOG_DEBUG);
if (mach->state_flags & MU_SV_SAVED_DBG_STATE)
{
unsigned severity = MU_LOG_DEBUG;
mu_stream_ioctl (mach->dbgstream, MU_IOCTL_LOGSTREAM,
MU_IOCTL_LOGSTREAM_SET_SEVERITY, &severity);
if (mach->locus.mu_file)
mu_stream_printf (mach->errstream, "\033O<%d>\033f<%u>%s\033l<%u>",
MU_LOGMODE_LOCUS,
(unsigned) strlen (mach->locus.mu_file),
mach->locus.mu_file,
mach->locus.mu_line);
mu_stream_printf (mach->errstream, "%4zu: %s: %s",
{
int mode = mach->dbg_mode | MU_LOGMODE_LOCUS;
mu_stream_ioctl (mach->dbgstream, MU_IOCTL_LOGSTREAM,
MU_IOCTL_LOGSTREAM_SET_LOCUS, &mach->locus);
mu_stream_ioctl (mach->dbgstream, MU_IOCTL_LOGSTREAM,
MU_IOCTL_LOGSTREAM_SET_MODE, &mode);
}
}
mu_stream_printf (mach->dbgstream, "%4zu: %s: %s",
pc, what, mach->identifier);
mu_i_sv_tagf (mach->errstream, taglist);
mu_i_sv_argf (mach->errstream, arglist);
mu_stream_write (mach->errstream, "\n", 1, NULL);
mu_i_sv_tagf (mach->dbgstream, taglist);
mu_i_sv_argf (mach->dbgstream, arglist);
mu_stream_write (mach->dbgstream, "\n", 1, NULL);
}
void
......@@ -452,3 +466,51 @@ mu_sieve_vlist_compare (mu_sieve_value_t *a, mu_sieve_value_t *b,
*count = d.count;
return rc;
}
void
mu_sieve_stream_save (mu_sieve_machine_t mach)
{
if (mach->state_flags & MU_SV_SAVED_STATE)
return;
if (mu_stream_ioctl (mach->errstream, MU_IOCTL_LOGSTREAM,
MU_IOCTL_LOGSTREAM_GET_MODE, &mach->err_mode) == 0
&& mu_stream_ioctl (mach->errstream, MU_IOCTL_LOGSTREAM,
MU_IOCTL_LOGSTREAM_SET_LOCUS, &mach->err_locus) == 0)
mach->state_flags |= MU_SV_SAVED_ERR_STATE;
if (mu_stream_ioctl (mach->dbgstream, MU_IOCTL_LOGSTREAM,
MU_IOCTL_LOGSTREAM_GET_MODE, &mach->dbg_mode) == 0
&& mu_stream_ioctl (mach->dbgstream, MU_IOCTL_LOGSTREAM,
MU_IOCTL_LOGSTREAM_SET_LOCUS, &mach->dbg_locus) == 0)
mach->state_flags |= MU_SV_SAVED_DBG_STATE;
mach->state_flags |= MU_SV_SAVED_STATE;
}
void
mu_sieve_stream_restore (mu_sieve_machine_t mach)
{
if (!(mach->state_flags & MU_SV_SAVED_STATE))
return;
if (mach->state_flags & MU_SV_SAVED_ERR_STATE)
{
mu_stream_ioctl (mach->errstream, MU_IOCTL_LOGSTREAM,
MU_IOCTL_LOGSTREAM_SET_MODE, &mach->err_mode);
mu_stream_ioctl (mach->errstream, MU_IOCTL_LOGSTREAM,
MU_IOCTL_LOGSTREAM_SET_LOCUS, &mach->err_locus);
}
if (mach->dbgstream != mach->errstream
&& (mach->state_flags & MU_SV_SAVED_DBG_STATE))
{
mu_stream_ioctl (mach->dbgstream, MU_IOCTL_LOGSTREAM,
MU_IOCTL_LOGSTREAM_SET_MODE, &mach->dbg_mode);
mu_stream_ioctl (mach->dbgstream, MU_IOCTL_LOGSTREAM,
MU_IOCTL_LOGSTREAM_SET_LOCUS, &mach->dbg_locus);
}
mach->state_flags = 0;
}
......
......@@ -5,3 +5,5 @@
PATH=@abs_builddir@:@abs_top_builddir@/mail:$top_srcdir:$srcdir:$PATH
testsuitedir=@abs_top_srcdir@/testsuite
MALLOC_CHECK_=2
export MALLOC_CHECK_
......
......@@ -107,7 +107,9 @@ api_sieve_machine_init (PyObject *self, PyObject *args)
if (status)
return _ro (PyInt_FromLong (status));
status = mu_sieve_machine_init_ex (&py_mach->mach, NULL, estr);
status = mu_sieve_machine_init (&py_mach->mach);
if (status == 0)
mu_sieve_set_diag_stream (py_mach->mach, estr);
mu_stream_unref (estr);
return _ro (PyInt_FromLong (status));
}
......
......@@ -247,12 +247,20 @@ static struct mu_cli_setup cli = {
N_("GNU sieve -- a mail filtering tool."),
"SCRIPT",
NULL,
N_("Debug flags:\n\
N_("Sieve-specific debug levels:\n\
\n\
trace1 - print parse tree before optimization\n\
trace2 - print parse tree after optimization\n\
trace3 - print parser traces\n\
trace4 - print tests and actions being executed\n\
trace9 - print each Sieve instruction being executed\n\
\n\
Compatibility debug flags:\n\
g - main parser traces\n\
T - mailutils traces (same as --debug-level=sieve.trace0-trace1)\n\
P - network protocols (same as --debug-level=sieve.=prot)\n\
t - sieve trace (MU_SIEVE_DEBUG_TRACE)\n\
i - sieve instructions trace (MU_SIEVE_DEBUG_INSTR)\n")
t - sieve trace (same as --debug-level=sieve.=trace4)\n\
i - sieve instructions trace (same as --debug-level=sieve.=trace9)\n")
};
static void
......@@ -440,7 +448,10 @@ main (int argc, char *argv[])
if (compile_only)
{
if (compile_only == 2)
{
mu_sieve_set_dbg_stream (mach, mu_strout);
mu_sieve_disass (mach);
}
return EX_OK;
}
......