dbug.c 61.8 KB
Newer Older
unknown's avatar
unknown committed
1
/******************************************************************************
unknown's avatar
unknown 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-     *
unknown's avatar
unknown committed
25 26
 *      chantability or fitness for any particular purpose.                   *
 *                                                                            *
unknown's avatar
unknown committed
27 28 29 30 31 32
 ******************************************************************************
 */

/*
 *  FILE
 *
unknown's avatar
unknown committed
33
 *      dbug.c   runtime support routines for dbug package
unknown's avatar
unknown committed
34 35 36
 *
 *  SCCS
 *
unknown's avatar
unknown committed
37
 *      @(#)dbug.c      1.25    7/25/89
unknown's avatar
unknown committed
38 39 40
 *
 *  DESCRIPTION
 *
unknown's avatar
unknown 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.
unknown's avatar
unknown committed
45
 *
unknown's avatar
unknown 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.
unknown's avatar
unknown committed
49 50 51
 *
 *  AUTHOR(S)
 *
unknown's avatar
unknown committed
52 53 54
 *      Fred Fish               (base code)
 *      Enhanced Software Technologies, Tempe, AZ
 *      asuvax!mcdphx!estinc!fnf
unknown's avatar
unknown committed
55
 *
unknown's avatar
unknown committed
56 57
 *      Binayak Banerjee        (profiling enhancements)
 *      seismo!bpa!sjuvax!bbanerje
unknown's avatar
unknown committed
58
 *
unknown's avatar
unknown 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
unknown's avatar
unknown 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_
unknown's avatar
unknown committed
70
 *      thread-local settings
unknown's avatar
unknown committed
71
 *
unknown's avatar
unknown committed
72 73
 */

74 75 76 77
/*
  We can't have SAFE_MUTEX defined here as this will cause recursion
  in pthread_mutex_lock
*/
78

79
#undef SAFE_MUTEX
80
#include <my_global.h>
unknown's avatar
unknown committed
81 82 83 84 85 86
#include <m_string.h>
#include <errno.h>
#if defined(MSDOS) || defined(__WIN__)
#include <process.h>
#endif

87 88 89
#ifndef DBUG_OFF


unknown's avatar
unknown committed
90
/*
unknown's avatar
unknown committed
91
 *            Manifest constants which may be "tuned" if desired.
unknown's avatar
unknown committed
92 93
 */

unknown's avatar
unknown committed
94 95 96
#define PRINTBUF              1024    /* Print buffer size */
#define INDENT                2       /* Indentation per trace level */
#define MAXDEPTH              200     /* Maximum trace depth default */
unknown's avatar
unknown committed
97 98

/*
unknown's avatar
unknown committed
99 100 101
 *      The following flags are used to determine which
 *      capabilities the user has enabled with the settings
 *      push macro.
unknown's avatar
unknown committed
102 103
 */

unknown's avatar
unknown committed
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
#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)
unknown's avatar
unknown committed
121 122

/*
unknown's avatar
unknown committed
123
 *      Typedefs to make things more obvious.
unknown's avatar
unknown committed
124 125
 */

126
#define BOOLEAN my_bool
unknown's avatar
unknown committed
127 128

/*
unknown's avatar
unknown committed
129
 *      Make it easy to change storage classes if necessary.
unknown's avatar
unknown committed
130 131
 */

unknown's avatar
unknown committed
132 133 134 135
#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 */
unknown's avatar
unknown committed
136 137 138 139 140 141 142 143 144 145 146 147 148 149

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

unknown's avatar
unknown committed
150 151 152 153
#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"
unknown's avatar
unknown committed
154

unknown's avatar
unknown committed
155
#ifdef M_I386           /* predefined by xenix 386 compiler */
unknown's avatar
unknown committed
156 157 158 159
#define AUTOS_REVERSE 1
#endif

/*
unknown's avatar
unknown committed
160
 *      Externally supplied functions.
unknown's avatar
unknown committed
161 162 163
 */

#ifndef HAVE_PERROR
unknown's avatar
unknown committed
164
static void perror();          /* Fake system/library error print routine */
unknown's avatar
unknown committed
165 166
#endif

unknown's avatar
unknown committed
167
IMPORT int _sanity(const char *file,uint line); /* safemalloc sanity checker */
unknown's avatar
unknown committed
168 169

/*
unknown's avatar
unknown committed
170 171 172
 *      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.
unknown's avatar
unknown committed
173 174 175 176
 */

struct link {
    struct link *next_link;   /* Pointer to the next link */
unknown's avatar
unknown committed
177
    char   str[1];        /* Pointer to link's contents */
unknown's avatar
unknown committed
178 179 180
};

/*
unknown's avatar
unknown committed
181 182 183 184 185 186 187
 *      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!
unknown's avatar
unknown committed
188 189
 */

unknown's avatar
unknown committed
190 191 192 193 194 195 196 197 198 199 200 201 202
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 */
unknown's avatar
unknown committed
203 204
};

unknown's avatar
unknown committed
205
#define is_shared(S, V) ((S)->next && (S)->next->V == (S)->V)
unknown's avatar
unknown committed
206 207

/*
unknown's avatar
unknown committed
208
 *      Local variables not seen by user.
unknown's avatar
unknown committed
209 210 211
 */


unknown's avatar
unknown committed
212 213
static BOOLEAN init_done= FALSE; /* Set to TRUE when initialization done */
static struct settings init_settings;
214
static const char *db_process= 0;/* Pointer to process name; argv[0] */
215
my_bool _dbug_on_= TRUE;	 /* FALSE if no debugging at all */
unknown's avatar
unknown committed
216

unknown's avatar
unknown committed
217 218 219 220 221 222 223 224 225 226 227
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() */
unknown's avatar
unknown committed
228 229

/*
unknown's avatar
unknown committed
230 231 232 233
 *      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.
unknown's avatar
unknown committed
234
 *
unknown's avatar
unknown committed
235 236
 *      These variables are currently used only by _db_pargs_() and
 *      _db_doprnt_().
unknown's avatar
unknown committed
237 238
 */

unknown's avatar
unknown committed
239 240 241
  uint u_line;                  /* User source code line number */
  int  locked;                  /* If locked with _db_lock_file_ */
  const char *u_keyword;        /* Keyword for current macro */
unknown's avatar
unknown committed
242 243
} CODE_STATE;

unknown's avatar
unknown committed
244 245 246 247
/*
  The test below is so we could call functions with DBUG_ENTER before
  my_thread_init().
*/
248 249
#define get_code_state_if_not_set_or_return if (!cs && !((cs=code_state()))) return
#define get_code_state_or_return if (!((cs=code_state()))) return
unknown's avatar
unknown committed
250 251 252 253 254 255 256 257 258 259 260 261

        /* 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);
262
	/* Free memory associated with debug state. */
263
static void FreeState (CODE_STATE *cs, struct settings *state, int free_state);
unknown's avatar
unknown committed
264 265 266 267
        /* Test for tracing enabled */
static BOOLEAN DoTrace(CODE_STATE *cs);

        /* Test to see if file is writable */
unknown's avatar
unknown committed
268
#if !(!defined(HAVE_ACCESS) || defined(MSDOS))
269
static BOOLEAN Writable(const char *pathname);
unknown's avatar
unknown committed
270 271 272
        /* Change file owner and group */
static void ChangeOwner(CODE_STATE *cs, char *pathname);
        /* Allocate memory for runtime support */
unknown's avatar
unknown committed
273
#endif
unknown's avatar
unknown committed
274 275 276

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

277
static char *DbugMalloc(size_t size);
unknown's avatar
unknown committed
278 279
static const char *BaseName(const char *pathname);
static void Indent(CODE_STATE *cs, int indent);
unknown's avatar
unknown committed
280 281 282
static BOOLEAN InList(struct link *linkp,const char *cp);
static void dbug_flush(CODE_STATE *);
static void DbugExit(const char *why);
unknown's avatar
unknown committed
283 284 285 286 287 288 289 290 291 292
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
unknown's avatar
unknown committed
293 294

/*
unknown's avatar
unknown committed
295
 *      Miscellaneous printf format strings.
unknown's avatar
unknown committed
296 297 298 299 300 301 302 303 304
 */

#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\": "

/*
unknown's avatar
unknown committed
305
 *      Macros and defines for testing file accessibility under UNIX and MSDOS.
unknown's avatar
unknown committed
306 307
 */

unknown's avatar
unknown committed
308
#undef EXISTS
unknown's avatar
unknown committed
309
#if !defined(HAVE_ACCESS) || defined(MSDOS)
unknown's avatar
unknown committed
310
#define EXISTS(pathname) (FALSE)        /* Assume no existance */
unknown's avatar
unknown committed
311 312
#define Writable(name) (TRUE)
#else
unknown's avatar
unknown committed
313 314
#define EXISTS(pathname)         (access(pathname, F_OK) == 0)
#define WRITABLE(pathname)       (access(pathname, W_OK) == 0)
unknown's avatar
unknown committed
315 316
#endif
#ifndef MSDOS
unknown's avatar
unknown committed
317
#define ChangeOwner(cs,name)
unknown's avatar
unknown committed
318 319
#endif

320

unknown's avatar
unknown committed
321 322 323 324 325 326
/*
** Macros to allow dbugging with threads
*/

#ifdef THREAD
#include <my_pthread.h>
327
static pthread_mutex_t THR_LOCK_dbug;
unknown's avatar
unknown committed
328 329 330

