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