]> git.saurik.com Git - apple/libc.git/blob - gmon/gmon.c
b18daab056375653757cdbe953daff2d0b13c81d
[apple/libc.git] / gmon / gmon.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 #if defined(PROFILE)
26 #error This module cannot be compiled with profiling
27 #endif
28
29 /*-
30 * Copyright (c) 1983, 1992, 1993
31 * The Regents of the University of California. All rights reserved.
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
35 * are met:
36 * 1. Redistributions of source code must retain the above copyright
37 * notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 * notice, this list of conditions and the following disclaimer in the
40 * documentation and/or other materials provided with the distribution.
41 * 3. All advertising materials mentioning features or use of this software
42 * must display the following acknowledgement:
43 * This product includes software developed by the University of
44 * California, Berkeley and its contributors.
45 * 4. Neither the name of the University nor the names of its contributors
46 * may be used to endorse or promote products derived from this software
47 * without specific prior written permission.
48 *
49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * SUCH DAMAGE.
60 */
61 /*
62 * History
63 * 2-Mar-90 Gregg Kellogg (gk) at NeXT
64 * Changed include of kern/mach.h to kern/mach_interface.h
65 *
66 * 1-May-90 Matthew Self (mself) at NeXT
67 * Added prototypes, and added casts to remove all warnings.
68 * Made all private data static.
69 * vm_deallocate old data defore vm_allocate'ing new data.
70 * Added new functions monoutput and monreset.
71 *
72 * 18-Dec-92 Development Environment Group at NeXT
73 * Added multiple profile areas, the ability to profile shlibs and the
74 * ability to profile rld loaded code. Moved the machine dependent mcount
75 * routine out of this source file.
76 *
77 * 13-Dec-92 Development Environment Group at NeXT
78 * Added support for dynamic shared libraries. Also removed the code that
79 * had been ifdef'ed out for profiling fixed shared libraries and
80 * objective-C.
81 */
82
83 #if defined(LIBC_SCCS) && !defined(lint)
84 static char sccsid[] = "@(#)gmon.c 5.2 (Berkeley) 6/21/85";
85 #endif
86
87 /*
88 * see profil(2) where this (SCALE_1_TO_1) is describe (incorrectly).
89 *
90 * The correct description: scale is a fixed point value with
91 * the binary point in the middle of the 32 bit value. (Bit 16 is
92 * 1, bit 15 is .5, etc.)
93 *
94 * Setting the scale to "1" (i.e. 0x10000), results in the kernel
95 * choosing the profile bucket address 1 to 1 with the pc sampled.
96 * Since buckets are shorts, if the profiling base were 0, then a pc
97 * of 0 increments bucket 0, a pc of 2 increments bucket 1, and a pc
98 * of 4 increments bucket 2.) (Actually, this seems a little bogus,
99 * 1 to 1 should map pc's to buckets -- that's probably what was
100 * intended from the man page, but historically....
101 */
102 #define SCALE_1_TO_1 0x10000L
103
104 #define MSG "No space for monitor buffer(s)\n"
105
106 #include <stdio.h>
107 #include <libc.h>
108 extern const struct section *getsectbyname(
109 const char *segname,
110 const char *sectname);
111 #include <monitor.h>
112 #include <sys/types.h>
113 #include <sys/gmon.h>
114 #include <sys/param.h>
115 #include <sys/sysctl.h>
116 #include <mach/mach.h>
117 #include <mach-o/loader.h>
118 #include <mach-o/dyld.h>
119
120 /*
121 * These are defined in here and these declarations need to be moved to libc.h
122 * where the other declarations for the monitor(3) routines are declared.
123 */
124 extern void moninit(
125 void);
126 extern void monaddition(
127 char *lowpc,
128 char *highpc);
129 extern void moncount(
130 char *frompc,
131 char *selfpc);
132 extern void monreset(
133 void);
134 extern void monoutput(
135 const char *filename);
136 extern int add_profil(char *, int, int, int);
137
138 static char profiling = -1; /* tas (test and set) location for NeXT */
139 static char init = 0; /* set while moninit() is being serviced */
140
141 static unsigned long order = 0; /* call order */
142
143 struct mon_t {
144 /* the address range and size this mon struct refers to */
145 char *lowpc;
146 char *highpc;
147 unsigned long textsize;
148 /* the data structures to support the arc's and their counts */
149 unsigned short *froms; /* froms is unsigned shorts indexing into tos */
150 struct tostruct *tos;
151 long tolimit;
152 /* the pc-sample buffer, it's size and scale */
153 char *sbuf;
154 int ssiz; /* includes the gmonhdr struct */
155 int scale;
156 };
157 static struct mon_t *mon = NULL;
158 static unsigned long nmon = 0;
159
160 static void monsetup(
161 struct mon_t *m,
162 char *lowpc,
163 char *highpc);
164 static int getprofhz(
165 void);
166
167 void
168 moninit(
169 void)
170 {
171 const struct section *section;
172 char *lowpc, *highpc;
173 unsigned long i;
174
175 monreset();
176 init = 1;
177
178 section = getsectbyname ("__TEXT", "__text");
179 lowpc = (char *)section->addr,
180 highpc = (char *)(section->addr + section->size);
181
182 if(mon == NULL){
183 if((mon = malloc(sizeof(struct mon_t))) == NULL){
184 write(2, MSG, sizeof(MSG) - 1);
185 return;
186 }
187 nmon = 1;
188 memset(mon, '\0', sizeof(struct mon_t));
189 }
190 /*
191 * To continue to make monstartup() and the functions that existed
192 * before adding multiple profiling areas working correctly the new
193 * calls to get the dyld loaded code profiled are made after
194 * the first mon_t struct is allocated so that they will not use the
195 * first mon_t and the old calls will always use the first mon_t struct
196 * in the list.
197 */
198 monsetup(mon, lowpc, highpc);
199
200 profil(mon->sbuf + sizeof(struct gmonhdr),
201 mon->ssiz - sizeof(struct gmonhdr),
202 (int)mon->lowpc, mon->scale);
203 for(i = 1; i < nmon; i++)
204 add_profil(mon[i].sbuf + sizeof(struct gmonhdr),
205 mon[i].ssiz - sizeof(struct gmonhdr),
206 (int)mon[i].lowpc, mon[i].scale);
207 init = 0;
208 profiling = 0;
209
210 #if defined(__DYNAMIC__)
211 /*
212 * Call _dyld_moninit() if the dyld is present. This is done after the
213 * above calls so the dynamic libraries will be added after the
214 * executable.
215 */
216 if(_dyld_present())
217 _dyld_moninit(monaddition);
218 #endif
219 }
220
221 void
222 monstartup(
223 char *lowpc,
224 char *highpc)
225 {
226 monreset();
227 if(mon == NULL){
228 if((mon = malloc(sizeof(struct mon_t))) == NULL){
229 write(2, MSG, sizeof(MSG) - 1);
230 return;
231 }
232 nmon = 1;
233 memset(mon, '\0', sizeof(struct mon_t));
234 }
235 monsetup(mon, lowpc, highpc);
236 }
237
238 /*
239 * monaddtion() is used for adding additional pc ranges to profile. This is
240 * used for profiling dyld loaded code.
241 */
242 void
243 monaddition(
244 char *lowpc,
245 char *highpc)
246 {
247 char save_profiling;
248 struct mon_t *m;
249
250 if(mon == NULL){
251 monstartup(lowpc, highpc);
252 return;
253 }
254 save_profiling = profiling;
255 profiling = -1;
256 if((mon = realloc(mon, (nmon + 1) * sizeof(struct mon_t))) == NULL){
257 write(2, MSG, sizeof(MSG) - 1);
258 return;
259 }
260 m = mon + nmon;
261 memset(m, '\0', sizeof(struct mon_t));
262 nmon++;
263 monsetup(m, lowpc, highpc);
264 profiling = save_profiling;
265 }
266
267 static
268 void
269 monsetup(
270 struct mon_t *m,
271 char *lowpc,
272 char *highpc)
273 {
274 int monsize;
275 char *buffer;
276 kern_return_t ret;
277 struct gmonhdr *p;
278 unsigned int o;
279
280 /*
281 * round lowpc and highpc to multiples of the density we're using
282 * so the rest of the scaling (here and in gprof) stays in ints.
283 */
284 lowpc = (char *)ROUNDDOWN((unsigned)lowpc,
285 HISTFRACTION * sizeof(HISTCOUNTER));
286 m->lowpc = lowpc;
287 highpc = (char *)ROUNDUP((unsigned)highpc,
288 HISTFRACTION * sizeof(HISTCOUNTER));
289 m->highpc = highpc;
290
291 if(m->froms)
292 vm_deallocate(mach_task_self(),
293 (vm_address_t)m->froms,
294 (vm_size_t)(m->textsize / HASHFRACTION));
295 m->textsize = highpc - lowpc;
296 ret = vm_allocate(mach_task_self(),
297 (vm_address_t *)&m->froms,
298 (vm_size_t)(m->textsize / HASHFRACTION),
299 TRUE);
300 if(ret != KERN_SUCCESS){
301 write(2, MSG, sizeof(MSG) - 1);
302 m->froms = 0;
303 return;
304 }
305
306 if(m->sbuf)
307 vm_deallocate(mach_task_self(),
308 (vm_address_t)m->sbuf,
309 (vm_size_t)m->ssiz);
310 monsize = (m->textsize / HISTFRACTION) + sizeof(struct gmonhdr);
311 ret = vm_allocate(mach_task_self(),
312 (vm_address_t *)&buffer,
313 (vm_size_t)monsize,
314 TRUE);
315 if(ret != KERN_SUCCESS){
316 write(2, MSG, sizeof(MSG) - 1);
317 m->sbuf = 0;
318 return;
319 }
320
321 if(m->tos)
322 vm_deallocate(mach_task_self(),
323 (vm_address_t)m->tos,
324 (vm_size_t)(m->tolimit * sizeof(struct tostruct)));
325 m->tolimit = m->textsize * ARCDENSITY / 100;
326 if(m->tolimit < MINARCS){
327 m->tolimit = MINARCS;
328 }
329 else if(m->tolimit > 65534){
330 m->tolimit = 65534;
331 }
332 ret = vm_allocate(mach_task_self(),
333 (vm_address_t *)&m->tos,
334 (vm_size_t)(m->tolimit * sizeof(struct tostruct)),
335 TRUE);
336 if(ret != KERN_SUCCESS){
337 write(2, MSG, sizeof(MSG) - 1);
338 m->tos = 0;
339 return;
340 }
341 m->tos[0].link = 0; /* a nop since tos was vm_allocated and is zero */
342
343 /*
344 * If this is call to monsetup() was via monstartup() (m == mon) then
345 * it is using or reusing the first pc range and then the pc sample
346 * buffer can be setup by the system call profil() via monitor() via
347 * a moncontrol(1) call.
348 *
349 * Otherwise this is call to monsetup() was via monaddition() and a
350 * new system call is needed to add an additional pc sample buffer in
351 * the kernel.
352 */
353 if(m == mon && !init){
354 monitor(lowpc, highpc, buffer, monsize, m->tolimit);
355 }
356 else{
357 /* monitor() functionality */
358 m->sbuf = buffer;
359 m->ssiz = monsize;
360 p = (struct gmonhdr *)m->sbuf;
361 memset(p, '\0', sizeof(struct gmonhdr));
362 p->lpc = (unsigned long)m->lowpc;
363 p->hpc = (unsigned long)m->highpc;
364 p->ncnt = m->ssiz;
365 p->version = GMONVERSION;
366 p->profrate = getprofhz();
367 o = highpc - lowpc;
368 if((monsize - sizeof(struct gmonhdr)) < o)
369 /* POSSIBLE BUG, if "(float) (monsize - sizeof(struct gmonhdr))/ o)" is zero
370 * then m->scale will be set to zero and the add_profil() call will disable
371 * profiling */
372 m->scale = ((float) (monsize - sizeof(struct gmonhdr))/ o) *
373 SCALE_1_TO_1;
374 else
375 m->scale = SCALE_1_TO_1;
376
377 /* moncontrol(mode == 1) functionality */
378 if(!init)
379 add_profil(m->sbuf + sizeof(struct gmonhdr),
380 m->ssiz - sizeof(struct gmonhdr),
381 (int)m->lowpc, m->scale);
382 }
383 }
384
385 void
386 monreset(
387 void)
388 {
389 unsigned long i;
390 struct mon_t *m;
391 struct gmonhdr *p;
392
393 moncontrol(0);
394 if(mon == NULL)
395 return;
396 for(i = 0; i < nmon; i++){
397 m = mon + i;
398 if(m->sbuf != NULL){
399 memset(m->sbuf, '\0', m->ssiz);
400 p = (struct gmonhdr *)m->sbuf;
401 p->lpc = (unsigned long)m->lowpc;
402 p->hpc = (unsigned long)m->highpc;
403 p->ncnt = m->ssiz;
404 p->version = GMONVERSION;
405 p->profrate = getprofhz();
406 }
407 if(m->froms != NULL)
408 memset(m->froms, '\0', m->textsize / HASHFRACTION);
409 if(m->tos != NULL)
410 memset(m->tos, '\0', m->tolimit * sizeof (struct tostruct));
411 }
412 order = 0;
413 moncontrol(1);
414 }
415
416 void
417 monoutput(
418 const char *filename)
419 {
420 int fd;
421 unsigned long magic, i, fromindex, endfrom, toindex;
422 struct gmon_data sample_data, arc_data, dyld_data;
423 char *frompc;
424 struct rawarc_order rawarc_order;
425 struct mon_t *m;
426 unsigned long image_count, vmaddr_slide;
427 char *image_name;
428
429 moncontrol(0);
430 m = mon;
431 if(m == NULL)
432 return;
433 fd = creat(filename, 0666);
434 if(fd < 0){
435 perror("mcount: gmon.out");
436 return;
437 }
438
439 magic = GMON_MAGIC;
440 write(fd, &magic, sizeof(unsigned long));
441
442 #if defined(__DYNAMIC__)
443 if(_dyld_present()){
444 image_count = _dyld_image_count();
445 if(image_count > 1){
446 #ifdef DYLD_DEBUG
447 printf("image_count = %lu\n", image_count - 1);
448 for(i = 1; i < image_count; i++){
449 vmaddr_slide = _dyld_get_image_vmaddr_slide(i);
450 printf("\tvmaddr_slide 0x%x\n", (unsigned int)vmaddr_slide);
451 image_name = _dyld_get_image_name(i);
452 printf("\timage_name %s\n", image_name);
453 }
454 #endif
455 /*
456 * Calculate the dyld_data.size.
457 */
458 dyld_data.type = GMONTYPE_DYLD_STATE;
459 dyld_data.size = sizeof(unsigned long) +
460 sizeof(unsigned long) * (image_count - 1);
461 for(i = 1; i < image_count; i++){
462 image_name = _dyld_get_image_name(i);
463 dyld_data.size += strlen(image_name) + 1;
464 }
465
466 /*
467 * Write the dyld_data.
468 */
469 write(fd, &dyld_data, sizeof(struct gmon_data));
470 image_count--;
471 write(fd, &image_count, sizeof(unsigned long));
472 image_count++;
473 for(i = 1; i < image_count; i++){
474 vmaddr_slide = _dyld_get_image_vmaddr_slide(i);
475 write(fd, &vmaddr_slide, sizeof(unsigned long));
476 image_name = _dyld_get_image_name(i);
477 write(fd, image_name, strlen(image_name) + 1);
478 }
479 }
480 }
481 #endif
482 for(i = 0; i < nmon; i++){
483 m = mon + i;
484 #ifdef DEBUG
485 fprintf(stderr, "[monoutput] sbuf 0x%x ssiz %d\n",
486 m->sbuf, m->ssiz);
487 #endif
488 sample_data.type = GMONTYPE_SAMPLES;
489 sample_data.size = m->ssiz;
490 write(fd, &sample_data, sizeof(struct gmon_data));
491 /*
492 * Write the gmonhdr struct and the pc-sample buffer. Note the
493 * gmonhdr struct is in sbuf at the beginning of sbuf already
494 * filled in.
495 */
496 write(fd, m->sbuf, m->ssiz);
497
498 /*
499 * Now write out the raw arcs.
500 */
501 endfrom = m->textsize / (HASHFRACTION * sizeof(*m->froms));
502 arc_data.type = GMONTYPE_ARCS_ORDERS;
503 arc_data.size = 0;
504 for(fromindex = 0; fromindex < endfrom; fromindex++){
505 if(m->froms[fromindex] == 0){
506 continue;
507 }
508 frompc = m->lowpc +
509 (fromindex * HASHFRACTION * sizeof(*m->froms));
510 for(toindex = m->froms[fromindex];
511 toindex != 0;
512 toindex = m->tos[toindex].link){
513 arc_data.size += sizeof(struct rawarc_order);
514 }
515 }
516 write(fd, &arc_data, sizeof(struct gmon_data));
517
518 for(fromindex = 0; fromindex < endfrom; fromindex++){
519 if(m->froms[fromindex] == 0){
520 continue;
521 }
522 frompc = m->lowpc +
523 (fromindex * HASHFRACTION * sizeof(*m->froms));
524 for(toindex = m->froms[fromindex];
525 toindex != 0;
526 toindex = m->tos[toindex].link){
527 #ifdef DEBUG
528 fprintf(stderr, "[monoutput] frompc 0x%x selfpc 0x%x "
529 "count %ld order %lu\n", (unsigned int)frompc,
530 (unsigned int)m->tos[toindex].selfpc,
531 m->tos[toindex].count, m->tos[toindex].order);
532 #endif
533 rawarc_order.raw_frompc = (unsigned long)frompc;
534 rawarc_order.raw_selfpc = (unsigned long)
535 m->tos[toindex].selfpc;
536 rawarc_order.raw_count = m->tos[toindex].count;
537 rawarc_order.raw_order = m->tos[toindex].order;
538 write(fd, &rawarc_order, sizeof(struct rawarc_order));
539 }
540 }
541 }
542 close(fd);
543 }
544
545 void
546 monitor(
547 char *lowpc,
548 char *highpc,
549 char *buf,
550 int bufsiz,
551 int nfunc) /* nfunc is not used; available for compatability only. */
552 {
553 unsigned int o;
554 struct gmonhdr *p;
555 struct mon_t *m;
556
557 moncontrol(0);
558 m = mon;
559 if(m == NULL)
560 return;
561 if(lowpc == 0){
562 moncontrol(0);
563 monoutput("gmon.out");
564 return;
565 }
566 m->sbuf = buf;
567 m->ssiz = bufsiz;
568 p = (struct gmonhdr *)buf;
569 memset(p, '\0', sizeof(struct gmonhdr));
570 p->lpc = (unsigned long)lowpc;
571 p->hpc = (unsigned long)highpc;
572 p->ncnt = m->ssiz;
573 p->version = GMONVERSION;
574 p->profrate = getprofhz();
575 bufsiz -= sizeof(struct gmonhdr);
576 if(bufsiz <= 0)
577 return;
578 o = highpc - lowpc;
579 if(bufsiz < o)
580 m->scale = ((float) bufsiz / o) * SCALE_1_TO_1;
581 else
582 m->scale = SCALE_1_TO_1;
583 moncontrol(1);
584 }
585
586 /*
587 * Control profiling
588 * profiling is what mcount checks to see if
589 * all the data structures are ready.
590 */
591 void
592 moncontrol(
593 int mode)
594 {
595 struct mon_t *m;
596 unsigned long i;
597
598 if(mode){
599 /* start */
600 m = mon;
601 if(m != NULL){
602 profil(m->sbuf + sizeof(struct gmonhdr),
603 m->ssiz - sizeof(struct gmonhdr),
604 (int)m->lowpc, m->scale);
605 for(i = 1; i < nmon; i++)
606 add_profil(mon[i].sbuf + sizeof(struct gmonhdr),
607 mon[i].ssiz - sizeof(struct gmonhdr),
608 (int)mon[i].lowpc, mon[i].scale);
609 profiling = 0;
610 }
611 }
612 else{
613 /* stop */
614 profil((char *)0, 0, 0, 0);
615 profiling = -1;
616 }
617 }
618
619 void
620 moncount(
621 char *frompc,
622 char *selfpc)
623 {
624 unsigned short *frompcindex;
625 struct tostruct *top, *prevtop;
626 unsigned long i, toindex;
627 struct mon_t *m;
628
629 m = mon;
630 if(m == NULL)
631 return;
632 /*
633 * Check that we are profiling and that we aren't recursively invoked.
634 * This should really be a test and set instruction in changing the
635 * value of profiling.
636 */
637 if(profiling)
638 return;
639 profiling++;
640
641
642 #ifdef DEBUG
643 fprintf(stderr, "[moncount] frompc 0x%x selfpc 0x%x\n",
644 (unsigned int)frompc, (unsigned int)selfpc);
645 #endif
646 frompcindex = (unsigned short *)frompc;
647
648 /*
649 * check that frompcindex is a reasonable pc value.
650 * for example: signal catchers get called from the stack,
651 * not from text space. too bad.
652 */
653 for(i = 0; i < nmon; i++){
654 m = mon + i;
655 if((unsigned long)frompcindex >= (unsigned long)m->lowpc &&
656 (unsigned long)frompcindex < (unsigned long)m->highpc)
657 break;
658 }
659 if(i == nmon){
660 goto done;
661 }
662 else{
663 frompcindex = (unsigned short *)
664 ((unsigned long)frompcindex - (unsigned long)m->lowpc);
665 }
666 frompcindex =
667 &m->froms[((long)frompcindex) / (HASHFRACTION * sizeof(*m->froms))];
668 toindex = *frompcindex;
669 if(toindex == 0){
670 /*
671 * first time traversing this arc
672 */
673 toindex = ++m->tos[0].link;
674 if(toindex >= m->tolimit){
675 goto overflow;
676 }
677 *frompcindex = toindex;
678 top = &m->tos[toindex];
679 top->selfpc = (unsigned long)selfpc;
680 top->count = 1;
681 top->link = 0;
682 top->order = ++order;
683 goto done;
684 }
685 top = &m->tos[toindex];
686 if(top->selfpc == (unsigned long)selfpc){
687 /*
688 * arc at front of chain; usual case.
689 */
690 top->count++;
691 goto done;
692 }
693 /*
694 * have to go looking down chain for it.
695 * top points to what we are looking at,
696 * prevtop points to previous top.
697 * we know it is not at the head of the chain.
698 */
699 for(; /* goto done */; ){
700 if(top->link == 0){
701 /*
702 * top is end of the chain and none of the chain
703 * had top->selfpc == selfpc.
704 * so we allocate a new tostruct
705 * and link it to the head of the chain.
706 */
707 toindex = ++m->tos[0].link;
708 if(toindex >= m->tolimit){
709 goto overflow;
710 }
711 top = &m->tos[toindex];
712 top->selfpc = (unsigned long)selfpc;
713 top->count = 1;
714 top->link = *frompcindex;
715 top->order = ++order;
716 *frompcindex = toindex;
717 goto done;
718 }
719 /*
720 * otherwise, check the next arc on the chain.
721 */
722 prevtop = top;
723 top = &m->tos[top->link];
724 if(top->selfpc == (unsigned long)selfpc){
725 /*
726 * there it is.
727 * increment its count
728 * move it to the head of the chain.
729 */
730 top->count++;
731 toindex = prevtop->link;
732 prevtop->link = top->link;
733 top->link = *frompcindex;
734 *frompcindex = toindex;
735 goto done;
736 }
737 }
738 done:
739 profiling--;
740 return;
741
742 overflow:
743 profiling++; /* halt further profiling */
744 #define TOLIMIT "mcount: tos overflow\n"
745 write(2, TOLIMIT, sizeof(TOLIMIT) - 1);
746 }
747
748 /*
749 * Get the profiling rate.
750 */
751 static
752 int
753 getprofhz(void)
754 {
755 int mib[2];
756 size_t size;
757 struct clockinfo clockrate;
758
759 mib[0] = CTL_KERN;
760 mib[1] = KERN_CLOCKRATE;
761 clockrate.profhz = 1;
762 size = sizeof(clockrate);
763 if(sysctl(mib, 2, &clockrate, &size, NULL, 0) < 0)
764 ;
765 return(clockrate.profhz);
766 }