static CODE_STATE *code_state(void)
{
331
  CODE_STATE *cs, **cs_ptr;
unknown's avatar
unknown committed
332

333 334 335 336 337 338 339
  /*
    _dbug_on_ is reset if we don't plan to use any debug commands at all and
    we want to run on maximum speed
   */
  if (!_dbug_on_)
    return 0;

unknown's avatar
unknown committed
340 341
  if (!init_done)
  {
342
    init_done=TRUE;
unknown's avatar
unknown committed
343 344 345 346 347 348
    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;
  }

349 350 351
  if (!(cs_ptr= (CODE_STATE**) my_thread_var_dbug()))
    return 0;                                   /* Thread not initialised */
  if (!(cs= *cs_ptr))
unknown's avatar
unknown committed
352
  {
353 354 355 356 357 358
    cs=(CODE_STATE*) DbugMalloc(sizeof(*cs));
    bzero((uchar*) cs,sizeof(*cs));
    cs->process= db_process ? db_process : "dbug";
    cs->func="?func";
    cs->file="?file";
    cs->stack=&init_settings;
359
    *cs_ptr= cs;
unknown's avatar
unknown committed
360
  }
unknown's avatar
unknown committed
361
  return cs;
unknown's avatar
unknown committed
362 363 364 365
}

#else /* !THREAD */

unknown's avatar
unknown committed
366 367
static CODE_STATE static_code_state=
{
unknown's avatar
unknown committed
368 369
  "dbug", "?func", "?file", NULL, &init_settings,
  NullS, NullS, 0,0,0,0,0,NullS
unknown's avatar
unknown committed
370
};
unknown's avatar
unknown committed
371 372 373 374 375 376 377 378 379 380 381 382 383 384 385

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) {}
unknown's avatar
unknown committed
386 387
#endif

unknown's avatar
unknown committed
388 389 390 391 392 393 394 395 396 397
/*
 *      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
unknown's avatar
unknown committed
398 399 400 401

/*
 *  FUNCTION
 *
unknown's avatar
unknown committed
402
 *      _db_process_       give the name to the current process/thread
unknown's avatar
unknown committed
403 404 405
 *
 *  SYNOPSIS
 *
406
 *      VOID _process_(name)
unknown's avatar
unknown committed
407
 *      char *name;
unknown's avatar
unknown committed
408
 *
unknown's avatar
unknown committed
409 410 411 412
 */

void _db_process_(const char *name)
{
413
  CODE_STATE *cs;
unknown's avatar
unknown committed
414 415 416 417 418 419 420 421 422 423

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

/*
 *  FUNCTION
unknown's avatar
unknown committed
424
 *
unknown's avatar
unknown committed
425
 *      _db_set_       set current debugger settings
unknown's avatar
unknown committed
426
 *
unknown's avatar
unknown committed
427
 *  SYNOPSIS
unknown's avatar
unknown committed
428
 *
unknown's avatar
unknown committed
429 430
 *      VOID _db_set_(control)
 *      char *control;
unknown's avatar
unknown committed
431
 *
unknown's avatar
unknown committed
432
 *  DESCRIPTION
unknown's avatar
unknown committed
433
 *
unknown's avatar
unknown committed
434 435 436
 *      Given pointer to a debug control string in "control",
 *      parses the control string, and sets
 *      up a current debug settings.
unknown's avatar
unknown committed
437
 *
unknown's avatar
unknown committed
438 439
 *      The debug control string is a sequence of colon separated fields
 *      as follows:
unknown's avatar
unknown committed
440
 *
unknown's avatar
unknown committed
441
 *              [+]<field_1>:<field_2>:...:<field_N>
unknown's avatar
unknown committed
442
 *
unknown's avatar
unknown committed
443 444
 *      Each field consists of a mandatory flag character followed by
 *      an optional "," and comma separated list of modifiers:
unknown's avatar
unknown committed
445
 *
unknown's avatar
unknown committed
446
 *              [sign]flag[,modifier,modifier,...,modifier]
unknown's avatar
unknown committed
447
 *
unknown's avatar
unknown committed
448
 *      See the manual for the list of supported signs, flags, and modifiers
unknown's avatar
unknown committed
449
 *
unknown's avatar
unknown committed
450
 *      For convenience, any leading "-#" is stripped off.
unknown's avatar
unknown committed
451 452 453
 *
 */

unknown's avatar
unknown committed
454
void _db_set_(CODE_STATE *cs, const char *control)
unknown's avatar
unknown committed
455
{
unknown's avatar
unknown committed
456
  const char *end;
457
  int rel;
458
  struct settings *stack;
unknown's avatar
unknown committed
459

460
  get_code_state_if_not_set_or_return;
461
  stack= cs->stack;
unknown's avatar
unknown committed
462

unknown's avatar
unknown committed
463 464
  if (control[0] == '-' && control[1] == '#')
    control+=2;
unknown's avatar
unknown committed
465

unknown's avatar
unknown committed
466
  rel= control[0] == '+' || control[0] == '-';
467
  if ((!rel || (!stack->out_file && !stack->next)))
unknown's avatar
unknown committed
468
  {
469 470 471 472 473 474 475 476 477 478
    stack->flags= 0;
    stack->delay= 0;
    stack->maxdepth= 0;
    stack->sub_level= 0;
    stack->out_file= stderr;
    stack->prof_file= NULL;
    stack->functions= NULL;
    stack->p_functions= NULL;
    stack->keywords= NULL;
    stack->processes= NULL;
unknown's avatar
unknown committed
479
  }
480
  else if (!stack->out_file)
unknown's avatar
unknown committed
481
  {
482 483 484 485 486 487 488 489
    stack->flags= stack->next->flags;
    stack->delay= stack->next->delay;
    stack->maxdepth= stack->next->maxdepth;
    stack->sub_level= stack->next->sub_level;
    strcpy(stack->name, stack->next->name);
    stack->out_file= stack->next->out_file;
    stack->prof_file= stack->next->prof_file;
    if (stack->next == &init_settings)
unknown's avatar
unknown committed
490 491
    {
      /* never share with the global parent - it can change under your feet */
492 493 494 495
      stack->functions= ListCopy(init_settings.functions);
      stack->p_functions= ListCopy(init_settings.p_functions);
      stack->keywords= ListCopy(init_settings.keywords);
      stack->processes= ListCopy(init_settings.processes);
unknown's avatar
unknown committed
496 497 498
    }
    else
    {
499 500 501 502
      stack->functions= stack->next->functions;
      stack->p_functions= stack->next->p_functions;
      stack->keywords= stack->next->keywords;
      stack->processes= stack->next->processes;
unknown's avatar
unknown committed
503
    }
unknown's avatar
unknown committed
504 505
  }

unknown's avatar
unknown committed
506 507 508 509 510 511 512 513
  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++;
unknown's avatar
unknown committed
514
    /* XXX when adding new cases here, don't forget _db_explain_ ! */
unknown's avatar
unknown committed
515
    switch (c) {
unknown's avatar
unknown committed
516
    case 'd':
unknown's avatar
unknown committed
517 518
      if (sign < 0 && control == end)
      {
519 520 521 522
        if (!is_shared(stack, keywords))
          FreeList(stack->keywords);
        stack->keywords=NULL;
        stack->flags &= ~DEBUG_ON;
unknown's avatar
unknown committed
523
        break;
unknown's avatar
unknown committed
524
      }
525 526
      if (rel && is_shared(stack, keywords))
        stack->keywords= ListCopy(stack->keywords);
unknown's avatar
unknown committed
527 528 529
      if (sign < 0)
      {
        if (DEBUGGING)
530
          stack->keywords= ListDel(stack->keywords, control, end);
unknown's avatar
unknown committed
531 532
      break;
      }
533 534
      stack->keywords= ListAdd(stack->keywords, control, end);
      stack->flags |= DEBUG_ON;
unknown's avatar
unknown committed
535 536
      break;
    case 'D':
537
      stack->delay= atoi(control);
unknown's avatar
unknown committed
538 539
      break;
    case 'f':
unknown's avatar
unknown committed
540 541
      if (sign < 0 && control == end)
      {
542 543 544
        if (!is_shared(stack,functions))
          FreeList(stack->functions);
        stack->functions=NULL;
unknown's avatar
unknown committed
545
        break;
unknown's avatar
unknown committed
546
      }
547 548
      if (rel && is_shared(stack,functions))
        stack->functions= ListCopy(stack->functions);
unknown's avatar
unknown committed
549
      if (sign < 0)
550
        stack->functions= ListDel(stack->functions, control, end);
unknown's avatar
unknown committed
551
      else
552
        stack->functions= ListAdd(stack->functions, control, end);
unknown's avatar
unknown committed
553 554
      break;
    case 'F':
unknown's avatar
unknown committed
555
      if (sign < 0)
556
        stack->flags &= ~FILE_ON;
unknown's avatar
unknown committed
557
      else
558
        stack->flags |= FILE_ON;
unknown's avatar
unknown committed
559 560
      break;
    case 'i':
unknown's avatar
unknown committed
561
      if (sign < 0)
562
        stack->flags &= ~PID_ON;
unknown's avatar
unknown committed
563
      else
564
        stack->flags |= PID_ON;
unknown's avatar
unknown committed
565 566 567
      break;
#ifndef THREAD
    case 'g':
unknown's avatar
unknown committed
568
      if (OpenProfile(cs, PROF_FILE))
unknown's avatar
unknown committed
569
      {
570 571
        stack->flags |= PROFILE_ON;
        stack->p_functions= ListAdd(stack->p_functions, control, end);
unknown's avatar
unknown committed
572 573 574 575
      }
      break;
#endif
    case 'L':
unknown's avatar
unknown committed
576
      if (sign < 0)
577
        stack->flags &= ~LINE_ON;
unknown's avatar
unknown committed
578
      else
579
        stack->flags |= LINE_ON;
unknown's avatar
unknown committed
580 581
      break;
    case 'n':
unknown's avatar
unknown committed
582
      if (sign < 0)
583
        stack->flags &= ~DEPTH_ON;
unknown's avatar
unknown committed
584
      else
585
        stack->flags |= DEPTH_ON;
unknown's avatar
unknown committed
586 587
      break;
    case 'N':
unknown's avatar
unknown committed
588
      if (sign < 0)
589
        stack->flags &= ~NUMBER_ON;
unknown's avatar
unknown committed
590
      else
591
        stack->flags |= NUMBER_ON;
unknown's avatar
unknown committed
592 593 594
      break;
    case 'A':
    case 'O':
595
      stack->flags |= FLUSH_ON_WRITE;
unknown's avatar
unknown committed
596
      /* fall through */
unknown's avatar
unknown committed
597 598
    case 'a':
    case 'o':
unknown's avatar
unknown committed
599 600
      if (sign < 0)
      {
601 602 603 604
        if (!is_shared(stack, out_file))
          DBUGCloseFile(cs, stack->out_file);
        stack->flags &= ~FLUSH_ON_WRITE;
        stack->out_file= stderr;
unknown's avatar
unknown committed
605
        break;
unknown's avatar
unknown committed
606
      }
unknown's avatar
unknown committed
607
      if (c == 'a' || c == 'A')
608
        stack->flags |= OPEN_APPEND;
unknown's avatar
unknown committed
609
      else
610
        stack->flags &= ~OPEN_APPEND;
unknown's avatar
unknown committed
611
      if (control != end)
612
        DBUGOpenFile(cs, control, end, stack->flags & OPEN_APPEND);
unknown's avatar
unknown committed
613 614
      else
        DBUGOpenFile(cs, "-",0,0);
unknown's avatar
unknown committed
615 616
      break;
    case 'p':
unknown's avatar
unknown committed
617 618
      if (sign < 0 && control == end)
      {
619 620 621
        if (!is_shared(stack,processes))
          FreeList(stack->processes);
        stack->processes=NULL;
unknown's avatar
unknown committed
622
        break;
unknown's avatar
unknown committed
623
      }
624 625
      if (rel && is_shared(stack, processes))
        stack->processes= ListCopy(stack->processes);
unknown's avatar
unknown committed
626
      if (sign < 0)
627
        stack->processes= ListDel(stack->processes, control, end);
unknown's avatar
unknown committed
628
      else
629
        stack->processes= ListAdd(stack->processes, control, end);
unknown's avatar
unknown committed
630 631
      break;
    case 'P':
unknown's avatar
unknown committed
632
      if (sign < 0)
633
        stack->flags &= ~PROCESS_ON;
unknown's avatar
unknown committed
634
      else
635
        stack->flags |= PROCESS_ON;
unknown's avatar
unknown committed
636 637
      break;
    case 'r':
638
      stack->sub_level= cs->level;
unknown's avatar
unknown committed
639 640
      break;
    case 't':
unknown's avatar
unknown committed
641 642 643
      if (sign < 0)
      {
        if (control != end)
644
          stack->maxdepth-= atoi(control);
unknown's avatar
unknown committed
645
        else
646
          stack->maxdepth= 0;
unknown's avatar
unknown committed
647 648 649 650
      }
      else
      {
        if (control != end)
651
          stack->maxdepth+= atoi(control);
unknown's avatar
unknown committed
652
        else
653
          stack->maxdepth= MAXDEPTH;
unknown's avatar
unknown committed
654
      }
655 656
      if (stack->maxdepth > 0)
        stack->flags |= TRACE_ON;
unknown's avatar
unknown committed
657
      else
658
        stack->flags &= ~TRACE_ON;
unknown's avatar
unknown committed
659 660 661
      break;
    case 'T':
      if (sign < 0)
662
        stack->flags &= ~TIMESTAMP_ON;
unknown's avatar
unknown committed
663
      else
664
        stack->flags |= TIMESTAMP_ON;
unknown's avatar
unknown committed
665 666
      break;
    case 'S':
unknown's avatar
unknown committed
667
      if (sign < 0)
668
        stack->flags &= ~SANITY_CHECK_ON;
unknown's avatar
unknown committed
669
      else
670
        stack->flags |= SANITY_CHECK_ON;
unknown's avatar
unknown committed
671 672
      break;
    }
unknown's avatar
unknown committed
673 674 675 676
    if (!*end)
      break;
    control=end+1;
    end= DbugStrTok(control);
unknown's avatar
unknown committed
677 678 679
  }
}

