summaryrefslogtreecommitdiff
path: root/dbug
diff options
context:
space:
mode:
authorunknown <serg@janus.mylan>2008-02-01 16:21:44 +0100
committerunknown <serg@janus.mylan>2008-02-01 16:21:44 +0100
commitd79e70597acbf4fab0e848d8df42888404cb2c29 (patch)
treec72f9566f5025f5c069393faf8da971fcb331364 /dbug
parent74efae60fcd186e15da1b123f7765c66f8598f4a (diff)
downloadmariadb-git-d79e70597acbf4fab0e848d8df42888404cb2c29.tar.gz
negative lists in dbug (-#-d,info => everything but "info").
unit tests for dbug dbug/Makefile.am: unit tests for dbug dbug/dbug.c: negative lists (-#-d,info => everything but "info") include/my_dbug.h: negative lists (-#-d,info => everything but "info") unittest/Makefile.am: unit tests for dbug dbug/tests-t.pl: unit tests for dbug dbug/tests.c: unit tests for dbug
Diffstat (limited to 'dbug')
-rw-r--r--dbug/Makefile.am13
-rw-r--r--dbug/dbug.c277
-rwxr-xr-xdbug/tests-t.pl371
-rw-r--r--dbug/tests.c73
4 files changed, 576 insertions, 158 deletions
diff --git a/dbug/Makefile.am b/dbug/Makefile.am
index 872ebdb7902..ef7323a0516 100644
--- a/dbug/Makefile.am
+++ b/dbug/Makefile.am
@@ -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,9 @@ output5.r: factorial
@RM@ -f $@
@SED@ -e 's!\\!\\\\!g' $< > $@
+# a hack to have executable in builddir, not in srcdir
+tests-t: tests-t.pl
+ cp $(srcdir)/tests-t.pl $(builddir)/tests-t
+
# Don't update the files from bitkeeper
%::SCCS/s.%
diff --git a/dbug/dbug.c b/dbug/dbug.c
index 136f86e6c33..fb442412d04 100644
--- a/dbug/dbug.c
+++ b/dbug/dbug.c
@@ -57,17 +57,19 @@
* 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")
*
*/
@@ -174,9 +176,14 @@ IMPORT int _sanity(const char *file,uint line); /* safemalloc sanity checker */
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 */
+#define INCLUDE 1
+#define EXCLUDE 2
+
/*
* Debugging settings can be pushed or popped off of a
* stack which is implemented as a linked list. Note
@@ -188,18 +195,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 */
+ 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 */
};
#define is_shared(S, V) ((S)->next && (S)->next->V == (S)->V)
@@ -249,9 +256,12 @@ typedef struct _db_code_state_ {
#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 int ListFlags(struct link *linkp);
static void FreeList(struct link *linkp);
/* OpenClose debug output stream */
@@ -277,7 +287,6 @@ static void DoPrefix(CODE_STATE *cs, uint line);
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 DbugExit(const char *why);
static const char *DbugStrTok(const char *s);
@@ -508,7 +517,7 @@ void _db_set_(CODE_STATE *cs, const char *control)
{
int c, sign= (*control == '+') ? 1 : (*control == '-') ? -1 : 0;
if (sign) control++;
- if (!rel) sign=0;
+ /* if (!rel) sign=0; */
c= *control++;
if (*control == ',') control++;
/* XXX when adding new cases here, don't forget _db_explain_ ! */
@@ -780,11 +789,12 @@ 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); \
listp=listp->next_link; \
} \
} while (0)
@@ -824,9 +834,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 { \
@@ -1137,7 +1156,7 @@ void _db_doprnt_(const char *format,...)
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)
@@ -1183,7 +1202,7 @@ void _db_dump_(uint _line_, const char *keyword,
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);
@@ -1223,93 +1242,66 @@ void _db_dump_(uint _line_, const char *keyword,
/*
* 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
+ * parses the list, and modifies "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.
+ * The mode of operation is defined by "todo" parameter.
*
- */
-
-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;
- *
- * DESCRIPTION
- *
- * 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's INCLUDE, elements (strings from "cltp") are added to the
+ * list, they'll 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's 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;
- while (ctlp < end)
+ ctlp--;
+next:
+ while (++ctlp < end)
{
start= ctlp;
while (ctlp < end && *ctlp != ',')
ctlp++;
len=ctlp-start;
- cur=&head;
- do
+ 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 (todo == EXCLUDE)
+ {
+ struct link *delme=*cur;
+ *cur=(*cur)->next_link;
+ free((void*) delme);
+ }
+ else
+ {
+ (*cur)->flags&=~EXCLUDE;
+ (*cur)->flags|=INCLUDE;
+ }
+ 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;
+ (*cur)->next_link=0;
}
return head;
}
@@ -1350,6 +1342,7 @@ static struct link *ListCopy(struct link *orig)
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;
@@ -1364,7 +1357,7 @@ static struct link *ListCopy(struct link *orig)
*
* SYNOPSIS
*
- * static BOOLEAN InList(linkp, cp)
+ * static int InList(linkp, cp)
* struct link *linkp;
* char *cp;
*
@@ -1372,37 +1365,48 @@ static struct link *ListCopy(struct link *orig)
*
* 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
+ * 0 - not in the list (or matched an EXCLUDE element)
+ * 1 - in the list by default (list is empty or only has EXCLUDE elements)
+ * 2 - in the list explictly (matched an INCLUDE element)
+ *
*/
-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=1; 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 (!strcmp(linkp->str, cp))
+ return linkp->flags & EXCLUDE ? 0 : 2;
+ if (!(linkp->flags & EXCLUDE))
+ result=0;
}
return result;
}
+/*
+ * FUNCTION
+ *
+ * ListFlags returns aggregated list flags (ORed over all elements)
+ *
+ */
+
+static int ListFlags(struct link *linkp)
+{
+ int f;
+ for (f=0; linkp != NULL; linkp= linkp->next_link)
+ f|= linkp->flags;
+ return f;
+}
/*
* FUNCTION
@@ -1589,50 +1593,15 @@ FILE *_db_fp_(void)
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;
- 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
@@ -1644,14 +1613,14 @@ BOOLEAN _db_strict_keyword_(const char *keyword)
*
*/
-BOOLEAN _db_keyword_(CODE_STATE *cs, const char *keyword)
+BOOLEAN _db_keyword_(CODE_STATE *cs, const char *keyword, int strict)
{
get_code_state_if_not_set_or_return FALSE;
return (DEBUGGING &&
(!TRACING || cs->level <= cs->stack->maxdepth) &&
InList(cs->stack->functions, cs->func) &&
- InList(cs->stack->keywords, keyword) &&
+ InList(cs->stack->keywords, keyword) > (strict != 0) &&
InList(cs->stack->processes, cs->process));
}
diff --git a/dbug/tests-t.pl b/dbug/tests-t.pl
new file mode 100755
index 00000000000..1533a49c9bf
--- /dev/null
+++ b/dbug/tests-t.pl
@@ -0,0 +1,371 @@
+#!/usr/bin/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.
+#
+
+$exe=$0;
+
+die unless $exe =~ s/(tests)-t(\.exe)?$/$1$2 /;
+
+# load tests
+@tests=();
+while (<DATA>) {
+ if (/^% tests /) {
+ push @tests, [ $' ]
+ } else {
+ push @{$tests[$#tests]}, $_
+ }
+}
+
+# require/import instead of use - we know the plan only when tests are loaded
+require Test::More;
+import Test::More 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
+func2: info: s=ok
+=> execute
+=> evaluate: ON
+=> evaluate_if: OFF
+main: explain: dbug explained: d
+% tests -#d,ret3
+=> evaluate: OFF
+=> evaluate_if: OFF
+% tests -#d:-d,ret3
+func2: info: s=ko
+func2: info: s=ko
+=> execute
+=> evaluate: ON
+=> evaluate_if: OFF
+main: explain: dbug explained: d:-d,ret3
+% tests -#t:-d,ret3
+>main
+| >func1
+| | >func2
+| | | >func3
+| | | <func3
+| | <func2
+| <func1
+| >func2
+| | >func3
+| | <func3
+| <func2
+=> evaluate: OFF
+=> evaluate_if: OFF
+<main
+% tests -#t:d,info:-d,ret3
+>main
+| >func1
+| | >func2
+| | | >func3
+| | | <func3
+| | | info: s=ko
+| | <func2
+| <func1
+| >func2
+| | >func3
+| | <func3
+| | info: s=ko
+| <func2
+=> evaluate: OFF
+=> evaluate_if: OFF
+<main
+% tests -#t:d,info:-d,ret3:-f,func2
+>main
+| >func1
+| | | >func3
+| | | <func3
+| <func1
+| | >func3
+| | <func3
+=> evaluate: OFF
+=> evaluate_if: OFF
+<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 +d,evaluate_if
+>main
+| >func1
+| | | >func3
+| | | <func3
+| <func1
+| | >func3
+| | <func3
+=> evaluate: OFF
+=> evaluate_if: ON
+<main
+% tests -#t:d:-d,ret3:-f,func2
+>main
+| >func1
+| | | >func3
+| | | <func3
+| <func1
+| | >func3
+| | <func3
+=> execute
+=> evaluate: ON
+=> evaluate_if: OFF
+| explain: dbug explained: d:-d,ret3:f:-f,func2:t
+<main
+% tests -#t:d:-d,ret3:f:-f,func2 -#+d,dump
+>main
+| >func1
+| | | >func3
+| | | <func3
+| <func1
+| | >func3
+| | <func3
+| 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
+<main
+% tests -#t:d:-d,ret3:f:-f,func2 +d,dump
+>main
+| >func1
+| | | >func3
+| | | <func3
+| <func1
+| | >func3
+| | <func3
+| 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
+<main
+% tests -#t:d:-d,ret3:f:-f,func2:+d,dump
+>main
+| >func1
+| | | >func3
+| | | <func3
+| <func1
+| | >func3
+| | <func3
+| 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
+<main
+% tests -#t:d:-d,ret3:f:-f,func2 +d,dump,explain
+>main
+| >func1
+| | | >func3
+| | | <func3
+| <func1
+| | >func3
+| | <func3
+| 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
+<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: | | >func3
+dbug-tests: | | <func3
+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: <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: | | >func3
+dbug-tests: tests.c: | | <func3
+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: <main
+% tests -#t:d:-d,ret3:f:-f,func2
+>main
+| >func1
+| | | >func3
+| | | <func3
+| <func1
+| | >func3
+| | <func3
+=> execute
+=> evaluate: ON
+=> evaluate_if: OFF
+| explain: dbug explained: d:-d,ret3:f:-f,func2:t
+<main
+% tests -#t:d:-d,ret3
+>main
+| >func1
+| | >func2
+| | | >func3
+| | | <func3
+| | | info: s=ko
+| | <func2
+| <func1
+| >func2
+| | >func3
+| | <func3
+| | info: s=ko
+| <func2
+=> execute
+=> evaluate: ON
+=> evaluate_if: OFF
+| explain: dbug explained: d:-d,ret3:t
+<main
+% tests -#t:d,info:-d,ret3:d,push
+>main
+| >func1
+| | >func2
+| | | >func3
+| | | <func3
+| | | info: s=ko
+| | <func2
+| <func1
+| >func2
+| | >func3
+| | <func3
+| | info: s=ko
+| <func2
+=> evaluate: OFF
+=> evaluate_if: OFF
+<main
+% tests -#d,info:-d,ret3:d,push
+func2: info: s=ko
+func2: info: s=ko
+=> evaluate: OFF
+=> evaluate_if: OFF
+<main
+% tests -#d,info:-d,ret3:d,push,explain
+func2: info: s=ko
+func2: info: s=ko
+=> evaluate: OFF
+=> evaluate_if: OFF
+| explain: dbug explained: d,info,push,explain:-d,ret3:t
+<main
+% tests -#d,info:-d,ret3:d,explain
+func2: info: s=ko
+func2: info: s=ko
+=> evaluate: OFF
+=> evaluate_if: OFF
+main: explain: dbug explained: d,info,explain:-d,ret3
+% tests -#d,info:-d,ret3:d,explain,pop
+func2: info: s=ko
+func2: info: s=ko
+=> evaluate: OFF
+=> evaluate_if: OFF
+% tests -#d,info:-d,ret3:d,explain,pop t
+>main
+| >func1
+| | >func2
+| | | >func3
+| | | <func3
+| | <func2
+| <func1
+| >func2
+| | >func3
+| | <func3
+| <func2
+=> evaluate: OFF
+=> evaluate_if: OFF
+<main
+% tests -#d,info:-d,ret3:d,explain,pop +t
+>main
+| >func1
+| | >func2
+| | | >func3
+| | | <func3
+| | | info: s=ko
+| | <func2
+| <func1
+| >func2
+| | >func3
+| | <func3
+| | info: s=ko
+| <func2
+=> evaluate: OFF
+=> evaluate_if: OFF
+main: explain: dbug explained: d,info,explain,pop:-d,ret3
+% tests -#d,info:-d,ret3:d,explain,set
+func2: info: s=ko
+func2: info: s=ko
+=> evaluate: OFF
+=> evaluate_if: OFF
+ tests.c: main: explain: dbug explained: d,info,explain,set:-d,ret3:F
+% tests -#d,info:-d,ret3:d,explain,set:t
+>main
+| >func1
+| | >func2
+| | | >func3
+| | | <func3
+| | | info: s=ko
+| | <func2
+| <func1
+| >func2
+| | >func3
+| | <func3
+| | info: s=ko
+| <func2
+=> evaluate: OFF
+=> evaluate_if: OFF
+ tests.c: | explain: dbug explained: d,info,explain,set:-d,ret3:F:t
+ tests.c: <main
+% tests t -#d,info:-d,ret3:d,explain,set:t
+>main
+| >func1
+| | >func2
+| | | >func3
+| | | <func3
+| | | info: s=ko
+| | <func2
+| <func1
+| >func2
+| | >func3
+| | <func3
+| | info: s=ko
+| <func2
+=> evaluate: OFF
+=> evaluate_if: OFF
+ tests.c: | explain: dbug explained: d,info,explain,set:-d,ret3:F:t
+ tests.c: <main
+% tests t -#d,info:-d,ret3:d,explain,set,pop
+func2: info: s=ko
+func2: info: s=ko
+=> evaluate: OFF
+=> evaluate_if: OFF
+<main
diff --git a/dbug/tests.c b/dbug/tests.c
new file mode 100644
index 00000000000..42482635eee
--- /dev/null
+++ b/dbug/tests.c
@@ -0,0 +1,73 @@
+/*
+ A program to test DBUG features. Used by tests-t.pl
+*/
+
+#ifdef DBUG_OFF /* We are testing dbug */
+#undef DBUG_OFF
+#endif
+
+#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();
+ DBUG_RETURN(10);
+}
+
+int main (int argc, char *argv[])
+{
+ int i;
+#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++)
+ DBUG_PUSH (argv[i]);
+ {
+ DBUG_ENTER ("main");
+ DBUG_PROCESS ("dbug-tests");
+ func1();
+ func2();
+ 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];
+ DBUG_EXPLAIN(s, sizeof(s)-1);
+ DBUG_PRINT("explain", ("dbug explained: %s", s));
+ }
+ DBUG_RETURN (0);
+ }
+}