dbug.c 60.7 KB
Newer Older
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1
/******************************************************************************
serg@serg.mylan's avatar
serg@serg.mylan committed
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 *                                                                            *
 *                                 N O T I C E                                *
 *                                                                            *
 *                    Copyright Abandoned, 1987, Fred Fish                    *
 *                                                                            *
 *                                                                            *
 *      This previously copyrighted work has been placed into the  public     *
 *      domain  by  the  author  and  may be freely used for any purpose,     *
 *      private or commercial.                                                *
 *                                                                            *
 *      Because of the number of inquiries I was receiving about the  use     *
 *      of this product in commercially developed works I have decided to     *
 *      simply make it public domain to further its unrestricted use.   I     *
 *      specifically  would  be  most happy to see this material become a     *
 *      part of the standard Unix distributions by AT&T and the  Berkeley     *
 *      Computer  Science  Research Group, and a standard part of the GNU     *
 *      system from the Free Software Foundation.                             *
 *                                                                            *
 *      I would appreciate it, as a courtesy, if this notice is  left  in     *
 *      all copies and derivative works.  Thank you.                          *
 *                                                                            *
 *      The author makes no warranty of any kind  with  respect  to  this     *
24
 *      product  and  explicitly disclaims any implied warranties of mer-     *
serg@serg.mylan's avatar
serg@serg.mylan committed
25 26
 *      chantability or fitness for any particular purpose.                   *
 *                                                                            *
bk@work.mysql.com's avatar
bk@work.mysql.com committed
27 28 29 30 31 32
 ******************************************************************************
 */

/*
 *  FILE
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
33
 *      dbug.c   runtime support routines for dbug package
bk@work.mysql.com's avatar
bk@work.mysql.com committed
34 35 36
 *
 *  SCCS
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
37
 *      @(#)dbug.c      1.25    7/25/89
bk@work.mysql.com's avatar
bk@work.mysql.com committed
38 39 40
 *
 *  DESCRIPTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
41 42 43 44
 *      These are the runtime support routines for the dbug package.
 *      The dbug package has two main components; the user include
 *      file containing various macro definitions, and the runtime
 *      support routines which are called from the macro expansions.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
45
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
46 47 48
 *      Externally visible functions in the runtime support module
 *      use the naming convention pattern "_db_xx...xx_", thus
 *      they are unlikely to collide with user defined function names.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
49 50 51
 *
 *  AUTHOR(S)
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
52 53 54
 *      Fred Fish               (base code)
 *      Enhanced Software Technologies, Tempe, AZ
 *      asuvax!mcdphx!estinc!fnf
bk@work.mysql.com's avatar
bk@work.mysql.com committed
55
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
56 57
 *      Binayak Banerjee        (profiling enhancements)
 *      seismo!bpa!sjuvax!bbanerje
bk@work.mysql.com's avatar
bk@work.mysql.com committed
58
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
59 60
 *      Michael Widenius:
 *      DBUG_DUMP       - To dump a block of memory.
61 62
 *      PUSH_FLAG "O"   - To be used insted of "o" if we
 *                        want flushing after each write
serg@serg.mylan's avatar
serg@serg.mylan committed
63 64 65 66 67 68 69
 *      PUSH_FLAG "A"   - as 'O', but we will append to the out file instead
 *                        of creating a new one.
 *      Check of malloc on entry/exit (option "S")
 *
 *      DBUG_EXECUTE_IF
 *      incremental mode (-#+t:-d,info ...)
 *      DBUG_SET, _db_explain_
serg@serg.mylan's avatar
serg@serg.mylan committed
70
 *      thread-local settings
serg@serg.mylan's avatar
serg@serg.mylan committed
71
 *
bk@work.mysql.com's avatar
bk@work.mysql.com committed
72 73 74 75 76
 */

#ifdef DBUG_OFF
#undef DBUG_OFF
#endif
77
#include <my_global.h>
bk@work.mysql.com's avatar
bk@work.mysql.com committed
78 79 80 81 82 83 84
#include <m_string.h>
#include <errno.h>
#if defined(MSDOS) || defined(__WIN__)
#include <process.h>
#endif

/*
serg@serg.mylan's avatar
serg@serg.mylan committed
85
 *            Manifest constants which may be "tuned" if desired.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
86 87
 */

serg@serg.mylan's avatar
serg@serg.mylan committed
88 89 90
#define PRINTBUF              1024    /* Print buffer size */
#define INDENT                2       /* Indentation per trace level */
#define MAXDEPTH              200     /* Maximum trace depth default */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
91 92

/*
serg@serg.mylan's avatar
serg@serg.mylan committed
93 94 95
 *      The following flags are used to determine which
 *      capabilities the user has enabled with the settings
 *      push macro.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
96 97
 */

serg@serg.mylan's avatar
serg@serg.mylan committed
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
#define TRACE_ON        000001  /* Trace enabled */
#define DEBUG_ON        000002  /* Debug enabled */
#define FILE_ON         000004  /* File name print enabled */
#define LINE_ON         000010  /* Line number print enabled */
#define DEPTH_ON        000020  /* Function nest level print enabled */
#define PROCESS_ON      000040  /* Process name print enabled */
#define NUMBER_ON       000100  /* Number each line of output */
#define PROFILE_ON      000200  /* Print out profiling code */
#define PID_ON          000400  /* Identify each line with process id */
#define TIMESTAMP_ON    001000  /* timestamp every line of output */
#define SANITY_CHECK_ON 002000  /* Check safemalloc on DBUG_ENTER */
#define FLUSH_ON_WRITE  004000  /* Flush on every write */
#define OPEN_APPEND     010000  /* Open for append      */

#define TRACING (cs->stack->flags & TRACE_ON)
#define DEBUGGING (cs->stack->flags & DEBUG_ON)
#define PROFILING (cs->stack->flags & PROFILE_ON)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
115 116

/*
serg@serg.mylan's avatar
serg@serg.mylan committed
117
 *      Typedefs to make things more obvious.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
118 119 120 121 122 123 124 125 126
 */

#ifndef __WIN__
typedef int BOOLEAN;
#else
#define BOOLEAN BOOL
#endif

/*
serg@serg.mylan's avatar
serg@serg.mylan committed
127
 *      Make it easy to change storage classes if necessary.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
128 129
 */

serg@serg.mylan's avatar
serg@serg.mylan committed
130 131 132 133
#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 */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
134 135 136 137 138 139 140 141 142 143 144 145 146 147

/*
 * 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.
 * 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.
 *
 */

serg@serg.mylan's avatar
serg@serg.mylan committed
148 149 150 151
#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"
bk@work.mysql.com's avatar
bk@work.mysql.com committed
152

serg@serg.mylan's avatar
serg@serg.mylan committed
153
#ifdef M_I386           /* predefined by xenix 386 compiler */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
154 155 156 157
#define AUTOS_REVERSE 1
#endif

/*
serg@serg.mylan's avatar
serg@serg.mylan committed
158
 *      Externally supplied functions.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
159 160 161
 */

#ifndef HAVE_PERROR
serg@serg.mylan's avatar
serg@serg.mylan committed
162
static void perror();          /* Fake system/library error print routine */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
163 164
#endif

serg@serg.mylan's avatar
serg@serg.mylan committed
165
IMPORT int _sanity(const char *file,uint line); /* safemalloc sanity checker */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
166 167

/*
serg@serg.mylan's avatar
serg@serg.mylan committed
168 169 170
 *      The user may specify a list of functions to trace or
 *      debug.  These lists are kept in a linear linked list,
 *      a very simple implementation.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
171 172 173 174
 */

struct link {
    struct link *next_link;   /* Pointer to the next link */
serg@serg.mylan's avatar
serg@serg.mylan committed
175
    char   str[1];        /* Pointer to link's contents */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
176 177 178
};

/*
serg@serg.mylan's avatar
serg@serg.mylan committed
179 180 181 182 183 184 185
 *      Debugging settings can be pushed or popped off of a
 *      stack which is implemented as a linked list.  Note
 *      that the head of the list is the current settings and the
 *      stack is pushed by adding a new settings to the head of the
 *      list or popped by removing the first link.
 *
 *      Note: if out_file is NULL, the other fields are not initialized at all!
bk@work.mysql.com's avatar
bk@work.mysql.com committed
186 187
 */

serg@serg.mylan's avatar
serg@serg.mylan committed
188 189 190 191 192 193 194 195 196 197 198 199 200
struct settings {
  int flags;                    /* Current settings flags */
  int maxdepth;                 /* Current maximum trace depth */
  uint delay;                   /* Delay after each output line */
  int sub_level;                /* Sub this from code_state->level */
  FILE *out_file;               /* Current output stream */
  FILE *prof_file;              /* Current profiling stream */
  char name[FN_REFLEN];         /* Name of output file */
  struct link *functions;       /* List of functions */
  struct link *p_functions;     /* List of profiled functions */
  struct link *keywords;        /* List of debug keywords */
  struct link *processes;       /* List of process names */
  struct settings *next;        /* Next settings in the list */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
201 202
};

serg@serg.mylan's avatar
serg@serg.mylan committed
203
#define is_shared(S, V) ((S)->next && (S)->next->V == (S)->V)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
204 205

/*
serg@serg.mylan's avatar
serg@serg.mylan committed
206
 *      Local variables not seen by user.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
207 208 209
 */


serg@serg.mylan's avatar
serg@serg.mylan committed
210 211
static BOOLEAN init_done= FALSE; /* Set to TRUE when initialization done */
static struct settings init_settings;
212
static const char *db_process= 0;/* Pointer to process name; argv[0] */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
213

serg@serg.mylan's avatar
serg@serg.mylan committed
214 215 216 217 218 219 220 221 222 223 224
typedef struct _db_code_state_ {
  const char *process;          /* Pointer to process name; usually argv[0] */
  const char *func;             /* Name of current user function */
  const char *file;             /* Name of current user file */
  char **framep;                /* Pointer to current frame */
  struct settings *stack;       /* debugging settings */
  const char *jmpfunc;          /* Remember current function for setjmp */
  const char *jmpfile;          /* Remember current file for setjmp */
  int lineno;                   /* Current debugger output line number */
  int level;                    /* Current function nesting level */
  int jmplevel;                 /* Remember nesting level at setjmp() */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
225 226

/*
serg@serg.mylan's avatar
serg@serg.mylan committed
227 228 229 230
 *      The following variables are used to hold the state information
 *      between the call to _db_pargs_() and _db_doprnt_(), during
 *      expansion of the DBUG_PRINT macro.  This is the only macro
 *      that currently uses these variables.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
231
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
232 233
 *      These variables are currently used only by _db_pargs_() and
 *      _db_doprnt_().
bk@work.mysql.com's avatar
bk@work.mysql.com committed
234 235
 */

serg@serg.mylan's avatar
serg@serg.mylan committed
236 237 238
  uint u_line;                  /* User source code line number */
  int  locked;                  /* If locked with _db_lock_file_ */
  const char *u_keyword;        /* Keyword for current macro */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
239 240
} CODE_STATE;

serg@serg.mylan's avatar
serg@serg.mylan committed
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
/*
  The test below is so we could call functions with DBUG_ENTER before
  my_thread_init().
*/
#define get_code_state_or_return if (!cs && !((cs=code_state()))) return

        /* Handling lists */
static struct link *ListAdd(struct link *, const char *, const char *);
static struct link *ListDel(struct link *, const char *, const char *);
static struct link *ListCopy(struct link *);
static void FreeList(struct link *linkp);

        /* OpenClose debug output stream */