680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700

/*
 *  FUNCTION
 *
 *      _db_push_       push current debugger settings and set up new one
 *
 *  SYNOPSIS
 *
 *      VOID _db_push_(control)
 *      char *control;
 *
 *  DESCRIPTION
 *
 *      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_()
 *
 */

void _db_push_(const char *control)
{
701
  CODE_STATE *cs;
702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723
  get_code_state_or_return;
  PushState(cs);
  _db_set_(cs, control);
}

/*
 *  FUNCTION
 *
 *      _db_set_init_       set initial debugger settings
 *
 *  SYNOPSIS
 *
 *      VOID _db_set_init_(control)
 *      char *control;
 *
 *  DESCRIPTION
 *      see _db_set_
 *
 */

void _db_set_init_(const char *control)
{
724
  CODE_STATE tmp_cs;
725
  bzero((uchar*) &tmp_cs, sizeof(tmp_cs));
726 727
  tmp_cs.stack= &init_settings;
  _db_set_(&tmp_cs, control);
728 729
}

unknown's avatar
unknown committed
730 731 732
/*
 *  FUNCTION
 *
unknown's avatar
unknown committed
733
 *      _db_pop_    pop the debug stack
unknown's avatar
unknown committed
734 735 736
 *
 *  DESCRIPTION
 *
unknown's avatar
unknown committed
737 738 739 740 741 742 743
 *      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.
unknown's avatar
unknown committed
744 745 746
 *
 */

unknown's avatar
unknown committed
747
void _db_pop_()
unknown's avatar
unknown committed
748
{
unknown's avatar
unknown committed
749
  struct settings *discard;
750
  CODE_STATE *cs;
unknown's avatar
unknown committed
751 752 753 754 755

  get_code_state_or_return;

  discard= cs->stack;
  if (discard->next != NULL)
unknown's avatar
unknown committed
756
  {
unknown's avatar
unknown committed
757
    cs->stack= discard->next;
758
    FreeState(cs, discard, 1);
unknown's avatar
unknown committed
759 760 761
  }
}

unknown's avatar
unknown committed
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
/*
 *  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)

840
int _db_explain_ (CODE_STATE *cs, char *buf, size_t len)
unknown's avatar
unknown committed
841 842 843
{
  char *start=buf, *end=buf+len-4;

844
  get_code_state_if_not_set_or_return *buf=0;
unknown's avatar
unknown committed
845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862

  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);
unknown's avatar
unknown committed
863
  op_bool_to_buf('T', cs->stack->flags & TIMESTAMP_ON);
unknown's avatar
unknown committed
864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886
  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
unknown's avatar
unknown committed
887 888 889 890

/*
 *  FUNCTION
 *
unknown's avatar
unknown committed
891 892 893 894 895 896
 *      _db_explain_init_       explain initial debugger settings
 *
 *  DESCRIPTION
 *      see _db_explain_
 */

897
int _db_explain_init_(char *buf, size_t len)
unknown's avatar
unknown committed
898 899
{
  CODE_STATE cs;
900
  bzero((uchar*) &cs,sizeof(cs));
unknown's avatar
unknown committed
901 902 903 904 905 906 907 908
  cs.stack=&init_settings;
  return _db_explain_(&cs, buf, len);
}

/*
 *  FUNCTION
 *
 *      _db_enter_    process entry point to user function
unknown's avatar
unknown committed
909 910 911
 *
 *  SYNOPSIS
 *
unknown's avatar
unknown committed
912 913 914 915 916 917 918 919 920
 *      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
unknown's avatar
unknown committed
921 922 923
 *
 *  DESCRIPTION
 *
unknown's avatar
unknown committed
924 925 926 927 928 929 930 931 932
 *      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.
unknown's avatar
unknown committed
933
 *
unknown's avatar
unknown committed
934 935
 *      Also prints a trace line if tracing is enabled and
 *      increments the current function nesting depth.
unknown's avatar
unknown committed
936
 *
unknown's avatar
unknown committed
937 938 939
 *      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.
unknown's avatar
unknown committed
940 941 942
 *
 */

unknown's avatar
unknown committed
943 944 945
void _db_enter_(const char *_func_, const char *_file_,
                uint _line_, const char **_sfunc_, const char **_sfile_,
                uint *_slevel_, char ***_sframep_ __attribute__((unused)))
