xref: /titanic_44/usr/src/lib/libbc/csu/common/mon.c (revision b7f45089ccbe01bab3d7c7377b49d80d2ae18a69)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 1989 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  *	Environment variable PROFDIR added such that:
31  *		If PROFDIR doesn't exist, "mon.out" is produced as before.
32  *		If PROFDIR = NULL, no profiling output is produced.
33  *		If PROFDIR = string, "string/pid.progname" is produced,
34  *		  where name consists of argv[0] suitably massaged.
35  */
36 #include <sys/param.h>
37 #include <sys/dir.h>
38 #include "mon.h"
39 #define PROFDIR	"PROFDIR"
40 
41 extern int creat(), write(), close(), getpid();
42 extern void profil(), perror();
43 extern char *getenv(), *strcpy(), *strrchr();
44 
45 void monitor(), moncontrol();
46 
47 char **___Argv = NULL; /* initialized to argv array by mcrt0 (if loaded) */
48 
49 struct cnt	*countbase;
50 int		numctrs;
51 int		profiling;
52 
53 static struct mondata {
54 	char	*s_sbuf;
55 	int 	s_bufsiz;
56 	int	s_scale;
57 	int	s_lowpc;
58 	char	mon_out[MAXPATHLEN];
59 	char	progname[MAXNAMLEN];
60 } *mondata, *_mondata();
61 
62 #define	MSG "No space for monitor buffer(s)\n"
63 
64 static struct mondata *
65 _mondata()
66 {
67 	register struct mondata *d = mondata;
68 
69 	if (d == 0) {
70 		if ((d = (struct mondata *)
71 			calloc(1, sizeof(struct mondata))) == NULL) {
72 				return (NULL);
73 		}
74 		mondata = d;
75 	}
76 	return (d);
77 }
78 
79 monstartup(lowpc, highpc)
80 	char *lowpc;
81 	char *highpc;
82 {
83 	int monsize;
84 	char *buffer;
85 	int cntsiz;
86 	char *_alloc_profil_buf();
87 
88 	cntsiz = (highpc - lowpc) * ARCDENSITY / 100;
89 	if (cntsiz < MINARCS)
90 		cntsiz = MINARCS;
91 	monsize = (highpc - lowpc + HISTFRACTION - 1) / HISTFRACTION
92 		+ sizeof(struct phdr) + cntsiz * sizeof(struct cnt);
93 	buffer = _alloc_profil_buf(monsize);
94 	if (buffer == (char *)-1) {
95 		write(2, MSG, sizeof(MSG));
96 		return;
97 	}
98 	monitor(lowpc, highpc, buffer, monsize, cntsiz);
99 }
100 
101 void
102 monitor(lowpc, highpc, buf, bufsiz, cntsiz)
103 	char *lowpc, *highpc;	/* boundaries of text to be monitored */
104 	char *buf;		/* ptr to space for monitor data (WORDs) */
105 	int bufsiz;		/* size of above space (in WORDs) */
106 	int cntsiz;		/* max no. of functions whose calls are counted */
107 {
108 	register struct mondata *d = _mondata();
109 	register int o;
110 	struct phdr *php;
111 	static int ssiz;
112 	static char *sbuf;
113 	register char *s, *name;
114 
115 	name = d->mon_out;
116 
117 	if (lowpc == NULL) {		/* true only at the end */
118 		moncontrol(0);
119 		if (sbuf != NULL) {
120 			register int pid, n;
121 
122 			if (d->progname[0] != '\0') { /* finish constructing
123 						    "PROFDIR/pid.progname" */
124 			    /* set name to end of PROFDIR */
125 			    name = strrchr(d->mon_out, '\0');
126 			    if ((pid = getpid()) <= 0) /* extra test just in case */
127 				pid = 1; /* getpid returns something inappropriate */
128 			    for (n = 10000; n > pid; n /= 10)
129 				; /* suppress leading zeros */
130 			    for ( ; ; n /= 10) {
131 				*name++ = pid/n + '0';
132 				if (n == 1)
133 				    break;
134 				pid %= n;
135 			    }
136 			    *name++ = '.';
137 			    (void)strcpy(name, d->progname);
138 			}
139 
140 			if ((o = creat(d->mon_out, 0666)) < 0 ||
141 			    write(o, sbuf, (unsigned)ssiz) == -1)
142 				perror(d->mon_out);
143 			if (o >= 0)
144 				close(o);
145 		}
146 		return;
147 	}
148 	countbase = (struct cnt *)(buf + sizeof(struct phdr));
149 	sbuf = NULL;
150 	o = sizeof(struct phdr) + cntsiz * sizeof(struct cnt);
151 	if (ssiz >= bufsiz || lowpc >= highpc)
152 		return;		/* buffer too small or PC range bad */
153 	if ((s = getenv(PROFDIR)) == NULL) /* PROFDIR not in environment */
154 		(void)strcpy(name, MON_OUT); /* use default "mon.out" */
155 	else if (*s == '\0') /* value of PROFDIR is NULL */
156 		return; /* no profiling on this run */
157 	else { /* set up mon_out and progname to construct
158 		  "PROFDIR/pid.progname" when done profiling */
159 
160 		while (*s != '\0') /* copy PROFDIR value (path-prefix) */
161 			*name++ = *s++;
162 		*name++ = '/'; /* two slashes won't hurt */
163 		if (___Argv != NULL) /* mcrt0.s executed */
164 			if ((s = strrchr(___Argv[0], '/')) != NULL)
165 			    strcpy(d->progname, s + 1);
166 			else
167 			    strcpy(d->progname, ___Argv[0]);
168 	}
169 	sbuf = buf;		/* for writing buffer at the wrapup */
170 	ssiz = bufsiz;
171 	php = (struct phdr *)&buf[0];
172 	php->lpc = (char *)lowpc;	/* initialize the first */
173 	php->hpc = (char *)highpc;	/* region of the buffer */
174 	php->ncnt = cntsiz;
175 	numctrs = cntsiz;
176 	buf += o;
177 	bufsiz -= o;
178 	if (bufsiz <= 0)
179 		return;
180 	o = (highpc - lowpc);
181 	if(bufsiz < o)
182 		o = ((float) bufsiz / o) * 65536;
183 	else
184 		o = 65536;
185 	d->s_scale = o;
186 	d->s_sbuf = buf;
187 	d->s_bufsiz = bufsiz;
188 	d->s_lowpc = (int) lowpc;
189 	moncontrol(1);
190 }
191 
192 /*
193  * Control profiling
194  *	profiling is what mcount checks to see if
195  *	all the data structures are ready.
196  */
197 void
198 moncontrol(mode)
199     int mode;
200 {
201     register struct mondata *d = _mondata();
202 
203     if (mode) {
204 	/* start */
205 	profil(d->s_sbuf, d->s_bufsiz, d->s_lowpc, d->s_scale);
206 	profiling = 0;
207     } else {
208 	/* stop */
209 	profil((char *)0, 0, 0, 0);
210 	profiling = 3;
211     }
212 }
213