static void DBUGOpenFile(CODE_STATE *,const char *, const char *, int);
static void DBUGCloseFile(CODE_STATE *cs, FILE *fp);
        /* Push current debug settings */
static void PushState(CODE_STATE *cs);
258
	/* Free memory associated with debug state. */
knielsen@mysql.com's avatar
knielsen@mysql.com committed
259
static void FreeState (CODE_STATE *cs, struct settings *state);
serg@serg.mylan's avatar
serg@serg.mylan committed
260 261 262 263
        /* Test for tracing enabled */
static BOOLEAN DoTrace(CODE_STATE *cs);

        /* Test to see if file is writable */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
264 265
#if !(!defined(HAVE_ACCESS) || defined(MSDOS))
static BOOLEAN Writable(char *pathname);
serg@serg.mylan's avatar
serg@serg.mylan committed
266 267 268
        /* Change file owner and group */
static void ChangeOwner(CODE_STATE *cs, char *pathname);
        /* Allocate memory for runtime support */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
269
#endif
serg@serg.mylan's avatar
serg@serg.mylan committed
270 271 272

static void DoPrefix(CODE_STATE *cs, uint line);

273
static char *DbugMalloc(size_t size);
serg@serg.mylan's avatar
serg@serg.mylan committed
274 275
static const char *BaseName(const char *pathname);
static void Indent(CODE_STATE *cs, int indent);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
276 277 278
static BOOLEAN InList(struct link *linkp,const char *cp);
static void dbug_flush(CODE_STATE *);
static void DbugExit(const char *why);
serg@serg.mylan's avatar
serg@serg.mylan committed
279 280 281 282 283 284 285 286 287 288
static const char *DbugStrTok(const char *s);

#ifndef THREAD
        /* Open profile output stream */
static FILE *OpenProfile(CODE_STATE *cs, const char *name);
        /* Profile if asked for it */
static BOOLEAN DoProfile(CODE_STATE *);
        /* Return current user time (ms) */
static unsigned long Clock(void);
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
289 290

/*
serg@serg.mylan's avatar
serg@serg.mylan committed
291
 *      Miscellaneous printf format strings.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
292 293 294 295 296 297 298 299 300
 */

#define ERR_MISSING_RETURN "%s: 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\": "

/*
serg@serg.mylan's avatar
serg@serg.mylan committed
301
 *      Macros and defines for testing file accessibility under UNIX and MSDOS.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
302 303
 */

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
304
#undef EXISTS
bk@work.mysql.com's avatar
bk@work.mysql.com committed
305
#if !defined(HAVE_ACCESS) || defined(MSDOS)
serg@serg.mylan's avatar
serg@serg.mylan committed
306
#define EXISTS(pathname) (FALSE)        /* Assume no existance */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
307 308
#define Writable(name) (TRUE)
#else
serg@serg.mylan's avatar
serg@serg.mylan committed
309 310
#define EXISTS(pathname)         (access(pathname, F_OK) == 0)
#define WRITABLE(pathname)       (access(pathname, W_OK) == 0)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
311 312
#endif
#ifndef MSDOS
serg@serg.mylan's avatar
serg@serg.mylan committed
313
#define ChangeOwner(cs,name)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
314 315 316 317 318 319 320 321 322 323 324 325
#endif

/*
** Macros to allow dbugging with threads
*/

#ifdef THREAD
#include <my_pthread.h>
pthread_mutex_t THR_LOCK_dbug;

static CODE_STATE *code_state(void)
{
serg@serg.mylan's avatar
serg@serg.mylan committed
326 327 328 329 330 331 332 333 334 335 336 337 338
  CODE_STATE *cs=0;
  struct st_my_thread_var *tmp;

  if (!init_done)
  {
    pthread_mutex_init(&THR_LOCK_dbug,MY_MUTEX_INIT_FAST);
    bzero(&init_settings, sizeof(init_settings));
    init_settings.out_file=stderr;
    init_settings.flags=OPEN_APPEND;
    init_done=TRUE;
  }

  if ((tmp=my_thread_var))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
339
  {
serg@serg.mylan's avatar
serg@serg.mylan committed
340
    if (!(cs=(CODE_STATE *) tmp->dbug))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
341
    {
serg@serg.mylan's avatar
serg@serg.mylan committed
342 343 344 345 346 347 348
      cs=(CODE_STATE*) DbugMalloc(sizeof(*cs));
      bzero((char*) cs,sizeof(*cs));
      cs->process= db_process ? db_process : "dbug";
      cs->func="?func";
      cs->file="?file";
      cs->stack=&init_settings;
      tmp->dbug=(gptr) cs;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
349 350
    }
  }
serg@serg.mylan's avatar
serg@serg.mylan committed
351
  return cs;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
352 353 354 355
}

#else /* !THREAD */

monty@mysql.com's avatar
monty@mysql.com committed
356 357
static CODE_STATE static_code_state=
{
serg@serg.mylan's avatar
serg@serg.mylan committed
358 359
  "dbug", "?func", "?file", NULL, &init_settings,
  NullS, NullS, 0,0,0,0,0,NullS
monty@mysql.com's avatar
monty@mysql.com committed
360
};
serg@serg.mylan's avatar
serg@serg.mylan committed
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375

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) {}
bk@work.mysql.com's avatar
bk@work.mysql.com committed
376 377
#endif

serg@serg.mylan's avatar
serg@serg.mylan committed
378 379 380 381 382 383 384 385 386 387
/*
 *      Translate some calls among different systems.
 */

#ifdef HAVE_SLEEP
/* sleep() wants seconds */
#define Delay(A) sleep(((uint) A)/10)
#else
#define Delay(A) (0)
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
388 389 390 391

/*
 *  FUNCTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
392
 *      _db_process_       give the name to the current process/thread
bk@work.mysql.com's avatar
bk@work.mysql.com committed
393 394 395
 *
 *  SYNOPSIS
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
396 397
 *      VOID _db_push_(name)
 *      char *name;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
398
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414
 */

void _db_process_(const char *name)
{
  CODE_STATE *cs=0;

  if (!db_process)
    db_process= name;
  
  get_code_state_or_return;
  cs->process= name;
}


/*
 *  FUNCTION
bk@work.mysql.com's avatar
bk@work.mysql.com committed
415
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
416
 *      _db_push_       push current debugger settings and set up new one
bk@work.mysql.com's avatar
bk@work.mysql.com committed
417
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
418
 *  SYNOPSIS
bk@work.mysql.com's avatar
bk@work.mysql.com committed
419
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
420 421
 *      VOID _db_push_(control)
 *      char *control;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
422
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
423
 *  DESCRIPTION
bk@work.mysql.com's avatar
bk@work.mysql.com committed
424
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
425 426 427
 *      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 _db_set_()
bk@work.mysql.com's avatar
bk@work.mysql.com committed
428
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
429 430 431 432 433 434 435 436 437 438 439 440 441
 */

void _db_push_(const char *control)
{
  CODE_STATE *cs=0;
  get_code_state_or_return;
  PushState(cs);
  _db_set_(cs, control);

}

/*
 *  FUNCTION
bk@work.mysql.com's avatar
bk@work.mysql.com committed
442
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
443
 *      _db_set_init_       set initial debugger settings
bk@work.mysql.com's avatar
bk@work.mysql.com committed
444
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
445
 *  SYNOPSIS
bk@work.mysql.com's avatar
bk@work.mysql.com committed
446
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
447 448
 *      VOID _db_set_init_(control)
 *      char *control;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
449
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
450 451
 *  DESCRIPTION
 *      see _db_set_
bk@work.mysql.com's avatar
bk@work.mysql.com committed
452
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
453 454 455 456 457 458 459 460 461 462 463 464
 */

void _db_set_init_(const char *control)
{
  CODE_STATE cs;
  bzero((char*) &cs,sizeof(cs));
  cs.stack=&init_settings;
  _db_set_(&cs, control);
}

/*
 *  FUNCTION
bk@work.mysql.com's avatar
bk@work.mysql.com committed
465
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
466
 *      _db_set_       set current debugger settings
bk@work.mysql.com's avatar
bk@work.mysql.com committed
467
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
468
 *  SYNOPSIS
bk@work.mysql.com's avatar
bk@work.mysql.com committed
469
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
470 471
 *      VOID _db_set_(control)
 *      char *control;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
472
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
473
 *  DESCRIPTION
bk@work.mysql.com's avatar
bk@work.mysql.com committed
474
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
475 476 477
 *      Given pointer to a debug control string in "control",
 *      parses the control string, and sets
 *      up a current debug settings.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
478
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
479 480
 *      The debug control string is a sequence of colon separated fields
 *      as follows:
bk@work.mysql.com's avatar
bk@work.mysql.com committed
481
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
482
 *              [+]<field_1>:<field_2>:...:<field_N>
bk@work.mysql.com's avatar
bk@work.mysql.com committed
483
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
484 485
 *      Each field consists of a mandatory flag character followed by
 *      an optional "," and comma separated list of modifiers:
bk@work.mysql.com's avatar
bk@work.mysql.com committed
486
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
487
 *              [sign]flag[,modifier,modifier,...,modifier]
bk@work.mysql.com's avatar
bk@work.mysql.com committed
488
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
489
 *      See the manual for the list of supported signs, flags, and modifiers
bk@work.mysql.com's avatar
bk@work.mysql.com committed
490
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
491
 *      For convenience, any leading "-#" is stripped off.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
492 493 494
 *
 */