unknown's avatar
unknown committed
946
{
947 948 949 950 951 952 953 954
  int save_errno;
  CODE_STATE *cs;
  if (!((cs=code_state())))
  {
    *_slevel_= 0; /* Set to avoid valgrind warnings if dbug is enabled later */
    return;
  }
  save_errno= errno;
unknown's avatar
unknown committed
955 956 957 958 959 960

  *_sfunc_= cs->func;
  *_sfile_= cs->file;
  cs->func=  _func_;
  cs->file=  _file_;
  *_slevel_=  ++cs->level;
unknown's avatar
unknown committed
961
#ifndef THREAD
unknown's avatar
unknown committed
962 963 964 965 966 967 968 969
  *_sframep_= cs->framep;
  cs->framep= (char **) _sframep_;
  if (DoProfile(cs))
  {
    long stackused;
    if (*cs->framep == NULL)
      stackused= 0;
    else
unknown's avatar
unknown committed
970
    {
unknown's avatar
unknown committed
971 972 973 974
      stackused= ((long)(*cs->framep)) - ((long)(cs->framep));
      stackused= stackused > 0 ? stackused : -stackused;
    }
    (void) fprintf(cs->stack->prof_file, PROF_EFMT , Clock(), cs->func);
unknown's avatar
unknown committed
975
#ifdef AUTOS_REVERSE
unknown's avatar
unknown committed
976
    (void) fprintf(cs->stack->prof_file, PROF_SFMT, cs->framep, stackused, *_sfunc_);
unknown's avatar
unknown committed
977
#else
unknown's avatar
unknown committed
978 979
    (void) fprintf(cs->stack->prof_file, PROF_SFMT, (ulong) cs->framep, stackused,
                    cs->func);
unknown's avatar
unknown committed
980
#endif
unknown's avatar
unknown committed
981 982
    (void) fflush(cs->stack->prof_file);
  }
unknown's avatar
unknown committed
983
#endif
unknown's avatar
unknown committed
984 985 986 987 988 989 990 991 992
  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 */
  }
unknown's avatar
unknown committed
993
#ifdef SAFEMALLOC
unknown's avatar
unknown committed
994 995 996
  if (cs->stack->flags & SANITY_CHECK_ON)
    if (_sanity(_file_,_line_))               /* Check of safemalloc */
      cs->stack->flags &= ~SANITY_CHECK_ON;
unknown's avatar
unknown committed
997
#endif
unknown's avatar
unknown committed
998
  errno=save_errno;
unknown's avatar
unknown committed
999 1000 1001 1002 1003
}

/*
 *  FUNCTION
 *
unknown's avatar
unknown committed
1004
 *      _db_return_    process exit from user function
unknown's avatar
unknown committed
1005 1006 1007
 *
 *  SYNOPSIS
 *
unknown's avatar
unknown committed
1008 1009 1010 1011 1012
 *      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
unknown's avatar
unknown committed
1013 1014 1015
 *
 *  DESCRIPTION
 *
unknown's avatar
unknown committed
1016 1017 1018 1019
 *      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.
unknown's avatar
unknown committed
1020 1021 1022
 *
 */

unknown's avatar
unknown committed
1023 1024 1025
/* helper macro */
void _db_return_(uint _line_, const char **_sfunc_,
                 const char **_sfile_, uint *_slevel_)
unknown's avatar
unknown committed
1026
{
unknown's avatar
unknown committed
1027
  int save_errno=errno;
1028
  CODE_STATE *cs;
unknown's avatar
unknown committed
1029
  get_code_state_or_return;
unknown's avatar
unknown committed
1030

unknown's avatar
unknown committed
1031 1032 1033 1034 1035 1036 1037 1038 1039
  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
unknown's avatar
unknown committed
1040 1041
  {
#ifdef SAFEMALLOC
unknown's avatar
unknown committed
1042 1043 1044 1045 1046
    if (cs->stack->flags & SANITY_CHECK_ON)
    {
      if (_sanity(*_sfile_,_line_))
        cs->stack->flags &= ~SANITY_CHECK_ON;
    }
unknown's avatar
unknown committed
1047 1048
#endif
#ifndef THREAD
unknown's avatar
unknown committed
1049 1050
    if (DoProfile(cs))
      (void) fprintf(cs->stack->prof_file, PROF_XFMT, Clock(), cs->func);
unknown's avatar
unknown committed
1051
#endif
unknown's avatar
unknown committed
1052 1053 1054 1055 1056 1057 1058 1059
    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);
unknown's avatar
unknown committed
1060
    }
unknown's avatar
unknown committed
1061
  }
1062 1063 1064 1065 1066
  /*
    Check to not set level < 0. This can happen if DBUG was disabled when
    function was entered and enabled in function.
  */
  cs->level= *_slevel_ != 0 ? *_slevel_-1 : 0;
unknown's avatar
unknown committed
1067 1068
  cs->func= *_sfunc_;
  cs->file= *_sfile_;
unknown's avatar
unknown committed
1069
#ifndef THREAD
unknown's avatar
unknown committed
1070 1071
  if (cs->framep != NULL)
    cs->framep= (char **) *cs->framep;
unknown's avatar
unknown committed
1072
#endif
unknown's avatar
unknown committed
1073
  errno=save_errno;
unknown's avatar
unknown committed
1074 1075 1076 1077 1078 1079
}


/*
 *  FUNCTION
 *
unknown's avatar
unknown committed
1080
 *      _db_pargs_    log arguments for subsequent use by _db_doprnt_()
unknown's avatar
unknown committed
1081 1082 1083
 *
 *  SYNOPSIS
 *
unknown's avatar
unknown committed
1084 1085 1086
 *      VOID _db_pargs_(_line_, keyword)
 *      int _line_;
 *      char *keyword;
unknown's avatar
unknown committed
1087 1088 1089
 *
 *  DESCRIPTION
 *
unknown's avatar
unknown committed
1090 1091 1092 1093
 *      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_().
unknown's avatar
unknown committed
1094 1095 1096
 *
 */

unknown's avatar
unknown committed
1097
void _db_pargs_(uint _line_, const char *keyword)
unknown's avatar
unknown committed
1098
{
1099
  CODE_STATE *cs;
unknown's avatar
unknown committed
1100 1101
  get_code_state_or_return;
  cs->u_line= _line_;
1102
  cs->u_keyword= keyword;
unknown's avatar
unknown committed
1103 1104 1105 1106 1107 1108
}


/*
 *  FUNCTION
 *
unknown's avatar
unknown committed
1109
 *      _db_doprnt_    handle print of debug lines
unknown's avatar
unknown committed
1110 1111 1112
 *
 *  SYNOPSIS
 *
unknown's avatar
unknown committed
1113 1114 1115
 *      VOID _db_doprnt_(format, va_alist)
 *      char *format;
 *      va_dcl;
unknown's avatar
unknown committed
1116 1117 1118
 *
 *  DESCRIPTION
 *
unknown's avatar
unknown committed
1119 1120 1121 1122 1123
 *      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.
unknown's avatar
unknown committed
1124
 *
unknown's avatar
unknown committed
1125 1126
 *      Note that the format string SHOULD NOT include a terminating
 *      newline, this is supplied automatically.
unknown's avatar
unknown committed
1127 1128 1129 1130 1131
 *
 */

#include <stdarg.h>

unknown's avatar
unknown committed
1132
void _db_doprnt_(const char *format,...)
unknown's avatar
unknown committed
1133 1134
{
  va_list args;
1135
  CODE_STATE *cs;
unknown's avatar
unknown committed
1136
  get_code_state_or_return;
unknown's avatar
unknown committed
1137 1138 1139

  va_start(args,format);

unknown's avatar
unknown committed
1140 1141
  if (_db_keyword_(cs, cs->u_keyword))
  {
unknown's avatar
unknown committed
1142
    int save_errno=errno;
unknown's avatar
unknown committed
1143
    if (!cs->locked)
unknown's avatar
unknown committed
1144
      pthread_mutex_lock(&THR_LOCK_dbug);
unknown's avatar
unknown committed
1145 1146 1147 1148 1149 1150 1151 1152 1153
    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);
unknown's avatar
unknown committed
1154 1155 1156 1157 1158 1159 1160 1161 1162
    errno=save_errno;
  }
  va_end(args);
}


/*
 *  FUNCTION
 *
1163
 *            _db_dump_    dump a string in hex
unknown's avatar
unknown committed
1164 1165 1166
 *
 *  SYNOPSIS
 *
unknown's avatar
unknown committed
1167 1168 1169 1170 1171
 *            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
unknown's avatar
unknown committed
1172 1173 1174 1175 1176 1177
 *
 *  DESCRIPTION
 *  Dump N characters in a binary array.
 *  Is used to examine corrputed memory or arrays.
 */

1178 1179
void _db_dump_(uint _line_, const char *keyword,
               const unsigned char *memory, size_t length)
unknown's avatar
unknown committed
1180 1181 1182
{
  int pos;
  char dbuff[90];
1183
  CODE_STATE *cs;
unknown's avatar
unknown committed
1184 1185
  get_code_state_or_return;

1186
  if (_db_keyword_(cs, keyword))
unknown's avatar
unknown committed
1187
  {
unknown's avatar
unknown committed
1188
    if (!cs->locked)
unknown's avatar
unknown committed
1189
      pthread_mutex_lock(&THR_LOCK_dbug);
unknown's avatar
unknown committed
1190
    DoPrefix(cs, _line_);
unknown's avatar
unknown committed
1191 1192
    if (TRACING)
    {
unknown's avatar
unknown committed
1193 1194
      Indent(cs, cs->level + 1);
      pos= min(max(cs->level-cs->stack->sub_level,0)*INDENT,80);
unknown's avatar
unknown committed
1195 1196 1197
    }
    else
    {
unknown's avatar
unknown committed
1198
      fprintf(cs->stack->out_file, "%s: ", cs->func);
unknown's avatar
unknown committed
1199
    }
1200
    sprintf(dbuff,"%s: Memory: 0x%lx  Bytes: (%ld)\n",
1201
            keyword, (ulong) memory, (long) length);
unknown's avatar
unknown committed
1202
    (void) fputs(dbuff,cs->stack->out_file);
unknown's avatar
unknown committed
1203 1204 1205 1206 1207 1208 1209

    pos=0;
    while (length-- > 0)
    {
      uint tmp= *((unsigned char*) memory++);
      if ((pos+=3) >= 80)
      {
unknown's avatar
unknown committed
1210 1211
        fputc('\n',cs->stack->out_file);
        pos=3;
unknown's avatar
unknown committed
1212
      }
unknown's avatar
unknown committed
1213 1214 1215
      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);
unknown's avatar
unknown committed
1216
    }
unknown's avatar
unknown committed
1217 1218
    (void) fputc('\n',cs->stack->out_file);
    dbug_flush(cs);
unknown's avatar
unknown committed
1219 1220 1221
  }
}

