List:Commits« Previous MessageNext Message »
From:Sergei Golubchik Date:October 30 2009 7:14pm
Subject:bzr commit into mysql-5.5-next-mr branch (serg:2909)
View as plain text  
#At file:///usr/home/serg/Abk/mysql/next-mr/ based on revid:holyfoot@stripped

 2909 Sergei Golubchik	2009-10-30
      backport of dbug extensions from 6.0:
        function/ syntax
        glob(7) wildcards
        unit tests

    removed:
      dbug/.cvsignore
      dbug/doinstall.sh
      dbug/install.sh
      dbug/mklintlib.sh
      dbug/qmake.cmd
      dbug/vargs.h
    added:
      dbug/remove_function_from_trace.pl
      dbug/tests-t.pl
      dbug/tests.c
    modified:
      .bzrignore
      client/mysqltest.cc
      dbug/Makefile.am
      dbug/dbug.c
      dbug/dbug_add_tags.pl
      dbug/user.r
      include/my_dbug.h
      include/my_global.h
      include/my_pthread.h
      libmysql/libmysql.c
      mysys/my_thr_init.c
      sql-common/client.c
      sql/debug_sync.cc
      sql/field.cc
      sql/ha_ndbcluster.cc
      sql/ha_ndbcluster_binlog.cc
      sql/log_event.cc
      sql/slave.cc
      sql/sql_select.cc
      sql/sql_table.cc
=== modified file '.bzrignore'
--- a/.bzrignore	2009-10-14 08:25:39 +0000
+++ b/.bzrignore	2009-10-30 18:13:58 +0000
@@ -3066,3 +3066,5 @@ sql/share/ukrainian
 libmysqld/examples/mysqltest.cc
 libmysqld/sql_signal.cc
 libmysqld/debug_sync.cc
+libmysqld/rpl_handler.cc
+dbug/tests

=== modified file 'client/mysqltest.cc'
--- a/client/mysqltest.cc	2009-10-22 07:40:16 +0000
+++ b/client/mysqltest.cc	2009-10-30 18:13:58 +0000
@@ -1168,7 +1168,6 @@ void free_used_memory()
     mysql_server_end();
 
   /* Don't use DBUG after mysql_server_end() */
-  DBUG_VIOLATION_HELPER_LEAVE;
   return;
 }
 

=== removed file 'dbug/.cvsignore'
--- a/dbug/.cvsignore	2000-07-31 19:29:14 +0000
+++ b/dbug/.cvsignore	1970-01-01 00:00:00 +0000
@@ -1,3 +0,0 @@
-.deps
-Makefile
-Makefile.in

=== modified file 'dbug/Makefile.am'
--- a/dbug/Makefile.am	2006-12-31 00:32:21 +0000
+++ b/dbug/Makefile.am	2009-10-30 18:13:58 +0000
@@ -23,19 +23,20 @@ libdbug_a_SOURCES =     dbug.c sanity.c
 EXTRA_DIST =            CMakeLists.txt example1.c example2.c example3.c \
                         user.r monty.doc dbug_add_tags.pl \
                         my_main.c main.c factorial.c dbug_analyze.c \
-						CMakeLists.txt
+                        CMakeLists.txt tests.c tests-t.pl
 NROFF_INC =             example1.r example2.r example3.r main.r \
                         factorial.r output1.r output2.r output3.r \
                         output4.r output5.r
-CLEANFILES =            $(NROFF_INC) user.t user.ps
+CLEANFILES =            $(NROFF_INC) user.t user.ps tests-t
 
 
 # Must be linked with libs that are not compiled yet
-noinst_PROGRAMS =       factorial dbug_analyze
+noinst_PROGRAMS =       factorial dbug_analyze tests
 factorial_SOURCES =     my_main.c factorial.c
+tests_SOURCES =         tests.c
 dbug_analyze_SOURCES =  dbug_analyze.c
 
-all:            user.t user.ps
+all:            user.t user.ps tests-t
 
 user.t:         user.r $(NROFF_INC)
 		-nroff -mm user.r > $@
@@ -61,5 +62,7 @@ output5.r:      factorial
 		@RM@ -f $@
 		@SED@ -e 's!\\!\\\\!g' $< > $@
 
-# Don't update the files from bitkeeper
-%::SCCS/s.%
+# a hack to have executable in builddir, not in srcdir
+tests-t:        tests-t.pl
+		cp -f $(srcdir)/tests-t.pl ./tests-t
+

=== modified file 'dbug/dbug.c'
--- a/dbug/dbug.c	2009-09-29 13:55:36 +0000
+++ b/dbug/dbug.c	2009-10-30 18:13:58 +0000
@@ -57,29 +57,48 @@
  *      seismo!bpa!sjuvax!bbanerje
  *
  *      Michael Widenius:
