summaryrefslogtreecommitdiff
path: root/dbug
diff options
context:
space:
mode:
Diffstat (limited to 'dbug')
-rw-r--r--dbug/CMakeLists.txt60
-rw-r--r--dbug/Makefile.am72
-rw-r--r--dbug/dbug.c945
-rw-r--r--dbug/dbug_analyze.c726
-rw-r--r--dbug/dbug_long.h16
-rw-r--r--dbug/my_main.c5
-rw-r--r--dbug/sanity.c13
-rwxr-xr-xdbug/tests-t.pl5
-rw-r--r--dbug/tests.c5
-rw-r--r--dbug/user.r122
10 files changed, 495 insertions, 1474 deletions
diff --git a/dbug/CMakeLists.txt b/dbug/CMakeLists.txt
index fabb592dccc..a408376a37d 100644
--- a/dbug/CMakeLists.txt
+++ b/dbug/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (C) 2006 MySQL AB
+# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -11,13 +11,57 @@
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/dbug)
+INCLUDE_DIRECTORIES(
+ ${CMAKE_SOURCE_DIR}/dbug
+ ${CMAKE_SOURCE_DIR}/include
+)
+SET(DBUG_SOURCES dbug.c)
+ADD_CONVENIENCE_LIBRARY(dbug ${DBUG_SOURCES})
+TARGET_LINK_LIBRARIES(dbug mysys)
-SET(DBUG_SOURCES dbug.c factorial.c sanity.c)
+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-t 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)
+ 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)
+ ADD_CUSTOM_TARGET(t ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/user.t)
+ ENDIF(NROFF)
+
+ENDIF(NOT WIN32)
-IF(NOT SOURCE_SUBLIBS)
- INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include)
- ADD_LIBRARY(dbug ${DBUG_SOURCES})
-ENDIF(NOT SOURCE_SUBLIBS)
diff --git a/dbug/Makefile.am b/dbug/Makefile.am
deleted file mode 100644
index e8acb0ca2c0..00000000000
--- a/dbug/Makefile.am
+++ /dev/null
@@ -1,72 +0,0 @@
-# Copyright (C) 2000, 2002, 2004-2006 MySQL AB
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Library General Public
-# License as published by the Free Software Foundation; version 2
-# of the License.
-#
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Library General Public License for more details.
-#
-# You should have received a copy of the GNU Library General Public
-# License along with this library; if not, write to the Free
-# Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
-# MA 02111-1307, USA
-
-INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include
-LDADD = libdbug.a $(top_builddir)/mysys/libmysys.a $(top_builddir)/strings/libmystrings.a
-pkglib_LIBRARIES = libdbug.a
-noinst_LTLIBRARIES = libdbug.la
-noinst_HEADERS = dbug_long.h
-libdbug_la_SOURCES = dbug.c sanity.c
-EXTRA_DIST = CMakeLists.txt example1.c example2.c example3.c \
- user.r monty.doc dbug_add_tags.pl \
- my_main.c main.c factorial.c dbug_analyze.c \
- CMakeLists.txt tests.c tests-t.pl
-NROFF_INC = example1.r example2.r example3.r main.r \
- factorial.r output1.r output2.r output3.r \
- output4.r output5.r
-CLEANFILES = $(NROFF_INC) user.t user.ps tests-t
-
-
-# Must be linked with libs that are not compiled yet
-noinst_PROGRAMS = factorial dbug_analyze tests
-factorial_SOURCES = my_main.c factorial.c
-tests_SOURCES = tests.c
-dbug_analyze_SOURCES = dbug_analyze.c
-
-all: user.t user.ps tests-t
-
-user.t: user.r $(NROFF_INC)
- -nroff -mm user.r > $@
-
-user.ps: user.r $(NROFF_INC)
- -groff -mm user.r > $@
-
-output1.r: factorial
- ./factorial 1 2 3 4 5 | cat > $@
-
-output2.r: factorial
- ./factorial -\#t:o 2 3 | cat >$@
-
-output3.r: factorial
- ./factorial -\#d:t:o 3 | cat >$@
-
-output4.r: factorial
- ./factorial -\#d,result:o 4 | cat >$@
-
-output5.r: factorial
- ./factorial -\#d:f,factorial:F:L:o 3 | cat >$@
-.c.r:
- @RM@ -f $@
- @SED@ -e 's!\\!\\\\!g' $< > $@
-
-# a hack to have executable in builddir, not in srcdir
-tests-t: tests-t.pl
- cp -f $(srcdir)/tests-t.pl ./tests-t
-
-libdbug_a_SOURCES=
-libdbug.a: libdbug.la
- $(CP) .libs/libdbug.a $@
diff --git a/dbug/dbug.c b/dbug/dbug.c
index 29657c9dd03..63b373921be 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
@@ -95,12 +92,12 @@
#define fnmatch(A,B,C) strcmp(A,B)
#endif
-#if defined(MSDOS) || defined(__WIN__)
+#if defined(__WIN__)
#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,17 +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 SANITY_CHECK_ON (1 << 10) /* Check safemalloc on DBUG_ENTER */
-#define FLUSH_ON_WRITE (1 << 11) /* Flush on every write */
-#define OPEN_APPEND (1 << 12) /* Open for append */
+#define 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.
@@ -144,50 +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 */
-#endif
-
-#ifdef SAFEMALLOC
-IMPORT int _sanity(const char *file,uint line); /* safemalloc sanity checker */
-#else
-#define _sanity(X,Y) (1)
+static void perror(char *s)
+{
+ if (s && *s != '\0')
+ (void) fprintf(stderr, "%s: ", s);
+ (void) fprintf(stderr, "<unknown system error>\n");
+}
#endif
/*
@@ -226,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 */
@@ -246,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] */
@@ -309,7 +270,7 @@ static int DoTrace(CODE_STATE *cs);
#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);
@@ -324,51 +285,45 @@ static void Indent(CODE_STATE *cs, int indent);
static void DbugFlush(CODE_STATE *);
static void DbugExit(const char *why);
static const char *DbugStrTok(const char *s);
+static void DbugVfprintf(FILE *stream, const char* format, va_list args);
-#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 DbugErr(CODE_STATE *, uint, const char* format, ...);
/*
* 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
+static int sf_sanity();
+static void sf_terminate();
/*
** Macros to allow dbugging with threads
*/
-#ifdef THREAD
#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;
@@ -383,7 +338,8 @@ static CODE_STATE *code_state(void)
if (!init_done)
{
init_done=TRUE;
- pthread_mutex_init(&THR_LOCK_dbug,MY_MUTEX_INIT_FAST);
+ 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;
@@ -396,38 +352,14 @@ 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;
}
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.
*/
@@ -509,20 +441,17 @@ int DbugParse(CODE_STATE *cs, const char *control)
if (control[0] == '-' && control[1] == '#')
control+=2;
+
rel= control[0] == '+' || control[0] == '-';
if ((!rel || (!stack->out_file && !stack->next)))
{
- /* If overwriting previous state, be sure to free old to avoid leak. */
- if (stack->out_file)
- FreeState(cs, stack, 0);
+ 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;
}
@@ -533,20 +462,23 @@ 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->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);
stack->processes= ListCopy(init_settings.processes);
}
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;
stack->processes= stack->next->processes;
}
@@ -556,8 +488,7 @@ int DbugParse(CODE_STATE *cs, const char *control)
while (control < end)
{
int c, sign= (*control == '+') ? 1 : (*control == '-') ? -1 : 0;
- if (sign)
- control++;
+ if (sign) control++;
c= *control++;
if (*control == ',')
control++;
@@ -614,15 +545,6 @@ int 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;
@@ -731,9 +653,9 @@ int DbugParse(CODE_STATE *cs, const char *control)
pthread_mutex_unlock(&THR_LOCK_dbug);
cs->locked= 0;
}
- return !rel || f_used;}
+ return !rel || f_used;
+}
-
#define framep_trace_flag(cs, frp) (frp ? \
frp->level & TRACE_ON : \
(ListFlags(cs->stack->functions) & INCLUDE) ? \
@@ -850,8 +772,9 @@ yuck:
* DESCRIPTION
*
* Given pointer to a debug control string in "control",
- * parses the control string, and sets
- * up a current debug settings.
+ * 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.
*
*/
@@ -861,6 +784,8 @@ void _db_set_(const char *control)
uint old_fflags;
get_code_state_or_return;
old_fflags=fflags(cs);
+ if (cs->stack == &init_settings)
+ PushState(cs);
if (DbugParse(cs, control))
FixTraceFlags(old_fflags, cs);
}
@@ -894,6 +819,7 @@ void _db_push_(const char *control)
FixTraceFlags(old_fflags, cs);
}
+
/**
Returns TRUE if session-local settings have been set.
*/
@@ -905,7 +831,6 @@ int _db_is_pushed_()
return (cs->stack != &init_settings);
}
-
/*
* FUNCTION
*
@@ -956,7 +881,7 @@ void _db_pop_()
get_code_state_or_return;
discard= cs->stack;
- if (discard->next != NULL)
+ if (discard != &init_settings)
{
old_fflags=fflags(cs);
cs->stack= discard->next;
@@ -1068,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);
@@ -1176,30 +1100,14 @@ void _db_enter_(const char *_func_, const char *_file_,
_stack_frame_->prev= cs->framep;
_stack_frame_->level= ++cs->level | framep_trace_flag(cs, cs->framep);
cs->framep= _stack_frame_;
-#ifndef THREAD
- if (DoProfile(cs))
- {
- long stackused;
- if (cs->framep->prev == NULL)
- stackused= 0;
- else
- {
- stackused= (char*)(cs->framep->prev) - (char*)(cs->framep);
- stackused= stackused > 0 ? stackused : -stackused;
- }
- (void) fprintf(cs->stack->prof_file, PROF_EFMT , Clock(), cs->func);
- (void) fprintf(cs->stack->prof_file, PROF_SFMT, (ulong) cs->framep, stackused,
- AUTOS_REVERSE ? _stack_frame_->func : cs->func);
- (void) fflush(cs->stack->prof_file);
- }
-#endif
+
switch (DoTrace(cs)) {
case ENABLE_TRACE:
cs->framep->level|= TRACE_ON;
if (!TRACING) break;
/* fall through */
case DO_TRACE:
- if ((cs->stack->flags & SANITY_CHECK_ON) && _sanity(_file_,_line_))
+ if ((cs->stack->flags & SANITY_CHECK_ON) && sf_sanity())
cs->stack->flags &= ~SANITY_CHECK_ON;
if (TRACING)
{
@@ -1240,7 +1148,6 @@ void _db_enter_(const char *_func_, const char *_file_,
*
*/
-/* helper macro */
void _db_return_(uint _line_, struct _db_stack_frame_ *_stack_frame_)
{
int save_errno=errno;
@@ -1248,34 +1155,25 @@ void _db_return_(uint _line_, struct _db_stack_frame_ *_stack_frame_)
CODE_STATE *cs;
get_code_state_or_return;
- if (cs->level != _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);
- DbugFlush(cs);
+ char buf[512];
+ my_snprintf(buf, sizeof(buf), ERR_MISSING_RETURN, cs->func);
+ DbugExit(buf);
}
- else
+
+ if (DoTrace(cs) & DO_TRACE)
{
-#ifndef THREAD
- if (DoProfile(cs))
- (void) fprintf(cs->stack->prof_file, PROF_XFMT, Clock(), cs->func);
-#endif
- if (DoTrace(cs) & DO_TRACE)
+ if ((cs->stack->flags & SANITY_CHECK_ON) && sf_sanity())
+ cs->stack->flags &= ~SANITY_CHECK_ON;
+ if (TRACING)
{
- if ((cs->stack->flags & SANITY_CHECK_ON) &&
- _sanity(_stack_frame_->file,_line_))
- cs->stack->flags &= ~SANITY_CHECK_ON;
- if (TRACING)
- {
- if (!cs->locked)
- pthread_mutex_lock(&THR_LOCK_dbug);
- DoPrefix(cs, _line_);
- Indent(cs, cs->level);
- (void) fprintf(cs->stack->out_file, "<%s\n", cs->func);
- DbugFlush(cs);
- }
+ 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);
}
}
/*
@@ -1365,8 +1263,7 @@ 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);
+ DbugVfprintf(cs->stack->out_file, format, args);
DbugFlush(cs);
errno=save_errno;
}
@@ -1376,6 +1273,18 @@ void _db_doprnt_(const char *format,...)
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
@@ -1392,14 +1301,13 @@ 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;
get_code_state_or_return;
@@ -1417,9 +1325,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)
@@ -1471,7 +1378,8 @@ static struct link *ListAddDel(struct link *head, const char *ctlp,
{
const char *start;
struct link **cur;
- int len, subdir;
+ size_t len;
+ int subdir;
ctlp--;
next:
@@ -1638,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;
}
@@ -1668,15 +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) &&
- state->out_file != stderr && state->out_file != stdout)
+
+ if (!is_shared(state, out_file))
DBUGCloseFile(cs, state->out_file);
- (void) fflush(cs->stack->out_file);
- if (state->prof_file &&
- state->prof_file != stderr && state->prof_file != stdout)
- DBUGCloseFile(cs, state->prof_file);
+ else
+ (void) fflush(state->out_file);
+
if (free_state)
free((void*) state);
}
@@ -1709,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();
}
@@ -1768,36 +1670,6 @@ static int DoTrace(CODE_STATE *cs)
return DONT_TRACE;
}
-
-/*
- * 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, 0) & (INCLUDE|MATCHED) &&
- InList(cs->stack->processes, cs->process, 0) & (INCLUDE|MATCHED));
-}
-#endif
-
FILE *_db_fp_(void)
{
CODE_STATE *cs;
@@ -1857,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++)
@@ -1889,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)
{
@@ -1924,11 +1796,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);
@@ -1992,14 +1860,14 @@ 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;
- REGISTER BOOLEAN newfile;
+ FILE *fp;
+ BOOLEAN newfile;
if (name != NULL)
{
if (end)
{
- int len= (int) (end-name);
+ size_t len=end-name;
memcpy(cs->stack->name, name, len);
cs->stack->name[len]=0;
}
@@ -2032,77 +1900,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
*
@@ -2122,7 +1925,7 @@ static FILE *OpenProfile(CODE_STATE *cs, const char *name)
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)
{
if (!cs->locked)
pthread_mutex_lock(&THR_LOCK_dbug);
@@ -2157,7 +1960,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();
}
@@ -2184,7 +1987,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");
@@ -2225,7 +2028,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)
@@ -2262,8 +2065,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))
@@ -2287,141 +2090,11 @@ static BOOLEAN Writable(const char *pathname)
}
#endif
-
/*
- * 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
- *
- * 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)
{
@@ -2481,124 +2154,340 @@ void _db_unlock_file_()
pthread_mutex_unlock(&THR_LOCK_dbug);
}
+const char* _db_get_func_(void)
+{
+ CODE_STATE *cs;
+ get_code_state_or_return NULL;
+ return cs->func;
+}
+
/*
- * Here we need the definitions of the clock routine. Add your
- * own for whatever system that you have.
- */
+ 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;
+ }
+ }
-#ifndef THREAD
-#if defined(HAVE_GETRUSAGE)
+ fprintf(stderr, "\n");
+}
-#include <sys/param.h>
-#include <sys/resource.h>
+/********************************************************************
+ memory debugger
+ based on safemalloc, memory sub-system, written by Bjorn Benson
+********************************************************************/
-/* extern int getrusage(int, struct rusage *); */
+#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 */
+};
/*
- * Returns the user time in milliseconds used by this process so
- * far.
+ 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);
+
+/*
+ * FUNCTION
+ *
+ * _db_malloc_ allocates memory
+ *
+ * SYNOPSIS
+ *
+ * void *_db_malloc_(size_t size)
+ * size_t size; Bytes to allocate
*/
-static unsigned long Clock()
+void *_db_malloc_(size_t size)
{
- struct rusage ru;
+ 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;
- (void) getrusage(RUSAGE_SELF, &ru);
- return ru.ru_utime.tv_sec*1000 + ru.ru_utime.tv_usec/1000;
+ 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;
}
-#elif defined(MSDOS) || defined(__WIN__)
+void *_db_realloc_(void *ptr, size_t size)
+{
+ char *data;
+
+ if (!ptr)
+ return _db_malloc_(size);
-static ulong Clock()
+ 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)
{
- return clock()*(1000/CLOCKS_PER_SEC);
+ if (!ptr || bad_ptr("Freeing", ptr))
+ return;
+
+ free_memory(ptr);
+ return;
}
-#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 void free_memory(void *ptr)
+{
+ struct st_irem *irem= (struct st_irem *)ptr - 1;
-static int first_clock= TRUE;
-static struct DateStamp begin;
-static struct DateStamp elapsed;
+ 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);
+ }
-static unsigned long Clock()
+ /* 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)
{
- register struct DateStamp *now;
- register unsigned long millisec= 0;
- extern VOID *AllocMem();
+ int i;
+ const char *allocated= flags & SF_ADD_NL ? "Allocated" : ", allocated";
- 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;
+ 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");
}
-#else
-static unsigned long Clock()
+
+static int bad_ptr(const char *where, void *ptr)
{
- return 0;
+ 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;
}
-#endif /* RUSAGE */
-#endif /* THREADS */
-#ifdef NO_VARARGS
+/* 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;
+}
/*
- * Fake vfprintf for systems that don't support it. If this
- * doesn't work, you are probably SOL...
+ * FUNCTION
+ *
+ * sf_terminate Report on all the memory pieces that have not been free'd
+ *
+ * SYNOPSIS
+ *
+ * void sf_terminate()
*/
-static int vfprintf(stream, format, ap)
-FILE *stream;
-char *format;
-va_list ap;
+static void sf_terminate()
{
- 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;
-}
+ struct st_irem *irem;
-#endif /* NO_VARARGS */
+ sf_sanity();
-#else
+ /* 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);
+ }
-/*
- * Dummy function, workaround for MySQL bug#14420 related
- * build failure on a platform where linking with an empty
- * archive fails.
- *
- * This block can be removed as soon as a fix for bug#14420
- * is implemented.
- */
-int i_am_a_dummy_function() {
- return 0;
+ return;
}
-
-#endif
diff --git a/dbug/dbug_analyze.c b/dbug/dbug_analyze.c
deleted file mode 100644
index 3263b2ccc59..00000000000
--- a/dbug/dbug_analyze.c
+++ /dev/null
@@ -1,726 +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)
-
-#ifdef MSDOS
-extern int getopt(int argc, char **argv, char *opts);
-#endif
-extern int optind;
-extern char *optarg;
-
-int main (int argc, char **argv)
-{
- register int c;
- int badflg = 0;
- FILE *infile;
- FILE *outfile = {stdout};
-
-#ifdef THREAD
-#if defined(HAVE_PTHREAD_INIT)
- pthread_init(); /* Must be called before DBUG_ENTER */
-#endif
- my_thread_global_init();
-#endif /* THREAD */
- {
- 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);
-}
-}
-
-#ifdef MSDOS
-
-/*
- * From std-unix@ut-sally.UUCP (Moderator, John Quarterman) Sun Nov 3 14:34:15 1985
- * Relay-Version: version B 2.10.3 4.3bsd-beta 6/6/85; site gatech.CSNET
- * Posting-Version: version B 2.10.2 9/18/84; site ut-sally.UUCP
- * Path: gatech!akgua!mhuxv!mhuxt!mhuxr!ulysses!allegra!mit-eddie!genrad!panda!talcott!harvard!seismo!ut-sally!std-unix
- * From: std-unix@ut-sally.UUCP (Moderator, John Quarterman)
- * Newsgroups: mod.std.unix
- * Subject: public domain AT&T getopt source
- * Message-ID: <3352@ut-sally.UUCP>
- * Date: 3 Nov 85 19:34:15 GMT
- * Date-Received: 4 Nov 85 12:25:09 GMT
- * Organization: IEEE/P1003 Portable Operating System Environment Committee
- * Lines: 91
- * Approved: jsq@ut-sally.UUCP
- *
- * Here's something you've all been waiting for: the AT&T public domain
- * source for getopt(3). It is the code which was given out at the 1985
- * UNIFORUM conference in Dallas. I obtained it by electronic mail
- * directly from AT&T. The people there assure me that it is indeed
- * in the public domain.
- *
- * There is no manual page. That is because the one they gave out at
- * UNIFORUM was slightly different from the current System V Release 2
- * manual page. The difference apparently involved a note about the
- * famous rules 5 and 6, recommending using white space between an option
- * and its first argument, and not grouping options that have arguments.
- * Getopt itself is currently lenient about both of these things White
- * space is allowed, but not mandatory, and the last option in a group can
- * have an argument. That particular version of the man page evidently
- * has no official existence, and my source at AT&T did not send a copy.
- * The current SVR2 man page reflects the actual behavor of this getopt.
- * However, I am not about to post a copy of anything licensed by AT&T.
- *
- * I will submit this source to Berkeley as a bug fix.
- *
- * I, personally, make no claims or guarantees of any kind about the
- * following source. I did compile it to get some confidence that
- * it arrived whole, but beyond that you're on your own.
- *
- */
-
-/*LINTLIBRARY*/
-
-int opterr = 1;
-int optind = 1;
-int optopt;
-char *optarg;
-
-static void _ERR(s,c,argv)
-char *s;
-int c;
-char *argv[];
-{
- char errbuf[3];
-
- if (opterr) {
- errbuf[0] = c;
- errbuf[1] = '\n';
- (void) fprintf(stderr, "%s", argv[0]);
- (void) fprintf(stderr, "%s", s);
- (void) fprintf(stderr, "%s", errbuf);
- }
-}
-
-int getopt(argc, argv, opts)
-int argc;
-char **argv, *opts;
-{
- static int sp = 1;
- register int c;
- register char *cp;
-
- if(sp == 1)
- if(optind >= argc ||
- argv[optind][0] != '-' || argv[optind][1] == '\0')
- return(EOF);
- else if(strcmp(argv[optind], "--") == 0) {
- optind++;
- return(EOF);
- }
- optopt = c = argv[optind][sp];
- if(c == ':' || (cp=strchr(opts, c)) == NULL) {
- _ERR(": illegal option -- ", c, argv);
- if(argv[optind][++sp] == '\0') {
- optind++;
- sp = 1;
- }
- return('?');
- }
- if(*++cp == ':') {
- if(argv[optind][sp+1] != '\0')
- optarg = &argv[optind++][sp+1];
- else if(++optind >= argc) {
- _ERR(": option requires an argument -- ", c, argv);
- sp = 1;
- return('?');
- } else
- optarg = argv[optind++];
- sp = 1;
- } else {
- if(argv[optind][++sp] == '\0') {
- sp = 1;
- optind++;
- }
- optarg = NULL;
- }
- return(c);
-}
-
-#endif /* !unix && !xenix */
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/my_main.c b/dbug/my_main.c
index 31c15aa67aa..48d092ca10a 100644
--- a/dbug/my_main.c
+++ b/dbug/my_main.c
@@ -16,12 +16,11 @@ char *argv[];
{
register int result, ix;
extern int factorial(int);
-#if defined(HAVE_PTHREAD_INIT) && defined(THREAD)
+#if defined(HAVE_PTHREAD_INIT)
pthread_init(); /* Must be called before DBUG_ENTER */
#endif
-#ifdef THREAD
my_thread_global_init();
-#endif
+
{
DBUG_ENTER ("main");
DBUG_PROCESS (argv[0]);
diff --git a/dbug/sanity.c b/dbug/sanity.c
deleted file mode 100644
index df43fc14ba9..00000000000
--- a/dbug/sanity.c
+++ /dev/null
@@ -1,13 +0,0 @@
-/* Declarate _sanity() if not declared in main program */
-
-#include <my_global.h>
-
-extern int _sanity(const char *file,uint line);
-
-#if defined(SAFEMALLOC) && !defined(MASTER) /* Avoid errors in MySQL */
-int _sanity(const char * file __attribute__((unused)),
- uint line __attribute__((unused)))
-{
- return 0;
-}
-#endif
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/tests.c b/dbug/tests.c
index d76266d34a3..837a477aef3 100644
--- a/dbug/tests.c
+++ b/dbug/tests.c
@@ -44,12 +44,11 @@ int main (int argc, char *argv[])
if (argc == 1)
return 0;
-#if defined(HAVE_PTHREAD_INIT) && defined(THREAD)
+#if defined(HAVE_PTHREAD_INIT)
pthread_init(); /* Must be called before DBUG_ENTER */
#endif
-#ifdef THREAD
my_thread_global_init();
-#endif
+
dup2(1, 2);
for (i = 1; i < argc; i++)
{
diff --git a/dbug/user.r b/dbug/user.r
index 847ad80b30f..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.
@@ -1020,9 +1003,11 @@ Most useful with
macros used to temporarily alter the
debugger state.
.LI S
-When compiled with
-.I safemalloc
-this flag forces "sanity" memory checks (for overwrites/underwrites)
+Check the memory allocated with
+.B DBUG_MALLOC
+and
+.B DBUG_REALLOC
+for overwrites/underwrites
on each
.B DBUG_ENTER
and
@@ -1086,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