unknown's avatar
unknown committed
1222 1223

/*
unknown's avatar
unknown committed
1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245
 *  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.
 *
 */
unknown's avatar
unknown committed
1246

unknown's avatar
unknown committed
1247 1248 1249 1250 1251 1252
static struct link *ListAdd(struct link *head,
                             const char *ctlp, const char *end)
{
  const char *start;
  struct link *new_malloc;
  int len;
unknown's avatar
unknown committed
1253

unknown's avatar
unknown committed
1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268
  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;
}
unknown's avatar
unknown committed
1269

unknown's avatar
unknown committed
1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291
/*
 *  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)
unknown's avatar
unknown committed
1292
{
unknown's avatar
unknown committed
1293 1294 1295
  const char *start;
  struct link **cur;
  int len;
unknown's avatar
unknown committed
1296

unknown's avatar
unknown committed
1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309
  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;
1310
        free((void*) delme);
unknown's avatar
unknown committed
1311 1312 1313 1314 1315
      }
    } while (*cur && *(cur=&((*cur)->next_link)));
  }
  return head;
}
unknown's avatar
unknown committed
1316

unknown's avatar
unknown committed
1317 1318 1319
/*
 *  FUNCTION
 *
unknown's avatar
unknown committed
1320
 *      ListCopy    make a copy of the list
unknown's avatar
unknown committed
1321 1322 1323
 *
 *  SYNOPSIS
 *
unknown's avatar
unknown committed
1324 1325
 *      static struct link *ListCopy(orig)
 *      struct link *orig;
unknown's avatar
unknown committed
1326 1327 1328
 *
 *  DESCRIPTION
 *
unknown's avatar
unknown committed
1329 1330
 *      Given pointer to list, which contains a copy of every element from
 *      the original list.
unknown's avatar
unknown committed
1331
 *
unknown's avatar
unknown committed
1332 1333 1334 1335 1336
 *      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.
unknown's avatar
unknown committed
1337 1338 1339
 *
 */

unknown's avatar
unknown committed
1340
static struct link *ListCopy(struct link *orig)
unknown's avatar
unknown committed
1341
{
unknown's avatar
unknown committed
1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355
  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;
unknown's avatar
unknown committed
1356
  }
unknown's avatar
unknown committed
1357
  return head;
unknown's avatar
unknown committed
1358 1359 1360 1361 1362
}

/*
 *  FUNCTION
 *
unknown's avatar
unknown committed
1363
 *      InList    test a given string for member of a given list
unknown's avatar
unknown committed
1364 1365 1366
 *
 *  SYNOPSIS
 *
unknown's avatar
unknown committed
1367 1368 1369
 *      static BOOLEAN InList(linkp, cp)
 *      struct link *linkp;
 *      char *cp;
unknown's avatar
unknown committed
1370 1371 1372
 *
 *  DESCRIPTION
 *
unknown's avatar
unknown committed
1373 1374 1375 1376 1377 1378 1379 1380
 *      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.
unknown's avatar
unknown committed
1381 1382 1383
 *
 */

unknown's avatar
unknown committed
1384
static BOOLEAN InList(struct link *linkp, const char *cp)
unknown's avatar
unknown committed
1385 1386 1387 1388
{
  REGISTER struct link *scan;
  REGISTER BOOLEAN result;

unknown's avatar
unknown committed
1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399
  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;
unknown's avatar
unknown committed
1400 1401 1402
      }
    }
  }
unknown's avatar
unknown committed
1403
  return result;
unknown's avatar
unknown committed
1404 1405 1406 1407 1408 1409
}


/*
 *  FUNCTION
 *
unknown's avatar
unknown committed
1410
 *      PushState    push current settings onto stack and set up new one
unknown's avatar
unknown committed
1411 1412 1413
 *
 *  SYNOPSIS
 *
unknown's avatar
unknown committed
1414
 *      static VOID PushState()
unknown's avatar
unknown committed
1415 1416 1417
 *
 *  DESCRIPTION
 *
unknown's avatar
unknown committed
1418 1419
 *      Pushes the current settings on the settings stack, and creates
 *      a new settings. The new settings is NOT initialized
unknown's avatar
unknown committed
1420
 *
unknown's avatar
unknown committed
1421 1422 1423
 *      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.
unknown's avatar
unknown committed
1424 1425 1426
 *
 */

unknown's avatar
unknown committed
1427
static void PushState(CODE_STATE *cs)
unknown's avatar
unknown committed
1428
{
unknown's avatar
unknown committed
1429
  struct settings *new_malloc;
unknown's avatar
unknown committed
1430

unknown's avatar
unknown committed
1431 1432 1433 1434
  new_malloc= (struct settings *) DbugMalloc(sizeof(struct settings));
  new_malloc->next= cs->stack;
  new_malloc->out_file= NULL;
  cs->stack= new_malloc;
unknown's avatar
unknown committed
1435 1436
}

1437 1438 1439 1440 1441 1442 1443 1444 1445
/*
 *  FUNCTION
 *
 *	FreeState    Free memory associated with a struct state.
 *
 *  SYNOPSIS
 *
 *	static void FreeState (state)
 *	struct state *state;
1446
 *      int free_state;
1447 1448 1449 1450
 *
 *  DESCRIPTION
 *
 *	Deallocates the memory allocated for various information in a
1451
 *	state. If free_state is set, also free 'state'
1452 1453
 *
 */
1454
static void FreeState(CODE_STATE *cs, struct settings *state, int free_state)
1455
{
1456 1457 1458 1459 1460 1461 1462 1463 1464 1465
  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);
1466
  (void) fflush(cs->stack->out_file);
1467 1468
  if (state->prof_file)
    DBUGCloseFile(cs, state->prof_file);
1469
  if (free_state)
1470
    free((void*) state);
1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490
}


/*
 *  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.
 *
 */
1491
void _db_end_()
1492
{
unknown's avatar
unknown committed
1493
  struct settings *discard;
1494
  static struct settings tmp;
1495 1496 1497 1498 1499 1500
  CODE_STATE *cs;
  /*
    Set _dbug_on_ to be able to do full reset even when DEBUGGER_OFF was
    called after dbug was initialized
  */
  _dbug_on_= 1;
unknown's avatar
unknown committed
1501 1502
  get_code_state_or_return;

1503 1504 1505
  while ((discard= cs->stack))
  {
    if (discard == &init_settings)
unknown's avatar
unknown committed
1506 1507
      break;
    cs->stack= discard->next;
1508
    FreeState(cs, discard, 1);
1509
  }
1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525
  tmp= init_settings;

  /* Use mutex lock to make it less likely anyone access out_file */
  pthread_mutex_lock(&THR_LOCK_dbug);
  init_settings.flags=    OPEN_APPEND;
  init_settings.out_file= stderr;
  init_settings.prof_file= stderr;
  init_settings.maxdepth= 0;
  init_settings.delay= 0;
  init_settings.sub_level= 0;
  init_settings.functions= 0;
  init_settings.p_functions= 0;
  init_settings.keywords= 0;
  init_settings.processes= 0;
  pthread_mutex_unlock(&THR_LOCK_dbug);
  FreeState(cs, &tmp, 0);
1526 1527
}

unknown's avatar
unknown committed
1528 1529 1530 1531

/*
 *  FUNCTION
 *
unknown's avatar
unknown committed
1532
 *      DoTrace    check to see if tracing is current enabled
unknown's avatar
unknown committed
1533 1534 1535
 *
 *  SYNOPSIS
 *
unknown's avatar
unknown committed
1536
 *      static BOOLEAN DoTrace(stack)
unknown's avatar
unknown committed
1537 1538 1539
 *
 *  DESCRIPTION
 *
unknown's avatar
unknown committed
1540 1541 1542 1543 1544
 *      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.
unknown's avatar
unknown committed
1545 1546 1547
 *
 */

unknown's avatar
unknown committed
1548
static BOOLEAN DoTrace(CODE_STATE *cs)
unknown's avatar
unknown committed
1549
{
unknown's avatar
unknown committed
1550 1551 1552
  return (TRACING && cs->level <= cs->stack->maxdepth &&
          InList(cs->stack->functions, cs->func) &&
          InList(cs->stack->processes, cs->process));
unknown's avatar
unknown committed
1553 1554 1555 1556 1557 1558
}


/*
 *  FUNCTION
 *
unknown's avatar
unknown committed
1559
 *      DoProfile    check to see if profiling is current enabled
unknown's avatar
unknown committed
1560 1561 1562
 *
 *  SYNOPSIS
 *
unknown's avatar
unknown committed
1563
 *      static BOOLEAN DoProfile()
unknown's avatar
unknown committed
1564 1565 1566
 *
 *  DESCRIPTION
 *
unknown's avatar
unknown committed
1567 1568 1569 1570 1571
 *      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.
unknown's avatar
unknown committed
1572 1573 1574 1575
 *
 */

#ifndef THREAD
unknown's avatar
unknown committed
1576
static BOOLEAN DoProfile(CODE_STATE *cs)
unknown's avatar
unknown committed
1577
{
unknown's avatar
unknown committed
1578 1579 1580 1581
  return PROFILING &&
         cs->level <= cs->stack->maxdepth &&
         InList(cs->stack->p_functions, cs->func) &&
         InList(cs->stack->processes, cs->process);
unknown's avatar
unknown committed
1582 1583 1584
}
#endif

