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