diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2007-04-18 07:33:39 +0000 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2007-04-18 07:33:39 +0000 |
commit | 71d23052e4bbb16978a2c38e151d2cbf71320e9d (patch) | |
tree | 2022ce3e3ed8b5438ac2b9e0fcd97c88691806a0 | |
parent | 9a1ddf916e38a3ed89d8d306997efe008a3b95b6 (diff) | |
download | mailfromd-71d23052e4bbb16978a2c38e151d2cbf71320e9d.tar.gz mailfromd-71d23052e4bbb16978a2c38e151d2cbf71320e9d.tar.bz2 |
Implement stack traces
git-svn-id: file:///svnroot/mailfromd/trunk@1363 7a8a7f39-df28-0410-adc6-e0d955640f24
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | NEWS | 27 | ||||
-rw-r--r-- | src/bi_other.m4 | 6 | ||||
-rw-r--r-- | src/gram.y | 6 | ||||
-rw-r--r-- | src/mailfromd.h | 1 | ||||
-rw-r--r-- | src/main.c | 16 | ||||
-rw-r--r-- | src/prog.c | 50 |
7 files changed, 105 insertions, 5 deletions
@@ -1,5 +1,9 @@ 2007-04-18 Sergey Poznyakoff <gray@gnu.org.ua> + * src/gram.y (apply_deferred_init): Fix error messages + * src/mailfromd.h, src/prog.c, src/main.c, src/bi_other.m4, + NEWS: Implement stack traces. + * mflib/match_dnsbl.mf, mflib/heloarg_test.mf, mflib/valid_domain.mf, mflib/match_rhsbl.mf, mflib/spf.mf, mflib/match_cidr.mf, doc/mailfromd.texi: Use <> in #include @@ -1,4 +1,4 @@ -Mailfromd NEWS -- history of user-visible changes. 2007-04-16 +Mailfromd NEWS -- history of user-visible changes. 2007-04-18 Copyright (C) 2005, 2006, 2007 Sergey Poznyakoff See the end of file for copying conditions. @@ -82,6 +82,31 @@ to the logs, notifying of the new stack size, e.g.: You can use these messages to adjust your stack size configuration settings. +* Runtime stack traces + +New command line option --stack-trace enables dumping stack traces +on runtime errors. This might help localize the source of the error. +The trace looks like: + +mailfromd: RUNTIME ERROR near ../mflib/match_cidr.mf:30: invalid CIDR (boo%) +mailfromd: Stack trace: +mailfromd: 0077: test.mf:7: match_cidr +mailfromd: 0096: test.mf:13: bar +mailfromd: 0110: test.mf:18: foo +mailfromd: Stack trace finishes +mailfromd: Execution of the configuration program was not finished + +Each trace line describes one stack frame, the lines appear in the +order of most recently called to least recently called. Each frame +consists of: + +1. Value of program counter at the time of its execution +2. Source code location, if available +3. Name of the function called + +The same output can be obtained by calling function stack_trace() +in your filter program. + * connect handler Connect handler is implemented. diff --git a/src/bi_other.m4 b/src/bi_other.m4 index 5c7ed7d3..94e3e029 100644 --- a/src/bi_other.m4 +++ b/src/bi_other.m4 @@ -112,4 +112,10 @@ MF_DEFUN(cancel_program_trace, VOID, STRING name) } END +MF_DEFUN(stack_trace, VOID) +{ + runtime_stack_trace(env); +} +END + MF_INIT @@ -3470,13 +3470,13 @@ apply_deferred_init() for (p = deferred_decl; p; p = p->next) { struct variable *var = variable_lookup(p->name->text); if (!var) { - mu_error("<command line>: warning: no such variable %s", - p->name); + mu_error("<command line>: warning: no such variable: %s", + p->name->text); continue; } if (initialize_variable(var, &p->value, get_locus())) mu_error("error initialising variable %s: incompatible types", - p->name); + p->name->text); } } diff --git a/src/mailfromd.h b/src/mailfromd.h index c09f834b..23574182 100644 --- a/src/mailfromd.h +++ b/src/mailfromd.h @@ -275,6 +275,7 @@ extern int script_dump_xref; extern size_t lock_retry_count_option; extern time_t lock_retry_timeout_option; extern char *mailfromd_state_dir; +extern int stack_trace_option; /* Configuration file parser */ @@ -92,7 +92,7 @@ time_t lock_retry_timeout_option = 1; /* DBM-related options end */ int source_info_option; /* Debug messages include source locations */ - +int stack_trace_option; /* Print stack traces on runtime errors */ char *file_option; /* File name for DB management commands */ struct db_format *format_option; @@ -652,6 +652,12 @@ set_source_info(void *value) source_info_option = (int) value; } +void +set_stack_trace(void *value) +{ + stack_trace_option = (int) value; +} + static void set_lock_retry_count(void *value) { @@ -844,6 +850,7 @@ struct option_cache { { "ehlo", NULL, option_ehlo, set_ehlo }, { "debug", NULL, option_debug, set_debug }, { "source-info", NULL, option_boolean, set_source_info }, + { "stack-trace", NULL, option_boolean, set_stack_trace }, { "expire-interval", NULL, option_time, set_expire }, { "positive-expire-interval", NULL, option_time, set_positive_expire }, { "negative-expire-interval", NULL, option_time, set_negative_expire }, @@ -939,6 +946,7 @@ enum mailfromd_option { OPTION_PREDICT_NEXT, OPTION_SHOW_DEFAULTS, OPTION_SINGLE_PROCESS, + OPTION_STACK_TRACE, OPTION_SOURCE_INFO, OPTION_SYSLOG, OPTION_TIME_FORMAT, @@ -1085,6 +1093,8 @@ static struct argp_option options[] = { N_("Set the identifier used in syslog messages to STRING"), GRP+1 }, { "source-info", OPTION_SOURCE_INFO, NULL, 0, N_("Debug messages include source information"), GRP+1 }, + { "stack-trace", OPTION_STACK_TRACE, NULL, 0, + N_("Enable stack traces on runtime errors"), GRP+1 }, #undef GRP /*DEPRECATED OPTIONS*/ @@ -1347,6 +1357,10 @@ parse_opt (int key, char *arg, struct argp_state *state) single_process_option = 1; break; + case OPTION_STACK_TRACE: + set_option("stack-trace", "yes", 1); + break; + case OPTION_SOURCE_INFO: set_option("source-info", "yes", 1); break; @@ -358,6 +358,54 @@ prog_trace(eval_environ_t env, const char *fmt, ...) buf); } +void instr_funcall(eval_environ_t env); +void instr_locus(eval_environ_t env); + +void +runtime_stack_trace(eval_environ_t env) +{ + size_t base; + + mu_error("Stack trace:"); + for (base = env->base; base < datasize + env->stack_size - 4; + base = (size_t) env->dataseg[base + 1] + base + 1) { + int i; + prog_counter_t pc = (prog_counter_t)env->dataseg[base + 2] - 1; + char *name; + struct locus *ploc = NULL, loc; + + if (prog[pc-2] == instr_funcall) { + name = (char*)(env->dataseg + (size_t) prog[pc-1]); + pc -= 2; + } else { + name = "(in catch)"; + pc -= 3; + } + + for (i = 0; i < 10; i++) { + if (pc > i + 3 + && prog[pc - i - 3] == instr_locus) { + loc.file = (char*)(env->dataseg + + (size_t) prog[pc - i - 2]); + loc.line = (size_t) prog[pc - i - 1]; + ploc = &loc; + break; + } + } + + if (ploc) + mu_error("%04d: %s:%lu: %s", + (unsigned long) pc, + ploc->file, (unsigned long) ploc->line, + name); + else + mu_error("%04d: %s", + (unsigned long) pc, + name); + } + mu_error("Stack trace finishes"); +} + void runtime_warning(eval_environ_t env, const char *fmt, ...) { @@ -386,6 +434,8 @@ runtime_error(eval_environ_t env, const char *fmt, ...) vsnprintf(buf + n, sizeof buf - n, fmt, ap); va_end(ap); mu_error(buf); + if (stack_trace_option) + runtime_stack_trace(env); env->status = SMFIS_TEMPFAIL; /* FIXME */ longjmp(env->x_jmp, 1); } |