unknown's avatar
unknown committed
1585 1586
FILE *_db_fp_(void)
{
1587
  CODE_STATE *cs;
unknown's avatar
unknown committed
1588 1589 1590 1591 1592
  get_code_state_or_return NULL;
  return cs->stack->out_file;
}


1593 1594 1595 1596 1597 1598 1599
/*
 *  FUNCTION
 *
 *      _db_strict_keyword_     test keyword for member of keyword list
 *
 *  SYNOPSIS
 *
unknown's avatar
unknown committed
1600
 *      BOOLEAN _db_strict_keyword_(keyword)
1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612
 *      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.
 *
 */

unknown's avatar
unknown committed
1613
BOOLEAN _db_strict_keyword_(const char *keyword)
1614
{
1615
  CODE_STATE *cs;
unknown's avatar
unknown committed
1616 1617
  get_code_state_or_return FALSE;
  if (!DEBUGGING || cs->stack->keywords == NULL)
1618
    return FALSE;
unknown's avatar
unknown committed
1619
  return _db_keyword_(cs, keyword);
1620
}
unknown's avatar
unknown committed
1621 1622 1623 1624

/*
 *  FUNCTION
 *
unknown's avatar
unknown committed
1625
 *      _db_keyword_    test keyword for member of keyword list
unknown's avatar
unknown committed
1626 1627 1628
 *
 *  SYNOPSIS
 *
unknown's avatar
unknown committed
1629 1630
 *      BOOLEAN _db_keyword_(keyword)
 *      char *keyword;
unknown's avatar
unknown committed
1631 1632 1633
 *
 *  DESCRIPTION
 *
unknown's avatar
unknown committed
1634 1635 1636 1637 1638 1639 1640 1641
 *      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.
unknown's avatar
unknown committed
1642
 *
unknown's avatar
unknown committed
1643
 *      Returns TRUE if keyword accepted, FALSE otherwise.
unknown's avatar
unknown committed
1644 1645 1646
 *
 */

unknown's avatar
unknown committed
1647
BOOLEAN _db_keyword_(CODE_STATE *cs, const char *keyword)
unknown's avatar
unknown committed
1648
{
1649
  get_code_state_if_not_set_or_return FALSE;
unknown's avatar
unknown committed
1650

unknown's avatar
unknown committed
1651 1652 1653 1654 1655
  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));
unknown's avatar
unknown committed
1656 1657 1658 1659 1660
}

/*
 *  FUNCTION
 *
unknown's avatar
unknown committed
1661
 *      Indent    indent a line to the given indentation level
unknown's avatar
unknown committed
1662 1663 1664
 *
 *  SYNOPSIS
 *
unknown's avatar
unknown committed
1665 1666
 *      static VOID Indent(indent)
 *      int indent;
unknown's avatar
unknown committed
1667 1668 1669
 *
 *  DESCRIPTION
 *
unknown's avatar
unknown committed
1670 1671 1672
 *      Indent a line to the given level.  Note that this is
 *      a simple minded but portable implementation.
 *      There are better ways.
unknown's avatar
unknown committed
1673
 *
unknown's avatar
unknown committed
1674 1675
 *      Also, the indent must be scaled by the compile time option
 *      of character positions per nesting level.
unknown's avatar
unknown committed
1676 1677 1678
 *
 */

unknown's avatar
unknown committed
1679
static void Indent(CODE_STATE *cs, int indent)
unknown's avatar
unknown committed
1680 1681 1682
{
  REGISTER int count;

unknown's avatar
unknown committed
1683 1684
  indent= max(indent-1-cs->stack->sub_level,0)*INDENT;
  for (count= 0; count < indent ; count++)
unknown's avatar
unknown committed
1685 1686
  {
    if ((count % INDENT) == 0)
unknown's avatar
unknown committed
1687
      fputc('|',cs->stack->out_file);
unknown's avatar
unknown committed
1688
    else
unknown's avatar
unknown committed
1689
      fputc(' ',cs->stack->out_file);
unknown's avatar
unknown committed
1690 1691 1692 1693 1694 1695 1696
  }
}


/*
 *  FUNCTION
 *
unknown's avatar
unknown committed
1697
 *      FreeList    free all memory associated with a linked list
unknown's avatar
unknown committed
1698 1699 1700
 *
 *  SYNOPSIS
 *
unknown's avatar
unknown committed
1701 1702
 *      static VOID FreeList(linkp)
 *      struct link *linkp;
unknown's avatar
unknown committed
1703 1704 1705
 *
 *  DESCRIPTION
 *
unknown's avatar
unknown committed
1706 1707
 *      Given pointer to the head of a linked list, frees all
 *      memory held by the list and the members of the list.
unknown's avatar
unknown committed
1708 1709 1710
 *
 */

unknown's avatar
unknown committed
1711
static void FreeList(struct link *linkp)
unknown's avatar
unknown committed
1712 1713 1714
{
  REGISTER struct link *old;

unknown's avatar
unknown committed
1715 1716 1717 1718
  while (linkp != NULL)
  {
    old= linkp;
    linkp= linkp->next_link;
1719
    free((void*) old);
unknown's avatar
unknown committed
1720 1721 1722 1723 1724 1725 1726
  }
}


/*
 *  FUNCTION
 *
unknown's avatar
unknown committed
1727
 *      DoPrefix    print debugger line prefix prior to indentation
unknown's avatar
unknown committed
1728 1729 1730
 *
 *  SYNOPSIS
 *
unknown's avatar
unknown committed
1731 1732
 *      static VOID DoPrefix(_line_)
 *      int _line_;
unknown's avatar
unknown committed
1733 1734 1735
 *
 *  DESCRIPTION
 *
unknown's avatar
unknown committed
1736 1737 1738 1739
 *      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.
unknown's avatar
unknown committed
1740 1741 1742
 *
 */

unknown's avatar
unknown committed
1743
static void DoPrefix(CODE_STATE *cs, uint _line_)
unknown's avatar
unknown committed
1744
{
unknown's avatar
unknown committed
1745 1746 1747
  cs->lineno++;
  if (cs->stack->flags & PID_ON)
  {
unknown's avatar
unknown committed
1748
#ifdef THREAD
unknown's avatar
unknown committed
1749
    (void) fprintf(cs->stack->out_file, "%-7s: ", my_thread_name());
unknown's avatar
unknown committed
1750
#else
unknown's avatar
unknown committed
1751
    (void) fprintf(cs->stack->out_file, "%5d: ", (int) getpid());
unknown's avatar
unknown committed
1752 1753
#endif
  }
unknown's avatar
unknown committed
1754 1755 1756 1757
  if (cs->stack->flags & NUMBER_ON)
    (void) fprintf(cs->stack->out_file, "%5d: ", cs->lineno);
  if (cs->stack->flags & TIMESTAMP_ON)
  {
unknown's avatar
unknown committed
1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768
#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
unknown's avatar
unknown committed
1769 1770 1771 1772
    struct timeval tv;
    struct tm *tm_p;
    if (gettimeofday(&tv, NULL) != -1)
    {
unknown's avatar
unknown committed
1773
      if ((tm_p= localtime((const time_t *)&tv.tv_sec)))
unknown's avatar
unknown committed
1774 1775 1776 1777 1778 1779 1780 1781 1782
      {
        (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));
      }
    }
unknown's avatar
unknown committed
1783
#endif
unknown's avatar
unknown committed
1784
  }
unknown's avatar
unknown committed
1785 1786 1787 1788 1789 1790 1791 1792
  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);
unknown's avatar
unknown committed
1793 1794 1795 1796 1797 1798
}


/*
 *  FUNCTION
 *
unknown's avatar
unknown committed
1799
 *      DBUGOpenFile    open new output stream for debugger output
unknown's avatar
unknown committed
1800 1801 1802
 *
 *  SYNOPSIS
 *
unknown's avatar
unknown committed
1803 1804
 *      static VOID DBUGOpenFile(name)
 *      char *name;
unknown's avatar
unknown committed
1805 1806 1807
 *
 *  DESCRIPTION
 *
unknown's avatar
unknown committed
1808 1809
 *      Given name of a new file (or "-" for stdout) opens the file
 *      and sets the output stream to the new file.
unknown's avatar
unknown committed
1810 1811 1812
 *
 */

unknown's avatar
unknown committed
1813 1814
static void DBUGOpenFile(CODE_STATE *cs,
                         const char *name,const char *end,int append)
unknown's avatar
unknown committed
1815 1816 1817 1818 1819 1820
{
  REGISTER FILE *fp;
  REGISTER BOOLEAN newfile;

  if (name != NULL)
  {
unknown's avatar
unknown committed
1821 1822 1823 1824 1825 1826 1827 1828 1829 1830
    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)
unknown's avatar
unknown committed
1831
    {
unknown's avatar
unknown committed
1832 1833 1834
      cs->stack->out_file= stdout;
      cs->stack->flags |= FLUSH_ON_WRITE;
      cs->stack->name[0]=0;
unknown's avatar
unknown committed
1835 1836 1837
    }
    else
    {
1838
      if (!Writable(name))
unknown's avatar
unknown committed
1839
      {
unknown's avatar
unknown committed
1840 1841 1842
        (void) fprintf(stderr, ERR_OPEN, cs->process, name);
        perror("");
        fflush(stderr);
unknown's avatar
unknown committed
1843 1844 1845
      }
      else
      {
unknown's avatar
unknown committed
1846
        newfile= !EXISTS(name);
1847 1848 1849 1850 1851 1852 1853
        if (!(fp= fopen(name,
#if defined(MSDOS) || defined(__WIN__)
		append ? "a+c" : "wc"
#else
                append ? "a+" : "w"
#endif
		)))
unknown's avatar
unknown committed
1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866
        {
          (void) fprintf(stderr, ERR_OPEN, cs->process, name);
          perror("");
          fflush(stderr);
        }
        else
        {
          cs->stack->out_file= fp;
          if (newfile)
          {
            ChangeOwner(cs, name);
          }
        }
unknown's avatar
unknown committed
1867 1868 1869 1870 1871 1872 1873 1874 1875
      }
    }
  }
}


