10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
70Sstevel@tonic-gate * with the License.
80Sstevel@tonic-gate *
90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate * See the License for the specific language governing permissions
120Sstevel@tonic-gate * and limitations under the License.
130Sstevel@tonic-gate *
140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate *
200Sstevel@tonic-gate * CDDL HEADER END
210Sstevel@tonic-gate */
220Sstevel@tonic-gate /*
23*633Sgt29601 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24*633Sgt29601 * Use is subject to license terms.
25*633Sgt29601 */
26*633Sgt29601 /*
270Sstevel@tonic-gate *
280Sstevel@tonic-gate * dbug.c
290Sstevel@tonic-gate *
300Sstevel@tonic-gate * Purpose:
310Sstevel@tonic-gate * Implements the dbug_routine class.
320Sstevel@tonic-gate * This code is derived from the public domain DBUG
330Sstevel@tonic-gate * package written by Fred Fish.
340Sstevel@tonic-gate *
350Sstevel@tonic-gate */
360Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
370Sstevel@tonic-gate
380Sstevel@tonic-gate #ifndef DBUG_OFF
390Sstevel@tonic-gate
400Sstevel@tonic-gate #include <stdio.h>
410Sstevel@tonic-gate #include <stdlib.h>
420Sstevel@tonic-gate #include <string.h>
430Sstevel@tonic-gate #include <unistd.h>
440Sstevel@tonic-gate #include <stdarg.h>
450Sstevel@tonic-gate #include <string.h>
460Sstevel@tonic-gate #include <time.h>
470Sstevel@tonic-gate #include <thread.h>
480Sstevel@tonic-gate #include <sys/types.h>
490Sstevel@tonic-gate #include <signal.h>
500Sstevel@tonic-gate #include "flist.h"
510Sstevel@tonic-gate #include "mdbug.h"
520Sstevel@tonic-gate #include "priv.h"
530Sstevel@tonic-gate
540Sstevel@tonic-gate /* forward references */
550Sstevel@tonic-gate static int listparse(register char *ctlp, flist_object_t *head);
560Sstevel@tonic-gate static boolean inlist(flist_object_t *flist_object_p, const char *cp);
570Sstevel@tonic-gate static boolean dotrace(dbug_state_object_t *dbug_state_object_p,
580Sstevel@tonic-gate const char *func, const char *process);
590Sstevel@tonic-gate static void indent(register dbug_state_object_t *dbug_state_object_p,
600Sstevel@tonic-gate int indent);
610Sstevel@tonic-gate static void doprefix(dbug_state_object_t *dbug_state_object_p, int line,
620Sstevel@tonic-gate long lineno, const char *file, const char *process);
630Sstevel@tonic-gate static FILE *openfile(char *name);
640Sstevel@tonic-gate static boolean writable(char *pathname);
650Sstevel@tonic-gate static void changeowner(char *pathname);
660Sstevel@tonic-gate static int delayarg(int value);
67*633Sgt29601 static void delay(uint_t xx);
68*633Sgt29601 static ulong_t getclock();
690Sstevel@tonic-gate static char *mystrtok(char *s1, char *s2);
700Sstevel@tonic-gate void doabort();
710Sstevel@tonic-gate
720Sstevel@tonic-gate /* initialize static members of class */
730Sstevel@tonic-gate int sd_on = 0;
740Sstevel@tonic-gate char sd_process[128];
750Sstevel@tonic-gate long sd_lineno = 0;
760Sstevel@tonic-gate dbug_state_object_t *sd_push = NULL;
770Sstevel@tonic-gate
780Sstevel@tonic-gate /* this structure defines thread specific data */
790Sstevel@tonic-gate typedef struct thread_data {
800Sstevel@tonic-gate #ifdef STACKINIT
810Sstevel@tonic-gate unsigned long td_stackinit; /* Begining of stack. */
820Sstevel@tonic-gate #endif
830Sstevel@tonic-gate int td_line; /* Current line number. */
840Sstevel@tonic-gate char td_keyword[64]; /* Current keyword. */
850Sstevel@tonic-gate dbug_object_t *td_first; /* Current routine. */
860Sstevel@tonic-gate } thread_data_t;
870Sstevel@tonic-gate #ifdef _REENTRANT
880Sstevel@tonic-gate mutex_t mdt_lock;
890Sstevel@tonic-gate int mdt_once = 0;
900Sstevel@tonic-gate thread_key_t mdt_key;
910Sstevel@tonic-gate #else
920Sstevel@tonic-gate thread_data_t mdt_data;
930Sstevel@tonic-gate #endif
940Sstevel@tonic-gate /*
950Sstevel@tonic-gate * format of control string
960Sstevel@tonic-gate * command[:command:...]
970Sstevel@tonic-gate *
980Sstevel@tonic-gate * commands
990Sstevel@tonic-gate * debugging on 'd' d[,<keyword>[,...]]
1000Sstevel@tonic-gate * delay value 'D' D[,<delay value>]
1010Sstevel@tonic-gate * function list 'f' f[,<function name>[,...]]
1020Sstevel@tonic-gate * print filename 'F' F
1030Sstevel@tonic-gate * print pid 'i' i
1040Sstevel@tonic-gate * print line number 'L' L
1050Sstevel@tonic-gate * print call depth 'n' n
1060Sstevel@tonic-gate * number each line 'N' N
1070Sstevel@tonic-gate * output file 'o' o[,<filename>
1080Sstevel@tonic-gate * process name list 'p' p[,<process name>[,...]]
1090Sstevel@tonic-gate * print proc name 'P' P
1100Sstevel@tonic-gate * reset indentation 'r' r
1110Sstevel@tonic-gate * print runtime 'R' R
1120Sstevel@tonic-gate * print thread info 'T' T
1130Sstevel@tonic-gate * print trace 't' t
1140Sstevel@tonic-gate * print stack depth 's' s
1150Sstevel@tonic-gate */
1160Sstevel@tonic-gate
1170Sstevel@tonic-gate /*
1180Sstevel@tonic-gate *
1190Sstevel@tonic-gate * dbug_object_create
1200Sstevel@tonic-gate *
1210Sstevel@tonic-gate * Description:
1220Sstevel@tonic-gate * Constructor for the dbug_routine class.
1230Sstevel@tonic-gate * Arguments:
1240Sstevel@tonic-gate * line - line number where object was created.
1250Sstevel@tonic-gate * file - file name object was created in.
1260Sstevel@tonic-gate * function- routine name object was created in.
1270Sstevel@tonic-gate * Returns:
1280Sstevel@tonic-gate * Errors:
1290Sstevel@tonic-gate * Preconditions:
1300Sstevel@tonic-gate */
1310Sstevel@tonic-gate void
dbug_object_create(int line,const char * file,const char * function)1320Sstevel@tonic-gate dbug_object_create(int line, const char *file, const char *function)
1330Sstevel@tonic-gate {
1340Sstevel@tonic-gate dbug_object_t *dbug_object_p;
1350Sstevel@tonic-gate dbug_state_object_t *dbug_state_object_p;
136*633Sgt29601 ulong_t stacksize;
1370Sstevel@tonic-gate int created = 0;
1380Sstevel@tonic-gate char *cptr;
1390Sstevel@tonic-gate
1400Sstevel@tonic-gate thread_data_t *tdp = NULL;
1410Sstevel@tonic-gate #ifdef _REENTRANT
1420Sstevel@tonic-gate LOCK_THREAD_DATA();
1430Sstevel@tonic-gate if (!mdt_once) {
1440Sstevel@tonic-gate if (thr_keycreate(&mdt_key, dbug_thread_exit) != 0)
1450Sstevel@tonic-gate doabort();
1460Sstevel@tonic-gate mdt_once++;
1470Sstevel@tonic-gate }
1480Sstevel@tonic-gate GET_THREAD_DATA_PTR(&tdp);
1490Sstevel@tonic-gate if (tdp == NULL) {
1500Sstevel@tonic-gate tdp = (thread_data_t *)calloc(sizeof (*tdp), 1);
1510Sstevel@tonic-gate if (tdp == NULL)
1520Sstevel@tonic-gate doabort();
1530Sstevel@tonic-gate thr_setspecific(mdt_key, tdp);
1540Sstevel@tonic-gate created = 1;
1550Sstevel@tonic-gate tdp->td_keyword[0] = '\0';
1560Sstevel@tonic-gate tdp->td_first = NULL;
1570Sstevel@tonic-gate }
1580Sstevel@tonic-gate #else
1590Sstevel@tonic-gate GET_THREAD_DATA_PTR(&tdp);
1600Sstevel@tonic-gate #endif
1610Sstevel@tonic-gate
1620Sstevel@tonic-gate dbug_object_p = (dbug_object_t *)calloc(sizeof (dbug_object_t), 1);
1630Sstevel@tonic-gate
1640Sstevel@tonic-gate if (dbug_object_p == NULL)
1650Sstevel@tonic-gate doabort();
1660Sstevel@tonic-gate
1670Sstevel@tonic-gate /* save the function name */
1680Sstevel@tonic-gate if (function)
1690Sstevel@tonic-gate strcpy(dbug_object_p->d_func, function);
1700Sstevel@tonic-gate else
1710Sstevel@tonic-gate strcpy(dbug_object_p->d_func, "unknown");
1720Sstevel@tonic-gate
1730Sstevel@tonic-gate /* save the base of the file name */
1740Sstevel@tonic-gate if (file) {
1750Sstevel@tonic-gate cptr = strrchr(file, '/');
1760Sstevel@tonic-gate if (cptr == NULL)
1770Sstevel@tonic-gate strcpy(dbug_object_p->d_file, file);
1780Sstevel@tonic-gate else
1790Sstevel@tonic-gate strcpy(dbug_object_p->d_file, cptr++);
1800Sstevel@tonic-gate } else
1810Sstevel@tonic-gate strcpy(dbug_object_p->d_file, "unknown");
1820Sstevel@tonic-gate
1830Sstevel@tonic-gate /* Chain this onto our list of them */
1840Sstevel@tonic-gate dbug_object_p->d_prev = tdp->td_first;
1850Sstevel@tonic-gate tdp->td_first = dbug_object_p;
1860Sstevel@tonic-gate
1870Sstevel@tonic-gate /* set the default routine exit point line number to zero */
1880Sstevel@tonic-gate dbug_object_p->d_leaveline = 0;
1890Sstevel@tonic-gate
1900Sstevel@tonic-gate /* If debugging is off, then all done */
1910Sstevel@tonic-gate if (NOT db_debugon())
1920Sstevel@tonic-gate goto out;
1930Sstevel@tonic-gate
1940Sstevel@tonic-gate /* if the active state is null initialize it */
1950Sstevel@tonic-gate if (sd_push == NULL)
1960Sstevel@tonic-gate db_push("d,:f,:F:i:L:n:N:o,cfsd_debug.out:p,:P:r:R:T:t:s");
1970Sstevel@tonic-gate
1980Sstevel@tonic-gate /* get a pointer to the active state */
1990Sstevel@tonic-gate dbug_state_object_p = sd_push;
2000Sstevel@tonic-gate
2010Sstevel@tonic-gate #ifdef STACKINIT
2020Sstevel@tonic-gate /*
2030Sstevel@tonic-gate * Get the new stack depth.
2040Sstevel@tonic-gate * There a two problems associated with this.
2050Sstevel@tonic-gate * One is because c++ allows declarations anywhere inside of
2060Sstevel@tonic-gate * a routine. So it is difficult to position the dbug_enter()
2070Sstevel@tonic-gate * macro after all declarations and still be useful.
2080Sstevel@tonic-gate * Two is that the dbug_enter() macro should be before all
2090Sstevel@tonic-gate * other automatic objects so that its destructor gets called
2100Sstevel@tonic-gate * last as the routine is returning.
2110Sstevel@tonic-gate * The solution is to advise placing the dbug_enter() macro at
2120Sstevel@tonic-gate * the start of the routine and specifying that that stack
2130Sstevel@tonic-gate * values apply upto but not including the current routine.
2140Sstevel@tonic-gate */
215*633Sgt29601 stacksize = (ulong_t)this;
2160Sstevel@tonic-gate if (GROWDOWN)
2170Sstevel@tonic-gate stacksize = tdp->td_stackinit - stacksize;
2180Sstevel@tonic-gate else
2190Sstevel@tonic-gate stacksize = stacksize - tdp->td_stackinit;
2200Sstevel@tonic-gate #endif
2210Sstevel@tonic-gate
2220Sstevel@tonic-gate /* record the new nesting level */
2230Sstevel@tonic-gate dbug_state_object_p->s_level++;
2240Sstevel@tonic-gate
2250Sstevel@tonic-gate /* if producing a trace of function calls */
2260Sstevel@tonic-gate if (dotrace(dbug_state_object_p, dbug_object_p->d_func, sd_process)) {
2270Sstevel@tonic-gate doprefix(dbug_state_object_p, line, sd_lineno++,
2280Sstevel@tonic-gate dbug_object_p->d_file, sd_process);
2290Sstevel@tonic-gate indent(dbug_state_object_p, dbug_state_object_p->s_level);
2300Sstevel@tonic-gate if (dbug_state_object_p->sf_stack)
2310Sstevel@tonic-gate fprintf(dbug_state_object_p->s_out_file, ">%s %ld\n",
2320Sstevel@tonic-gate dbug_object_p->d_func, stacksize);
2330Sstevel@tonic-gate else
2340Sstevel@tonic-gate fprintf(dbug_state_object_p->s_out_file, ">%s\n",
2350Sstevel@tonic-gate dbug_object_p->d_func);
2360Sstevel@tonic-gate fflush(dbug_state_object_p->s_out_file);
2370Sstevel@tonic-gate delay(dbug_state_object_p->s_delay);
2380Sstevel@tonic-gate }
2390Sstevel@tonic-gate
2400Sstevel@tonic-gate /* if a new thread */
2410Sstevel@tonic-gate if (created && dbug_state_object_p->sf_thread) {
2420Sstevel@tonic-gate doprefix(dbug_state_object_p, line, sd_lineno++,
2430Sstevel@tonic-gate dbug_object_p->d_file, sd_process);
2440Sstevel@tonic-gate indent(dbug_state_object_p, dbug_state_object_p->s_level);
2450Sstevel@tonic-gate fprintf(dbug_state_object_p->s_out_file, "thread created\n");
2460Sstevel@tonic-gate fflush(dbug_state_object_p->s_out_file);
2470Sstevel@tonic-gate delay(dbug_state_object_p->s_delay);
2480Sstevel@tonic-gate }
2490Sstevel@tonic-gate
2500Sstevel@tonic-gate out:;
2510Sstevel@tonic-gate UNLOCK_THREAD_DATA();
2520Sstevel@tonic-gate }
2530Sstevel@tonic-gate
2540Sstevel@tonic-gate /*
2550Sstevel@tonic-gate *
2560Sstevel@tonic-gate * dbug_object_destroy
2570Sstevel@tonic-gate *
2580Sstevel@tonic-gate * Description:
2590Sstevel@tonic-gate * Destructor for the dbug_routine class.
2600Sstevel@tonic-gate * Unchains this object from the list.
2610Sstevel@tonic-gate * Arguments:
2620Sstevel@tonic-gate * Returns:
2630Sstevel@tonic-gate * Errors:
2640Sstevel@tonic-gate * Preconditions:
2650Sstevel@tonic-gate */
2660Sstevel@tonic-gate void
dbug_object_destroy(char * function_name,int line)2670Sstevel@tonic-gate dbug_object_destroy(char *function_name, int line)
2680Sstevel@tonic-gate {
2690Sstevel@tonic-gate dbug_object_t *dbug_object_p;
2700Sstevel@tonic-gate dbug_state_object_t *dbug_state_object_p;
2710Sstevel@tonic-gate thread_data_t *tdp;
2720Sstevel@tonic-gate
2730Sstevel@tonic-gate LOCK_THREAD_DATA();
2740Sstevel@tonic-gate GET_THREAD_DATA_PTR(&tdp);
2750Sstevel@tonic-gate
2760Sstevel@tonic-gate /* unchain from the list of objects */
2770Sstevel@tonic-gate dbug_object_p = tdp->td_first;
2780Sstevel@tonic-gate tdp->td_first = dbug_object_p->d_prev;
2790Sstevel@tonic-gate
2800Sstevel@tonic-gate /* If debugging is off, then nothing else to do */
2810Sstevel@tonic-gate if (NOT db_debugon())
2820Sstevel@tonic-gate goto out;
2830Sstevel@tonic-gate
2840Sstevel@tonic-gate dbug_object_p->d_leaveline = line;
2850Sstevel@tonic-gate
2860Sstevel@tonic-gate /* get a pointer to the active state */
2870Sstevel@tonic-gate dbug_state_object_p = sd_push;
2880Sstevel@tonic-gate
2890Sstevel@tonic-gate /*
2900Sstevel@tonic-gate * Make sure the last one created is being deleted.
2910Sstevel@tonic-gate * This will not be the case if there are multiple dbug_routine
2920Sstevel@tonic-gate * objects per routine or if one is created outside of a routine.
2930Sstevel@tonic-gate */
2940Sstevel@tonic-gate if (strcmp(function_name, dbug_object_p->d_func)) {
2950Sstevel@tonic-gate doprefix(dbug_state_object_p, dbug_object_p->d_leaveline,
2960Sstevel@tonic-gate sd_lineno++, dbug_object_p->d_file, sd_process);
2970Sstevel@tonic-gate indent(dbug_state_object_p, dbug_state_object_p->s_level);
2980Sstevel@tonic-gate fprintf(dbug_state_object_p->s_out_file,
2990Sstevel@tonic-gate "<expected %s, actual %s, ERROR: "
3000Sstevel@tonic-gate "dbug_enter/dbug_leave out of sequence.\n",
3010Sstevel@tonic-gate dbug_object_p->d_func, function_name);
3020Sstevel@tonic-gate fflush(dbug_state_object_p->s_out_file);
3030Sstevel@tonic-gate /* delay(dbug_state_object_p->s_delay); */
3040Sstevel@tonic-gate }
3050Sstevel@tonic-gate
3060Sstevel@tonic-gate /* if producing a trace of function calls */
3070Sstevel@tonic-gate if (dotrace(dbug_state_object_p, dbug_object_p->d_func, sd_process)) {
3080Sstevel@tonic-gate doprefix(dbug_state_object_p, dbug_object_p->d_leaveline,
3090Sstevel@tonic-gate sd_lineno++, dbug_object_p->d_file, sd_process);
3100Sstevel@tonic-gate indent(dbug_state_object_p, dbug_state_object_p->s_level);
3110Sstevel@tonic-gate fprintf(dbug_state_object_p->s_out_file, "<%s\n",
3120Sstevel@tonic-gate dbug_object_p->d_func);
3130Sstevel@tonic-gate fflush(dbug_state_object_p->s_out_file);
3140Sstevel@tonic-gate #if 0
3150Sstevel@tonic-gate delay(dbug_state_object_p->s_delay);
3160Sstevel@tonic-gate #endif
3170Sstevel@tonic-gate }
3180Sstevel@tonic-gate
3190Sstevel@tonic-gate
3200Sstevel@tonic-gate /* record the new nesting level */
3210Sstevel@tonic-gate dbug_state_object_p->s_level--;
3220Sstevel@tonic-gate
3230Sstevel@tonic-gate out:;
3240Sstevel@tonic-gate free(dbug_object_p);
3250Sstevel@tonic-gate UNLOCK_THREAD_DATA();
3260Sstevel@tonic-gate }
3270Sstevel@tonic-gate
3280Sstevel@tonic-gate /*
3290Sstevel@tonic-gate *
3300Sstevel@tonic-gate * db_keyword
3310Sstevel@tonic-gate *
3320Sstevel@tonic-gate * Description:
3330Sstevel@tonic-gate * Test a keyword to determine if it is in the currently active
3340Sstevel@tonic-gate * keyword list. As with the function list, a keyword is accepted
3350Sstevel@tonic-gate * if the list is null, otherwise it must match one of the list
3360Sstevel@tonic-gate * members. When debugging is not on, no keywords are accepted.
3370Sstevel@tonic-gate * After the maximum trace level is exceeded, no keywords are
3380Sstevel@tonic-gate * accepted (this behavior subject to change). Additionally,
3390Sstevel@tonic-gate * the current function and process must be accepted based on
3400Sstevel@tonic-gate * their respective lists.
3410Sstevel@tonic-gate * Arguments:
3420Sstevel@tonic-gate * keyword - the keyword to test
3430Sstevel@tonic-gate * Returns:
3440Sstevel@tonic-gate * Returns 1 if keyword accepted, 0 otherwise.
3450Sstevel@tonic-gate * Errors:
3460Sstevel@tonic-gate * Preconditions:
3470Sstevel@tonic-gate * precond(keyword)
3480Sstevel@tonic-gate */
3490Sstevel@tonic-gate int
db_keyword(dbug_object_t * dbug_object_p,const char * keyword)3500Sstevel@tonic-gate db_keyword(dbug_object_t *dbug_object_p, const char *keyword)
3510Sstevel@tonic-gate {
3520Sstevel@tonic-gate dbug_state_object_t *dbug_state_object_p;
3530Sstevel@tonic-gate int ret = 0;
3540Sstevel@tonic-gate
3550Sstevel@tonic-gate /* return FALSE if not debugging */
3560Sstevel@tonic-gate if (NOT db_debugon())
3570Sstevel@tonic-gate return (0);
3580Sstevel@tonic-gate
3590Sstevel@tonic-gate LOCK_THREAD_DATA();
3600Sstevel@tonic-gate
3610Sstevel@tonic-gate /* return FALSE if not debugging */
3620Sstevel@tonic-gate if (NOT db_debugon())
3630Sstevel@tonic-gate goto out;
3640Sstevel@tonic-gate
3650Sstevel@tonic-gate /* get a pointer to the active state */
3660Sstevel@tonic-gate dbug_state_object_p = sd_push;
3670Sstevel@tonic-gate
3680Sstevel@tonic-gate if (dbug_state_object_p->sf_debug) { /* is this test necessary ? */
3690Sstevel@tonic-gate if (inlist(dbug_state_object_p->s_functions,
3700Sstevel@tonic-gate dbug_object_p->d_func)) {
3710Sstevel@tonic-gate if (inlist(dbug_state_object_p->s_processes,
3720Sstevel@tonic-gate sd_process)) {
3730Sstevel@tonic-gate if (inlist(dbug_state_object_p->s_keywords,
3740Sstevel@tonic-gate keyword)) {
3750Sstevel@tonic-gate ret = 1;
3760Sstevel@tonic-gate goto out;
3770Sstevel@tonic-gate }
3780Sstevel@tonic-gate }
3790Sstevel@tonic-gate }
3800Sstevel@tonic-gate }
3810Sstevel@tonic-gate
3820Sstevel@tonic-gate out:
3830Sstevel@tonic-gate UNLOCK_THREAD_DATA();
3840Sstevel@tonic-gate return (ret);
3850Sstevel@tonic-gate }
3860Sstevel@tonic-gate
3870Sstevel@tonic-gate /*
3880Sstevel@tonic-gate *
3890Sstevel@tonic-gate * db_pargs
3900Sstevel@tonic-gate *
3910Sstevel@tonic-gate * Description:
3920Sstevel@tonic-gate * Saves arguments for subsequent usage by db_printf.
3930Sstevel@tonic-gate * Arguments:
3940Sstevel@tonic-gate * line - the line number the db_print occurs on
3950Sstevel@tonic-gate * keyword - determines whether or not to really print anything
3960Sstevel@tonic-gate * Returns:
3970Sstevel@tonic-gate * Errors:
3980Sstevel@tonic-gate * Preconditions:
3990Sstevel@tonic-gate * precond(keyword)
4000Sstevel@tonic-gate */
4010Sstevel@tonic-gate void
db_pargs(dbug_object_t * dbug_object_p,int line,char * keyword)4020Sstevel@tonic-gate db_pargs(dbug_object_t *dbug_object_p, int line, char *keyword)
4030Sstevel@tonic-gate {
4040Sstevel@tonic-gate thread_data_t *tdp;
4050Sstevel@tonic-gate
4060Sstevel@tonic-gate /* return if no debugging yet */
4070Sstevel@tonic-gate if (NOT db_debugon())
4080Sstevel@tonic-gate return;
4090Sstevel@tonic-gate
4100Sstevel@tonic-gate GET_THREAD_DATA_PTR(&tdp);
4110Sstevel@tonic-gate
4120Sstevel@tonic-gate tdp->td_line = line;
4130Sstevel@tonic-gate if (keyword)
4140Sstevel@tonic-gate strcpy(tdp->td_keyword, keyword);
4150Sstevel@tonic-gate else
4160Sstevel@tonic-gate tdp->td_keyword[0] = '\0';
4170Sstevel@tonic-gate }
4180Sstevel@tonic-gate
4190Sstevel@tonic-gate int
db_getfd()4200Sstevel@tonic-gate db_getfd()
4210Sstevel@tonic-gate {
4220Sstevel@tonic-gate return (fileno(sd_push->s_out_file));
4230Sstevel@tonic-gate }
4240Sstevel@tonic-gate
4250Sstevel@tonic-gate /*
4260Sstevel@tonic-gate *
4270Sstevel@tonic-gate * db_printf
4280Sstevel@tonic-gate *
4290Sstevel@tonic-gate * Description:
4300Sstevel@tonic-gate * Outputs the specified message if the keyword specified
4310Sstevel@tonic-gate * by db_pargs() has been selected. The line number specified
4320Sstevel@tonic-gate * by db_pargs() is also used as the line number the db_printf()
4330Sstevel@tonic-gate * occurs on. The format string should NOT include a terminating
4340Sstevel@tonic-gate * newline as one is supplied automatically.
4350Sstevel@tonic-gate * Arguments:
4360Sstevel@tonic-gate * format - printf style printing control string
4370Sstevel@tonic-gate * ... - additional arguments required by the control string
4380Sstevel@tonic-gate * Returns:
4390Sstevel@tonic-gate * Errors:
4400Sstevel@tonic-gate * Preconditions:
4410Sstevel@tonic-gate * precond(format)
4420Sstevel@tonic-gate */
4430Sstevel@tonic-gate void
db_printf(char * keyword,char * format,...)4440Sstevel@tonic-gate db_printf(char *keyword, char *format, ...)
4450Sstevel@tonic-gate {
4460Sstevel@tonic-gate dbug_object_t *dbug_object_p;
4470Sstevel@tonic-gate thread_data_t *tdp;
4480Sstevel@tonic-gate dbug_state_object_t *dbug_state_object_p = sd_push;
4490Sstevel@tonic-gate va_list args;
4500Sstevel@tonic-gate
4510Sstevel@tonic-gate dbug_object_p = db_get_dbug_object_p();
4520Sstevel@tonic-gate /* return if no debugging yet */
4530Sstevel@tonic-gate if (NOT db_debugon())
4540Sstevel@tonic-gate return;
4550Sstevel@tonic-gate
4560Sstevel@tonic-gate GET_THREAD_DATA_PTR(&tdp);
4570Sstevel@tonic-gate
4580Sstevel@tonic-gate /* return if keyword not selected */
4590Sstevel@tonic-gate if (NOT db_keyword(dbug_object_p, tdp->td_keyword))
4600Sstevel@tonic-gate return;
4610Sstevel@tonic-gate
4620Sstevel@tonic-gate LOCK_THREAD_DATA();
4630Sstevel@tonic-gate
4640Sstevel@tonic-gate /* get a pointer to the active state */
4650Sstevel@tonic-gate
4660Sstevel@tonic-gate va_start(args, format);
4670Sstevel@tonic-gate
4680Sstevel@tonic-gate doprefix(dbug_state_object_p, tdp->td_line, sd_lineno++,
4690Sstevel@tonic-gate dbug_object_p->d_file, sd_process);
4700Sstevel@tonic-gate if (dbug_state_object_p->sf_trace)
4710Sstevel@tonic-gate indent(dbug_state_object_p, dbug_state_object_p->s_level +1);
4720Sstevel@tonic-gate else
4730Sstevel@tonic-gate fprintf(dbug_state_object_p->s_out_file, "%s: ",
4740Sstevel@tonic-gate dbug_object_p->d_func);
4750Sstevel@tonic-gate if (tdp->td_keyword[0])
4760Sstevel@tonic-gate fprintf(dbug_state_object_p->s_out_file, "%s: ",
4770Sstevel@tonic-gate tdp->td_keyword);
4780Sstevel@tonic-gate vfprintf(dbug_state_object_p->s_out_file, format, args);
4790Sstevel@tonic-gate fprintf(dbug_state_object_p->s_out_file, "\n");
4800Sstevel@tonic-gate fflush(dbug_state_object_p->s_out_file);
4810Sstevel@tonic-gate delay(dbug_state_object_p->s_delay);
4820Sstevel@tonic-gate
4830Sstevel@tonic-gate va_end(args);
4840Sstevel@tonic-gate
4850Sstevel@tonic-gate UNLOCK_THREAD_DATA();
4860Sstevel@tonic-gate }
4870Sstevel@tonic-gate
4880Sstevel@tonic-gate /*
4890Sstevel@tonic-gate *
4900Sstevel@tonic-gate * db_traceprint
4910Sstevel@tonic-gate *
4920Sstevel@tonic-gate * Description:
4930Sstevel@tonic-gate * Prints out a trace of the call stack.
4940Sstevel@tonic-gate * Arguments:
4950Sstevel@tonic-gate * line - the line number where this call was made
4960Sstevel@tonic-gate * keyword - keyword to test against
4970Sstevel@tonic-gate * Returns:
4980Sstevel@tonic-gate * Errors:
4990Sstevel@tonic-gate * Preconditions:
5000Sstevel@tonic-gate */
5010Sstevel@tonic-gate void
db_traceprint(int line,const char * keyword)5020Sstevel@tonic-gate db_traceprint(int line, const char *keyword)
5030Sstevel@tonic-gate {
5040Sstevel@tonic-gate dbug_object_t *dbug_object_p;
5050Sstevel@tonic-gate dbug_object_t *pdr;
5060Sstevel@tonic-gate /* return if no debugging yet */
5070Sstevel@tonic-gate if (NOT db_debugon())
5080Sstevel@tonic-gate return;
5090Sstevel@tonic-gate
5100Sstevel@tonic-gate if ((dbug_object_p = db_get_dbug_object_p()) == NULL)
5110Sstevel@tonic-gate doabort();
5120Sstevel@tonic-gate
5130Sstevel@tonic-gate /* If the specified keyword is enabled */
5140Sstevel@tonic-gate if (db_keyword(dbug_object_p, keyword)) {
5150Sstevel@tonic-gate /* perform setup for using db_printf */
5160Sstevel@tonic-gate db_pargs(dbug_object_p, line, NULL);
5170Sstevel@tonic-gate
5180Sstevel@tonic-gate /* Output a header message */
5190Sstevel@tonic-gate db_printf(NULL, "Stack Trace");
5200Sstevel@tonic-gate
5210Sstevel@tonic-gate /* walk the stack of dbug_routine objects */
5220Sstevel@tonic-gate for (pdr = dbug_object_p; pdr != NULL; pdr = pdr->d_prev) {
5230Sstevel@tonic-gate /* output the routine name */
5240Sstevel@tonic-gate db_printf(NULL, " %s() (%s)", pdr->d_func,
5250Sstevel@tonic-gate pdr->d_file);
5260Sstevel@tonic-gate }
5270Sstevel@tonic-gate }
5280Sstevel@tonic-gate }
5290Sstevel@tonic-gate
5300Sstevel@tonic-gate /*
5310Sstevel@tonic-gate *
5320Sstevel@tonic-gate * db_assert
5330Sstevel@tonic-gate *
5340Sstevel@tonic-gate * Description:
5350Sstevel@tonic-gate * Called when an assert fails.
5360Sstevel@tonic-gate * Prints out a stack trace and aborts.
5370Sstevel@tonic-gate * Arguments:
5380Sstevel@tonic-gate * line line number assert occurred at
5390Sstevel@tonic-gate * msgp string form of assert code that failed
5400Sstevel@tonic-gate * Returns:
5410Sstevel@tonic-gate * Preconditions:
5420Sstevel@tonic-gate * precond(msgp)
5430Sstevel@tonic-gate */
5440Sstevel@tonic-gate void
db_assert(dbug_object_t * dbug_object_p,int line,const char * msgp)5450Sstevel@tonic-gate db_assert(dbug_object_t *dbug_object_p, int line, const char *msgp)
5460Sstevel@tonic-gate {
5470Sstevel@tonic-gate if (NOT db_debugon())
5480Sstevel@tonic-gate db_push("-#:d");
5490Sstevel@tonic-gate db_pargs(dbug_object_p, line, NULL);
5500Sstevel@tonic-gate db_printf(NULL, "Assertion Failed %s:%s():%d \"%s\"",
5510Sstevel@tonic-gate dbug_object_p->d_file, dbug_object_p->d_func, line, msgp);
5520Sstevel@tonic-gate db_traceprint(line, NULL);
5530Sstevel@tonic-gate doabort();
5540Sstevel@tonic-gate }
5550Sstevel@tonic-gate
5560Sstevel@tonic-gate /*
5570Sstevel@tonic-gate *
5580Sstevel@tonic-gate * db_precond
5590Sstevel@tonic-gate *
5600Sstevel@tonic-gate * Description:
5610Sstevel@tonic-gate * Called when an precond fails.
5620Sstevel@tonic-gate * Prints out a stack trace and aborts.
5630Sstevel@tonic-gate * Arguments:
5640Sstevel@tonic-gate * line line number precond occurred at
5650Sstevel@tonic-gate * msgp string form of precond code that failed
5660Sstevel@tonic-gate * Returns:
5670Sstevel@tonic-gate * Preconditions:
5680Sstevel@tonic-gate * precond(msgp)
5690Sstevel@tonic-gate */
5700Sstevel@tonic-gate void
db_precond(dbug_object_t * dbug_object_p,int line,const char * msgp)5710Sstevel@tonic-gate db_precond(dbug_object_t *dbug_object_p, int line, const char *msgp)
5720Sstevel@tonic-gate {
5730Sstevel@tonic-gate if (NOT db_debugon())
5740Sstevel@tonic-gate db_push("-#:d");
5750Sstevel@tonic-gate db_pargs(dbug_object_p, line, NULL);
5760Sstevel@tonic-gate db_printf(NULL, "Precondition Failed %s:%s():%d \"%s\"",
5770Sstevel@tonic-gate dbug_object_p->d_file, dbug_object_p->d_func, line, msgp);
5780Sstevel@tonic-gate db_traceprint(line, NULL);
5790Sstevel@tonic-gate doabort();
5800Sstevel@tonic-gate }
5810Sstevel@tonic-gate
5820Sstevel@tonic-gate /*
5830Sstevel@tonic-gate *
5840Sstevel@tonic-gate * db_push
5850Sstevel@tonic-gate *
5860Sstevel@tonic-gate * Description:
5870Sstevel@tonic-gate * Push current debugger state and set up a new one.
5880Sstevel@tonic-gate * Returns NULL if no errors, an error string if there
5890Sstevel@tonic-gate * is an error.
5900Sstevel@tonic-gate *
5910Sstevel@tonic-gate * format of control string
5920Sstevel@tonic-gate * command[:command:...]
5930Sstevel@tonic-gate *
5940Sstevel@tonic-gate * commands
5950Sstevel@tonic-gate * debugging on 'd' d[,<keyword>[,...]]
5960Sstevel@tonic-gate * delay value 'D' D[,<delay value>]
5970Sstevel@tonic-gate * function list 'f' f[,<function name>[,...]]
5980Sstevel@tonic-gate * print filename 'F' F
5990Sstevel@tonic-gate * print pid 'i' i
6000Sstevel@tonic-gate * print line number 'L' L
6010Sstevel@tonic-gate * print call depth 'n' n
6020Sstevel@tonic-gate * number each line 'N' N
6030Sstevel@tonic-gate * output file 'o' o[,<filename>
6040Sstevel@tonic-gate * process name list 'p' p[,<process name>[,...]]
6050Sstevel@tonic-gate * print proc name 'P' P
6060Sstevel@tonic-gate * reset indentation 'r' r
6070Sstevel@tonic-gate * print runtime 'R' R
6080Sstevel@tonic-gate * print thread info 'T' T
6090Sstevel@tonic-gate * print trace 't' t
6100Sstevel@tonic-gate * print stack depth 's' s
6110Sstevel@tonic-gate */
6120Sstevel@tonic-gate char *
db_push(const char * control)6130Sstevel@tonic-gate db_push(const char *control)
6140Sstevel@tonic-gate {
6150Sstevel@tonic-gate char *dupcontrol = NULL;
6160Sstevel@tonic-gate dbug_state_object_t *dbug_state_object_p;
6170Sstevel@tonic-gate flist_object_t *flist_object_p;
6180Sstevel@tonic-gate register char *scan;
6190Sstevel@tonic-gate int retval;
6200Sstevel@tonic-gate char res[100];
6210Sstevel@tonic-gate int level;
6220Sstevel@tonic-gate
6230Sstevel@tonic-gate LOCK_THREAD_DATA();
6240Sstevel@tonic-gate
6250Sstevel@tonic-gate /* error if the control string is NULL */
6260Sstevel@tonic-gate if (control == NULL) {
6270Sstevel@tonic-gate strcpy(res, "mdbug: control string is NULL");
6280Sstevel@tonic-gate goto out;
6290Sstevel@tonic-gate }
6300Sstevel@tonic-gate
6310Sstevel@tonic-gate /* turn debugging flag off */
6320Sstevel@tonic-gate sd_on = FALSE;
6330Sstevel@tonic-gate
6340Sstevel@tonic-gate /* get the level from the old state if it exists */
6350Sstevel@tonic-gate if (sd_push == NULL)
6360Sstevel@tonic-gate level = 0;
6370Sstevel@tonic-gate else
6380Sstevel@tonic-gate level = sd_push->s_level;
6390Sstevel@tonic-gate
6400Sstevel@tonic-gate /* Create a new state */
6410Sstevel@tonic-gate dbug_state_object_p = dbug_state_create(level);
6420Sstevel@tonic-gate if (dbug_state_object_p == NULL) {
6430Sstevel@tonic-gate strcpy(res, "mdbug: out of memory, dbug_state_create");
6440Sstevel@tonic-gate goto out;
6450Sstevel@tonic-gate }
6460Sstevel@tonic-gate
6470Sstevel@tonic-gate /* add it to our list of states and make it the current one */
6480Sstevel@tonic-gate dbug_state_object_p->s_next = sd_push;
6490Sstevel@tonic-gate sd_push = dbug_state_object_p;
6500Sstevel@tonic-gate
6510Sstevel@tonic-gate /* Strip off -# if in the control string */
6520Sstevel@tonic-gate if ((*control == '-') && (*(control+1) == '#'))
6530Sstevel@tonic-gate control += 2;
6540Sstevel@tonic-gate
6550Sstevel@tonic-gate /* make a copy of the control string so we can modify it with strtok */
6560Sstevel@tonic-gate dupcontrol = strdup(control);
6570Sstevel@tonic-gate if (dupcontrol == NULL) {
6580Sstevel@tonic-gate strcpy(res, "mdbug: out of memory, strdup");
6590Sstevel@tonic-gate goto out;
6600Sstevel@tonic-gate }
6610Sstevel@tonic-gate
6620Sstevel@tonic-gate /* parse the control string */
6630Sstevel@tonic-gate for (scan = mystrtok(dupcontrol, ":");
6640Sstevel@tonic-gate scan != NULL;
6650Sstevel@tonic-gate scan = mystrtok(NULL, ":")) {
6660Sstevel@tonic-gate switch (*scan++) {
6670Sstevel@tonic-gate case 'd': /* debugging on */
6680Sstevel@tonic-gate sd_on = TRUE;
6690Sstevel@tonic-gate dbug_state_object_p->sf_debug = TRUE;
6700Sstevel@tonic-gate if (*scan++ == ',') {
6710Sstevel@tonic-gate retval = listparse(scan,
6720Sstevel@tonic-gate dbug_state_object_p->s_keywords);
6730Sstevel@tonic-gate if (retval < 0) {
6740Sstevel@tonic-gate strcpy(res,
6750Sstevel@tonic-gate "mdbug: -d too many keywords");
6760Sstevel@tonic-gate goto out;
6770Sstevel@tonic-gate }
6780Sstevel@tonic-gate }
6790Sstevel@tonic-gate break;
6800Sstevel@tonic-gate
6810Sstevel@tonic-gate case 'D': /* specify delay value */
6820Sstevel@tonic-gate dbug_state_object_p->s_delay = 0;
6830Sstevel@tonic-gate if (*scan++ == ',') {
6840Sstevel@tonic-gate flist_object_p = flist_create();
6850Sstevel@tonic-gate retval = listparse(scan, flist_object_p);
6860Sstevel@tonic-gate if (retval < 0) {
6870Sstevel@tonic-gate strcpy(res,
6880Sstevel@tonic-gate "mdbug: -D too many delays");
6890Sstevel@tonic-gate goto out;
6900Sstevel@tonic-gate }
6910Sstevel@tonic-gate if (flist_object_p->f_count > 0) {
6920Sstevel@tonic-gate dbug_state_object_p->s_delay =
6930Sstevel@tonic-gate delayarg(atoi(
6940Sstevel@tonic-gate (char *)fl_top(flist_object_p)));
6950Sstevel@tonic-gate }
6960Sstevel@tonic-gate flist_destroy(flist_object_p);
6970Sstevel@tonic-gate }
6980Sstevel@tonic-gate break;
6990Sstevel@tonic-gate
7000Sstevel@tonic-gate case 'f': /* list of functions to watch */
7010Sstevel@tonic-gate if (*scan++ == ',') {
7020Sstevel@tonic-gate retval = listparse(scan,
7030Sstevel@tonic-gate dbug_state_object_p->s_functions);
7040Sstevel@tonic-gate if (retval < 0) {
7050Sstevel@tonic-gate strcpy(res,
7060Sstevel@tonic-gate "mdbug: -f too many functions");
7070Sstevel@tonic-gate goto out;
7080Sstevel@tonic-gate }
7090Sstevel@tonic-gate }
7100Sstevel@tonic-gate break;
7110Sstevel@tonic-gate
7120Sstevel@tonic-gate case 'F': /* print file name with dbug output */
7130Sstevel@tonic-gate dbug_state_object_p->sf_file = TRUE;
7140Sstevel@tonic-gate break;
7150Sstevel@tonic-gate
7160Sstevel@tonic-gate case 'i': /* print pid with dbug output */
7170Sstevel@tonic-gate dbug_state_object_p->sf_pid = TRUE;
7180Sstevel@tonic-gate break;
7190Sstevel@tonic-gate
7200Sstevel@tonic-gate case 'L': /* print line nums with dbug output */
7210Sstevel@tonic-gate dbug_state_object_p->sf_line = TRUE;
7220Sstevel@tonic-gate break;
7230Sstevel@tonic-gate
7240Sstevel@tonic-gate case 'n': /* print function call depth */
7250Sstevel@tonic-gate dbug_state_object_p->sf_depth = TRUE;
7260Sstevel@tonic-gate break;
7270Sstevel@tonic-gate
7280Sstevel@tonic-gate case 'N': /* number each line of dbug output */
7290Sstevel@tonic-gate dbug_state_object_p->sf_number = TRUE;
7300Sstevel@tonic-gate break;
7310Sstevel@tonic-gate
7320Sstevel@tonic-gate case 'o': /* specifies output file for dbug */
7330Sstevel@tonic-gate if (*scan++ == ',') {
7340Sstevel@tonic-gate flist_object_p = flist_create();
7350Sstevel@tonic-gate retval = listparse(scan, flist_object_p);
7360Sstevel@tonic-gate if (retval < 0) {
7370Sstevel@tonic-gate strcpy(res,
7380Sstevel@tonic-gate "mdbug: -o too many output files");
7390Sstevel@tonic-gate goto out;
7400Sstevel@tonic-gate }
7410Sstevel@tonic-gate
7420Sstevel@tonic-gate if (flist_object_p->f_count > 0) {
7430Sstevel@tonic-gate dbug_state_object_p->s_out_file =
7440Sstevel@tonic-gate openfile((char *)
7450Sstevel@tonic-gate fl_top(flist_object_p));
7460Sstevel@tonic-gate if (dbug_state_object_p->s_out_file !=
7470Sstevel@tonic-gate NULL)
7480Sstevel@tonic-gate dbug_state_object_p->sf_didopen
7490Sstevel@tonic-gate = 1;
7500Sstevel@tonic-gate } else
7510Sstevel@tonic-gate dbug_state_object_p->s_out_file =
7520Sstevel@tonic-gate openfile(NULL);
7530Sstevel@tonic-gate flist_destroy(flist_object_p);
7540Sstevel@tonic-gate } else
7550Sstevel@tonic-gate dbug_state_object_p->s_out_file =
7560Sstevel@tonic-gate openfile(NULL);
7570Sstevel@tonic-gate if (dbug_state_object_p->s_out_file == NULL) {
7580Sstevel@tonic-gate strcpy(res,
7590Sstevel@tonic-gate "mdbug: -o cannot open output file");
7600Sstevel@tonic-gate goto out;
7610Sstevel@tonic-gate }
7620Sstevel@tonic-gate break;
7630Sstevel@tonic-gate
7640Sstevel@tonic-gate case 'p': /* debug specified processes */
7650Sstevel@tonic-gate if (*scan++ == ',') {
7660Sstevel@tonic-gate retval = listparse(scan,
7670Sstevel@tonic-gate dbug_state_object_p->s_processes);
7680Sstevel@tonic-gate if (retval < 0) {
7690Sstevel@tonic-gate strcpy(res,
7700Sstevel@tonic-gate "mdbug: -p too many processes");
7710Sstevel@tonic-gate goto out;
7720Sstevel@tonic-gate }
7730Sstevel@tonic-gate }
7740Sstevel@tonic-gate break;
7750Sstevel@tonic-gate
7760Sstevel@tonic-gate case 'P': /* print process name on dbug output */
7770Sstevel@tonic-gate dbug_state_object_p->sf_process = TRUE;
7780Sstevel@tonic-gate break;
7790Sstevel@tonic-gate
7800Sstevel@tonic-gate case 'r': /* reset indentation to zero */
7810Sstevel@tonic-gate dbug_state_object_p->s_level = 0;
7820Sstevel@tonic-gate break;
7830Sstevel@tonic-gate
7840Sstevel@tonic-gate case 's': /* print stack depth on enter */
7850Sstevel@tonic-gate dbug_state_object_p->sf_stack = TRUE;
7860Sstevel@tonic-gate break;
7870Sstevel@tonic-gate
7880Sstevel@tonic-gate case 'R': /* print time prog has been running */
7890Sstevel@tonic-gate dbug_state_object_p->sf_time = TRUE;
7900Sstevel@tonic-gate time(&dbug_state_object_p->s_starttime);
7910Sstevel@tonic-gate break;
7920Sstevel@tonic-gate
7930Sstevel@tonic-gate case 'T': /* print thread information */
7940Sstevel@tonic-gate dbug_state_object_p->sf_thread = TRUE;
7950Sstevel@tonic-gate break;
7960Sstevel@tonic-gate
7970Sstevel@tonic-gate case 't': /* print trace of functions called */
7980Sstevel@tonic-gate dbug_state_object_p->sf_trace = TRUE;
7990Sstevel@tonic-gate dbug_state_object_p->s_maxdepth = MAXDEPTH;
8000Sstevel@tonic-gate if (*scan++ == ',') {
8010Sstevel@tonic-gate flist_object_p = flist_create();
8020Sstevel@tonic-gate retval = listparse(scan, flist_object_p);
8030Sstevel@tonic-gate if (retval < 0) {
8040Sstevel@tonic-gate strcpy(res,
8050Sstevel@tonic-gate "mdbug: -t too many traces");
8060Sstevel@tonic-gate goto out;
8070Sstevel@tonic-gate }
8080Sstevel@tonic-gate if (flist_object_p->f_count > 0) {
8090Sstevel@tonic-gate dbug_state_object_p->s_maxdepth =
8100Sstevel@tonic-gate atoi((char *)
8110Sstevel@tonic-gate fl_top(flist_object_p));
8120Sstevel@tonic-gate }
8130Sstevel@tonic-gate flist_destroy(flist_object_p);
8140Sstevel@tonic-gate }
8150Sstevel@tonic-gate break;
8160Sstevel@tonic-gate }
8170Sstevel@tonic-gate }
8180Sstevel@tonic-gate
8190Sstevel@tonic-gate out:
8200Sstevel@tonic-gate /* free up the dupped control string */
8210Sstevel@tonic-gate free(dupcontrol);
8220Sstevel@tonic-gate
8230Sstevel@tonic-gate UNLOCK_THREAD_DATA();
8240Sstevel@tonic-gate
8250Sstevel@tonic-gate /* return result */
8260Sstevel@tonic-gate return (NULL);
8270Sstevel@tonic-gate }
8280Sstevel@tonic-gate
8290Sstevel@tonic-gate /*
8300Sstevel@tonic-gate *
8310Sstevel@tonic-gate * db_pop
8320Sstevel@tonic-gate *
8330Sstevel@tonic-gate * Description:
8340Sstevel@tonic-gate * Pop the debug stack.
8350Sstevel@tonic-gate */
8360Sstevel@tonic-gate void
db_pop()8370Sstevel@tonic-gate db_pop()
8380Sstevel@tonic-gate {
8390Sstevel@tonic-gate dbug_state_object_t *dbug_state_object_p;
8400Sstevel@tonic-gate
8410Sstevel@tonic-gate LOCK_THREAD_DATA();
8420Sstevel@tonic-gate
8430Sstevel@tonic-gate /* return if no debugging yet */
8440Sstevel@tonic-gate if (sd_push == NULL)
8450Sstevel@tonic-gate goto out;
8460Sstevel@tonic-gate
8470Sstevel@tonic-gate /* get and remove the top item from the list */
8480Sstevel@tonic-gate dbug_state_object_p = sd_push;
8490Sstevel@tonic-gate sd_push = dbug_state_object_p->s_next;
8500Sstevel@tonic-gate
8510Sstevel@tonic-gate /* Delete the item. */
8520Sstevel@tonic-gate dbug_state_destroy(dbug_state_object_p);
8530Sstevel@tonic-gate
8540Sstevel@tonic-gate /* get the current top of the stack */
8550Sstevel@tonic-gate dbug_state_object_p = sd_push;
8560Sstevel@tonic-gate if (dbug_state_object_p) {
8570Sstevel@tonic-gate /* See if debugging is turned on */
8580Sstevel@tonic-gate if (dbug_state_object_p->sf_debug)
8590Sstevel@tonic-gate sd_on = TRUE;
8600Sstevel@tonic-gate else
8610Sstevel@tonic-gate sd_on = FALSE;
8620Sstevel@tonic-gate }
8630Sstevel@tonic-gate
8640Sstevel@tonic-gate out:;
8650Sstevel@tonic-gate UNLOCK_THREAD_DATA();
8660Sstevel@tonic-gate }
8670Sstevel@tonic-gate
8680Sstevel@tonic-gate /*
8690Sstevel@tonic-gate *
8700Sstevel@tonic-gate * db_process
8710Sstevel@tonic-gate *
8720Sstevel@tonic-gate * Description:
8730Sstevel@tonic-gate * Specifies the name of the process.
8740Sstevel@tonic-gate * Only the pointer is saved, the string is not copied.
8750Sstevel@tonic-gate * Arguments:
8760Sstevel@tonic-gate * namep
8770Sstevel@tonic-gate * Returns:
8780Sstevel@tonic-gate * Preconditions:
8790Sstevel@tonic-gate */
8800Sstevel@tonic-gate void
db_process(const char * namep)8810Sstevel@tonic-gate db_process(const char *namep)
8820Sstevel@tonic-gate {
8830Sstevel@tonic-gate thread_data_t *tdp;
8840Sstevel@tonic-gate
8850Sstevel@tonic-gate strcpy(sd_process, namep);
8860Sstevel@tonic-gate
8870Sstevel@tonic-gate #ifdef STACKINIT
8880Sstevel@tonic-gate GET_THREAD_DATA_PTR(&tdp);
889*633Sgt29601 tdp->td_stackinit = (ulong_t)this;
8900Sstevel@tonic-gate #endif
8910Sstevel@tonic-gate }
8920Sstevel@tonic-gate
8930Sstevel@tonic-gate /*
8940Sstevel@tonic-gate *
8950Sstevel@tonic-gate * listparse
8960Sstevel@tonic-gate *
8970Sstevel@tonic-gate * Description:
8980Sstevel@tonic-gate * parse list of modifiers in debug control string
8990Sstevel@tonic-gate *
9000Sstevel@tonic-gate * Given pointer to a comma separated list of strings in "cltp",
9010Sstevel@tonic-gate * parses the list, building a list and returning a pointer to it.
9020Sstevel@tonic-gate * The original comma separated list is destroyed in the process of
9030Sstevel@tonic-gate * building the linked list, thus it had better be a duplicate
9040Sstevel@tonic-gate * if it is important.
9050Sstevel@tonic-gate *
9060Sstevel@tonic-gate * This routine is only called from db_push.
9070Sstevel@tonic-gate * Returns 0 for success, -1 for failure.
9080Sstevel@tonic-gate */
9090Sstevel@tonic-gate static int
listparse(register char * ctlp,flist_object_t * head)9100Sstevel@tonic-gate listparse(register char *ctlp, flist_object_t *head)
9110Sstevel@tonic-gate {
9120Sstevel@tonic-gate char *start;
9130Sstevel@tonic-gate char *item;
9140Sstevel@tonic-gate
9150Sstevel@tonic-gate /* scan the string until end */
9160Sstevel@tonic-gate while (*ctlp != '\0') {
9170Sstevel@tonic-gate /* See if no more room on the list */
9180Sstevel@tonic-gate if (fl_space(head) == 0)
9190Sstevel@tonic-gate return (-1);
9200Sstevel@tonic-gate
9210Sstevel@tonic-gate /* save the begining of this section */
9220Sstevel@tonic-gate start = ctlp;
9230Sstevel@tonic-gate
9240Sstevel@tonic-gate /* loop until the end of the token is found */
9250Sstevel@tonic-gate while ((*ctlp != '\0') && (*ctlp != ','))
9260Sstevel@tonic-gate ctlp++;
9270Sstevel@tonic-gate
9280Sstevel@tonic-gate /* add a string terminator if necessary, for strdup */
9290Sstevel@tonic-gate if (*ctlp == ',')
9300Sstevel@tonic-gate *ctlp++ = '\0';
9310Sstevel@tonic-gate
9320Sstevel@tonic-gate /* make a copy of the string */
9330Sstevel@tonic-gate item = strdup(start);
9340Sstevel@tonic-gate if (item == NULL)
9350Sstevel@tonic-gate return (-1);
9360Sstevel@tonic-gate
9370Sstevel@tonic-gate /* add it to the list */
9380Sstevel@tonic-gate fl_push(head, item);
9390Sstevel@tonic-gate }
9400Sstevel@tonic-gate
9410Sstevel@tonic-gate return (0);
9420Sstevel@tonic-gate }
9430Sstevel@tonic-gate
9440Sstevel@tonic-gate /*
9450Sstevel@tonic-gate *
9460Sstevel@tonic-gate * inlist
9470Sstevel@tonic-gate *
9480Sstevel@tonic-gate * Description:
9490Sstevel@tonic-gate * Tests the string pointed to by "cp" to determine if it is in
9500Sstevel@tonic-gate * the list pointed to by "flist_object_p". Linkp points to the first
9510Sstevel@tonic-gate * link in the list. If flist_object_p is empty then the string is treated
9520Sstevel@tonic-gate * as if it is in the list (I.E all strings are in the null list).
9530Sstevel@tonic-gate * This may seem rather strange at first but leads to the desired
9540Sstevel@tonic-gate * operation if no list is given. The net effect is that all
9550Sstevel@tonic-gate * strings will be accepted when there is no list, and when there
9560Sstevel@tonic-gate * is a list, only those strings in the list will be accepted.
9570Sstevel@tonic-gate */
9580Sstevel@tonic-gate static boolean
inlist(flist_object_t * flist_object_p,const char * cp)9590Sstevel@tonic-gate inlist(flist_object_t *flist_object_p, const char *cp)
9600Sstevel@tonic-gate {
9610Sstevel@tonic-gate register boolean accept;
9620Sstevel@tonic-gate register char *item;
9630Sstevel@tonic-gate
9640Sstevel@tonic-gate if ((flist_object_p == NULL) || (flist_object_p->f_count == 0) ||
9650Sstevel@tonic-gate (cp == NULL))
9660Sstevel@tonic-gate accept = TRUE;
9670Sstevel@tonic-gate else {
9680Sstevel@tonic-gate accept = FALSE;
9690Sstevel@tonic-gate
9700Sstevel@tonic-gate /* walk the list of items */
9710Sstevel@tonic-gate for (item = (char *)fl_top(flist_object_p);
9720Sstevel@tonic-gate item != NULL;
9730Sstevel@tonic-gate item = (char *)fl_next(flist_object_p)) {
9740Sstevel@tonic-gate /* see if a match */
9750Sstevel@tonic-gate if (strcmp(item, cp) == 0) {
9760Sstevel@tonic-gate accept = TRUE;
9770Sstevel@tonic-gate break;
9780Sstevel@tonic-gate }
9790Sstevel@tonic-gate }
9800Sstevel@tonic-gate }
9810Sstevel@tonic-gate
9820Sstevel@tonic-gate return (accept);
9830Sstevel@tonic-gate }
9840Sstevel@tonic-gate
9850Sstevel@tonic-gate /*
9860Sstevel@tonic-gate *
9870Sstevel@tonic-gate * dotrace
9880Sstevel@tonic-gate *
9890Sstevel@tonic-gate * Description:
9900Sstevel@tonic-gate * Checks to see if tracing is enabled based on whether the
9910Sstevel@tonic-gate * user has specified tracing, the maximum trace depth has
9920Sstevel@tonic-gate * not yet been reached, the current function is selected,
9930Sstevel@tonic-gate * and the current process is selected. Returns TRUE if
9940Sstevel@tonic-gate * tracing is enabled, FALSE otherwise.
9950Sstevel@tonic-gate */
9960Sstevel@tonic-gate static boolean
dotrace(dbug_state_object_t * dbug_state_object_p,const char * func,const char * process)9970Sstevel@tonic-gate dotrace(dbug_state_object_t *dbug_state_object_p, const char *func,
9980Sstevel@tonic-gate const char *process)
9990Sstevel@tonic-gate {
10000Sstevel@tonic-gate boolean trace;
10010Sstevel@tonic-gate
10020Sstevel@tonic-gate trace = FALSE;
10030Sstevel@tonic-gate if (dbug_state_object_p->sf_trace) {
10040Sstevel@tonic-gate if (dbug_state_object_p->s_level <=
10050Sstevel@tonic-gate dbug_state_object_p->s_maxdepth) {
10060Sstevel@tonic-gate if (inlist(dbug_state_object_p->s_functions, func)) {
10070Sstevel@tonic-gate if (inlist(dbug_state_object_p->s_processes,
10080Sstevel@tonic-gate process)) {
10090Sstevel@tonic-gate trace = TRUE;
10100Sstevel@tonic-gate }
10110Sstevel@tonic-gate }
10120Sstevel@tonic-gate }
10130Sstevel@tonic-gate }
10140Sstevel@tonic-gate
10150Sstevel@tonic-gate return (trace);
10160Sstevel@tonic-gate }
10170Sstevel@tonic-gate
10180Sstevel@tonic-gate /*
10190Sstevel@tonic-gate *
10200Sstevel@tonic-gate * indent
10210Sstevel@tonic-gate *
10220Sstevel@tonic-gate * Description:
10230Sstevel@tonic-gate * Indent a line to the given level. Note that this is
10240Sstevel@tonic-gate * a simple minded but portable implementation.
10250Sstevel@tonic-gate * There are better ways.
10260Sstevel@tonic-gate *
10270Sstevel@tonic-gate * Also, the indent must be scaled by the compile time option
10280Sstevel@tonic-gate * of character positions per nesting level.
10290Sstevel@tonic-gate */
10300Sstevel@tonic-gate static void
indent(register dbug_state_object_t * dbug_state_object_p,int indent)10310Sstevel@tonic-gate indent(register dbug_state_object_t *dbug_state_object_p, int indent)
10320Sstevel@tonic-gate {
10330Sstevel@tonic-gate register int count;
10340Sstevel@tonic-gate char buffer[PRINTBUF];
10350Sstevel@tonic-gate
10360Sstevel@tonic-gate indent *= INDENT;
10370Sstevel@tonic-gate for (count = 0;
10380Sstevel@tonic-gate (count < (indent - INDENT)) && (count < (PRINTBUF - 1));
10390Sstevel@tonic-gate count++) {
10400Sstevel@tonic-gate if ((count % INDENT) == 0)
10410Sstevel@tonic-gate buffer[count] = '|';
10420Sstevel@tonic-gate else
10430Sstevel@tonic-gate buffer[count] = ' ';
10440Sstevel@tonic-gate }
10450Sstevel@tonic-gate
10460Sstevel@tonic-gate buffer[count] = '\0';
10470Sstevel@tonic-gate fprintf(dbug_state_object_p->s_out_file, buffer);
10480Sstevel@tonic-gate fflush(dbug_state_object_p->s_out_file);
10490Sstevel@tonic-gate }
10500Sstevel@tonic-gate
10510Sstevel@tonic-gate /*
10520Sstevel@tonic-gate *
10530Sstevel@tonic-gate * doprefix
10540Sstevel@tonic-gate *
10550Sstevel@tonic-gate * Description:
10560Sstevel@tonic-gate * Print prefix common to all debugger output lines, prior to
10570Sstevel@tonic-gate * doing indentation if necessary. Print such information as
10580Sstevel@tonic-gate * current process name, current source file name and line number,
10590Sstevel@tonic-gate * and current function nesting depth.
10600Sstevel@tonic-gate */
10610Sstevel@tonic-gate static void
doprefix(dbug_state_object_t * dbug_state_object_p,int line,long lineno,const char * file,const char * process)10620Sstevel@tonic-gate doprefix(dbug_state_object_t *dbug_state_object_p, int line, long lineno,
10630Sstevel@tonic-gate const char *file, const char *process)
10640Sstevel@tonic-gate {
10650Sstevel@tonic-gate #if DBUG_UNIX
10660Sstevel@tonic-gate if (dbug_state_object_p->sf_pid)
1067*633Sgt29601 fprintf(dbug_state_object_p->s_out_file, "%5d: ",
1068*633Sgt29601 (int)getpid());
10690Sstevel@tonic-gate #endif
10700Sstevel@tonic-gate
10710Sstevel@tonic-gate if (dbug_state_object_p->sf_thread)
1072*633Sgt29601 fprintf(dbug_state_object_p->s_out_file, "%5ld: ",
1073*633Sgt29601 (long)thr_self());
10740Sstevel@tonic-gate
10750Sstevel@tonic-gate if (dbug_state_object_p->sf_number)
10760Sstevel@tonic-gate fprintf(dbug_state_object_p->s_out_file, "%5ld: ", lineno);
10770Sstevel@tonic-gate
10780Sstevel@tonic-gate if (dbug_state_object_p->sf_process && process)
10790Sstevel@tonic-gate fprintf(dbug_state_object_p->s_out_file, "%s: ", process);
10800Sstevel@tonic-gate
10810Sstevel@tonic-gate if (dbug_state_object_p->sf_file)
10820Sstevel@tonic-gate fprintf(dbug_state_object_p->s_out_file, "%14s: ", file);
10830Sstevel@tonic-gate
10840Sstevel@tonic-gate if (dbug_state_object_p->sf_line)
10850Sstevel@tonic-gate fprintf(dbug_state_object_p->s_out_file, "%5d: ", line);
10860Sstevel@tonic-gate
10870Sstevel@tonic-gate if (dbug_state_object_p->sf_depth)
10880Sstevel@tonic-gate fprintf(dbug_state_object_p->s_out_file, "%4d: ",
10890Sstevel@tonic-gate dbug_state_object_p->s_level);
10900Sstevel@tonic-gate
10910Sstevel@tonic-gate fflush(dbug_state_object_p->s_out_file);
10920Sstevel@tonic-gate }
10930Sstevel@tonic-gate
10940Sstevel@tonic-gate /*
10950Sstevel@tonic-gate *
10960Sstevel@tonic-gate * openfile
10970Sstevel@tonic-gate *
10980Sstevel@tonic-gate * Description:
10990Sstevel@tonic-gate * Given name of a new file (or NULL for stdout) opens the file
11000Sstevel@tonic-gate * and sets the output stream to the new file.
11010Sstevel@tonic-gate */
11020Sstevel@tonic-gate static FILE *
openfile(char * name)11030Sstevel@tonic-gate openfile(char *name)
11040Sstevel@tonic-gate {
11050Sstevel@tonic-gate FILE *fp;
11060Sstevel@tonic-gate boolean newfile;
11070Sstevel@tonic-gate
11080Sstevel@tonic-gate if (name == NULL)
11090Sstevel@tonic-gate return (stdout);
11100Sstevel@tonic-gate
11110Sstevel@tonic-gate if (NOT writable(name))
11120Sstevel@tonic-gate return (NULL);
11130Sstevel@tonic-gate
11140Sstevel@tonic-gate /* see if the file already exists */
11150Sstevel@tonic-gate if (file_exists(name))
11160Sstevel@tonic-gate newfile = FALSE;
11170Sstevel@tonic-gate else
11180Sstevel@tonic-gate newfile = TRUE;
11190Sstevel@tonic-gate
11200Sstevel@tonic-gate /* open the file */
11210Sstevel@tonic-gate fp = fopen(name, "a+");
11220Sstevel@tonic-gate if (fp == NULL)
11230Sstevel@tonic-gate return (NULL);
11240Sstevel@tonic-gate
11250Sstevel@tonic-gate /*
11260Sstevel@tonic-gate * If the file is newly created, give it away to the user
11270Sstevel@tonic-gate * that started the program.
11280Sstevel@tonic-gate */
11290Sstevel@tonic-gate if (newfile) {
11300Sstevel@tonic-gate changeowner(name);
11310Sstevel@tonic-gate }
11320Sstevel@tonic-gate return (fp);
11330Sstevel@tonic-gate }
11340Sstevel@tonic-gate
11350Sstevel@tonic-gate /*
11360Sstevel@tonic-gate *
11370Sstevel@tonic-gate * writable
11380Sstevel@tonic-gate *
11390Sstevel@tonic-gate * Description:
11400Sstevel@tonic-gate * Because the debugger might be linked in with a program that
11410Sstevel@tonic-gate * runs with the set-uid-bit (suid) set, we have to be careful
11420Sstevel@tonic-gate * about opening a user named file for debug output. This consists
11430Sstevel@tonic-gate * of checking the file for write access with the real user id,
11440Sstevel@tonic-gate * or checking the directory where the file will be created.
11450Sstevel@tonic-gate *
11460Sstevel@tonic-gate * Returns TRUE if the user would normally be allowed write or
11470Sstevel@tonic-gate * create access to the named file. Returns FALSE otherwise.
11480Sstevel@tonic-gate */
11490Sstevel@tonic-gate static boolean
writable(char * pathname)11500Sstevel@tonic-gate writable(char *pathname)
11510Sstevel@tonic-gate {
11520Sstevel@tonic-gate #if DBUG_UNIX
11530Sstevel@tonic-gate
11540Sstevel@tonic-gate char *lastslash;
11550Sstevel@tonic-gate
11560Sstevel@tonic-gate boolean granted = FALSE;
11570Sstevel@tonic-gate if (file_exists(pathname)) {
11580Sstevel@tonic-gate if (file_writable(pathname)) {
11590Sstevel@tonic-gate granted = TRUE;
11600Sstevel@tonic-gate }
11610Sstevel@tonic-gate } else {
11620Sstevel@tonic-gate lastslash = strrchr(pathname, '/');
11630Sstevel@tonic-gate if (lastslash != NULL) {
11640Sstevel@tonic-gate *lastslash = '\0';
11650Sstevel@tonic-gate } else {
11660Sstevel@tonic-gate pathname = ".";
11670Sstevel@tonic-gate }
11680Sstevel@tonic-gate if (file_writable(pathname)) {
11690Sstevel@tonic-gate granted = TRUE;
11700Sstevel@tonic-gate }
11710Sstevel@tonic-gate if (lastslash != NULL) {
11720Sstevel@tonic-gate *lastslash = '/';
11730Sstevel@tonic-gate }
11740Sstevel@tonic-gate }
11750Sstevel@tonic-gate return (granted);
11760Sstevel@tonic-gate #else
11770Sstevel@tonic-gate return (TRUE);
11780Sstevel@tonic-gate #endif
11790Sstevel@tonic-gate }
11800Sstevel@tonic-gate
11810Sstevel@tonic-gate /*
11820Sstevel@tonic-gate *
11830Sstevel@tonic-gate * changeowner
11840Sstevel@tonic-gate *
11850Sstevel@tonic-gate * Description:
11860Sstevel@tonic-gate * For unix systems, change the owner of the newly created debug
11870Sstevel@tonic-gate * file to the real owner. This is strictly for the benefit of
11880Sstevel@tonic-gate * programs that are running with the set-user-id bit set.
11890Sstevel@tonic-gate *
11900Sstevel@tonic-gate * Note that at this point, the fact that pathname represents
11910Sstevel@tonic-gate * a newly created file has already been established. If the
11920Sstevel@tonic-gate * program that the debugger is linked to is not running with
11930Sstevel@tonic-gate * the suid bit set, then this operation is redundant (but
11940Sstevel@tonic-gate * harmless).
11950Sstevel@tonic-gate */
11960Sstevel@tonic-gate static void
changeowner(char * pathname)11970Sstevel@tonic-gate changeowner(char *pathname)
11980Sstevel@tonic-gate {
11990Sstevel@tonic-gate #if DBUG_UNIX
12000Sstevel@tonic-gate chown(pathname, getuid(), getgid());
12010Sstevel@tonic-gate #endif
12020Sstevel@tonic-gate }
12030Sstevel@tonic-gate
12040Sstevel@tonic-gate /*
12050Sstevel@tonic-gate *
12060Sstevel@tonic-gate * delayarg
12070Sstevel@tonic-gate *
12080Sstevel@tonic-gate * Description:
12090Sstevel@tonic-gate * Converts delay argument, given in tenths of a second, to the
12100Sstevel@tonic-gate * appropriate numerical argument used by the system to delay
12110Sstevel@tonic-gate * that that many tenths of a second. For example, on the
12120Sstevel@tonic-gate * amiga, there is a system call "Delay()" which takes an
12130Sstevel@tonic-gate * argument in ticks (50 per second). On unix, the sleep
12140Sstevel@tonic-gate * command takes seconds. Thus a value of "10", for one
12150Sstevel@tonic-gate * second of delay, gets converted to 50 on the amiga, and 1
12160Sstevel@tonic-gate * on unix. Other systems will need to use a timing loop.
12170Sstevel@tonic-gate */
12180Sstevel@tonic-gate static int
delayarg(int value)12190Sstevel@tonic-gate delayarg(int value)
12200Sstevel@tonic-gate {
12210Sstevel@tonic-gate unsigned int delayarg = 0;
12220Sstevel@tonic-gate
12230Sstevel@tonic-gate #if (unix || xenix)
12240Sstevel@tonic-gate delayarg = value / 10; /* Delay is in seconds for sleep () */
12250Sstevel@tonic-gate #endif
12260Sstevel@tonic-gate return (delayarg);
12270Sstevel@tonic-gate }
12280Sstevel@tonic-gate
12290Sstevel@tonic-gate /*
12300Sstevel@tonic-gate *
12310Sstevel@tonic-gate * delay
12320Sstevel@tonic-gate *
12330Sstevel@tonic-gate * Description:
12340Sstevel@tonic-gate * Implements the delay function.
12350Sstevel@tonic-gate *
12360Sstevel@tonic-gate * A dummy delay stub for systems that do not support delays.
12370Sstevel@tonic-gate * With a little work, this can be turned into a timing loop.
12380Sstevel@tonic-gate */
12390Sstevel@tonic-gate
12400Sstevel@tonic-gate static void
delay(uint_t xx)1241*633Sgt29601 delay(uint_t xx)
12420Sstevel@tonic-gate {
12430Sstevel@tonic-gate #if (unix || xenix)
12440Sstevel@tonic-gate sleep(xx);
12450Sstevel@tonic-gate #endif
12460Sstevel@tonic-gate #if amiga
12470Sstevel@tonic-gate Delay(xx);
12480Sstevel@tonic-gate #endif
12490Sstevel@tonic-gate #ifdef __ZTC__
1250*633Sgt29601 msleep((ulong_t)xx);
12510Sstevel@tonic-gate #endif
12520Sstevel@tonic-gate }
12530Sstevel@tonic-gate
12540Sstevel@tonic-gate /*
12550Sstevel@tonic-gate *
12560Sstevel@tonic-gate * getclock
12570Sstevel@tonic-gate *
12580Sstevel@tonic-gate * Description:
12590Sstevel@tonic-gate * Returns the time in milliseconds used by this process
12600Sstevel@tonic-gate * so far.
12610Sstevel@tonic-gate */
12620Sstevel@tonic-gate #if (unix || xenix)
12630Sstevel@tonic-gate
12640Sstevel@tonic-gate #include <sys/param.h>
12650Sstevel@tonic-gate #if BSD4_3 || sun
12660Sstevel@tonic-gate
12670Sstevel@tonic-gate #include <sys/time.h>
12680Sstevel@tonic-gate #include <sys/resource.h>
12690Sstevel@tonic-gate
1270*633Sgt29601 static ulong_t
getclock()12710Sstevel@tonic-gate getclock()
12720Sstevel@tonic-gate {
12730Sstevel@tonic-gate #if 0
12740Sstevel@tonic-gate struct rusage ru;
12750Sstevel@tonic-gate
12760Sstevel@tonic-gate getrusage(RUSAGE_SELF, &ru);
12770Sstevel@tonic-gate return ((ru.ru_utime.tv_sec * 1000) + (ru.ru_utime.tv_usec / 1000));
12780Sstevel@tonic-gate #else
12790Sstevel@tonic-gate return (0);
12800Sstevel@tonic-gate #endif
12810Sstevel@tonic-gate }
12820Sstevel@tonic-gate
12830Sstevel@tonic-gate #else
12840Sstevel@tonic-gate
1285*633Sgt29601 static ulong_t
getclock()12860Sstevel@tonic-gate getclock()
12870Sstevel@tonic-gate {
12880Sstevel@tonic-gate return (0);
12890Sstevel@tonic-gate }
12900Sstevel@tonic-gate
12910Sstevel@tonic-gate #endif
12920Sstevel@tonic-gate #endif /* unix */
12930Sstevel@tonic-gate
12940Sstevel@tonic-gate #ifdef MSDOS
1295*633Sgt29601 static ulong_t
getclock()12960Sstevel@tonic-gate getclock()
12970Sstevel@tonic-gate {
12980Sstevel@tonic-gate return (clock() * 10);
12990Sstevel@tonic-gate }
13000Sstevel@tonic-gate #endif
13010Sstevel@tonic-gate
13020Sstevel@tonic-gate /*
13030Sstevel@tonic-gate *
13040Sstevel@tonic-gate * mystrtok
13050Sstevel@tonic-gate *
13060Sstevel@tonic-gate * Description:
13070Sstevel@tonic-gate * A version of strtok for those systems without it
13080Sstevel@tonic-gate */
13090Sstevel@tonic-gate static char *
mystrtok(char * s1,char * s2)13100Sstevel@tonic-gate mystrtok(char *s1, char *s2)
13110Sstevel@tonic-gate {
13120Sstevel@tonic-gate static char *end = NULL;
13130Sstevel@tonic-gate register char *rtnval;
13140Sstevel@tonic-gate
13150Sstevel@tonic-gate rtnval = NULL;
13160Sstevel@tonic-gate if (s2 != NULL) {
13170Sstevel@tonic-gate if (s1 != NULL) {
13180Sstevel@tonic-gate end = s1;
1319*633Sgt29601 rtnval = mystrtok((char *)NULL, s2);
13200Sstevel@tonic-gate } else if (end != NULL) {
13210Sstevel@tonic-gate if (*end != '\0') {
13220Sstevel@tonic-gate rtnval = end;
13230Sstevel@tonic-gate while ((*end != *s2) && (*end != '\0')) {
13240Sstevel@tonic-gate end++;
13250Sstevel@tonic-gate }
13260Sstevel@tonic-gate if (*end != '\0') {
13270Sstevel@tonic-gate *end++ = '\0';
13280Sstevel@tonic-gate }
13290Sstevel@tonic-gate }
13300Sstevel@tonic-gate }
13310Sstevel@tonic-gate }
13320Sstevel@tonic-gate
13330Sstevel@tonic-gate return (rtnval);
13340Sstevel@tonic-gate }
13350Sstevel@tonic-gate
13360Sstevel@tonic-gate /*
13370Sstevel@tonic-gate *
13380Sstevel@tonic-gate * dbug_thread_exit
13390Sstevel@tonic-gate *
13400Sstevel@tonic-gate * Description:
13410Sstevel@tonic-gate * Called when a thread exits.
13420Sstevel@tonic-gate * Arguments:
13430Sstevel@tonic-gate * data pointer to thread specific data
13440Sstevel@tonic-gate * Returns:
13450Sstevel@tonic-gate * Preconditions:
13460Sstevel@tonic-gate */
13470Sstevel@tonic-gate void
dbug_thread_exit(void * data)13480Sstevel@tonic-gate dbug_thread_exit(void *data)
13490Sstevel@tonic-gate {
13500Sstevel@tonic-gate dbug_state_object_t *dbug_state_object_p;
13510Sstevel@tonic-gate
13520Sstevel@tonic-gate LOCK_THREAD_DATA();
13530Sstevel@tonic-gate
13540Sstevel@tonic-gate /* If debugging is off, then nothing else to do */
13550Sstevel@tonic-gate if (NOT db_debugon())
13560Sstevel@tonic-gate goto out;
13570Sstevel@tonic-gate
13580Sstevel@tonic-gate /* get a pointer to the active state */
13590Sstevel@tonic-gate dbug_state_object_p = sd_push;
13600Sstevel@tonic-gate
13610Sstevel@tonic-gate if (dbug_state_object_p->sf_thread) {
13620Sstevel@tonic-gate doprefix(dbug_state_object_p, 0, sd_lineno++, "unknown",
13630Sstevel@tonic-gate sd_process);
13640Sstevel@tonic-gate indent(dbug_state_object_p, dbug_state_object_p->s_level);
13650Sstevel@tonic-gate fprintf(dbug_state_object_p->s_out_file, "thread destroyed\n");
13660Sstevel@tonic-gate fflush(dbug_state_object_p->s_out_file);
13670Sstevel@tonic-gate delay(dbug_state_object_p->s_delay);
13680Sstevel@tonic-gate }
13690Sstevel@tonic-gate
13700Sstevel@tonic-gate out:;
13710Sstevel@tonic-gate FREE_THREAD_DATA(data);
13720Sstevel@tonic-gate UNLOCK_THREAD_DATA();
13730Sstevel@tonic-gate }
13740Sstevel@tonic-gate
13750Sstevel@tonic-gate /*
13760Sstevel@tonic-gate *
13770Sstevel@tonic-gate * doabort
13780Sstevel@tonic-gate *
13790Sstevel@tonic-gate * Description:
13800Sstevel@tonic-gate * Causes the process to exit immediatly with a core dump.
13810Sstevel@tonic-gate * Arguments:
13820Sstevel@tonic-gate * Returns:
13830Sstevel@tonic-gate * Preconditions:
13840Sstevel@tonic-gate */
13850Sstevel@tonic-gate void
doabort()13860Sstevel@tonic-gate doabort()
13870Sstevel@tonic-gate {
13880Sstevel@tonic-gate dbug_state_object_t *dbug_state_object_p = sd_push;
13890Sstevel@tonic-gate fflush(dbug_state_object_p->s_out_file);
13900Sstevel@tonic-gate for (;;) {
13910Sstevel@tonic-gate kill(getpid(), SIGABRT);
13920Sstevel@tonic-gate (void) signal(SIGABRT, SIG_DFL);
13930Sstevel@tonic-gate (void) sigrelse(SIGABRT);
13940Sstevel@tonic-gate }
13950Sstevel@tonic-gate }
13960Sstevel@tonic-gate
13970Sstevel@tonic-gate /*
13980Sstevel@tonic-gate *
13990Sstevel@tonic-gate * dbug_state_create
14000Sstevel@tonic-gate *
14010Sstevel@tonic-gate * Description:
14020Sstevel@tonic-gate * Constructor for the dbug_state class.
14030Sstevel@tonic-gate * Arguments:
14040Sstevel@tonic-gate * The current level in the call stack.
14050Sstevel@tonic-gate * Returns:
14060Sstevel@tonic-gate * Preconditions:
14070Sstevel@tonic-gate */
14080Sstevel@tonic-gate dbug_state_object_t *
dbug_state_create(int level)14090Sstevel@tonic-gate dbug_state_create(int level)
14100Sstevel@tonic-gate {
14110Sstevel@tonic-gate dbug_state_object_t *dbug_state_object_p;
14120Sstevel@tonic-gate
14130Sstevel@tonic-gate dbug_state_object_p =
14140Sstevel@tonic-gate (dbug_state_object_t *)calloc(sizeof (dbug_state_object_t), 1);
14150Sstevel@tonic-gate
14160Sstevel@tonic-gate if (dbug_state_object_p == NULL)
14170Sstevel@tonic-gate doabort();
14180Sstevel@tonic-gate
14190Sstevel@tonic-gate dbug_state_object_p->sf_trace = 0;
14200Sstevel@tonic-gate dbug_state_object_p->sf_debug = 0;
14210Sstevel@tonic-gate dbug_state_object_p->sf_file = 0;
14220Sstevel@tonic-gate dbug_state_object_p->sf_line = 0;
14230Sstevel@tonic-gate dbug_state_object_p->sf_depth = 0;
14240Sstevel@tonic-gate dbug_state_object_p->sf_process = 0;
14250Sstevel@tonic-gate dbug_state_object_p->sf_number = 0;
14260Sstevel@tonic-gate dbug_state_object_p->sf_pid = 0;
14270Sstevel@tonic-gate dbug_state_object_p->sf_stack = 0;
14280Sstevel@tonic-gate dbug_state_object_p->sf_time = 0;
14290Sstevel@tonic-gate dbug_state_object_p->sf_didopen = 0;
14300Sstevel@tonic-gate dbug_state_object_p->sf_thread = 0;
14310Sstevel@tonic-gate dbug_state_object_p->s_maxdepth = MAXDEPTH;
14320Sstevel@tonic-gate dbug_state_object_p->s_delay = 0;
14330Sstevel@tonic-gate dbug_state_object_p->s_level = level;
14340Sstevel@tonic-gate dbug_state_object_p->s_starttime = 0;
14350Sstevel@tonic-gate dbug_state_object_p->s_out_file = stderr;
14360Sstevel@tonic-gate dbug_state_object_p->s_next = NULL;
14370Sstevel@tonic-gate return (dbug_state_object_p);
14380Sstevel@tonic-gate }
14390Sstevel@tonic-gate
14400Sstevel@tonic-gate /*
14410Sstevel@tonic-gate *
14420Sstevel@tonic-gate * dbug_state_destroy
14430Sstevel@tonic-gate *
14440Sstevel@tonic-gate * Description:
14450Sstevel@tonic-gate * Destructor for the dbug_state class.
14460Sstevel@tonic-gate * Arguments:
14470Sstevel@tonic-gate * Returns:
14480Sstevel@tonic-gate * Preconditions:
14490Sstevel@tonic-gate */
14500Sstevel@tonic-gate void
dbug_state_destroy(dbug_state_object_t * dbug_state_object_p)14510Sstevel@tonic-gate dbug_state_destroy(dbug_state_object_t *dbug_state_object_p)
14520Sstevel@tonic-gate {
14530Sstevel@tonic-gate if (dbug_state_object_p->sf_didopen)
14540Sstevel@tonic-gate fclose(dbug_state_object_p->s_out_file);
14550Sstevel@tonic-gate free(dbug_state_object_p);
14560Sstevel@tonic-gate }
14570Sstevel@tonic-gate
14580Sstevel@tonic-gate /*
14590Sstevel@tonic-gate *
14600Sstevel@tonic-gate * db_debugon
14610Sstevel@tonic-gate *
14620Sstevel@tonic-gate * Description:
14630Sstevel@tonic-gate * Returns 1 if debugging is currently enabled, 0 otherwise.
14640Sstevel@tonic-gate * Arguments:
14650Sstevel@tonic-gate * Returns:
14660Sstevel@tonic-gate * Errors:
14670Sstevel@tonic-gate * Preconditions:
14680Sstevel@tonic-gate */
14690Sstevel@tonic-gate
14700Sstevel@tonic-gate int
db_debugon(dbug_object_p)14710Sstevel@tonic-gate db_debugon(dbug_object_p)
14720Sstevel@tonic-gate dbug_object_t *dbug_object_p;
14730Sstevel@tonic-gate {
14740Sstevel@tonic-gate return (sd_on);
14750Sstevel@tonic-gate }
14760Sstevel@tonic-gate boolean
file_exists(const char * pathname)14770Sstevel@tonic-gate file_exists(const char *pathname)
14780Sstevel@tonic-gate {
14790Sstevel@tonic-gate return (access(pathname, F_OK) == 0);
14800Sstevel@tonic-gate }
14810Sstevel@tonic-gate boolean
file_writable(const char * pathname)14820Sstevel@tonic-gate file_writable(const char *pathname)
14830Sstevel@tonic-gate {
14840Sstevel@tonic-gate return (access(pathname, W_OK) == 0);
14850Sstevel@tonic-gate }
14860Sstevel@tonic-gate dbug_object_t *
db_get_dbug_object_p()14870Sstevel@tonic-gate db_get_dbug_object_p()
14880Sstevel@tonic-gate {
14890Sstevel@tonic-gate thread_data_t *tdp;
14900Sstevel@tonic-gate
14910Sstevel@tonic-gate GET_THREAD_DATA_PTR(&tdp);
14920Sstevel@tonic-gate return (tdp->td_first);
14930Sstevel@tonic-gate }
14940Sstevel@tonic-gate #endif /* DBUG_OFF */
1495