aboutsummaryrefslogtreecommitdiff
path: root/dep/mysqllite/dbug/dbug.c
diff options
context:
space:
mode:
Diffstat (limited to 'dep/mysqllite/dbug/dbug.c')
-rw-r--r--dep/mysqllite/dbug/dbug.c1195
1 files changed, 534 insertions, 661 deletions
diff --git a/dep/mysqllite/dbug/dbug.c b/dep/mysqllite/dbug/dbug.c
index 8fa5ed9af6b..2c06eeff95a 100644
--- a/dep/mysqllite/dbug/dbug.c
+++ b/dep/mysqllite/dbug/dbug.c
@@ -57,28 +57,47 @@
* 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>
-#if defined(MSDOS) || defined(__WIN__)
-#include <process.h>
+
+#ifdef HAVE_FNMATCH_H
+#include <fnmatch.h>
+#else
+#define fnmatch(A,B,C) strcmp(A,B)
#endif
+#if defined(__WIN__)
+#include <process.h>
+#endif
#ifndef DBUG_OFF
@@ -95,21 +114,23 @@
* 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 FLUSH_ON_WRITE (1 << 10) /* Flush on every write */
+#define OPEN_APPEND (1 << 11) /* 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 +140,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 +156,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 +171,8 @@ typedef int BOOLEAN;
#ifdef M_I386 /* predefined by xenix 386 compiler */
#define AUTOS_REVERSE 1
+#else
+#define AUTOS_REVERSE 0
#endif
/*
@@ -164,8 +183,6 @@ typedef int BOOLEAN;
static void perror(); /* Fake system/library error print routine */
#endif
-IMPORT int _sanity(const char *file,uint line); /* safemalloc sanity checker */
-
/*
* The user may specify a list of functions to trace or
* debug. These lists are kept in a linear linked list,
@@ -174,9 +191,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 +214,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 +238,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 +271,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 +291,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)
static BOOLEAN Writable(const char *pathname);
/* Change file owner and group */
static void ChangeOwner(CODE_STATE *cs, char *pathname);
@@ -275,109 +314,76 @@ 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);
-
-#ifndef THREAD
- /* Open profile output stream */
-static FILE *OpenProfile(CODE_STATE *cs, const char *name);
- /* Profile if asked for it */
-static BOOLEAN DoProfile(CODE_STATE *);
- /* Return current user time (ms) */
-static unsigned long Clock(void);
-#endif
+static void DbugVfprintf(FILE *stream, const char* format, va_list args);
/*
* Miscellaneous printf format strings.
*/
-#define ERR_MISSING_RETURN "%s: missing DBUG_RETURN or DBUG_VOID_RETURN macro in function \"%s\"\n"
+#define ERR_MISSING_RETURN "missing DBUG_RETURN or DBUG_VOID_RETURN macro in function \"%s\"\n"
#define ERR_OPEN "%s: can't open debug output stream \"%s\": "
#define ERR_CLOSE "%s: can't close debug file: "
#define ERR_ABORT "%s: debugger aborting because %s\n"
-#define ERR_CHOWN "%s: can't change owner/group of \"%s\": "
/*
* Macros and defines for testing file accessibility under UNIX and MSDOS.
*/
#undef EXISTS
-#if !defined(HAVE_ACCESS) || defined(MSDOS)
+#if !defined(HAVE_ACCESS)
#define EXISTS(pathname) (FALSE) /* Assume no existance */
#define Writable(name) (TRUE)
#else
#define EXISTS(pathname) (access(pathname, F_OK) == 0)
#define WRITABLE(pathname) (access(pathname, W_OK) == 0)
#endif
-#ifndef MSDOS
-#define ChangeOwner(cs,name)
-#endif
/*
** Macros to allow dbugging with threads
*/
-#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)
{
- pthread_mutex_init(&THR_LOCK_dbug,MY_MUTEX_INIT_FAST);
+ init_done=TRUE;
+ pthread_mutex_init(&THR_LOCK_dbug, NULL);
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;
}
-#else /* !THREAD */
-
-static CODE_STATE static_code_state=
-{
- "dbug", "?func", "?file", NULL, &init_settings,
- NullS, NullS, 0,0,0,0,0,NullS
-};
-
-static CODE_STATE *code_state(void)
-{
- if (!init_done)
- {
- bzero(&init_settings, sizeof(init_settings));
- init_settings.out_file=stderr;
- init_settings.flags=OPEN_APPEND;
- init_done=TRUE;
- }
- return &static_code_state;
-}
-
-#define pthread_mutex_lock(A) {}
-#define pthread_mutex_unlock(A) {}
-#endif
-
/*
* Translate some calls among different systems.
*/
@@ -403,20 +409,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 +443,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,13 +462,8 @@ static void DbugParse(CODE_STATE *cs, const char *control)
rel= control[0] == '+' || control[0] == '-';
if ((!rel || (!stack->out_file && !stack->next)))
{
- /*
- We need to free what's already in init_settings, because unlike
- the thread related stack frames there's a chance that something
- is in these variables already.
- */
- if (stack == &init_settings)
- FreeState(cs, stack, 0);
+ /* Free memory associated with the state before resetting its members */
+ FreeState(cs, stack, 0);
stack->flags= 0;
stack->delay= 0;
stack->maxdepth= 0;
@@ -480,11 +482,16 @@ static void DbugParse(CODE_STATE *cs, const char *control)
stack->maxdepth= stack->next->maxdepth;
stack->sub_level= stack->next->sub_level;
strcpy(stack->name, stack->next->name);
- stack->out_file= stack->next->out_file;
stack->prof_file= stack->next->prof_file;
if (stack->next == &init_settings)
{
- /* never share with the global parent - it can change under your feet */
+ /*
+ Never share with the global parent - it can change under your feet.
+
+ Reset out_file to stderr to prevent sharing of trace files between
+ global and session settings.
+ */
+ stack->out_file= stderr;
stack->functions= ListCopy(init_settings.functions);
stack->p_functions= ListCopy(init_settings.p_functions);
stack->keywords= ListCopy(init_settings.keywords);
@@ -492,6 +499,7 @@ static void DbugParse(CODE_STATE *cs, const char *control)
}
else
{
+ stack->out_file= stack->next->out_file;
stack->functions= stack->next->functions;
stack->p_functions= stack->next->p_functions;
stack->keywords= stack->next->keywords;
@@ -504,7 +512,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_ ! */
@@ -533,6 +540,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))
@@ -559,15 +567,6 @@ static void DbugParse(CODE_STATE *cs, const char *control)
else
stack->flags |= PID_ON;
break;
-#ifndef THREAD
- case 'g':
- if (OpenProfile(cs, PROF_FILE))
- {
- stack->flags |= PROFILE_ON;
- stack->p_functions= ListAdd(stack->p_functions, control, end);
- }
- break;
-#endif
case 'L':
if (sign < 0)
stack->flags &= ~LINE_ON;
@@ -659,20 +658,117 @@ static void DbugParse(CODE_STATE *cs, const char *control)
else
stack->flags |= TIMESTAMP_ON;
break;
- case 'S':
- if (sign < 0)
- stack->flags &= ~SANITY_CHECK_ON;
- else
- stack->flags |= SANITY_CHECK_ON;
- break;
}
if (!*end)
break;
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
@@ -690,19 +786,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
*
@@ -723,10 +821,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);
}
/*
@@ -749,6 +862,7 @@ void _db_set_init_(const char *control)
CODE_STATE tmp_cs;
bzero((uchar*) &tmp_cs, sizeof(tmp_cs));
tmp_cs.stack= &init_settings;
+ tmp_cs.process= db_process ? db_process : "dbug";
DbugParse(&tmp_cs, control);
}
@@ -772,15 +886,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);
}
}
@@ -805,11 +922,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)
@@ -849,9 +971,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 { \
@@ -866,7 +997,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);
@@ -886,7 +1017,6 @@ int _db_explain_ (CODE_STATE *cs, char *buf, size_t len)
op_bool_to_buf('r', cs->stack->sub_level != 0);
op_intf_to_buf('t', cs->stack->maxdepth, MAXDEPTH, TRACING);
op_bool_to_buf('T', cs->stack->flags & TIMESTAMP_ON);
- op_bool_to_buf('S', cs->stack->flags & SANITY_CHECK_ON);
*buf= '\0';
return 0;
@@ -934,15 +1064,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
*
@@ -966,55 +1092,48 @@ 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;
-#ifndef THREAD
- *_sframep_= cs->framep;
- cs->framep= (char **) _sframep_;
- if (DoProfile(cs))
- {
- long stackused;
- if (*cs->framep == NULL)
- stackused= 0;
- else
+ _stack_frame_->prev= cs->framep;
+ _stack_frame_->level= ++cs->level | framep_trace_flag(cs, cs->framep);
+ cs->framep= _stack_frame_;
+
+ switch (DoTrace(cs)) {
+ case ENABLE_TRACE:
+ cs->framep->level|= TRACE_ON;
+ if (!TRACING) break;
+ /* fall through */
+ case DO_TRACE:
+ if (TRACING)
{
- stackused= ((long)(*cs->framep)) - ((long)(cs->framep));
- stackused= stackused > 0 ? stackused : -stackused;
+ 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 */
}
- (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
- (void) fflush(cs->stack->prof_file);
+ break;
+ case DISABLE_TRACE:
+ cs->framep->level&= ~TRACE_ON;
+ /* fall through */
+ case DONT_TRACE:
+ break;
}
-#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 */
- cs->stack->flags &= ~SANITY_CHECK_ON;
-#endif
errno=save_errno;
}
@@ -1025,11 +1144,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
*
@@ -1040,52 +1157,41 @@ 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->framep != _stack_frame_)
{
- 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);
+ char buf[512];
+ my_snprintf(buf, sizeof(buf), ERR_MISSING_RETURN, cs->func);
+ DbugExit(buf);
}
- else
+
+ if (DoTrace(cs) & DO_TRACE)
{
-#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 (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);
- dbug_flush(cs);
+ 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;
}
@@ -1112,7 +1218,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;
@@ -1148,13 +1254,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)
@@ -1165,14 +1270,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);
+ DbugVfprintf(cs->stack->out_file, format, args);
+ DbugFlush(cs);
errno=save_errno;
}
va_end(args);
}
+/*
+ * This function is intended as a
+ * vfprintf clone with consistent, platform independent output for
+ * problematic formats like %p, %zd and %lld.
+ */
+static void DbugVfprintf(FILE *stream, const char* format, va_list args)
+{
+ char cvtbuf[1024];
+ (void) my_vsnprintf(cvtbuf, sizeof(cvtbuf), format, args);
+ (void) fprintf(stream, "%s\n", cvtbuf);
+}
+
/*
* FUNCTION
@@ -1189,19 +1305,17 @@ void _db_doprnt_(const char *format,...)
*
* DESCRIPTION
* Dump N characters in a binary array.
- * Is used to examine corrputed memory or arrays.
+ * Is used to examine corrupted memory or arrays.
*/
void _db_dump_(uint _line_, const char *keyword,
const unsigned char *memory, size_t length)
{
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);
@@ -1215,9 +1329,8 @@ void _db_dump_(uint _line_, const char *keyword,
{
fprintf(cs->stack->out_file, "%s: ", cs->func);
}
- sprintf(dbuff,"%s: Memory: 0x%lx Bytes: (%ld)\n",
+ (void) fprintf(cs->stack->out_file, "%s: Memory: 0x%lx Bytes: (%ld)\n",
keyword, (ulong) memory, (long) length);
- (void) fputs(dbuff,cs->stack->out_file);
pos=0;
while (length-- > 0)
@@ -1233,7 +1346,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);
}
}
@@ -1241,93 +1354,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
- *
- * Note that since each link is added at the head of the list,
- * the final list will be in "reverse order", which is not
- * significant for our usage here.
- *
- */
-
-static struct link *ListAdd(struct link *head,
- const char *ctlp, const char *end)
-{
- const char *start;
- struct link *new_malloc;
- int len;
-
- while (ctlp < end)
- {
- start= ctlp;
- while (ctlp < end && *ctlp != ',')
- ctlp++;
- len=ctlp-start;
- new_malloc= (struct link *) DbugMalloc(sizeof(struct link)+len);
- memcpy(new_malloc->str, start, len);
- new_malloc->str[len]=0;
- new_malloc->next_link= head;
- head= new_malloc;
- ctlp++;
- }
- return head;
-}
-
-/*
- * FUNCTION
+ * parses the list, and modifies "listp", returning a pointer
+ * to the new list.
*
- * ListDel remove from the list modifiers in debug control string
+ * The mode of operation is defined by "todo" parameter.
*
- * 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] == '/')
+ {
+ len--;
+ subdir=SUBDIR;
+ }
+ if (len == 0) continue;
+ for (cur=&head; *cur; cur=&((*cur)->next_link))
{
- while (*cur && !strncmp((*cur)->str, start, len))
+ if (!strncmp((*cur)->str, start, len))
{
- struct link *delme=*cur;
- *cur=(*cur)->next_link;
- free((void*) delme);
+ if ((*cur)->flags & todo) /* same action ? */
+ (*cur)->flags|= subdir; /* just merge the SUBDIR flag */
+ else if (todo == EXCLUDE)
+ {
+ struct link *delme=*cur;
+ *cur=(*cur)->next_link;
+ free((void*) delme);
+ }
+ else
+ {
+ (*cur)->flags&=~(EXCLUDE & SUBDIR);
+ (*cur)->flags|=INCLUDE | subdir;
+ }
+ goto next;
}
- } while (*cur && *(cur=&((*cur)->next_link)));
+ }
+ *cur= (struct link *) DbugMalloc(sizeof(struct link)+len);
+ memcpy((*cur)->str, start, len);
+ (*cur)->str[len]=0;
+ (*cur)->flags=todo | subdir;
+ (*cur)->next_link=0;
}
return head;
}
@@ -1359,7 +1454,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)
@@ -1368,6 +1463,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;
@@ -1380,47 +1476,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
@@ -1447,8 +1548,8 @@ static void PushState(CODE_STATE *cs)
struct settings *new_malloc;
new_malloc= (struct settings *) DbugMalloc(sizeof(struct settings));
+ bzero(new_malloc, sizeof(struct settings));
new_malloc->next= cs->stack;
- new_malloc->out_file= NULL;
cs->stack= new_malloc;
}
@@ -1479,11 +1580,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);
}
@@ -1510,8 +1617,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))
@@ -1545,108 +1656,48 @@ 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));
-}
-
-
-/*
- * FUNCTION
- *
- * DoProfile check to see if profiling is current enabled
- *
- * SYNOPSIS
- *
- * static BOOLEAN DoProfile()
- *
- * DESCRIPTION
- *
- * Checks to see if profiling is enabled based on whether the
- * user has specified profiling, the maximum trace depth has
- * not yet been reached, the current function is selected,
- * and the current process is selected. Returns TRUE if
- * profiling is enabled, FALSE otherwise.
- *
- */
-
-#ifndef THREAD
-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);
+ 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;
}
-#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
@@ -1658,15 +1709,13 @@ 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_or_return FALSE;
+ get_code_state_if_not_set_or_return FALSE;
+ strict=strict ? INCLUDE : INCLUDE|MATCHED;
- return (DEBUGGING &&
- (!TRACING || cs->level <= cs->stack->maxdepth) &&
- InList(cs->stack->functions, cs->func) &&
- InList(cs->stack->keywords, keyword) &&
- InList(cs->stack->processes, cs->process));
+ return DEBUGGING && DoTrace(cs) & DO_TRACE &&
+ InList(cs->stack->keywords, keyword) & strict;
}
/*
@@ -1759,11 +1808,7 @@ static void DoPrefix(CODE_STATE *cs, uint _line_)
cs->lineno++;
if (cs->stack->flags & PID_ON)
{
-#ifdef THREAD
(void) fprintf(cs->stack->out_file, "%-7s: ", my_thread_name());
-#else
- (void) fprintf(cs->stack->out_file, "%5d: ", (int) getpid());
-#endif
}
if (cs->stack->flags & NUMBER_ON)
(void) fprintf(cs->stack->out_file, "%5d: ", cs->lineno);
@@ -1834,7 +1879,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;
}
@@ -1867,77 +1912,12 @@ static void DBUGOpenFile(CODE_STATE *cs,
else
{
cs->stack->out_file= fp;
- if (newfile)
- {
- ChangeOwner(cs, name);
- }
}
}
}
}
}
-
-/*
- * FUNCTION
- *
- * OpenProfile open new output stream for profiler output
- *
- * SYNOPSIS
- *
- * static FILE *OpenProfile(name)
- * char *name;
- *
- * DESCRIPTION
- *
- * Given name of a new file, opens the file
- * and sets the profiler output stream to the new file.
- *
- * It is currently unclear whether the prefered behavior is
- * to truncate any existing file, or simply append to it.
- * The latter behavior would be desirable for collecting
- * accumulated runtime history over a number of separate
- * runs. It might take some changes to the analyzer program
- * though, and the notes that Binayak sent with the profiling
- * diffs indicated that append was the normal mode, but this
- * does not appear to agree with the actual code. I haven't
- * investigated at this time [fnf; 24-Jul-87].
- */
-
-#ifndef THREAD
-static FILE *OpenProfile(CODE_STATE *cs, const char *name)
-{
- REGISTER FILE *fp;
- REGISTER BOOLEAN newfile;
-
- fp=0;
- if (!Writable(name))
- {
- (void) fprintf(cs->stack->out_file, ERR_OPEN, cs->process, name);
- perror("");
- (void) Delay(cs->stack->delay);
- }
- else
- {
- newfile= !EXISTS(name);
- if (!(fp= fopen(name, "w")))
- {
- (void) fprintf(cs->stack->out_file, ERR_OPEN, cs->process, name);
- perror("");
- }
- else
- {
- cs->stack->prof_file= fp;
- if (newfile)
- {
- ChangeOwner(cs, name);
- }
- }
- }
- return fp;
-}
-#endif
-
/*
* FUNCTION
*
@@ -1957,12 +1937,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 != NULL && 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);
}
}
@@ -1991,7 +1971,7 @@ static void DbugExit(const char *why)
CODE_STATE *cs=code_state();
(void) fprintf(stderr, ERR_ABORT, cs ? cs->process : "(null)", why);
(void) fflush(stderr);
- exit(1);
+ DBUG_ABORT();
}
@@ -2125,42 +2105,6 @@ static BOOLEAN Writable(const char *pathname)
/*
* FUNCTION
*
- * ChangeOwner change owner to real user for suid programs
- *
- * SYNOPSIS
- *
- * static VOID ChangeOwner(pathname)
- *
- * DESCRIPTION
- *
- * For unix systems, change the owner of the newly created debug
- * file to the real owner. This is strictly for the benefit of
- * programs that are running with the set-user-id bit set.
- *
- * Note that at this point, the fact that pathname represents
- * a newly created file has already been established. If the
- * program that the debugger is linked to is not running with
- * the suid bit set, then this operation is redundant (but
- * harmless).
- *
- */
-
-#ifndef ChangeOwner
-static void ChangeOwner(CODE_STATE *cs, char *pathname)
-{
- if (chown(pathname, getuid(), getgid()) == -1)
- {
- (void) fprintf(stderr, ERR_CHOWN, cs->process, pathname);
- perror("");
- (void) fflush(stderr);
- }
-}
-#endif
-
-
-/*
- * FUNCTION
- *
* _db_setjmp_ save debugger environment
*
* SYNOPSIS
@@ -2179,7 +2123,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;
@@ -2206,7 +2150,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;
@@ -2257,11 +2201,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)
@@ -2269,130 +2211,61 @@ static void dbug_flush(CODE_STATE *cs)
}
if (!cs->locked)
pthread_mutex_unlock(&THR_LOCK_dbug);
-} /* dbug_flush */
+} /* DbugFlush */
-void _db_lock_file_()
-{
- CODE_STATE *cs=0;
- get_code_state_or_return;
- pthread_mutex_lock(&THR_LOCK_dbug);
- cs->locked=1;
-}
+/* For debugging */
-void _db_unlock_file_()
+void _db_flush_()
{
- CODE_STATE *cs=0;
+ CODE_STATE *cs= NULL;
get_code_state_or_return;
- cs->locked=0;
- pthread_mutex_unlock(&THR_LOCK_dbug);
+ (void) fflush(cs->stack->out_file);
}
-/*
- * Here we need the definitions of the clock routine. Add your
- * own for whatever system that you have.
- */
-
-#ifndef THREAD
-#if defined(HAVE_GETRUSAGE)
-
-#include <sys/param.h>
-#include <sys/resource.h>
-
-/* extern int getrusage(int, struct rusage *); */
-/*
- * Returns the user time in milliseconds used by this process so
- * far.
- */
-
-static unsigned long Clock()
+#ifndef __WIN__
+void _db_suicide_()
{
- struct rusage ru;
-
- (void) getrusage(RUSAGE_SELF, &ru);
- return ru.ru_utime.tv_sec*1000 + ru.ru_utime.tv_usec/1000;
+ int retval;
+ sigset_t new_mask;
+ sigfillset(&new_mask);
+
+ fprintf(stderr, "SIGKILL myself\n");
+ fflush(stderr);
+
+ retval= kill(getpid(), SIGKILL);
+ assert(retval == 0);
+ retval= sigsuspend(&new_mask);
+ fprintf(stderr, "sigsuspend returned %d errno %d \n", retval, errno);
+ assert(FALSE); /* With full signal mask, we should never return here. */
}
+#endif /* ! __WIN__ */
-#elif defined(MSDOS) || defined(__WIN__)
-static ulong Clock()
+void _db_lock_file_()
{
- return clock()*(1000/CLOCKS_PER_SEC);
+ CODE_STATE *cs;
+ get_code_state_or_return;
+ pthread_mutex_lock(&THR_LOCK_dbug);
+ cs->locked=1;
}
-#elif defined(amiga)
-struct DateStamp { /* Yes, this is a hack, but doing it right */
- long ds_Days; /* is incredibly ugly without splitting this */
- long ds_Minute; /* off into a separate file */
- long ds_Tick;
-};
-
-static int first_clock= TRUE;
-static struct DateStamp begin;
-static struct DateStamp elapsed;
-
-static unsigned long Clock()
-{
- register struct DateStamp *now;
- register unsigned long millisec= 0;
- extern VOID *AllocMem();
-
- now= (struct DateStamp *) AllocMem((long) sizeof(struct DateStamp), 0L);
- if (now != NULL)
- {
- if (first_clock == TRUE)
- {
- first_clock= FALSE;
- (void) DateStamp(now);
- begin= *now;
- }
- (void) DateStamp(now);
- millisec= 24 * 3600 * (1000 / HZ) * (now->ds_Days - begin.ds_Days);
- millisec += 60 * (1000 / HZ) * (now->ds_Minute - begin.ds_Minute);
- millisec += (1000 / HZ) * (now->ds_Tick - begin.ds_Tick);
- (void) FreeMem(now, (long) sizeof(struct DateStamp));
- }
- return millisec;
-}
-#else
-static unsigned long Clock()
+void _db_unlock_file_()
{
- return 0;
+ CODE_STATE *cs;
+ get_code_state_or_return;
+ cs->locked=0;
+ pthread_mutex_unlock(&THR_LOCK_dbug);
}
-#endif /* RUSAGE */
-#endif /* THREADS */
-#ifdef NO_VARARGS
-
-/*
- * Fake vfprintf for systems that don't support it. If this
- * doesn't work, you are probably SOL...
- */
-
-static int vfprintf(stream, format, ap)
-FILE *stream;
-char *format;
-va_list ap;
+const char* _db_get_func_(void)
{
- int rtnval;
- ARGS_DCL;
-
- ARG0= va_arg(ap, ARGS_TYPE);
- ARG1= va_arg(ap, ARGS_TYPE);
- ARG2= va_arg(ap, ARGS_TYPE);
- ARG3= va_arg(ap, ARGS_TYPE);
- ARG4= va_arg(ap, ARGS_TYPE);
- ARG5= va_arg(ap, ARGS_TYPE);
- ARG6= va_arg(ap, ARGS_TYPE);
- ARG7= va_arg(ap, ARGS_TYPE);
- ARG8= va_arg(ap, ARGS_TYPE);
- ARG9= va_arg(ap, ARGS_TYPE);
- rtnval= fprintf(stream, format, ARGS_LIST);
- return rtnval;
+ CODE_STATE *cs;
+ get_code_state_or_return NULL;
+ return cs->func;
}
-#endif /* NO_VARARGS */
#else