/*
 *  FUNCTION
 *
unknown's avatar
unknown committed
1876
 *      OpenProfile    open new output stream for profiler output
unknown's avatar
unknown committed
1877 1878 1879
 *
 *  SYNOPSIS
 *
unknown's avatar
unknown committed
1880 1881
 *      static FILE *OpenProfile(name)
 *      char *name;
unknown's avatar
unknown committed
1882 1883 1884
 *
 *  DESCRIPTION
 *
unknown's avatar
unknown committed
1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896
 *      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].
unknown's avatar
unknown committed
1897 1898 1899
 */

#ifndef THREAD
unknown's avatar
unknown committed
1900
static FILE *OpenProfile(CODE_STATE *cs, const char *name)
unknown's avatar
unknown committed
1901 1902 1903 1904 1905
{
  REGISTER FILE *fp;
  REGISTER BOOLEAN newfile;

  fp=0;
unknown's avatar
unknown committed
1906
  if (!Writable(name))
unknown's avatar
unknown committed
1907
  {
unknown's avatar
unknown committed
1908 1909 1910
    (void) fprintf(cs->stack->out_file, ERR_OPEN, cs->process, name);
    perror("");
    (void) Delay(cs->stack->delay);
unknown's avatar
unknown committed
1911 1912 1913
  }
  else
  {
unknown's avatar
unknown committed
1914 1915
    newfile= !EXISTS(name);
    if (!(fp= fopen(name, "w")))
unknown's avatar
unknown committed
1916
    {
unknown's avatar
unknown committed
1917 1918
      (void) fprintf(cs->stack->out_file, ERR_OPEN, cs->process, name);
      perror("");
unknown's avatar
unknown committed
1919 1920 1921
    }
    else
    {
unknown's avatar
unknown committed
1922
      cs->stack->prof_file= fp;
unknown's avatar
unknown committed
1923 1924
      if (newfile)
      {
unknown's avatar
unknown committed
1925
        ChangeOwner(cs, name);
unknown's avatar
unknown committed
1926 1927 1928 1929 1930 1931 1932 1933 1934 1935
      }
    }
  }
  return fp;
}
#endif

/*
 *  FUNCTION
 *
unknown's avatar
unknown committed
1936
 *      DBUGCloseFile    close the debug output stream
unknown's avatar
unknown committed
1937 1938 1939
 *
 *  SYNOPSIS
 *
unknown's avatar
unknown committed
1940 1941
 *      static VOID DBUGCloseFile(fp)
 *      FILE *fp;
unknown's avatar
unknown committed
1942 1943 1944
 *
 *  DESCRIPTION
 *
unknown's avatar
unknown committed
1945 1946
 *      Closes the debug output stream unless it is standard output
 *      or standard error.
unknown's avatar
unknown committed
1947 1948 1949
 *
 */

unknown's avatar
unknown committed
1950
static void DBUGCloseFile(CODE_STATE *cs, FILE *fp)
unknown's avatar
unknown committed
1951
{
unknown's avatar
unknown committed
1952 1953 1954 1955 1956
  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("");
1957
    dbug_flush(cs);
unknown's avatar
unknown committed
1958 1959 1960 1961 1962 1963 1964
  }
}


/*
 *  FUNCTION
 *
unknown's avatar
unknown committed
1965
 *      DbugExit    print error message and exit
unknown's avatar
unknown committed
1966 1967 1968
 *
 *  SYNOPSIS
 *
unknown's avatar
unknown committed
1969 1970
 *      static VOID DbugExit(why)
 *      char *why;
unknown's avatar
unknown committed
1971 1972 1973
 *
 *  DESCRIPTION
 *
unknown's avatar
unknown committed
1974 1975 1976 1977
 *      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.
unknown's avatar
unknown committed
1978 1979 1980
 *
 */

unknown's avatar
unknown committed
1981
static void DbugExit(const char *why)
unknown's avatar
unknown committed
1982
{
unknown's avatar
unknown committed
1983 1984 1985 1986
  CODE_STATE *cs=code_state();
  (void) fprintf(stderr, ERR_ABORT, cs ? cs->process : "(null)", why);
  (void) fflush(stderr);
  exit(1);
unknown's avatar
unknown committed
1987 1988 1989 1990 1991 1992
}


/*
 *  FUNCTION
 *
unknown's avatar
unknown committed
1993
 *      DbugMalloc    allocate memory for debugger runtime support
unknown's avatar
unknown committed
1994 1995 1996
 *
 *  SYNOPSIS
 *
unknown's avatar
unknown committed
1997 1998
 *      static long *DbugMalloc(size)
 *      int size;
unknown's avatar
unknown committed
1999 2000 2001
 *
 *  DESCRIPTION
 *
unknown's avatar
unknown committed
2002 2003 2004 2005 2006 2007
 *      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.
unknown's avatar
unknown committed
2008 2009 2010
 *
 */

unknown's avatar
unknown committed
2011
static char *DbugMalloc(size_t size)
unknown's avatar
unknown committed
2012
{
2013
  register char *new_malloc;
unknown's avatar
unknown committed
2014

2015
  if (!(new_malloc= (char*) malloc(size)))
unknown's avatar
unknown committed
2016 2017
    DbugExit("out of memory");
  return new_malloc;
unknown's avatar
unknown committed
2018 2019 2020 2021
}


/*
2022
 *     strtok lookalike - splits on ':', magically handles ::, :\ and :/
unknown's avatar
unknown committed
2023 2024
 */

unknown's avatar
unknown committed
2025
static const char *DbugStrTok(const char *s)
unknown's avatar
unknown committed
2026
{
2027 2028
  while (s[0] && (s[0] != ':' ||
                  (s[1] == '\\' || s[1] == '/' || (s[1] == ':' && s++))))
unknown's avatar
unknown committed
2029 2030
    s++;
  return s;
unknown's avatar
unknown committed
2031 2032 2033 2034 2035 2036
}


/*
 *  FUNCTION
 *
unknown's avatar
unknown committed
2037
 *      BaseName    strip leading pathname components from name
unknown's avatar
unknown committed
2038 2039 2040
 *
 *  SYNOPSIS
 *
unknown's avatar
unknown committed
2041 2042
 *      static char *BaseName(pathname)
 *      char *pathname;
unknown's avatar
unknown committed
2043 2044 2045
 *
 *  DESCRIPTION
 *
unknown's avatar
unknown committed
2046 2047 2048
 *      Given pointer to a complete pathname, locates the base file
 *      name at the end of the pathname and returns a pointer to
 *      it.
unknown's avatar
unknown committed
2049 2050 2051
 *
 */

unknown's avatar
unknown committed
2052
static const char *BaseName(const char *pathname)
unknown's avatar
unknown committed
2053 2054 2055
{
  register const char *base;

unknown's avatar
unknown committed
2056
  base= strrchr(pathname, FN_LIBCHAR);
unknown's avatar
unknown committed
2057
  if (base++ == NullS)
unknown's avatar
unknown committed
2058 2059
    base= pathname;
  return base;
unknown's avatar
unknown committed
2060 2061 2062 2063 2064 2065
}


/*
 *  FUNCTION
 *
unknown's avatar
unknown committed
2066
 *      Writable    test to see if a pathname is writable/creatable
unknown's avatar
unknown committed
2067 2068 2069
 *
 *  SYNOPSIS
 *
unknown's avatar
unknown committed
2070 2071
 *      static BOOLEAN Writable(pathname)
 *      char *pathname;
unknown's avatar
unknown committed
2072 2073 2074
 *
 *  DESCRIPTION
 *
unknown's avatar
unknown committed
2075 2076 2077 2078 2079
 *      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.
unknown's avatar
unknown committed
2080
 *
unknown's avatar
unknown committed
2081 2082
 *      Returns TRUE if the user would normally be allowed write or
 *      create access to the named file.  Returns FALSE otherwise.
unknown's avatar
unknown committed
2083 2084 2085 2086 2087 2088
 *
 */


#ifndef Writable

2089
static BOOLEAN Writable(const char *pathname)
unknown's avatar
unknown committed
2090 2091 2092 2093
{
  REGISTER BOOLEAN granted;
  REGISTER char *lastslash;

unknown's avatar
unknown committed
2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110
  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= '/';
unknown's avatar
unknown committed
2111
  }
unknown's avatar
unknown committed
2112
  return granted;
unknown's avatar
unknown committed
2113 2114 2115 2116 2117 2118 2119
}
#endif


/*
 *  FUNCTION
 *
unknown's avatar
unknown committed
2120
 *      ChangeOwner    change owner to real user for suid programs
unknown's avatar
unknown committed
2121 2122 2123
 *
 *  SYNOPSIS
 *
unknown's avatar
unknown committed
2124
 *      static VOID ChangeOwner(pathname)
unknown's avatar
unknown committed
2125 2126 2127
 *
 *  DESCRIPTION
 *
unknown's avatar
unknown committed
2128 2129 2130
 *      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.
unknown's avatar
unknown committed
2131
 *
unknown's avatar
unknown committed
2132 2133 2134 2135 2136
 *      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).
unknown's avatar
unknown committed
2137 2138 2139 2140
 *
 */

