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