Commit | Line | Data |
---|---|---|
15637ed4 RG |
1 | /*- |
2 | * Copyright (c) 1991 The Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
5 | * Redistribution and use in source and binary forms, with or without | |
6 | * modification, are permitted provided that the following conditions | |
7 | * are met: | |
8 | * 1. Redistributions of source code must retain the above copyright | |
9 | * notice, this list of conditions and the following disclaimer. | |
10 | * 2. Redistributions in binary form must reproduce the above copyright | |
11 | * notice, this list of conditions and the following disclaimer in the | |
12 | * documentation and/or other materials provided with the distribution. | |
13 | * 3. All advertising materials mentioning features or use of this software | |
14 | * must display the following acknowledgement: | |
15 | * This product includes software developed by the University of | |
16 | * California, Berkeley and its contributors. | |
17 | * 4. Neither the name of the University nor the names of its contributors | |
18 | * may be used to endorse or promote products derived from this software | |
19 | * without specific prior written permission. | |
20 | * | |
21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
31 | * SUCH DAMAGE. | |
32 | */ | |
33 | ||
34 | #if defined(LIBC_SCCS) && !defined(lint) | |
90c075bb PR |
35 | /*static char sccsid[] = "from: @(#)gmon.c 5.3 (Berkeley) 5/22/91";*/ |
36 | static char rcsid[] = "$Id: gmon.c,v 1.2 1993/08/01 18:44:18 mycroft Exp $"; | |
15637ed4 RG |
37 | #endif /* LIBC_SCCS and not lint */ |
38 | ||
39 | ||
40 | #include <unistd.h> | |
41 | ||
42 | #ifdef DEBUG | |
43 | #include <stdio.h> | |
44 | #endif | |
45 | ||
46 | #include "gmon.h" | |
47 | ||
48 | extern mcount() asm ("mcount"); | |
49 | extern char *minbrk asm ("minbrk"); | |
50 | ||
51 | /* | |
52 | * froms is actually a bunch of unsigned shorts indexing tos | |
53 | */ | |
54 | static int profiling = 3; | |
55 | static unsigned short *froms; | |
56 | static struct tostruct *tos = 0; | |
57 | static long tolimit = 0; | |
58 | static char *s_lowpc = 0; | |
59 | static char *s_highpc = 0; | |
60 | static unsigned long s_textsize = 0; | |
61 | ||
62 | static int ssiz; | |
63 | static char *sbuf; | |
64 | static int s_scale; | |
65 | /* see profil(2) where this is describe (incorrectly) */ | |
66 | #define SCALE_1_TO_1 0x10000L | |
67 | ||
68 | #define MSG "No space for profiling buffer(s)\n" | |
69 | ||
70 | monstartup(lowpc, highpc) | |
71 | char *lowpc; | |
72 | char *highpc; | |
73 | { | |
74 | int monsize; | |
75 | char *buffer; | |
76 | register int o; | |
77 | ||
78 | /* | |
79 | * round lowpc and highpc to multiples of the density we're using | |
80 | * so the rest of the scaling (here and in gprof) stays in ints. | |
81 | */ | |
82 | lowpc = (char *) | |
83 | ROUNDDOWN((unsigned)lowpc, HISTFRACTION*sizeof(HISTCOUNTER)); | |
84 | s_lowpc = lowpc; | |
85 | highpc = (char *) | |
86 | ROUNDUP((unsigned)highpc, HISTFRACTION*sizeof(HISTCOUNTER)); | |
87 | s_highpc = highpc; | |
88 | s_textsize = highpc - lowpc; | |
89 | monsize = (s_textsize / HISTFRACTION) + sizeof(struct phdr); | |
90 | buffer = sbrk( monsize ); | |
91 | if ( buffer == (char *) -1 ) { | |
92 | write( 2 , MSG , sizeof(MSG) ); | |
93 | return; | |
94 | } | |
95 | froms = (unsigned short *) sbrk( s_textsize / HASHFRACTION ); | |
96 | if ( froms == (unsigned short *) -1 ) { | |
97 | write( 2 , MSG , sizeof(MSG) ); | |
98 | froms = 0; | |
99 | return; | |
100 | } | |
101 | tolimit = s_textsize * ARCDENSITY / 100; | |
102 | if ( tolimit < MINARCS ) { | |
103 | tolimit = MINARCS; | |
104 | } else if ( tolimit > 65534 ) { | |
105 | tolimit = 65534; | |
106 | } | |
107 | tos = (struct tostruct *) sbrk( tolimit * sizeof( struct tostruct ) ); | |
108 | if ( tos == (struct tostruct *) -1 ) { | |
109 | write( 2 , MSG , sizeof(MSG) ); | |
110 | froms = 0; | |
111 | tos = 0; | |
112 | return; | |
113 | } | |
114 | minbrk = sbrk(0); | |
115 | tos[0].link = 0; | |
116 | sbuf = buffer; | |
117 | ssiz = monsize; | |
118 | ( (struct phdr *) buffer ) -> lpc = lowpc; | |
119 | ( (struct phdr *) buffer ) -> hpc = highpc; | |
120 | ( (struct phdr *) buffer ) -> ncnt = ssiz; | |
121 | monsize -= sizeof(struct phdr); | |
122 | if ( monsize <= 0 ) | |
123 | return; | |
124 | o = highpc - lowpc; | |
125 | if( monsize < o ) | |
126 | #ifndef hp300 | |
127 | s_scale = ( (float) monsize / o ) * SCALE_1_TO_1; | |
128 | #else /* avoid floating point */ | |
129 | { | |
130 | int quot = o / monsize; | |
131 | ||
132 | if (quot >= 0x10000) | |
133 | s_scale = 1; | |
134 | else if (quot >= 0x100) | |
135 | s_scale = 0x10000 / quot; | |
136 | else if (o >= 0x800000) | |
137 | s_scale = 0x1000000 / (o / (monsize >> 8)); | |
138 | else | |
139 | s_scale = 0x1000000 / ((o << 8) / monsize); | |
140 | } | |
141 | #endif | |
142 | else | |
143 | s_scale = SCALE_1_TO_1; | |
144 | moncontrol(1); | |
145 | } | |
146 | ||
147 | _mcleanup() | |
148 | { | |
149 | int fd; | |
150 | int fromindex; | |
151 | int endfrom; | |
152 | char *frompc; | |
153 | int toindex; | |
154 | struct rawarc rawarc; | |
155 | ||
156 | moncontrol(0); | |
157 | fd = creat( "gmon.out" , 0666 ); | |
158 | if ( fd < 0 ) { | |
159 | perror( "mcount: gmon.out" ); | |
160 | return; | |
161 | } | |
162 | # ifdef DEBUG | |
163 | fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz ); | |
164 | # endif DEBUG | |
165 | write( fd , sbuf , ssiz ); | |
166 | endfrom = s_textsize / (HASHFRACTION * sizeof(*froms)); | |
167 | for ( fromindex = 0 ; fromindex < endfrom ; fromindex++ ) { | |
168 | if ( froms[fromindex] == 0 ) { | |
169 | continue; | |
170 | } | |
171 | frompc = s_lowpc + (fromindex * HASHFRACTION * sizeof(*froms)); | |
172 | for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) { | |
173 | # ifdef DEBUG | |
174 | fprintf( stderr , | |
175 | "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" , | |
176 | frompc , tos[toindex].selfpc , tos[toindex].count ); | |
177 | # endif DEBUG | |
178 | rawarc.raw_frompc = (unsigned long) frompc; | |
179 | rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc; | |
180 | rawarc.raw_count = tos[toindex].count; | |
181 | write( fd , &rawarc , sizeof rawarc ); | |
182 | } | |
183 | } | |
184 | close( fd ); | |
185 | } | |
186 | ||
187 | mcount() | |
188 | { | |
189 | register char *selfpc; | |
190 | register unsigned short *frompcindex; | |
191 | register struct tostruct *top; | |
192 | register struct tostruct *prevtop; | |
193 | register long toindex; | |
194 | ||
195 | /* | |
196 | * find the return address for mcount, | |
197 | * and the return address for mcount's caller. | |
198 | */ | |
199 | asm(".text"); /* make sure we're in text space */ | |
200 | /* | |
201 | * selfpc = pc pushed by mcount call | |
202 | */ | |
203 | asm("movl 4(%%ebp),%0" : "=r" (selfpc)); | |
204 | /* | |
205 | * frompcindex = pc pushed by jsr into self. | |
206 | * In GCC the caller's stack frame has already been built so we | |
207 | * have to chase a6 to find caller's raddr. | |
208 | */ | |
209 | asm("movl (%%ebp),%0" : "=r" (frompcindex)); | |
210 | frompcindex = ((unsigned short **)frompcindex)[1]; | |
211 | /* | |
212 | * check that we are profiling | |
213 | * and that we aren't recursively invoked. | |
214 | */ | |
215 | if (profiling) { | |
216 | goto out; | |
217 | } | |
218 | profiling++; | |
219 | /* | |
220 | * check that frompcindex is a reasonable pc value. | |
221 | * for example: signal catchers get called from the stack, | |
222 | * not from text space. too bad. | |
223 | */ | |
224 | frompcindex = (unsigned short *)((long)frompcindex - (long)s_lowpc); | |
225 | if ((unsigned long)frompcindex > s_textsize) { | |
226 | goto done; | |
227 | } | |
228 | frompcindex = | |
229 | &froms[((long)frompcindex) / (HASHFRACTION * sizeof(*froms))]; | |
230 | toindex = *frompcindex; | |
231 | if (toindex == 0) { | |
232 | /* | |
233 | * first time traversing this arc | |
234 | */ | |
235 | toindex = ++tos[0].link; | |
236 | if (toindex >= tolimit) { | |
237 | goto overflow; | |
238 | } | |
239 | *frompcindex = toindex; | |
240 | top = &tos[toindex]; | |
241 | top->selfpc = selfpc; | |
242 | top->count = 1; | |
243 | top->link = 0; | |
244 | goto done; | |
245 | } | |
246 | top = &tos[toindex]; | |
247 | if (top->selfpc == selfpc) { | |
248 | /* | |
249 | * arc at front of chain; usual case. | |
250 | */ | |
251 | top->count++; | |
252 | goto done; | |
253 | } | |
254 | /* | |
255 | * have to go looking down chain for it. | |
256 | * top points to what we are looking at, | |
257 | * prevtop points to previous top. | |
258 | * we know it is not at the head of the chain. | |
259 | */ | |
260 | for (; /* goto done */; ) { | |
261 | if (top->link == 0) { | |
262 | /* | |
263 | * top is end of the chain and none of the chain | |
264 | * had top->selfpc == selfpc. | |
265 | * so we allocate a new tostruct | |
266 | * and link it to the head of the chain. | |
267 | */ | |
268 | toindex = ++tos[0].link; | |
269 | if (toindex >= tolimit) { | |
270 | goto overflow; | |
271 | } | |
272 | top = &tos[toindex]; | |
273 | top->selfpc = selfpc; | |
274 | top->count = 1; | |
275 | top->link = *frompcindex; | |
276 | *frompcindex = toindex; | |
277 | goto done; | |
278 | } | |
279 | /* | |
280 | * otherwise, check the next arc on the chain. | |
281 | */ | |
282 | prevtop = top; | |
283 | top = &tos[top->link]; | |
284 | if (top->selfpc == selfpc) { | |
285 | /* | |
286 | * there it is. | |
287 | * increment its count | |
288 | * move it to the head of the chain. | |
289 | */ | |
290 | top->count++; | |
291 | toindex = prevtop->link; | |
292 | prevtop->link = top->link; | |
293 | top->link = *frompcindex; | |
294 | *frompcindex = toindex; | |
295 | goto done; | |
296 | } | |
297 | ||
298 | } | |
299 | done: | |
300 | profiling--; | |
301 | /* and fall through */ | |
302 | out: | |
303 | return; /* normal return restores saved registers */ | |
304 | ||
305 | overflow: | |
306 | profiling++; /* halt further profiling */ | |
307 | # define TOLIMIT "mcount: tos overflow\n" | |
308 | write(2, TOLIMIT, sizeof(TOLIMIT)); | |
309 | goto out; | |
310 | } | |
311 | ||
312 | /* | |
313 | * Control profiling | |
314 | * profiling is what mcount checks to see if | |
315 | * all the data structures are ready. | |
316 | */ | |
317 | moncontrol(mode) | |
318 | int mode; | |
319 | { | |
320 | if (mode) { | |
321 | /* start */ | |
322 | profil(sbuf + sizeof(struct phdr), ssiz - sizeof(struct phdr), | |
323 | (int)s_lowpc, s_scale); | |
324 | profiling = 0; | |
325 | } else { | |
326 | /* stop */ | |
327 | profil((char *)0, 0, 0, 0); | |
328 | profiling = 3; | |
329 | } | |
330 | } |