summaryrefslogtreecommitdiff
path: root/dbug
diff options
context:
space:
mode:
Diffstat (limited to 'dbug')
-rw-r--r--dbug/CMakeLists.txt45
-rw-r--r--dbug/dbug.c627
-rwxr-xr-xdbug/dbug_add_tags.pl1
-rw-r--r--dbug/dbug_analyze.c605
-rw-r--r--dbug/dbug_long.h16
-rwxr-xr-xdbug/remove_function_from_trace.pl11
-rwxr-xr-xdbug/tests-t.pl5
-rw-r--r--dbug/user.r124
8 files changed, 495 insertions, 939 deletions
diff --git a/dbug/CMakeLists.txt b/dbug/CMakeLists.txt
index b0a6eba5d08..a4f30f75f97 100644
--- a/dbug/CMakeLists.txt
+++ b/dbug/CMakeLists.txt
@@ -20,3 +20,48 @@ INCLUDE_DIRECTORIES(
SET(DBUG_SOURCES dbug.c)
ADD_CONVENIENCE_LIBRARY(dbug ${DBUG_SOURCES})
TARGET_LINK_LIBRARIES(dbug mysys)
+
+ADD_EXECUTABLE(tests tests.c)
+TARGET_LINK_LIBRARIES(tests dbug)
+
+ADD_EXECUTABLE(factorial my_main.c factorial.c)
+TARGET_LINK_LIBRARIES(factorial dbug)
+
+IF(NOT WIN32)
+ FIND_PROGRAM(GROFF groff)
+ FIND_PROGRAM(NROFF nroff)
+ SET(OUTPUT_INC output1.r output2.r output3.r output4.r output5.r)
+ SET(SOURCE_INC factorial.r main.r example1.r example2.r example3.r)
+ ADD_CUSTOM_COMMAND(OUTPUT ${OUTPUT_INC}
+ DEPENDS factorial
+ COMMAND ./factorial 1 2 3 4 5 > output1.r
+ COMMAND ./factorial -\#t:o 2 3 > output2.r
+ COMMAND ./factorial -\#d:t:o 3 > output3.r
+ COMMAND ./factorial -\#d,result:o 4 > output4.r
+ COMMAND ./factorial -\#d:f,factorial:F:L:o 3 > output5.r)
+ FOREACH(file ${SOURCE_INC})
+ STRING(REGEX REPLACE "\\.r" ".c" srcfile ${file})
+ ADD_CUSTOM_COMMAND(OUTPUT ${file} DEPENDS ${srcfile}
+ COMMAND sed -e 's!\\\\!\\\\\\\\!g'
+ <${CMAKE_CURRENT_SOURCE_DIR}/${srcfile} >${file})
+ ENDFOREACH(file)
+ ADD_CUSTOM_COMMAND(OUTPUT dbug-t DEPENDS tests-t.pl
+ COMMAND cp -f ${CMAKE_CURRENT_SOURCE_DIR}/tests-t.pl dbug-t)
+ ADD_CUSTOM_TARGET(dbug-unit-tests ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/dbug-t)
+ MY_ADD_TEST(dbug)
+
+ IF(GROFF)
+ ADD_CUSTOM_COMMAND(OUTPUT user.ps
+ DEPENDS user.r ${OUTPUT_INC} ${SOURCE_INC}
+ COMMAND ${GROFF} -mm ${CMAKE_CURRENT_SOURCE_DIR}/user.r > user.ps || touch user.ps)
+ ADD_CUSTOM_TARGET(ps ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/user.ps)
+ ENDIF(GROFF)
+ IF(NROFF)
+ ADD_CUSTOM_COMMAND(OUTPUT user.t
+ DEPENDS user.r ${OUTPUT_INC} ${SOURCE_INC}
+ COMMAND ${NROFF} -mm ${CMAKE_CURRENT_SOURCE_DIR}/user.r > user.t || touch user.t)
+ ADD_CUSTOM_TARGET(t ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/user.t)
+ ENDIF(NROFF)
+
+ENDIF(NOT WIN32)
+
diff --git a/dbug/dbug.c b/dbug/dbug.c
index 2dadf7bb2d5..8d2d5082b6a 100644
--- a/dbug/dbug.c
+++ b/dbug/dbug.c
@@ -53,9 +53,6 @@
* Enhanced Software Technologies, Tempe, AZ
* asuvax!mcdphx!estinc!fnf
*
- * Binayak Banerjee (profiling enhancements)
- * 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
@@ -84,8 +81,8 @@
in pthread_mutex_lock
*/
-#undef SAFE_MUTEX
#include <my_global.h>
+#undef SAFE_MUTEX
#include <m_string.h>
#include <errno.h>
@@ -99,8 +96,8 @@
#include <process.h>
#endif
-#ifndef DBUG_OFF
-
+#include <my_valgrind.h> /* TRASH */
+#include <my_stacktrace.h> /* my_safe_print_str */
/*
* Manifest constants which may be "tuned" if desired.
@@ -125,16 +122,15 @@
#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 SANITY_CHECK_ON (1 << 12) /* Check memory on every DBUG_ENTER/RETURN */
#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)
-#define PROFILING (cs->stack->flags & PROFILE_ON)
/*
* Typedefs to make things more obvious.
@@ -143,44 +139,16 @@
#define BOOLEAN my_bool
/*
- * Make it easy to change storage classes if necessary.
- */
-
-#define IMPORT extern /* Names defined externally */
-#define EXPORT /* Allocated here, available globally */
-#define AUTO auto /* Names to be allocated on stack */
-#define REGISTER register /* Names to be placed in registers */
-
-/*
- * The default file for profiling. Could also add another flag
- * (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 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,
- * the difference represents stack used by the caller function.
- *
- */
-
-#define PROF_FILE "dbugmon.out"
-#define PROF_EFMT "E\t%ld\t%s\n"
-#define PROF_SFMT "S\t%lx\t%lx\t%s\n"
-#define PROF_XFMT "X\t%ld\t%s\n"
-
-#ifdef M_I386 /* predefined by xenix 386 compiler */
-#define AUTOS_REVERSE 1
-#else
-#define AUTOS_REVERSE 0
-#endif
-
-/*
* Externally supplied functions.
*/
#ifndef HAVE_PERROR
-static void perror(); /* Fake system/library error print routine */
+static void perror(char *s)
+{
+ if (s && *s != '\0')
+ (void) fprintf(stderr, "%s: ", s);
+ (void) fprintf(stderr, "<unknown system error>\n");
+}
#endif
/*
@@ -219,10 +187,8 @@ struct settings {
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 */
@@ -239,6 +205,8 @@ 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 */
+static const char *unknown_func= "?func";
+static const char *unknown_file= "?file";
typedef struct _db_code_state_ {
const char *process; /* Pointer to process name; usually argv[0] */
@@ -279,7 +247,7 @@ typedef struct _db_code_state_ {
#define ListDel(A,B,C) ListAddDel(A,B,C,EXCLUDE)
static struct link *ListAddDel(struct link *, const char *, const char *, int);
static struct link *ListCopy(struct link *);
-static int InList(struct link *linkp,const char *cp);
+static int InList(struct link *linkp,const char *cp, int exact_match);
static uint ListFlags(struct link *linkp);
static void FreeList(struct link *linkp);
@@ -319,6 +287,8 @@ static void DbugExit(const char *why);
static const char *DbugStrTok(const char *s);
static void DbugVfprintf(FILE *stream, const char* format, va_list args);
+static void DbugErr(CODE_STATE *, uint, const char* format, ...);
+
/*
* Miscellaneous printf format strings.
*/
@@ -341,6 +311,8 @@ static void DbugVfprintf(FILE *stream, const char* format, va_list args);
#define WRITABLE(pathname) (access(pathname, W_OK) == 0)
#endif
+static int sf_sanity();
+static void sf_terminate();
/*
** Macros to allow dbugging with threads
@@ -349,6 +321,9 @@ static void DbugVfprintf(FILE *stream, const char* format, va_list args);
#include <my_pthread.h>
static pthread_mutex_t THR_LOCK_dbug;
+/* this mutex protects all sf_* variables, and nothing else*/
+static pthread_mutex_t sf_mutex;
+
static CODE_STATE *code_state(void)
{
CODE_STATE *cs, **cs_ptr;
@@ -364,6 +339,7 @@ static CODE_STATE *code_state(void)
{
init_done=TRUE;
pthread_mutex_init(&THR_LOCK_dbug, NULL);
+ pthread_mutex_init(&sf_mutex, NULL);
bzero(&init_settings, sizeof(init_settings));
init_settings.out_file=stderr;
init_settings.flags=OPEN_APPEND;
@@ -376,8 +352,8 @@ static CODE_STATE *code_state(void)
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->func= unknown_func;
+ cs->file= unknown_file;
cs->stack=&init_settings;
*cs_ptr= cs;
}
@@ -453,25 +429,29 @@ int DbugParse(CODE_STATE *cs, const char *control)
const char *end;
int rel, f_used=0;
struct settings *stack;
+ int org_cs_locked;
stack= cs->stack;
+ if (!(org_cs_locked= cs->locked))
+ {
+ cs->locked= 1;
+ pthread_mutex_lock(&THR_LOCK_dbug);
+ }
+
if (control[0] == '-' && control[1] == '#')
control+=2;
rel= control[0] == '+' || control[0] == '-';
if ((!rel || (!stack->out_file && !stack->next)))
{
- /* Free memory associated with the state before resetting its members */
FreeState(cs, stack, 0);
stack->flags= 0;
stack->delay= 0;
stack->maxdepth= 0;
stack->sub_level= 0;
stack->out_file= stderr;
- stack->prof_file= NULL;
stack->functions= NULL;
- stack->p_functions= NULL;
stack->keywords= NULL;
stack->processes= NULL;
}
@@ -482,7 +462,6 @@ int 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->prof_file= stack->next->prof_file;
if (stack->next == &init_settings)
{
/*
@@ -493,7 +472,6 @@ int DbugParse(CODE_STATE *cs, const char *control)
*/
stack->out_file= stderr;
stack->functions= ListCopy(init_settings.functions);
- stack->p_functions= ListCopy(init_settings.p_functions);
stack->keywords= ListCopy(init_settings.keywords);
stack->processes= ListCopy(init_settings.processes);
}
@@ -501,7 +479,6 @@ int DbugParse(CODE_STATE *cs, const char *control)
{
stack->out_file= stack->next->out_file;
stack->functions= stack->next->functions;
- stack->p_functions= stack->next->p_functions;
stack->keywords= stack->next->keywords;
stack->processes= stack->next->processes;
}
@@ -513,7 +490,8 @@ int DbugParse(CODE_STATE *cs, const char *control)
int c, sign= (*control == '+') ? 1 : (*control == '-') ? -1 : 0;
if (sign) control++;
c= *control++;
- if (*control == ',') control++;
+ if (*control == ',')
+ control++;
/* XXX when adding new cases here, don't forget _db_explain_ ! */
switch (c) {
case 'd':
@@ -531,7 +509,7 @@ int DbugParse(CODE_STATE *cs, const char *control)
{
if (DEBUGGING)
stack->keywords= ListDel(stack->keywords, control, end);
- break;
+ break;
}
stack->keywords= ListAdd(stack->keywords, control, end);
stack->flags |= DEBUG_ON;
@@ -658,15 +636,26 @@ int 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);
}
+ if (!org_cs_locked)
+ {
+ pthread_mutex_unlock(&THR_LOCK_dbug);
+ cs->locked= 0;
+ }
return !rel || f_used;
}
-
+
#define framep_trace_flag(cs, frp) (frp ? \
frp->level & TRACE_ON : \
(ListFlags(cs->stack->functions) & INCLUDE) ? \
@@ -815,7 +804,7 @@ void _db_set_(const char *control)
*
* Given pointer to a debug control string in "control", pushes
* the current debug settings, parses the control string, and sets
- * up a new debug settings with DbugParse()
+ * up a new debug settings
*
*/
@@ -919,7 +908,7 @@ void _db_pop_()
} while (0)
#define str_to_buf(S) do { \
char_to_buf(','); \
- buf=strnmov(buf, (S), len+1); \
+ buf=strnmov(buf, (S), (uint) (end-buf)); \
if (buf >= end) goto overflow; \
} while (0)
#define list_to_buf(l, f) do { \
@@ -1004,7 +993,6 @@ int _db_explain_ (CODE_STATE *cs, char *buf, size_t len)
op_list_to_buf('f', cs->stack->functions, cs->stack->functions);
op_bool_to_buf('F', cs->stack->flags & FILE_ON);
op_bool_to_buf('i', cs->stack->flags & PID_ON);
- op_list_to_buf('g', cs->stack->p_functions, PROFILING);
op_bool_to_buf('L', cs->stack->flags & LINE_ON);
op_bool_to_buf('n', cs->stack->flags & DEPTH_ON);
op_bool_to_buf('N', cs->stack->flags & NUMBER_ON);
@@ -1017,6 +1005,7 @@ 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;
@@ -1118,6 +1107,8 @@ void _db_enter_(const char *_func_, const char *_file_,
if (!TRACING) break;
/* fall through */
case DO_TRACE:
+ if ((cs->stack->flags & SANITY_CHECK_ON) && sf_sanity())
+ cs->stack->flags &= ~SANITY_CHECK_ON;
if (TRACING)
{
if (!cs->locked)
@@ -1173,6 +1164,8 @@ void _db_return_(uint _line_, struct _db_stack_frame_ *_stack_frame_)
if (DoTrace(cs) & DO_TRACE)
{
+ if ((cs->stack->flags & SANITY_CHECK_ON) && sf_sanity())
+ cs->stack->flags &= ~SANITY_CHECK_ON;
if (TRACING)
{
if (!cs->locked)
@@ -1259,11 +1252,11 @@ void _db_doprnt_(const char *format,...)
va_start(args,format);
+ if (!cs->locked)
+ pthread_mutex_lock(&THR_LOCK_dbug);
if (_db_keyword_(cs, cs->u_keyword, 0))
{
int save_errno=errno;
- if (!cs->locked)
- pthread_mutex_lock(&THR_LOCK_dbug);
DoPrefix(cs, cs->u_line);
if (TRACING)
Indent(cs, cs->level + 1);
@@ -1274,6 +1267,9 @@ void _db_doprnt_(const char *format,...)
DbugFlush(cs);
errno=save_errno;
}
+ else if (!cs->locked)
+ pthread_mutex_unlock(&THR_LOCK_dbug);
+
va_end(args);
}
@@ -1315,10 +1311,10 @@ void _db_dump_(uint _line_, const char *keyword,
CODE_STATE *cs;
get_code_state_or_return;
+ if (!cs->locked)
+ pthread_mutex_lock(&THR_LOCK_dbug);
if (_db_keyword_(cs, keyword, 0))
{
- if (!cs->locked)
- pthread_mutex_lock(&THR_LOCK_dbug);
DoPrefix(cs, _line_);
if (TRACING)
{
@@ -1348,6 +1344,8 @@ void _db_dump_(uint _line_, const char *keyword,
(void) fputc('\n',cs->stack->out_file);
DbugFlush(cs);
}
+ else if (!cs->locked)
+ pthread_mutex_unlock(&THR_LOCK_dbug);
}
@@ -1391,7 +1389,7 @@ next:
subdir=0;
while (ctlp < end && *ctlp != ',')
ctlp++;
- len=ctlp-start;
+ len= (int) (ctlp-start);
if (start[len-1] == '/')
{
len--;
@@ -1492,13 +1490,13 @@ static struct link *ListCopy(struct link *orig)
*
*/
-static int InList(struct link *linkp, const char *cp)
+static int InList(struct link *linkp, const char *cp, int exact_match)
{
int result;
for (result=MATCHED; linkp != NULL; linkp= linkp->next_link)
{
- if (!fnmatch(linkp->str, cp, 0))
+ if (!(exact_match ? strcmp(linkp->str,cp) : fnmatch(linkp->str, cp, 0)))
return linkp->flags;
if (!(linkp->flags & EXCLUDE))
result=NOT_MATCHED;
@@ -1548,7 +1546,7 @@ static void PushState(CODE_STATE *cs)
struct settings *new_malloc;
new_malloc= (struct settings *) DbugMalloc(sizeof(struct settings));
- bzero(new_malloc, sizeof(struct settings));
+ bzero(new_malloc, sizeof(*new_malloc));
new_malloc->next= cs->stack;
cs->stack= new_malloc;
}
@@ -1578,19 +1576,12 @@ static void FreeState(CODE_STATE *cs, struct settings *state, int free_state)
FreeList(state->functions);
if (!is_shared(state, processes))
FreeList(state->processes);
- if (!is_shared(state, p_functions))
- FreeList(state->p_functions);
if (!is_shared(state, out_file))
DBUGCloseFile(cs, state->out_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);
}
@@ -1623,31 +1614,28 @@ void _db_end_()
called after dbug was initialized
*/
_dbug_on_= 1;
- get_code_state_or_return;
+ cs= code_state();
- while ((discard= cs->stack))
- {
- if (discard == &init_settings)
- break;
- cs->stack= discard->next;
- FreeState(cs, discard, 1);
- }
+ if (cs)
+ while ((discard= cs->stack))
+ {
+ if (discard == &init_settings)
+ break;
+ cs->stack= discard->next;
+ FreeState(cs, discard, 1);
+ }
tmp= init_settings;
- /* Use mutex lock to make it less likely anyone access out_file */
- pthread_mutex_lock(&THR_LOCK_dbug);
init_settings.flags= OPEN_APPEND;
init_settings.out_file= stderr;
- init_settings.prof_file= stderr;
init_settings.maxdepth= 0;
init_settings.delay= 0;
init_settings.sub_level= 0;
init_settings.functions= 0;
- init_settings.p_functions= 0;
init_settings.keywords= 0;
init_settings.processes= 0;
- pthread_mutex_unlock(&THR_LOCK_dbug);
FreeState(cs, &tmp, 0);
+ sf_terminate();
}
@@ -1667,8 +1655,8 @@ void _db_end_()
static int DoTrace(CODE_STATE *cs)
{
if ((cs->stack->maxdepth == 0 || cs->level <= cs->stack->maxdepth) &&
- InList(cs->stack->processes, cs->process) & (MATCHED|INCLUDE))
- switch(InList(cs->stack->functions, cs->func)) {
+ InList(cs->stack->processes, cs->process, 0) & (MATCHED|INCLUDE))
+ switch(InList(cs->stack->functions, cs->func, 0)) {
case INCLUDE|SUBDIR: return ENABLE_TRACE;
case INCLUDE: return DO_TRACE;
case MATCHED|SUBDIR:
@@ -1711,11 +1699,11 @@ FILE *_db_fp_(void)
BOOLEAN _db_keyword_(CODE_STATE *cs, const char *keyword, int strict)
{
+ int match= strict ? INCLUDE : INCLUDE|MATCHED;
get_code_state_if_not_set_or_return FALSE;
- strict=strict ? INCLUDE : INCLUDE|MATCHED;
- return DEBUGGING && DoTrace(cs) & DO_TRACE &&
- InList(cs->stack->keywords, keyword) & strict;
+ return (DEBUGGING && DoTrace(cs) & DO_TRACE &&
+ InList(cs->stack->keywords, keyword, strict) & match);
}
/*
@@ -1741,7 +1729,7 @@ BOOLEAN _db_keyword_(CODE_STATE *cs, const char *keyword, int strict)
static void Indent(CODE_STATE *cs, int indent)
{
- REGISTER int count;
+ int count;
indent= max(indent-1-cs->stack->sub_level,0)*INDENT;
for (count= 0; count < indent ; count++)
@@ -1773,7 +1761,7 @@ static void Indent(CODE_STATE *cs, int indent)
static void FreeList(struct link *linkp)
{
- REGISTER struct link *old;
+ struct link *old;
while (linkp != NULL)
{
@@ -1872,7 +1860,7 @@ static void DoPrefix(CODE_STATE *cs, uint _line_)
static void DBUGOpenFile(CODE_STATE *cs,
const char *name,const char *end,int append)
{
- REGISTER FILE *fp;
+ FILE *fp;
if (name != NULL)
{
@@ -1935,9 +1923,10 @@ static void DBUGOpenFile(CODE_STATE *cs,
static void DBUGCloseFile(CODE_STATE *cs, FILE *fp)
{
- if (fp != NULL && fp != stderr && fp != stdout && fclose(fp) == EOF)
+ if (cs && fp && fp != stderr && fp != stdout && fclose(fp) == EOF)
{
- pthread_mutex_lock(&THR_LOCK_dbug);
+ if (!cs->locked)
+ pthread_mutex_lock(&THR_LOCK_dbug);
(void) fprintf(cs->stack->out_file, ERR_CLOSE, cs->process);
perror("");
DbugFlush(cs);
@@ -1996,7 +1985,7 @@ static void DbugExit(const char *why)
static char *DbugMalloc(size_t size)
{
- register char *new_malloc;
+ char *new_malloc;
if (!(new_malloc= (char*) malloc(size)))
DbugExit("out of memory");
@@ -2037,7 +2026,7 @@ static const char *DbugStrTok(const char *s)
static const char *BaseName(const char *pathname)
{
- register const char *base;
+ const char *base;
base= strrchr(pathname, FN_LIBCHAR);
if (base++ == NullS)
@@ -2074,8 +2063,8 @@ static const char *BaseName(const char *pathname)
static BOOLEAN Writable(const char *pathname)
{
- REGISTER BOOLEAN granted;
- REGISTER char *lastslash;
+ BOOLEAN granted;
+ char *lastslash;
granted= FALSE;
if (EXISTS(pathname))
@@ -2099,105 +2088,11 @@ static BOOLEAN Writable(const char *pathname)
}
#endif
-
/*
- * FUNCTION
- *
- * _db_setjmp_ save debugger environment
- *
- * SYNOPSIS
- *
- * VOID _db_setjmp_()
- *
- * DESCRIPTION
- *
- * Invoked as part of the user's DBUG_SETJMP macro to save
- * the debugger environment in parallel with saving the user's
- * environment.
- *
- */
-
-#ifdef HAVE_LONGJMP
-
-EXPORT void _db_setjmp_()
-{
- CODE_STATE *cs;
- get_code_state_or_return;
-
- cs->jmplevel= cs->level;
- cs->jmpfunc= cs->func;
- cs->jmpfile= cs->file;
-}
-
-/*
- * FUNCTION
- *
- * _db_longjmp_ restore previously saved debugger environment
- *
- * SYNOPSIS
- *
- * VOID _db_longjmp_()
- *
- * DESCRIPTION
- *
- * Invoked as part of the user's DBUG_LONGJMP macro to restore
- * the debugger environment in parallel with restoring the user's
- * previously saved environment.
- *
- */
-
-EXPORT void _db_longjmp_()
-{
- CODE_STATE *cs;
- get_code_state_or_return;
-
- cs->level= cs->jmplevel;
- if (cs->jmpfunc)
- cs->func= cs->jmpfunc;
- if (cs->jmpfile)
- cs->file= cs->jmpfile;
-}
-#endif
-
-/*
- * FUNCTION
- *
- * perror perror simulation for systems that don't have it
- *
- * SYNOPSIS
- *
- * static VOID perror(s)
- * char *s;
- *
- * DESCRIPTION
- *
- * Perror produces a message on the standard error stream which
- * provides more information about the library or system error
- * just encountered. The argument string s is printed, followed
- * by a ':', a blank, and then a message and a newline.
- *
- * An undocumented feature of the unix perror is that if the string
- * 's' is a null string (NOT a NULL pointer!), then the ':' and
- * blank are not printed.
- *
- * This version just complains about an "unknown system error".
- *
- */
-
-#ifndef HAVE_PERROR
-static void perror(s)
-char *s;
-{
- if (s && *s != '\0')
- (void) fprintf(stderr, "%s: ", s);
- (void) fprintf(stderr, "<unknown system error>\n");
-}
-#endif /* HAVE_PERROR */
-
-
- /* flush dbug-stream, free mutex lock & wait delay */
- /* This is because some systems (MSDOS!!) dosn't flush fileheader */
- /* and dbug-file isn't readable after a system crash !! */
+ flush dbug-stream, free mutex lock & wait delay
+ This is because some systems (MSDOS!!) dosn't flush fileheader
+ and dbug-file isn't readable after a system crash !!
+*/
static void DbugFlush(CODE_STATE *cs)
{
@@ -2216,7 +2111,7 @@ static void DbugFlush(CODE_STATE *cs)
void _db_flush_()
{
- CODE_STATE *cs= NULL;
+ CODE_STATE *cs;
get_code_state_or_return;
(void) fflush(cs->stack->out_file);
}
@@ -2264,19 +2159,333 @@ const char* _db_get_func_(void)
return cs->func;
}
+/*
+ prints the error message, followed by a stack trace
+ of the specified depth
+*/
+static void DbugErr(CODE_STATE *cs, uint depth, const char* format, ...)
+{
+ va_list args;
+ va_start(args,format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+
+ if (cs || ((cs= code_state())))
+ {
+ uint i= depth;
+ struct _db_stack_frame_ *frame= cs->framep;
+ while (i-- && frame)
+ {
+ fprintf(stderr, ", at %s", frame->func);
+ frame= frame->prev;
+ }
+ }
-#else
+ fprintf(stderr, "\n");
+}
+
+/********************************************************************
+ memory debugger
+ based on safemalloc, memory sub-system, written by Bjorn Benson
+********************************************************************/
+
+#ifndef SF_REMEMBER_FRAMES
+#define SF_REMEMBER_FRAMES 16
+#endif
+
+/*
+ Structure that stores information of an allocated memory block
+ The data is at &struct_adr+sizeof(struct irem)
+ Note that sizeof(struct st_irem) % sizeof(double) == 0
+*/
+struct st_irem
+{
+ struct st_irem *next; /* Linked list of structures */
+ struct st_irem *prev; /* Other link */
+ size_t datasize; /* Size requested */
+ const char *frame[SF_REMEMBER_FRAMES]; /* call stack */
+ uint32 marker; /* Underrun marker value */
+};
+
+/*
+ DBUG_MALLOC/DBUG_REALLOC/DBUG_FREE can be called even
+ before dbug is initialized. We cannot properly take into account
+ these calls, but we can at least wrap allocated memory
+ in st_irem's and check for overrun/underruns.
+ These special irem's - that are not linked into a global list -
+ are distinguished by a special value in the 'next' pointer.
+*/
+#define NOT_LINKED ((struct st_irem *)1)
+
+size_t sf_malloc_mem_limit= (intptr)~0ULL;
+static size_t sf_malloc_cur_memory= 0L; /* Current memory usage */
+static size_t sf_malloc_max_memory= 0L; /* Maximum memory usage */
+
+static int sf_malloc_count= 0; /* Number of allocated chunks */
+
+static void *sf_min_adress= (void*) (intptr)~0ULL,
+ *sf_max_adress= 0;
+
+static struct st_irem *sf_malloc_root = 0;
+
+#define MAGICSTART 0x14235296 /* A magic value for underrun key */
+
+#define MAGICEND0 0x68 /* Magic values for overrun keys */
+#define MAGICEND1 0x34 /* " */
+#define MAGICEND2 0x7A /* " */
+#define MAGICEND3 0x15 /* " */
+
+static int bad_ptr(const char *where, void *ptr);
+static void free_memory(void *ptr);
/*
- * Dummy function, workaround for MySQL bug#14420 related
- * build failure on a platform where linking with an empty
- * archive fails.
+ * FUNCTION
*
- * This block can be removed as soon as a fix for bug#14420
- * is implemented.
+ * _db_malloc_ allocates memory
+ *
+ * SYNOPSIS
+ *
+ * void *_db_malloc_(size_t size)
+ * size_t size; Bytes to allocate
*/
-int i_am_a_dummy_function() {
- return 0;
+
+void *_db_malloc_(size_t size)
+{
+ CODE_STATE *cs= code_state();
+ struct st_irem *irem;
+ uchar *data;
+ struct _db_stack_frame_ *frame;
+ int i= 0;
+
+ if (size + sf_malloc_cur_memory > sf_malloc_mem_limit)
+ irem= 0;
+ else
+ irem= (struct st_irem *) malloc (sizeof(struct st_irem) + size + 4);
+
+ if (!irem)
+ return 0;
+
+ compile_time_assert(sizeof(struct st_irem) % sizeof(double) == 0);
+
+ /* Fill up the structure */
+ data= (uchar*) (irem + 1);
+ irem->datasize= size;
+ irem->prev= 0;
+ irem->marker= MAGICSTART;
+ data[size + 0]= MAGICEND0;
+ data[size + 1]= MAGICEND1;
+ data[size + 2]= MAGICEND2;
+ data[size + 3]= MAGICEND3;
+
+ if (cs && cs->framep)
+ {
+ for (frame= cs->framep;
+ i < SF_REMEMBER_FRAMES && frame->func != unknown_func;
+ i++, frame= frame->prev)
+ irem->frame[i]= frame->func;
+ }
+
+ if (i < SF_REMEMBER_FRAMES)
+ irem->frame[i]= unknown_func;
+ if (i==0)
+ irem->frame[0]= (char*)1;
+
+ if (init_done)
+ {
+ pthread_mutex_lock(&sf_mutex);
+ /* Add this structure to the linked list */
+ if ((irem->next= sf_malloc_root))
+ sf_malloc_root->prev= irem;
+ sf_malloc_root= irem;
+
+ /* Keep the statistics */
+ sf_malloc_count++;
+ sf_malloc_cur_memory+= size;
+ set_if_bigger(sf_malloc_max_memory, sf_malloc_cur_memory);
+ set_if_smaller(sf_min_adress, (void*)data);
+ set_if_bigger(sf_max_adress, (void*)data);
+ pthread_mutex_unlock(&sf_mutex);
+ }
+ else
+ {
+ set_if_bigger(sf_malloc_max_memory, sf_malloc_cur_memory);
+ set_if_smaller(sf_min_adress, (void*)data);
+ set_if_bigger(sf_max_adress, (void*)data);
+ irem->next= NOT_LINKED;
+ }
+
+ TRASH_ALLOC(data, size);
+ return data;
}
-#endif
+void *_db_realloc_(void *ptr, size_t size)
+{
+ char *data;
+
+ if (!ptr)
+ return _db_malloc_(size);
+
+ if (bad_ptr("Reallocating", ptr))
+ return 0;
+
+ if ((data= _db_malloc_(size)))
+ {
+ struct st_irem *irem= (struct st_irem *)ptr - 1;
+ set_if_smaller(size, irem->datasize);
+ memcpy(data, ptr, size);
+ free_memory(ptr);
+ }
+ return data;
+}
+
+void _db_free_(void *ptr)
+{
+ if (!ptr || bad_ptr("Freeing", ptr))
+ return;
+
+ free_memory(ptr);
+ return;
+}
+
+static void free_memory(void *ptr)
+{
+ struct st_irem *irem= (struct st_irem *)ptr - 1;
+
+ if (irem->next != NOT_LINKED)
+ {
+ pthread_mutex_lock(&sf_mutex);
+ /* Remove this structure from the linked list */
+ if (irem->prev)
+ irem->prev->next= irem->next;
+ else
+ sf_malloc_root= irem->next;
+
+ if (irem->next)
+ irem->next->prev= irem->prev;
+
+ /* Handle the statistics */
+ sf_malloc_cur_memory-= irem->datasize;
+ sf_malloc_count--;
+ pthread_mutex_unlock(&sf_mutex);
+ }
+
+ /* only trash the data and magic values, but keep the stack trace */
+ TRASH_FREE((uchar*)(irem + 1) - 4, irem->datasize + 8);
+ free(irem);
+ return;
+}
+
+#define SF_ADD_NL 1
+#define SF_USE_SAFE_PRINT 2
+static void print_allocated_at(struct st_irem *irem, int flags)
+{
+ int i;
+ const char *allocated= flags & SF_ADD_NL ? "Allocated" : ", allocated";
+
+ for (i=0;
+ i < SF_REMEMBER_FRAMES && irem->frame[i] != unknown_func;
+ i++)
+ {
+ fprintf(stderr, "%s at ", i ? "," : allocated);
+ if (flags & SF_USE_SAFE_PRINT)
+ my_safe_print_str(irem->frame[i], 80);
+ else
+ fputs(irem->frame[i], stderr);
+ }
+ if (i && (flags & SF_ADD_NL))
+ fprintf(stderr, "\n");
+}
+
+static int bad_ptr(const char *where, void *ptr)
+{
+ struct st_irem *irem= (struct st_irem *)ptr - 1;
+ const uchar *magicend;
+
+ if (((intptr) ptr) % sizeof(double))
+ {
+ DbugErr(0, SF_REMEMBER_FRAMES, "Error: %s wrong aligned pointer", where);
+ return 1;
+ }
+ if (ptr < sf_min_adress || ptr > sf_max_adress)
+ {
+ DbugErr(0, SF_REMEMBER_FRAMES, "Error: %s pointer out of range", where);
+ return 1;
+ }
+ if (irem->marker != MAGICSTART)
+ {
+ DbugErr(0, SF_REMEMBER_FRAMES,
+ "Error: %s unallocated data or underrun buffer", where);
+ /*
+ we cannot use print_allocated_at here:
+ if the memory was not allocated, there's nothing to print,
+ if it was allocated and underrun, call stack may be corrupted
+ */
+ return 1;
+ }
+
+ magicend= (uchar*)ptr + irem->datasize;
+ if (magicend[0] != MAGICEND0 ||
+ magicend[1] != MAGICEND1 ||
+ magicend[2] != MAGICEND2 ||
+ magicend[3] != MAGICEND3)
+ {
+ DbugErr(0, SF_REMEMBER_FRAMES, "Error: %s overrun buffer", where);
+ print_allocated_at(irem, SF_ADD_NL);
+ return 1;
+ }
+
+ return 0;
+}
+
+/* check all allocated memory list for consistency */
+static int sf_sanity()
+{
+ struct st_irem *irem;
+ int flag= 0;
+ int count= 0;
+
+ pthread_mutex_lock(&sf_mutex);
+ count= sf_malloc_count;
+ for (irem= sf_malloc_root; irem && count > 0; count--, irem= irem->next)
+ flag+= bad_ptr("Safemalloc", irem + 1);
+ pthread_mutex_unlock(&sf_mutex);
+ if (count || irem)
+ {
+ DbugErr(0, SF_REMEMBER_FRAMES, "Error: Safemalloc link list destroyed");
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * FUNCTION
+ *
+ * sf_terminate Report on all the memory pieces that have not been free'd
+ *
+ * SYNOPSIS
+ *
+ * void sf_terminate()
+ */
+
+static void sf_terminate()
+{
+ struct st_irem *irem;
+
+ sf_sanity();
+
+ /* Report on all the memory that was allocated but not free'd */
+ if ((irem= sf_malloc_root))
+ {
+ while (irem)
+ {
+ fprintf(stderr, "Warning: %6lu bytes at %p are not freed", (ulong) irem->datasize, irem + 1);
+ print_allocated_at(irem, SF_USE_SAFE_PRINT);
+ fprintf(stderr, "\n");
+ irem= irem->next;
+ }
+ fprintf(stderr, "Memory lost: %lu bytes in %d chunks\n",
+ (ulong) sf_malloc_cur_memory, sf_malloc_count);
+ }
+
+ return;
+}
diff --git a/dbug/dbug_add_tags.pl b/dbug/dbug_add_tags.pl
index 66096450f82..fe3637b4d12 100755
--- a/dbug/dbug_add_tags.pl
+++ b/dbug/dbug_add_tags.pl
@@ -86,4 +86,3 @@ while($src=shift)
}
warn "All done!\n";
-
diff --git a/dbug/dbug_analyze.c b/dbug/dbug_analyze.c
deleted file mode 100644
index cd395cd3b02..00000000000
--- a/dbug/dbug_analyze.c
+++ /dev/null
@@ -1,605 +0,0 @@
-/*
- * Analyze the profile file (cmon.out) written out by the dbug
- * routines with profiling enabled.
- *
- * Copyright June 1987, Binayak Banerjee
- * All rights reserved.
- *
- * This program may be freely distributed under the same terms and
- * conditions as Fred Fish's Dbug package.
- *
- * Compile with -- cc -O -s -o %s analyze.c
- *
- * Analyze will read an trace file created by the dbug package
- * (when run with traceing enabled). It will then produce a
- * summary on standard output listing the name of each traced
- * function, the number of times it was called, the percentage
- * of total calls, the time spent executing the function, the
- * proportion of the total time and the 'importance'. The last
- * is a metric which is obtained by multiplying the proportions
- * of calls and the proportions of time for each function. The
- * greater the importance, the more likely it is that a speedup
- * could be obtained by reducing the time taken by that function.
- *
- * Note that the timing values that you obtain are only rough
- * measures. The overhead of the dbug package is included
- * within. However, there is no need to link in special profiled
- * libraries and the like.
- *
- * CHANGES:
- *
- * 2-Mar-89: fnf
- * Changes to support tracking of stack usage. This required
- * reordering the fields in the profile log file to make
- * parsing of different record types easier. Corresponding
- * changes made in dbug runtime library. Also used this
- * opportunity to reformat the code more to my liking (my
- * apologies to Binayak Banerjee for "uglifying" his code).
- *
- * 24-Jul-87: fnf
- * Because I tend to use functions names like
- * "ExternalFunctionDoingSomething", I've rearranged the
- * printout to put the function name last in each line, so
- * long names don't screw up the formatting unless they are
- * *very* long and wrap around the screen width...
- *
- * 24-Jul-87: fnf
- * Modified to put out table very similar to Unix profiler
- * by default, but also puts out original verbose table
- * if invoked with -v flag.
- */
-
-#include <my_global.h>
-#include <m_string.h>
-#include <my_pthread.h>
-
-static char *my_name;
-static int verbose;
-
-/*
- * Structure of the stack.
- */
-
-#define PRO_FILE "dbugmon.out" /* Default output file name */
-#define STACKSIZ 100 /* Maximum function nesting */
-#define MAXPROCS 10000 /* Maximum number of function calls */
-
-# ifdef BSD
-# include <sysexits.h>
-# else
-# define EX_SOFTWARE 1
-# define EX_DATAERR 1
-# define EX_USAGE 1
-# define EX_OSERR 1
-# define EX_IOERR 1
-#ifndef EX_OK
-# define EX_OK 0
-#endif
-# endif
-
-#define __MERF_OO_ "%s: Malloc Failed in %s: %d\n"
-
-#define MALLOC(Ptr,Num,Typ) do /* Malloc w/error checking & exit */ \
- if (!(Ptr = (Typ *)malloc((Num)*(sizeof(Typ))))) \
- {fprintf(stderr,__MERF_OO_,my_name,__FILE__,__LINE__);\
- exit(EX_OSERR);} while(0)
-
-#define Malloc(Ptr,Num,Typ) do /* Weaker version of above */\
- if (!(Ptr = (Typ *)malloc((Num)*(sizeof(Typ))))) \
- fprintf(stderr,__MERF_OO_,my_name,__FILE__,__LINE__);\
- while(0)
-
-#define FILEOPEN(Fp,Fn,Mod) do /* File open with error exit */ \
- if (!(Fp = fopen(Fn,Mod)))\
- {fprintf(stderr,"%s: Couldn't open %s\n",my_name,Fn);\
- exit(EX_IOERR);} while(0)
-
-#define Fileopen(Fp,Fn,Mod) do /* Weaker version of above */ \
- if(!(Fp = fopen(Fn,Mod))) \
- fprintf(stderr,"%s: Couldn't open %s\n",my_name,Fn);\
- while(0)
-
-
-struct stack_t {
- unsigned int pos; /* which function? */
- unsigned long time; /* Time that this was entered */
- unsigned long children; /* Time spent in called funcs */
-};
-
-static struct stack_t fn_stack[STACKSIZ+1];
-
-static unsigned int stacktop = 0; /* Lowest stack position is a dummy */
-
-static unsigned long tot_time = 0;
-static unsigned long tot_calls = 0;
-static unsigned long highstack = 0;
-static unsigned long lowstack = (ulong) ~0;
-
-/*
- * top() returns a pointer to the top item on the stack.
- * (was a function, now a macro)
- */
-
-#define top() &fn_stack[stacktop]
-
-/*
- * Push - Push the given record on the stack.
- */
-
-void push (name_pos, time_entered)
-register unsigned int name_pos;
-register unsigned long time_entered;
-{
- register struct stack_t *t;
-
- DBUG_ENTER("push");
- if (++stacktop > STACKSIZ) {
- fprintf (DBUG_FILE,"%s: stack overflow (%s:%d)\n",
- my_name, __FILE__, __LINE__);
- exit (EX_SOFTWARE);
- }
- DBUG_PRINT ("push", ("%d %ld",name_pos,time_entered));
- t = &fn_stack[stacktop];
- t -> pos = name_pos;
- t -> time = time_entered;
- t -> children = 0;
- DBUG_VOID_RETURN;
-}
-
-/*
- * Pop - pop the top item off the stack, assigning the field values
- * to the arguments. Returns 0 on stack underflow, or on popping first
- * item off stack.
- */
-
-unsigned int pop (name_pos, time_entered, child_time)
-register unsigned int *name_pos;
-register unsigned long *time_entered;
-register unsigned long *child_time;
-{
- register struct stack_t *temp;
- register unsigned int rtnval;
-
- DBUG_ENTER ("pop");
-
- if (stacktop < 1) {
- rtnval = 0;
- } else {
- temp = &fn_stack[stacktop];
- *name_pos = temp->pos;
- *time_entered = temp->time;
- *child_time = temp->children;
- DBUG_PRINT ("pop", ("%d %lu %lu",*name_pos,*time_entered,*child_time));
- rtnval = stacktop--;
- }
- DBUG_RETURN (rtnval);
-}
-
-/*
- * We keep the function info in another array (serves as a simple
- * symbol table)
- */
-
-struct module_t {
- char *name;
- unsigned long m_time;
- unsigned long m_calls;
- unsigned long m_stkuse;
-};
-
-static struct module_t modules[MAXPROCS];
-
-/*
- * We keep a binary search tree in order to look up function names
- * quickly (and sort them at the end.
- */
-
-struct bnode {
- unsigned int lchild; /* Index of left subtree */
- unsigned int rchild; /* Index of right subtree */
- unsigned int pos; /* Index of module_name entry */
-};
-
-static struct bnode s_table[MAXPROCS];
-
-static unsigned int n_items = 0; /* No. of items in the array so far */
-
-/*
- * Need a function to allocate space for a string and squirrel it away.
- */
-
-char *strsave (s)
-char *s;
-{
- register char *retval;
- register unsigned int len;
-
- DBUG_ENTER ("strsave");
- DBUG_PRINT ("strsave", ("%s",s));
- if (!s || (len = strlen (s)) == 0) {
- DBUG_RETURN (0);
- }
- MALLOC (retval, ++len, char);
- strcpy (retval, s);
- DBUG_RETURN (retval);
-}
-
-/*
- * add() - adds m_name to the table (if not already there), and returns
- * the index of its location in the table. Checks s_table (which is a
- * binary search tree) to see whether or not it should be added.
- */
-
-unsigned int add (m_name)
-char *m_name;
-{
- register unsigned int ind = 0;
- register int cmp;
-
- DBUG_ENTER ("add");
- if (n_items == 0) { /* First item to be added */
- s_table[0].pos = ind;
- s_table[0].lchild = s_table[0].rchild = MAXPROCS;
- addit:
- modules[n_items].name = strsave (m_name);
- modules[n_items].m_time = 0;
- modules[n_items].m_calls = 0;
- modules[n_items].m_stkuse = 0;
- DBUG_RETURN (n_items++);
- }
- while ((cmp = strcmp (m_name,modules[ind].name))) {
- if (cmp < 0) { /* In left subtree */
- if (s_table[ind].lchild == MAXPROCS) {
- /* Add as left child */
- if (n_items >= MAXPROCS) {
- fprintf (DBUG_FILE,
- "%s: Too many functions being profiled\n",
- my_name);
- exit (EX_SOFTWARE);
- }
- s_table[n_items].pos = s_table[ind].lchild = n_items;
- s_table[n_items].lchild = s_table[n_items].rchild = MAXPROCS;
-#ifdef notdef
- modules[n_items].name = strsave (m_name);
- modules[n_items].m_time = modules[n_items].m_calls = 0;
- DBUG_RETURN (n_items++);
-#else
- goto addit;
-#endif
-
- }
- ind = s_table[ind].lchild; /* else traverse l-tree */
- } else {
- if (s_table[ind].rchild == MAXPROCS) {
- /* Add as right child */
- if (n_items >= MAXPROCS) {
- fprintf (DBUG_FILE,
- "%s: Too many functions being profiled\n",
- my_name);
- exit (EX_SOFTWARE);
- }
- s_table[n_items].pos = s_table[ind].rchild = n_items;
- s_table[n_items].lchild = s_table[n_items].rchild = MAXPROCS;
-#ifdef notdef
- modules[n_items].name = strsave (m_name);
- modules[n_items].m_time = modules[n_items].m_calls = 0;
- DBUG_RETURN (n_items++);
-#else
- goto addit;
-#endif
-
- }
- ind = s_table[ind].rchild; /* else traverse r-tree */
- }
- }
- DBUG_RETURN (ind);
-}
-
-/*
- * process() - process the input file, filling in the modules table.
- */
-
-void process (inf)
-FILE *inf;
-{
- char buf[BUFSIZ];
- char fn_name[64]; /* Max length of fn_name */
- unsigned long fn_time;
- unsigned long fn_sbot;
- unsigned long fn_ssz;
- unsigned long lastuse;
- unsigned int pos;
- unsigned long local_time;
- unsigned int oldpos;
- unsigned long oldtime;
- unsigned long oldchild;
- struct stack_t *t;
-
- DBUG_ENTER ("process");
- while (fgets (buf,BUFSIZ,inf) != NULL) {
- switch (buf[0]) {
- case 'E':
- sscanf (buf+2, "%ld %64s", &fn_time, fn_name);
- DBUG_PRINT ("erec", ("%ld %s", fn_time, fn_name));
- pos = add (fn_name);
- push (pos, fn_time);
- break;
- case 'X':
- sscanf (buf+2, "%ld %64s", &fn_time, fn_name);
- DBUG_PRINT ("xrec", ("%ld %s", fn_time, fn_name));
- pos = add (fn_name);
- /*
- * An exited function implies that all stacked
- * functions are also exited, until the matching
- * function is found on the stack.
- */
- while (pop (&oldpos, &oldtime, &oldchild)) {
- DBUG_PRINT ("popped", ("%lu %lu", oldtime, oldchild));
- local_time = fn_time - oldtime;
- t = top ();
- t -> children += local_time;
- DBUG_PRINT ("update", ("%s", modules[t -> pos].name));
- DBUG_PRINT ("update", ("%lu", t -> children));
- local_time -= oldchild;
- modules[oldpos].m_time += local_time;
- modules[oldpos].m_calls++;
- tot_time += local_time;
- tot_calls++;
- if (pos == oldpos) {
- goto next_line; /* Should be a break2 */
- }
- }
- /*
- * Assume that item seen started at time 0.
- * (True for function main). But initialize
- * it so that it works the next time too.
- */
- t = top ();
- local_time = fn_time - t -> time - t -> children;
- t -> time = fn_time; t -> children = 0;
- modules[pos].m_time += local_time;
- modules[pos].m_calls++;
- tot_time += local_time;
- tot_calls++;
- break;
- case 'S':
- sscanf (buf+2, "%lx %lx %64s", &fn_sbot, &fn_ssz, fn_name);
- DBUG_PRINT ("srec", ("%lx %lx %s", fn_sbot, fn_ssz, fn_name));
- pos = add (fn_name);
- lastuse = modules[pos].m_stkuse;
-#if 0
- /*
- * Needs further thought. Stack use is determined by
- * difference in stack between two functions with DBUG_ENTER
- * macros. If A calls B calls C, where A and C have the
- * macros, and B doesn't, then B's stack use will be lumped
- * in with either A's or C's. If somewhere else A calls
- * C directly, the stack use will seem to change. Just
- * take the biggest for now...
- */
- if (lastuse > 0 && lastuse != fn_ssz) {
- fprintf (stderr,
- "warning - %s stack use changed (%lx to %lx)\n",
- fn_name, lastuse, fn_ssz);
- }
-#endif
- if (fn_ssz > lastuse) {
- modules[pos].m_stkuse = fn_ssz;
- }
- if (fn_sbot > highstack) {
- highstack = fn_sbot;
- } else if (fn_sbot < lowstack) {
- lowstack = fn_sbot;
- }
- break;
- default:
- fprintf (stderr, "unknown record type '%c'\n", buf[0]);
- break;
- }
- next_line:;
- }
-
- /*
- * Now, we've hit eof. If we still have stuff stacked, then we
- * assume that the user called exit, so give everything the exited
- * time of fn_time.
- */
- while (pop (&oldpos,&oldtime,&oldchild)) {
- local_time = fn_time - oldtime;
- t = top ();
- t -> children += local_time;
- local_time -= oldchild;
- modules[oldpos].m_time += local_time;
- modules[oldpos].m_calls++;
- tot_time += local_time;
- tot_calls++;
- }
- DBUG_VOID_RETURN;
-}
-
-/*
- * out_header () -- print out the header of the report.
- */
-
-void out_header (outf)
-FILE *outf;
-{
- DBUG_ENTER ("out_header");
- if (verbose) {
- fprintf (outf, "Profile of Execution\n");
- fprintf (outf, "Execution times are in milliseconds\n\n");
- fprintf (outf, " Calls\t\t\t Time\n");
- fprintf (outf, " -----\t\t\t ----\n");
- fprintf (outf, "Times\tPercentage\tTime Spent\tPercentage\n");
- fprintf (outf, "Called\tof total\tin Function\tof total Importance\tFunction\n");
- fprintf (outf, "======\t==========\t===========\t========== ==========\t========\t\n");
- } else {
- fprintf (outf, "%ld bytes of stack used, from %lx down to %lx\n\n",
- highstack - lowstack, highstack, lowstack);
- fprintf (outf,
- " %%time sec #call ms/call %%calls weight stack name\n");
- }
- DBUG_VOID_RETURN;
-}
-
-/*
- * out_trailer () - writes out the summary line of the report.
- */
-
-void out_trailer (outf,sum_calls,sum_time)
-FILE *outf;
-unsigned long int sum_calls, sum_time;
-{
- DBUG_ENTER ("out_trailer");
- if (verbose)
- {
- fprintf(outf, "======\t==========\t===========\t==========\t========\n");
- fprintf(outf, "%6ld\t%10.2f\t%11ld\t%10.2f\t\t%-15s\n",
- sum_calls, 100.0, sum_time, 100.0, "Totals");
- }
- DBUG_VOID_RETURN;
-}
-
-/*
- * out_item () - prints out the output line for a single entry,
- * and sets the calls and time fields appropriately.
- */
-
-void out_item (outf, m,called,timed)
-FILE *outf;
-register struct module_t *m;
-unsigned long int *called, *timed;
-{
- char *name = m -> name;
- register unsigned int calls = m -> m_calls;
- register unsigned long local_time = m -> m_time;
- register unsigned long stkuse = m -> m_stkuse;
- unsigned int import;
- double per_time = 0.0;
- double per_calls = 0.0;
- double ms_per_call, local_ftime;
-
- DBUG_ENTER ("out_item");
-
- if (tot_time > 0) {
- per_time = (double) (local_time * 100) / (double) tot_time;
- }
- if (tot_calls > 0) {
- per_calls = (double) (calls * 100) / (double) tot_calls;
- }
- import = (unsigned int) (per_time * per_calls);
-
- if (verbose) {
- fprintf (outf, "%6d\t%10.2f\t%11ld\t%10.2f %10d\t%-15s\n",
- calls, per_calls, local_time, per_time, import, name);
- } else {
- ms_per_call = local_time;
- ms_per_call /= calls;
- local_ftime = local_time;
- local_ftime /= 1000;
- fprintf(outf, "%8.2f%8.3f%8u%8.3f%8.2f%8u%8lu %-s\n",
- per_time, local_ftime, calls, ms_per_call, per_calls, import,
- stkuse, name);
- }
- *called = calls;
- *timed = local_time;
- DBUG_VOID_RETURN;
-}
-
-/*
- * out_body (outf, root,s_calls,s_time) -- Performs an inorder traversal
- * on the binary search tree (root). Calls out_item to actually print
- * the item out.
- */
-
-void out_body (outf, root,s_calls,s_time)
-FILE *outf;
-register unsigned int root;
-register unsigned long int *s_calls, *s_time;
-{
- unsigned long int calls, local_time;
-
- DBUG_ENTER ("out_body");
- DBUG_PRINT ("out_body", ("%lu,%lu",*s_calls,*s_time));
- if (root == MAXPROCS) {
- DBUG_PRINT ("out_body", ("%lu,%lu",*s_calls,*s_time));
- } else {
- while (root != MAXPROCS) {
- out_body (outf, s_table[root].lchild,s_calls,s_time);
- out_item (outf, &modules[s_table[root].pos],&calls,&local_time);
- DBUG_PRINT ("out_body", ("-- %lu -- %lu --", calls, local_time));
- *s_calls += calls;
- *s_time += local_time;
- root = s_table[root].rchild;
- }
- DBUG_PRINT ("out_body", ("%lu,%lu", *s_calls, *s_time));
- }
- DBUG_VOID_RETURN;
-}
-
-/*
- * output () - print out a nice sorted output report on outf.
- */
-
-void output (outf)
-FILE *outf;
-{
- unsigned long int sum_calls = 0;
- unsigned long int sum_time = 0;
-
- DBUG_ENTER ("output");
- if (n_items == 0) {
- fprintf (outf, "%s: No functions to trace\n", my_name);
- exit (EX_DATAERR);
- }
- out_header (outf);
- out_body (outf, 0,&sum_calls,&sum_time);
- out_trailer (outf, sum_calls,sum_time);
- DBUG_VOID_RETURN;
-}
-
-
-#define usage() fprintf (DBUG_FILE,"Usage: %s [-v] [prof-file]\n",my_name)
-
-extern int optind;
-extern char *optarg;
-
-int main (int argc, char **argv)
-{
- register int c;
- int badflg = 0;
- FILE *infile;
- FILE *outfile = {stdout};
-
- my_thread_global_init();
- {
- DBUG_ENTER ("main");
- DBUG_PROCESS (argv[0]);
- my_name = argv[0];
- while ((c = getopt (argc,argv,"#:v")) != EOF) {
- switch (c) {
- case '#': /* Debugging Macro enable */
- DBUG_PUSH (optarg);
- break;
- case 'v': /* Verbose mode */
- verbose++;
- break;
- default:
- badflg++;
- break;
- }
- }
- if (badflg) {
- usage ();
- DBUG_RETURN (EX_USAGE);
- }
- if (optind < argc) {
- FILEOPEN (infile, argv[optind], "r");
- } else {
- FILEOPEN (infile, PRO_FILE, "r");
- }
- process (infile);
- output (outfile);
- DBUG_RETURN (EX_OK);
- }
-}
diff --git a/dbug/dbug_long.h b/dbug/dbug_long.h
index 829df181ef1..e77218b29b7 100644
--- a/dbug/dbug_long.h
+++ b/dbug/dbug_long.h
@@ -116,16 +116,10 @@
# define DBUG_VOID_RETURN return
# define DBUG_EXECUTE(keyword,a1)
# define DBUG_PRINT(keyword,arglist)
-# define DBUG_2(keyword,format) /* Obsolete */
-# define DBUG_3(keyword,format,a1) /* Obsolete */
-# define DBUG_4(keyword,format,a1,a2) /* Obsolete */
-# define DBUG_5(keyword,format,a1,a2,a3) /* Obsolete */
# define DBUG_PUSH(a1)
# define DBUG_POP()
# define DBUG_PROCESS(a1)
# define DBUG_FILE (stderr)
-# define DBUG_SETJMP setjmp
-# define DBUG_LONGJMP longjmp
# define DBUG_DUMP(keyword,a1)
# else
# define DBUG_ENTER(a) \
@@ -142,19 +136,9 @@
{if (_db_on_) {if (_db_keyword_ (keyword)) { a1 }}}
# define DBUG_PRINT(keyword,arglist) \
{if (_db_on_) {_db_pargs_(__LINE__,keyword); _db_doprnt_ arglist;}}
-# define DBUG_2(keyword,format) \
- DBUG_PRINT(keyword,(format)) /* Obsolete */
-# define DBUG_3(keyword,format,a1) \
- DBUG_PRINT(keyword,(format,a1)) /* Obsolete */
-# define DBUG_4(keyword,format,a1,a2) \
- DBUG_PRINT(keyword,(format,a1,a2)) /* Obsolete */
-# define DBUG_5(keyword,format,a1,a2,a3) \
- DBUG_PRINT(keyword,(format,a1,a2,a3)) /* Obsolete */
# define DBUG_PUSH(a1) _db_push_ (a1)
# define DBUG_POP() _db_pop_ ()
# define DBUG_PROCESS(a1) (_db_process_ = a1)
# define DBUG_FILE (_db_fp_)
-# define DBUG_SETJMP(a1) (_db_setjmp_ (), setjmp (a1))
-# define DBUG_LONGJMP(a1,a2) (_db_longjmp_ (), longjmp (a1, a2))
# define DBUG_DUMP(keyword,a1,a2) _db_dump_(__LINE__,keyword,a1,a2)
# endif
diff --git a/dbug/remove_function_from_trace.pl b/dbug/remove_function_from_trace.pl
index 1da9e25f9ba..380df168caf 100755
--- a/dbug/remove_function_from_trace.pl
+++ b/dbug/remove_function_from_trace.pl
@@ -1,6 +1,5 @@
#!/usr/bin/perl
-
die <<EEE unless @ARGV;
Usage: $0 func1 [func2 [ ...] ]
@@ -11,16 +10,16 @@ DBUG_ENTER() and DBUG_POP(); right before DBUG_RETURN in every such a function.
EEE
$re=join('|', @ARGV);
-$skip='';
while(<STDIN>) {
- print unless $skip;
+ ($thd) = /^(T@\d+)/;
+ print unless $skip{$thd};
next unless /^(?:.*: )*((?:\| )*)([<>])($re)\n/o;
if ($2 eq '>') {
- $skip=$1.$3 unless $skip;
+ $skip{$thd}=$1.$3 unless $skip{$thd};
next;
}
- next if $skip ne $1.$3;
- $skip='';
+ next if $skip{$thd} ne $1.$3;
+ delete $skip{$thd};
print;
}
diff --git a/dbug/tests-t.pl b/dbug/tests-t.pl
index de9ed6f6ab9..9f517ba3efd 100755
--- a/dbug/tests-t.pl
+++ b/dbug/tests-t.pl
@@ -8,8 +8,9 @@
use Test::More;
$exe=$0;
+$exe =~ s@[^/]+$@tests@;
-die unless $exe =~ s/(tests)-t(\.exe)?$/$1$2 /;
+die unless -x $exe;
# load tests
@tests=();
@@ -28,7 +29,7 @@ plan skip_all => "because dbug is disabled" if system $exe;
plan tests => scalar(@tests);
for (@tests) {
- $t=$exe . shift @$_;
+ $t=$exe . ' ' . shift @$_;
chomp($t);
open F, '-|', $t or die "open($t|): $!";
local $";
diff --git a/dbug/user.r b/dbug/user.r
index 5628f5a4fa1..1ccd46bd21e 100644
--- a/dbug/user.r
+++ b/dbug/user.r
@@ -823,28 +823,6 @@ number of bytes to dump.
.SP 1
EX: \fCDBUG_DBUG\ ("net",\ packet,\ len);\fR
.SP 1
-.LI DBUG_SETJMP\
-Used in place of the setjmp() function to first save the current
-debugger state and then execute the standard setjmp call.
-This allows to the debugger to restore its state when the
-DBUG_LONGJMP macro is used to invoke the standard longjmp() call.
-Currently all instances of DBUG_SETJMP must occur within the
-same function and at the same function nesting level.
-.SP 1
-EX: \fCDBUG_SETJMP\ (env);\fR
-.SP 1
-.LI DBUG_LONGJMP\
-Used in place of the longjmp() function to first restore the
-previous debugger state at the time of the last DBUG_SETJMP
-and then execute the standard longjmp() call.
-Note that currently all DBUG_LONGJMP macros restore the state
-at the time of the last DBUG_SETJMP.
-It would be possible to maintain separate DBUG_SETJMP and DBUG_LONGJMP
-pairs by having the debugger runtime support module use the first
-argument to differentiate the pairs.
-.SP 1
-EX: \fCDBUG_LONGJMP\ (env,val);\fR
-.SP 1
.LI DBUG_LOCK_FILE\
Used in multi-threaded environment to lock DBUG_FILE stream.
It can be used, for example, in functions that need to write something to a
@@ -903,6 +881,20 @@ Modifying
.I initial
value does not affect threads that are already running. Obviously,
these macros are only useful in the multi-threaded environment.
+.SP 1
+.LI DBUG_MALLOC\
+.LI DBUG_REALLOC\
+.LI DBUG_FREE\
+When these macros are used instead of system malloc(), realloc(), and free(),
+.I dbug
+built-in memory debugger performs checks for memory overwrites, underwrites,
+memory leaks, and accesses to uninitialized or freed memory. Memory leaks are
+found as memory not deallocated at shutdown. Memory overwrites and underwrites
+are detected when this memory is about to be freed (by
+.B DBUG_FREE
+macro), unless
+.B S
+flag is present in the debug control string (see below).
.LE
.SK
@@ -971,15 +963,6 @@ containing the macro causing the output.
.LI i
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
-below.
.LI L
Mark each debugger output line with the source file line number of
the macro causing the output.
@@ -1019,6 +1002,16 @@ Most useful with
.B DBUG_PUSH
macros used to temporarily alter the
debugger state.
+.LI S
+Check the memory allocated with
+.B DBUG_MALLOC
+and
+.B DBUG_REALLOC
+for overwrites/underwrites
+on each
+.B DBUG_ENTER
+and
+.B DBUG_RETURN.
.LI t[,N]
Enable function control flow tracing.
The maximum nesting depth is specified by N, and defaults to
@@ -1078,76 +1071,7 @@ all writes to a file are always followed by a flush.
.SK
.B
-PROFILING WITH DBUG
-.R
-
-.P
-With
-.I dbug
-one can do profiling in a machine independent fashion,
-without a need for profiled version of system libraries.
-For this,
-.I dbug
-can write out a file
-called
-.B dbugmon.out
-(by default). This is an ascii file containing lines of the form:
-.DS CB N
-\fC<function-name> E <time-entered>
-<function-name> X <time-exited>
-.DE
-.P
-A second program (\fBanalyze\fR) reads this file, and produces a report on
-standard output.
-
-.P
-Profiling is enabled through the
-.B g
-flag. It can take a list of
-function names for which profiling is enabled. By default, it
-profiles all functions.
-
-.P
-The profile file is opened for appending. This
-is in order that one can run a program several times, and get the
-sum total of all the times, etc.
-
-.P
-An example of the report generated follows:
-.DS CB N
-\fC
- Profile of Execution
- Execution times are in milliseconds
-
- Calls Time
- ----- ----
- Times Percentage Time Spent Percentage
-Function Called of total in Function of total Importance
-======== ====== ========== =========== ========== ==========
-factorial 5 83.33 30 100.00 8333
-main 1 16.67 0 0.00 0
-======== ====== ========== =========== ==========
-Totals 6 100.00 30 100.00
-.DE
-.P
-As you can see, it's quite self-evident. The
-.B Importance
-column is a
-metric obtained by multiplying the percentage of the calls and the percentage
-of the time. Functions with higher 'importance' benefit the most from
-being sped up.
-
-.P
-As a limitation - setjmp/longjmp, or child processes, are ignored
-for the time being. Also, profiling does not work
-in a multi-threaded environment.
-
-.P
-Profiling code is (c) Binayak Banerjee.
-
-.SK
-.B
HINTS AND MISCELLANEOUS
.R