#ifndef ChangeOwner
unknown's avatar
unknown committed
2141
static void ChangeOwner(CODE_STATE *cs, char *pathname)
unknown's avatar
unknown committed
2142
{
unknown's avatar
unknown committed
2143
  if (chown(pathname, getuid(), getgid()) == -1)
unknown's avatar
unknown committed
2144
  {
unknown's avatar
unknown committed
2145 2146 2147
    (void) fprintf(stderr, ERR_CHOWN, cs->process, pathname);
    perror("");
    (void) fflush(stderr);
unknown's avatar
unknown committed
2148 2149 2150 2151 2152 2153 2154 2155
  }
}
#endif


/*
 *  FUNCTION
 *
unknown's avatar
unknown committed
2156
 *      _db_setjmp_    save debugger environment
unknown's avatar
unknown committed
2157 2158 2159
 *
 *  SYNOPSIS
 *
unknown's avatar
unknown committed
2160
 *      VOID _db_setjmp_()
unknown's avatar
unknown committed
2161 2162 2163
 *
 *  DESCRIPTION
 *
unknown's avatar
unknown committed
2164 2165 2166
 *      Invoked as part of the user's DBUG_SETJMP macro to save
 *      the debugger environment in parallel with saving the user's
 *      environment.
unknown's avatar
unknown committed
2167 2168 2169 2170 2171
 *
 */

#ifdef HAVE_LONGJMP

unknown's avatar
unknown committed
2172
EXPORT void _db_setjmp_()
unknown's avatar
unknown committed
2173
{
2174
  CODE_STATE *cs;
unknown's avatar
unknown committed
2175
  get_code_state_or_return;
unknown's avatar
unknown committed
2176

unknown's avatar
unknown committed
2177 2178 2179
  cs->jmplevel= cs->level;
  cs->jmpfunc= cs->func;
  cs->jmpfile= cs->file;
unknown's avatar
unknown committed
2180 2181 2182 2183 2184
}

/*
 *  FUNCTION
 *
unknown's avatar
unknown committed
2185
 *      _db_longjmp_    restore previously saved debugger environment
unknown's avatar
unknown committed
2186 2187 2188
 *
 *  SYNOPSIS
 *
unknown's avatar
unknown committed
2189
 *      VOID _db_longjmp_()
unknown's avatar
unknown committed
2190 2191 2192
 *
 *  DESCRIPTION
 *
unknown's avatar
unknown committed
2193 2194 2195
 *      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.
unknown's avatar
unknown committed
2196 2197 2198
 *
 */

unknown's avatar
unknown committed
2199
EXPORT void _db_longjmp_()
unknown's avatar
unknown committed
2200
{
2201
  CODE_STATE *cs;
unknown's avatar
unknown committed
2202 2203 2204 2205 2206 2207 2208
  get_code_state_or_return;

  cs->level= cs->jmplevel;
  if (cs->jmpfunc)
    cs->func= cs->jmpfunc;
  if (cs->jmpfile)
    cs->file= cs->jmpfile;
unknown's avatar
unknown committed
2209 2210 2211 2212 2213 2214
}
#endif

/*
 *  FUNCTION
 *
unknown's avatar
unknown committed
2215
 *      perror    perror simulation for systems that don't have it
unknown's avatar
unknown committed
2216 2217 2218
 *
 *  SYNOPSIS
 *
unknown's avatar
unknown committed
2219 2220
 *      static VOID perror(s)
 *      char *s;
unknown's avatar
unknown committed
2221 2222 2223
 *
 *  DESCRIPTION
 *
unknown's avatar
unknown committed
2224 2225 2226 2227
 *      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.
unknown's avatar
unknown committed
2228
 *
unknown's avatar
unknown committed
2229 2230 2231
 *      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.
unknown's avatar
unknown committed
2232
 *
unknown's avatar
unknown committed
2233
 *      This version just complains about an "unknown system error".
unknown's avatar
unknown committed
2234 2235 2236 2237
 *
 */

#ifndef HAVE_PERROR
unknown's avatar
unknown committed
2238
static void perror(s)
unknown's avatar
unknown committed
2239 2240
char *s;
{
unknown's avatar
unknown committed
2241 2242 2243
  if (s && *s != '\0')
    (void) fprintf(stderr, "%s: ", s);
  (void) fprintf(stderr, "<unknown system error>\n");
unknown's avatar
unknown committed
2244 2245 2246 2247
}
#endif /* HAVE_PERROR */


unknown's avatar
unknown committed
2248 2249 2250
        /* 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 !! */
unknown's avatar
unknown committed
2251

unknown's avatar
unknown committed
2252
static void dbug_flush(CODE_STATE *cs)
unknown's avatar
unknown committed
2253
{
unknown's avatar
unknown committed
2254
  if (cs->stack->flags & FLUSH_ON_WRITE)
unknown's avatar
unknown committed
2255
  {
2256 2257 2258
    (void) fflush(cs->stack->out_file);
    if (cs->stack->delay)
      (void) Delay(cs->stack->delay);
unknown's avatar
unknown committed
2259
  }
unknown's avatar
unknown committed
2260
  if (!cs->locked)
unknown's avatar
unknown committed
2261 2262 2263 2264
    pthread_mutex_unlock(&THR_LOCK_dbug);
} /* dbug_flush */


unknown's avatar
unknown committed
2265
void _db_lock_file_()
unknown's avatar
unknown committed
2266
{
2267
  CODE_STATE *cs;
unknown's avatar
unknown committed
2268
  get_code_state_or_return;
unknown's avatar
unknown committed
2269
  pthread_mutex_lock(&THR_LOCK_dbug);
unknown's avatar
unknown committed
2270
  cs->locked=1;
unknown's avatar
unknown committed
2271 2272
}

unknown's avatar
unknown committed
2273
void _db_unlock_file_()
unknown's avatar
unknown committed
2274
{
2275
  CODE_STATE *cs;
unknown's avatar
unknown committed
2276 2277
  get_code_state_or_return;
  cs->locked=0;
unknown's avatar
unknown committed
2278 2279 2280 2281 2282 2283 2284 2285
  pthread_mutex_unlock(&THR_LOCK_dbug);
}

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

unknown's avatar
unknown committed
2286 2287
#ifndef THREAD
#if defined(HAVE_GETRUSAGE)
unknown's avatar
unknown committed
2288 2289 2290 2291

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

unknown's avatar
unknown committed
2292
/* extern int getrusage(int, struct rusage *); */
unknown's avatar
unknown committed
2293 2294 2295 2296 2297 2298

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

unknown's avatar
unknown committed
2299
static unsigned long Clock()
unknown's avatar
unknown committed
2300 2301 2302
{
    struct rusage ru;

unknown's avatar
unknown committed
2303 2304
    (void) getrusage(RUSAGE_SELF, &ru);
    return ru.ru_utime.tv_sec*1000 + ru.ru_utime.tv_usec/1000;
unknown's avatar
unknown committed
2305 2306
}

2307
#elif defined(MSDOS) || defined(__WIN__)
unknown's avatar
unknown committed
2308 2309 2310 2311 2312

static ulong Clock()
{
  return clock()*(1000/CLOCKS_PER_SEC);
}
unknown's avatar
unknown committed
2313
#elif defined(amiga)
unknown's avatar
unknown committed
2314

unknown's avatar
unknown committed
2315 2316 2317 2318
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;
unknown's avatar
unknown committed
2319 2320
};

unknown's avatar
unknown committed
2321
static int first_clock= TRUE;
unknown's avatar
unknown committed
2322 2323 2324
static struct DateStamp begin;
static struct DateStamp elapsed;

unknown's avatar
unknown committed
2325
static unsigned long Clock()
unknown's avatar
unknown committed
2326 2327
{
    register struct DateStamp *now;
unknown's avatar
unknown committed
2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344
    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));
unknown's avatar
unknown committed
2345
    }
unknown's avatar
unknown committed
2346
    return millisec;
unknown's avatar
unknown committed
2347 2348
}
#else
unknown's avatar
unknown committed
2349
static unsigned long Clock()
unknown's avatar
unknown committed
2350
{
unknown's avatar
unknown committed
2351
    return 0;
unknown's avatar
unknown committed
2352 2353
}
#endif /* RUSAGE */
unknown's avatar
unknown committed
2354
#endif /* THREADS */
unknown's avatar
unknown committed
2355 2356 2357 2358

#ifdef NO_VARARGS

/*
unknown's avatar
unknown committed
2359 2360
 *      Fake vfprintf for systems that don't support it.  If this
 *      doesn't work, you are probably SOL...
unknown's avatar
unknown committed
2361 2362
 */

unknown's avatar
unknown committed
2363
static int vfprintf(stream, format, ap)
unknown's avatar
unknown committed
2364 2365 2366 2367 2368 2369 2370
FILE *stream;
char *format;
va_list ap;
{
    int rtnval;
    ARGS_DCL;

unknown's avatar
unknown committed
2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382
    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;
unknown's avatar
unknown committed
2383 2384
}

unknown's avatar
unknown committed
2385
#endif  /* NO_VARARGS */
2386

2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400
#else

/*
 * Dummy function, workaround for MySQL bug#14420 related
 * build failure on a platform where linking with an empty
 * archive fails.
 *
 * This block can be removed as soon as a fix for bug#14420
 * is implemented.
 */
int i_am_a_dummy_function() {
       return 0;
}

2401
#endif