dbug.c
上传用户:jmzj888
上传日期:2007-01-02
资源大小:220k
文件大小:48k
源码类别:

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