📄 dbug.c
字号:
/****************************************************************************** * * * N O T I C E * * * * Copyright Abandoned, 1987, Fred Fish * * * * * * This previously copyrighted work has been placed into the public * * domain by the author and may be freely used for any purpose, * * private or commercial. * * * * Because of the number of inquiries I was receiving about the use * * of this product in commercially developed works I have decided to * * simply make it public domain to further its unrestricted use. I * * specifically would be most happy to see this material become a * * part of the standard Unix distributions by AT&T and the Berkeley * * Computer Science Research Group, and a standard part of the GNU * * system from the Free Software Foundation. * * * * I would appreciate it, as a courtesy, if this notice is left in * * all copies and derivative works. Thank you. * * * * The author makes no warranty of any kind with respect to this * * product and explicitly disclaims any implied warranties of mer- * * chantability or fitness for any particular purpose. * * * ****************************************************************************** *//* * FILE * * dbug.c runtime support routines for dbug package * * SCCS * * @(#)dbug.c 1.25 7/25/89 * * DESCRIPTION * * These are the runtime support routines for the dbug package. * The dbug package has two main components; the user include * file containing various macro definitions, and the runtime * support routines which are called from the macro expansions. * * Externally visible functions in the runtime support module * use the naming convention pattern "_db_xx...xx_", thus * they are unlikely to collide with user defined function names. * * AUTHOR(S) * * Fred Fish (base code) * Enhanced Software Technologies, Tempe, AZ * asuvax!mcdphx!estinc!fnf * * Binayak Banerjee (profiling enhancements) * seismo!bpa!sjuvax!bbanerje * * Michael Widenius: * DBUG_DUMP - To dump a pice of memory. * PUSH_FLAG "O" - To be used insted of "o" if we don't * want flushing (for slow systems) * Check of malloc on entry/exit (option "S") */#ifdef DBUG_OFF#undef DBUG_OFF#endif#include "..\include\global.h"#include "..\include\m_string.h"#if defined(MSDOS) || defined(__WIN32__)#include <process.h>#endif#ifdef _DBUG_CONDITION_#define _DBUG_START_CONDITION_ "d:t"#else#define _DBUG_START_CONDITION_ ""#endif/* * Manifest constants that should not require any changes. */#define EOS '\000' /* End Of String marker *//* * Manifest constants which may be "tuned" if desired. */#define PRINTBUF 1024 /* Print buffer size */#define INDENT 2 /* Indentation per trace level */#define MAXDEPTH 200 /* Maximum trace depth default *//* * The following flags are used to determine which * capabilities the user has enabled with the state * push macro. */#define TRACE_ON 000001 /* Trace enabled */#define DEBUG_ON 000002 /* Debug enabled */#define FILE_ON 000004 /* File name print enabled */#define LINE_ON 000010 /* Line number print enabled */#define DEPTH_ON 000020 /* Function nest level print enabled */#define PROCESS_ON 000040 /* Process name print enabled */#define NUMBER_ON 000100 /* Number each line of output */#define PROFILE_ON 000200 /* Print out profiling code */#define PID_ON 000400 /* Identify each line with process id */#define SANITY_CHECK_ON 001000 /* Check safemalloc on DBUG_ENTER */#define FLUSH_ON_WRITE 002000 /* Flush on every write */#define TRACING (stack -> flags & TRACE_ON)#define DEBUGGING (stack -> flags & DEBUG_ON)#define PROFILING (stack -> flags & PROFILE_ON)#define STREQ(a,b) (strcmp(a,b) == 0)/* * Typedefs to make things more obvious. */#ifndef __WIN32__typedef int BOOLEAN;#else#define BOOLEAN BOOL#endif/* * Make it easy to change storage classes if necessary. */#define IMPORT extern /* Names defined externally */#define EXPORT /* Allocated here, available globally */#define AUTO auto /* Names to be allocated on stack */#define REGISTER register /* Names to be placed in registers *//* * The default file for profiling. Could also add another flag * (G?) which allowed the user to specify this. * * If the automatic variables get allocated on the stack in * reverse order from their declarations, then define AUTOS_REVERSE. * This is used by the code that keeps track of stack usage. For * forward allocation, the difference in the dbug frame pointers * represents stack used by the callee function. For reverse allocation, * the difference represents stack used by the caller function. * */#define PROF_FILE "dbugmon.out"#define PROF_EFMT "E\t%ld\t%s\n"#define PROF_SFMT "S\t%lx\t%lx\t%s\n"#define PROF_XFMT "X\t%ld\t%s\n"#ifdef M_I386 /* predefined by xenix 386 compiler */#define AUTOS_REVERSE 1#endif/* * Variables which are available externally but should only * be accessed via the macro package facilities. */EXPORT FILE *_db_fp_ = (FILE *) 0; /* Output stream, default stderr */EXPORT char *_db_process_ = "dbug"; /* Pointer to process name; argv[0] */EXPORT FILE *_db_pfp_ = (FILE *)0; /* Profile stream, 'dbugmon.out' */EXPORT BOOLEAN _db_on_ = FALSE; /* TRUE if debugging currently on */EXPORT BOOLEAN _db_pon_ = FALSE; /* TRUE if profile currently on */EXPORT BOOLEAN _no_db_ = FALSE; /* TRUE if no debugging at all *//* * Externally supplied functions. */#ifndef HAVE_PERRORstatic void perror (); /* Fake system/library error print routine */#endifIMPORT int _sanity(const char *file,uint line);/* * The user may specify a list of functions to trace or * debug. These lists are kept in a linear linked list, * a very simple implementation. */struct link { char *str; /* Pointer to link's contents */ struct link *next_link; /* Pointer to the next link */};/* * Debugging states can be pushed or popped off of a * stack which is implemented as a linked list. Note * that the head of the list is the current state and the * stack is pushed by adding a new state to the head of the * list or popped by removing the first link. */struct state { int flags; /* Current state flags */ int maxdepth; /* Current maximum trace depth */ uint delay; /* Delay after each output line */ int sub_level; /* Sub this from code_state->level */ FILE *out_file; /* Current output stream */ FILE *prof_file; /* Current profiling stream */ char name[FN_REFLEN]; /* Name of output file */ struct link *functions; /* List of functions */ struct link *p_functions; /* List of profiled functions */ struct link *keywords; /* List of debug keywords */ struct link *processes; /* List of process names */ struct state *next_state; /* Next state in the list */};/* * Local variables not seen by user. */static my_bool init_done = FALSE; /* Set to TRUE when initialization done */static struct state *stack=0;typedef struct st_code_state { int lineno; /* Current debugger output line number */ int level; /* Current function nesting level */ char *func; /* Name of current user function */ char *file; /* Name of current user file */ char **framep; /* Pointer to current frame */ int jmplevel; /* Remember nesting level at setjmp () */ char *jmpfunc; /* Remember current function for setjmp */ char *jmpfile; /* Remember current file for setjmp *//* * The following variables are used to hold the state information * between the call to _db_pargs_() and _db_doprnt_(), during * expansion of the DBUG_PRINT macro. This is the only macro * that currently uses these variables. * * These variables are currently used only by _db_pargs_() and * _db_doprnt_(). */ uint u_line; /* User source code line number */ char *u_keyword; /* Keyword for current macro */} CODE_STATE; /* Parse a debug command string */static struct link *ListParse(char *ctlp); /* Make a fresh copy of a string */static char *StrDup(const char *str); /* Open debug output stream */static void DBUGOpenFile(char *name);#ifndef THREAD /* Open profile output stream */static FILE *OpenProfile(char *name); /* Profile if asked for it */static BOOLEAN DoProfile(void); /* Return current user time (ms) */static unsigned long Clock (void);#endif /* Close debug output stream */static void CloseFile(FILE *fp); /* Push current debug state */static void PushState(void); /* Change file owner and group */static void ChangeOwner(char *pathname); /* Test for tracing enabled */static BOOLEAN DoTrace(CODE_STATE *state); /* Test to see if file is writable */static BOOLEAN Writable(char *pathname); /* Allocate memory for runtime support */static char *DbugMalloc(int size); /* Remove leading pathname components */static char *BaseName(char *pathname);static void DoPrefix(uint line);static void FreeList(struct link *linkp);static void Indent(int indent);static BOOLEAN InList(struct link *linkp,char *cp);static void dbug_flush(void);static void DbugExit(char *why);static int DelayArg(int value); /* Supplied in Sys V runtime environ */ /* Break string into tokens */static char *static_strtok(char *s1,pchar chr);/* * Miscellaneous printf format strings. */#define ERR_MISSING_RETURN "%s: missing DBUG_RETURN or DBUG_VOID_RETURN macro in function \"%s\"\n"#define ERR_OPEN "%s: can't open debug output stream \"%s\": "#define ERR_CLOSE "%s: can't close debug file: "#define ERR_ABORT "%s: debugger aborting because %s\n"#define ERR_CHOWN "%s: can't change owner/group of \"%s\": "/* * Macros and defines for testing file accessibility under UNIX and MSDOS. */#if !defined(HAVE_ACCESS) || defined(MSDOS)#define EXISTS(pathname) (FALSE) /* Assume no existance */#define Writable(name) (TRUE)#define ChangeOwner(name)#else#define EXISTS(pathname) (access (pathname, F_OK) == 0)#define WRITABLE(pathname) (access (pathname, W_OK) == 0)#endif/* * Translate some calls among different systems. */#if defined(unix) || defined(xenix) || defined(VMS)# define Delay(A) sleep((uint) A)IMPORT unsigned sleep (); /* Pause for given number of seconds */#else#if defined(AMIGA)IMPORT int Delay (); /* Pause for given number of ticks */#elsestatic int Delay(int ticks);#endif#endif/*** Macros to allow dbugging with threads*/#ifdef THREAD#include <my_pthread.h>pthread_mutex_t THR_LOCK_dbug;#ifndef __WIN32__static pthread_key(CODE_STATE,THR_KEY_dbug_state);static void init_dbug_state(void){ pthread_key_create(&THR_KEY_dbug_state,free); pthread_mutex_init(&THR_LOCK_dbug,NULL);}static CODE_STATE *code_state(void){ CODE_STATE *state; if (!(state=my_pthread_getspecific(CODE_STATE*,THR_KEY_dbug_state))) { state=(CODE_STATE*) DbugMalloc(sizeof(*state)); bzero(state,sizeof(*state)); state->func="?func"; state->file="?file"; pthread_setspecific(THR_KEY_dbug_state,(void*) state); } return state;}#else /* __WIN32__ */static void init_dbug_state(void){ pthread_mutex_init(&THR_LOCK_dbug,NULL);}__declspec( thread ) static CODE_STATE static_code_state ={ 0,0,"?func","?file",NULL,0,NULL,NULL,0,"?"};#define code_state() (&static_code_state)#endif /* __WIN32__ */#else /* !THREAD */#define init_dbug_state()#define code_state() (&static_code_state)#define pthread_mutex_lock(A)#define pthread_mutex_unlock(A)static CODE_STATE static_code_state = { 0,0,"?func","?file",NULL,0,NULL, NULL,0,"?"};#endif/* * FUNCTION * * _db_push_ push current debugger state and set up new one * * SYNOPSIS * * VOID _db_push_ (control) * char *control; * * DESCRIPTION * * Given pointer to a debug control string in "control", pushes * the current debug state, parses the control string, and sets * up a new debug state. * * The only attribute of the new state inherited from the previous * state is the current function nesting level. This can be * overridden by using the "r" flag in the control string. * * The debug control string is a sequence of colon separated fields * as follows: * * <field_1>:<field_2>:...:<field_N> * * Each field consists of a mandatory flag character followed by * an optional "," and comma separated list of modifiers: * * flag[,modifier,modifier,...,modifier] * * The currently recognized flag characters are: * * d Enable output from DBUG_<N> macros for * for the current state. May be followed * by a list of keywords which selects output * only for the DBUG macros with that keyword. * A null list of keywords implies output for * all macros. * * D Delay after each debugger output line. * The argument is the number of tenths of seconds * to delay, subject to machine capabilities. * I.E. -#D,20 is delay two seconds. * * f Limit debugging and/or tracing, and profiling to the * list of named functions. Note that a null list will * disable all functions. The appropriate "d" or "t" * flags must still be given, this flag only limits their * actions if they are enabled. * * F Identify the source file name for each * line of debug or trace output. * * i Identify the process with the pid for each line of * debug or trace output. * * g Enable profiling. Create a file called 'dbugmon.out' * containing information that can be used to profile * the program. May be followed by a list of keywords * that select profiling only for the functions in that * list. A null list implies that all functions are * considered. * * L Identify the source file line number for * each line of debug or trace output. * * n Print the current function nesting depth for * each line of debug or trace output. * * N Number each line of dbug output. * * o Redirect the debugger output stream to the * specified file. The default output is stderr. * * O As O but the file is really flushed between each * write. When neaded the file is closed and reopened * between each write. * * p Limit debugger actions to specified processes. * A process must be identified with the * DBUG_PROCESS macro and match one in the list * for debugger actions to occur. * * P Print the current process name for each * line of debug or trace output. * * r When pushing a new state, do not inherit * the previous state's function nesting level. * Useful when the output is to start at the * left margin. * * S Do function _sanity(_file_,_line_) at each * debugged function until _sanity() returns * something that differs from 0. * (Moustly used with safemalloc) * * t Enable function call/exit trace lines. * May be followed by a list (containing only * one modifier) giving a numeric maximum * trace level, beyond which no output will * occur for either debugging or tracing * macros. The default is a compile time * option. * * Some examples of debug control strings which might appear * on a shell command line (the "-#" is typically used to * introduce a control string to an application program) are: * * -#d:t * -#d:f,main,subr1:F:L:t,20 * -#d,input,output,files:n * * For convenience, any leading "-#" is stripped off. * */void _db_push_ (control)const char *control;{ reg1 char *scan; reg2 struct link *temp; CODE_STATE *state; char *new_str; if (! _db_fp_) _db_fp_= stderr; /* Output stream, default stderr */ if (control && *control == '-') { if (*++control == '#') control++; } if (*control) _no_db_=0; /* We are using dbug after all */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -