Commit | Line | Data |
---|---|---|
586c39b1 DF |
1 | /* |
2 | * Copyright (c) 1980 Regents of the University of California. | |
3 | * All rights reserved. The Berkeley software License Agreement | |
4 | * specifies the terms and conditions for redistribution. | |
5 | */ | |
6 | ||
2ce81398 | 7 | #if defined(LIBC_SCCS) && !defined(lint) |
44be2432 | 8 | static char sccsid[] = "@(#)gmon.c 5.4 (Berkeley) %G%"; |
2ce81398 | 9 | #endif LIBC_SCCS and not lint |
50084e08 | 10 | |
bb9c5045 | 11 | #ifdef DEBUG |
50084e08 | 12 | #include <stdio.h> |
bb9c5045 | 13 | #endif DEBUG |
50084e08 | 14 | |
ee56ba6f | 15 | #include "gmon.h" |
387d0540 PK |
16 | |
17 | /* | |
18 | * froms is actually a bunch of unsigned shorts indexing tos | |
19 | */ | |
5a9da8d5 | 20 | static int profiling = 3; |
50084e08 PK |
21 | static unsigned short *froms; |
22 | static struct tostruct *tos = 0; | |
019e8582 | 23 | static long tolimit = 0; |
50084e08 PK |
24 | static char *s_lowpc = 0; |
25 | static char *s_highpc = 0; | |
3a2b18f4 | 26 | static unsigned long s_textsize = 0; |
50084e08 | 27 | |
387d0540 | 28 | static int ssiz; |
37a37eeb | 29 | static char *sbuf; |
13c3ba68 | 30 | static int s_scale; |
37a37eeb PK |
31 | /* see profil(2) where this is describe (incorrectly) */ |
32 | #define SCALE_1_TO_1 0x10000L | |
50084e08 | 33 | |
50084e08 PK |
34 | #define MSG "No space for monitor buffer(s)\n" |
35 | ||
ee56ba6f | 36 | monstartup(lowpc, highpc) |
387d0540 PK |
37 | char *lowpc; |
38 | char *highpc; | |
50084e08 | 39 | { |
3a2b18f4 PK |
40 | int monsize; |
41 | char *buffer; | |
42 | char *sbrk(); | |
b8c5b964 | 43 | extern char *minbrk; |
50084e08 | 44 | |
019e8582 PK |
45 | /* |
46 | * round lowpc and highpc to multiples of the density we're using | |
47 | * so the rest of the scaling (here and in gprof) stays in ints. | |
48 | */ | |
49 | lowpc = (char *) | |
50 | ROUNDDOWN((unsigned)lowpc, HISTFRACTION*sizeof(HISTCOUNTER)); | |
387d0540 | 51 | s_lowpc = lowpc; |
019e8582 PK |
52 | highpc = (char *) |
53 | ROUNDUP((unsigned)highpc, HISTFRACTION*sizeof(HISTCOUNTER)); | |
387d0540 | 54 | s_highpc = highpc; |
3a2b18f4 | 55 | s_textsize = highpc - lowpc; |
019e8582 | 56 | monsize = (s_textsize / HISTFRACTION) + sizeof(struct phdr); |
387d0540 PK |
57 | buffer = sbrk( monsize ); |
58 | if ( buffer == (char *) -1 ) { | |
44be2432 | 59 | write( 2 , MSG , sizeof(MSG) - 1 ); |
387d0540 PK |
60 | return; |
61 | } | |
f4d8fa4a | 62 | froms = (unsigned short *) sbrk( s_textsize / HASHFRACTION ); |
387d0540 | 63 | if ( froms == (unsigned short *) -1 ) { |
44be2432 | 64 | write( 2 , MSG , sizeof(MSG) - 1 ); |
387d0540 PK |
65 | froms = 0; |
66 | return; | |
67 | } | |
5a9da8d5 KM |
68 | tolimit = s_textsize * ARCDENSITY / 100; |
69 | if ( tolimit < MINARCS ) { | |
70 | tolimit = MINARCS; | |
71 | } else if ( tolimit > 65534 ) { | |
72 | tolimit = 65534; | |
4dff44be | 73 | } |
5a9da8d5 | 74 | tos = (struct tostruct *) sbrk( tolimit * sizeof( struct tostruct ) ); |
387d0540 | 75 | if ( tos == (struct tostruct *) -1 ) { |
44be2432 | 76 | write( 2 , MSG , sizeof(MSG) - 1 ); |
387d0540 PK |
77 | froms = 0; |
78 | tos = 0; | |
79 | return; | |
80 | } | |
b8c5b964 | 81 | minbrk = sbrk(0); |
387d0540 | 82 | tos[0].link = 0; |
5a9da8d5 | 83 | monitor( lowpc , highpc , buffer , monsize , tolimit ); |
50084e08 PK |
84 | } |
85 | ||
86 | _mcleanup() | |
87 | { | |
bb9c5045 KM |
88 | int fd; |
89 | int fromindex; | |
f4d8fa4a | 90 | int endfrom; |
bb9c5045 KM |
91 | char *frompc; |
92 | int toindex; | |
93 | struct rawarc rawarc; | |
50084e08 | 94 | |
bb9c5045 KM |
95 | fd = creat( "gmon.out" , 0666 ); |
96 | if ( fd < 0 ) { | |
387d0540 | 97 | perror( "mcount: gmon.out" ); |
50084e08 PK |
98 | return; |
99 | } | |
387d0540 PK |
100 | # ifdef DEBUG |
101 | fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz ); | |
102 | # endif DEBUG | |
bb9c5045 | 103 | write( fd , sbuf , ssiz ); |
f4d8fa4a KM |
104 | endfrom = s_textsize / (HASHFRACTION * sizeof(*froms)); |
105 | for ( fromindex = 0 ; fromindex < endfrom ; fromindex++ ) { | |
50084e08 PK |
106 | if ( froms[fromindex] == 0 ) { |
107 | continue; | |
108 | } | |
f4d8fa4a | 109 | frompc = s_lowpc + (fromindex * HASHFRACTION * sizeof(*froms)); |
50084e08 PK |
110 | for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) { |
111 | # ifdef DEBUG | |
22f3ec41 PK |
112 | fprintf( stderr , |
113 | "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" , | |
50084e08 PK |
114 | frompc , tos[toindex].selfpc , tos[toindex].count ); |
115 | # endif DEBUG | |
bb9c5045 KM |
116 | rawarc.raw_frompc = (unsigned long) frompc; |
117 | rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc; | |
118 | rawarc.raw_count = tos[toindex].count; | |
119 | write( fd , &rawarc , sizeof rawarc ); | |
50084e08 PK |
120 | } |
121 | } | |
bb9c5045 | 122 | close( fd ); |
50084e08 PK |
123 | } |
124 | ||
019e8582 | 125 | asm(".text"); |
13c3ba68 | 126 | asm(".align 2"); |
019e8582 PK |
127 | asm("#the beginning of mcount()"); |
128 | asm(".data"); | |
50084e08 PK |
129 | mcount() |
130 | { | |
019e8582 PK |
131 | register char *selfpc; /* r11 => r5 */ |
132 | register unsigned short *frompcindex; /* r10 => r4 */ | |
133 | register struct tostruct *top; /* r9 => r3 */ | |
134 | register struct tostruct *prevtop; /* r8 => r2 */ | |
135 | register long toindex; /* r7 => r1 */ | |
019e8582 | 136 | |
50084e08 | 137 | /* |
785a53a1 PK |
138 | * find the return address for mcount, |
139 | * and the return address for mcount's caller. | |
50084e08 | 140 | */ |
019e8582 PK |
141 | asm(" .text"); /* make sure we're in text space */ |
142 | asm(" movl (sp), r11"); /* selfpc = ... (jsb frame) */ | |
143 | asm(" movl 16(fp), r10"); /* frompcindex = (calls frame) */ | |
785a53a1 PK |
144 | /* |
145 | * check that we are profiling | |
387d0540 | 146 | * and that we aren't recursively invoked. |
785a53a1 | 147 | */ |
019e8582 PK |
148 | if (profiling) { |
149 | goto out; | |
150 | } | |
5a9da8d5 | 151 | profiling++; |
785a53a1 PK |
152 | /* |
153 | * check that frompcindex is a reasonable pc value. | |
154 | * for example: signal catchers get called from the stack, | |
155 | * not from text space. too bad. | |
156 | */ | |
019e8582 PK |
157 | frompcindex = (unsigned short *)((long)frompcindex - (long)s_lowpc); |
158 | if ((unsigned long)frompcindex > s_textsize) { | |
159 | goto done; | |
50084e08 | 160 | } |
019e8582 | 161 | frompcindex = |
f4d8fa4a | 162 | &froms[((long)frompcindex) / (HASHFRACTION * sizeof(*froms))]; |
019e8582 PK |
163 | toindex = *frompcindex; |
164 | if (toindex == 0) { | |
165 | /* | |
166 | * first time traversing this arc | |
167 | */ | |
168 | toindex = ++tos[0].link; | |
169 | if (toindex >= tolimit) { | |
170 | goto overflow; | |
171 | } | |
172 | *frompcindex = toindex; | |
173 | top = &tos[toindex]; | |
174 | top->selfpc = selfpc; | |
175 | top->count = 1; | |
176 | top->link = 0; | |
177 | goto done; | |
50084e08 | 178 | } |
019e8582 PK |
179 | top = &tos[toindex]; |
180 | if (top->selfpc == selfpc) { | |
181 | /* | |
182 | * arc at front of chain; usual case. | |
183 | */ | |
184 | top->count++; | |
185 | goto done; | |
186 | } | |
187 | /* | |
188 | * have to go looking down chain for it. | |
189 | * top points to what we are looking at, | |
190 | * prevtop points to previous top. | |
191 | * we know it is not at the head of the chain. | |
192 | */ | |
193 | for (; /* goto done */; ) { | |
194 | if (top->link == 0) { | |
195 | /* | |
196 | * top is end of the chain and none of the chain | |
197 | * had top->selfpc == selfpc. | |
198 | * so we allocate a new tostruct | |
199 | * and link it to the head of the chain. | |
200 | */ | |
201 | toindex = ++tos[0].link; | |
202 | if (toindex >= tolimit) { | |
203 | goto overflow; | |
204 | } | |
205 | top = &tos[toindex]; | |
206 | top->selfpc = selfpc; | |
207 | top->count = 1; | |
208 | top->link = *frompcindex; | |
209 | *frompcindex = toindex; | |
210 | goto done; | |
211 | } | |
212 | /* | |
213 | * otherwise, check the next arc on the chain. | |
214 | */ | |
215 | prevtop = top; | |
216 | top = &tos[top->link]; | |
217 | if (top->selfpc == selfpc) { | |
218 | /* | |
219 | * there it is. | |
220 | * increment its count | |
221 | * move it to the head of the chain. | |
222 | */ | |
223 | top->count++; | |
224 | toindex = prevtop->link; | |
225 | prevtop->link = top->link; | |
226 | top->link = *frompcindex; | |
227 | *frompcindex = toindex; | |
228 | goto done; | |
229 | } | |
230 | ||
50084e08 | 231 | } |
785a53a1 | 232 | done: |
5a9da8d5 | 233 | profiling--; |
019e8582 | 234 | /* and fall through */ |
50084e08 | 235 | out: |
019e8582 | 236 | asm(" rsb"); |
50084e08 PK |
237 | |
238 | overflow: | |
5a9da8d5 | 239 | profiling++; /* halt further profiling */ |
50084e08 | 240 | # define TOLIMIT "mcount: tos overflow\n" |
44be2432 | 241 | write(2, TOLIMIT, sizeof(TOLIMIT) - 1); |
019e8582 | 242 | goto out; |
50084e08 | 243 | } |
019e8582 PK |
244 | asm(".text"); |
245 | asm("#the end of mcount()"); | |
246 | asm(".data"); | |
50084e08 | 247 | |
ee56ba6f KM |
248 | /*VARARGS1*/ |
249 | monitor( lowpc , highpc , buf , bufsiz , nfunc ) | |
387d0540 | 250 | char *lowpc; |
387d0540 | 251 | char *highpc; |
37a37eeb PK |
252 | char *buf; /* declared ``short buffer[]'' in monitor(3) */ |
253 | int bufsiz; | |
ee56ba6f | 254 | int nfunc; /* not used, available for compatability only */ |
50084e08 | 255 | { |
387d0540 | 256 | register o; |
50084e08 | 257 | |
387d0540 | 258 | if ( lowpc == 0 ) { |
13c3ba68 | 259 | moncontrol(0); |
ee56ba6f | 260 | _mcleanup(); |
387d0540 PK |
261 | return; |
262 | } | |
263 | sbuf = buf; | |
264 | ssiz = bufsiz; | |
265 | ( (struct phdr *) buf ) -> lpc = lowpc; | |
266 | ( (struct phdr *) buf ) -> hpc = highpc; | |
267 | ( (struct phdr *) buf ) -> ncnt = ssiz; | |
37a37eeb | 268 | bufsiz -= sizeof(struct phdr); |
387d0540 PK |
269 | if ( bufsiz <= 0 ) |
270 | return; | |
37a37eeb | 271 | o = highpc - lowpc; |
387d0540 | 272 | if( bufsiz < o ) |
37a37eeb | 273 | s_scale = ( (float) bufsiz / o ) * SCALE_1_TO_1; |
387d0540 | 274 | else |
37a37eeb | 275 | s_scale = SCALE_1_TO_1; |
13c3ba68 PK |
276 | moncontrol(1); |
277 | } | |
278 | ||
279 | /* | |
280 | * Control profiling | |
281 | * profiling is what mcount checks to see if | |
282 | * all the data structures are ready. | |
283 | */ | |
284 | moncontrol(mode) | |
285 | int mode; | |
286 | { | |
287 | if (mode) { | |
288 | /* start */ | |
289 | profil(sbuf + sizeof(struct phdr), ssiz - sizeof(struct phdr), | |
290 | s_lowpc, s_scale); | |
291 | profiling = 0; | |
292 | } else { | |
293 | /* stop */ | |
294 | profil((char *)0, 0, 0, 0); | |
295 | profiling = 3; | |
296 | } | |
50084e08 | 297 | } |