serg@serg.mylan's avatar
serg@serg.mylan committed
495
void _db_set_(CODE_STATE *cs, const char *control)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
496
{
serg@serg.mylan's avatar
serg@serg.mylan committed
497 498 499 500
  const char *end;
  int rel=0;

  get_code_state_or_return;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
501

serg@serg.mylan's avatar
serg@serg.mylan committed
502 503
  if (control[0] == '-' && control[1] == '#')
    control+=2;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
504

serg@serg.mylan's avatar
serg@serg.mylan committed
505 506
  rel= control[0] == '+' || control[0] == '-';
  if (!rel || (!cs->stack->out_file && !cs->stack->next))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
507
  {
serg@serg.mylan's avatar
serg@serg.mylan committed
508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542
    cs->stack->flags= 0;
    cs->stack->delay= 0;
    cs->stack->maxdepth= 0;
    cs->stack->sub_level= 0;
    cs->stack->out_file= stderr;
    cs->stack->prof_file= NULL;
    cs->stack->functions= NULL;
    cs->stack->p_functions= NULL;
    cs->stack->keywords= NULL;
    cs->stack->processes= NULL;
  }
  else if (!cs->stack->out_file)
  {
    cs->stack->flags= cs->stack->next->flags;
    cs->stack->delay= cs->stack->next->delay;
    cs->stack->maxdepth= cs->stack->next->maxdepth;
    cs->stack->sub_level= cs->stack->next->sub_level;
    strcpy(cs->stack->name, cs->stack->next->name);
    cs->stack->out_file= cs->stack->next->out_file;
    cs->stack->prof_file= cs->stack->next->prof_file;
    if (cs->stack->next == &init_settings)
    {
      /* never share with the global parent - it can change under your feet */
      cs->stack->functions= ListCopy(init_settings.functions);
      cs->stack->p_functions= ListCopy(init_settings.p_functions);
      cs->stack->keywords= ListCopy(init_settings.keywords);
      cs->stack->processes= ListCopy(init_settings.processes);
    }
    else
    {
      cs->stack->functions= cs->stack->next->functions;
      cs->stack->p_functions= cs->stack->next->p_functions;
      cs->stack->keywords= cs->stack->next->keywords;
      cs->stack->processes= cs->stack->next->processes;
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
543 544
  }

serg@serg.mylan's avatar
serg@serg.mylan committed
545 546 547 548 549 550 551 552
  end= DbugStrTok(control);
  while (1)
  {
    int c, sign= (*control == '+') ? 1 : (*control == '-') ? -1 : 0;
    if (sign) control++;
    if (!rel) sign=0;
    c= *control++;
    if (*control == ',') control++;
serg@serg.mylan's avatar
serg@serg.mylan committed
553
    /* XXX when adding new cases here, don't forget _db_explain_ ! */
serg@serg.mylan's avatar
serg@serg.mylan committed
554
    switch (c) {
bk@work.mysql.com's avatar
bk@work.mysql.com committed
555
    case 'd':
serg@serg.mylan's avatar
serg@serg.mylan committed
556 557 558 559 560 561 562
      if (sign < 0 && control == end)
      {
        if (!is_shared(cs->stack, keywords))
          FreeList(cs->stack->keywords);
        cs->stack->keywords=NULL;
        cs->stack->flags &= ~DEBUG_ON;
        break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
563
      }
serg@serg.mylan's avatar
serg@serg.mylan committed
564 565 566 567 568 569
      if (rel && is_shared(cs->stack, keywords))
        cs->stack->keywords= ListCopy(cs->stack->keywords);
      if (sign < 0)
      {
        if (DEBUGGING)
          cs->stack->keywords= ListDel(cs->stack->keywords, control, end);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
570 571
      break;
      }
serg@serg.mylan's avatar
serg@serg.mylan committed
572 573 574 575 576
      cs->stack->keywords= ListAdd(cs->stack->keywords, control, end);
      cs->stack->flags |= DEBUG_ON;
      break;
    case 'D':
      cs->stack->delay= atoi(control);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
577 578
      break;
    case 'f':
serg@serg.mylan's avatar
serg@serg.mylan committed
579 580 581 582 583 584
      if (sign < 0 && control == end)
      {
        if (!is_shared(cs->stack,functions))
          FreeList(cs->stack->functions);
        cs->stack->functions=NULL;
        break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
585
      }
serg@serg.mylan's avatar
serg@serg.mylan committed
586 587 588 589 590 591
      if (rel && is_shared(cs->stack,functions))
        cs->stack->functions= ListCopy(cs->stack->functions);
      if (sign < 0)
        cs->stack->functions= ListDel(cs->stack->functions, control, end);
      else
        cs->stack->functions= ListAdd(cs->stack->functions, control, end);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
592 593
      break;
    case 'F':
serg@serg.mylan's avatar
serg@serg.mylan committed
594 595 596 597
      if (sign < 0)
        cs->stack->flags &= ~FILE_ON;
      else
        cs->stack->flags |= FILE_ON;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
598 599
      break;
    case 'i':
serg@serg.mylan's avatar
serg@serg.mylan committed
600 601 602 603
      if (sign < 0)
        cs->stack->flags &= ~PID_ON;
      else
        cs->stack->flags |= PID_ON;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
604 605 606
      break;
#ifndef THREAD
    case 'g':
serg@serg.mylan's avatar
serg@serg.mylan committed
607
      if (OpenProfile(cs, PROF_FILE))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
608
      {
serg@serg.mylan's avatar
serg@serg.mylan committed
609 610
        cs->stack->flags |= PROFILE_ON;
        cs->stack->p_functions= ListAdd(cs->stack->p_functions, control, end);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
611 612 613 614
      }
      break;
#endif
    case 'L':
serg@serg.mylan's avatar
serg@serg.mylan committed
615 616 617 618
      if (sign < 0)
        cs->stack->flags &= ~LINE_ON;
      else
        cs->stack->flags |= LINE_ON;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
619 620
      break;
    case 'n':
serg@serg.mylan's avatar
serg@serg.mylan committed
621 622 623 624
      if (sign < 0)
        cs->stack->flags &= ~DEPTH_ON;
      else
        cs->stack->flags |= DEPTH_ON;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
625 626
      break;
    case 'N':
serg@serg.mylan's avatar
serg@serg.mylan committed
627 628 629 630
      if (sign < 0)
        cs->stack->flags &= ~NUMBER_ON;
      else
        cs->stack->flags |= NUMBER_ON;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
631 632 633
      break;
    case 'A':
    case 'O':
serg@serg.mylan's avatar
serg@serg.mylan committed
634 635
      cs->stack->flags |= FLUSH_ON_WRITE;
      /* fall through */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
636 637
    case 'a':
    case 'o':
serg@serg.mylan's avatar
serg@serg.mylan committed
638 639 640 641 642 643 644
      if (sign < 0)
      {
        if (!is_shared(cs->stack, out_file))
          DBUGCloseFile(cs, cs->stack->out_file);
        cs->stack->flags &= ~FLUSH_ON_WRITE;
        cs->stack->out_file= stderr;
        break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
645
      }
serg@serg.mylan's avatar
serg@serg.mylan committed
646 647 648 649 650 651 652 653
      if (c == 'a' || c == 'A')
        cs->stack->flags |= OPEN_APPEND;
      else
        cs->stack->flags &= ~OPEN_APPEND;
      if (control != end)
        DBUGOpenFile(cs, control, end, cs->stack->flags & OPEN_APPEND);
      else
        DBUGOpenFile(cs, "-",0,0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
654 655
      break;
    case 'p':
serg@serg.mylan's avatar
serg@serg.mylan committed
656 657 658 659 660 661
      if (sign < 0 && control == end)
      {
        if (!is_shared(cs->stack,processes))
          FreeList(cs->stack->processes);
        cs->stack->processes=NULL;
        break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
662
      }
serg@serg.mylan's avatar
serg@serg.mylan committed
663 664 665 666 667 668
      if (rel && is_shared(cs->stack, processes))
        cs->stack->processes= ListCopy(cs->stack->processes);
      if (sign < 0)
        cs->stack->processes= ListDel(cs->stack->processes, control, end);
      else
        cs->stack->processes= ListAdd(cs->stack->processes, control, end);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
669 670
      break;
    case 'P':
serg@serg.mylan's avatar
serg@serg.mylan committed
671 672 673 674
      if (sign < 0)
        cs->stack->flags &= ~PROCESS_ON;
      else
        cs->stack->flags |= PROCESS_ON;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
675 676
      break;
    case 'r':
serg@serg.mylan's avatar
serg@serg.mylan committed
677
      cs->stack->sub_level= cs->level;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
678 679
      break;
    case 't':
serg@serg.mylan's avatar
serg@serg.mylan committed
680 681 682 683 684 685 686 687 688 689 690 691 692
      if (sign < 0)
      {
        if (control != end)
          cs->stack->maxdepth-= atoi(control);
        else
          cs->stack->maxdepth= 0;
      }
      else
      {
        if (control != end)
          cs->stack->maxdepth+= atoi(control);
        else
          cs->stack->maxdepth= MAXDEPTH;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
693
      }
serg@serg.mylan's avatar
serg@serg.mylan committed
694 695 696 697 698 699 700 701 702 703
      if (cs->stack->maxdepth > 0)
        cs->stack->flags |= TRACE_ON;
      else
        cs->stack->flags &= ~TRACE_ON;
      break;
    case 'T':
      if (sign < 0)
        cs->stack->flags &= ~TIMESTAMP_ON;
      else
        cs->stack->flags |= TIMESTAMP_ON;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
704 705
      break;
    case 'S':
serg@serg.mylan's avatar
serg@serg.mylan committed
706 707 708 709
      if (sign < 0)
        cs->stack->flags &= ~SANITY_CHECK_ON;
      else
        cs->stack->flags |= SANITY_CHECK_ON;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
710 711
      break;
    }
serg@serg.mylan's avatar
serg@serg.mylan committed
712 713 714 715
    if (!*end)
      break;
    control=end+1;
    end= DbugStrTok(control);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
716 717 718 719 720 721
  }
}

/*
 *  FUNCTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
722
 *      _db_pop_    pop the debug stack
bk@work.mysql.com's avatar
bk@work.mysql.com committed
723 724 725
 *
 *  DESCRIPTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
726 727 728 729 730 731 732
 *      Pops the debug stack, returning the debug settings to its
 *      condition prior to the most recent _db_push_ invocation.
 *      Note that the pop will fail if it would remove the last
 *      valid settings from the stack.  This prevents user errors
 *      in the push/pop sequence from screwing up the debugger.
 *      Maybe there should be some kind of warning printed if the
 *      user tries to pop too many states.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
733 734 735
 *
 */

serg@serg.mylan's avatar
serg@serg.mylan committed
736
void _db_pop_()
bk@work.mysql.com's avatar
bk@work.mysql.com committed
737
{
serg@serg.mylan's avatar
serg@serg.mylan committed
738 739 740 741 742 743 744
  struct settings *discard;
  CODE_STATE *cs=0;

  get_code_state_or_return;

  discard= cs->stack;
  if (discard->next != NULL)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
745
  {
serg@serg.mylan's avatar
serg@serg.mylan committed
746
    cs->stack= discard->next;
knielsen@mysql.com's avatar
knielsen@mysql.com committed
747
    FreeState(cs, discard);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
748 749 750
  }
}

serg@serg.mylan's avatar
serg@serg.mylan committed
751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851
/*
 *  FUNCTION
 *
 *      _db_explain_    generates 'control' string for the current settings
 *
 *  RETURN
 *      0 - ok
 *      1  - buffer too short, output truncated
 *
 */

/* helper macros */
#define char_to_buf(C)    do {                  \
        *buf++=(C);                             \
        if (buf >= end) goto overflow;          \
      } while (0)
#define str_to_buf(S)    do {                   \
        char_to_buf(',');                       \
        buf=strnmov(buf, (S), len+1);           \
        if (buf >= end) goto overflow;          \
      } while (0)
#define list_to_buf(l)  do {                    \
        struct link *listp=(l);                 \
        while (listp)                           \
        {                                       \
          str_to_buf(listp->str);               \
          listp=listp->next_link;               \
        }                                       \
      } while (0)
#define int_to_buf(i)  do {                     \
        char b[50];                             \
        int10_to_str((i), b, 10);               \
        str_to_buf(b);                          \
      } while (0)
#define colon_to_buf   do {                     \
        if (buf != start) char_to_buf(':');     \
      } while(0)
#define op_int_to_buf(C, val, def) do {         \
        if ((val) != (def))                     \
        {                                       \
          colon_to_buf;                         \
          char_to_buf((C));                     \
          int_to_buf(val);                      \
        }                                       \
      } while (0)
#define op_intf_to_buf(C, val, def, cond) do {  \
        if ((cond))                             \
        {                                       \
          colon_to_buf;                         \
          char_to_buf((C));                     \
          if ((val) != (def)) int_to_buf(val);  \
        }                                       \
      } while (0)
#define op_str_to_buf(C, val, cond) do {        \
        if ((cond))                             \
        {                                       \
          char *s=(val);                        \
          colon_to_buf;                         \
          char_to_buf((C));                     \
          if (*s) str_to_buf(s);                \
        }                                       \
      } while (0)
