1*e4b17023SJohn Marino /*-
2*e4b17023SJohn Marino  * Copyright (c) 1991 The Regents of the University of California.
3*e4b17023SJohn Marino  * All rights reserved.
4*e4b17023SJohn Marino  *
5*e4b17023SJohn Marino  * Redistribution and use in source and binary forms, with or without
6*e4b17023SJohn Marino  * modification, are permitted provided that the following conditions
7*e4b17023SJohn Marino  * are met:
8*e4b17023SJohn Marino  * 1. Redistributions of source code must retain the above copyright
9*e4b17023SJohn Marino  *    notice, this list of conditions and the following disclaimer.
10*e4b17023SJohn Marino  * 2. Redistributions in binary form must reproduce the above copyright
11*e4b17023SJohn Marino  *    notice, this list of conditions and the following disclaimer in the
12*e4b17023SJohn Marino  *    documentation and/or other materials provided with the distribution.
13*e4b17023SJohn Marino  * 3. [rescinded 22 July 1999]
14*e4b17023SJohn Marino  * 4. Neither the name of the University nor the names of its contributors
15*e4b17023SJohn Marino  *    may be used to endorse or promote products derived from this software
16*e4b17023SJohn Marino  *    without specific prior written permission.
17*e4b17023SJohn Marino  *
18*e4b17023SJohn Marino  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19*e4b17023SJohn Marino  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20*e4b17023SJohn Marino  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21*e4b17023SJohn Marino  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22*e4b17023SJohn Marino  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23*e4b17023SJohn Marino  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24*e4b17023SJohn Marino  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25*e4b17023SJohn Marino  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26*e4b17023SJohn Marino  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27*e4b17023SJohn Marino  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28*e4b17023SJohn Marino  * SUCH DAMAGE.
29*e4b17023SJohn Marino  */
30*e4b17023SJohn Marino 
31*e4b17023SJohn Marino /* Mangled into a form that works on Solaris 2/SPARC by Mark Eichin
32*e4b17023SJohn Marino  * for Cygnus Support, July 1992.
33*e4b17023SJohn Marino  *
34*e4b17023SJohn Marino  * Modified to support Solaris 2/x86 by J.W.Hawtin <oolon@ankh.org>, 14/8/96.
35*e4b17023SJohn Marino  *
36*e4b17023SJohn Marino  * It must be used in conjunction with sol2-gc1.S, which is used to start
37*e4b17023SJohn Marino  * and stop process monitoring.
38*e4b17023SJohn Marino  */
39*e4b17023SJohn Marino 
40*e4b17023SJohn Marino #include "tconfig.h"
41*e4b17023SJohn Marino #include "tsystem.h"
42*e4b17023SJohn Marino #include <fcntl.h>		/* For creat.  */
43*e4b17023SJohn Marino 
44*e4b17023SJohn Marino extern void monstartup (char *, char *);
45*e4b17023SJohn Marino extern void _mcleanup (void);
46*e4b17023SJohn Marino #ifdef __i386__
47*e4b17023SJohn Marino static void internal_mcount (void) __attribute__ ((used));
48*e4b17023SJohn Marino #else
49*e4b17023SJohn Marino static void internal_mcount (char *, unsigned short *) __attribute__ ((used));
50*e4b17023SJohn Marino #endif
51*e4b17023SJohn Marino static void moncontrol (int);
52*e4b17023SJohn Marino 
53*e4b17023SJohn Marino struct phdr {
54*e4b17023SJohn Marino   char *lpc;
55*e4b17023SJohn Marino   char *hpc;
56*e4b17023SJohn Marino   int ncnt;
57*e4b17023SJohn Marino };
58*e4b17023SJohn Marino 
59*e4b17023SJohn Marino #define HISTFRACTION	2
60*e4b17023SJohn Marino #define HISTCOUNTER	unsigned short
61*e4b17023SJohn Marino #define HASHFRACTION	1
62*e4b17023SJohn Marino #define ARCDENSITY	2
63*e4b17023SJohn Marino #define MINARCS		50
64*e4b17023SJohn Marino 
65*e4b17023SJohn Marino struct tostruct {
66*e4b17023SJohn Marino   char *selfpc;
67*e4b17023SJohn Marino   long count;
68*e4b17023SJohn Marino   unsigned short link;
69*e4b17023SJohn Marino };
70*e4b17023SJohn Marino 
71*e4b17023SJohn Marino struct rawarc {
72*e4b17023SJohn Marino   unsigned long raw_frompc;
73*e4b17023SJohn Marino   unsigned long raw_selfpc;
74*e4b17023SJohn Marino   long raw_count;
75*e4b17023SJohn Marino };
76*e4b17023SJohn Marino 
77*e4b17023SJohn Marino #define ROUNDDOWN(x, y)	(((x) / (y)) * (y))
78*e4b17023SJohn Marino #define ROUNDUP(x, y)	((((x) + (y) - 1) / (y)) * (y))
79*e4b17023SJohn Marino 
80*e4b17023SJohn Marino /* froms is actually a bunch of unsigned shorts indexing tos.  */
81*e4b17023SJohn Marino static int profiling = 3;
82*e4b17023SJohn Marino static unsigned short *froms;
83*e4b17023SJohn Marino static struct tostruct *tos = NULL;
84*e4b17023SJohn Marino static long tolimit = 0;
85*e4b17023SJohn Marino static char *s_lowpc = NULL;
86*e4b17023SJohn Marino static char *s_highpc = NULL;
87*e4b17023SJohn Marino static size_t s_textsize = 0;
88*e4b17023SJohn Marino 
89*e4b17023SJohn Marino static int ssiz;
90*e4b17023SJohn Marino static char *sbuf;
91*e4b17023SJohn Marino static int s_scale;
92*e4b17023SJohn Marino /* See profil(2) where this is describe (incorrectly).  */
93*e4b17023SJohn Marino #define	SCALE_1_TO_1	0x10000L
94*e4b17023SJohn Marino 
95*e4b17023SJohn Marino #define	MSG "No space for profiling buffer(s)\n"
96*e4b17023SJohn Marino 
97*e4b17023SJohn Marino void
monstartup(char * lowpc,char * highpc)98*e4b17023SJohn Marino monstartup (char *lowpc, char *highpc)
99*e4b17023SJohn Marino {
100*e4b17023SJohn Marino   size_t monsize;
101*e4b17023SJohn Marino   char *buffer;
102*e4b17023SJohn Marino   size_t o;
103*e4b17023SJohn Marino 
104*e4b17023SJohn Marino   /* Round lowpc and highpc to multiples of the density we're using
105*e4b17023SJohn Marino      so the rest of the scaling (here and in gprof) stays in ints.  */
106*e4b17023SJohn Marino   lowpc = (char *) ROUNDDOWN ((size_t) lowpc,
107*e4b17023SJohn Marino 			      HISTFRACTION * sizeof (HISTCOUNTER));
108*e4b17023SJohn Marino   s_lowpc = lowpc;
109*e4b17023SJohn Marino   highpc = (char *) ROUNDUP ((size_t) highpc,
110*e4b17023SJohn Marino 			     HISTFRACTION * sizeof (HISTCOUNTER));
111*e4b17023SJohn Marino   s_highpc = highpc;
112*e4b17023SJohn Marino   s_textsize = highpc - lowpc;
113*e4b17023SJohn Marino   monsize = (s_textsize / HISTFRACTION) + sizeof (struct phdr);
114*e4b17023SJohn Marino   buffer = sbrk (monsize);
115*e4b17023SJohn Marino   if (buffer == (void *) -1) {
116*e4b17023SJohn Marino     write (STDERR_FILENO, MSG, sizeof (MSG));
117*e4b17023SJohn Marino     return;
118*e4b17023SJohn Marino   }
119*e4b17023SJohn Marino   froms = sbrk (s_textsize / HASHFRACTION);
120*e4b17023SJohn Marino   if (froms == (void *) -1) {
121*e4b17023SJohn Marino     write (STDERR_FILENO, MSG, sizeof (MSG));
122*e4b17023SJohn Marino     froms = NULL;
123*e4b17023SJohn Marino     return;
124*e4b17023SJohn Marino   }
125*e4b17023SJohn Marino   tolimit = s_textsize * ARCDENSITY / 100;
126*e4b17023SJohn Marino   if (tolimit < MINARCS) {
127*e4b17023SJohn Marino     tolimit = MINARCS;
128*e4b17023SJohn Marino   } else if (tolimit > 65534) {
129*e4b17023SJohn Marino     tolimit = 65534;
130*e4b17023SJohn Marino   }
131*e4b17023SJohn Marino   tos = sbrk (tolimit * sizeof (struct tostruct));
132*e4b17023SJohn Marino   if (tos == (void *) -1) {
133*e4b17023SJohn Marino     write (STDERR_FILENO, MSG, sizeof (MSG));
134*e4b17023SJohn Marino     froms = NULL;
135*e4b17023SJohn Marino     tos = NULL;
136*e4b17023SJohn Marino     return;
137*e4b17023SJohn Marino   }
138*e4b17023SJohn Marino   tos[0].link = 0;
139*e4b17023SJohn Marino   sbuf = buffer;
140*e4b17023SJohn Marino   ssiz = monsize;
141*e4b17023SJohn Marino   ((struct phdr *) buffer)->lpc = lowpc;
142*e4b17023SJohn Marino   ((struct phdr *) buffer)->hpc = highpc;
143*e4b17023SJohn Marino   ((struct phdr *) buffer)->ncnt = ssiz;
144*e4b17023SJohn Marino   monsize -= sizeof (struct phdr);
145*e4b17023SJohn Marino   if (monsize <= 0)
146*e4b17023SJohn Marino     return;
147*e4b17023SJohn Marino   o = highpc - lowpc;
148*e4b17023SJohn Marino   if(monsize < o)
149*e4b17023SJohn Marino     s_scale = ((float) monsize / o) * SCALE_1_TO_1;
150*e4b17023SJohn Marino   else
151*e4b17023SJohn Marino     s_scale = SCALE_1_TO_1;
152*e4b17023SJohn Marino   moncontrol (1);
153*e4b17023SJohn Marino }
154*e4b17023SJohn Marino 
155*e4b17023SJohn Marino void
_mcleanup(void)156*e4b17023SJohn Marino _mcleanup (void)
157*e4b17023SJohn Marino {
158*e4b17023SJohn Marino   int fd;
159*e4b17023SJohn Marino   int fromindex;
160*e4b17023SJohn Marino   int endfrom;
161*e4b17023SJohn Marino   char *frompc;
162*e4b17023SJohn Marino   int toindex;
163*e4b17023SJohn Marino   struct rawarc	rawarc;
164*e4b17023SJohn Marino   char *profdir;
165*e4b17023SJohn Marino   const char *proffile;
166*e4b17023SJohn Marino   char *progname;
167*e4b17023SJohn Marino   char buf[PATH_MAX];
168*e4b17023SJohn Marino   extern char **___Argv;
169*e4b17023SJohn Marino 
170*e4b17023SJohn Marino   moncontrol (0);
171*e4b17023SJohn Marino 
172*e4b17023SJohn Marino   if ((profdir = getenv ("PROFDIR")) != NULL) {
173*e4b17023SJohn Marino     /* If PROFDIR contains a null value, no profiling output is produced.  */
174*e4b17023SJohn Marino     if (*profdir == '\0') {
175*e4b17023SJohn Marino       return;
176*e4b17023SJohn Marino     }
177*e4b17023SJohn Marino 
178*e4b17023SJohn Marino     progname = strrchr (___Argv[0], '/');
179*e4b17023SJohn Marino     if (progname == NULL)
180*e4b17023SJohn Marino       progname = ___Argv[0];
181*e4b17023SJohn Marino     else
182*e4b17023SJohn Marino       progname++;
183*e4b17023SJohn Marino 
184*e4b17023SJohn Marino     sprintf (buf, "%s/%ld.%s", profdir, (long) getpid (), progname);
185*e4b17023SJohn Marino     proffile = buf;
186*e4b17023SJohn Marino   } else {
187*e4b17023SJohn Marino     proffile = "gmon.out";
188*e4b17023SJohn Marino   }
189*e4b17023SJohn Marino 
190*e4b17023SJohn Marino   fd = creat (proffile, 0666);
191*e4b17023SJohn Marino   if (fd < 0) {
192*e4b17023SJohn Marino     perror (proffile);
193*e4b17023SJohn Marino     return;
194*e4b17023SJohn Marino   }
195*e4b17023SJohn Marino #ifdef DEBUG
196*e4b17023SJohn Marino   fprintf (stderr, "[mcleanup] sbuf %#x ssiz %d\n", sbuf, ssiz);
197*e4b17023SJohn Marino #endif /* DEBUG */
198*e4b17023SJohn Marino 
199*e4b17023SJohn Marino   write (fd, sbuf, ssiz);
200*e4b17023SJohn Marino   endfrom = s_textsize / (HASHFRACTION * sizeof (*froms));
201*e4b17023SJohn Marino   for (fromindex = 0; fromindex < endfrom; fromindex++) {
202*e4b17023SJohn Marino     if (froms[fromindex] == 0) {
203*e4b17023SJohn Marino       continue;
204*e4b17023SJohn Marino     }
205*e4b17023SJohn Marino     frompc = s_lowpc + (fromindex * HASHFRACTION * sizeof (*froms));
206*e4b17023SJohn Marino     for (toindex = froms[fromindex];
207*e4b17023SJohn Marino 	 toindex != 0;
208*e4b17023SJohn Marino 	 toindex = tos[toindex].link) {
209*e4b17023SJohn Marino #ifdef DEBUG
210*e4b17023SJohn Marino       fprintf (stderr, "[mcleanup] frompc %#x selfpc %#x count %d\n",
211*e4b17023SJohn Marino 	       frompc, tos[toindex].selfpc, tos[toindex].count);
212*e4b17023SJohn Marino #endif /* DEBUG */
213*e4b17023SJohn Marino       rawarc.raw_frompc = (unsigned long) frompc;
214*e4b17023SJohn Marino       rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc;
215*e4b17023SJohn Marino       rawarc.raw_count = tos[toindex].count;
216*e4b17023SJohn Marino       write (fd, &rawarc, sizeof (rawarc));
217*e4b17023SJohn Marino     }
218*e4b17023SJohn Marino   }
219*e4b17023SJohn Marino   close (fd);
220*e4b17023SJohn Marino }
221*e4b17023SJohn Marino 
222*e4b17023SJohn Marino /* Solaris 2 libraries use _mcount.  */
223*e4b17023SJohn Marino #if defined __i386__
224*e4b17023SJohn Marino asm(".globl _mcount\n"
225*e4b17023SJohn Marino     "_mcount:\n"
226*e4b17023SJohn Marino     "	jmp	internal_mcount\n");
227*e4b17023SJohn Marino #elif defined __x86_64__
228*e4b17023SJohn Marino /* See GLIBC for additional information about this technique.  */
229*e4b17023SJohn Marino asm(".globl _mcount\n"
230*e4b17023SJohn Marino     "	.type	_mcount, @function\n"
231*e4b17023SJohn Marino     "_mcount:\n"
232*e4b17023SJohn Marino     /* The compiler calls _mcount after the prologue, and does not
233*e4b17023SJohn Marino        save any of the registers.  Therefore we must preserve all
234*e4b17023SJohn Marino        seven registers which may contain function arguments.  */
235*e4b17023SJohn Marino     "	subq	$0x38, %rsp\n"
236*e4b17023SJohn Marino     "	movq	%rax, (%rsp)\n"
237*e4b17023SJohn Marino     "	movq	%rcx, 0x08(%rsp)\n"
238*e4b17023SJohn Marino     "	movq	%rdx, 0x10(%rsp)\n"
239*e4b17023SJohn Marino     "	movq	%rsi, 0x18(%rsp)\n"
240*e4b17023SJohn Marino     "	movq	%rdi, 0x20(%rsp)\n"
241*e4b17023SJohn Marino     "	movq	%r8, 0x28(%rsp)\n"
242*e4b17023SJohn Marino     "	movq	%r9, 0x30(%rsp)\n"
243*e4b17023SJohn Marino     /* Get SELFPC (pushed by the call to this function) and
244*e4b17023SJohn Marino        FROMPCINDEX (via the frame pointer).  */
245*e4b17023SJohn Marino     "	movq	0x38(%rsp), %rdi\n"
246*e4b17023SJohn Marino     "	movq	0x8(%rbp), %rsi\n"
247*e4b17023SJohn Marino     "	call	internal_mcount\n"
248*e4b17023SJohn Marino     /* Restore the saved registers.  */
249*e4b17023SJohn Marino     "	movq	0x30(%rsp), %r9\n"
250*e4b17023SJohn Marino     "	movq	0x28(%rsp), %r8\n"
251*e4b17023SJohn Marino     "	movq	0x20(%rsp), %rdi\n"
252*e4b17023SJohn Marino     "	movq	0x18(%rsp), %rsi\n"
253*e4b17023SJohn Marino     "	movq	0x10(%rsp), %rdx\n"
254*e4b17023SJohn Marino     "	movq	0x08(%rsp), %rcx\n"
255*e4b17023SJohn Marino     "	movq	(%rsp), %rax\n"
256*e4b17023SJohn Marino     "	addq	$0x38, %rsp\n"
257*e4b17023SJohn Marino     "	retq\n");
258*e4b17023SJohn Marino #elif defined __sparc__
259*e4b17023SJohn Marino /* The SPARC stack frame is only held together by the frame pointers
260*e4b17023SJohn Marino    in the register windows. According to the SVR4 SPARC ABI
261*e4b17023SJohn Marino    Supplement, Low Level System Information/Operating System
262*e4b17023SJohn Marino    Interface/Software Trap Types, a type 3 trap will flush all of the
263*e4b17023SJohn Marino    register windows to the stack, which will make it possible to walk
264*e4b17023SJohn Marino    the frames and find the return addresses.
265*e4b17023SJohn Marino 	However, it seems awfully expensive to incur a trap (system
266*e4b17023SJohn Marino    call) for every function call. It turns out that "call" simply puts
267*e4b17023SJohn Marino    the return address in %o7 expecting the "save" in the procedure to
268*e4b17023SJohn Marino    shift it into %i7; this means that before the "save" occurs, %o7
269*e4b17023SJohn Marino    contains the address of the call to mcount, and %i7 still contains
270*e4b17023SJohn Marino    the caller above that. The asm mcount here simply saves those
271*e4b17023SJohn Marino    registers in argument registers and branches to internal_mcount,
272*e4b17023SJohn Marino    simulating a call with arguments.
273*e4b17023SJohn Marino 	Kludges:
274*e4b17023SJohn Marino 	1) the branch to internal_mcount is hard coded; it should be
275*e4b17023SJohn Marino    possible to tell asm to use the assembler-name of a symbol.
276*e4b17023SJohn Marino 	2) in theory, the function calling mcount could have saved %i7
277*e4b17023SJohn Marino    somewhere and reused the register; in practice, I *think* this will
278*e4b17023SJohn Marino    break longjmp (and maybe the debugger) but I'm not certain. (I take
279*e4b17023SJohn Marino    some comfort in the knowledge that it will break the native mcount
280*e4b17023SJohn Marino    as well.)
281*e4b17023SJohn Marino 	3) if builtin_return_address worked, this could be portable.
282*e4b17023SJohn Marino    However, it would really have to be optimized for arguments of 0
283*e4b17023SJohn Marino    and 1 and do something like what we have here in order to avoid the
284*e4b17023SJohn Marino    trap per function call performance hit.
285*e4b17023SJohn Marino 	4) the atexit and monsetup calls prevent this from simply
286*e4b17023SJohn Marino    being a leaf routine that doesn't do a "save" (and would thus have
287*e4b17023SJohn Marino    access to %o7 and %i7 directly) but the call to write() at the end
288*e4b17023SJohn Marino    would have also prevented this.
289*e4b17023SJohn Marino 
290*e4b17023SJohn Marino    -- [eichin:19920702.1107EST]  */
291*e4b17023SJohn Marino asm(".global _mcount\n"
292*e4b17023SJohn Marino     "_mcount:\n"
293*e4b17023SJohn Marino     /* i7 == last ret, -> frompcindex.  */
294*e4b17023SJohn Marino     "	mov	%i7, %o1\n"
295*e4b17023SJohn Marino     /* o7 == current ret, -> selfpc.  */
296*e4b17023SJohn Marino     "	mov	%o7, %o0\n"
297*e4b17023SJohn Marino     "	b,a	internal_mcount\n");
298*e4b17023SJohn Marino #endif
299*e4b17023SJohn Marino 
300*e4b17023SJohn Marino static void
301*e4b17023SJohn Marino #ifdef __i386__
internal_mcount(void)302*e4b17023SJohn Marino internal_mcount (void)
303*e4b17023SJohn Marino #else
304*e4b17023SJohn Marino internal_mcount (char *selfpc, unsigned short *frompcindex)
305*e4b17023SJohn Marino #endif
306*e4b17023SJohn Marino {
307*e4b17023SJohn Marino   struct tostruct *top;
308*e4b17023SJohn Marino   struct tostruct *prevtop;
309*e4b17023SJohn Marino   long toindex;
310*e4b17023SJohn Marino   static char already_setup;
311*e4b17023SJohn Marino 
312*e4b17023SJohn Marino #ifdef __i386__
313*e4b17023SJohn Marino   char *selfpc;
314*e4b17023SJohn Marino   unsigned short *frompcindex;
315*e4b17023SJohn Marino 
316*e4b17023SJohn Marino   /* Find the return address for mcount and the return address for mcount's
317*e4b17023SJohn Marino      caller.  */
318*e4b17023SJohn Marino 
319*e4b17023SJohn Marino   /* selfpc = pc pushed by mcount call.
320*e4b17023SJohn Marino      This identifies the function that was just entered.  */
321*e4b17023SJohn Marino   selfpc = (void *) __builtin_return_address (0);
322*e4b17023SJohn Marino   /* frompcindex = pc in preceding frame.
323*e4b17023SJohn Marino      This identifies the caller of the function just entered.  */
324*e4b17023SJohn Marino   frompcindex = (void *) __builtin_return_address (1);
325*e4b17023SJohn Marino #endif
326*e4b17023SJohn Marino 
327*e4b17023SJohn Marino   if(!already_setup) {
328*e4b17023SJohn Marino     extern char etext[];
329*e4b17023SJohn Marino 
330*e4b17023SJohn Marino     already_setup = 1;
331*e4b17023SJohn Marino 
332*e4b17023SJohn Marino #if defined __i386__
333*e4b17023SJohn Marino     /* <sys/vmparam.h> USERSTACK.  */
334*e4b17023SJohn Marino     monstartup ((char *) 0x8048000, etext);
335*e4b17023SJohn Marino #elif defined __x86_64__
336*e4b17023SJohn Marino     monstartup (NULL, etext);
337*e4b17023SJohn Marino #elif defined __sparc__
338*e4b17023SJohn Marino     {
339*e4b17023SJohn Marino       extern char _start[];
340*e4b17023SJohn Marino       extern char _init[];
341*e4b17023SJohn Marino 
342*e4b17023SJohn Marino       monstartup (_start < _init ? _start : _init, etext);
343*e4b17023SJohn Marino     }
344*e4b17023SJohn Marino #endif
345*e4b17023SJohn Marino     atexit (_mcleanup);
346*e4b17023SJohn Marino   }
347*e4b17023SJohn Marino   /* Check that we are profiling and that we aren't recursively invoked.  */
348*e4b17023SJohn Marino   if (profiling) {
349*e4b17023SJohn Marino     goto out;
350*e4b17023SJohn Marino   }
351*e4b17023SJohn Marino   profiling++;
352*e4b17023SJohn Marino   /* Check that frompcindex is a reasonable pc value.  For example: signal
353*e4b17023SJohn Marino      catchers get called from the stack, not from text space.  too bad.  */
354*e4b17023SJohn Marino   frompcindex = (unsigned short *) ((long) frompcindex - (long) s_lowpc);
355*e4b17023SJohn Marino   if ((unsigned long) frompcindex > s_textsize) {
356*e4b17023SJohn Marino     goto done;
357*e4b17023SJohn Marino   }
358*e4b17023SJohn Marino   frompcindex = &froms[((long) frompcindex) / (HASHFRACTION * sizeof (*froms))];
359*e4b17023SJohn Marino   toindex = *frompcindex;
360*e4b17023SJohn Marino   if (toindex == 0) {
361*e4b17023SJohn Marino     /* First time traversing this arc.  */
362*e4b17023SJohn Marino     toindex = ++tos[0].link;
363*e4b17023SJohn Marino     if (toindex >= tolimit) {
364*e4b17023SJohn Marino       goto overflow;
365*e4b17023SJohn Marino     }
366*e4b17023SJohn Marino     *frompcindex = toindex;
367*e4b17023SJohn Marino     top = &tos[toindex];
368*e4b17023SJohn Marino     top->selfpc = selfpc;
369*e4b17023SJohn Marino     top->count = 1;
370*e4b17023SJohn Marino     top->link = 0;
371*e4b17023SJohn Marino     goto done;
372*e4b17023SJohn Marino   }
373*e4b17023SJohn Marino   top = &tos[toindex];
374*e4b17023SJohn Marino   if (top->selfpc == selfpc) {
375*e4b17023SJohn Marino     /* arc at front of chain; usual case.  */
376*e4b17023SJohn Marino     top->count++;
377*e4b17023SJohn Marino     goto done;
378*e4b17023SJohn Marino   }
379*e4b17023SJohn Marino   /* Have to go looking down chain for it.  Top points to what we are
380*e4b17023SJohn Marino      looking at, prevtop points to previous top.  We know it is not at the
381*e4b17023SJohn Marino      head of the chain.  */
382*e4b17023SJohn Marino   for (; /* goto done */; ) {
383*e4b17023SJohn Marino     if (top->link == 0) {
384*e4b17023SJohn Marino       /* top is end of the chain and none of the chain had top->selfpc ==
385*e4b17023SJohn Marino 	 selfpc, so we allocate a new tostruct and link it to the head of
386*e4b17023SJohn Marino 	 the chain.  */
387*e4b17023SJohn Marino       toindex = ++tos[0].link;
388*e4b17023SJohn Marino       if (toindex >= tolimit) {
389*e4b17023SJohn Marino 	goto overflow;
390*e4b17023SJohn Marino       }
391*e4b17023SJohn Marino       top = &tos[toindex];
392*e4b17023SJohn Marino       top->selfpc = selfpc;
393*e4b17023SJohn Marino       top->count = 1;
394*e4b17023SJohn Marino       top->link = *frompcindex;
395*e4b17023SJohn Marino       *frompcindex = toindex;
396*e4b17023SJohn Marino       goto done;
397*e4b17023SJohn Marino     }
398*e4b17023SJohn Marino     /* Otherwise, check the next arc on the chain.  */
399*e4b17023SJohn Marino     prevtop = top;
400*e4b17023SJohn Marino     top = &tos[top->link];
401*e4b17023SJohn Marino     if (top->selfpc == selfpc) {
402*e4b17023SJohn Marino       /* There it is.  Increment its count move it to the head of the
403*e4b17023SJohn Marino 	 chain.  */
404*e4b17023SJohn Marino       top->count++;
405*e4b17023SJohn Marino       toindex = prevtop->link;
406*e4b17023SJohn Marino       prevtop->link = top->link;
407*e4b17023SJohn Marino       top->link = *frompcindex;
408*e4b17023SJohn Marino       *frompcindex = toindex;
409*e4b17023SJohn Marino       goto done;
410*e4b17023SJohn Marino     }
411*e4b17023SJohn Marino 
412*e4b17023SJohn Marino   }
413*e4b17023SJohn Marino  done:
414*e4b17023SJohn Marino   profiling--;
415*e4b17023SJohn Marino   /* ... and fall through. */
416*e4b17023SJohn Marino  out:
417*e4b17023SJohn Marino   /* Normal return restores saved registers.  */
418*e4b17023SJohn Marino   return;
419*e4b17023SJohn Marino 
420*e4b17023SJohn Marino  overflow:
421*e4b17023SJohn Marino   /* Halt further profiling.  */
422*e4b17023SJohn Marino   profiling++;
423*e4b17023SJohn Marino 
424*e4b17023SJohn Marino #define	TOLIMIT	"mcount: tos overflow\n"
425*e4b17023SJohn Marino   write (STDERR_FILENO, TOLIMIT, sizeof (TOLIMIT));
426*e4b17023SJohn Marino   goto out;
427*e4b17023SJohn Marino }
428*e4b17023SJohn Marino 
429*e4b17023SJohn Marino /* Control profiling.  Profiling is what mcount checks to see if all the
430*e4b17023SJohn Marino    data structures are ready.  */
431*e4b17023SJohn Marino static void
moncontrol(int mode)432*e4b17023SJohn Marino moncontrol (int mode)
433*e4b17023SJohn Marino {
434*e4b17023SJohn Marino   if (mode) {
435*e4b17023SJohn Marino     /* Start.  */
436*e4b17023SJohn Marino     profil ((unsigned short *) (sbuf + sizeof (struct phdr)),
437*e4b17023SJohn Marino 	    ssiz - sizeof (struct phdr), (size_t) s_lowpc, s_scale);
438*e4b17023SJohn Marino     profiling = 0;
439*e4b17023SJohn Marino   } else {
440*e4b17023SJohn Marino     /* Stop.  */
441*e4b17023SJohn Marino     profil ((unsigned short *) 0, 0, 0, 0);
442*e4b17023SJohn Marino     profiling = 3;
443*e4b17023SJohn Marino   }
444*e4b17023SJohn Marino }
445