summaryrefslogtreecommitdiff
path: root/dbug
diff options
context:
space:
mode:
authorSergei Golubchik <serg@mysql.com>2009-10-30 19:13:58 +0100
committerSergei Golubchik <serg@mysql.com>2009-10-30 19:13:58 +0100
commit319847a4ec9cbe96b2bf7fb1ff5f8d263e8d12bb (patch)
tree53d531c0319fefc2db3ea6c70ceb4648c3cb4ed9 /dbug
parenteff49de23e87dabb17b07b74f04b104748df8517 (diff)
downloadmariadb-git-319847a4ec9cbe96b2bf7fb1ff5f8d263e8d12bb.tar.gz
backport of dbug extensions from 6.0:
function/ syntax glob(7) wildcards unit tests
Diffstat (limited to 'dbug')
-rw-r--r--dbug/.cvsignore3
-rw-r--r--dbug/Makefile.am15
-rw-r--r--dbug/dbug.c876
-rwxr-xr-xdbug/dbug_add_tags.pl4
-rw-r--r--dbug/doinstall.sh15
-rw-r--r--dbug/install.sh64
-rw-r--r--dbug/mklintlib.sh30
-rw-r--r--dbug/qmake.cmd4
-rwxr-xr-xdbug/remove_function_from_trace.pl26
-rwxr-xr-xdbug/tests-t.pl496
-rw-r--r--dbug/tests.c87
-rw-r--r--dbug/user.r54
-rw-r--r--dbug/vargs.h139
13 files changed, 1178 insertions, 635 deletions
diff --git a/dbug/.cvsignore b/dbug/.cvsignore
deleted file mode 100644
index e9955884756..00000000000
--- a/dbug/.cvsignore
+++ /dev/null
@@ -1,3 +0,0 @@
-.deps
-Makefile
-Makefile.in
diff --git a/dbug/Makefile.am b/dbug/Makefile.am
index 872ebdb7902..4091858a1af 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,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
+
diff --git a/dbug/dbug.c b/dbug/dbug.c
index 1ea160852eb..b501fac0894 100644
--- a/dbug/dbug.c
+++ b/dbug/dbug.c
@@ -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 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 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, 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 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_ptr= (CODE_STATE**) my_thread_var_dbug()))
+ return 0; /* Thread not initialised */
+ if (!(cs= *cs_ptr))
{
- 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;
- }
+ 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, const char *control)
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, const char *control)
{
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, const char *control)
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, const char *control)
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, const char *control)
* 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 *control)
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 *buf, size_t len)
{
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 len)
*
* 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 len)
*/
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_, const char *_file_,
*
* 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_, const char *_file_,
*/
/* 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 **_sfunc_,
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 *keyword)
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 *keyword,
{
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 *keyword,
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 *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 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] == '/')
{
- while (*cur && !strncmp((*cur)->str, start, len))
+ len--;
+ subdir=SUBDIR;
+ }
+ if (len == 0) continue;
+ for (cur=&head; *cur; cur=&((*cur)->next_link))
+ {
+ 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 *orig)
{
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 *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;
@@ -1373,47 +1561,52 @@ static struct link *ListCopy(struct link *orig)
*
* 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, struct settings *state, int free_state)
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)
+static int DoTrace(CODE_STATE *cs)
{
- return (TRACING && cs->level <= cs->stack->maxdepth &&
- InList(cs->stack->functions, cs->func) &&
- InList(cs->stack->processes, cs->process));
+ 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 *keyword)
*
*/
-BOOLEAN _db_keyword_(CODE_STATE *cs, const char *keyword)
-{
- get_code_state_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->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)
+BOOLEAN _db_keyword_(CODE_STATE *cs, const char *keyword, int strict)
{
- char dest[_DBUG_MAX_FUNC_NAME_ + 1];
-
- strxnmov(dest, _DBUG_MAX_FUNC_NAME_, function, type, NULL);
+ get_code_state_if_not_set_or_return FALSE;
+ strict=strict ? INCLUDE : INCLUDE|MATCHED;
- 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, const char *name)
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, char *pathname)
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;
}
diff --git a/dbug/dbug_add_tags.pl b/dbug/dbug_add_tags.pl
index 141a2ed85f1..3e51a54c707 100755
--- a/dbug/dbug_add_tags.pl
+++ b/dbug/dbug_add_tags.pl
@@ -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";
diff --git a/dbug/doinstall.sh b/dbug/doinstall.sh
deleted file mode 100644
index 707f193c761..00000000000
--- a/dbug/doinstall.sh
+++ /dev/null
@@ -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
diff --git a/dbug/install.sh b/dbug/install.sh
deleted file mode 100644
index 7226e01b1cf..00000000000
--- a/dbug/install.sh
+++ /dev/null
@@ -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
-
diff --git a/dbug/mklintlib.sh b/dbug/mklintlib.sh
deleted file mode 100644
index 6963016f334..00000000000
--- a/dbug/mklintlib.sh
+++ /dev/null
@@ -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
diff --git a/dbug/qmake.cmd b/dbug/qmake.cmd
deleted file mode 100644
index ebd4432f7fc..00000000000
--- a/dbug/qmake.cmd
+++ /dev/null
@@ -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;
diff --git a/dbug/remove_function_from_trace.pl b/dbug/remove_function_from_trace.pl
new file mode 100755
index 00000000000..1da9e25f9ba
--- /dev/null
+++ b/dbug/remove_function_from_trace.pl
@@ -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;
+}
diff --git a/dbug/tests-t.pl b/dbug/tests-t.pl
new file mode 100755
index 00000000000..de9ed6f6ab9
--- /dev/null
+++ b/dbug/tests-t.pl
@@ -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/
diff --git a/dbug/tests.c b/dbug/tests.c
new file mode 100644
index 00000000000..d76266d34a3
--- /dev/null
+++ b/dbug/tests.c
@@ -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);
+ }
+}
diff --git a/dbug/user.r b/dbug/user.r
index ef67ef7a7cf..847ad80b30f 100644
--- a/dbug/user.r
+++ b/dbug/user.r
@@ -512,7 +512,7 @@ possible since all code preceding the first call to
.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 execute "dangerous" actions, e.g
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 disable asserts separately with NDEBUG.
.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. This mode is implicit in
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 (value of 10 is one second).
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 PID (or thread ID) of 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, do not append.
.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
diff --git a/dbug/vargs.h b/dbug/vargs.h
deleted file mode 100644
index 4609c8301bb..00000000000
--- a/dbug/vargs.h
+++ /dev/null
@@ -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]