dbug.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:50k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /******************************************************************************
  2.  *       *
  3.  *    N O T I C E       *
  4.  *       *
  5.  *       Copyright Abandoned, 1987, Fred Fish       *
  6.  *       *
  7.  *       *
  8.  * This previously copyrighted work has been placed into the  public     *
  9.  * domain by  the  author  and  may be freely used for any purpose,     *
  10.  * private or commercial.       *
  11.  *       *
  12.  * Because of the number of inquiries I was receiving about the  use     *
  13.  * of this product in commercially developed works I have decided to     *
  14.  * simply make it public domain to further its unrestricted use. I     *
  15.  * specifically  would  be  most happy to see this material become a     *
  16.  * part of the standard Unix distributions by AT&T and the  Berkeley     *
  17.  * Computer  Science  Research Group, and a standard part of the GNU     *
  18.  * system from the Free Software Foundation.       *
  19.  *       *
  20.  * I would appreciate it, as a courtesy, if this notice is  left  in     *
  21.  * all copies and derivative works.  Thank you.       *
  22.  *       *
  23.  * The author makes no warranty of any kind  with respect  to  this     *
  24.  * product  and  explicitly disclaims any implied warranties of mer-     *ct_lex.table_list.first=0;
  25.   thd->lex.selec
  26.  * chantability or fitness for any particular purpose.       *
  27.  *       *
  28.  ******************************************************************************
  29.  */
  30. /*
  31.  *  FILE
  32.  *
  33.  * dbug.c  runtime support routines for dbug package
  34.  *
  35.  *  SCCS
  36.  *
  37.  * @(#)dbug.c 1.25 7/25/89
  38.  *
  39.  *  DESCRIPTION
  40.  *
  41.  * These are the runtime support routines for the dbug package.
  42.  * The dbug package has two main components; the user include
  43.  * file containing various macro definitions, and the runtime
  44.  * support routines which are called from the macro expansions.
  45.  *
  46.  * Externally visible functions in the runtime support module
  47.  * use the naming convention pattern "_db_xx...xx_", thus
  48.  * they are unlikely to collide with user defined function names.
  49.  *
  50.  *  AUTHOR(S)
  51.  *
  52.  * Fred Fish (base code)
  53.  * Enhanced Software Technologies, Tempe, AZ
  54.  * asuvax!mcdphx!estinc!fnf
  55.  *
  56.  * Binayak Banerjee (profiling enhancements)
  57.  * seismo!bpa!sjuvax!bbanerje
  58.  *
  59.  * Michael Widenius:
  60.  * DBUG_DUMP - To dump a block of memory.
  61.  * PUSH_FLAG "O" - To be used insted of "o" if we don't
  62.  *   want flushing (for slow systems)
  63.  * PUSH_FLAG "A" - as 'O', but we will append to the out file instead
  64.  *   of creating a new one.
  65.  * Check of malloc on entry/exit (option "S")
  66.  */
  67. #ifdef DBUG_OFF
  68. #undef DBUG_OFF
  69. #endif
  70. #include <my_global.h>
  71. #include <m_string.h>
  72. #include <errno.h>
  73. #if defined(MSDOS) || defined(__WIN__)
  74. #include <process.h>
  75. #endif
  76. #ifdef _DBUG_CONDITION_
  77. #define _DBUG_START_CONDITION_ "d:t"
  78. #else
  79. #define _DBUG_START_CONDITION_ ""
  80. #endif
  81. /*
  82.  *       Manifest constants that should not require any changes.
  83.  */
  84. #define EOS       '00'  /* End Of String marker */
  85. /*
  86.  *       Manifest constants which may be "tuned" if desired.
  87.  */
  88. #define PRINTBUF       1024    /* Print buffer size */
  89. #define INDENT       2       /* Indentation per trace level */
  90. #define MAXDEPTH       200     /* Maximum trace depth default */
  91. /*
  92.  * The following flags are used to determine which
  93.  * capabilities the user has enabled with the state
  94.  * push macro.
  95.  */
  96. #define TRACE_ON 000001 /* Trace enabled */
  97. #define DEBUG_ON 000002 /* Debug enabled */
  98. #define FILE_ON 000004 /* File name print enabled */
  99. #define LINE_ON 000010 /* Line number print enabled */
  100. #define DEPTH_ON 000020 /* Function nest level print enabled */
  101. #define PROCESS_ON 000040 /* Process name print enabled */
  102. #define NUMBER_ON 000100 /* Number each line of output */
  103. #define PROFILE_ON 000200 /* Print out profiling code */
  104. #define PID_ON 000400 /* Identify each line with process id */
  105. #define SANITY_CHECK_ON 001000 /* Check safemalloc on DBUG_ENTER */
  106. #define FLUSH_ON_WRITE 002000 /* Flush on every write */
  107. #define TRACING (stack -> flags & TRACE_ON)
  108. #define DEBUGGING (stack -> flags & DEBUG_ON)
  109. #define PROFILING (stack -> flags & PROFILE_ON)
  110. #define STREQ(a,b) (strcmp(a,b) == 0)
  111. /*
  112.  * Typedefs to make things more obvious.
  113.  */
  114. #ifndef __WIN__
  115. typedef int BOOLEAN;
  116. #else
  117. #define BOOLEAN BOOL
  118. #endif
  119. /*
  120.  * Make it easy to change storage classes if necessary.
  121.  */
  122. #define IMPORT extern /* Names defined externally */
  123. #define EXPORT /* Allocated here, available globally */
  124. #define AUTO auto /* Names to be allocated on stack */
  125. #define REGISTER register /* Names to be placed in registers */
  126. /*
  127.  * The default file for profiling.  Could also add another flag
  128.  * (G?) which allowed the user to specify this.
  129.  *
  130.  * If the automatic variables get allocated on the stack in
  131.  * reverse order from their declarations, then define AUTOS_REVERSE.
  132.  * This is used by the code that keeps track of stack usage.  For
  133.  * forward allocation, the difference in the dbug frame pointers
  134.  * represents stack used by the callee function.  For reverse allocation,
  135.  * the difference represents stack used by the caller function.
  136.  *
  137.  */
  138. #define PROF_FILE "dbugmon.out"
  139. #define PROF_EFMT "Et%ldt%sn"
  140. #define PROF_SFMT "St%lxt%lxt%sn"
  141. #define PROF_XFMT "Xt%ldt%sn"
  142. #ifdef M_I386 /* predefined by xenix 386 compiler */
  143. #define AUTOS_REVERSE 1
  144. #endif
  145. /*
  146.  * Variables which are available externally but should only
  147.  * be accessed via the macro package facilities.
  148.  */
  149. EXPORT FILE *_db_fp_ = (FILE *) 0; /* Output stream, default stderr */
  150. EXPORT char *_db_process_ = (char*) "dbug"; /* Pointer to process name; argv[0] */
  151. EXPORT FILE *_db_pfp_ = (FILE *)0; /* Profile stream, 'dbugmon.out' */
  152. EXPORT BOOLEAN _db_on_ = FALSE; /* TRUE if debugging currently on */
  153. EXPORT BOOLEAN _db_pon_ = FALSE; /* TRUE if profile currently on */
  154. EXPORT BOOLEAN _no_db_ = FALSE; /* TRUE if no debugging at all */
  155. /*
  156.  * Externally supplied functions.
  157.  */
  158. #ifndef HAVE_PERROR
  159. static void perror (); /* Fake system/library error print routine */
  160. #endif
  161. IMPORT int _sanity(const char *file,uint line);
  162. /*
  163.  * The user may specify a list of functions to trace or
  164.  * debug. These lists are kept in a linear linked list,
  165.  * a very simple implementation.
  166.  */
  167. struct link {
  168.     char *str;       /* Pointer to link's contents */
  169.     struct link *next_link;   /* Pointer to the next link */
  170. };
  171. /*
  172.  * Debugging states can be pushed or popped off of a
  173.  * stack which is implemented as a linked list.  Note
  174.  * that the head of the list is the current state and the
  175.  * stack is pushed by adding a new state to the head of the
  176.  * list or popped by removing the first link.
  177.  */
  178. struct state {
  179.   int flags; /* Current state flags */
  180.   int maxdepth; /* Current maximum trace depth */
  181.   uint delay; /* Delay after each output line */
  182.   int sub_level; /* Sub this from code_state->level */
  183.   FILE *out_file; /* Current output stream */
  184.   FILE *prof_file; /* Current profiling stream */
  185.   char name[FN_REFLEN]; /* Name of output file */
  186.   struct link *functions; /* List of functions */
  187.   struct link *p_functions; /* List of profiled functions */
  188.   struct link *keywords; /* List of debug keywords */
  189.   struct link *processes; /* List of process names */
  190.   struct state *next_state; /* Next state in the list */
  191. };
  192. /*
  193.  * Local variables not seen by user.
  194.  */
  195. static my_bool init_done = FALSE; /* Set to TRUE when initialization done */
  196. static struct state *stack=0;
  197. typedef struct st_code_state {
  198.   const char *func; /* Name of current user function */
  199.   const char *file; /* Name of current user file */
  200.   char **framep; /* Pointer to current frame */
  201.   const char *jmpfunc; /* Remember current function for setjmp */
  202.   const char *jmpfile; /* Remember current file for setjmp */
  203.   int lineno; /* Current debugger output line number */
  204.   int level; /* Current function nesting level */
  205.   int disable_output; /* Set to it if output is disabled */
  206.   int jmplevel; /* Remember nesting level at setjmp () */
  207. /*
  208.  * The following variables are used to hold the state information
  209.  * between the call to _db_pargs_() and _db_doprnt_(), during
  210.  * expansion of the DBUG_PRINT macro.  This is the only macro
  211.  * that currently uses these variables.
  212.  *
  213.  * These variables are currently used only by _db_pargs_() and
  214.  * _db_doprnt_().
  215.  */
  216.   uint u_line; /* User source code line number */
  217.   int  locked; /* If locked with _db_lock_file */
  218.   const char *u_keyword; /* Keyword for current macro */
  219. } CODE_STATE;
  220. /* Parse a debug command string */
  221. static struct link *ListParse(char *ctlp);
  222. /* Make a fresh copy of a string */
  223. static char *StrDup(const char *str);
  224. /* Open debug output stream */
  225. static void DBUGOpenFile(const char *name, int append);
  226. #ifndef THREAD
  227. /* Open profile output stream */
  228. static FILE *OpenProfile(const char *name);
  229. /* Profile if asked for it */
  230. static BOOLEAN DoProfile(void);
  231. #endif
  232. /* Return current user time (ms) */
  233. #ifndef THREAD
  234. static unsigned long Clock (void);
  235. #endif
  236. /* Close debug output stream */
  237. static void CloseFile(FILE *fp);
  238. /* Push current debug state */
  239. static void PushState(void);
  240. /* Test for tracing enabled */
  241. static BOOLEAN DoTrace(CODE_STATE *state);
  242. /* Test to see if file is writable */
  243. #if !(!defined(HAVE_ACCESS) || defined(MSDOS))
  244. static BOOLEAN Writable(char *pathname);
  245. /* Change file owner and group */
  246. static void ChangeOwner(char *pathname);
  247. /* Allocate memory for runtime support */
  248. #endif
  249. static char *DbugMalloc(size_t size);
  250. /* Remove leading pathname components */
  251. static char *BaseName(const char *pathname);
  252. static void DoPrefix(uint line);
  253. static void FreeList(struct link *linkp);
  254. static void Indent(int indent);
  255. static BOOLEAN InList(struct link *linkp,const char *cp);
  256. static void dbug_flush(CODE_STATE *);
  257. static void DbugExit(const char *why);
  258. static int DelayArg(int value);
  259. /* Supplied in Sys V runtime environ */
  260. /* Break string into tokens */
  261. static char *static_strtok(char *s1,pchar chr);
  262. /*
  263.  * Miscellaneous printf format strings.
  264.  */
  265. #define ERR_MISSING_RETURN "%s: missing DBUG_RETURN or DBUG_VOID_RETURN macro in function "%s"n"
  266. #define ERR_OPEN "%s: can't open debug output stream "%s": "
  267. #define ERR_CLOSE "%s: can't close debug file: "
  268. #define ERR_ABORT "%s: debugger aborting because %sn"
  269. #define ERR_CHOWN "%s: can't change owner/group of "%s": "
  270. /*
  271.  * Macros and defines for testing file accessibility under UNIX and MSDOS.
  272.  */
  273. #undef EXISTS
  274. #if !defined(HAVE_ACCESS) || defined(MSDOS)
  275. #define EXISTS(pathname) (FALSE) /* Assume no existance */
  276. #define Writable(name) (TRUE)
  277. #else
  278. #define EXISTS(pathname)  (access (pathname, F_OK) == 0)
  279. #define WRITABLE(pathname)  (access (pathname, W_OK) == 0)
  280. #endif
  281. #ifndef MSDOS
  282. #define ChangeOwner(name)
  283. #endif
  284. /*
  285.  * Translate some calls among different systems.
  286.  */
  287. #if defined(unix) || defined(xenix) || defined(VMS) || defined(__NetBSD__)
  288. # define Delay(A) sleep((uint) A)
  289. #elif defined(AMIGA)
  290. IMPORT int Delay (); /* Pause for given number of ticks */
  291. #else
  292. static int Delay(int ticks);
  293. #endif
  294. /*
  295. ** Macros to allow dbugging with threads
  296. */
  297. #ifdef THREAD
  298. #include <my_pthread.h>
  299. pthread_mutex_t THR_LOCK_dbug;
  300. static void init_dbug_state(void)
  301. {
  302.   pthread_mutex_init(&THR_LOCK_dbug,MY_MUTEX_INIT_FAST);
  303. }
  304. static CODE_STATE *code_state(void)
  305. {
  306.   CODE_STATE *state=0;
  307.   struct st_my_thread_var *tmp=my_thread_var;
  308.   if (tmp)
  309.   {
  310.     if (!(state=(CODE_STATE *) tmp->dbug))
  311.     {
  312.       state=(CODE_STATE*) DbugMalloc(sizeof(*state));
  313.       bzero((char*) state,sizeof(*state));
  314.       state->func="?func";
  315.       state->file="?file";
  316.       tmp->dbug=(gptr) state;
  317.     }
  318.   }
  319.   return state;
  320. }
  321. #else /* !THREAD */
  322. #define init_dbug_state()
  323. #define code_state() (&static_code_state)
  324. #define pthread_mutex_lock(A) {}
  325. #define pthread_mutex_unlock(A) {}
  326. static CODE_STATE static_code_state=
  327. {
  328.   "?func", "?file", NULL, NullS, NullS, 0,0,0,0,0,0, NullS
  329. };
  330. #endif
  331. /*
  332.  *  FUNCTION
  333.  *
  334.  * _db_push_ push current debugger state and set up new one
  335.  *
  336.  *  SYNOPSIS
  337.  *
  338.  * VOID _db_push_ (control)
  339.  * char *control;
  340.  *
  341.  *  DESCRIPTION
  342.  *
  343.  * Given pointer to a debug control string in "control", pushes
  344.  * the current debug state, parses the control string, and sets
  345.  * up a new debug state.
  346.  *
  347.  * The only attribute of the new state inherited from the previous
  348.  * state is the current function nesting level.  This can be
  349.  * overridden by using the "r" flag in the control string.
  350.  *
  351.  * The debug control string is a sequence of colon separated fields
  352.  * as follows:
  353.  *
  354.  * <field_1>:<field_2>:...:<field_N>
  355.  *
  356.  * Each field consists of a mandatory flag character followed by
  357.  * an optional "," and comma separated list of modifiers:
  358.  *
  359.  * flag[,modifier,modifier,...,modifier]
  360.  *
  361.  * The currently recognized flag characters are:
  362.  *
  363.  * d Enable output from DBUG_<N> macros for
  364.  * for the current state. May be followed
  365.  * by a list of keywords which selects output
  366.  * only for the DBUG macros with that keyword.
  367.  * A null list of keywords implies output for
  368.  * all macros.
  369.  *
  370.  * D Delay after each debugger output line.
  371.  * The argument is the number of tenths of seconds
  372.  * to delay, subject to machine capabilities.
  373.  * I.E.  -#D,20 is delay two seconds.
  374.  *
  375.  * f Limit debugging and/or tracing, and profiling to the
  376.  * list of named functions.  Note that a null list will
  377.  * disable all functions. The appropriate "d" or "t"
  378.  * flags must still be given, this flag only limits their
  379.  * actions if they are enabled.
  380.  *
  381.  * F Identify the source file name for each
  382.  * line of debug or trace output.
  383.  *
  384.  * i Identify the process with the pid for each line of
  385.  * debug or trace output.
  386.  *
  387.  * g Enable profiling.  Create a file called 'dbugmon.out'
  388.  * containing information that can be used to profile
  389.  * the program.  May be followed by a list of keywords
  390.  * that select profiling only for the functions in that
  391.  * list.  A null list implies that all functions are
  392.  * considered.
  393.  *
  394.  * L Identify the source file line number for
  395.  * each line of debug or trace output.
  396.  *
  397.  * n Print the current function nesting depth for
  398.  * each line of debug or trace output.
  399.  *
  400.  * N Number each line of dbug output.
  401.  *
  402.  * o Redirect the debugger output stream to the
  403.  * specified file.  The default output is stderr.
  404.  *
  405.  * O As O but the file is really flushed between each
  406.  * write. When neaded the file is closed and reopened
  407.  * between each write.
  408.  *
  409.  * p Limit debugger actions to specified processes.
  410.  * A process must be identified with the
  411.  * DBUG_PROCESS macro and match one in the list
  412.  * for debugger actions to occur.
  413.  *
  414.  * P Print the current process name for each
  415.  * line of debug or trace output.
  416.  *
  417.  * r When pushing a new state, do not inherit
  418.  * the previous state's function nesting level.
  419.  * Useful when the output is to start at the
  420.  * left margin.
  421.  *
  422.  * S Do function _sanity(_file_,_line_) at each
  423.  * debugged function until _sanity() returns
  424.  * something that differs from 0.
  425.  * (Moustly used with safemalloc)
  426.  *
  427.  * t Enable function call/exit trace lines.
  428.  * May be followed by a list (containing only
  429.  * one modifier) giving a numeric maximum
  430.  * trace level, beyond which no output will
  431.  * occur for either debugging or tracing
  432.  * macros.  The default is a compile time
  433.  * option.
  434.  *
  435.  * Some examples of debug control strings which might appear
  436.  * on a shell command line (the "-#" is typically used to
  437.  * introduce a control string to an application program) are:
  438.  *
  439.  * -#d:t
  440.  * -#d:f,main,subr1:F:L:t,20
  441.  * -#d,input,output,files:n
  442.  *
  443.  * For convenience, any leading "-#" is stripped off.
  444.  *
  445.  */
  446. void _db_push_ (const char *control)
  447. {
  448.   reg1 char *scan;
  449.   reg2 struct link *temp;
  450.   CODE_STATE *state;
  451.   char *new_str;
  452.   if (! _db_fp_)
  453.     _db_fp_= stderr; /* Output stream, default stderr */
  454.   if (*control == '-')
  455.   {
  456.     if (*++control == '#')
  457.       control++;
  458.   }
  459.   if (*control)
  460.     _no_db_=0; /* We are using dbug after all */
  461.   new_str = StrDup (control);
  462.   PushState ();
  463.   state=code_state();
  464.   scan = static_strtok (new_str, ':');
  465.   for (; scan != NULL; scan = static_strtok ((char *)NULL, ':')) {
  466.     switch (*scan++) {
  467.     case 'd':
  468.       _db_on_ = TRUE;
  469.       stack -> flags |= DEBUG_ON;
  470.       if (*scan++ == ',') {
  471. stack -> keywords = ListParse (scan);
  472.       }
  473.       break;
  474.     case 'D':
  475.       stack -> delay = 0;
  476.       if (*scan++ == ',') {
  477. temp = ListParse (scan);
  478. stack -> delay = DelayArg (atoi (temp -> str));
  479. FreeList (temp);
  480.       }
  481.       break;
  482.     case 'f':
  483.       if (*scan++ == ',') {
  484. stack -> functions = ListParse (scan);
  485.       }
  486.       break;
  487.     case 'F':
  488.       stack -> flags |= FILE_ON;
  489.       break;
  490.     case 'i':
  491.       stack -> flags |= PID_ON;
  492.       break;
  493. #ifndef THREAD
  494.     case 'g':
  495.       _db_pon_ = TRUE;
  496.       if (OpenProfile(PROF_FILE))
  497.       {
  498. stack -> flags |= PROFILE_ON;
  499. if (*scan++ == ',')
  500.   stack -> p_functions = ListParse (scan);
  501.       }
  502.       break;
  503. #endif
  504.     case 'L':
  505.       stack -> flags |= LINE_ON;
  506.       break;
  507.     case 'n':
  508.       stack -> flags |= DEPTH_ON;
  509.       break;
  510.     case 'N':
  511.       stack -> flags |= NUMBER_ON;
  512.       break;
  513.     case 'A':
  514.     case 'O':
  515.       stack -> flags |= FLUSH_ON_WRITE;
  516.     case 'a':
  517.     case 'o':
  518.       if (*scan++ == ',') {
  519. temp = ListParse (scan);
  520. DBUGOpenFile(temp -> str, (int) (scan[-2] == 'A' || scan[-2] == 'a'));
  521. FreeList (temp);
  522.       } else {
  523. DBUGOpenFile ("-",0);
  524.       }
  525.       break;
  526.     case 'p':
  527.       if (*scan++ == ',') {
  528. stack -> processes = ListParse (scan);
  529.       }
  530.       break;
  531.     case 'P':
  532.       stack -> flags |= PROCESS_ON;
  533.       break;
  534.     case 'r':
  535.       stack->sub_level= state->level;
  536.       break;
  537.     case 't':
  538.       stack -> flags |= TRACE_ON;
  539.       if (*scan++ == ',') {
  540. temp = ListParse (scan);
  541. stack -> maxdepth = atoi (temp -> str);
  542. FreeList (temp);
  543.       }
  544.       break;
  545.     case 'S':
  546.       stack -> flags |= SANITY_CHECK_ON;
  547.       break;
  548.     }
  549.   }
  550.   free (new_str);
  551. }
  552. /*
  553.  *  FUNCTION
  554.  *
  555.  * _db_pop_    pop the debug stack
  556.  *
  557.  *  DESCRIPTION
  558.  *
  559.  * Pops the debug stack, returning the debug state to its
  560.  * condition prior to the most recent _db_push_ invocation.
  561.  * Note that the pop will fail if it would remove the last
  562.  * valid state from the stack.  This prevents user errors
  563.  * in the push/pop sequence from screwing up the debugger.
  564.  * Maybe there should be some kind of warning printed if the
  565.  * user tries to pop too many states.
  566.  *
  567.  */
  568. void _db_pop_ ()
  569. {
  570.   reg1 struct state *discard;
  571.   discard = stack;
  572.   if (discard != NULL && discard -> next_state != NULL) {
  573.     stack = discard -> next_state;
  574.     _db_fp_ = stack -> out_file;
  575.     _db_pfp_ = stack -> prof_file;
  576.     if (discard -> keywords != NULL) {
  577.       FreeList (discard -> keywords);
  578.     }
  579.     if (discard -> functions != NULL) {
  580.       FreeList (discard -> functions);
  581.     }
  582.     if (discard -> processes != NULL) {
  583.       FreeList (discard -> processes);
  584.     }
  585.     if (discard -> p_functions != NULL) {
  586.       FreeList (discard -> p_functions);
  587.     }
  588.     CloseFile (discard -> out_file);
  589.     if (discard -> prof_file)
  590.       CloseFile (discard -> prof_file);
  591.     free ((char *) discard);
  592.     if (!(stack->flags & DEBUG_ON))
  593.       _db_on_=0;
  594.   }
  595.   else
  596.   {
  597.     _db_on_=0;
  598.   }
  599. }
  600. /*
  601.  *  FUNCTION
  602.  *
  603.  * _db_enter_    process entry point to user function
  604.  *
  605.  *  SYNOPSIS
  606.  *
  607.  * VOID _db_enter_ (_func_, _file_, _line_,
  608.  *  _sfunc_, _sfile_, _slevel_, _sframep_)
  609.  * char *_func_; points to current function name
  610.  * char *_file_; points to current file name
  611.  * int _line_; called from source line number
  612.  * char **_sfunc_; save previous _func_
  613.  * char **_sfile_; save previous _file_
  614.  * int *_slevel_; save previous nesting level
  615.  * char ***_sframep_; save previous frame pointer
  616.  *
  617.  *  DESCRIPTION
  618.  *
  619.  * Called at the beginning of each user function to tell
  620.  * the debugger that a new function has been entered.
  621.  * Note that the pointers to the previous user function
  622.  * name and previous user file name are stored on the
  623.  * caller's stack (this is why the ENTER macro must be
  624.  * the first "executable" code in a function, since it
  625.  * allocates these storage locations).  The previous nesting
  626.  * level is also stored on the callers stack for internal
  627.  * self consistency checks.
  628.  *
  629.  * Also prints a trace line if tracing is enabled and
  630.  * increments the current function nesting depth.
  631.  *
  632.  * Note that this mechanism allows the debugger to know
  633.  * what the current user function is at all times, without
  634.  * maintaining an internal stack for the function names.
  635.  *
  636.  */
  637. void _db_enter_ (
  638. const char *_func_,
  639. const char *_file_,
  640. uint _line_,
  641. const char **_sfunc_,
  642. const char **_sfile_,
  643. uint *_slevel_,
  644. char ***_sframep_ __attribute__((unused)))
  645. {
  646.   reg1 CODE_STATE *state;
  647.   if (!_no_db_)
  648.   {
  649.     int save_errno=errno;
  650.     /*
  651.       Sasha: the test below is so we could call functions with DBUG_ENTER
  652.       before my_thread_init(). I needed this because I suspected corruption
  653.       of a block allocated by my_thread_init() itself, so I wanted to use
  654.       my_malloc()/my_free() in my_thread_init()/my_thread_end()
  655.     */
  656.     if (!(state=code_state()))
  657.       return;
  658.     if (!init_done)
  659.       _db_push_ (_DBUG_START_CONDITION_);
  660.     *_sfunc_ = state->func;
  661.     *_sfile_ = state->file;
  662.     state->func =(char*)  _func_;
  663.     state->file = (char*) _file_; /* BaseName takes time !! */
  664.     *_slevel_ =  ++state->level;
  665. #ifndef THREAD
  666.     *_sframep_ = state->framep;
  667.     state->framep = (char **) _sframep_;
  668.     if (DoProfile ())
  669.     {
  670.       long stackused;
  671.       if (*state->framep == NULL)
  672.       {
  673. stackused = 0;
  674.       }
  675.       else
  676.       {
  677. stackused = ((long)(*state->framep)) - ((long)(state->framep));
  678. stackused = stackused > 0 ? stackused : -stackused;
  679.       }
  680.       (void) fprintf (_db_pfp_, PROF_EFMT , Clock (), state->func);
  681. #ifdef AUTOS_REVERSE
  682.       (void) fprintf (_db_pfp_, PROF_SFMT, state->framep, stackused, *_sfunc_);
  683. #else
  684.       (void) fprintf (_db_pfp_, PROF_SFMT, (ulong) state->framep, stackused,
  685.       state->func);
  686. #endif
  687.       (void) fflush (_db_pfp_);
  688.     }
  689. #endif
  690.     if (DoTrace(state))
  691.     {
  692.       if (!state->locked)
  693. pthread_mutex_lock(&THR_LOCK_dbug);
  694.       DoPrefix (_line_);
  695.       Indent (state -> level);
  696.       (void) fprintf (_db_fp_, ">%sn", state->func);
  697.       dbug_flush (state); /* This does a unlock */
  698.     }
  699. #ifdef SAFEMALLOC
  700.     if (stack->flags & SANITY_CHECK_ON && !state->disable_output)
  701.       if (_sanity(_file_,_line_)) /* Check of safemalloc */
  702. stack -> flags &= ~SANITY_CHECK_ON;
  703. #endif
  704.     errno=save_errno;
  705.   }
  706. }
  707. /*
  708.  *  FUNCTION
  709.  *
  710.  * _db_return_    process exit from user function
  711.  *
  712.  *  SYNOPSIS
  713.  *
  714.  * VOID _db_return_ (_line_, _sfunc_, _sfile_, _slevel_)
  715.  * int _line_; current source line number
  716.  * char **_sfunc_; where previous _func_ is to be retrieved
  717.  * char **_sfile_; where previous _file_ is to be retrieved
  718.  * int *_slevel_; where previous level was stashed
  719.  *
  720.  *  DESCRIPTION
  721.  *
  722.  * Called just before user function executes an explicit or implicit
  723.  * return.  Prints a trace line if trace is enabled, decrements
  724.  * the current nesting level, and restores the current function and
  725.  * file names from the defunct function's stack.
  726.  *
  727.  */
  728. void _db_return_ (
  729. uint _line_,
  730. const char **_sfunc_,
  731. const char **_sfile_,
  732. uint *_slevel_)
  733. {
  734.   CODE_STATE *state;
  735.   if (!_no_db_)
  736.   {
  737.     int save_errno=errno;
  738.     if (!(state=code_state()))
  739.       return;
  740.     if (!init_done)
  741.       _db_push_ ("");
  742.     if (stack->flags & (TRACE_ON | DEBUG_ON | PROFILE_ON))
  743.     {
  744.       if (!state->locked)
  745. pthread_mutex_lock(&THR_LOCK_dbug);
  746.       if (state->level != (int) *_slevel_)
  747. (void) fprintf (_db_fp_, ERR_MISSING_RETURN, _db_process_,
  748. state->func);
  749.       else
  750.       {
  751. #ifdef SAFEMALLOC
  752. if (stack->flags & SANITY_CHECK_ON && !state->disable_output)
  753.         {
  754.   if (_sanity(*_sfile_,_line_))
  755.     stack->flags &= ~SANITY_CHECK_ON;
  756.         }
  757. #endif
  758. #ifndef THREAD
  759. if (DoProfile ())
  760.   (void) fprintf (_db_pfp_, PROF_XFMT, Clock(), state->func);
  761. #endif
  762. if (DoTrace (state))
  763. {
  764.   DoPrefix (_line_);
  765.   Indent (state->level);
  766.   (void) fprintf (_db_fp_, "<%sn", state->func);
  767. }
  768.       }
  769.       dbug_flush(state);
  770.     }
  771.     state->level = *_slevel_-1;
  772.     state->func = *_sfunc_;
  773.     state->file = *_sfile_;
  774. #ifndef THREAD
  775.     if (state->framep != NULL)
  776.       state->framep = (char **) *state->framep;
  777. #endif
  778.     errno=save_errno;
  779.   }
  780. }
  781. /*
  782.  *  FUNCTION
  783.  *
  784.  * _db_pargs_    log arguments for subsequent use by _db_doprnt_()
  785.  *
  786.  *  SYNOPSIS
  787.  *
  788.  * VOID _db_pargs_ (_line_, keyword)
  789.  * int _line_;
  790.  * char *keyword;
  791.  *
  792.  *  DESCRIPTION
  793.  *
  794.  * The new universal printing macro DBUG_PRINT, which replaces
  795.  * all forms of the DBUG_N macros, needs two calls to runtime
  796.  * support routines.  The first, this function, remembers arguments
  797.  * that are used by the subsequent call to _db_doprnt_().
  798.  *
  799.  */
  800. void _db_pargs_ (
  801. uint _line_,
  802. const char *keyword)
  803. {
  804.   CODE_STATE *state=code_state();
  805.   /* Sasha: pre-my_thread_init() safety */
  806.   if (!state)
  807.     return;
  808.   state->u_line = _line_;
  809.   state->u_keyword = (char*) keyword;
  810. }
  811. /*
  812.  *  FUNCTION
  813.  *
  814.  * _db_doprnt_    handle print of debug lines
  815.  *
  816.  *  SYNOPSIS
  817.  *
  818.  * VOID _db_doprnt_ (format, va_alist)
  819.  * char *format;
  820.  * va_dcl;
  821.  *
  822.  *  DESCRIPTION
  823.  *
  824.  * When invoked via one of the DBUG macros, tests the current keyword
  825.  * set by calling _db_pargs_() to see if that macro has been selected
  826.  * for processing via the debugger control string, and if so, handles
  827.  * printing of the arguments via the format string.  The line number
  828.  * of the DBUG macro in the source is found in u_line.
  829.  *
  830.  * Note that the format string SHOULD NOT include a terminating
  831.  * newline, this is supplied automatically.
  832.  *
  833.  */
  834. #include <stdarg.h>
  835. void _db_doprnt_ (const char *format,...)
  836. {
  837.   va_list args;
  838.   CODE_STATE *state;
  839.   /* Sasha: pre-my_thread_init() safety */
  840.   if (!(state=code_state()))
  841.     return;
  842.   va_start(args,format);
  843.   if (_db_keyword_ (state->u_keyword)) {
  844.     int save_errno=errno;
  845.     if (!state->locked)
  846.       pthread_mutex_lock(&THR_LOCK_dbug);
  847.     DoPrefix (state->u_line);
  848.     if (TRACING) {
  849.       Indent (state->level + 1);
  850.     } else {
  851.       (void) fprintf (_db_fp_, "%s: ", state->func);
  852.     }
  853.     (void) fprintf (_db_fp_, "%s: ", state->u_keyword);
  854.     (void) vfprintf (_db_fp_, format, args);
  855.     (void) fputc('n',_db_fp_);
  856.     dbug_flush(state);
  857.     errno=save_errno;
  858.   }
  859.   va_end(args);
  860. }
  861. /*
  862.  *  FUNCTION
  863.  *
  864.  *       _db_dump_    dump a string until '' is found
  865.  *
  866.  *  SYNOPSIS
  867.  *
  868.  *       void _db_dump_ (_line_,keyword,memory,length)
  869.  *       int _line_; current source line number
  870.  *       char *keyword;
  871.  *       char *memory; Memory to print
  872.  *       int length; Bytes to print
  873.  *
  874.  *  DESCRIPTION
  875.  *  Dump N characters in a binary array.
  876.  *  Is used to examine corrputed memory or arrays.
  877.  */
  878. void _db_dump_(
  879. uint _line_,
  880. const char *keyword,
  881. const char *memory,
  882. uint length)
  883. {
  884.   int pos;
  885.   char dbuff[90];
  886.   CODE_STATE *state;
  887.   if (!(state=code_state()))
  888.     return;
  889.   if (_db_keyword_ ((char*) keyword))
  890.   {
  891.     if (!state->locked)
  892.       pthread_mutex_lock(&THR_LOCK_dbug);
  893.     DoPrefix (_line_);
  894.     if (TRACING)
  895.     {
  896.       Indent (state->level + 1);
  897.       pos= min(max(state->level-stack->sub_level,0)*INDENT,80);
  898.     }
  899.     else
  900.     {
  901.       fprintf(_db_fp_, "%s: ", state->func);
  902.     }
  903.     sprintf(dbuff,"%s: Memory: %lx  Bytes: (%d)n",
  904.     keyword,(ulong) memory, length);
  905.     (void) fputs(dbuff,_db_fp_);
  906.     pos=0;
  907.     while (length-- > 0)
  908.     {
  909.       uint tmp= *((unsigned char*) memory++);
  910.       if ((pos+=3) >= 80)
  911.       {
  912. fputc('n',_db_fp_);
  913. pos=3;
  914.       }
  915.       fputc(_dig_vec_upper[((tmp >> 4) & 15)], _db_fp_);
  916.       fputc(_dig_vec_upper[tmp & 15], _db_fp_);
  917.       fputc(' ',_db_fp_);
  918.     }
  919.     (void) fputc('n',_db_fp_);
  920.     dbug_flush(state);
  921.   }
  922. }
  923. /*
  924.   Enable/Disable output for this thread
  925.   SYNOPSIS
  926.     _db_output_()
  927.     flag 1 = enable output, 0 = disable_output
  928. */
  929. void _db_output_(uint flag)
  930. {
  931.   CODE_STATE *state;
  932.   if (!(state=code_state()))
  933.     return;
  934.   state->disable_output= !flag;
  935. }
  936. /*
  937.  *  FUNCTION
  938.  *
  939.  * ListParse    parse list of modifiers in debug control string
  940.  *
  941.  *  SYNOPSIS
  942.  *
  943.  * static struct link *ListParse (ctlp)
  944.  * char *ctlp;
  945.  *
  946.  *  DESCRIPTION
  947.  *
  948.  * Given pointer to a comma separated list of strings in "cltp",
  949.  * parses the list, building a list and returning a pointer to it.
  950.  * The original comma separated list is destroyed in the process of
  951.  * building the linked list, thus it had better be a duplicate
  952.  * if it is important.
  953.  *
  954.  * Note that since each link is added at the head of the list,
  955.  * the final list will be in "reverse order", which is not
  956.  * significant for our usage here.
  957.  *
  958.  */
  959. static struct link *ListParse (
  960. char *ctlp)
  961. {
  962.   REGISTER char *start;
  963.   REGISTER struct link *new_malloc;
  964.   REGISTER struct link *head;
  965.   head = NULL;
  966.   while (*ctlp != EOS) {
  967.     start = ctlp;
  968.     while (*ctlp != EOS && *ctlp != ',') {
  969.       ctlp++;
  970.     }
  971.     if (*ctlp == ',') {
  972.       *ctlp++ = EOS;
  973.     }
  974.     new_malloc = (struct link *) DbugMalloc (sizeof (struct link));
  975.     new_malloc -> str = StrDup (start);
  976.     new_malloc -> next_link = head;
  977.     head = new_malloc;
  978.   }
  979.   return (head);
  980. }
  981. /*
  982.  *  FUNCTION
  983.  *
  984.  * InList   test a given string for member of a given list
  985.  *
  986.  *  SYNOPSIS
  987.  *
  988.  * static BOOLEAN InList (linkp, cp)
  989.  * struct link *linkp;
  990.  * char *cp;
  991.  *
  992.  *  DESCRIPTION
  993.  *
  994.  * Tests the string pointed to by "cp" to determine if it is in
  995.  * the list pointed to by "linkp".  Linkp points to the first
  996.  * link in the list.  If linkp is NULL then the string is treated
  997.  * as if it is in the list (I.E all strings are in the null list).
  998.  * This may seem rather strange at first but leads to the desired
  999.  * operation if no list is given. The net effect is that all
  1000.  * strings will be accepted when there is no list, and when there
  1001.  * is a list, only those strings in the list will be accepted.
  1002.  *
  1003.  */
  1004. static BOOLEAN InList (
  1005. struct link *linkp,
  1006. const char *cp)
  1007. {
  1008.   REGISTER struct link *scan;
  1009.   REGISTER BOOLEAN result;
  1010.   if (linkp == NULL) {
  1011.     result = TRUE;
  1012.   } else {
  1013.     result = FALSE;
  1014.     for (scan = linkp; scan != NULL; scan = scan -> next_link) {
  1015.       if (STREQ (scan -> str, cp)) {
  1016. result = TRUE;
  1017. break;
  1018.       }
  1019.     }
  1020.   }
  1021.   return (result);
  1022. }
  1023. /*
  1024.  *  FUNCTION
  1025.  *
  1026.  * PushState    push current state onto stack and set up new one
  1027.  *
  1028.  *  SYNOPSIS
  1029.  *
  1030.  * static VOID PushState ()
  1031.  *
  1032.  *  DESCRIPTION
  1033.  *
  1034.  * Pushes the current state on the state stack, and initializes
  1035.  * a new state.  The only parameter inherited from the previous
  1036.  * state is the function nesting level.  This action can be
  1037.  * inhibited if desired, via the "r" flag.
  1038.  *
  1039.  * The state stack is a linked list of states, with the new
  1040.  * state added at the head.  This allows the stack to grow
  1041.  * to the limits of memory if necessary.
  1042.  *
  1043.  */
  1044. static void PushState ()
  1045. {
  1046.   REGISTER struct state *new_malloc;
  1047.   if (!init_done)
  1048.   {
  1049.     init_dbug_state();
  1050.     init_done=TRUE;
  1051.   }
  1052.   (void) code_state(); /* Alloc memory */
  1053.   new_malloc = (struct state *) DbugMalloc(sizeof (struct state));
  1054.   new_malloc -> flags = 0;
  1055.   new_malloc -> delay = 0;
  1056.   new_malloc -> maxdepth = MAXDEPTH;
  1057.   new_malloc -> sub_level=0;
  1058.   new_malloc -> out_file = stderr;
  1059.   new_malloc -> prof_file = (FILE*) 0;
  1060.   new_malloc -> functions = NULL;
  1061.   new_malloc -> p_functions = NULL;
  1062.   new_malloc -> keywords = NULL;
  1063.   new_malloc -> processes = NULL;
  1064.   new_malloc -> next_state = stack;
  1065.   stack=new_malloc;
  1066. }
  1067. /*
  1068.  *  FUNCTION
  1069.  *
  1070.  * DoTrace    check to see if tracing is current enabled
  1071.  *
  1072.  *  SYNOPSIS
  1073.  *
  1074.  * static BOOLEAN DoTrace (stack)
  1075.  *
  1076.  *  DESCRIPTION
  1077.  *
  1078.  * Checks to see if tracing is enabled based on whether the
  1079.  * user has specified tracing, the maximum trace depth has
  1080.  * not yet been reached, the current function is selected,
  1081.  * and the current process is selected.  Returns TRUE if
  1082.  * tracing is enabled, FALSE otherwise.
  1083.  *
  1084.  */
  1085. static BOOLEAN DoTrace (CODE_STATE *state)
  1086. {
  1087.   reg2 BOOLEAN trace=FALSE;
  1088.   if (TRACING && !state->disable_output &&
  1089.       state->level <= stack -> maxdepth &&
  1090.       InList (stack -> functions, state->func) &&
  1091.       InList (stack -> processes, _db_process_))
  1092.       trace = TRUE;
  1093.   return (trace);
  1094. }
  1095. /*
  1096.  *  FUNCTION
  1097.  *
  1098.  * DoProfile    check to see if profiling is current enabled
  1099.  *
  1100.  *  SYNOPSIS
  1101.  *
  1102.  * static BOOLEAN DoProfile ()
  1103.  *
  1104.  *  DESCRIPTION
  1105.  *
  1106.  * Checks to see if profiling is enabled based on whether the
  1107.  * user has specified profiling, the maximum trace depth has
  1108.  * not yet been reached, the current function is selected,
  1109.  * and the current process is selected.  Returns TRUE if
  1110.  * profiling is enabled, FALSE otherwise.
  1111.  *
  1112.  */
  1113. #ifndef THREAD
  1114. static BOOLEAN DoProfile ()
  1115. {
  1116.   REGISTER BOOLEAN profile;
  1117.   CODE_STATE *state;
  1118.   state=code_state();
  1119.   profile = FALSE;
  1120.   if (PROFILING && !state->disable_output &&
  1121.       state->level <= stack -> maxdepth &&
  1122.       InList (stack -> p_functions, state->func) &&
  1123.       InList (stack -> processes, _db_process_))
  1124.     profile = TRUE;
  1125.   return (profile);
  1126. }
  1127. #endif
  1128. /*
  1129.  *  FUNCTION
  1130.  *
  1131.  * _db_keyword_ test keyword for member of keyword list
  1132.  *
  1133.  *  SYNOPSIS
  1134.  *
  1135.  * BOOLEAN _db_keyword_ (keyword)
  1136.  * char *keyword;
  1137.  *
  1138.  *  DESCRIPTION
  1139.  *
  1140.  * Test a keyword to determine if it is in the currently active
  1141.  * keyword list.  As with the function list, a keyword is accepted
  1142.  * if the list is null, otherwise it must match one of the list
  1143.  * members.  When debugging is not on, no keywords are accepted.
  1144.  * After the maximum trace level is exceeded, no keywords are
  1145.  * accepted (this behavior subject to change).  Additionally,
  1146.  * the current function and process must be accepted based on
  1147.  * their respective lists.
  1148.  *
  1149.  * Returns TRUE if keyword accepted, FALSE otherwise.
  1150.  *
  1151.  */
  1152. BOOLEAN _db_keyword_ (
  1153. const char *keyword)
  1154. {
  1155.   REGISTER BOOLEAN result;
  1156.   CODE_STATE *state;
  1157.   if (!init_done)
  1158.     _db_push_ ("");
  1159.   /* Sasha: pre-my_thread_init() safety */
  1160.   if (!(state=code_state()))
  1161.     return FALSE;
  1162.   result = FALSE;
  1163.   if (DEBUGGING && !state->disable_output &&
  1164.       state->level <= stack -> maxdepth &&
  1165.       InList (stack -> functions, state->func) &&
  1166.       InList (stack -> keywords, keyword) &&
  1167.       InList (stack -> processes, _db_process_))
  1168.     result = TRUE;
  1169.   return (result);
  1170. }
  1171. /*
  1172.  *  FUNCTION
  1173.  *
  1174.  * Indent   indent a line to the given indentation level
  1175.  *
  1176.  *  SYNOPSIS
  1177.  *
  1178.  * static VOID Indent (indent)
  1179.  * int indent;
  1180.  *
  1181.  *  DESCRIPTION
  1182.  *
  1183.  * Indent a line to the given level.  Note that this is
  1184.  * a simple minded but portable implementation.
  1185.  * There are better ways.
  1186.  *
  1187.  * Also, the indent must be scaled by the compile time option
  1188.  * of character positions per nesting level.
  1189.  *
  1190.  */
  1191. static void Indent (
  1192. int indent)
  1193. {
  1194.   REGISTER int count;
  1195.   indent= max(indent-1-stack->sub_level,0)*INDENT;
  1196.   for (count = 0; count < indent ; count++)
  1197.   {
  1198.     if ((count % INDENT) == 0)
  1199.       fputc('|',_db_fp_);
  1200.     else
  1201.       fputc(' ',_db_fp_);
  1202.   }
  1203. }
  1204. /*
  1205.  *  FUNCTION
  1206.  *
  1207.  * FreeList    free all memory associated with a linked list
  1208.  *
  1209.  *  SYNOPSIS
  1210.  *
  1211.  * static VOID FreeList (linkp)
  1212.  * struct link *linkp;
  1213.  *
  1214.  *  DESCRIPTION
  1215.  *
  1216.  * Given pointer to the head of a linked list, frees all
  1217.  * memory held by the list and the members of the list.
  1218.  *
  1219.  */
  1220. static void FreeList (
  1221. struct link *linkp)
  1222. {
  1223.   REGISTER struct link *old;
  1224.   while (linkp != NULL) {
  1225.     old = linkp;
  1226.     linkp = linkp -> next_link;
  1227.     if (old -> str != NULL) {
  1228.       free (old -> str);
  1229.     }
  1230.     free ((char *) old);
  1231.   }
  1232. }
  1233. /*
  1234.  *  FUNCTION
  1235.  *
  1236.  * StrDup  make a duplicate of a string in new memory
  1237.  *
  1238.  *  SYNOPSIS
  1239.  *
  1240.  * static char *StrDup (my_string)
  1241.  * char *string;
  1242.  *
  1243.  *  DESCRIPTION
  1244.  *
  1245.  * Given pointer to a string, allocates sufficient memory to make
  1246.  * a duplicate copy, and copies the string to the newly allocated
  1247.  * memory.  Failure to allocated sufficient memory is immediately
  1248.  * fatal.
  1249.  *
  1250.  */
  1251. static char *StrDup (const char *str)
  1252. {
  1253.     reg1 char *new_malloc;
  1254.     new_malloc = DbugMalloc((size_t) strlen (str) + 1);
  1255.     (void) strcpy (new_malloc, str);
  1256.     return (new_malloc);
  1257. }
  1258. /*
  1259.  *  FUNCTION
  1260.  *
  1261.  * DoPrefix    print debugger line prefix prior to indentation
  1262.  *
  1263.  *  SYNOPSIS
  1264.  *
  1265.  * static VOID DoPrefix (_line_)
  1266.  * int _line_;
  1267.  *
  1268.  *  DESCRIPTION
  1269.  *
  1270.  * Print prefix common to all debugger output lines, prior to
  1271.  * doing indentation if necessary.  Print such information as
  1272.  * current process name, current source file name and line number,
  1273.  * and current function nesting depth.
  1274.  *
  1275.  */
  1276. static void DoPrefix (
  1277. uint _line_)
  1278. {
  1279.   CODE_STATE *state;
  1280.   state=code_state();
  1281.   state->lineno++;
  1282.   if (stack -> flags & PID_ON) {
  1283. #ifdef THREAD
  1284.     (void) fprintf (_db_fp_, "%-7s: ", my_thread_name());
  1285. #else
  1286.     (void) fprintf (_db_fp_, "%5d: ", (int) getpid ());
  1287. #endif
  1288.   }
  1289.   if (stack -> flags & NUMBER_ON) {
  1290.     (void) fprintf (_db_fp_, "%5d: ", state->lineno);
  1291.   }
  1292.   if (stack -> flags & PROCESS_ON) {
  1293.     (void) fprintf (_db_fp_, "%s: ", _db_process_);
  1294.   }
  1295.   if (stack -> flags & FILE_ON) {
  1296.     (void) fprintf (_db_fp_, "%14s: ", BaseName(state->file));
  1297.   }
  1298.   if (stack -> flags & LINE_ON) {
  1299.     (void) fprintf (_db_fp_, "%5d: ", _line_);
  1300.   }
  1301.   if (stack -> flags & DEPTH_ON) {
  1302.     (void) fprintf (_db_fp_, "%4d: ", state->level);
  1303.   }
  1304. }
  1305. /*
  1306.  *  FUNCTION
  1307.  *
  1308.  * DBUGOpenFile open new output stream for debugger output
  1309.  *
  1310.  *  SYNOPSIS
  1311.  *
  1312.  * static VOID DBUGOpenFile (name)
  1313.  * char *name;
  1314.  *
  1315.  *  DESCRIPTION
  1316.  *
  1317.  * Given name of a new file (or "-" for stdout) opens the file
  1318.  * and sets the output stream to the new file.
  1319.  *
  1320.  */
  1321. static void DBUGOpenFile (const char *name,int append)
  1322. {
  1323.   REGISTER FILE *fp;
  1324.   REGISTER BOOLEAN newfile;
  1325.   if (name != NULL)
  1326.   {
  1327.     strmov(stack->name,name);
  1328.     if (strcmp (name, "-") == 0)
  1329.     {
  1330.       _db_fp_ = stdout;
  1331.       stack -> out_file = _db_fp_;
  1332.       stack -> flags |= FLUSH_ON_WRITE;
  1333.     }
  1334.     else
  1335.     {
  1336.       if (!Writable((char*)name))
  1337.       {
  1338. (void) fprintf (stderr, ERR_OPEN, _db_process_, name);
  1339. perror ("");
  1340. fflush(stderr);
  1341.       }
  1342.       else
  1343.       {
  1344. newfile= !EXISTS (name);
  1345. if (!(fp = fopen(name, append ? "a+" : "w")))
  1346. {
  1347.   (void) fprintf (stderr, ERR_OPEN, _db_process_, name);
  1348.   perror ("");
  1349.   fflush(stderr);
  1350. }
  1351. else
  1352. {
  1353.   _db_fp_ = fp;
  1354.   stack -> out_file = fp;
  1355.   if (newfile) {
  1356.     ChangeOwner (name);
  1357.   }
  1358. }
  1359.       }
  1360.     }
  1361.   }
  1362. }
  1363. /*
  1364.  *  FUNCTION
  1365.  *
  1366.  * OpenProfile    open new output stream for profiler output
  1367.  *
  1368.  *  SYNOPSIS
  1369.  *
  1370.  * static FILE *OpenProfile (name)
  1371.  * char *name;
  1372.  *
  1373.  *  DESCRIPTION
  1374.  *
  1375.  * Given name of a new file, opens the file
  1376.  * and sets the profiler output stream to the new file.
  1377.  *
  1378.  * It is currently unclear whether the prefered behavior is
  1379.  * to truncate any existing file, or simply append to it.
  1380.  * The latter behavior would be desirable for collecting
  1381.  * accumulated runtime history over a number of separate
  1382.  * runs.  It might take some changes to the analyzer program
  1383.  * though, and the notes that Binayak sent with the profiling
  1384.  * diffs indicated that append was the normal mode, but this
  1385.  * does not appear to agree with the actual code. I haven't
  1386.  * investigated at this time [fnf; 24-Jul-87].
  1387.  */
  1388. #ifndef THREAD
  1389. static FILE *OpenProfile (const char *name)
  1390. {
  1391.   REGISTER FILE *fp;
  1392.   REGISTER BOOLEAN newfile;
  1393.   fp=0;
  1394.   if (!Writable (name))
  1395.   {
  1396.     (void) fprintf (_db_fp_, ERR_OPEN, _db_process_, name);
  1397.     perror ("");
  1398.     dbug_flush(0);
  1399.     (void) Delay (stack -> delay);
  1400.   }
  1401.   else
  1402.   {
  1403.     newfile= !EXISTS (name);
  1404.     if (!(fp = fopen (name, "w")))
  1405.     {
  1406.       (void) fprintf (_db_fp_, ERR_OPEN, _db_process_, name);
  1407.       perror ("");
  1408.       dbug_flush(0);
  1409.     }
  1410.     else
  1411.     {
  1412.       _db_pfp_ = fp;
  1413.       stack -> prof_file = fp;
  1414.       if (newfile)
  1415.       {
  1416. ChangeOwner (name);
  1417.       }
  1418.     }
  1419.   }
  1420.   return fp;
  1421. }
  1422. #endif
  1423. /*
  1424.  *  FUNCTION
  1425.  *
  1426.  * CloseFile    close the debug output stream
  1427.  *
  1428.  *  SYNOPSIS
  1429.  *
  1430.  * static VOID CloseFile (fp)
  1431.  * FILE *fp;
  1432.  *
  1433.  *  DESCRIPTION
  1434.  *
  1435.  * Closes the debug output stream unless it is standard output
  1436.  * or standard error.
  1437.  *
  1438.  */
  1439. static void CloseFile (
  1440. FILE *fp)
  1441. {
  1442.   if (fp != stderr && fp != stdout) {
  1443.     if (fclose (fp) == EOF) {
  1444.       pthread_mutex_lock(&THR_LOCK_dbug);
  1445.       (void) fprintf (_db_fp_, ERR_CLOSE, _db_process_);
  1446.       perror ("");
  1447.       dbug_flush(0);
  1448.     }
  1449.   }
  1450. }
  1451. /*
  1452.  *  FUNCTION
  1453.  *
  1454.  * DbugExit    print error message and exit
  1455.  *
  1456.  *  SYNOPSIS
  1457.  *
  1458.  * static VOID DbugExit (why)
  1459.  * char *why;
  1460.  *
  1461.  *  DESCRIPTION
  1462.  *
  1463.  * Prints error message using current process name, the reason for
  1464.  * aborting (typically out of memory), and exits with status 1.
  1465.  * This should probably be changed to use a status code
  1466.  * defined in the user's debugger include file.
  1467.  *
  1468.  */
  1469. static void DbugExit (const char *why)
  1470. {
  1471.   (void) fprintf (stderr, ERR_ABORT, _db_process_, why);
  1472.   (void) fflush (stderr);
  1473.   exit (1);
  1474. }
  1475. /*
  1476.  *  FUNCTION
  1477.  *
  1478.  * DbugMalloc    allocate memory for debugger runtime support
  1479.  *
  1480.  *  SYNOPSIS
  1481.  *
  1482.  * static long *DbugMalloc (size)
  1483.  * int size;
  1484.  *
  1485.  *  DESCRIPTION
  1486.  *
  1487.  * Allocate more memory for debugger runtime support functions.
  1488.  * Failure to to allocate the requested number of bytes is
  1489.  * immediately fatal to the current process.  This may be
  1490.  * rather unfriendly behavior.  It might be better to simply
  1491.  * print a warning message, freeze the current debugger state,
  1492.  * and continue execution.
  1493.  *
  1494.  */
  1495. static char *DbugMalloc (size_t size)
  1496. {
  1497.   register char *new_malloc;
  1498.   if (!(new_malloc = (char*) malloc((size_t) size)))
  1499.     DbugExit ("out of memory");
  1500.   return (new_malloc);
  1501. }
  1502. /*
  1503.  * As strtok but two separators in a row are changed to one
  1504.  * separator (to allow directory-paths in dos).
  1505.  */
  1506. static char *static_strtok (char *s1, pchar separator)
  1507. {
  1508.   static char *end = NULL;
  1509.   reg1 char *rtnval,*cpy;
  1510.   rtnval = NULL;
  1511.   if (s1 != NULL)
  1512.     end = s1;
  1513.   if (end != NULL && *end != EOS)
  1514.   {
  1515.     rtnval=cpy=end;
  1516.     do
  1517.     {
  1518.       if ((*cpy++ = *end++) == separator)
  1519.       {
  1520. if (*end != separator)
  1521. {
  1522.   cpy--; /* Point at separator */
  1523.   break;
  1524. }
  1525. end++; /* Two separators in a row, skip one */
  1526.       }
  1527.     } while (*end != EOS);
  1528.     *cpy=EOS; /* Replace last separator */
  1529.   }
  1530.   return (rtnval);
  1531. }
  1532. /*
  1533.  *  FUNCTION
  1534.  *
  1535.  * BaseName    strip leading pathname components from name
  1536.  *
  1537.  *  SYNOPSIS
  1538.  *
  1539.  * static char *BaseName (pathname)
  1540.  * char *pathname;
  1541.  *
  1542.  *  DESCRIPTION
  1543.  *
  1544.  * Given pointer to a complete pathname, locates the base file
  1545.  * name at the end of the pathname and returns a pointer to
  1546.  * it.
  1547.  *
  1548.  */
  1549. static char *BaseName (const char *pathname)
  1550. {
  1551.   register const char *base;
  1552.   base = strrchr (pathname, FN_LIBCHAR);
  1553.   if (base++ == NullS)
  1554.     base = pathname;
  1555.   return ((char*) base);
  1556. }
  1557. /*
  1558.  *  FUNCTION
  1559.  *
  1560.  * Writable    test to see if a pathname is writable/creatable
  1561.  *
  1562.  *  SYNOPSIS
  1563.  *
  1564.  * static BOOLEAN Writable (pathname)
  1565.  * char *pathname;
  1566.  *
  1567.  *  DESCRIPTION
  1568.  *
  1569.  * Because the debugger might be linked in with a program that
  1570.  * runs with the set-uid-bit (suid) set, we have to be careful
  1571.  * about opening a user named file for debug output.  This consists
  1572.  * of checking the file for write access with the real user id,
  1573.  * or checking the directory where the file will be created.
  1574.  *
  1575.  * Returns TRUE if the user would normally be allowed write or
  1576.  * create access to the named file.  Returns FALSE otherwise.
  1577.  *
  1578.  */
  1579. #ifndef Writable
  1580. static BOOLEAN Writable (
  1581. char *pathname)
  1582. {
  1583.   REGISTER BOOLEAN granted;
  1584.   REGISTER char *lastslash;
  1585.   granted = FALSE;
  1586.   if (EXISTS (pathname)) {
  1587.     if (WRITABLE (pathname)) {
  1588.       granted = TRUE;
  1589.     }
  1590.   } else {
  1591.     lastslash = strrchr (pathname, '/');
  1592.     if (lastslash != NULL) {
  1593.       *lastslash = EOS;
  1594.     } else {
  1595.       pathname = ".";
  1596.     }
  1597.     if (WRITABLE (pathname)) {
  1598.       granted = TRUE;
  1599.     }
  1600.     if (lastslash != NULL) {
  1601.       *lastslash = '/';
  1602.     }
  1603.   }
  1604.   return (granted);
  1605. }
  1606. #endif
  1607. /*
  1608.  *  FUNCTION
  1609.  *
  1610.  * ChangeOwner    change owner to real user for suid programs
  1611.  *
  1612.  *  SYNOPSIS
  1613.  *
  1614.  * static VOID ChangeOwner (pathname)
  1615.  *
  1616.  *  DESCRIPTION
  1617.  *
  1618.  * For unix systems, change the owner of the newly created debug
  1619.  * file to the real owner.  This is strictly for the benefit of
  1620.  * programs that are running with the set-user-id bit set.
  1621.  *
  1622.  * Note that at this point, the fact that pathname represents
  1623.  * a newly created file has already been established.  If the
  1624.  * program that the debugger is linked to is not running with
  1625.  * the suid bit set, then this operation is redundant (but
  1626.  * harmless).
  1627.  *
  1628.  */
  1629. #ifndef ChangeOwner
  1630. static void ChangeOwner (
  1631. char *pathname)
  1632. {
  1633.   if (chown (pathname, getuid (), getgid ()) == -1)
  1634.   {
  1635.     (void) fprintf (stderr, ERR_CHOWN, _db_process_, pathname);
  1636.     perror ("");
  1637.     (void) fflush (stderr);
  1638.   }
  1639. }
  1640. #endif
  1641. /*
  1642.  *  FUNCTION
  1643.  *
  1644.  * _db_setjmp_    save debugger environment
  1645.  *
  1646.  *  SYNOPSIS
  1647.  *
  1648.  * VOID _db_setjmp_ ()
  1649.  *
  1650.  *  DESCRIPTION
  1651.  *
  1652.  * Invoked as part of the user's DBUG_SETJMP macro to save
  1653.  * the debugger environment in parallel with saving the user's
  1654.  * environment.
  1655.  *
  1656.  */
  1657. #ifdef HAVE_LONGJMP
  1658. EXPORT void _db_setjmp_ ()
  1659. {
  1660.   CODE_STATE *state;
  1661.   state=code_state();
  1662.   state->jmplevel = state->level;
  1663.   state->jmpfunc = state->func;
  1664.   state->jmpfile = state->file;
  1665. }
  1666. /*
  1667.  *  FUNCTION
  1668.  *
  1669.  * _db_longjmp_ restore previously saved debugger environment
  1670.  *
  1671.  *  SYNOPSIS
  1672.  *
  1673.  * VOID _db_longjmp_ ()
  1674.  *
  1675.  *  DESCRIPTION
  1676.  *
  1677.  * Invoked as part of the user's DBUG_LONGJMP macro to restore
  1678.  * the debugger environment in parallel with restoring the user's
  1679.  * previously saved environment.
  1680.  *
  1681.  */
  1682. EXPORT void _db_longjmp_ ()
  1683. {
  1684.   CODE_STATE *state;
  1685.   state=code_state();
  1686.   state->level = state->jmplevel;
  1687.   if (state->jmpfunc) {
  1688.     state->func = state->jmpfunc;
  1689.   }
  1690.   if (state->jmpfile) {
  1691.     state->file = state->jmpfile;
  1692.   }
  1693. }
  1694. #endif
  1695. /*
  1696.  *  FUNCTION
  1697.  *
  1698.  * DelayArg   convert D flag argument to appropriate value
  1699.  *
  1700.  *  SYNOPSIS
  1701.  *
  1702.  * static int DelayArg (value)
  1703.  * int value;
  1704.  *
  1705.  *  DESCRIPTION
  1706.  *
  1707.  * Converts delay argument, given in tenths of a second, to the
  1708.  * appropriate numerical argument used by the system to delay
  1709.  * that that many tenths of a second.  For example, on the
  1710.  * amiga, there is a system call "Delay()" which takes an
  1711.  * argument in ticks (50 per second).  On unix, the sleep
  1712.  * command takes seconds. Thus a value of "10", for one
  1713.  * second of delay, gets converted to 50 on the amiga, and 1
  1714.  * on unix.  Other systems will need to use a timing loop.
  1715.  *
  1716.  */
  1717. #ifdef AMIGA
  1718. #define HZ (50)       /* Probably in some header somewhere */
  1719. #endif
  1720. static int DelayArg (
  1721. int value)
  1722. {
  1723.   uint delayarg = 0;
  1724. #if (unix || xenix)
  1725.   delayarg = value / 10; /* Delay is in seconds for sleep () */
  1726. #endif
  1727. #ifdef AMIGA
  1728.   delayarg = (HZ * value) / 10; /* Delay in ticks for Delay () */
  1729. #endif
  1730.   return (delayarg);
  1731. }
  1732. /*
  1733.  * A dummy delay stub for systems that do not support delays.
  1734.  * With a little work, this can be turned into a timing loop.
  1735.  */
  1736. #if ! defined(Delay) && ! defined(AMIGA)
  1737. static int Delay (
  1738. int ticks)
  1739. {
  1740.   return ticks;
  1741. }
  1742. #endif
  1743. /*
  1744.  *  FUNCTION
  1745.  *
  1746.  * perror   perror simulation for systems that don't have it
  1747.  *
  1748.  *  SYNOPSIS
  1749.  *
  1750.  * static VOID perror (s)
  1751.  * char *s;
  1752.  *
  1753.  *  DESCRIPTION
  1754.  *
  1755.  * Perror produces a message on the standard error stream which
  1756.  * provides more information about the library or system error
  1757.  * just encountered.  The argument string s is printed, followed
  1758.  * by a ':', a blank, and then a message and a newline.
  1759.  *
  1760.  * An undocumented feature of the unix perror is that if the string
  1761.  * 's' is a null string (NOT a NULL pointer!), then the ':' and
  1762.  * blank are not printed.
  1763.  *
  1764.  * This version just complains about an "unknown system error".
  1765.  *
  1766.  */
  1767. #ifndef HAVE_PERROR
  1768. static void perror (s)
  1769. char *s;
  1770. {
  1771.   if (s && *s != EOS) {
  1772.     (void) fprintf (stderr, "%s: ", s);
  1773.   }
  1774.   (void) fprintf (stderr, "<unknown system error>n");
  1775. }
  1776. #endif /* HAVE_PERROR */
  1777. /* flush dbug-stream, free mutex lock & wait delay */
  1778. /* This is because some systems (MSDOS!!) dosn't flush fileheader */
  1779. /* and dbug-file isn't readable after a system crash !! */
  1780. static void dbug_flush(CODE_STATE *state)
  1781. {
  1782. #ifndef THREAD
  1783.   if (stack->flags & FLUSH_ON_WRITE)
  1784. #endif
  1785.   {
  1786. #if defined(MSDOS) || defined(__WIN__)
  1787.     if (_db_fp_ != stdout && _db_fp_ != stderr)
  1788.     {
  1789.       if (!(freopen(stack->name,"a",_db_fp_)))
  1790.       {
  1791. (void) fprintf(stderr, ERR_OPEN, _db_process_, stack->name);
  1792. fflush(stderr);
  1793. _db_fp_ = stdout;
  1794. stack -> out_file = _db_fp_;
  1795. stack -> flags|=FLUSH_ON_WRITE;
  1796.       }
  1797.     }
  1798.     else
  1799. #endif
  1800.     {
  1801.       (void) fflush (_db_fp_);
  1802.       if (stack->delay)
  1803. (void) Delay (stack->delay);
  1804.     }
  1805.   }
  1806.   if (!state || !state->locked)
  1807.     pthread_mutex_unlock(&THR_LOCK_dbug);
  1808. } /* dbug_flush */
  1809. void _db_lock_file()
  1810. {
  1811.   CODE_STATE *state;
  1812.   state=code_state();
  1813.   pthread_mutex_lock(&THR_LOCK_dbug);
  1814.   state->locked=1;
  1815. }
  1816. void _db_unlock_file()
  1817. {
  1818.   CODE_STATE *state;
  1819.   state=code_state();
  1820.   state->locked=0;
  1821.   pthread_mutex_unlock(&THR_LOCK_dbug);
  1822. }
  1823. /*
  1824.  * Here we need the definitions of the clock routine.  Add your
  1825.  * own for whatever system that you have.
  1826.  */
  1827. #ifndef THREAD
  1828. #if defined(HAVE_GETRUSAGE)
  1829. #include <sys/param.h>
  1830. #include <sys/resource.h>
  1831. /* extern int getrusage(int, struct rusage *); */
  1832. /*
  1833.  * Returns the user time in milliseconds used by this process so
  1834.  * far.
  1835.  */
  1836. static unsigned long Clock ()
  1837. {
  1838.     struct rusage ru;
  1839.     (void) getrusage (RUSAGE_SELF, &ru);
  1840.     return ((ru.ru_utime.tv_sec * 1000) + (ru.ru_utime.tv_usec / 1000));
  1841. }
  1842. #elif defined(MSDOS) || defined(__WIN__) || defined(OS2)
  1843. static ulong Clock()
  1844. {
  1845.   return clock()*(1000/CLOCKS_PER_SEC);
  1846. }
  1847. #elif defined (amiga)
  1848. struct DateStamp { /* Yes, this is a hack, but doing it right */
  1849. long ds_Days; /* is incredibly ugly without splitting this */
  1850. long ds_Minute; /* off into a separate file */
  1851. long ds_Tick;
  1852. };
  1853. static int first_clock = TRUE;
  1854. static struct DateStamp begin;
  1855. static struct DateStamp elapsed;
  1856. static unsigned long Clock ()
  1857. {
  1858.     register struct DateStamp *now;
  1859.     register unsigned long millisec = 0;
  1860.     extern VOID *AllocMem ();
  1861.     now = (struct DateStamp *) AllocMem ((long) sizeof (struct DateStamp), 0L);
  1862.     if (now != NULL) {
  1863. if (first_clock == TRUE) {
  1864.     first_clock = FALSE;
  1865.     (void) DateStamp (now);
  1866.     begin = *now;
  1867. }
  1868. (void) DateStamp (now);
  1869. millisec = 24 * 3600 * (1000 / HZ) * (now -> ds_Days - begin.ds_Days);
  1870. millisec += 60 * (1000 / HZ) * (now -> ds_Minute - begin.ds_Minute);
  1871. millisec += (1000 / HZ) * (now -> ds_Tick - begin.ds_Tick);
  1872. (void) FreeMem (now, (long) sizeof (struct DateStamp));
  1873.     }
  1874.     return (millisec);
  1875. }
  1876. #else
  1877. static unsigned long Clock ()
  1878. {
  1879.     return (0);
  1880. }
  1881. #endif /* RUSAGE */
  1882. #endif /* THREADS */
  1883. #ifdef NO_VARARGS
  1884. /*
  1885.  * Fake vfprintf for systems that don't support it.  If this
  1886.  * doesn't work, you are probably SOL...
  1887.  */
  1888. static int vfprintf (stream, format, ap)
  1889. FILE *stream;
  1890. char *format;
  1891. va_list ap;
  1892. {
  1893.     int rtnval;
  1894.     ARGS_DCL;
  1895.     ARG0 =  va_arg (ap, ARGS_TYPE);
  1896.     ARG1 =  va_arg (ap, ARGS_TYPE);
  1897.     ARG2 =  va_arg (ap, ARGS_TYPE);
  1898.     ARG3 =  va_arg (ap, ARGS_TYPE);
  1899.     ARG4 =  va_arg (ap, ARGS_TYPE);
  1900.     ARG5 =  va_arg (ap, ARGS_TYPE);
  1901.     ARG6 =  va_arg (ap, ARGS_TYPE);
  1902.     ARG7 =  va_arg (ap, ARGS_TYPE);
  1903.     ARG8 =  va_arg (ap, ARGS_TYPE);
  1904.     ARG9 =  va_arg (ap, ARGS_TYPE);
  1905.     rtnval = fprintf (stream, format, ARGS_LIST);
  1906.     return (rtnval);
  1907. }
  1908. #endif /* NO_VARARGS */