Commit | Line | Data |
---|---|---|
f4d8fa4a | 1 | static char *sccsid = "@(#)gmon.c 4.9 (Berkeley) %G%"; |
50084e08 | 2 | |
bb9c5045 | 3 | #ifdef DEBUG |
50084e08 | 4 | #include <stdio.h> |
bb9c5045 | 5 | #endif DEBUG |
50084e08 | 6 | |
ee56ba6f | 7 | #include "gmon.h" |
387d0540 PK |
8 | |
9 | /* | |
10 | * froms is actually a bunch of unsigned shorts indexing tos | |
11 | */ | |
50084e08 PK |
12 | static unsigned short *froms; |
13 | static struct tostruct *tos = 0; | |
019e8582 | 14 | static long tolimit = 0; |
50084e08 PK |
15 | static char *s_lowpc = 0; |
16 | static char *s_highpc = 0; | |
3a2b18f4 | 17 | static unsigned long s_textsize = 0; |
63238688 | 18 | static char *minsbrk = 0; |
50084e08 | 19 | |
387d0540 PK |
20 | static int ssiz; |
21 | static int *sbuf; | |
50084e08 | 22 | |
50084e08 PK |
23 | #define MSG "No space for monitor buffer(s)\n" |
24 | ||
ee56ba6f | 25 | monstartup(lowpc, highpc) |
387d0540 PK |
26 | char *lowpc; |
27 | char *highpc; | |
50084e08 | 28 | { |
3a2b18f4 PK |
29 | int monsize; |
30 | char *buffer; | |
31 | char *sbrk(); | |
32 | unsigned long limit; | |
50084e08 | 33 | |
019e8582 PK |
34 | /* |
35 | * round lowpc and highpc to multiples of the density we're using | |
36 | * so the rest of the scaling (here and in gprof) stays in ints. | |
37 | */ | |
38 | lowpc = (char *) | |
39 | ROUNDDOWN((unsigned)lowpc, HISTFRACTION*sizeof(HISTCOUNTER)); | |
387d0540 | 40 | s_lowpc = lowpc; |
019e8582 PK |
41 | highpc = (char *) |
42 | ROUNDUP((unsigned)highpc, HISTFRACTION*sizeof(HISTCOUNTER)); | |
387d0540 | 43 | s_highpc = highpc; |
3a2b18f4 | 44 | s_textsize = highpc - lowpc; |
019e8582 | 45 | monsize = (s_textsize / HISTFRACTION) + sizeof(struct phdr); |
387d0540 PK |
46 | buffer = sbrk( monsize ); |
47 | if ( buffer == (char *) -1 ) { | |
48 | write( 2 , MSG , sizeof(MSG) ); | |
49 | return; | |
50 | } | |
f4d8fa4a | 51 | froms = (unsigned short *) sbrk( s_textsize / HASHFRACTION ); |
387d0540 PK |
52 | if ( froms == (unsigned short *) -1 ) { |
53 | write( 2 , MSG , sizeof(MSG) ); | |
54 | froms = 0; | |
55 | return; | |
56 | } | |
019e8582 PK |
57 | limit = s_textsize * ARCDENSITY / 100; |
58 | if ( limit < MINARCS ) { | |
59 | limit = MINARCS; | |
4dff44be KM |
60 | } else if ( limit > 65534 ) { |
61 | limit = 65534; | |
62 | } | |
63 | tos = (struct tostruct *) sbrk( limit * sizeof( struct tostruct ) ); | |
387d0540 PK |
64 | if ( tos == (struct tostruct *) -1 ) { |
65 | write( 2 , MSG , sizeof(MSG) ); | |
66 | froms = 0; | |
67 | tos = 0; | |
68 | return; | |
69 | } | |
019e8582 | 70 | minsbrk = sbrk(0); |
387d0540 | 71 | tos[0].link = 0; |
3a2b18f4 PK |
72 | /* |
73 | * tolimit is what mcount checks to see if | |
74 | * all the data structures are ready!!! | |
75 | * make sure it won't overflow. | |
76 | */ | |
4dff44be | 77 | tolimit = limit; |
ee56ba6f | 78 | monitor( lowpc , highpc , buffer , monsize , tolimit ); |
50084e08 PK |
79 | } |
80 | ||
81 | _mcleanup() | |
82 | { | |
bb9c5045 KM |
83 | int fd; |
84 | int fromindex; | |
f4d8fa4a | 85 | int endfrom; |
bb9c5045 KM |
86 | char *frompc; |
87 | int toindex; | |
88 | struct rawarc rawarc; | |
50084e08 | 89 | |
bb9c5045 KM |
90 | fd = creat( "gmon.out" , 0666 ); |
91 | if ( fd < 0 ) { | |
387d0540 | 92 | perror( "mcount: gmon.out" ); |
50084e08 PK |
93 | return; |
94 | } | |
387d0540 PK |
95 | # ifdef DEBUG |
96 | fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz ); | |
97 | # endif DEBUG | |
bb9c5045 | 98 | write( fd , sbuf , ssiz ); |
f4d8fa4a KM |
99 | endfrom = s_textsize / (HASHFRACTION * sizeof(*froms)); |
100 | for ( fromindex = 0 ; fromindex < endfrom ; fromindex++ ) { | |
50084e08 PK |
101 | if ( froms[fromindex] == 0 ) { |
102 | continue; | |
103 | } | |
f4d8fa4a | 104 | frompc = s_lowpc + (fromindex * HASHFRACTION * sizeof(*froms)); |
50084e08 PK |
105 | for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) { |
106 | # ifdef DEBUG | |
22f3ec41 PK |
107 | fprintf( stderr , |
108 | "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" , | |
50084e08 PK |
109 | frompc , tos[toindex].selfpc , tos[toindex].count ); |
110 | # endif DEBUG | |
bb9c5045 KM |
111 | rawarc.raw_frompc = (unsigned long) frompc; |
112 | rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc; | |
113 | rawarc.raw_count = tos[toindex].count; | |
114 | write( fd , &rawarc , sizeof rawarc ); | |
50084e08 PK |
115 | } |
116 | } | |
bb9c5045 | 117 | close( fd ); |
50084e08 PK |
118 | } |
119 | ||
019e8582 PK |
120 | asm(".text"); |
121 | asm("#the beginning of mcount()"); | |
122 | asm(".data"); | |
50084e08 PK |
123 | mcount() |
124 | { | |
019e8582 PK |
125 | register char *selfpc; /* r11 => r5 */ |
126 | register unsigned short *frompcindex; /* r10 => r4 */ | |
127 | register struct tostruct *top; /* r9 => r3 */ | |
128 | register struct tostruct *prevtop; /* r8 => r2 */ | |
129 | register long toindex; /* r7 => r1 */ | |
130 | static int profiling = 0; | |
131 | ||
50084e08 | 132 | #ifdef lint |
019e8582 PK |
133 | selfpc = (char *)0; |
134 | frompcindex = 0; | |
50084e08 PK |
135 | #else not lint |
136 | /* | |
785a53a1 PK |
137 | * find the return address for mcount, |
138 | * and the return address for mcount's caller. | |
50084e08 | 139 | */ |
019e8582 PK |
140 | asm(" .text"); /* make sure we're in text space */ |
141 | asm(" movl (sp), r11"); /* selfpc = ... (jsb frame) */ | |
142 | asm(" movl 16(fp), r10"); /* frompcindex = (calls frame) */ | |
50084e08 | 143 | #endif not lint |
785a53a1 PK |
144 | /* |
145 | * check that we are profiling | |
387d0540 | 146 | * and that we aren't recursively invoked. |
785a53a1 | 147 | */ |
019e8582 PK |
148 | if (tolimit == 0) { |
149 | goto out; | |
150 | } | |
151 | if (profiling) { | |
152 | goto out; | |
153 | } | |
154 | profiling = 1; | |
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: |
019e8582 PK |
236 | profiling = 0; |
237 | /* and fall through */ | |
50084e08 | 238 | out: |
019e8582 | 239 | asm(" rsb"); |
50084e08 PK |
240 | |
241 | overflow: | |
019e8582 | 242 | tolimit = 0; |
50084e08 | 243 | # define TOLIMIT "mcount: tos overflow\n" |
019e8582 PK |
244 | write(2, TOLIMIT, sizeof(TOLIMIT)); |
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 PK |
254 | char *highpc; |
255 | int *buf, bufsiz; | |
ee56ba6f | 256 | int nfunc; /* not used, available for compatability only */ |
50084e08 | 257 | { |
387d0540 | 258 | register o; |
50084e08 | 259 | |
387d0540 PK |
260 | if ( lowpc == 0 ) { |
261 | profil( (char *) 0 , 0 , 0 , 0 ); | |
ee56ba6f | 262 | _mcleanup(); |
387d0540 PK |
263 | return; |
264 | } | |
265 | sbuf = buf; | |
266 | ssiz = bufsiz; | |
267 | ( (struct phdr *) buf ) -> lpc = lowpc; | |
268 | ( (struct phdr *) buf ) -> hpc = highpc; | |
269 | ( (struct phdr *) buf ) -> ncnt = ssiz; | |
270 | o = sizeof(struct phdr); | |
271 | buf = (int *) ( ( (int) buf ) + o ); | |
272 | bufsiz -= o; | |
273 | if ( bufsiz <= 0 ) | |
274 | return; | |
ef7f2ecf | 275 | o = ( ( (char *) highpc - (char *) lowpc) ); |
387d0540 | 276 | if( bufsiz < o ) |
ef7f2ecf | 277 | o = ( (float) bufsiz / o ) * 65536; |
387d0540 | 278 | else |
ef7f2ecf | 279 | o = 65536; |
387d0540 | 280 | profil( buf , bufsiz , lowpc , o ); |
50084e08 | 281 | } |
0bbf4774 KM |
282 | |
283 | /* | |
284 | * This is a stub for the "brk" system call, which we want to | |
63238688 KM |
285 | * catch so that it will not deallocate our data space. |
286 | * (of which the program is not aware) | |
0bbf4774 | 287 | */ |
63238688 KM |
288 | extern char *curbrk; |
289 | ||
0bbf4774 | 290 | brk(addr) |
63238688 | 291 | char *addr; |
0bbf4774 | 292 | { |
63238688 KM |
293 | |
294 | if (addr < minsbrk) | |
295 | addr = minsbrk; | |
296 | asm(" chmk $17"); | |
ee56ba6f KM |
297 | asm(" jcc 1f"); |
298 | asm(" jmp cerror"); | |
299 | asm("1:"); | |
63238688 KM |
300 | curbrk = addr; |
301 | return (0); | |
0bbf4774 | 302 | } |