#define op_list_to_buf(C, val, cond) do {       \
        if ((cond))                             \
        {                                       \
          colon_to_buf;                         \
          char_to_buf((C));                     \
          list_to_buf(val);                     \
        }                                       \
      } while (0)
#define op_bool_to_buf(C, cond) do {            \
        if ((cond))                             \
        {                                       \
          colon_to_buf;                         \
          char_to_buf((C));                     \
        }                                       \
      } while (0)

int _db_explain_ (CODE_STATE *cs, char *buf, int len)
{
  char *start=buf, *end=buf+len-4;

  get_code_state_or_return *buf=0;

  op_list_to_buf('d', cs->stack->keywords, DEBUGGING);
  op_int_to_buf ('D', cs->stack->delay, 0);
  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);
  op_str_to_buf(
    ((cs->stack->flags & FLUSH_ON_WRITE ? 0 : 32) |
     (cs->stack->flags & OPEN_APPEND ? 'A' : 'O')),
    cs->stack->name, cs->stack->out_file != stderr);
  op_list_to_buf('p', cs->stack->processes, cs->stack->processes);
  op_bool_to_buf('P', cs->stack->flags & PROCESS_ON);
  op_bool_to_buf('r', cs->stack->sub_level != 0);
  op_intf_to_buf('t', cs->stack->maxdepth, MAXDEPTH, TRACING);
serg@serg.mylan's avatar
serg@serg.mylan committed
852
  op_bool_to_buf('T', cs->stack->flags & TIMESTAMP_ON);
serg@serg.mylan's avatar
serg@serg.mylan committed
853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875
  op_bool_to_buf('S', cs->stack->flags & SANITY_CHECK_ON);

  *buf= '\0';
  return 0;

overflow:
  *end++= '.';
  *end++= '.';
  *end++= '.';
  *end=   '\0';
  return 1;
}

#undef char_to_buf
#undef str_to_buf
#undef list_to_buf
#undef int_to_buf
#undef colon_to_buf
#undef op_int_to_buf
#undef op_intf_to_buf
#undef op_str_to_buf
#undef op_list_to_buf
#undef op_bool_to_buf
bk@work.mysql.com's avatar
bk@work.mysql.com committed
876 877 878 879

/*
 *  FUNCTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897
 *      _db_explain_init_       explain initial debugger settings
 *
 *  DESCRIPTION
 *      see _db_explain_
 */

int _db_explain_init_(char *buf, int len)
{
  CODE_STATE cs;
  bzero((char*) &cs,sizeof(cs));
  cs.stack=&init_settings;
  return _db_explain_(&cs, buf, len);
}

/*
 *  FUNCTION
 *
 *      _db_enter_    process entry point to user function
bk@work.mysql.com's avatar
bk@work.mysql.com committed
898 899 900
 *
 *  SYNOPSIS
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
901 902 903 904 905 906 907 908 909
 *      VOID _db_enter_(_func_, _file_, _line_,
 *                       _sfunc_, _sfile_, _slevel_, _sframep_)
 *      char *_func_;           points to current function name
 *      char *_file_;           points to current file name
 *      int _line_;             called from source line number
 *      char **_sfunc_;         save previous _func_
 *      char **_sfile_;         save previous _file_
 *      int *_slevel_;          save previous nesting level
 *      char ***_sframep_;      save previous frame pointer
bk@work.mysql.com's avatar
bk@work.mysql.com committed
910 911 912
 *
 *  DESCRIPTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
913 914 915 916 917 918 919 920 921
 *      Called at the beginning of each user function to tell
 *      the debugger that a new function has been entered.
 *      Note that the pointers to the previous user function
 *      name and previous user file name are stored on the
 *      caller's stack (this is why the ENTER macro must be
 *      the first "executable" code in a function, since it
 *      allocates these storage locations).  The previous nesting
 *      level is also stored on the callers stack for internal
 *      self consistency checks.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
922
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
923 924
 *      Also prints a trace line if tracing is enabled and
 *      increments the current function nesting depth.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
925
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
926 927 928
 *      Note that this mechanism allows the debugger to know
 *      what the current user function is at all times, without
 *      maintaining an internal stack for the function names.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
929 930 931
 *
 */

