Commit | Line | Data |
---|---|---|
e804469b | 1 | static char *sccsid = "@(#)gmon.c 4.10 (Berkeley) 1/14/83"; |
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 | */ | |
5a9da8d5 | 12 | static int profiling = 3; |
50084e08 PK |
13 | static unsigned short *froms; |
14 | static struct tostruct *tos = 0; | |
019e8582 | 15 | static long tolimit = 0; |
50084e08 PK |
16 | static char *s_lowpc = 0; |
17 | static char *s_highpc = 0; | |
3a2b18f4 | 18 | static unsigned long s_textsize = 0; |
63238688 | 19 | static char *minsbrk = 0; |
50084e08 | 20 | |
387d0540 PK |
21 | static int ssiz; |
22 | static int *sbuf; | |
50084e08 | 23 | |
50084e08 PK |
24 | #define MSG "No space for monitor buffer(s)\n" |
25 | ||
ee56ba6f | 26 | monstartup(lowpc, highpc) |
387d0540 PK |
27 | char *lowpc; |
28 | char *highpc; | |
50084e08 | 29 | { |
3a2b18f4 PK |
30 | int monsize; |
31 | char *buffer; | |
32 | char *sbrk(); | |
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 | } | |
5a9da8d5 KM |
57 | tolimit = s_textsize * ARCDENSITY / 100; |
58 | if ( tolimit < MINARCS ) { | |
59 | tolimit = MINARCS; | |
60 | } else if ( tolimit > 65534 ) { | |
61 | tolimit = 65534; | |
4dff44be | 62 | } |
5a9da8d5 | 63 | tos = (struct tostruct *) sbrk( tolimit * 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; |
5a9da8d5 | 72 | monitor( lowpc , highpc , buffer , monsize , tolimit ); |
3a2b18f4 | 73 | /* |
5a9da8d5 | 74 | * profiling is what mcount checks to see if |
3a2b18f4 | 75 | * all the data structures are ready!!! |
3a2b18f4 | 76 | */ |
5a9da8d5 | 77 | profiling = 0; |
50084e08 PK |
78 | } |
79 | ||
80 | _mcleanup() | |
81 | { | |
bb9c5045 KM |
82 | int fd; |
83 | int fromindex; | |
f4d8fa4a | 84 | int endfrom; |
bb9c5045 KM |
85 | char *frompc; |
86 | int toindex; | |
87 | struct rawarc rawarc; | |
50084e08 | 88 | |
bb9c5045 KM |
89 | fd = creat( "gmon.out" , 0666 ); |
90 | if ( fd < 0 ) { | |
387d0540 | 91 | perror( "mcount: gmon.out" ); |
50084e08 PK |
92 | return; |
93 | } | |
387d0540 PK |
94 | # ifdef DEBUG |
95 | fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz ); | |
96 | # endif DEBUG | |
bb9c5045 | 97 | write( fd , sbuf , ssiz ); |
f4d8fa4a KM |
98 | endfrom = s_textsize / (HASHFRACTION * sizeof(*froms)); |
99 | for ( fromindex = 0 ; fromindex < endfrom ; fromindex++ ) { | |
50084e08 PK |
100 | if ( froms[fromindex] == 0 ) { |
101 | continue; | |
102 | } | |
f4d8fa4a | 103 | frompc = s_lowpc + (fromindex * HASHFRACTION * sizeof(*froms)); |
50084e08 PK |
104 | for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) { |
105 | # ifdef DEBUG | |
22f3ec41 PK |
106 | fprintf( stderr , |
107 | "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" , | |
50084e08 PK |
108 | frompc , tos[toindex].selfpc , tos[toindex].count ); |
109 | # endif DEBUG | |
bb9c5045 KM |
110 | rawarc.raw_frompc = (unsigned long) frompc; |
111 | rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc; | |
112 | rawarc.raw_count = tos[toindex].count; | |
113 | write( fd , &rawarc , sizeof rawarc ); | |
50084e08 PK |
114 | } |
115 | } | |
bb9c5045 | 116 | close( fd ); |
50084e08 PK |
117 | } |
118 | ||
019e8582 PK |
119 | asm(".text"); |
120 | asm("#the beginning of mcount()"); | |
121 | asm(".data"); | |
50084e08 PK |
122 | mcount() |
123 | { | |
019e8582 PK |
124 | register char *selfpc; /* r11 => r5 */ |
125 | register unsigned short *frompcindex; /* r10 => r4 */ | |
126 | register struct tostruct *top; /* r9 => r3 */ | |
127 | register struct tostruct *prevtop; /* r8 => r2 */ | |
128 | register long toindex; /* r7 => r1 */ | |
019e8582 | 129 | |
50084e08 | 130 | #ifdef lint |
019e8582 PK |
131 | selfpc = (char *)0; |
132 | frompcindex = 0; | |
50084e08 PK |
133 | #else not lint |
134 | /* | |
785a53a1 PK |
135 | * find the return address for mcount, |
136 | * and the return address for mcount's caller. | |
50084e08 | 137 | */ |
019e8582 PK |
138 | asm(" .text"); /* make sure we're in text space */ |
139 | asm(" movl (sp), r11"); /* selfpc = ... (jsb frame) */ | |
140 | asm(" movl 16(fp), r10"); /* frompcindex = (calls frame) */ | |
50084e08 | 141 | #endif not lint |
785a53a1 PK |
142 | /* |
143 | * check that we are profiling | |
387d0540 | 144 | * and that we aren't recursively invoked. |
785a53a1 | 145 | */ |
019e8582 PK |
146 | if (profiling) { |
147 | goto out; | |
148 | } | |
5a9da8d5 | 149 | profiling++; |
785a53a1 PK |
150 | /* |
151 | * check that frompcindex is a reasonable pc value. | |
152 | * for example: signal catchers get called from the stack, | |
153 | * not from text space. too bad. | |
154 | */ | |
019e8582 PK |
155 | frompcindex = (unsigned short *)((long)frompcindex - (long)s_lowpc); |
156 | if ((unsigned long)frompcindex > s_textsize) { | |
157 | goto done; | |
50084e08 | 158 | } |
019e8582 | 159 | frompcindex = |
f4d8fa4a | 160 | &froms[((long)frompcindex) / (HASHFRACTION * sizeof(*froms))]; |
019e8582 PK |
161 | toindex = *frompcindex; |
162 | if (toindex == 0) { | |
163 | /* | |
164 | * first time traversing this arc | |
165 | */ | |
166 | toindex = ++tos[0].link; | |
167 | if (toindex >= tolimit) { | |
168 | goto overflow; | |
169 | } | |
170 | *frompcindex = toindex; | |
171 | top = &tos[toindex]; | |
172 | top->selfpc = selfpc; | |
173 | top->count = 1; | |
174 | top->link = 0; | |
175 | goto done; | |
50084e08 | 176 | } |
019e8582 PK |
177 | top = &tos[toindex]; |
178 | if (top->selfpc == selfpc) { | |
179 | /* | |
180 | * arc at front of chain; usual case. | |
181 | */ | |
182 | top->count++; | |
183 | goto done; | |
184 | } | |
185 | /* | |
186 | * have to go looking down chain for it. | |
187 | * top points to what we are looking at, | |
188 | * prevtop points to previous top. | |
189 | * we know it is not at the head of the chain. | |
190 | */ | |
191 | for (; /* goto done */; ) { | |
192 | if (top->link == 0) { | |
193 | /* | |
194 | * top is end of the chain and none of the chain | |
195 | * had top->selfpc == selfpc. | |
196 | * so we allocate a new tostruct | |
197 | * and link it to the head of the chain. | |
198 | */ | |
199 | toindex = ++tos[0].link; | |
200 | if (toindex >= tolimit) { | |
201 | goto overflow; | |
202 | } | |
203 | top = &tos[toindex]; | |
204 | top->selfpc = selfpc; | |
205 | top->count = 1; | |
206 | top->link = *frompcindex; | |
207 | *frompcindex = toindex; | |
208 | goto done; | |
209 | } | |
210 | /* | |
211 | * otherwise, check the next arc on the chain. | |
212 | */ | |
213 | prevtop = top; | |
214 | top = &tos[top->link]; | |
215 | if (top->selfpc == selfpc) { | |
216 | /* | |
217 | * there it is. | |
218 | * increment its count | |
219 | * move it to the head of the chain. | |
220 | */ | |
221 | top->count++; | |
222 | toindex = prevtop->link; | |
223 | prevtop->link = top->link; | |
224 | top->link = *frompcindex; | |
225 | *frompcindex = toindex; | |
226 | goto done; | |
227 | } | |
228 | ||
50084e08 | 229 | } |
785a53a1 | 230 | done: |
5a9da8d5 | 231 | profiling--; |
019e8582 | 232 | /* and fall through */ |
50084e08 | 233 | out: |
019e8582 | 234 | asm(" rsb"); |
50084e08 PK |
235 | |
236 | overflow: | |
5a9da8d5 | 237 | profiling++; /* halt further profiling */ |
50084e08 | 238 | # define TOLIMIT "mcount: tos overflow\n" |
019e8582 PK |
239 | write(2, TOLIMIT, sizeof(TOLIMIT)); |
240 | goto out; | |
50084e08 | 241 | } |
019e8582 PK |
242 | asm(".text"); |
243 | asm("#the end of mcount()"); | |
244 | asm(".data"); | |
50084e08 | 245 | |
ee56ba6f KM |
246 | /*VARARGS1*/ |
247 | monitor( lowpc , highpc , buf , bufsiz , nfunc ) | |
387d0540 | 248 | char *lowpc; |
387d0540 PK |
249 | char *highpc; |
250 | int *buf, bufsiz; | |
ee56ba6f | 251 | int nfunc; /* not used, available for compatability only */ |
50084e08 | 252 | { |
387d0540 | 253 | register o; |
50084e08 | 254 | |
387d0540 | 255 | if ( lowpc == 0 ) { |
5a9da8d5 | 256 | profiling++; /* halt profiling */ |
387d0540 | 257 | profil( (char *) 0 , 0 , 0 , 0 ); |
ee56ba6f | 258 | _mcleanup(); |
387d0540 PK |
259 | return; |
260 | } | |
261 | sbuf = buf; | |
262 | ssiz = bufsiz; | |
263 | ( (struct phdr *) buf ) -> lpc = lowpc; | |
264 | ( (struct phdr *) buf ) -> hpc = highpc; | |
265 | ( (struct phdr *) buf ) -> ncnt = ssiz; | |
266 | o = sizeof(struct phdr); | |
267 | buf = (int *) ( ( (int) buf ) + o ); | |
268 | bufsiz -= o; | |
269 | if ( bufsiz <= 0 ) | |
270 | return; | |
ef7f2ecf | 271 | o = ( ( (char *) highpc - (char *) lowpc) ); |
387d0540 | 272 | if( bufsiz < o ) |
ef7f2ecf | 273 | o = ( (float) bufsiz / o ) * 65536; |
387d0540 | 274 | else |
ef7f2ecf | 275 | o = 65536; |
387d0540 | 276 | profil( buf , bufsiz , lowpc , o ); |
50084e08 | 277 | } |
0bbf4774 KM |
278 | |
279 | /* | |
280 | * This is a stub for the "brk" system call, which we want to | |
63238688 KM |
281 | * catch so that it will not deallocate our data space. |
282 | * (of which the program is not aware) | |
0bbf4774 | 283 | */ |
63238688 KM |
284 | extern char *curbrk; |
285 | ||
0bbf4774 | 286 | brk(addr) |
63238688 | 287 | char *addr; |
0bbf4774 | 288 | { |
63238688 KM |
289 | |
290 | if (addr < minsbrk) | |
291 | addr = minsbrk; | |
292 | asm(" chmk $17"); | |
ee56ba6f KM |
293 | asm(" jcc 1f"); |
294 | asm(" jmp cerror"); | |
295 | asm("1:"); | |
63238688 KM |
296 | curbrk = addr; |
297 | return (0); | |
0bbf4774 | 298 | } |