- *      DBUG_DUMP       - To dump a block of memory.
- *      PUSH_FLAG "O"   - To be used insted of "o" if we
- *                        want flushing after each write
- *      PUSH_FLAG "A"   - as 'O', but we will append to the out file instead
- *                        of creating a new one.
- *      Check of malloc on entry/exit (option "S")
- *
- *      DBUG_EXECUTE_IF
- *      incremental mode (-#+t:-d,info ...)
- *      DBUG_SET, _db_explain_
- *      thread-local settings
+ *        DBUG_DUMP       - To dump a block of memory.
+ *        PUSH_FLAG "O"   - To be used insted of "o" if we
+ *                          want flushing after each write
+ *        PUSH_FLAG "A"   - as 'O', but we will append to the out file instead
+ *                          of creating a new one.
+ *        Check of malloc on entry/exit (option "S")
+ *
+ *      Sergei Golubchik:
+ *        DBUG_EXECUTE_IF
+ *        incremental mode (-#+t:-d,info ...)
+ *        DBUG_SET, _db_explain_
+ *        thread-local settings
+ *        negative lists (-#-d,info => everything but "info")
+ *
+ *        function/ syntax
+ *        (the logic is - think of a call stack as of a path.
+ *        "function" means only this function, "function/" means the hierarchy.
+ *        in the future, filters like function1/function2 could be supported.
+ *        following this logic glob(7) wildcards are supported.)
  *
  */
 
+/*
+  We can't have SAFE_MUTEX defined here as this will cause recursion
+  in pthread_mutex_lock
+*/
 
+#undef SAFE_MUTEX
 #include <my_global.h>
 #include <m_string.h>
 #include <errno.h>
+
+#ifdef HAVE_FNMATCH_H
+#include <fnmatch.h>
+#else
+#define fnmatch(A,B,C) strcmp(A,B)
+#endif
+
 #if defined(MSDOS) || defined(__WIN__)
 #include <process.h>
 #endif
 
-
 #ifndef DBUG_OFF
 
 
@@ -95,21 +114,24 @@
  *      The following flags are used to determine which
  *      capabilities the user has enabled with the settings
  *      push macro.
+ *
+ *      TRACE_ON is also used in _db_stack_frame_->level
+ *      (until we add flags to _db_stack_frame_, increasing it by 4 bytes)
  */
 
-#define TRACE_ON        000001  /* Trace enabled */
-#define DEBUG_ON        000002  /* Debug enabled */
-#define FILE_ON         000004  /* File name print enabled */
-#define LINE_ON         000010  /* Line number print enabled */
-#define DEPTH_ON        000020  /* Function nest level print enabled */
-#define PROCESS_ON      000040  /* Process name print enabled */
-#define NUMBER_ON       000100  /* Number each line of output */
-#define PROFILE_ON      000200  /* Print out profiling code */
-#define PID_ON          000400  /* Identify each line with process id */
-#define TIMESTAMP_ON    001000  /* timestamp every line of output */
-#define SANITY_CHECK_ON 002000  /* Check safemalloc on DBUG_ENTER */
-#define FLUSH_ON_WRITE  004000  /* Flush on every write */
-#define OPEN_APPEND     010000  /* Open for append      */
+#define DEBUG_ON        (1 <<  1)  /* Debug enabled */
+#define FILE_ON         (1 <<  2)  /* File name print enabled */
+#define LINE_ON         (1 <<  3)  /* Line number print enabled */
+#define DEPTH_ON        (1 <<  4)  /* Function nest level print enabled */
+#define PROCESS_ON      (1 <<  5)  /* Process name print enabled */
+#define NUMBER_ON       (1 <<  6)  /* Number each line of output */
+#define PROFILE_ON      (1 <<  7)  /* Print out profiling code */
+#define PID_ON          (1 <<  8)  /* Identify each line with process id */
+#define TIMESTAMP_ON    (1 <<  9)  /* timestamp every line of output */
+#define SANITY_CHECK_ON (1 << 10)  /* Check safemalloc on DBUG_ENTER */
+#define FLUSH_ON_WRITE  (1 << 11)  /* Flush on every write */
+#define OPEN_APPEND     (1 << 12)  /* Open for append      */
+#define TRACE_ON        ((uint)1 << 31)  /* Trace enabled. MUST be the highest bit!*/
 
 #define TRACING (cs->stack->flags & TRACE_ON)
 #define DEBUGGING (cs->stack->flags & DEBUG_ON)
@@ -119,11 +141,7 @@
  *      Typedefs to make things more obvious.
  */
 
-#ifndef __WIN__
-typedef int BOOLEAN;
-#else
-#define BOOLEAN BOOL
-#endif
+#define BOOLEAN my_bool
 
 /*
  *      Make it easy to change storage classes if necessary.
@@ -139,7 +157,7 @@ typedef int BOOLEAN;
  * (G?) which allowed the user to specify this.
  *
  * If the automatic variables get allocated on the stack in
- * reverse order from their declarations, then define AUTOS_REVERSE.
+ * reverse order from their declarations, then define AUTOS_REVERSE to 1.
  * This is used by the code that keeps track of stack usage.  For
  * forward allocation, the difference in the dbug frame pointers
  * represents stack used by the callee function.  For reverse allocation,
@@ -154,6 +172,8 @@ typedef int BOOLEAN;
 
 #ifdef M_I386           /* predefined by xenix 386 compiler */
 #define AUTOS_REVERSE 1
+#else
+#define AUTOS_REVERSE 0
 #endif
 
 /*
@@ -164,7 +184,11 @@ typedef int BOOLEAN;
 static void perror();          /* Fake system/library error print routine */
 #endif
 
+#ifdef SAFEMALLOC
 IMPORT int _sanity(const char *file,uint line); /* safemalloc sanity checker */
+#else
+#define _sanity(X,Y) (1)
+#endif
 
 /*
  *      The user may specify a list of functions to trace or
@@ -174,9 +198,18 @@ IMPORT int _sanity(const char *file,uint
 
 struct link {
     struct link *next_link;   /* Pointer to the next link */
-    char   str[1];        /* Pointer to link's contents */
+    char   flags;
+    char   str[1];            /* Pointer to link's contents */
 };
 
+/* flags for struct link and return flags of InList */
+#define SUBDIR          1 /* this MUST be 1 */
+#define INCLUDE         2
+#define EXCLUDE         4
+/* this is not a struct link flag, but only a return flags of InList */
+#define MATCHED     65536
+#define NOT_MATCHED     0
+
 /*
  *      Debugging settings can be pushed or popped off of a
  *      stack which is implemented as a linked list.  Note
@@ -188,18 +221,18 @@ struct link {
  */
 
 struct settings {
-  int flags;                    /* Current settings flags */
-  int maxdepth;                 /* Current maximum trace depth */
-  uint delay;                   /* Delay after each output line */
-  int sub_level;                /* Sub this from code_state->level */
-  FILE *out_file;               /* Current output stream */
-  FILE *prof_file;              /* Current profiling stream */
-  char name[FN_REFLEN];         /* Name of output file */
-  struct link *functions;       /* List of functions */
-  struct link *p_functions;     /* List of profiled functions */
-  struct link *keywords;        /* List of debug keywords */
-  struct link *processes;       /* List of process names */
-  struct settings *next;        /* Next settings in the list */
+  uint flags;                   /* Current settings flags               */
+  uint maxdepth;                /* Current maximum trace depth          */
+  uint delay;                   /* Delay after each output line         */
+  uint sub_level;               /* Sub this from code_state->level      */
+  FILE *out_file;               /* Current output stream                */
+  FILE *prof_file;              /* Current profiling stream             */
+  char name[FN_REFLEN];         /* Name of output file                  */
+  struct link *functions;       /* List of functions                    */
+  struct link *p_functions;     /* List of profiled functions           */
+  struct link *keywords;        /* List of debug keywords               */
+  struct link *processes;       /* List of process names                */
+  struct settings *next;        /* Next settings in the list            */
 };
 
 #define is_shared(S, V) ((S)->next && (S)->next->V == (S)->V)
@@ -212,18 +245,19 @@ struct settings {
 static BOOLEAN init_done= FALSE; /* Set to TRUE when initialization done */
 static struct settings init_settings;
 static const char *db_process= 0;/* Pointer to process name; argv[0] */
+my_bool _dbug_on_= TRUE;	 /* FALSE if no debugging at all */
 
 typedef struct _db_code_state_ {
   const char *process;          /* Pointer to process name; usually argv[0] */
-  const char *func;             /* Name of current user function */
-  const char *file;             /* Name of current user file */
-  char **framep;                /* Pointer to current frame */
-  struct settings *stack;       /* debugging settings */
-  const char *jmpfunc;          /* Remember current function for setjmp */
-  const char *jmpfile;          /* Remember current file for setjmp */
-  int lineno;                   /* Current debugger output line number */
-  int level;                    /* Current function nesting level */
-  int jmplevel;                 /* Remember nesting level at setjmp() */
+  const char *func;             /* Name of current user function            */
+  const char *file;             /* Name of current user file                */
+  struct _db_stack_frame_ *framep; /* Pointer to current frame              */
+  struct settings *stack;       /* debugging settings                       */
+  const char *jmpfunc;          /* Remember current function for setjmp     */
+  const char *jmpfile;          /* Remember current file for setjmp         */
+  int lineno;                   /* Current debugger output line number      */
+  uint level;                   /* Current function nesting level           */
+  int jmplevel;                 /* Remember nesting level at setjmp()       */
 
 /*
  *      The following variables are used to hold the state information
@@ -244,12 +278,16 @@ typedef struct _db_code_state_ {
   The test below is so we could call functions with DBUG_ENTER before
   my_thread_init().
 */
-#define get_code_state_or_return if (!cs && !((cs=code_state()))) return
+#define get_code_state_if_not_set_or_return if (!cs && !((cs=code_state()))) return
+#define get_code_state_or_return if (!((cs=code_state()))) return
 
         /* Handling lists */
-static struct link *ListAdd(struct link *, const char *, const char *);
-static struct link *ListDel(struct link *, const char *, const char *);
+#define ListAdd(A,B,C) ListAddDel(A,B,C,INCLUDE)
+#define ListDel(A,B,C) ListAddDel(A,B,C,EXCLUDE)
+static struct link *ListAddDel(struct link *, const char *, const char *, int);
 static struct link *ListCopy(struct link *);
+static int InList(struct link *linkp,const char *cp);
+static uint ListFlags(struct link *linkp);
 static void FreeList(struct link *linkp);
 
         /* OpenClose debug output stream */
@@ -260,10 +298,18 @@ static void PushState(CODE_STATE *cs);
 	/* Free memory associated with debug state. */
 static void FreeState (CODE_STATE *cs, struct settings *state, int free_state);
         /* Test for tracing enabled */
-static BOOLEAN DoTrace(CODE_STATE *cs);
+static int DoTrace(CODE_STATE *cs);
+/*
+  return values of DoTrace.
+  Can also be used as bitmask: ret & DO_TRACE
+*/
+#define DO_TRACE        1
+#define DONT_TRACE      2
+#define ENABLE_TRACE    3
+#define DISABLE_TRACE   4
 
         /* Test to see if file is writable */
-#if !(!defined(HAVE_ACCESS) || defined(MSDOS))
+#if defined(HAVE_ACCESS) && !defined(MSDOS)
 static BOOLEAN Writable(const char *pathname);
         /* Change file owner and group */
 static void ChangeOwner(CODE_STATE *cs, char *pathname);
@@ -275,10 +321,10 @@ static void DoPrefix(CODE_STATE *cs, uin
 static char *DbugMalloc(size_t size);
 static const char *BaseName(const char *pathname);
 static void Indent(CODE_STATE *cs, int indent);
-static BOOLEAN InList(struct link *linkp,const char *cp);
-static void dbug_flush(CODE_STATE *);
+static void DbugFlush(CODE_STATE *);
 static void DbugExit(const char *why);
 static const char *DbugStrTok(const char *s);
+static void DbugFprintf(FILE *stream, const char* format, va_list args);
 
 #ifndef THREAD
         /* Open profile output stream */
@@ -322,34 +368,39 @@ static unsigned long Clock(void);
 
 #ifdef THREAD
 #include <my_pthread.h>
-pthread_mutex_t THR_LOCK_dbug;
+static pthread_mutex_t THR_LOCK_dbug;
 
 static CODE_STATE *code_state(void)
 {
-  CODE_STATE *cs=0;
-  struct st_my_thread_var *tmp;
+  CODE_STATE *cs, **cs_ptr;
+
+  /*
+    _dbug_on_ is reset if we don't plan to use any debug commands at all and
+    we want to run on maximum speed
+   */
+  if (!_dbug_on_)
+    return 0;
 
   if (!init_done)
   {
+    init_done=TRUE;
     pthread_mutex_init(&THR_LOCK_dbug,MY_MUTEX_INIT_FAST);
     bzero(&init_settings, sizeof(init_settings));
     init_settings.out_file=stderr;
     init_settings.flags=OPEN_APPEND;
-    init_done=TRUE;
   }
 
-  if ((tmp=my_thread_var))
-  {
-    if (!(cs=(CODE_STATE *) tmp->dbug))
-    {
-      cs=(CODE_STATE*) DbugMalloc(sizeof(*cs));
-      bzero((uchar*) cs,sizeof(*cs));
-      cs->process= db_process ? db_process : "dbug";
-      cs->func="?func";
-      cs->file="?file";
-      cs->stack=&init_settings;
-      tmp->dbug= (void*) cs;
-    }
+  if (!(cs_ptr= (CODE_STATE**) my_thread_var_dbug()))
+    return 0;                                   /* Thread not initialised */
+  if (!(cs= *cs_ptr))
+  {
+    cs=(CODE_STATE*) DbugMalloc(sizeof(*cs));
+    bzero((uchar*) cs,sizeof(*cs));
+    cs->process= db_process ? db_process : "dbug";
+    cs->func="?func";
+    cs->file="?file";
+    cs->stack=&init_settings;
+    *cs_ptr= cs;
   }
   return cs;
 }
@@ -403,20 +454,19 @@ static CODE_STATE *code_state(void)
 
 void _db_process_(const char *name)
 {
-  CODE_STATE *cs=0;
+  CODE_STATE *cs;
 
   if (!db_process)
     db_process= name;
-  
+
   get_code_state_or_return;
   cs->process= name;
 }
 
-
 /*
  *  FUNCTION
  *
- *      DbugParse       parse control string and set current debugger setting
+ *      DbugParse  parse control string and set current debugger settings
  *
  *  DESCRIPTION
  *
@@ -438,15 +488,17 @@ void _db_process_(const char *name)
  *
  *      For convenience, any leading "-#" is stripped off.
  *
+ *  RETURN
+ *      1 - a list of functions ("f" flag) was possibly changed
+ *      0 - a list of functions was not changed
  */
 
-static void DbugParse(CODE_STATE *cs, const char *control)
+int DbugParse(CODE_STATE *cs, const char *control)
 {
   const char *end;
-  int rel=0;
+  int rel, f_used=0;
   struct settings *stack;
 
-  get_code_state_or_return;
   stack= cs->stack;
 
   if (control[0] == '-' && control[1] == '#')
@@ -455,6 +507,7 @@ static void DbugParse(CODE_STATE *cs, co
   rel= control[0] == '+' || control[0] == '-';
   if ((!rel || (!stack->out_file && !stack->next)))
   {
+    FreeState(cs, stack, 0);
     stack->flags= 0;
     stack->delay= 0;
     stack->maxdepth= 0;
@@ -497,7 +550,6 @@ static void DbugParse(CODE_STATE *cs, co
   {
     int c, sign= (*control == '+') ? 1 : (*control == '-') ? -1 : 0;
     if (sign) control++;
-    if (!rel) sign=0;
     c= *control++;
     if (*control == ',') control++;
     /* XXX when adding new cases here, don't forget _db_explain_ ! */
@@ -526,6 +578,7 @@ static void DbugParse(CODE_STATE *cs, co
       stack->delay= atoi(control);
       break;
     case 'f':
+      f_used= 1;
       if (sign < 0 && control == end)
       {
         if (!is_shared(stack,functions))
@@ -664,8 +717,111 @@ static void DbugParse(CODE_STATE *cs, co
     control=end+1;
     end= DbugStrTok(control);
   }
+  return !rel || f_used;
 }
 
+#define framep_trace_flag(cs, frp) (frp ?                                    \
+                                     frp->level & TRACE_ON :                 \
+                              (ListFlags(cs->stack->functions) & INCLUDE) ?  \
+                                       0 : (uint)TRACE_ON)
+
+void FixTraceFlags_helper(CODE_STATE *cs, const char *func,
+                          struct _db_stack_frame_ *framep)
+{
+  if (framep->prev)
+    FixTraceFlags_helper(cs, framep->func, framep->prev);
+
+  cs->func= func;
+  cs->level= framep->level & ~TRACE_ON;
+  framep->level= cs->level | framep_trace_flag(cs, framep->prev);
+  /*
+    we don't set cs->framep correctly, even though DoTrace uses it.
+    It's ok, because cs->framep may only affect DO_TRACE/DONT_TRACE return
+    values, but we ignore them here anyway
+  */
+  switch(DoTrace(cs)) {
+  case ENABLE_TRACE:
+    framep->level|= TRACE_ON;
+    break;
+  case DISABLE_TRACE:
+    framep->level&= ~TRACE_ON;
+    break;
+  }
+}
+
+#define fflags(cs) cs->stack->out_file ? ListFlags(cs->stack->functions) : TRACE_ON;
+
+void FixTraceFlags(uint old_fflags, CODE_STATE *cs)
+{
+  const char *func;
+  uint new_fflags, traceon, level;
+  struct _db_stack_frame_ *framep;
+
+  /*
+    first (a.k.a. safety) check:
+    if we haven't started tracing yet, no call stack at all - we're safe.
+  */
+  framep=cs->framep;
+  if (framep == 0)
+    return;
+
+  /*
+    Ok, the tracing has started, call stack isn't empty.
+
+    second check: does the new list have a SUBDIR rule ?
+  */
+  new_fflags=fflags(cs);
+  if (new_fflags & SUBDIR)
+    goto yuck;
+
+  /*
+    Ok, new list doesn't use SUBDIR.
+
+    third check: we do NOT need to re-scan if
+    neither old nor new lists used SUBDIR flag and if a default behavior
+    (whether an unlisted function is traced) hasn't changed.
+    Default behavior depends on whether there're INCLUDE elements in the list.
+  */
+  if (!(old_fflags & SUBDIR) && !((new_fflags^old_fflags) & INCLUDE))
+    return;
+
+  /*
+    Ok, old list may've used SUBDIR, or defaults could've changed.
+
+    fourth check: are we inside a currently active SUBDIR rule ?
+    go up the call stack, if TRACE_ON flag ever changes its value - we are.
+  */
+  for (traceon=framep->level; framep; framep=framep->prev)
+    if ((traceon ^ framep->level) & TRACE_ON)
+      goto yuck;
+
+  /*
+    Ok, TRACE_ON flag doesn't change in the call stack.
+
+    fifth check: but is the top-most value equal to a default one ?
+  */
+  if (((traceon & TRACE_ON) != 0) == ((new_fflags & INCLUDE) == 0))
+    return;
+
+yuck:
+  /*
+    Yuck! function list was changed, and one of the currently active rules
+    was possibly affected. For example, a tracing could've been enabled or
+    disabled for a function somewhere up the call stack.
+    To react correctly, we must go up the call stack all the way to
+    the top and re-match rules to set TRACE_ON bit correctly.
+
+    We must traverse the stack forwards, not backwards.
+    That's what a recursive helper is doing.
+    It'll destroy two CODE_STATE fields, save them now.
+  */
+  func= cs->func;
+  level= cs->level;
+  FixTraceFlags_helper(cs, func, cs->framep);
+  /* now we only need to restore CODE_STATE fields, and we're done */
+  cs->func= func;
+  cs->level= level;
+}
 
 /*
  *  FUNCTION
@@ -683,19 +839,21 @@ static void DbugParse(CODE_STATE *cs, co
  *      parses the control string, and sets up a current debug
  *      settings. Pushes a new debug settings if the current is
  *      set to the initial debugger settings.
+ *
  */
 
-void _db_set_(CODE_STATE *cs, const char *control)
+void _db_set_(const char *control)
 {
+  CODE_STATE *cs;
+  uint old_fflags;
   get_code_state_or_return;
-
+  old_fflags=fflags(cs);
   if (cs->stack == &init_settings)
     PushState(cs);
-
-  DbugParse(cs, control);
+  if (DbugParse(cs, control))
+    FixTraceFlags(old_fflags, cs);
 }
 
-
 /*
  *  FUNCTION
  *
@@ -716,10 +874,25 @@ void _db_set_(CODE_STATE *cs, const char
 
 void _db_push_(const char *control)
 {
-  CODE_STATE *cs=0;
+  CODE_STATE *cs;
+  uint old_fflags;
   get_code_state_or_return;
+  old_fflags=fflags(cs);
   PushState(cs);
-  DbugParse(cs, control);
+  if (DbugParse(cs, control))
+    FixTraceFlags(old_fflags, cs);
+}
+
+
+/**
+  Returns TRUE if session-local settings have been set.
+*/
+
+int _db_is_pushed_()
+{
+  CODE_STATE *cs= NULL;
+  get_code_state_or_return FALSE;
+  return (cs->stack != &init_settings);
 }
 
 /*
@@ -765,15 +938,18 @@ void _db_set_init_(const char *control)
 void _db_pop_()
 {
   struct settings *discard;
-  CODE_STATE *cs=0;
+  uint old_fflags;
+  CODE_STATE *cs;
 
   get_code_state_or_return;
 
   discard= cs->stack;
-  if (discard->next != NULL)
+  if (discard != &init_settings)
   {
+    old_fflags=fflags(cs);
     cs->stack= discard->next;
     FreeState(cs, discard, 1);
+    FixTraceFlags(old_fflags, cs);
   }
 }
 
@@ -798,11 +974,16 @@ void _db_pop_()
         buf=strnmov(buf, (S), len+1);           \
         if (buf >= end) goto overflow;          \
       } while (0)
-#define list_to_buf(l)  do {                    \
+#define list_to_buf(l, f)  do {                 \
         struct link *listp=(l);                 \
         while (listp)                           \
         {                                       \
-          str_to_buf(listp->str);               \
+          if (listp->flags & (f))               \
+          {                                     \
+            str_to_buf(listp->str);             \
+            if (listp->flags & SUBDIR)          \
+              char_to_buf('/');                 \
+          }                                     \
           listp=listp->next_link;               \
         }                                       \
       } while (0)
@@ -842,9 +1023,18 @@ void _db_pop_()
 #define op_list_to_buf(C, val, cond) do {       \
         if ((cond))                             \
         {                                       \
+          int f=ListFlags(val);                 \
           colon_to_buf;                         \
           char_to_buf((C));                     \
-          list_to_buf(val);                     \
+          if (f & INCLUDE)                      \
+            list_to_buf(val, INCLUDE);          \
+          if (f & EXCLUDE)                      \
+          {                                     \
+            colon_to_buf;                       \
+            char_to_buf('-');                   \
+            char_to_buf((C));                   \
+            list_to_buf(val, EXCLUDE);          \
+          }                                     \
         }                                       \
       } while (0)
 #define op_bool_to_buf(C, cond) do {            \
@@ -859,7 +1049,7 @@ int _db_explain_ (CODE_STATE *cs, char *
 {
   char *start=buf, *end=buf+len-4;
 
-  get_code_state_or_return *buf=0;
+  get_code_state_if_not_set_or_return *buf=0;
 
   op_list_to_buf('d', cs->stack->keywords, DEBUGGING);
   op_int_to_buf ('D', cs->stack->delay, 0);
@@ -927,15 +1117,11 @@ int _db_explain_init_(char *buf, size_t 
  *
  *  SYNOPSIS
  *
- *      VOID _db_enter_(_func_, _file_, _line_,
- *                       _sfunc_, _sfile_, _slevel_, _sframep_)
+ *      VOID _db_enter_(_func_, _file_, _line_, _stack_frame_)
  *      char *_func_;           points to current function name
  *      char *_file_;           points to current file name
  *      int _line_;             called from source line number
- *      char **_sfunc_;         save previous _func_
- *      char **_sfile_;         save previous _file_
- *      int *_slevel_;          save previous nesting level
- *      char ***_sframep_;      save previous frame pointer
+ *      struct _db_stack_frame_ allocated on the caller's stack
  *
  *  DESCRIPTION
  *
@@ -959,55 +1145,66 @@ int _db_explain_init_(char *buf, size_t 
  */
 
 void _db_enter_(const char *_func_, const char *_file_,
-                uint _line_, const char **_sfunc_, const char **_sfile_,
-                uint *_slevel_, char ***_sframep_ __attribute__((unused)))
+                uint _line_, struct _db_stack_frame_ *_stack_frame_)
 {
-  int save_errno=errno;
-  CODE_STATE *cs=0;
-  get_code_state_or_return;
+  int save_errno;
+  CODE_STATE *cs;
+  if (!((cs=code_state())))
+  {
+    _stack_frame_->level= 0; /* Set to avoid valgrind warnings if dbug is enabled later */
+    _stack_frame_->prev= 0;
+    return;
+  }
+  save_errno= errno;
 
-  *_sfunc_= cs->func;
-  *_sfile_= cs->file;
+  _stack_frame_->func= cs->func;
+  _stack_frame_->file= cs->file;
   cs->func=  _func_;
   cs->file=  _file_;
-  *_slevel_=  ++cs->level;
+  _stack_frame_->prev= cs->framep;
+  _stack_frame_->level= ++cs->level | framep_trace_flag(cs, cs->framep);
+  cs->framep= _stack_frame_;
 #ifndef THREAD
-  *_sframep_= cs->framep;
-  cs->framep= (char **) _sframep_;
   if (DoProfile(cs))
   {
     long stackused;
-    if (*cs->framep == NULL)
+    if (cs->framep->prev == NULL)
       stackused= 0;
     else
     {
-      stackused= ((long)(*cs->framep)) - ((long)(cs->framep));
+      stackused= (char*)(cs->framep->prev) - (char*)(cs->framep);
       stackused= stackused > 0 ? stackused : -stackused;
     }
     (void) fprintf(cs->stack->prof_file, PROF_EFMT , Clock(), cs->func);
-#ifdef AUTOS_REVERSE
-    (void) fprintf(cs->stack->prof_file, PROF_SFMT, cs->framep, stackused, *_sfunc_);
-#else
     (void) fprintf(cs->stack->prof_file, PROF_SFMT, (ulong) cs->framep, stackused,
-                    cs->func);
-#endif
+                   AUTOS_REVERSE ? _stack_frame_->func : cs->func);
     (void) fflush(cs->stack->prof_file);
   }
 #endif
-  if (DoTrace(cs))
-  {
-    if (!cs->locked)
-      pthread_mutex_lock(&THR_LOCK_dbug);
-    DoPrefix(cs, _line_);
-    Indent(cs, cs->level);
-    (void) fprintf(cs->stack->out_file, ">%s\n", cs->func);
-    dbug_flush(cs);                       /* This does a unlock */
-  }
-#ifdef SAFEMALLOC
-  if (cs->stack->flags & SANITY_CHECK_ON)
-    if (_sanity(_file_,_line_))               /* Check of safemalloc */
+  switch (DoTrace(cs)) {
+  case ENABLE_TRACE:
+    cs->framep->level|= TRACE_ON;
+    if (!TRACING) break;
+    /* fall through */
+  case DO_TRACE:
+    if ((cs->stack->flags & SANITY_CHECK_ON) && _sanity(_file_,_line_))
       cs->stack->flags &= ~SANITY_CHECK_ON;
-#endif
+    if (TRACING)
+    {
+      if (!cs->locked)
+        pthread_mutex_lock(&THR_LOCK_dbug);
+      DoPrefix(cs, _line_);
+      Indent(cs, cs->level);
+      (void) fprintf(cs->stack->out_file, ">%s\n", cs->func);
+      DbugFlush(cs);                       /* This does a unlock */
+    }
+    break;
+  case DISABLE_TRACE:
+    cs->framep->level&= ~TRACE_ON;
+    /* fall through */
+  case DONT_TRACE:
+    break;
+  }
   errno=save_errno;
 }
 
@@ -1018,11 +1215,9 @@ void _db_enter_(const char *_func_, cons
  *
  *  SYNOPSIS
  *
- *      VOID _db_return_(_line_, _sfunc_, _sfile_, _slevel_)
+ *      VOID _db_return_(_line_, _stack_frame_)
  *      int _line_;             current source line number
- *      char **_sfunc_;         where previous _func_ is to be retrieved
- *      char **_sfile_;         where previous _file_ is to be retrieved
- *      int *_slevel_;          where previous level was stashed
+ *      struct _db_stack_frame_ allocated on the caller's stack
  *
  *  DESCRIPTION
  *
@@ -1034,51 +1229,52 @@ void _db_enter_(const char *_func_, cons
  */
 
 /* helper macro */
-void _db_return_(uint _line_, const char **_sfunc_,
-                 const char **_sfile_, uint *_slevel_)
+void _db_return_(uint _line_, struct _db_stack_frame_ *_stack_frame_)
 {
   int save_errno=errno;
-  CODE_STATE *cs=0;
+  uint _slevel_= _stack_frame_->level & ~TRACE_ON;
+  CODE_STATE *cs;
   get_code_state_or_return;
 
-  if (cs->level != (int) *_slevel_)
+  if (cs->level != _slevel_)
   {
     if (!cs->locked)
       pthread_mutex_lock(&THR_LOCK_dbug);
     (void) fprintf(cs->stack->out_file, ERR_MISSING_RETURN, cs->process,
                    cs->func);
-    dbug_flush(cs);
+    DbugFlush(cs);
   }
   else
   {
-#ifdef SAFEMALLOC
-    if (cs->stack->flags & SANITY_CHECK_ON)
-    {
-      if (_sanity(*_sfile_,_line_))
-        cs->stack->flags &= ~SANITY_CHECK_ON;
-    }
-#endif
 #ifndef THREAD
     if (DoProfile(cs))
       (void) fprintf(cs->stack->prof_file, PROF_XFMT, Clock(), cs->func);
 #endif
-    if (DoTrace(cs))
+    if (DoTrace(cs) & DO_TRACE)
     {
-      if (!cs->locked)
-        pthread_mutex_lock(&THR_LOCK_dbug);
-      DoPrefix(cs, _line_);
-      Indent(cs, cs->level);
-      (void) fprintf(cs->stack->out_file, "<%s\n", cs->func);
-      dbug_flush(cs);
+      if ((cs->stack->flags & SANITY_CHECK_ON) &&
+          _sanity(_stack_frame_->file,_line_))
+        cs->stack->flags &= ~SANITY_CHECK_ON;
+      if (TRACING)
+      {
+        if (!cs->locked)
+          pthread_mutex_lock(&THR_LOCK_dbug);
+        DoPrefix(cs, _line_);
+        Indent(cs, cs->level);
+        (void) fprintf(cs->stack->out_file, "<%s\n", cs->func);
+        DbugFlush(cs);
+      }
     }
   }
-  cs->level= *_slevel_-1;
-  cs->func= *_sfunc_;
-  cs->file= *_sfile_;
-#ifndef THREAD
+  /*
+    Check to not set level < 0. This can happen if DBUG was disabled when
+    function was entered and enabled in function.
+  */
+  cs->level= _slevel_ != 0 ? _slevel_ - 1 : 0;
+  cs->func= _stack_frame_->func;
+  cs->file= _stack_frame_->file;
   if (cs->framep != NULL)
-    cs->framep= (char **) *cs->framep;
-#endif
+    cs->framep= cs->framep->prev;
   errno=save_errno;
 }
 
@@ -1105,7 +1301,7 @@ void _db_return_(uint _line_, const char
 
 void _db_pargs_(uint _line_, const char *keyword)
 {
-  CODE_STATE *cs=0;
+  CODE_STATE *cs;
   get_code_state_or_return;
   cs->u_line= _line_;
   cs->u_keyword= keyword;
@@ -1141,13 +1337,12 @@ void _db_pargs_(uint _line_, const char 
 void _db_doprnt_(const char *format,...)
 {
   va_list args;
-
-  CODE_STATE *cs=0;
+  CODE_STATE *cs;
   get_code_state_or_return;
 
   va_start(args,format);
 
-  if (_db_keyword_(cs, cs->u_keyword))
+  if (_db_keyword_(cs, cs->u_keyword, 0))
   {
     int save_errno=errno;
     if (!cs->locked)
@@ -1158,14 +1353,25 @@ void _db_doprnt_(const char *format,...)
     else
       (void) fprintf(cs->stack->out_file, "%s: ", cs->func);
     (void) fprintf(cs->stack->out_file, "%s: ", cs->u_keyword);
-    (void) vfprintf(cs->stack->out_file, format, args);
-    (void) fputc('\n',cs->stack->out_file);
-    dbug_flush(cs);
+    DbugFprintf(cs->stack->out_file, format, args);
+    DbugFlush(cs);
     errno=save_errno;
   }
   va_end(args);
 }
 
+/*
+ * fprintf clone with consistent, platform independent output for 
+ * problematic formats like %p, %zd and %lld.
+ */
+static void DbugFprintf(FILE *stream, const char* format, va_list args)
+{
+  char cvtbuf[1024];
+  size_t len;
+  len = my_vsnprintf(cvtbuf, sizeof(cvtbuf), format, args);
+  (void) fprintf(stream, "%s\n", cvtbuf);
+}
+
 
 /*
  *  FUNCTION
@@ -1190,11 +1396,10 @@ void _db_dump_(uint _line_, const char *
 {
   int pos;
   char dbuff[90];
-
-  CODE_STATE *cs=0;
+  CODE_STATE *cs;
   get_code_state_or_return;
 
-  if (_db_keyword_(cs, keyword))
+  if (_db_keyword_(cs, keyword, 0))
   {
     if (!cs->locked)
       pthread_mutex_lock(&THR_LOCK_dbug);
@@ -1226,7 +1431,7 @@ void _db_dump_(uint _line_, const char *
       fputc(' ',cs->stack->out_file);
     }
     (void) fputc('\n',cs->stack->out_file);
-    dbug_flush(cs);
+    DbugFlush(cs);
   }
 }
 
@@ -1234,93 +1439,75 @@ void _db_dump_(uint _line_, const char *
 /*
  *  FUNCTION
  *
- *      ListAdd    add to the list modifiers from debug control string
- *
- *  SYNOPSIS
- *
- *      static struct link *ListAdd(listp, ctlp, end)
- *      struct link *listp;
- *      char *ctlp;
- *      char *end;
+ *      ListAddDel    modify the list according to debug control string
  *
  *  DESCRIPTION
  *
  *      Given pointer to a comma separated list of strings in "cltp",
- *      parses the list, and adds it to listp, returning a pointer
- *      to the new list
- *
- *      Note that since each link is added at the head of the list,
- *      the final list will be in "reverse order", which is not
- *      significant for our usage here.
- *
- */
-
-static struct link *ListAdd(struct link *head,
-                             const char *ctlp, const char *end)
-{
-  const char *start;
-  struct link *new_malloc;
-  int len;
-
-  while (ctlp < end)
-  {
-    start= ctlp;
-    while (ctlp < end && *ctlp != ',')
-      ctlp++;
-    len=ctlp-start;
-    new_malloc= (struct link *) DbugMalloc(sizeof(struct link)+len);
-    memcpy(new_malloc->str, start, len);
-    new_malloc->str[len]=0;
-    new_malloc->next_link= head;
-    head= new_malloc;
-    ctlp++;
-  }
-  return head;
-}
-
-/*
- *  FUNCTION
- *
- *      ListDel    remove from the list modifiers in debug control string
- *
- *  SYNOPSIS
- *
- *      static struct link *ListDel(listp, ctlp, end)
- *      struct link *listp;
- *      char *ctlp;
- *      char *end;
+ *      parses the list, and modifies "listp", returning a pointer
+ *      to the new list.
  *
- *  DESCRIPTION
+ *      The mode of operation is defined by "todo" parameter.
  *
- *      Given pointer to a comma separated list of strings in "cltp",
- *      parses the list, and removes these strings from the listp,
- *      returning a pointer to the new list.
+ *      If it is INCLUDE, elements (strings from "cltp") are added to the
+ *      list, they will have INCLUDE flag set. If the list already contains
+ *      the string in question, new element is not added, but a flag of
+ *      the existing element is adjusted (INCLUDE bit is set, EXCLUDE bit
+ *      is removed).
  *
+ *      If it is EXCLUDE, elements are added to the list with the EXCLUDE
+ *      flag set. If the list already contains the string in question,
+ *      it is removed, new element is not added.
  */
 
-static struct link *ListDel(struct link *head,
-                             const char *ctlp, const char *end)
+static struct link *ListAddDel(struct link *head, const char *ctlp,
+                               const char *end, int todo)
 {
   const char *start;
   struct link **cur;
-  int len;
+  size_t len;
+  int subdir;
 
-  while (ctlp < end)
+  ctlp--;
+next:
+  while (++ctlp < end)
   {
     start= ctlp;
+    subdir=0;
     while (ctlp < end && *ctlp != ',')
       ctlp++;
     len=ctlp-start;
-    cur=&head;
-    do
+    if (start[len-1] == '/')
+    {
+      len--;
+      subdir=SUBDIR;
+    }
+    if (len == 0) continue;
+    for (cur=&head; *cur; cur=&((*cur)->next_link))
     {
-      while (*cur && !strncmp((*cur)->str, start, len))
+      if (!strncmp((*cur)->str, start, len))
       {
-        struct link *delme=*cur;
-        *cur=(*cur)->next_link;
-        free((void*) delme);
+        if ((*cur)->flags & todo)  /* same action ? */
+          (*cur)->flags|= subdir;  /* just merge the SUBDIR flag */
+        else if (todo == EXCLUDE)
+        {
+          struct link *delme=*cur;
+          *cur=(*cur)->next_link;
+          free((void*) delme);
+        }
+        else
+        {
+          (*cur)->flags&=~(EXCLUDE & SUBDIR);
+          (*cur)->flags|=INCLUDE | subdir;
+        }
+        goto next;
       }
-    } while (*cur && *(cur=&((*cur)->next_link)));
+    }
+    *cur= (struct link *) DbugMalloc(sizeof(struct link)+len);
+    memcpy((*cur)->str, start, len);
+    (*cur)->str[len]=0;
+    (*cur)->flags=todo | subdir;
+    (*cur)->next_link=0;
   }
   return head;
 }
@@ -1352,7 +1539,7 @@ static struct link *ListCopy(struct link
 {
   struct link *new_malloc;
   struct link *head;
-  int len;
+  size_t len;
 
   head= NULL;
   while (orig != NULL)
@@ -1361,6 +1548,7 @@ static struct link *ListCopy(struct link
     new_malloc= (struct link *) DbugMalloc(sizeof(struct link)+len);
     memcpy(new_malloc->str, orig->str, len);
     new_malloc->str[len]= 0;
+    new_malloc->flags=orig->flags;
     new_malloc->next_link= head;
     head= new_malloc;
     orig= orig->next_link;
@@ -1373,47 +1561,52 @@ static struct link *ListCopy(struct link
  *
  *      InList    test a given string for member of a given list
  *
- *  SYNOPSIS
- *
- *      static BOOLEAN InList(linkp, cp)
- *      struct link *linkp;
- *      char *cp;
- *
  *  DESCRIPTION
  *
  *      Tests the string pointed to by "cp" to determine if it is in
  *      the list pointed to by "linkp".  Linkp points to the first
- *      link in the list.  If linkp is NULL then the string is treated
- *      as if it is in the list (I.E all strings are in the null list).
+ *      link in the list.  If linkp is NULL or contains only EXCLUDE
+ *      elements then the string is treated as if it is in the list.
  *      This may seem rather strange at first but leads to the desired
  *      operation if no list is given.  The net effect is that all
  *      strings will be accepted when there is no list, and when there
  *      is a list, only those strings in the list will be accepted.
  *
+ *  RETURN
+ *      combination of SUBDIR, INCLUDE, EXCLUDE, MATCHED flags
+ *
  */
 
-static BOOLEAN InList(struct link *linkp, const char *cp)
+static int InList(struct link *linkp, const char *cp)
 {
-  REGISTER struct link *scan;
-  REGISTER BOOLEAN result;
+  int result;
 
-  if (linkp == NULL)
-    result= TRUE;
-  else
+  for (result=MATCHED; linkp != NULL; linkp= linkp->next_link)
   {
-    result= FALSE;
-    for (scan= linkp; scan != NULL; scan= scan->next_link)
-    {
-      if (!strcmp(scan->str, cp))
-      {
-        result= TRUE;
-        break;
-      }
-    }
+    if (!fnmatch(linkp->str, cp, 0))
+      return linkp->flags;
+    if (!(linkp->flags & EXCLUDE))
+      result=NOT_MATCHED;
+    if (linkp->flags & SUBDIR)
+      result|=SUBDIR;
   }
   return result;
 }
 
+/*
+ *  FUNCTION
+ *
+ *      ListFlags    returns aggregated list flags (ORed over all elements)
+ *
+ */
+
+static uint ListFlags(struct link *linkp)
+{
+  uint f;
+  for (f=0; linkp != NULL; linkp= linkp->next_link)
+    f|= linkp->flags;
+  return f;
+}
 
 /*
  *  FUNCTION
@@ -1440,8 +1633,8 @@ static void PushState(CODE_STATE *cs)
   struct settings *new_malloc;
 
   new_malloc= (struct settings *) DbugMalloc(sizeof(struct settings));
+  bzero(new_malloc, sizeof(*new_malloc));
   new_malloc->next= cs->stack;
-  new_malloc->out_file= NULL;
   cs->stack= new_malloc;
 }
 
@@ -1472,11 +1665,17 @@ static void FreeState(CODE_STATE *cs, st
     FreeList(state->processes);
   if (!is_shared(state, p_functions))
     FreeList(state->p_functions);
+
   if (!is_shared(state, out_file))
     DBUGCloseFile(cs, state->out_file);
-  (void) fflush(cs->stack->out_file);
-  if (state->prof_file)
+  else
+    (void) fflush(state->out_file);
+
+  if (!is_shared(state, prof_file))
     DBUGCloseFile(cs, state->prof_file);
+  else
+    (void) fflush(state->prof_file);
+
   if (free_state)
     free((void*) state);
 }
@@ -1503,8 +1702,12 @@ void _db_end_()
 {
   struct settings *discard;
   static struct settings tmp;
-  CODE_STATE *cs=0;
-
+  CODE_STATE *cs;
+  /*
+    Set _dbug_on_ to be able to do full reset even when DEBUGGER_OFF was
+    called after dbug was initialized
+  */
+  _dbug_on_= 1;
   get_code_state_or_return;
 
   while ((discard= cs->stack))
@@ -1538,25 +1741,30 @@ void _db_end_()
  *
  *      DoTrace    check to see if tracing is current enabled
  *
- *  SYNOPSIS
- *
- *      static BOOLEAN DoTrace(stack)
- *
  *  DESCRIPTION
  *
- *      Checks to see if tracing is enabled based on whether the
- *      user has specified tracing, the maximum trace depth has
- *      not yet been reached, the current function is selected,
- *      and the current process is selected.  Returns TRUE if
- *      tracing is enabled, FALSE otherwise.
+ *      Checks to see if dbug in this function is enabled based on
+ *      whether the maximum trace depth has been reached, the current
+ *      function is selected, and the current process is selected.
  *
  */
 
-static BOOLEAN DoTrace(CODE_STATE *cs)
-{
-  return (TRACING && cs->level <= cs->stack->maxdepth &&
-          InList(cs->stack->functions, cs->func) &&
-          InList(cs->stack->processes, cs->process));
+static int DoTrace(CODE_STATE *cs)
+{
+  if ((cs->stack->maxdepth == 0 || cs->level <= cs->stack->maxdepth) &&
+      InList(cs->stack->processes, cs->process) & (MATCHED|INCLUDE))
+    switch(InList(cs->stack->functions, cs->func)) {
+    case INCLUDE|SUBDIR:  return ENABLE_TRACE;
+    case INCLUDE:         return DO_TRACE;
+    case MATCHED|SUBDIR:
+    case NOT_MATCHED|SUBDIR:
+    case MATCHED:         return framep_trace_flag(cs, cs->framep) ?
+                                           DO_TRACE : DONT_TRACE;
+    case EXCLUDE:
+    case NOT_MATCHED:     return DONT_TRACE;
+    case EXCLUDE|SUBDIR:  return DISABLE_TRACE;
+    }
+  return DONT_TRACE;
 }
 
 
@@ -1584,62 +1792,27 @@ static BOOLEAN DoProfile(CODE_STATE *cs)
 {
   return PROFILING &&
          cs->level <= cs->stack->maxdepth &&
-         InList(cs->stack->p_functions, cs->func) &&
-         InList(cs->stack->processes, cs->process);
+         InList(cs->stack->p_functions, cs->func) & (INCLUDE|MATCHED) &&
+         InList(cs->stack->processes, cs->process) & (INCLUDE|MATCHED);
 }
 #endif
 
 FILE *_db_fp_(void)
 {
-  CODE_STATE *cs=0;
+  CODE_STATE *cs;
   get_code_state_or_return NULL;
   return cs->stack->out_file;
 }
 
-
-/*
- *  FUNCTION
- *
- *      _db_strict_keyword_     test keyword for member of keyword list
- *
- *  SYNOPSIS
- *
- *      BOOLEAN _db_strict_keyword_(keyword)
- *      char *keyword;
- *
- *  DESCRIPTION
- *
- *      Similar to _db_keyword_, but keyword is NOT accepted if keyword list
- *      is empty. Used in DBUG_EXECUTE_IF() - for actions that must not be
- *      executed by default.
- *
- *      Returns TRUE if keyword accepted, FALSE otherwise.
- *
- */
-
-BOOLEAN _db_strict_keyword_(const char *keyword)
-{
-  CODE_STATE *cs=0;
-  get_code_state_or_return FALSE;
-  if (!DEBUGGING || cs->stack->keywords == NULL)
-    return FALSE;
-  return _db_keyword_(cs, keyword);
-}
-
 /*
  *  FUNCTION
  *
  *      _db_keyword_    test keyword for member of keyword list
  *
- *  SYNOPSIS
- *
- *      BOOLEAN _db_keyword_(keyword)
- *      char *keyword;
- *
  *  DESCRIPTION
  *
  *      Test a keyword to determine if it is in the currently active
- *      keyword list.  As with the function list, a keyword is accepted
+ *      keyword list.  If strict=0, a keyword is accepted
  *      if the list is null, otherwise it must match one of the list
  *      members.  When debugging is not on, no keywords are accepted.
  *      After the maximum trace level is exceeded, no keywords are
@@ -1651,36 +1824,13 @@ BOOLEAN _db_strict_keyword_(const char *
  *
  */
 
-BOOLEAN _db_keyword_(CODE_STATE *cs, const char *keyword)
+BOOLEAN _db_keyword_(CODE_STATE *cs, const char *keyword, int strict)
 {
-  get_code_state_or_return FALSE;
+  get_code_state_if_not_set_or_return FALSE;
+  strict=strict ? INCLUDE : INCLUDE|MATCHED;
 
-  return (DEBUGGING &&
-          (!TRACING || cs->level <= cs->stack->maxdepth) &&
-          InList(cs->stack->functions, cs->func) &&
-          InList(cs->stack->keywords, keyword) &&
-          InList(cs->stack->processes, cs->process));
-}
-
-/*
- *  FUNCTION
- *
- *      _db_keywords_    test keyword formed by a set of strings for member
- *                       of keyword list
- *
- *  DESCRIPTION
- *
- *      This function is similar to _db_keyword but receives a set of strings to
- *      be concatenated in order to make the keyword to be compared.
- */
-
-BOOLEAN _db_keywords_(const char *function, const char *type)
-{
-  char dest[_DBUG_MAX_FUNC_NAME_ + 1];
-
-  strxnmov(dest, _DBUG_MAX_FUNC_NAME_, function, type, NULL);
-
-  return _db_strict_keyword_(dest);
+  return DEBUGGING && DoTrace(cs) & DO_TRACE &&
+         InList(cs->stack->keywords, keyword) & strict;
 }
 
 /*
@@ -1848,7 +1998,7 @@ static void DBUGOpenFile(CODE_STATE *cs,
   {
     if (end)
     {
-      int len=end-name;
+      size_t len=end-name;
       memcpy(cs->stack->name, name, len);
       cs->stack->name[len]=0;
     }
@@ -1971,12 +2121,12 @@ static FILE *OpenProfile(CODE_STATE *cs,
 
 static void DBUGCloseFile(CODE_STATE *cs, FILE *fp)
 {
-  if (fp != stderr && fp != stdout && fclose(fp) == EOF)
+  if (fp && fp != stderr && fp != stdout && fclose(fp) == EOF)
   {
     pthread_mutex_lock(&THR_LOCK_dbug);
     (void) fprintf(cs->stack->out_file, ERR_CLOSE, cs->process);
     perror("");
-    dbug_flush(cs);
+    DbugFlush(cs);
   }
 }
 
@@ -2193,7 +2343,7 @@ static void ChangeOwner(CODE_STATE *cs, 
 
 EXPORT void _db_setjmp_()
 {
-  CODE_STATE *cs=0;
+  CODE_STATE *cs;
   get_code_state_or_return;
 
   cs->jmplevel= cs->level;
@@ -2220,7 +2370,7 @@ EXPORT void _db_setjmp_()
 
 EXPORT void _db_longjmp_()
 {
-  CODE_STATE *cs=0;
+  CODE_STATE *cs;
   get_code_state_or_return;
 
   cs->level= cs->jmplevel;
@@ -2271,11 +2421,9 @@ char *s;
         /* This is because some systems (MSDOS!!) dosn't flush fileheader */
         /* and dbug-file isn't readable after a system crash !! */
 
-static void dbug_flush(CODE_STATE *cs)
+static void DbugFlush(CODE_STATE *cs)
 {
-#ifndef THREAD
   if (cs->stack->flags & FLUSH_ON_WRITE)
-#endif
   {
     (void) fflush(cs->stack->out_file);
     if (cs->stack->delay)
@@ -2283,12 +2431,22 @@ static void dbug_flush(CODE_STATE *cs)
   }
   if (!cs->locked)
     pthread_mutex_unlock(&THR_LOCK_dbug);
-} /* dbug_flush */
+} /* DbugFlush */
+
+
+/* For debugging */
+
+void _db_flush_()
+{
+  CODE_STATE *cs;
+  get_code_state_or_return;
+  (void) fflush(cs->stack->out_file);
+}
 
 
 void _db_lock_file_()
 {
-  CODE_STATE *cs=0;
+  CODE_STATE *cs;
   get_code_state_or_return;
   pthread_mutex_lock(&THR_LOCK_dbug);
   cs->locked=1;
@@ -2296,7 +2454,7 @@ void _db_lock_file_()
 
 void _db_unlock_file_()
 {
-  CODE_STATE *cs=0;
+  CODE_STATE *cs;
   get_code_state_or_return;
   cs->locked=0;
   pthread_mutex_unlock(&THR_LOCK_dbug);
@@ -2304,7 +2462,7 @@ void _db_unlock_file_()
 
 const char* _db_get_func_(void)
 {
-  CODE_STATE *cs= 0;
+  CODE_STATE *cs;
   get_code_state_or_return NULL;
   return cs->func;
 }

=== modified file 'dbug/dbug_add_tags.pl'
--- a/dbug/dbug_add_tags.pl	2002-11-05 15:06:11 +0000
+++ b/dbug/dbug_add_tags.pl	2009-10-30 18:13:58 +0000
@@ -7,7 +7,7 @@ $ctags="exctags -x -f - --c-types=f -u";
 sub get_tag {
   local $.; local $_=<TAGS>;
   ($symbol, $line)= /^(.*\S)\s+function\s+(\d+)/;
-  $symbol=$1 if /\s(\S+)\s*\(/;
+  $symbol=$1 if /[\s*]([^\s*]+)\s*\(/;
   $line=1e50 unless $line;
 }
 
@@ -51,7 +51,7 @@ while($src=shift)
       $skip=!$semicolon;
       $semicolon= /;\s*$/;
       print && next if $skip ||
-        (/^\s+\w+((::\w+)?|<\w+>)\s+\**\w+/ && !/^\s*return/);
+        (/^\s+\w+((::\w+)?|<\w+>)\s+\**\w+/ && !/^\s*return\b/);
       last if /DBUG_ENTER/;
       print "$tab  DBUG_ENTER(\"$symbol\");\n";
       print "\n" unless $_ eq "\n";

=== removed file 'dbug/doinstall.sh'
--- a/dbug/doinstall.sh	2000-07-31 19:29:14 +0000
+++ b/dbug/doinstall.sh	1970-01-01 00:00:00 +0000
@@ -1,15 +0,0 @@
-
-# Warning - first line left blank for sh/csh/ksh compatibility.  Do not
-# remove it.  fnf@Unisoft
-
-# doinstall.sh --- figure out environment and do recursive make with
-# appropriate pathnames.  Works under SV or BSD.
-
-if [ -r /usr/include/search.h ]
-then
-	# System V
-	$* LLIB=/usr/lib
-else
-	# 4.2 BSD
-	$* LLIB=/usr/lib/lint
-fi

=== removed file 'dbug/install.sh'
--- a/dbug/install.sh	2000-07-31 19:29:14 +0000
+++ b/dbug/install.sh	1970-01-01 00:00:00 +0000
@@ -1,64 +0,0 @@
-
-#	WARNING -- first line intentionally left blank for sh/csh/ksh
-#	compatibility.  Do not remove it!  FNF, UniSoft Systems.
-#
-#	Usage is:
-#			install <from> <to>
-#
-#	The file <to> is replaced with the file <from>, after first
-#	moving <to> to a backup file.  The backup file name is created
-#	by prepending the filename (after removing any leading pathname
-#	components) with "OLD".
-#
-#	This script is currently not real robust in the face of signals
-#	or permission problems.  It also does not do (by intention) all
-#	the things that the System V or BSD install scripts try to do
-#
-
-if [ $# -ne 2 ]
-then
-	echo  "usage: $0 <from> <to>"
-	exit 1
-fi
-
-# Now extract the dirname and basename components.  Unfortunately, BSD does
-# not have dirname, so we do it the hard way.
-
-fd=`expr $1'/' : '\(/\)[^/]*/$' \| $1'/' : '\(.*[^/]\)//*[^/][^/]*//*$' \| .`
-ff=`basename $1`
-td=`expr $2'/' : '\(/\)[^/]*/$' \| $2'/' : '\(.*[^/]\)//*[^/][^/]*//*$' \| .`
-tf=`basename $2`
-
-# Now test to make sure that they are not the same files.
-
-if [ $fd/$ff = $td/$tf ]
-then
-	echo "install: input and output are same files"
-	exit 2
-fi
-
-# Save a copy of the "to" file as a backup.
-
-if test -f $td/$tf
-then
-	if test -f $td/OLD$tf
-	then
-		rm -f $td/OLD$tf
-	fi
-	mv $td/$tf $td/OLD$tf
-	if [ $? != 0 ]
-	then
-		exit 3
-	fi
-fi
-
-# Now do the copy and return appropriate status
-
-cp $fd/$ff $td/$tf
-if [ $? != 0 ]
-then
-	exit 4
-else
-	exit 0
-fi
-

=== removed file 'dbug/mklintlib.sh'
--- a/dbug/mklintlib.sh	2000-07-31 19:29:14 +0000
+++ b/dbug/mklintlib.sh	1970-01-01 00:00:00 +0000
@@ -1,30 +0,0 @@
-
-# Warning - first line left blank for sh/csh/ksh compatibility.  Do not
-# remove it.  fnf@Unisoft
-
-# mklintlib --- make a lint library, under either System V or 4.2 BSD
-#
-# usage:  mklintlib <infile> <outfile>
-#
-
-if test $# -ne 2
-then
-	echo "usage: mklintlib <infile> <outfile>"
-	exit 1
-fi
-
-if grep SIGTSTP /usr/include/signal.h >/dev/null
-then							# BSD
-	if test -r /usr/include/whoami.h		# 4.1
-	then
-		/lib/cpp -C -Dlint $1 >hlint
-		(/usr/lib/lint/lint1 <hlint >$2) 2>&1 | grep -v warning
-	else						# 4.2
-		lint -Cxxxx $1
-		mv llib-lxxxx.ln $2
-	fi
-else							# USG
-	cc -E -C -Dlint $1 | /usr/lib/lint1 -vx -Hhlint >$2
-	rm -f hlint
-fi
-exit 0							# don't kill make

=== removed file 'dbug/qmake.cmd'
--- a/dbug/qmake.cmd	2000-07-31 19:29:14 +0000
+++ b/dbug/qmake.cmd	1970-01-01 00:00:00 +0000
@@ -1,4 +0,0 @@
-CL -I\my\include -AL -Gsm2 -FPi -DDBUG_OFF *.c
-rm \my\lib\dbug.lib
-lib.exe \my\lib\dbug dbug.obj sanity.obj;
-link /NOD /STACK:8000 main factoria,factoria,,DBUG+STRINGS+LLIBCEP+DOSCALLS;

=== added file 'dbug/remove_function_from_trace.pl'
--- a/dbug/remove_function_from_trace.pl	1970-01-01 00:00:00 +0000
+++ b/dbug/remove_function_from_trace.pl	2009-10-30 18:13:58 +0000
@@ -0,0 +1,26 @@
+#!/usr/bin/perl
+
+
+die <<EEE unless @ARGV;
+Usage: $0 func1 [func2 [ ...] ]
+
+This filter (stdin->stdout) removes lines from dbug trace that were generated
+by specified functions and all functions down the call stack. Produces the
+same effect as if the original source had DBUG_PUSH(""); right after
+DBUG_ENTER() and DBUG_POP(); right before DBUG_RETURN in every such a function.
+EEE
+
+$re=join('|', @ARGV);
+$skip='';
+
+while(<STDIN>) {
+  print unless $skip;
+  next unless /^(?:.*: )*((?:\| )*)([<>])($re)\n/o;
+  if ($2 eq '>') {
+    $skip=$1.$3 unless $skip;
+    next;
+  }
+  next if $skip ne $1.$3;
+  $skip='';
+  print;
+}

=== added file 'dbug/tests-t.pl'
--- a/dbug/tests-t.pl	1970-01-01 00:00:00 +0000
+++ b/dbug/tests-t.pl	2009-10-30 18:13:58 +0000
@@ -0,0 +1,496 @@
+#!/usr/bin/env perl
+
+#
+#  A driver program to test DBUG features - runs tests (shell commands)
+#  from the end of file to invoke tests.c, which does the real dbug work.
+#
+
+use Test::More;
+
+$exe=$0;
+
+die unless $exe =~ s/(tests)-t(\.exe)?$/$1$2 /;
+
+# load tests
+@tests=();
+while (<DATA>) {
+  if (/^% \.\/tests /) {
+    push @tests, [ $' ]
+  } elsif (/^#/) {
+    next;
+  } else {
+    push @{$tests[$#tests]}, $_
+  }
+}
+
+plan skip_all => "because dbug is disabled" if system $exe;
+
+plan tests => scalar(@tests);
+
+for (@tests) {
+  $t=$exe . shift @$_;
+  chomp($t);
+  open F, '-|',  $t or die "open($t|): $!";
+  local $";
+  $out=join($", <F>); close(F);
+  # special cases are handled here:
+  $out =~ s/Memory: 0x[0-9A-Fa-f]+/Memory: 0x####/g if $t =~ /dump/;
+  # compare ("\n" at the beginning makes better output in case of errors)
+  is("\n$out","\n@$_", $t);
+}
+
+__DATA__
+% ./tests -#d
+func2: info: s=ok
+=> execute
+=> evaluate: ON
+=> evaluate_if: OFF
+main: explain: dbug explained: d
+func2: info: s=ok
+% ./tests d,ret3
+=> evaluate: OFF
+=> evaluate_if: OFF
+#
+## Testing negative lists
+#
+% ./tests d:-d,ret3
+func2: info: s=ko
+=> execute
+=> evaluate: ON
+=> evaluate_if: OFF
+main: explain: dbug explained: d:-d,ret3
+func2: info: s=ko
+% ./tests t:-d,ret3
+>main
+| >func1
+| | >func2
+| | | >func3
+| | | <func3
+| | <func2
+| <func1
+=> evaluate: OFF
+=> evaluate_if: OFF
+| >func2
+| | >func3
+| | <func3
+| <func2
+<main
+% ./tests t:d,info:-d,ret3
+>main
+| >func1
+| | >func2
+| | | >func3
+| | | <func3
+| | | info: s=ko
+| | <func2
+| <func1
+=> evaluate: OFF
+=> evaluate_if: OFF
+| >func2
+| | >func3
+| | <func3
+| | info: s=ko
+| <func2
+<main
+% ./tests t:d,info:-d,ret3:-f,func2
+>main
+| >func1
+| | | >func3
+| | | <func3
+| <func1
+=> evaluate: OFF
+=> evaluate_if: OFF
+| | >func3
+| | <func3
+<main
+% ./tests t:d,info:-d,ret3:-f,func2 d,evaluate
+=> evaluate: ON
+=> evaluate_if: OFF
+% ./tests t:d,info:-d,ret3:-f,func2 d,evaluate_if
+=> evaluate: OFF
+=> evaluate_if: ON
+% ./tests t:d:-d,ret3:-f,func2 d,evaluate_if
+=> evaluate: OFF
+=> evaluate_if: ON
+% ./tests t:d:-d,ret3:-f,func2
+>main
+| >func1
+| | | >func3
+| | | <func3
+| <func1
+=> execute
+=> evaluate: ON
+=> evaluate_if: OFF
+| explain: dbug explained: d:-d,ret3:f:-f,func2:t
+| | >func3
+| | <func3
+<main
+#
+## Adding incremental settings to the brew
+#
+% ./tests t:d:-d,ret3:-f,func2 +d,evaluate_if
+>main
+| >func1
+| | | >func3
+| | | <func3
+| <func1
+=> evaluate: OFF
+=> evaluate_if: ON
+| | >func3
+| | <func3
+<main
+#
+## DBUG_DUMP
+#
+% ./tests t:d:-d,ret3:f:-f,func2 +d,dump
+>main
+| >func1
+| | | >func3
+| | | <func3
+| <func1
+| dump: Memory: 0x####  Bytes: (27)
+64 2C 64 75 6D 70 3A 2D 64 2C 72 65 74 33 3A 66 3A 2D 66 2C 66 75 6E 63 32 3A 
+74 
+=> evaluate: OFF
+=> evaluate_if: OFF
+| | >func3
+| | <func3
+<main
+% ./tests t:d:-d,ret3:f:-f,func2 +d,dump
+>main
+| >func1
+| | | >func3
+| | | <func3
+| <func1
+| dump: Memory: 0x####  Bytes: (27)
+64 2C 64 75 6D 70 3A 2D 64 2C 72 65 74 33 3A 66 3A 2D 66 2C 66 75 6E 63 32 3A 
+74 
+=> evaluate: OFF
+=> evaluate_if: OFF
+| | >func3
+| | <func3
+<main
+% ./tests t:d:-d,ret3:f:-f,func2:+d,dump
+>main
+| >func1
+| | | >func3
+| | | <func3
+| <func1
+| dump: Memory: 0x####  Bytes: (27)
+64 2C 64 75 6D 70 3A 2D 64 2C 72 65 74 33 3A 66 3A 2D 66 2C 66 75 6E 63 32 3A 
+74 
+=> evaluate: OFF
+=> evaluate_if: OFF
+| | >func3
+| | <func3
+<main
+% ./tests t:d:-d,ret3:f:-f,func2 +d,dump,explain
+>main
+| >func1
+| | | >func3
+| | | <func3
+| <func1
+| dump: Memory: 0x####  Bytes: (35)
+64 2C 64 75 6D 70 2C 65 78 70 6C 61 69 6E 3A 2D 64 2C 72 65 74 33 3A 66 3A 2D 
+66 2C 66 75 6E 63 32 3A 74 
+=> evaluate: OFF
+=> evaluate_if: OFF
+| explain: dbug explained: d,dump,explain:-d,ret3:f:-f,func2:t
+| | >func3
+| | <func3
+<main
+% ./tests t:d:-d,ret3:f:-f,func2 +d,dump,explain:P
+dbug: >main
+dbug-tests: | >func1
+dbug-tests: | | | >func3
+dbug-tests: | | | <func3
+dbug-tests: | <func1
+dbug-tests: | dump: Memory: 0x####  Bytes: (37)
+64 2C 64 75 6D 70 2C 65 78 70 6C 61 69 6E 3A 2D 64 2C 72 65 74 33 3A 66 3A 2D 
+66 2C 66 75 6E 63 32 3A 50 3A 74 
+=> evaluate: OFF
+=> evaluate_if: OFF
+dbug-tests: | explain: dbug explained: d,dump,explain:-d,ret3:f:-f,func2:P:t
+dbug-tests: | | >func3
+dbug-tests: | | <func3
+dbug-tests: <main
+% ./tests t:d:-d,ret3:f:-f,func2 +d,dump,explain:P:F
+dbug:        tests.c: >main
+dbug-tests:        tests.c: | >func1
+dbug-tests:        tests.c: | | | >func3
+dbug-tests:        tests.c: | | | <func3
+dbug-tests:        tests.c: | <func1
+dbug-tests:        tests.c: | dump: Memory: 0x####  Bytes: (39)
+64 2C 64 75 6D 70 2C 65 78 70 6C 61 69 6E 3A 2D 64 2C 72 65 74 33 3A 66 3A 2D 
+66 2C 66 75 6E 63 32 3A 46 3A 50 3A 74 
+=> evaluate: OFF
+=> evaluate_if: OFF
+dbug-tests:        tests.c: | explain: dbug explained: d,dump,explain:-d,ret3:f:-f,func2:F:P:t
+dbug-tests:        tests.c: | | >func3
+dbug-tests:        tests.c: | | <func3
+dbug-tests:        tests.c: <main
+#
+## DBUG_EXPLAIN, DBUG_PUSH, DBUG_POP, DBUG_SET
+#
+% ./tests t:d:-d,ret3:f:-f,func2
+>main
+| >func1
+| | | >func3
+| | | <func3
+| <func1
+=> execute
+=> evaluate: ON
+=> evaluate_if: OFF
+| explain: dbug explained: d:-d,ret3:f:-f,func2:t
+| | >func3
+| | <func3
+<main
+% ./tests t:d:-d,ret3
+>main
+| >func1
+| | >func2
+| | | >func3
+| | | <func3
+| | | info: s=ko
+| | <func2
+| <func1
+=> execute
+=> evaluate: ON
+=> evaluate_if: OFF
+| explain: dbug explained: d:-d,ret3:t
+| >func2
+| | >func3
+| | <func3
+| | info: s=ko
+| <func2
+<main
+% ./tests d,info:-d,ret3:d,push
+func2: info: s=ko
+=> evaluate: OFF
+=> evaluate_if: OFF
+| >func2
+| | >func3
+| | <func3
+| | info: s=ko
+| <func2
+<main
+% ./tests d,info:-d,ret3:d,push,explain
+func2: info: s=ko
+=> evaluate: OFF
+=> evaluate_if: OFF
+| explain: dbug explained: d,info,push,explain:-d,ret3:t
+| >func2
+| | >func3
+| | <func3
+| | info: s=ko
+| <func2
+<main
+% ./tests d,info:-d,ret3:d,explain
+func2: info: s=ko
+=> evaluate: OFF
+=> evaluate_if: OFF
+main: explain: dbug explained: d,info,explain:-d,ret3
+func2: info: s=ko
+% ./tests d,info:-d,ret3:d,explain,pop
+func2: info: s=ko
+=> evaluate: OFF
+=> evaluate_if: OFF
+% ./tests d,info:-d,ret3:d,explain t:d,pop
+>main
+| >func1
+| | >func2
+| | | >func3
+| | | <func3
+| | <func2
+| <func1
+=> evaluate: OFF
+=> evaluate_if: OFF
+main: explain: dbug explained: d,info,explain:-d,ret3
+func2: info: s=ko
+% ./tests d,info:-d,ret3:d,explain,pop +t
+>main
+| >func1
+| | >func2
+| | | >func3
+| | | <func3
+| | | info: s=ko
+| | <func2
+| <func1
+=> evaluate: OFF
+=> evaluate_if: OFF
+main: explain: dbug explained: d,info,explain,pop:-d,ret3
+func2: info: s=ko
+% ./tests d,info:-d,ret3:d,explain,set
+func2: info: s=ko
+=> evaluate: OFF
+=> evaluate_if: OFF
+       tests.c: main: explain: dbug explained: d,info,explain,set:-d,ret3:F
+       tests.c: func2: info: s=ko
+% ./tests d,info:-d,ret3:d,explain,set:t
+>main
+| >func1
+| | >func2
+| | | >func3
+| | | <func3
+| | | info: s=ko
+| | <func2
+| <func1
+=> evaluate: OFF
+=> evaluate_if: OFF
+       tests.c: | explain: dbug explained: d,info,explain,set:-d,ret3:F:t
+       tests.c: | >func2
+       tests.c: | | >func3
+       tests.c: | | <func3
+       tests.c: | | info: s=ko
+       tests.c: | <func2
+       tests.c: <main
+% ./tests t d,info:-d,ret3:d,explain,set:t
+>main
+| >func1
+| | >func2
+| | | >func3
+| | | <func3
+| | | info: s=ko
+| | <func2
+| <func1
+=> evaluate: OFF
+=> evaluate_if: OFF
+       tests.c: | explain: dbug explained: d,info,explain,set:-d,ret3:F:t
+       tests.c: | >func2
+       tests.c: | | >func3
+       tests.c: | | <func3
+       tests.c: | | info: s=ko
+       tests.c: | <func2
+       tests.c: <main
+% ./tests t d,info:-d,ret3:d,explain,set,pop
+func2: info: s=ko
+=> evaluate: OFF
+=> evaluate_if: OFF
+| >func2
+| | >func3
+| | <func3
+| <func2
+<main
+% ./tests t:f,func2
+| | >func2
+| | <func2
+=> evaluate: OFF
+=> evaluate_if: OFF
+| >func2
+| <func2
+#
+## Testing SUBDIR rules
+#
+% ./tests t:-f,func2/:d
+>main
+| >func1
+| <func1
+=> execute
+=> evaluate: ON
+=> evaluate_if: OFF
+| explain: dbug explained: d:f:-f,func2/:t
+<main
+% ./tests t:f,func1/:d
+| >func1
+| | >func2
+| | | >func3
+| | | <func3
+| | | info: s=ok
+| | <func2
+| <func1
+=> evaluate: OFF
+=> evaluate_if: OFF
+% ./tests t:f,main/:d,pop
+>main
+| >func1
+| | >func2
+| | | >func3
+| | | <func3
+| | <func2
+| <func1
+=> evaluate: OFF
+=> evaluate_if: OFF
+% ./tests f,main/:d,push
+=> evaluate: OFF
+=> evaluate_if: OFF
+| >func2
+| | >func3
+| | <func3
+| <func2
+<main
+#
+## Testing FixTraceFlags() - when we need to traverse the call stack
+# (these tests fail with FixTraceFlags() disabled)
+#
+# delete the INCLUDE rule up the stack
+% ./tests t:f,func1/ --push1=t:f,func3/
+| >func1
+| | >func2
+| | | >func3
+| | | <func3
+| | <func2
+=> push1
+=> evaluate: OFF
+=> evaluate_if: OFF
+| | >func3
+| | <func3
+# delete the EXCLUDE rule up the stack
+% ./tests t:-f,func1/ --push1=t
+>main
+=> push1
+| <func1
+=> evaluate: OFF
+=> evaluate_if: OFF
+| >func2
+| | >func3
+| | <func3
+| <func2
+<main
+# add the INCLUDE rule up the stack
+% ./tests t:f,func3 --push1=t:f,main/
+| | | >func3
+| | | <func3
+=> push1
+| <func1
+=> evaluate: OFF
+=> evaluate_if: OFF
+| >func2
+| | >func3
+| | <func3
+| <func2
+<main
+# add the EXCLUDE rule up the stack
+% ./tests t --push1=t:-f,main/
+>main
+| >func1
+| | >func2
+| | | >func3
+| | | <func3
+| | <func2
+=> push1
+=> evaluate: OFF
+=> evaluate_if: OFF
+# change the defaults
+% ./tests t:f,func3 --push1=t
+| | | >func3
+| | | <func3
+=> push1
+| <func1
+=> evaluate: OFF
+=> evaluate_if: OFF
+| >func2
+| | >func3
+| | <func3
+| <func2
+<main
+# repeated keyword
+% ./tests d:-d,info,info
+=> execute
+=> evaluate: ON
+=> evaluate_if: OFF
+main: explain: dbug explained: d:-d,info
+% ./tests d:-d,info/,info
+=> execute
+=> evaluate: ON
+=> evaluate_if: OFF
+main: explain: dbug explained: d:-d,info/

=== added file 'dbug/tests.c'
--- a/dbug/tests.c	1970-01-01 00:00:00 +0000
+++ b/dbug/tests.c	2009-10-30 18:13:58 +0000
@@ -0,0 +1,87 @@
+/*
+  A program to test DBUG features. Used by tests-t.pl
+*/
+
+char *push1=0;
+
+#include <my_global.h>  /* This includes dbug.h */
+#include <my_pthread.h>
+#include <string.h>
+
+const char *func3()
+{
+  DBUG_ENTER("func3");
+  DBUG_RETURN(DBUG_EVALUATE("ret3", "ok", "ko"));
+}
+
+void func2()
+{
+  const char *s;
+  DBUG_ENTER("func2");
+  s=func3();
+  DBUG_PRINT("info", ("s=%s", s));
+  DBUG_VOID_RETURN;
+}
+
+int func1()
+{
+  DBUG_ENTER("func1");
+  func2();
+  if (push1)
+  {
+    DBUG_PUSH(push1);
+    fprintf(DBUG_FILE, "=> push1\n");
+  }
+  DBUG_RETURN(10);
+}
+
+int main (int argc, char *argv[])
+{
+  int i;
+#ifdef DBUG_OFF
+  return 1;
+#endif
+  if (argc == 1)
+    return 0;
+
+#if defined(HAVE_PTHREAD_INIT) && defined(THREAD)
+  pthread_init();                       /* Must be called before DBUG_ENTER */
+#endif
+#ifdef THREAD
+  my_thread_global_init();
+#endif
+  dup2(1, 2);
+  for (i = 1; i < argc; i++)
+  {
+    if (strncmp(argv[i], "--push1=", 8) == 0)
+      push1=argv[i]+8;
+    else
+      DBUG_PUSH (argv[i]);
+  }
+  {
+    DBUG_ENTER ("main");
+    DBUG_PROCESS ("dbug-tests");
+    func1();
+    DBUG_EXECUTE_IF("dump",
+    {
+      char s[1000];
+      DBUG_EXPLAIN(s, sizeof(s)-1);
+      DBUG_DUMP("dump", (uchar*)s, strlen(s));
+    });
+    DBUG_EXECUTE_IF("push",  DBUG_PUSH("+t"); );
+    DBUG_EXECUTE("execute", fprintf(DBUG_FILE, "=> execute\n"); );
+    DBUG_EXECUTE_IF("set",  DBUG_SET("+F"); );
+    fprintf(DBUG_FILE, "=> evaluate: %s\n",
+            DBUG_EVALUATE("evaluate", "ON", "OFF"));
+    fprintf(DBUG_FILE, "=> evaluate_if: %s\n",
+            DBUG_EVALUATE_IF("evaluate_if", "ON", "OFF"));
+    DBUG_EXECUTE_IF("pop",  DBUG_POP(); );
+    {
+      char s[1000] __attribute__((unused));
+      DBUG_EXPLAIN(s, sizeof(s)-1);
+      DBUG_PRINT("explain", ("dbug explained: %s", s));
+    }
+    func2();
+    DBUG_RETURN (0);
+  }
+}

=== modified file 'dbug/user.r'
--- a/dbug/user.r	2009-06-05 12:30:57 +0000
+++ b/dbug/user.r	2009-10-30 18:13:58 +0000
@@ -512,7 +512,7 @@ possible since all code preceding the fi
 .B DBUG_PUSH 
 is
 essentially invisible to 
-.B dbug
+.I dbug
 (this can be worked around by
 inserting a temporary 
 .B DBUG_PUSH(argv[1])
@@ -708,7 +708,7 @@ EX:\ \fCDBUG_PROCESS\ (argv[0]);\fR
 .SP 1
 .LI DBUG_PUSH\ 
 Sets a new debugger state by pushing the current
-.B dbug
+.I dbug
 state onto an internal stack and setting up the new state using the
 debug control string passed as the macro argument.  The most common
 usage is to set the state specified by a debug control string
@@ -769,14 +769,14 @@ the 'd' flag. Used to conditionally exec
 to crash the program testing how recovery works, or to introduce an
 artificial delay checking for race conditions.
 .SP 1
-EX:\ \fCDBUG_EXECUTE_IF\ ("crashme",\ abort\ ());\fR
+EX:\ \fCDBUG_EXECUTE_IF\ ("crashme",\ DBUG_ABORT()\ ());\fR
 .SP 1
 .LI DBUG_EVALUATE\ 
 The DBUG_EVALUATE macro is similar to DBUG_EXECUTE, but it can be used in
 the expression context. The first argument is the debug keyword that is used to
 choose whether the second (keyword is enabled) or the third (keyword is not
 enabled) argument is evaluated. When
-.B dbug
+.I dbug
 is compiled off, the third argument is evaluated.
 .SP 1
 EX:\fC
@@ -796,7 +796,7 @@ EX:\fC
 .br
     if (prepare_transaction () ||
 .br
-        DBUG_EVALUATE ("crashme", (abort (), 0), 0) ||
+        DBUG_EVALUATE ("crashme", (DBUG_ABORT(), 0), 0) ||
 .br
         commit_transaction () )\fR
 .SP 1
@@ -875,6 +875,12 @@ library. So there will be no need to dis
 .SP 1
 EX:\ \fCDBUG_ASSERT(\ a\ >\ 0\ );\fR
 .SP 1
+.LI DBUG_ABORT\ 
+This macro could be used instead of abort(). It flushes DBUG_FILE stream
+to ensure that no
+.I dbug
+output is lost and then calls abort().
+.SP 1
 .LI DBUG_EXPLAIN\ 
 Generates control string corresponding to the current debug state.
 The macro takes two arguments - a buffer to store the result string
@@ -910,17 +916,17 @@ via the 
 .B DBUG_PUSH 
 or
 .B DBUG_SET
-macros. Control string consists of colon separate flags.  Colons
+macros. Control string consists of colon separated flags.  Colons
 that are part of ':\\',  ':/', or '::' are not considered flag
 separators. A flag may take an argument or a list of arguments.
 If a control string starts from a '+' sign it works
 .I incrementally,
-that is, it can modify existing state without overriding it. In such a
-string every flag may be preceded by a '+' or '-' to enable or disable
-a corresponding option in the debugger state.  This section summarizes
-the currently available debugger options and the flag characters which
-enable or disable them.  Argument lists enclosed in '[' and ']' are
-optional.
+that is, it can modify existing state without overriding it.  Every
+flag may be preceded by a '+' or '-' to enable or disable a
+corresponding option in the debugger state or to add or remove
+arguments to the list. This section summarizes the currently available
+debugger options and the flag characters which enable or disable them.
+Argument lists enclosed in '[' and ']' are optional.
 .SP 2
 .BL 22
 .LI a[,file]
@@ -936,6 +942,9 @@ a complete log file in case of crashes. 
 multi-threaded environment.
 .LI d[,keywords]
 Enable output from macros with specified keywords.
+Every keyword can be a
+.I glob(7)
+pattern.
 An empty list of keywords implies that all keywords are selected.
 .LI D[,time]
 Delay for specified time after each output line, to let output drain.
@@ -943,7 +952,19 @@ Time is given in tenths of a second (val
 Default is zero.
 .LI f[,functions]
 Limit debugger actions to the specified list of functions.
+Every function can be a
+.I glob(7)
+pattern.
 An empty list of functions implies that all functions are selected.
+Every function in the list may optionally be followed by a '/' -
+this will implicitly select all the functions down the call stack.
+.SP 1
+EX: \fCf,func1,func2/:-f,func3,func4/\fR
+.SP 1
+This would enable debugger in functions 'func1()', 'func2()' and all
+functions called from it (directly or indirectly). But not in
+functions 'func3()' or 'func4()' and all functions called from
+it.
 .LI F
 Mark each debugger output line with the name of the source file
 containing the macro causing the output.
@@ -952,6 +973,9 @@ Mark each debugger output line with the 
 current process.
 .LI g,[functions]
 Enable profiling for the specified list of functions.
+Every function can be a
+.I glob(7)
+pattern.
 An empty list of functions enables profiling for all functions.
 See
 .B PROFILING\ WITH\ DBUG
@@ -970,7 +994,11 @@ Like 'a[,file]' but overwrite old file, 
 .LI O[,file]
 Like 'A[,file]' but overwrite old file, do not append.
 .LI p[,processes]
-Limit debugger actions to the specified processes.  An empty list
+Limit debugger actions to the specified processes.
+Every name can be a
+.I glob(7)
+pattern.
+An empty list
 implies all processes.  This is useful for processes which run child
 processes.  Note that each debugger output line can be marked with the
 name of the current process via the 'P' flag.  The process name must

=== removed file 'dbug/vargs.h'
--- a/dbug/vargs.h	2000-07-31 19:29:14 +0000
+++ b/dbug/vargs.h	1970-01-01 00:00:00 +0000
@@ -1,139 +0,0 @@
-/******************************************************************************
- *									      *
- *				   N O T I C E				      *
- *									      *
- *		      Copyright Abandoned, 1987, Fred Fish		      *
- *									      *
- *									      *
- *	This previously copyrighted work has been placed into the  public     *
- *	domain	by  the  author  and  may be freely used for any purpose,     *
- *	private or commercial.						      *
- *									      *
- *	Because of the number of inquiries I was receiving about the  use     *
- *	of this product in commercially developed works I have decided to     *
- *	simply make it public domain to further its unrestricted use.	I     *
- *	specifically  would  be  most happy to see this material become a     *
- *	part of the standard Unix distributions by AT&T and the  Berkeley     *
- *	Computer  Science  Research Group, and a standard part of the GNU     *
- *	system from the Free Software Foundation.			      *
- *									      *
- *	I would appreciate it, as a courtesy, if this notice is  left  in     *
- *	all copies and derivative works.  Thank you.			      *
- *									      *
- *	The author makes no warranty of any kind  with	respect  to  this     *
- *	product  and  explicitly disclaims any implied warranties of mer-     *
- *	chantability or fitness for any particular purpose.		      *
- *									      *
- ******************************************************************************
- */
-
-
-/*
- *  FILE
- *
- *	vargs.h    include file for environments without varargs.h
- *
- *  SCCS
- *
- *	@(#)vargs.h	1.2	5/8/88
- *
- *  SYNOPSIS
- *
- *	#include "vargs.h"
- *
- *  DESCRIPTION
- *
- *	This file implements a varargs macro set for use in those
- *	environments where there is no system supplied varargs.  This
- *	generally works because systems which don't supply a varargs
- *	package are precisely those which don't strictly need a varargs
- *	package.  Using this one then allows us to minimize source
- *	code changes.  So in some sense, this is a "portable" varargs
- *	since it is only used for convenience, when it is not strictly
- *	needed.
- *
- */
-
-/*
- *	These macros allow us to rebuild an argument list on the stack
- *	given only a va_list.  We can use these to fake a function like
- *	vfprintf, which gets a fixed number of arguments, the last of
- *	which is a va_list, by rebuilding a stack and calling the variable
- *	argument form fprintf.	Of course this only works when vfprintf
- *	is not available in the host environment, and thus is not available
- *	for fprintf to call (which would give us an infinite loop).
- *
- *	Note that ARGS_TYPE is a long, which lets us get several bytes
- *	at a time while also preventing lots of "possible pointer alignment
- *	problem" messages from lint.  The messages are valid, because this
- *	IS nonportable, but then we should only be using it in very
- *	nonrestrictive environments, and using the real varargs where it
- *	really counts.
- *
- */
-
-#define ARG0 a0
-#define ARG1 a1
-#define ARG2 a2
-#define ARG3 a3
-#define ARG4 a4
-#define ARG5 a5
-#define ARG6 a6
-#define ARG7 a7
-#define ARG8 a8
-#define ARG9 a9
-
-#define ARGS_TYPE long
-#define ARGS_LIST ARG0,ARG1,ARG2,ARG3,ARG4,ARG5,ARG6,ARG7,ARG8,ARG9
-#define ARGS_DCL auto ARGS_TYPE ARGS_LIST
-
-/*
- *	A pointer of type "va_list" points to a section of memory
- *	containing an array of variable sized arguments of unknown
- *	number.  This pointer is initialized by the va_start
- *	macro to point to the first byte of the first argument.
- *	We can then use it to walk through the argument list by
- *	incrementing it by the size of the argument being referenced.
- */
-
-typedef char *va_list;
-
-/*
- *	The first variable argument overlays va_alist, which is
- *	nothing more than a "handle" which allows us to get the
- *	address of the first argument on the stack.  Note that
- *	by definition, the va_dcl macro includes the terminating
- *	semicolon, which makes use of va_dcl in the source code
- *	appear to be missing a semicolon.
- */
-
-#define va_dcl ARGS_TYPE va_alist;
-
-/*
- *	The va_start macro takes a variable of type "va_list" and
- *	initializes it.  In our case, it initializes a local variable
- *	of type "pointer to char" to point to the first argument on
- *	the stack.
- */
-
-#define va_start(list) list = (char *) &va_alist
-
-/*
- *	The va_end macro is a null operation for our use.
- */
-
-#define va_end(list)
-
-/*
- *	The va_arg macro is the tricky one.  This one takes
- *	a va_list as the first argument, and a type as the second
- *	argument, and returns a value of the appropriate type
- *	while advancing the va_list to the following argument.
- *	For our case, we first increment the va_list arg by the
- *	size of the type being recovered, cast the result to
- *	a pointer of the appropriate type, and then dereference
- *	that pointer as an array to get the previous arg (which
- *	is the one we wanted.
- */
-
-#define va_arg(list,type) ((type *) (list += sizeof (type)))[-1]

=== modified file 'include/my_dbug.h'
--- a/include/my_dbug.h	2009-10-22 22:30:28 +0000
+++ b/include/my_dbug.h	2009-10-30 18:13:58 +0000
@@ -16,103 +16,64 @@
 #ifndef _dbug_h
 #define _dbug_h
 
-#if defined(__cplusplus) && !defined(DBUG_OFF)
-class Dbug_violation_helper
-{
-public:
-  inline Dbug_violation_helper() :
-    _entered(TRUE)
-  { }
-
-  inline ~Dbug_violation_helper()
-  {
-    assert(!_entered);
-  }
-
-  inline void leave()
-  {
-    _entered= FALSE;
-  }
-
-private:
-  bool _entered;
-};
-#endif /* C++ */
-
-#ifdef	__cplusplus
+#ifdef  __cplusplus
 extern "C" {
 #endif
 #if !defined(DBUG_OFF) && !defined(_lint)
-struct _db_code_state_;
-extern	int _db_keyword_(struct _db_code_state_ *cs, const char *keyword);
-extern  int _db_keywords_(const char *, const char *);
-extern  int _db_strict_keyword_(const char *keyword);
+
+struct _db_stack_frame_ {
+  const char *func;      /* function name of the previous stack frame       */
+  const char *file;      /* filename of the function of previous frame      */
+  uint level;            /* this nesting level, highest bit enables tracing */
+  struct _db_stack_frame_ *prev; /* pointer to the previous frame */
+};
+
+struct  _db_code_state_;
+extern  my_bool _dbug_on_;
+extern  my_bool _db_keyword_(struct _db_code_state_ *, const char *, int);
 extern  int _db_explain_(struct _db_code_state_ *cs, char *buf, size_t len);
 extern  int _db_explain_init_(char *buf, size_t len);
-extern	void _db_setjmp_(void);
-extern	void _db_longjmp_(void);
+extern	int _db_is_pushed_(void);
+extern  void _db_setjmp_(void);
+extern  void _db_longjmp_(void);
 extern  void _db_process_(const char *name);
-extern	void _db_push_(const char *control);
-extern	void _db_pop_(void);
-extern  void _db_set_(struct _db_code_state_ *cs, const char *control);
+extern  void _db_push_(const char *control);
+extern  void _db_pop_(void);
+extern  void _db_set_(const char *control);
 extern  void _db_set_init_(const char *control);
-extern	void _db_enter_(const char *_func_,const char *_file_,uint _line_,
-			const char **_sfunc_,const char **_sfile_,
-			uint *_slevel_, char ***);
-extern	void _db_return_(uint _line_,const char **_sfunc_,const char **_sfile_,
-			 uint *_slevel_);
-extern	void _db_pargs_(uint _line_,const char *keyword);
-extern	void _db_doprnt_ _VARARGS((const char *format,...))
+extern void _db_enter_(const char *_func_, const char *_file_, uint _line_,
+                       struct _db_stack_frame_ *_stack_frame_);
+extern  void _db_return_(uint _line_, struct _db_stack_frame_ *_stack_frame_);
+extern  void _db_pargs_(uint _line_,const char *keyword);
+extern  void _db_doprnt_ _VARARGS((const char *format,...))
   ATTRIBUTE_FORMAT(printf, 1, 2);
-extern	void _db_dump_(uint _line_,const char *keyword,
+extern  void _db_dump_(uint _line_,const char *keyword,
                        const unsigned char *memory, size_t length);
-extern	void _db_end_(void);
-extern	void _db_lock_file_(void);
-extern	void _db_unlock_file_(void);
-extern FILE *_db_fp_(void);
+extern  void _db_end_(void);
+extern  void _db_lock_file_(void);
+extern  void _db_unlock_file_(void);
+extern  FILE *_db_fp_(void);
+extern  void _db_flush_();
 extern  const char* _db_get_func_(void);
 
-#ifdef __cplusplus
-
-#define DBUG_ENTER(a) \
-        const char *_db_func_, *_db_file_; \
-        uint _db_level_; \
-        char **_db_framep_; \
-        Dbug_violation_helper dbug_violation_helper; \
-        _db_enter_ (a, __FILE__, __LINE__, &_db_func_, &_db_file_, \
-                    &_db_level_, &_db_framep_)
-#define DBUG_VIOLATION_HELPER_LEAVE dbug_violation_helper.leave()
-
-#else /* C */
-
-#define DBUG_ENTER(a) \
-        const char *_db_func_, *_db_file_; \
-        uint _db_level_; \
-        char **_db_framep_; \
-        _db_enter_ (a, __FILE__, __LINE__, &_db_func_, &_db_file_, \
-                    &_db_level_, &_db_framep_)
-#define DBUG_VIOLATION_HELPER_LEAVE do { } while(0)
-
-#endif /* C++ */
-
-#define DBUG_LEAVE \
-        DBUG_VIOLATION_HELPER_LEAVE; \
-	_db_return_ (__LINE__, &_db_func_, &_db_file_, &_db_level_)
+#define DBUG_ENTER(a) struct _db_stack_frame_ _db_stack_frame_; \
+        _db_enter_ (a,__FILE__,__LINE__,&_db_stack_frame_)
+#define DBUG_LEAVE _db_return_ (__LINE__, &_db_stack_frame_)
 #define DBUG_RETURN(a1) do {DBUG_LEAVE; return(a1);} while(0)
 #define DBUG_VOID_RETURN do {DBUG_LEAVE; return;} while(0)
 #define DBUG_EXECUTE(keyword,a1) \
-        do {if (_db_keyword_(0, (keyword))) { a1 }} while(0)
+        do {if (_db_keyword_(0, (keyword), 0)) { a1 }} while(0)
 #define DBUG_EXECUTE_IF(keyword,a1) \
-        do {if (_db_strict_keyword_ (keyword)) { a1 } } while(0)
+        do {if (_db_keyword_(0, (keyword), 1)) { a1 }} while(0)
 #define DBUG_EVALUATE(keyword,a1,a2) \
-        (_db_keyword_(0,(keyword)) ? (a1) : (a2))
+        (_db_keyword_(0,(keyword), 0) ? (a1) : (a2))
 #define DBUG_EVALUATE_IF(keyword,a1,a2) \
-        (_db_strict_keyword_((keyword)) ? (a1) : (a2))
+        (_db_keyword_(0,(keyword), 1) ? (a1) : (a2))
 #define DBUG_PRINT(keyword,arglist) \
         do {_db_pargs_(__LINE__,keyword); _db_doprnt_ arglist;} while(0)
 #define DBUG_PUSH(a1) _db_push_ (a1)
 #define DBUG_POP() _db_pop_ ()
-#define DBUG_SET(a1) _db_set_ (0, (a1))
+#define DBUG_SET(a1) _db_set_ (a1)
 #define DBUG_SET_INITIAL(a1) _db_set_init_ (a1)
 #define DBUG_PROCESS(a1) _db_process_(a1)
 #define DBUG_FILE _db_fp_()
@@ -125,54 +86,66 @@ extern  const char* _db_get_func_(void);
 #define DBUG_ASSERT(A) assert(A)
 #define DBUG_EXPLAIN(buf,len) _db_explain_(0, (buf),(len))
 #define DBUG_EXPLAIN_INITIAL(buf,len) _db_explain_init_((buf),(len))
-#define IF_DBUG(A) A
-#define _DBUG_MAX_FUNC_NAME_ 255
+#define DEBUGGER_OFF                    do { _dbug_on_= 0; } while(0)
+#define DEBUGGER_ON                     do { _dbug_on_= 1; } while(0)
+#ifndef __WIN__
+#define DBUG_ABORT()                    (_db_flush_(), abort())
+#else
+/*
+  Avoid popup with abort/retry/ignore buttons. When BUG#31745 is fixed we can
+  call abort() instead of _exit(3) (now it would cause a "test signal" popup).
+*/
+#include <crtdbg.h>
+#define DBUG_ABORT() (_db_flush_(),\
+                     (void)_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE),\
+                     (void)_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR),\
+                     _exit(3))
+#endif
 #define DBUG_CHECK_CRASH(func, op) \
-        do { \
-          if (_db_keywords_((func), (op))) \
-            { abort(); } \
-        } while (0)
+  do { char _dbuf_[255]; strxnmov(_dbuf_, sizeof(_dbuf_)-1, (func), (op)); \
+    DBUG_EXECUTE_IF(_dbuf_, DBUG_ABORT()); } while(0)
 #define DBUG_CRASH_ENTER(func) \
   DBUG_ENTER(func); DBUG_CHECK_CRASH(func, "_crash_enter")
 #define DBUG_CRASH_RETURN(val) \
-  do {DBUG_CHECK_CRASH(_db_get_func_(), "_crash_return"); \
-    DBUG_RETURN(val);} while(0)
+  DBUG_CHECK_CRASH(_db_get_func_(), "_crash_return")
 #define DBUG_CRASH_VOID_RETURN \
-  do {DBUG_CHECK_CRASH (_db_get_func_(), "_crash_return"); \
-    DBUG_VOID_RETURN;} while(0)
-#else						/* No debugger */
+  DBUG_CHECK_CRASH (_db_get_func_(), "_crash_return")
+
+#else                                           /* No debugger */
 
 #define DBUG_ENTER(a1)
 #define DBUG_LEAVE
-#define DBUG_VIOLATION_HELPER_LEAVE
-#define DBUG_RETURN(a1)             do { return(a1); } while(0)
-#define DBUG_VOID_RETURN            do { return; } while(0)
-#define DBUG_EXECUTE(keyword,a1)    do { } while(0)
-#define DBUG_EXECUTE_IF(keyword,a1) do { } while(0)
+#define DBUG_RETURN(a1)                 do { return(a1); } while(0)
+#define DBUG_VOID_RETURN                do { return; } while(0)
+#define DBUG_EXECUTE(keyword,a1)        do { } while(0)
+#define DBUG_EXECUTE_IF(keyword,a1)     do { } while(0)
 #define DBUG_EVALUATE(keyword,a1,a2) (a2)
 #define DBUG_EVALUATE_IF(keyword,a1,a2) (a2)
-#define DBUG_PRINT(keyword,arglist) do { } while(0)
-#define DBUG_PUSH(a1)
-#define DBUG_SET(a1)                do { } while(0)
-#define DBUG_SET_INITIAL(a1)        do { } while(0)
-#define DBUG_POP()
-#define DBUG_PROCESS(a1)
+#define DBUG_PRINT(keyword,arglist)     do { } while(0)
+#define DBUG_PUSH(a1)                   do { } while(0)
+#define DBUG_SET(a1)                    do { } while(0)
+#define DBUG_SET_INITIAL(a1)            do { } while(0)
+#define DBUG_POP()                      do { } while(0)
+#define DBUG_PROCESS(a1)                do { } while(0)
 #define DBUG_SETJMP(a1) setjmp(a1)
 #define DBUG_LONGJMP(a1) longjmp(a1)
-#define DBUG_DUMP(keyword,a1,a2)    do { } while(0)
-#define DBUG_END()
-#define DBUG_ASSERT(A)              do { } while(0)
-#define DBUG_LOCK_FILE
+#define DBUG_DUMP(keyword,a1,a2)        do { } while(0)
+#define DBUG_END()                      do { } while(0)
+#define DBUG_ASSERT(A)                  do { } while(0)
+#define DBUG_LOCK_FILE                  do { } while(0)
 #define DBUG_FILE (stderr)
-#define DBUG_UNLOCK_FILE
+#define DBUG_UNLOCK_FILE                do { } while(0)
 #define DBUG_EXPLAIN(buf,len)
 #define DBUG_EXPLAIN_INITIAL(buf,len)
-#define IF_DBUG(A)
+#define DEBUGGER_OFF                    do { } while(0)
+#define DEBUGGER_ON                     do { } while(0)
+#define DBUG_ABORT()                    abort()
 #define DBUG_CRASH_ENTER(func)
-#define DBUG_CRASH_RETURN(val)      do { return(val); } while(0)
-#define DBUG_CRASH_VOID_RETURN      do { return; } while(0)
+#define DBUG_CRASH_RETURN(val)          do { return(val); } while(0)
+#define DBUG_CRASH_VOID_RETURN          do { return; } while(0)
+
 #endif
-#ifdef	__cplusplus
+#ifdef  __cplusplus
 }
 #endif
 #endif

=== modified file 'include/my_global.h'
--- a/include/my_global.h	2009-10-21 10:48:22 +0000
+++ b/include/my_global.h	2009-10-30 18:13:58 +0000
@@ -649,8 +649,6 @@ C_MODE_END
 #  endif
 #endif
 
-#include <my_dbug.h>
-
 #define MIN_ARRAY_SIZE	0	/* Zero or One. Gcc allows zero*/
 #define ASCII_BITS_USED 8	/* Bit char used */
 #define NEAR_F			/* No near function handling */
@@ -1177,6 +1175,8 @@ typedef char		bool;	/* Ordinary boolean 
 #define reg16 register
 #endif
 
+#include <my_dbug.h>
+
 /*
   Sometimes we want to make sure that the variable is not put into
   a register in debugging mode so we can see its value in the core

=== modified file 'include/my_pthread.h'
--- a/include/my_pthread.h	2009-09-30 15:40:12 +0000
+++ b/include/my_pthread.h	2009-10-30 18:13:58 +0000
@@ -670,6 +670,7 @@ struct st_my_thread_var
 };
 
 extern struct st_my_thread_var *_my_thread_var(void) __attribute__ ((const));
+extern void **my_thread_var_dbug();
 extern uint my_thread_end_wait_time;
 #define my_thread_var (_my_thread_var())
 #define my_errno my_thread_var->thr_errno

=== modified file 'libmysql/libmysql.c'
--- a/libmysql/libmysql.c	2009-08-28 16:21:54 +0000
+++ b/libmysql/libmysql.c	2009-10-30 18:13:58 +0000
@@ -131,7 +131,7 @@ int STDCALL mysql_server_init(int argc _
       mysql_port = MYSQL_PORT;
 #ifndef MSDOS
       {
-	struct servent *serv_ptr;
+	struct servent *serv_ptr __attribute__((unused));
 	char	*env;
 
         /*

=== modified file 'mysys/my_thr_init.c'
--- a/mysys/my_thr_init.c	2009-10-14 08:25:39 +0000
+++ b/mysys/my_thr_init.c	2009-10-30 18:13:58 +0000
@@ -387,6 +387,15 @@ const char *my_thread_name(void)
   }
   return tmp->name;
 }
+
+/* Return pointer to DBUG for holding current state */
+
+extern void **my_thread_var_dbug()
+{
+  struct st_my_thread_var *tmp=
+    my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
+  return tmp && tmp->init ? &tmp->dbug : 0;
+}
 #endif /* DBUG_OFF */
 
 

=== modified file 'sql-common/client.c'
--- a/sql-common/client.c	2009-10-27 09:57:44 +0000
+++ b/sql-common/client.c	2009-10-30 18:13:58 +0000
@@ -2389,7 +2389,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,cons
 
       for (i= 0; status && hp->h_addr_list[i]; i++)
       {
-        IF_DBUG(char ipaddr[18];)
+        char ipaddr[18] __attribute__((unused));
         memcpy(&sock_addr.sin_addr, hp->h_addr_list[i],
                min(sizeof(sock_addr.sin_addr), (size_t) hp->h_length));
         DBUG_PRINT("info",("Trying %s...",

=== modified file 'sql/debug_sync.cc'
--- a/sql/debug_sync.cc	2009-10-04 09:53:02 +0000
+++ b/sql/debug_sync.cc	2009-10-30 18:13:58 +0000
@@ -1701,9 +1701,11 @@ uchar *sys_var_debug_sync::value_ptr(THD
 
 static void debug_sync_execute(THD *thd, st_debug_sync_action *action)
 {
-  IF_DBUG(const char *dsp_name= action->sync_point.c_ptr());
-  IF_DBUG(const char *sig_emit= action->signal.c_ptr());
-  IF_DBUG(const char *sig_wait= action->wait_for.c_ptr());
+#ifndef DBUG_OFF
+  const char *dsp_name= action->sync_point.c_ptr();
+  const char *sig_emit= action->signal.c_ptr();
+  const char *sig_wait= action->wait_for.c_ptr();
+#endif
   DBUG_ENTER("debug_sync_execute");
   DBUG_ASSERT(thd);
   DBUG_ASSERT(action);

=== modified file 'sql/field.cc'
--- a/sql/field.cc	2009-10-21 10:48:22 +0000
+++ b/sql/field.cc	2009-10-30 18:13:58 +0000
@@ -6729,9 +6729,8 @@ int Field_string::cmp(const uchar *a_ptr
 
 void Field_string::sort_string(uchar *to,uint length)
 {
-  IF_DBUG(uint tmp=) my_strnxfrm(field_charset,
-                                 to, length,
-                                 ptr, field_length);
+  uint tmp __attribute__((unused))=
+    my_strnxfrm(field_charset, to, length, ptr, field_length);
   DBUG_ASSERT(tmp == length);
 }
 

=== modified file 'sql/ha_ndbcluster.cc'
--- a/sql/ha_ndbcluster.cc	2009-10-14 08:25:39 +0000
+++ b/sql/ha_ndbcluster.cc	2009-10-30 18:13:58 +0000
@@ -4316,7 +4316,7 @@ int ha_ndbcluster::end_bulk_insert()
       }
       else
       {
-        IF_DBUG(int res=) trans->restart();
+        int res __attribute__((unused))= trans->restart();
         DBUG_ASSERT(res == 0);
       }
     }
@@ -5928,7 +5928,7 @@ int ha_ndbcluster::rename_table(const ch
   {
     DBUG_PRINT("NDB_SHARE", ("%s temporary  use_count: %u",
                              share->key, share->use_count));
-    IF_DBUG(int r=) rename_share(share, to);
+    int r __attribute__((unused))= rename_share(share, to);
     DBUG_ASSERT(r == 0);
   }
 #endif
@@ -5952,7 +5952,7 @@ int ha_ndbcluster::rename_table(const ch
 #ifdef HAVE_NDB_BINLOG
     if (share)
     {
-      IF_DBUG(int ret=) rename_share(share, from);
+      int ret __attribute__((unused))= rename_share(share, from);
       DBUG_ASSERT(ret == 0);
       /* ndb_share reference temporary free */
       DBUG_PRINT("NDB_SHARE", ("%s temporary free  use_count: %u",

=== modified file 'sql/ha_ndbcluster_binlog.cc'
--- a/sql/ha_ndbcluster_binlog.cc	2009-10-14 08:25:39 +0000
+++ b/sql/ha_ndbcluster_binlog.cc	2009-10-30 18:13:58 +0000
@@ -3390,14 +3390,14 @@ ndb_binlog_thread_handle_data_event(Ndb 
       if (share->flags & NSF_BLOB_FLAG)
       {
         my_ptrdiff_t ptrdiff= 0;
-        IF_DBUG(int ret =) get_ndb_blobs_value(table, share->ndb_value[0],
+        int ret __attribute__((unused))= get_ndb_blobs_value(table, share->ndb_value[0],
                                                blobs_buffer[0],
                                                blobs_buffer_size[0],
                                                ptrdiff);
         DBUG_ASSERT(ret == 0);
       }
       ndb_unpack_record(table, share->ndb_value[0], &b, table->record[0]);
-      IF_DBUG(int ret=) trans.write_row(originating_server_id,
+      int ret __attribute__((unused))= trans.write_row(originating_server_id,
                                         injector::transaction::table(table,
                                                                      TRUE),
                                         &b, n_fields, table->record[0]);
@@ -3429,7 +3429,7 @@ ndb_binlog_thread_handle_data_event(Ndb 
       if (share->flags & NSF_BLOB_FLAG)
       {
         my_ptrdiff_t ptrdiff= table->record[n] - table->record[0];
-        IF_DBUG(int ret =) get_ndb_blobs_value(table, share->ndb_value[n],
+        int ret __attribute__((unused))= get_ndb_blobs_value(table, share->ndb_value[n],
                                                blobs_buffer[n],
                                                blobs_buffer_size[n],
                                                ptrdiff);
@@ -3437,7 +3437,7 @@ ndb_binlog_thread_handle_data_event(Ndb 
       }
       ndb_unpack_record(table, share->ndb_value[n], &b, table->record[n]);
       DBUG_EXECUTE("info", print_records(table, table->record[n]););
-      IF_DBUG(int ret =) trans.delete_row(originating_server_id,
+      int ret __attribute__((unused))= trans.delete_row(originating_server_id,
                                           injector::transaction::table(table,
                                                                        TRUE),
                                           &b, n_fields, table->record[n]);
@@ -3452,7 +3452,7 @@ ndb_binlog_thread_handle_data_event(Ndb 
       if (share->flags & NSF_BLOB_FLAG)
       {
         my_ptrdiff_t ptrdiff= 0;
-        IF_DBUG(int ret =) get_ndb_blobs_value(table, share->ndb_value[0],
+        int ret __attribute__((unused))= get_ndb_blobs_value(table, share->ndb_value[0],
                                                blobs_buffer[0],
                                                blobs_buffer_size[0],
                                                ptrdiff);
@@ -3480,7 +3480,7 @@ ndb_binlog_thread_handle_data_event(Ndb 
         if (share->flags & NSF_BLOB_FLAG)
         {
           my_ptrdiff_t ptrdiff= table->record[1] - table->record[0];
-          IF_DBUG(int ret =) get_ndb_blobs_value(table, share->ndb_value[1],
+          int ret __attribute__((unused))= get_ndb_blobs_value(table, share->ndb_value[1],
                                                  blobs_buffer[1],
                                                  blobs_buffer_size[1],
                                                  ptrdiff);
@@ -3488,7 +3488,7 @@ ndb_binlog_thread_handle_data_event(Ndb 
         }
         ndb_unpack_record(table, share->ndb_value[1], &b, table->record[1]);
         DBUG_EXECUTE("info", print_records(table, table->record[1]););
-        IF_DBUG(int ret =) trans.update_row(originating_server_id,
+        int ret __attribute__((unused))= trans.update_row(originating_server_id,
                                             injector::transaction::table(table,
                                                                          TRUE),
                                             &b, n_fields,
@@ -3792,7 +3792,7 @@ restart:
         { C_STRING_WITH_LEN("mysqld startup")    },
         { C_STRING_WITH_LEN("cluster disconnect")}
       };
-    IF_DBUG(int error=)
+    int error __attribute__((unused))=
       inj->record_incident(thd, INCIDENT_LOST_EVENTS, msg[incident_id]);
     DBUG_ASSERT(!error);
     break;
@@ -4107,7 +4107,7 @@ restart:
             DBUG_PRINT("info", ("use_table: %.*s",
                                 (int) name.length, name.str));
             injector::transaction::table tbl(table, TRUE);
-            IF_DBUG(int ret=) trans.use_table(::server_id, tbl);
+            int ret __attribute__((unused))= trans.use_table(::server_id, tbl);
             DBUG_ASSERT(ret == 0);
           }
         }
@@ -4123,7 +4123,7 @@ restart:
                                 (int) name.length, name.str));
 #endif
             injector::transaction::table tbl(table, TRUE);
-            IF_DBUG(int ret=) trans.use_table(::server_id, tbl);
+            int ret __attribute__((unused))= trans.use_table(::server_id, tbl);
             DBUG_ASSERT(ret == 0);
 
 	    /* 
@@ -4193,7 +4193,7 @@ restart:
           else
           {
             // set injector_ndb database/schema from table internal name
-            IF_DBUG(int ret=)
+            int ret __attribute__((unused))=
               i_ndb->setDatabaseAndSchemaName(pOp->getEvent()->getTable());
             DBUG_ASSERT(ret == 0);
             ndb_binlog_thread_handle_non_data_event(thd, i_ndb, pOp, row);

=== modified file 'sql/log_event.cc'
--- a/sql/log_event.cc	2009-10-22 22:30:28 +0000
+++ b/sql/log_event.cc	2009-10-30 18:13:58 +0000
@@ -1200,14 +1200,14 @@ Log_event* Log_event::read_log_event(con
     */
     if (description_event->event_type_permutation)
     {
-      IF_DBUG({
-          int new_event_type=
-            description_event->event_type_permutation[event_type];
-          DBUG_PRINT("info",
-                     ("converting event type %d to %d (%s)",
-                      event_type, new_event_type,
-                      get_type_str((Log_event_type)new_event_type)));
-        });
+#ifndef DBUG_OFF
+      int new_event_type=
+        description_event->event_type_permutation[event_type];
+      DBUG_PRINT("info",
+                 ("converting event type %d to %d (%s)",
+                  event_type, new_event_type,
+                  get_type_str((Log_event_type)new_event_type)));
+#endif
       event_type= description_event->event_type_permutation[event_type];
     }
 
@@ -3609,10 +3609,12 @@ Format_description_log_event(uint8 binlo
     */
     if (post_header_len)
     {
+#ifndef DBUG_OFF      
       // Allows us to sanity-check that all events initialized their
       // events (see the end of this 'if' block).
-      IF_DBUG(memset(post_header_len, 255,
-                     number_of_event_types*sizeof(uint8)););
+      memset(post_header_len, 255,
+                     number_of_event_types*sizeof(uint8));
+#endif
 
       /* Note: all event types must explicitly fill in their lengths here. */
       post_header_len[START_EVENT_V3-1]= START_V3_HEADER_LEN;
@@ -3666,11 +3668,9 @@ Format_description_log_event(uint8 binlo
       post_header_len[HEARTBEAT_LOG_EVENT-1]= 0;
 
       // Sanity-check that all post header lengths are initialized.
-      IF_DBUG({
-          int i;
-          for (i=0; i<number_of_event_types; i++)
-            assert(post_header_len[i] != 255);
-        });
+      int i;
+      for (i=0; i<number_of_event_types; i++)
+        DBUG_ASSERT(post_header_len[i] != 255);
     }
     break;
 

=== modified file 'sql/slave.cc'
--- a/sql/slave.cc	2009-10-22 22:30:28 +0000
+++ b/sql/slave.cc	2009-10-30 18:13:58 +0000
@@ -583,7 +583,7 @@ terminate_slave_thread(THD *thd,
       EINVAL: invalid signal number (can't happen)
       ESRCH: thread already killed (can happen, should be ignored)
     */
-    IF_DBUG(int err= ) pthread_kill(thd->real_id, thr_client_alarm);
+    int err __attribute__((unused))= pthread_kill(thd->real_id, thr_client_alarm);
     DBUG_ASSERT(err != EINVAL);
 #endif
     thd->awake(THD::NOT_KILLED);
@@ -1087,7 +1087,7 @@ static bool check_io_slave_killed(THD *t
   if (io_slave_killed(thd, mi))
   {
     if (info && global_system_variables.log_warnings)
-      sql_print_information(info);
+      sql_print_information("%s", info);
     return TRUE;
   }
   return FALSE;

=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc	2009-10-19 13:36:19 +0000
+++ b/sql/sql_select.cc	2009-10-30 18:13:58 +0000
@@ -5079,8 +5079,8 @@ greedy_search(JOIN      *join,
       the interleaving state to the one of the non-extended partial plan 
       on exit.
     */
-    IF_DBUG(bool is_interleave_error= )
-    check_interleaving_with_nj (best_table);
+    bool is_interleave_error __attribute__((unused))= 
+      check_interleaving_with_nj (best_table);
     /* This has been already checked by best_extension_by_limited_search */
     DBUG_ASSERT(!is_interleave_error);
 
@@ -15045,7 +15045,7 @@ setup_copy_fields(THD *thd, TMP_TABLE_PA
   Item *pos;
   List_iterator_fast<Item> li(all_fields);
   Copy_field *copy= NULL;
-  IF_DBUG(Copy_field *copy_start);
+  Copy_field *copy_start __attribute__((unused));
   res_selected_fields.empty();
   res_all_fields.empty();
   List_iterator_fast<Item> itr(res_all_fields);
@@ -15058,7 +15058,7 @@ setup_copy_fields(THD *thd, TMP_TABLE_PA
     goto err2;
 
   param->copy_funcs.empty();
-  IF_DBUG(copy_start= copy);
+  copy_start= copy;
   for (i= 0; (pos= li++); i++)
   {
     Field *field;

=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc	2009-10-21 10:48:22 +0000
+++ b/sql/sql_table.cc	2009-10-30 18:13:58 +0000
@@ -5423,7 +5423,7 @@ binlog:
         }
         VOID(pthread_mutex_unlock(&LOCK_open));
 
-        IF_DBUG(int result=)
+        int result __attribute__((unused))=
           store_create_info(thd, table, &query,
                             create_info, FALSE /* show_database */);
 


Attachment: [text/bzr-bundle] bzr/serg@mysql.com-20091030181358-215e0ghcyjohzl09.bundle
Thread
bzr commit into mysql-5.5-next-mr branch (serg:2909) Sergei Golubchik30 Oct