serg@serg.mylan's avatar
serg@serg.mylan committed
932 933 934
void _db_enter_(const char *_func_, const char *_file_,
                uint _line_, const char **_sfunc_, const char **_sfile_,
                uint *_slevel_, char ***_sframep_ __attribute__((unused)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
935
{
serg@serg.mylan's avatar
serg@serg.mylan committed
936 937 938 939 940 941 942 943 944
  int save_errno=errno;
  CODE_STATE *cs=0;
  get_code_state_or_return;

  *_sfunc_= cs->func;
  *_sfile_= cs->file;
  cs->func=  _func_;
  cs->file=  _file_;
  *_slevel_=  ++cs->level;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
945
#ifndef THREAD
serg@serg.mylan's avatar
serg@serg.mylan committed
946 947 948 949 950 951 952 953
  *_sframep_= cs->framep;
  cs->framep= (char **) _sframep_;
  if (DoProfile(cs))
  {
    long stackused;
    if (*cs->framep == NULL)
      stackused= 0;
    else
bk@work.mysql.com's avatar
bk@work.mysql.com committed
954
    {
serg@serg.mylan's avatar
serg@serg.mylan committed
955 956 957 958
      stackused= ((long)(*cs->framep)) - ((long)(cs->framep));
      stackused= stackused > 0 ? stackused : -stackused;
    }
    (void) fprintf(cs->stack->prof_file, PROF_EFMT , Clock(), cs->func);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
959
#ifdef AUTOS_REVERSE
serg@serg.mylan's avatar
serg@serg.mylan committed
960
    (void) fprintf(cs->stack->prof_file, PROF_SFMT, cs->framep, stackused, *_sfunc_);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
961
#else
serg@serg.mylan's avatar
serg@serg.mylan committed
962 963
    (void) fprintf(cs->stack->prof_file, PROF_SFMT, (ulong) cs->framep, stackused,
                    cs->func);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
964
#endif
serg@serg.mylan's avatar
serg@serg.mylan committed
965 966
    (void) fflush(cs->stack->prof_file);
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
967
#endif
serg@serg.mylan's avatar
serg@serg.mylan committed
968 969 970 971 972 973 974 975 976
  if (DoTrace(cs))
  {
    if (!cs->locked)
      pthread_mutex_lock(&THR_LOCK_dbug);
    DoPrefix(cs, _line_);
    Indent(cs, cs->level);
    (void) fprintf(cs->stack->out_file, ">%s\n", cs->func);
    dbug_flush(cs);                       /* This does a unlock */
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
977
#ifdef SAFEMALLOC
serg@serg.mylan's avatar
serg@serg.mylan committed
978 979 980
  if (cs->stack->flags & SANITY_CHECK_ON)
    if (_sanity(_file_,_line_))               /* Check of safemalloc */
      cs->stack->flags &= ~SANITY_CHECK_ON;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
981
#endif
serg@serg.mylan's avatar
serg@serg.mylan committed
982
  errno=save_errno;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
983 984 985 986 987
}

/*
 *  FUNCTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
988
 *      _db_return_    process exit from user function
bk@work.mysql.com's avatar
bk@work.mysql.com committed
989 990 991
 *
 *  SYNOPSIS
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
992 993 994 995 996
 *      VOID _db_return_(_line_, _sfunc_, _sfile_, _slevel_)
 *      int _line_;             current source line number
 *      char **_sfunc_;         where previous _func_ is to be retrieved
 *      char **_sfile_;         where previous _file_ is to be retrieved
 *      int *_slevel_;          where previous level was stashed
bk@work.mysql.com's avatar
bk@work.mysql.com committed
997 998 999
 *
 *  DESCRIPTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1000 1001 1002 1003
 *      Called just before user function executes an explicit or implicit
 *      return.  Prints a trace line if trace is enabled, decrements
 *      the current nesting level, and restores the current function and
 *      file names from the defunct function's stack.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1004 1005 1006
 *
 */

serg@serg.mylan's avatar
serg@serg.mylan committed
1007 1008 1009
/* helper macro */
void _db_return_(uint _line_, const char **_sfunc_,
                 const char **_sfile_, uint *_slevel_)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1010
{
serg@serg.mylan's avatar
serg@serg.mylan committed
1011 1012 1013
  int save_errno=errno;
  CODE_STATE *cs=0;
  get_code_state_or_return;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1014

serg@serg.mylan's avatar
serg@serg.mylan committed
1015 1016 1017 1018 1019 1020 1021 1022 1023
  if (cs->level != (int) *_slevel_)
  {
    if (!cs->locked)
      pthread_mutex_lock(&THR_LOCK_dbug);
    (void) fprintf(cs->stack->out_file, ERR_MISSING_RETURN, cs->process,
                   cs->func);
    dbug_flush(cs);
  }
  else
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1024 1025
  {
#ifdef SAFEMALLOC
serg@serg.mylan's avatar
serg@serg.mylan committed
1026 1027 1028 1029 1030
    if (cs->stack->flags & SANITY_CHECK_ON)
    {
      if (_sanity(*_sfile_,_line_))
        cs->stack->flags &= ~SANITY_CHECK_ON;
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1031 1032
#endif
#ifndef THREAD
serg@serg.mylan's avatar
serg@serg.mylan committed
1033 1034
    if (DoProfile(cs))
      (void) fprintf(cs->stack->prof_file, PROF_XFMT, Clock(), cs->func);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1035
#endif
serg@serg.mylan's avatar
serg@serg.mylan committed
1036 1037 1038 1039 1040 1041 1042 1043
    if (DoTrace(cs))
    {
      if (!cs->locked)
        pthread_mutex_lock(&THR_LOCK_dbug);
      DoPrefix(cs, _line_);
      Indent(cs, cs->level);
      (void) fprintf(cs->stack->out_file, "<%s\n", cs->func);
      dbug_flush(cs);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1044
    }
serg@serg.mylan's avatar
serg@serg.mylan committed
1045 1046 1047 1048
  }
  cs->level= *_slevel_-1;
  cs->func= *_sfunc_;
  cs->file= *_sfile_;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1049
#ifndef THREAD
serg@serg.mylan's avatar
serg@serg.mylan committed
1050 1051
  if (cs->framep != NULL)
    cs->framep= (char **) *cs->framep;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1052
#endif
serg@serg.mylan's avatar
serg@serg.mylan committed
1053
  errno=save_errno;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1054 1055 1056 1057 1058 1059
}


/*
 *  FUNCTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1060
 *      _db_pargs_    log arguments for subsequent use by _db_doprnt_()
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1061 1062 1063
 *
 *  SYNOPSIS
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1064 1065 1066
 *      VOID _db_pargs_(_line_, keyword)
 *      int _line_;
 *      char *keyword;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1067 1068 1069
 *
 *  DESCRIPTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1070 1071 1072 1073
 *      The new universal printing macro DBUG_PRINT, which replaces
 *      all forms of the DBUG_N macros, needs two calls to runtime
 *      support routines.  The first, this function, remembers arguments
 *      that are used by the subsequent call to _db_doprnt_().
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1074 1075 1076
 *
 */

serg@serg.mylan's avatar
serg@serg.mylan committed
1077
void _db_pargs_(uint _line_, const char *keyword)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1078
{
serg@serg.mylan's avatar
serg@serg.mylan committed
1079 1080 1081 1082
  CODE_STATE *cs=0;
  get_code_state_or_return;
  cs->u_line= _line_;
  cs->u_keyword= (char*) keyword;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1083 1084 1085 1086 1087 1088
}


/*
 *  FUNCTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1089
 *      _db_doprnt_    handle print of debug lines
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1090 1091 1092
 *
 *  SYNOPSIS
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1093 1094 1095
 *      VOID _db_doprnt_(format, va_alist)
 *      char *format;
 *      va_dcl;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1096 1097 1098
 *
 *  DESCRIPTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1099 1100 1101 1102 1103
 *      When invoked via one of the DBUG macros, tests the current keyword
 *      set by calling _db_pargs_() to see if that macro has been selected
 *      for processing via the debugger control string, and if so, handles
 *      printing of the arguments via the format string.  The line number
 *      of the DBUG macro in the source is found in u_line.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1104
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1105 1106
 *      Note that the format string SHOULD NOT include a terminating
 *      newline, this is supplied automatically.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1107 1108 1109 1110 1111
 *
 */

#include <stdarg.h>

serg@serg.mylan's avatar
serg@serg.mylan committed
1112
void _db_doprnt_(const char *format,...)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1113 1114
{
  va_list args;
serg@serg.mylan's avatar
serg@serg.mylan committed
1115 1116 1117

  CODE_STATE *cs=0;
  get_code_state_or_return;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1118 1119 1120

  va_start(args,format);

serg@serg.mylan's avatar
serg@serg.mylan committed
1121 1122
  if (_db_keyword_(cs, cs->u_keyword))
  {
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1123
    int save_errno=errno;
serg@serg.mylan's avatar
serg@serg.mylan committed
1124
    if (!cs->locked)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1125
      pthread_mutex_lock(&THR_LOCK_dbug);
serg@serg.mylan's avatar
serg@serg.mylan committed
1126 1127 1128 1129 1130 1131 1132 1133 1134
    DoPrefix(cs, cs->u_line);
    if (TRACING)
      Indent(cs, cs->level + 1);
    else
      (void) fprintf(cs->stack->out_file, "%s: ", cs->func);
    (void) fprintf(cs->stack->out_file, "%s: ", cs->u_keyword);
    (void) vfprintf(cs->stack->out_file, format, args);
    (void) fputc('\n',cs->stack->out_file);
    dbug_flush(cs);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1135 1136 1137 1138 1139 1140 1141 1142 1143
    errno=save_errno;
  }
  va_end(args);
}


/*
 *  FUNCTION
 *
1144
 *            _db_dump_    dump a string in hex
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1145 1146 1147
 *
 *  SYNOPSIS
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1148 1149 1150 1151 1152
 *            void _db_dump_(_line_,keyword,memory,length)
 *            int _line_;               current source line number
 *            char *keyword;
 *            char *memory;             Memory to print
 *            int length;               Bytes to print
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1153 1154 1155 1156 1157 1158
 *
 *  DESCRIPTION
 *  Dump N characters in a binary array.
 *  Is used to examine corrputed memory or arrays.
 */

serg@serg.mylan's avatar
serg@serg.mylan committed
1159
void _db_dump_(uint _line_, const char *keyword, const char *memory, uint length)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1160 1161 1162 1163
{
  int pos;
  char dbuff[90];

serg@serg.mylan's avatar
serg@serg.mylan committed
1164 1165 1166 1167
  CODE_STATE *cs=0;
  get_code_state_or_return;

  if (_db_keyword_(cs, (char*) keyword))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1168
  {
serg@serg.mylan's avatar
serg@serg.mylan committed
1169
    if (!cs->locked)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1170
      pthread_mutex_lock(&THR_LOCK_dbug);
serg@serg.mylan's avatar
serg@serg.mylan committed
1171
    DoPrefix(cs, _line_);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1172 1173
    if (TRACING)
    {
serg@serg.mylan's avatar
serg@serg.mylan committed
1174 1175
      Indent(cs, cs->level + 1);
      pos= min(max(cs->level-cs->stack->sub_level,0)*INDENT,80);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1176 1177 1178
    }
    else
    {
serg@serg.mylan's avatar
serg@serg.mylan committed
1179
      fprintf(cs->stack->out_file, "%s: ", cs->func);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1180
    }
1181
    sprintf(dbuff,"%s: Memory: 0x%lx  Bytes: (%d)\n",
serg@serg.mylan's avatar
serg@serg.mylan committed
1182 1183
            keyword,(ulong) memory, length);
    (void) fputs(dbuff,cs->stack->out_file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1184 1185 1186 1187 1188 1189 1190

    pos=0;
    while (length-- > 0)
    {
      uint tmp= *((unsigned char*) memory++);
      if ((pos+=3) >= 80)
      {
serg@serg.mylan's avatar
serg@serg.mylan committed
1191 1192
        fputc('\n',cs->stack->out_file);
        pos=3;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1193
      }
serg@serg.mylan's avatar
serg@serg.mylan committed
1194 1195 1196
      fputc(_dig_vec_upper[((tmp >> 4) & 15)], cs->stack->out_file);
      fputc(_dig_vec_upper[tmp & 15], cs->stack->out_file);
      fputc(' ',cs->stack->out_file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1197
    }
serg@serg.mylan's avatar
serg@serg.mylan committed
1198 1199
    (void) fputc('\n',cs->stack->out_file);
    dbug_flush(cs);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1200 1201 1202
  }
}

monty@mysql.com's avatar
monty@mysql.com committed
1203 1204

/*
serg@serg.mylan's avatar
serg@serg.mylan committed
1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226
 *  FUNCTION
 *
 *      ListAdd    add to the list modifiers from debug control string
 *
 *  SYNOPSIS
 *
 *      static struct link *ListAdd(listp, ctlp, end)
 *      struct link *listp;
 *      char *ctlp;
 *      char *end;
 *
 *  DESCRIPTION
 *
 *      Given pointer to a comma separated list of strings in "cltp",
 *      parses the list, and adds it to listp, returning a pointer
 *      to the new list
 *
 *      Note that since each link is added at the head of the list,
 *      the final list will be in "reverse order", which is not
 *      significant for our usage here.
 *
 */
monty@mysql.com's avatar
monty@mysql.com committed
1227

serg@serg.mylan's avatar
serg@serg.mylan committed
1228 1229 1230 1231 1232 1233
static struct link *ListAdd(struct link *head,
                             const char *ctlp, const char *end)
{
  const char *start;
  struct link *new_malloc;
  int len;
monty@mysql.com's avatar
monty@mysql.com committed
1234

serg@serg.mylan's avatar
serg@serg.mylan committed
1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249
  while (ctlp < end)
  {
    start= ctlp;
    while (ctlp < end && *ctlp != ',')
      ctlp++;
    len=ctlp-start;
    new_malloc= (struct link *) DbugMalloc(sizeof(struct link)+len);
    memcpy(new_malloc->str, start, len);
    new_malloc->str[len]=0;
    new_malloc->next_link= head;
    head= new_malloc;
    ctlp++;
  }
  return head;
}
monty@mysql.com's avatar
monty@mysql.com committed
1250

serg@serg.mylan's avatar
serg@serg.mylan committed
1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272
/*
 *  FUNCTION
 *
 *      ListDel    remove from the list modifiers in debug control string
 *
 *  SYNOPSIS
 *
 *      static struct link *ListDel(listp, ctlp, end)
 *      struct link *listp;
 *      char *ctlp;
 *      char *end;
 *
 *  DESCRIPTION
 *
 *      Given pointer to a comma separated list of strings in "cltp",
 *      parses the list, and removes these strings from the listp,
 *      returning a pointer to the new list.
 *
 */

static struct link *ListDel(struct link *head,
                             const char *ctlp, const char *end)
monty@mysql.com's avatar
monty@mysql.com committed
1273
{
serg@serg.mylan's avatar
serg@serg.mylan committed
1274 1275 1276
  const char *start;
  struct link **cur;
  int len;
monty@mysql.com's avatar
monty@mysql.com committed
1277

serg@serg.mylan's avatar
serg@serg.mylan committed
1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296
  while (ctlp < end)
  {
    start= ctlp;
    while (ctlp < end && *ctlp != ',')
      ctlp++;
    len=ctlp-start;
    cur=&head;
    do
    {
      while (*cur && !strncmp((*cur)->str, start, len))
      {
        struct link *delme=*cur;
        *cur=(*cur)->next_link;
        free((char*)delme);
      }
    } while (*cur && *(cur=&((*cur)->next_link)));
  }
  return head;
}
monty@mysql.com's avatar
monty@mysql.com committed
1297

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1298 1299 1300
/*
 *  FUNCTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1301
 *      ListCopy    make a copy of the list
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1302 1303 1304
 *
 *  SYNOPSIS
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1305 1306
 *      static struct link *ListCopy(orig)
 *      struct link *orig;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1307 1308 1309
 *
 *  DESCRIPTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1310 1311
 *      Given pointer to list, which contains a copy of every element from
 *      the original list.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1312
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1313 1314 1315 1316 1317
 *      the orig pointer can be NULL
 *
 *      Note that since each link is added at the head of the list,
 *      the final list will be in "reverse order", which is not
 *      significant for our usage here.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1318 1319 1320
 *
 */

serg@serg.mylan's avatar
serg@serg.mylan committed
1321
static struct link *ListCopy(struct link *orig)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1322
{
serg@serg.mylan's avatar
serg@serg.mylan committed
1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336
  struct link *new_malloc;
  struct link *head;
  int len;

  head= NULL;
  while (orig != NULL)
  {
    len= strlen(orig->str);
    new_malloc= (struct link *) DbugMalloc(sizeof(struct link)+len);
    memcpy(new_malloc->str, orig->str, len);
    new_malloc->str[len]= 0;
    new_malloc->next_link= head;
    head= new_malloc;
    orig= orig->next_link;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1337
  }
serg@serg.mylan's avatar
serg@serg.mylan committed
1338
  return head;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1339 1340 1341 1342 1343
}

/*
 *  FUNCTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1344
 *      InList    test a given string for member of a given list
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1345 1346 1347
 *
 *  SYNOPSIS
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1348 1349 1350
 *      static BOOLEAN InList(linkp, cp)
 *      struct link *linkp;
 *      char *cp;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1351 1352 1353
 *
 *  DESCRIPTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1354 1355 1356 1357 1358 1359 1360 1361
 *      Tests the string pointed to by "cp" to determine if it is in
 *      the list pointed to by "linkp".  Linkp points to the first
 *      link in the list.  If linkp is NULL then the string is treated
 *      as if it is in the list (I.E all strings are in the null list).
 *      This may seem rather strange at first but leads to the desired
 *      operation if no list is given.  The net effect is that all
 *      strings will be accepted when there is no list, and when there
 *      is a list, only those strings in the list will be accepted.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1362 1363 1364
 *
 */

serg@serg.mylan's avatar
serg@serg.mylan committed
1365
static BOOLEAN InList(struct link *linkp, const char *cp)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1366 1367 1368 1369
{
  REGISTER struct link *scan;
  REGISTER BOOLEAN result;

serg@serg.mylan's avatar
serg@serg.mylan committed
1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380
  if (linkp == NULL)
    result= TRUE;
  else
  {
    result= FALSE;
    for (scan= linkp; scan != NULL; scan= scan->next_link)
    {
      if (!strcmp(scan->str, cp))
      {
        result= TRUE;
        break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1381 1382 1383
      }
    }
  }
serg@serg.mylan's avatar
serg@serg.mylan committed
1384
  return result;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1385 1386 1387 1388 1389 1390
}


/*
 *  FUNCTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1391
 *      PushState    push current settings onto stack and set up new one
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1392 1393 1394
 *
 *  SYNOPSIS
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1395
 *      static VOID PushState()
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1396 1397 1398
 *
 *  DESCRIPTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1399 1400
 *      Pushes the current settings on the settings stack, and creates
 *      a new settings. The new settings is NOT initialized
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1401
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1402 1403 1404
 *      The settings stack is a linked list of settings, with the new
 *      settings added at the head.  This allows the stack to grow
 *      to the limits of memory if necessary.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1405 1406 1407
 *
 */

serg@serg.mylan's avatar
serg@serg.mylan committed
1408
static void PushState(CODE_STATE *cs)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1409
{
serg@serg.mylan's avatar
serg@serg.mylan committed
1410
  struct settings *new_malloc;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1411

serg@serg.mylan's avatar
serg@serg.mylan committed
1412 1413 1414 1415
  new_malloc= (struct settings *) DbugMalloc(sizeof(struct settings));
  new_malloc->next= cs->stack;
  new_malloc->out_file= NULL;
  cs->stack= new_malloc;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1416 1417
}

1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434
/*
 *  FUNCTION
 *
 *	FreeState    Free memory associated with a struct state.
 *
 *  SYNOPSIS
 *
 *	static void FreeState (state)
 *	struct state *state;
 *
 *  DESCRIPTION
 *
 *	Deallocates the memory allocated for various information in a
 *	state.
 *
 */
static void FreeState (
knielsen@mysql.com's avatar
knielsen@mysql.com committed
1435 1436
CODE_STATE *cs,
struct settings *state)
1437
{
1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450
  if (!is_shared(state, keywords))
    FreeList(state->keywords);
  if (!is_shared(state, functions))
    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);
  if (state->prof_file)
    DBUGCloseFile(cs, state->prof_file);
  free((char *) state);
1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472
}


/*
 *  FUNCTION
 *
 *	_db_end_    End debugging, freeing state stack memory.
 *
 *  SYNOPSIS
 *
 *	static VOID _db_end_ ()
 *
 *  DESCRIPTION
 *
 *	Ends debugging, de-allocating the memory allocated to the
 *	state stack.
 *
 *	To be called at the very end of the program.
 *
 */
void _db_end_ ()
{
knielsen@mysql.com's avatar
knielsen@mysql.com committed
1473 1474 1475 1476 1477 1478 1479 1480 1481 1482
  struct settings *discard;
  CODE_STATE *cs=0;

  get_code_state_or_return;

  while((discard= cs->stack) != NULL) {
    if(discard == &init_settings)
      break;
    cs->stack= discard->next;
    FreeState (cs, discard);
1483 1484 1485
  }
}

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1486 1487 1488 1489

/*
 *  FUNCTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1490
 *      DoTrace    check to see if tracing is current enabled
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1491 1492 1493
 *
 *  SYNOPSIS
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1494
 *      static BOOLEAN DoTrace(stack)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1495 1496 1497
 *
 *  DESCRIPTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1498 1499 1500 1501 1502
 *      Checks to see if tracing is enabled based on whether the
 *      user has specified tracing, the maximum trace depth has
 *      not yet been reached, the current function is selected,
 *      and the current process is selected.  Returns TRUE if
 *      tracing is enabled, FALSE otherwise.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1503 1504 1505
 *
 */

serg@serg.mylan's avatar
serg@serg.mylan committed
1506
static BOOLEAN DoTrace(CODE_STATE *cs)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1507
{
serg@serg.mylan's avatar
serg@serg.mylan committed
1508 1509 1510
  return (TRACING && cs->level <= cs->stack->maxdepth &&
          InList(cs->stack->functions, cs->func) &&
          InList(cs->stack->processes, cs->process));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1511 1512 1513 1514 1515 1516
}


/*
 *  FUNCTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1517
 *      DoProfile    check to see if profiling is current enabled
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1518 1519 1520
 *
 *  SYNOPSIS
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1521
 *      static BOOLEAN DoProfile()
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1522 1523 1524
 *
 *  DESCRIPTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1525 1526 1527 1528 1529
 *      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.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1530 1531 1532 1533
 *
 */

#ifndef THREAD
serg@serg.mylan's avatar
serg@serg.mylan committed
1534
static BOOLEAN DoProfile(CODE_STATE *cs)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1535
{
serg@serg.mylan's avatar
serg@serg.mylan committed
1536 1537 1538 1539
  return PROFILING &&
         cs->level <= cs->stack->maxdepth &&
         InList(cs->stack->p_functions, cs->func) &&
         InList(cs->stack->processes, cs->process);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1540 1541 1542
}
#endif

serg@serg.mylan's avatar
serg@serg.mylan committed
1543 1544 1545 1546 1547 1548 1549 1550
FILE *_db_fp_(void)
{
  CODE_STATE *cs=0;
  get_code_state_or_return NULL;
  return cs->stack->out_file;
}


1551 1552 1553 1554 1555 1556 1557
/*
 *  FUNCTION
 *
 *      _db_strict_keyword_     test keyword for member of keyword list
 *
 *  SYNOPSIS
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1558
 *      BOOLEAN _db_strict_keyword_(keyword)
1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570
 *      char *keyword;
 *
 *  DESCRIPTION
 *
 *      Similar to _db_keyword_, but keyword is NOT accepted if keyword list
 *      is empty. Used in DBUG_EXECUTE_IF() - for actions that must not be
 *      executed by default.
 *
 *      Returns TRUE if keyword accepted, FALSE otherwise.
 *
 */

serg@serg.mylan's avatar
serg@serg.mylan committed
1571
BOOLEAN _db_strict_keyword_(const char *keyword)
1572
{
serg@serg.mylan's avatar
serg@serg.mylan committed
1573 1574 1575
  CODE_STATE *cs=0;
  get_code_state_or_return FALSE;
  if (!DEBUGGING || cs->stack->keywords == NULL)
1576
    return FALSE;
serg@serg.mylan's avatar
serg@serg.mylan committed
1577
  return _db_keyword_(cs, keyword);
1578
}
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1579 1580 1581 1582

/*
 *  FUNCTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1583
 *      _db_keyword_    test keyword for member of keyword list
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1584 1585 1586
 *
 *  SYNOPSIS
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1587 1588
 *      BOOLEAN _db_keyword_(keyword)
 *      char *keyword;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1589 1590 1591
 *
 *  DESCRIPTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1592 1593 1594 1595 1596 1597 1598 1599
 *      Test a keyword to determine if it is in the currently active
 *      keyword list.  As with the function list, a keyword is accepted
 *      if the list is null, otherwise it must match one of the list
 *      members.  When debugging is not on, no keywords are accepted.
 *      After the maximum trace level is exceeded, no keywords are
 *      accepted (this behavior subject to change).  Additionally,
 *      the current function and process must be accepted based on
 *      their respective lists.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1600
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1601
 *      Returns TRUE if keyword accepted, FALSE otherwise.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1602 1603 1604
 *
 */

serg@serg.mylan's avatar
serg@serg.mylan committed
1605
BOOLEAN _db_keyword_(CODE_STATE *cs, const char *keyword)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1606
{
serg@serg.mylan's avatar
serg@serg.mylan committed
1607
  get_code_state_or_return FALSE;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1608

serg@serg.mylan's avatar
serg@serg.mylan committed
1609 1610 1611 1612 1613
  return (DEBUGGING &&
          (!TRACING || cs->level <= cs->stack->maxdepth) &&
          InList(cs->stack->functions, cs->func) &&
          InList(cs->stack->keywords, keyword) &&
          InList(cs->stack->processes, cs->process));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1614 1615 1616 1617 1618
}

/*
 *  FUNCTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1619
 *      Indent    indent a line to the given indentation level
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1620 1621 1622
 *
 *  SYNOPSIS
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1623 1624
 *      static VOID Indent(indent)
 *      int indent;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1625 1626 1627
 *
 *  DESCRIPTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1628 1629 1630
 *      Indent a line to the given level.  Note that this is
 *      a simple minded but portable implementation.
 *      There are better ways.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1631
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1632 1633
 *      Also, the indent must be scaled by the compile time option
 *      of character positions per nesting level.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1634 1635 1636
 *
 */

serg@serg.mylan's avatar
serg@serg.mylan committed
1637
static void Indent(CODE_STATE *cs, int indent)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1638 1639 1640
{
  REGISTER int count;

serg@serg.mylan's avatar
serg@serg.mylan committed
1641 1642
  indent= max(indent-1-cs->stack->sub_level,0)*INDENT;
  for (count= 0; count < indent ; count++)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1643 1644
  {
    if ((count % INDENT) == 0)
serg@serg.mylan's avatar
serg@serg.mylan committed
1645
      fputc('|',cs->stack->out_file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1646
    else
serg@serg.mylan's avatar
serg@serg.mylan committed
1647
      fputc(' ',cs->stack->out_file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1648 1649 1650 1651 1652 1653 1654
  }
}


/*
 *  FUNCTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1655
 *      FreeList    free all memory associated with a linked list
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1656 1657 1658
 *
 *  SYNOPSIS
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1659 1660
 *      static VOID FreeList(linkp)
 *      struct link *linkp;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1661 1662 1663
 *
 *  DESCRIPTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1664 1665
 *      Given pointer to the head of a linked list, frees all
 *      memory held by the list and the members of the list.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1666 1667 1668
 *
 */

serg@serg.mylan's avatar
serg@serg.mylan committed
1669
static void FreeList(struct link *linkp)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1670 1671 1672
{
  REGISTER struct link *old;

serg@serg.mylan's avatar
serg@serg.mylan committed
1673 1674 1675 1676 1677
  while (linkp != NULL)
  {
    old= linkp;
    linkp= linkp->next_link;
    free((char *) old);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1678 1679 1680 1681 1682 1683 1684
  }
}


/*
 *  FUNCTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1685
 *      DoPrefix    print debugger line prefix prior to indentation
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1686 1687 1688
 *
 *  SYNOPSIS
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1689 1690
 *      static VOID DoPrefix(_line_)
 *      int _line_;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1691 1692 1693
 *
 *  DESCRIPTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1694 1695 1696 1697
 *      Print prefix common to all debugger output lines, prior to
 *      doing indentation if necessary.  Print such information as
 *      current process name, current source file name and line number,
 *      and current function nesting depth.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1698 1699 1700
 *
 */

serg@serg.mylan's avatar
serg@serg.mylan committed
1701
static void DoPrefix(CODE_STATE *cs, uint _line_)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1702
{
serg@serg.mylan's avatar
serg@serg.mylan committed
1703 1704 1705
  cs->lineno++;
  if (cs->stack->flags & PID_ON)
  {
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1706
#ifdef THREAD
serg@serg.mylan's avatar
serg@serg.mylan committed
1707
    (void) fprintf(cs->stack->out_file, "%-7s: ", my_thread_name());
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1708
#else
serg@serg.mylan's avatar
serg@serg.mylan committed
1709
    (void) fprintf(cs->stack->out_file, "%5d: ", (int) getpid());
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1710 1711
#endif
  }
serg@serg.mylan's avatar
serg@serg.mylan committed
1712 1713 1714 1715
  if (cs->stack->flags & NUMBER_ON)
    (void) fprintf(cs->stack->out_file, "%5d: ", cs->lineno);
  if (cs->stack->flags & TIMESTAMP_ON)
  {
kent@mysql.com's avatar
kent@mysql.com committed
1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726
#ifdef __WIN__
    /* FIXME This doesn't give microseconds as in Unix case, and the resolution is
       in system ticks, 10 ms intervals. See my_getsystime.c for high res */
    SYSTEMTIME loc_t;
    GetLocalTime(&loc_t);
    (void) fprintf (cs->stack->out_file,
                    /* "%04d-%02d-%02d " */
                    "%02d:%02d:%02d.%06d ",
                    /*tm_p->tm_year + 1900, tm_p->tm_mon + 1, tm_p->tm_mday,*/
                    loc_t.wHour, loc_t.wMinute, loc_t.wSecond, loc_t.wMilliseconds);
#else
serg@serg.mylan's avatar
serg@serg.mylan committed
1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740
    struct timeval tv;
    struct tm *tm_p;
    if (gettimeofday(&tv, NULL) != -1)
    {
      if ((tm_p= localtime(&tv.tv_sec)))
      {
        (void) fprintf (cs->stack->out_file,
                        /* "%04d-%02d-%02d " */
                        "%02d:%02d:%02d.%06d ",
                        /*tm_p->tm_year + 1900, tm_p->tm_mon + 1, tm_p->tm_mday,*/
                        tm_p->tm_hour, tm_p->tm_min, tm_p->tm_sec,
                        (int) (tv.tv_usec));
      }
    }
kent@mysql.com's avatar
kent@mysql.com committed
1741
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1742
  }
serg@serg.mylan's avatar
serg@serg.mylan committed
1743 1744 1745 1746 1747 1748 1749 1750
  if (cs->stack->flags & PROCESS_ON)
    (void) fprintf(cs->stack->out_file, "%s: ", cs->process);
  if (cs->stack->flags & FILE_ON)
    (void) fprintf(cs->stack->out_file, "%14s: ", BaseName(cs->file));
  if (cs->stack->flags & LINE_ON)
    (void) fprintf(cs->stack->out_file, "%5d: ", _line_);
  if (cs->stack->flags & DEPTH_ON)
    (void) fprintf(cs->stack->out_file, "%4d: ", cs->level);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1751 1752 1753 1754 1755 1756
}


/*
 *  FUNCTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1757
 *      DBUGOpenFile    open new output stream for debugger output
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1758 1759 1760
 *
 *  SYNOPSIS
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1761 1762
 *      static VOID DBUGOpenFile(name)
 *      char *name;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1763 1764 1765
 *
 *  DESCRIPTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1766 1767
 *      Given name of a new file (or "-" for stdout) opens the file
 *      and sets the output stream to the new file.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1768 1769 1770
 *
 */

serg@serg.mylan's avatar
serg@serg.mylan committed
1771 1772
static void DBUGOpenFile(CODE_STATE *cs,
                         const char *name,const char *end,int append)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1773 1774 1775 1776 1777 1778
{
  REGISTER FILE *fp;
  REGISTER BOOLEAN newfile;

  if (name != NULL)
  {
serg@serg.mylan's avatar
serg@serg.mylan committed
1779 1780 1781 1782 1783 1784 1785 1786 1787 1788
    if (end)
    {
      int len=end-name;
      memcpy(cs->stack->name, name, len);
      cs->stack->name[len]=0;
    }
    else
    strmov(cs->stack->name,name);
    name=cs->stack->name;
    if (strcmp(name, "-") == 0)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1789
    {
serg@serg.mylan's avatar
serg@serg.mylan committed
1790 1791 1792
      cs->stack->out_file= stdout;
      cs->stack->flags |= FLUSH_ON_WRITE;
      cs->stack->name[0]=0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1793 1794 1795
    }
    else
    {
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1796
      if (!Writable((char*)name))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1797
      {
serg@serg.mylan's avatar
serg@serg.mylan committed
1798 1799 1800
        (void) fprintf(stderr, ERR_OPEN, cs->process, name);
        perror("");
        fflush(stderr);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1801 1802 1803
      }
      else
      {
serg@serg.mylan's avatar
serg@serg.mylan committed
1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818
        newfile= !EXISTS(name);
        if (!(fp= fopen(name, append ? "a+" : "w")))
        {
          (void) fprintf(stderr, ERR_OPEN, cs->process, name);
          perror("");
          fflush(stderr);
        }
        else
        {
          cs->stack->out_file= fp;
          if (newfile)
          {
            ChangeOwner(cs, name);
          }
        }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1819 1820 1821 1822 1823 1824 1825 1826 1827
      }
    }
  }
}


/*
 *  FUNCTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1828
 *      OpenProfile    open new output stream for profiler output
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1829 1830 1831
 *
 *  SYNOPSIS
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1832 1833
 *      static FILE *OpenProfile(name)
 *      char *name;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1834 1835 1836
 *
 *  DESCRIPTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848
 *      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].
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1849 1850 1851
 */

#ifndef THREAD
serg@serg.mylan's avatar
serg@serg.mylan committed
1852
static FILE *OpenProfile(CODE_STATE *cs, const char *name)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1853 1854 1855 1856 1857
{
  REGISTER FILE *fp;
  REGISTER BOOLEAN newfile;

  fp=0;
serg@serg.mylan's avatar
serg@serg.mylan committed
1858
  if (!Writable(name))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1859
  {
serg@serg.mylan's avatar
serg@serg.mylan committed
1860 1861
    (void) fprintf(cs->stack->out_file, ERR_OPEN, cs->process, name);
    perror("");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1862
    dbug_flush(0);
serg@serg.mylan's avatar
serg@serg.mylan committed
1863
    (void) Delay(cs->stack->delay);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1864 1865 1866
  }
  else
  {
serg@serg.mylan's avatar
serg@serg.mylan committed
1867 1868
    newfile= !EXISTS(name);
    if (!(fp= fopen(name, "w")))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1869
    {
serg@serg.mylan's avatar
serg@serg.mylan committed
1870 1871
      (void) fprintf(cs->stack->out_file, ERR_OPEN, cs->process, name);
      perror("");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1872 1873 1874 1875
      dbug_flush(0);
    }
    else
    {
serg@serg.mylan's avatar
serg@serg.mylan committed
1876
      cs->stack->prof_file= fp;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1877 1878
      if (newfile)
      {
serg@serg.mylan's avatar
serg@serg.mylan committed
1879
        ChangeOwner(cs, name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1880 1881 1882 1883 1884 1885 1886 1887 1888 1889
      }
    }
  }
  return fp;
}
#endif

/*
 *  FUNCTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1890
 *      DBUGCloseFile    close the debug output stream
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1891 1892 1893
 *
 *  SYNOPSIS
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1894 1895
 *      static VOID DBUGCloseFile(fp)
 *      FILE *fp;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1896 1897 1898
 *
 *  DESCRIPTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1899 1900
 *      Closes the debug output stream unless it is standard output
 *      or standard error.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1901 1902 1903
 *
 */

serg@serg.mylan's avatar
serg@serg.mylan committed
1904
static void DBUGCloseFile(CODE_STATE *cs, FILE *fp)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1905
{
serg@serg.mylan's avatar
serg@serg.mylan committed
1906 1907 1908 1909 1910 1911
  if (fp != stderr && fp != stdout && fclose(fp) == EOF)
  {
    pthread_mutex_lock(&THR_LOCK_dbug);
    (void) fprintf(cs->stack->out_file, ERR_CLOSE, cs->process);
    perror("");
    dbug_flush(0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1912 1913 1914 1915 1916 1917 1918
  }
}


/*
 *  FUNCTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1919
 *      DbugExit    print error message and exit
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1920 1921 1922
 *
 *  SYNOPSIS
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1923 1924
 *      static VOID DbugExit(why)
 *      char *why;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1925 1926 1927
 *
 *  DESCRIPTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1928 1929 1930 1931
 *      Prints error message using current process name, the reason for
 *      aborting (typically out of memory), and exits with status 1.
 *      This should probably be changed to use a status code
 *      defined in the user's debugger include file.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1932 1933 1934
 *
 */

serg@serg.mylan's avatar
serg@serg.mylan committed
1935
static void DbugExit(const char *why)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1936
{
serg@serg.mylan's avatar
serg@serg.mylan committed
1937 1938 1939 1940
  CODE_STATE *cs=code_state();
  (void) fprintf(stderr, ERR_ABORT, cs ? cs->process : "(null)", why);
  (void) fflush(stderr);
  exit(1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1941 1942 1943 1944 1945 1946
}


/*
 *  FUNCTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1947
 *      DbugMalloc    allocate memory for debugger runtime support
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1948 1949 1950
 *
 *  SYNOPSIS
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1951 1952
 *      static long *DbugMalloc(size)
 *      int size;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1953 1954 1955
 *
 *  DESCRIPTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1956 1957 1958 1959 1960 1961
 *      Allocate more memory for debugger runtime support functions.
 *      Failure to to allocate the requested number of bytes is
 *      immediately fatal to the current process.  This may be
 *      rather unfriendly behavior.  It might be better to simply
 *      print a warning message, freeze the current debugger cs,
 *      and continue execution.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1962 1963 1964
 *
 */

serg@serg.mylan's avatar
serg@serg.mylan committed
1965
static char *DbugMalloc(size_t size)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1966
{
1967
  register char *new_malloc;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1968

serg@serg.mylan's avatar
serg@serg.mylan committed
1969 1970 1971
  if (!(new_malloc= (char*) malloc((size_t) size)))
    DbugExit("out of memory");
  return new_malloc;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1972 1973 1974 1975
}


/*
serg@serg.mylan's avatar
serg@serg.mylan committed
1976
 *     strtok lookalike - splits on ':', magically handles :\ and :/
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1977 1978
 */

serg@serg.mylan's avatar
serg@serg.mylan committed
1979
static const char *DbugStrTok(const char *s)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1980
{
serg@serg.mylan's avatar
serg@serg.mylan committed
1981 1982 1983
  while (s[0] && (s[0] != ':' || (s[1] == '\\' || s[1] == '/')))
    s++;
  return s;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1984 1985 1986 1987 1988 1989
}


/*
 *  FUNCTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1990
 *      BaseName    strip leading pathname components from name
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1991 1992 1993
 *
 *  SYNOPSIS
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1994 1995
 *      static char *BaseName(pathname)
 *      char *pathname;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1996 1997 1998
 *
 *  DESCRIPTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
1999 2000 2001
 *      Given pointer to a complete pathname, locates the base file
 *      name at the end of the pathname and returns a pointer to
 *      it.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2002 2003 2004
 *
 */

serg@serg.mylan's avatar
serg@serg.mylan committed
2005
static const char *BaseName(const char *pathname)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2006 2007 2008
{
  register const char *base;

serg@serg.mylan's avatar
serg@serg.mylan committed
2009
  base= strrchr(pathname, FN_LIBCHAR);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2010
  if (base++ == NullS)
serg@serg.mylan's avatar
serg@serg.mylan committed
2011 2012
    base= pathname;
  return base;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2013 2014 2015 2016 2017 2018
}


/*
 *  FUNCTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
2019
 *      Writable    test to see if a pathname is writable/creatable
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2020 2021 2022
 *
 *  SYNOPSIS
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
2023 2024
 *      static BOOLEAN Writable(pathname)
 *      char *pathname;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2025 2026 2027
 *
 *  DESCRIPTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
2028 2029 2030 2031 2032
 *      Because the debugger might be linked in with a program that
 *      runs with the set-uid-bit (suid) set, we have to be careful
 *      about opening a user named file for debug output.  This consists
 *      of checking the file for write access with the real user id,
 *      or checking the directory where the file will be created.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2033
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
2034 2035
 *      Returns TRUE if the user would normally be allowed write or
 *      create access to the named file.  Returns FALSE otherwise.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2036 2037 2038 2039 2040 2041
 *
 */


#ifndef Writable

serg@serg.mylan's avatar
serg@serg.mylan committed
2042
static BOOLEAN Writable(char *pathname)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2043 2044 2045 2046
{
  REGISTER BOOLEAN granted;
  REGISTER char *lastslash;

serg@serg.mylan's avatar
serg@serg.mylan committed
2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063
  granted= FALSE;
  if (EXISTS(pathname))
  {
    if (WRITABLE(pathname))
      granted= TRUE;
  }
  else
  {
    lastslash= strrchr(pathname, '/');
    if (lastslash != NULL)
      *lastslash= '\0';
    else
      pathname= ".";
    if (WRITABLE(pathname))
      granted= TRUE;
    if (lastslash != NULL)
      *lastslash= '/';
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2064
  }
serg@serg.mylan's avatar
serg@serg.mylan committed
2065
  return granted;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2066 2067 2068 2069 2070 2071 2072
}
#endif


/*
 *  FUNCTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
2073
 *      ChangeOwner    change owner to real user for suid programs
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2074 2075 2076
 *
 *  SYNOPSIS
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
2077
 *      static VOID ChangeOwner(pathname)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2078 2079 2080
 *
 *  DESCRIPTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
2081 2082 2083
 *      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.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2084
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
2085 2086 2087 2088 2089
 *      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).
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2090 2091 2092 2093
 *
 */

#ifndef ChangeOwner
serg@serg.mylan's avatar
serg@serg.mylan committed
2094
static void ChangeOwner(CODE_STATE *cs, char *pathname)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2095
{
serg@serg.mylan's avatar
serg@serg.mylan committed
2096
  if (chown(pathname, getuid(), getgid()) == -1)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2097
  {
serg@serg.mylan's avatar
serg@serg.mylan committed
2098 2099 2100
    (void) fprintf(stderr, ERR_CHOWN, cs->process, pathname);
    perror("");
    (void) fflush(stderr);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2101 2102 2103 2104 2105 2106 2107 2108
  }
}
#endif


/*
 *  FUNCTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
2109
 *      _db_setjmp_    save debugger environment
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2110 2111 2112
 *
 *  SYNOPSIS
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
2113
 *      VOID _db_setjmp_()
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2114 2115 2116
 *
 *  DESCRIPTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
2117 2118 2119
 *      Invoked as part of the user's DBUG_SETJMP macro to save
 *      the debugger environment in parallel with saving the user's
 *      environment.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2120 2121 2122 2123 2124
 *
 */

#ifdef HAVE_LONGJMP

serg@serg.mylan's avatar
serg@serg.mylan committed
2125
EXPORT void _db_setjmp_()
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2126
{
serg@serg.mylan's avatar
serg@serg.mylan committed
2127 2128
  CODE_STATE *cs=0;
  get_code_state_or_return;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2129

serg@serg.mylan's avatar
serg@serg.mylan committed
2130 2131 2132
  cs->jmplevel= cs->level;
  cs->jmpfunc= cs->func;
  cs->jmpfile= cs->file;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2133 2134 2135 2136 2137
}

/*
 *  FUNCTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
2138
 *      _db_longjmp_    restore previously saved debugger environment
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2139 2140 2141
 *
 *  SYNOPSIS
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
2142
 *      VOID _db_longjmp_()
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2143 2144 2145
 *
 *  DESCRIPTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
2146 2147 2148
 *      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.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2149 2150 2151
 *
 */

serg@serg.mylan's avatar
serg@serg.mylan committed
2152
EXPORT void _db_longjmp_()
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2153
{
serg@serg.mylan's avatar
serg@serg.mylan committed
2154 2155 2156 2157 2158 2159 2160 2161
  CODE_STATE *cs=0;
  get_code_state_or_return;

  cs->level= cs->jmplevel;
  if (cs->jmpfunc)
    cs->func= cs->jmpfunc;
  if (cs->jmpfile)
    cs->file= cs->jmpfile;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2162 2163 2164 2165 2166 2167
}
#endif

/*
 *  FUNCTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
2168
 *      perror    perror simulation for systems that don't have it
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2169 2170 2171
 *
 *  SYNOPSIS
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
2172 2173
 *      static VOID perror(s)
 *      char *s;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2174 2175 2176
 *
 *  DESCRIPTION
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
2177 2178 2179 2180
 *      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.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2181
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
2182 2183 2184
 *      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.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2185
 *
serg@serg.mylan's avatar
serg@serg.mylan committed
2186
 *      This version just complains about an "unknown system error".
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2187 2188 2189 2190
 *
 */

#ifndef HAVE_PERROR
serg@serg.mylan's avatar
serg@serg.mylan committed
2191
static void perror(s)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2192 2193
char *s;
{
serg@serg.mylan's avatar
serg@serg.mylan committed
2194 2195 2196
  if (s && *s != '\0')
    (void) fprintf(stderr, "%s: ", s);
  (void) fprintf(stderr, "<unknown system error>\n");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2197 2198 2199 2200
}
#endif /* HAVE_PERROR */


serg@serg.mylan's avatar
serg@serg.mylan committed
2201 2202 2203
        /* 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 !! */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2204

serg@serg.mylan's avatar
serg@serg.mylan committed
2205
static void dbug_flush(CODE_STATE *cs)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2206 2207
{
#ifndef THREAD
serg@serg.mylan's avatar
serg@serg.mylan committed
2208
  if (cs->stack->flags & FLUSH_ON_WRITE)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2209 2210 2211
#endif
  {
#if defined(MSDOS) || defined(__WIN__)
serg@serg.mylan's avatar
serg@serg.mylan committed
2212
    if (cs->stack->out_file != stdout && cs->stack->out_file != stderr)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2213
    {
serg@serg.mylan's avatar
serg@serg.mylan committed
2214
      if (!(freopen(cs->stack->name,"a",cs->stack->out_file)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2215
      {
serg@serg.mylan's avatar
serg@serg.mylan committed
2216 2217 2218
        (void) fprintf(stderr, ERR_OPEN, cs->process, cs->stack->name);
        fflush(stderr);
        cs->stack->out_file= stderr;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2219 2220 2221 2222 2223
      }
    }
    else
#endif
    {
serg@serg.mylan's avatar
serg@serg.mylan committed
2224 2225 2226
      (void) fflush(cs->stack->out_file);
      if (cs->stack->delay)
        (void) Delay(cs->stack->delay);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2227 2228
    }
  }
serg@serg.mylan's avatar
serg@serg.mylan committed
2229
  if (!cs->locked)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2230 2231 2232 2233
    pthread_mutex_unlock(&THR_LOCK_dbug);
} /* dbug_flush */


serg@serg.mylan's avatar
serg@serg.mylan committed
2234
void _db_lock_file_()
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2235
{
serg@serg.mylan's avatar
serg@serg.mylan committed
2236 2237
  CODE_STATE *cs=0;
  get_code_state_or_return;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2238
  pthread_mutex_lock(&THR_LOCK_dbug);
serg@serg.mylan's avatar
serg@serg.mylan committed
2239
  cs->locked=1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2240 2241
}

serg@serg.mylan's avatar
serg@serg.mylan committed
2242
void _db_unlock_file_()
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2243
{
serg@serg.mylan's avatar
serg@serg.mylan committed
2244 2245 2246
  CODE_STATE *cs=0;
  get_code_state_or_return;
  cs->locked=0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2247 2248 2249 2250 2251 2252 2253 2254
  pthread_mutex_unlock(&THR_LOCK_dbug);
}

/*
 * Here we need the definitions of the clock routine.  Add your
 * own for whatever system that you have.
 */

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2255 2256
#ifndef THREAD
#if defined(HAVE_GETRUSAGE)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2257 2258 2259 2260

#include <sys/param.h>
#include <sys/resource.h>

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2261
/* extern int getrusage(int, struct rusage *); */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2262 2263 2264 2265 2266 2267

/*
 * Returns the user time in milliseconds used by this process so
 * far.
 */

serg@serg.mylan's avatar
serg@serg.mylan committed
2268
static unsigned long Clock()
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2269 2270 2271
{
    struct rusage ru;

serg@serg.mylan's avatar
serg@serg.mylan committed
2272 2273
    (void) getrusage(RUSAGE_SELF, &ru);
    return ru.ru_utime.tv_sec*1000 + ru.ru_utime.tv_usec/1000;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2274 2275
}

2276
#elif defined(MSDOS) || defined(__WIN__)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2277 2278 2279 2280 2281

static ulong Clock()
{
  return clock()*(1000/CLOCKS_PER_SEC);
}
serg@serg.mylan's avatar
serg@serg.mylan committed
2282
#elif defined(amiga)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2283

serg@serg.mylan's avatar
serg@serg.mylan committed
2284 2285 2286 2287
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;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2288 2289
};

serg@serg.mylan's avatar
serg@serg.mylan committed
2290
static int first_clock= TRUE;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2291 2292 2293
static struct DateStamp begin;
static struct DateStamp elapsed;

serg@serg.mylan's avatar
serg@serg.mylan committed
2294
static unsigned long Clock()
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2295 2296
{
    register struct DateStamp *now;
serg@serg.mylan's avatar
serg@serg.mylan committed
2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313
    register unsigned long millisec= 0;
    extern VOID *AllocMem();

    now= (struct DateStamp *) AllocMem((long) sizeof(struct DateStamp), 0L);
    if (now != NULL)
    {
        if (first_clock == TRUE)
        {
            first_clock= FALSE;
            (void) DateStamp(now);
            begin= *now;
        }
        (void) DateStamp(now);
        millisec= 24 * 3600 * (1000 / HZ) * (now->ds_Days - begin.ds_Days);
        millisec += 60 * (1000 / HZ) * (now->ds_Minute - begin.ds_Minute);
        millisec += (1000 / HZ) * (now->ds_Tick - begin.ds_Tick);
        (void) FreeMem(now, (long) sizeof(struct DateStamp));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2314
    }
serg@serg.mylan's avatar
serg@serg.mylan committed
2315
    return millisec;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2316 2317
}
#else
serg@serg.mylan's avatar
serg@serg.mylan committed
2318
static unsigned long Clock()
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2319
{
serg@serg.mylan's avatar
serg@serg.mylan committed
2320
    return 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2321 2322
}
#endif /* RUSAGE */
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2323
#endif /* THREADS */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2324 2325 2326 2327

#ifdef NO_VARARGS

/*
serg@serg.mylan's avatar
serg@serg.mylan committed
2328 2329
 *      Fake vfprintf for systems that don't support it.  If this
 *      doesn't work, you are probably SOL...
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2330 2331
 */

serg@serg.mylan's avatar
serg@serg.mylan committed
2332
static int vfprintf(stream, format, ap)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2333 2334 2335 2336 2337 2338 2339
FILE *stream;
char *format;
va_list ap;
{
    int rtnval;
    ARGS_DCL;

serg@serg.mylan's avatar
serg@serg.mylan committed
2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351
    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;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2352 2353
}

serg@serg.mylan's avatar
serg@serg.mylan committed
2354
#endif  /* NO_VARARGS */