]> git.saurik.com Git - apple/libc.git/blob - gmon/gmon.c
Libc-594.9.4.tar.gz
[apple/libc.git] / gmon / gmon.c
1 /*
2 * Copyright (c) 1999, 2003, 2004, 2007, 2008 Apple 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 _dyld_moninit(monaddition);
216 #endif
217 }
218
219 void
220 monstartup(
221 char *lowpc,
222 char *highpc)
223 {
224 monreset();
225 if(mon == NULL){
226 if((mon = malloc(sizeof(mon_t))) == NULL){
227 write(2, MSG, sizeof(MSG) - 1);
228 return;
229 }
230 nmon = 1;
231 memset(mon, '\0', sizeof(mon_t));
232 }
233 monsetup(mon, lowpc, highpc);
234 }
235
236 /*
237 * monaddtion() is used for adding additional pc ranges to profile. This is
238 * used for profiling dyld loaded code.
239 */
240 void
241 monaddition(
242 char *lowpc,
243 char *highpc)
244 {
245 char save_profiling;
246 mon_t *m;
247
248 if(mon == NULL){
249 monstartup(lowpc, highpc);
250 return;
251 }
252 save_profiling = profiling;
253 profiling = -1;
254 if((mon = realloc(mon, (nmon + 1) * sizeof(mon_t))) == NULL){
255 write(2, MSG, sizeof(MSG) - 1);
256 return;
257 }
258 m = mon + nmon;
259 memset(m, '\0', sizeof(mon_t));
260 nmon++;
261 monsetup(m, lowpc, highpc);
262 profiling = save_profiling;
263 }
264
265 static
266 void
267 monsetup(
268 mon_t *m,
269 char *lowpc,
270 char *highpc)
271 {
272 long monsize;
273 char *buffer;
274 kern_return_t ret;
275 gmonhdr_t *p;
276 uintptr_t o;
277
278 /*
279 * round lowpc and highpc to multiples of the density we're using
280 * so the rest of the scaling (here and in gprof) stays in longs.
281 */
282 lowpc = (char *)ROUNDDOWN((uintptr_t)lowpc,
283 HISTFRACTION * sizeof(HISTCOUNTER));
284 m->lowpc = lowpc;
285 highpc = (char *)ROUNDUP((uintptr_t)highpc,
286 HISTFRACTION * sizeof(HISTCOUNTER));
287 m->highpc = highpc;
288
289 if(m->froms)
290 vm_deallocate(mach_task_self(),
291 (vm_address_t)m->froms,
292 (vm_size_t)(m->textsize / HASHFRACTION));
293 m->textsize = highpc - lowpc;
294 ret = vm_allocate(mach_task_self(),
295 (vm_address_t *)&m->froms,
296 (vm_size_t)(m->textsize / HASHFRACTION),
297 TRUE);
298 if(ret != KERN_SUCCESS){
299 write(2, MSG, sizeof(MSG) - 1);
300 m->froms = 0;
301 return;
302 }
303
304 if(m->sbuf)
305 vm_deallocate(mach_task_self(),
306 (vm_address_t)m->sbuf,
307 (vm_size_t)m->ssiz);
308 monsize = (m->textsize / HISTFRACTION) + sizeof(gmonhdr_t);
309 ret = vm_allocate(mach_task_self(),
310 (vm_address_t *)&buffer,
311 (vm_size_t)monsize,
312 TRUE);
313 if(ret != KERN_SUCCESS){
314 write(2, MSG, sizeof(MSG) - 1);
315 m->sbuf = 0;
316 return;
317 }
318
319 if(m->tos)
320 vm_deallocate(mach_task_self(),
321 (vm_address_t)m->tos,
322 (vm_size_t)(m->tolimit * sizeof(tostruct_t)));
323 m->tolimit = m->textsize * ARCDENSITY / 100;
324 if(m->tolimit < MINARCS){
325 m->tolimit = MINARCS;
326 }
327 else if(m->tolimit > 65534){
328 m->tolimit = 65534;
329 }
330 ret = vm_allocate(mach_task_self(),
331 (vm_address_t *)&m->tos,
332 (vm_size_t)(m->tolimit * sizeof(tostruct_t)),
333 TRUE);
334 if(ret != KERN_SUCCESS){
335 write(2, MSG, sizeof(MSG) - 1);
336 m->tos = 0;
337 return;
338 }
339 m->tos[0].link = 0; /* a nop since tos was vm_allocated and is zero */
340
341 /*
342 * If this is call to monsetup() was via monstartup() (m == mon) then
343 * it is using or reusing the first pc range and then the pc sample
344 * buffer can be setup by the system call profil() via monitor() via
345 * a moncontrol(1) call.
346 *
347 * Otherwise this is call to monsetup() was via monaddition() and a
348 * new system call is needed to add an additional pc sample buffer in
349 * the kernel.
350 */
351 if(m == mon && !init){
352 monitor(lowpc, highpc, buffer, monsize, m->tolimit);
353 }
354 else{
355 /* monitor() functionality */
356 m->sbuf = buffer;
357 m->ssiz = monsize;
358 p = (gmonhdr_t *)m->sbuf;
359 memset(p, '\0', sizeof(gmonhdr_t));
360 p->lpc = (uintptr_t)m->lowpc;
361 p->hpc = (uintptr_t)m->highpc;
362 p->ncnt = m->ssiz;
363 p->version = GMONVERSION;
364 p->profrate = getprofhz();
365 o = highpc - lowpc;
366 if((monsize - sizeof(gmonhdr_t)) < o)
367 /* POSSIBLE BUG, if "(float) (monsize - sizeof(gmonhdr_t))/ o)" is zero
368 * then m->scale will be set to zero and the add_profil() call will disable
369 * profiling */
370 m->scale = ((float) (monsize - sizeof(gmonhdr_t))/ o) *
371 SCALE_1_TO_1;
372 else
373 m->scale = SCALE_1_TO_1;
374
375 /* moncontrol(mode == 1) functionality */
376 if(!init)
377 add_profil(m->sbuf + sizeof(gmonhdr_t),
378 m->ssiz - sizeof(gmonhdr_t),
379 (long)m->lowpc, m->scale);
380 }
381 }
382
383 void
384 monreset(
385 void)
386 {
387 unsigned long i;
388 mon_t *m;
389 gmonhdr_t *p;
390
391 moncontrol(0);
392 if(mon == NULL)
393 return;
394 for(i = 0; i < nmon; i++){
395 m = mon + i;
396 if(m->sbuf != NULL){
397 memset(m->sbuf, '\0', m->ssiz);
398 p = (gmonhdr_t *)m->sbuf;
399 p->lpc = (uintptr_t)m->lowpc;
400 p->hpc = (uintptr_t)m->highpc;
401 p->ncnt = m->ssiz;
402 p->version = GMONVERSION;
403 p->profrate = getprofhz();
404 }
405 if(m->froms != NULL)
406 memset(m->froms, '\0', m->textsize / HASHFRACTION);
407 if(m->tos != NULL)
408 memset(m->tos, '\0', m->tolimit * sizeof(tostruct_t));
409 }
410 order = 0;
411 moncontrol(1);
412 }
413
414 void
415 monoutput(
416 const char *filename)
417 {
418 int fd;
419 unsigned long i, fromindex, endfrom, toindex;
420 uint32_t magic;
421 gmon_data_t sample_data, arc_data, dyld_data;
422 char *frompc;
423 rawarc_order_t rawarc_order;
424 mon_t *m;
425 uint32_t image_count;
426 intptr_t image_header;
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 #ifndef __LP64__
440 magic = GMON_MAGIC;
441 #else
442 magic = GMON_MAGIC_64;
443 #endif
444 write(fd, &magic, sizeof(uint32_t));
445
446 #if defined(__DYNAMIC__)
447 {
448 image_count = _dyld_image_count();
449 if(image_count > 1){
450 #ifdef DYLD_DEBUG
451 printf("image_count = %lu\n", image_count - 1);
452 for(i = 1; i < image_count; i++){
453 image_header = _dyld_get_image_header(i);
454 printf("\timage_header %p\n", image_header);
455 image_name = _dyld_get_image_name(i);
456 printf("\timage_name %s\n", image_name);
457 }
458 #endif
459 /*
460 * Calculate the dyld_data.size.
461 */
462 dyld_data.type = GMONTYPE_DYLD2_STATE;
463 dyld_data.size = sizeof(uint32_t) +
464 sizeof(intptr_t) * (image_count - 1);
465 for(i = 1; i < image_count; i++){
466 image_name = _dyld_get_image_name(i);
467 dyld_data.size += strlen(image_name) + 1;
468 }
469
470 /*
471 * Write the dyld_data.
472 */
473 write(fd, &dyld_data, sizeof(gmon_data_t));
474 image_count--;
475 write(fd, &image_count, sizeof(uint32_t));
476 image_count++;
477 for(i = 1; i < image_count; i++){
478 image_header = (intptr_t)_dyld_get_image_header(i);
479 write(fd, &image_header, sizeof(intptr_t));
480 image_name = _dyld_get_image_name(i);
481 write(fd, image_name, strlen(image_name) + 1);
482 }
483 }
484 }
485 #endif
486 for(i = 0; i < nmon; i++){
487 m = mon + i;
488 #ifdef DEBUG
489 fprintf(stderr, "[monoutput] sbuf %p ssiz %d\n", m->sbuf, m->ssiz);
490 #endif
491 sample_data.type = GMONTYPE_SAMPLES;
492 sample_data.size = m->ssiz;
493 write(fd, &sample_data, sizeof(gmon_data_t));
494 /*
495 * Write the gmonhdr_t and the pc-sample buffer. Note the
496 * gmonhdr_t is in sbuf at the beginning of sbuf already
497 * filled in.
498 */
499 write(fd, m->sbuf, m->ssiz);
500
501 /*
502 * Now write out the raw arcs.
503 */
504 endfrom = m->textsize / (HASHFRACTION * sizeof(*m->froms));
505 arc_data.type = GMONTYPE_ARCS_ORDERS;
506 arc_data.size = 0;
507 #ifdef DEBUG
508 fprintf(stderr, "[monoutput] raw arcs, total %lu\n", endfrom);
509 #endif
510 for(fromindex = 0; fromindex < endfrom; fromindex++){
511 if(m->froms[fromindex] == 0){
512 continue;
513 }
514 #ifdef DEBUG
515 fprintf(stderr, "[monoutput] raw arc count at index[%lu] %u\n",
516 fromindex, m->froms[fromindex]);
517 #endif
518 frompc = m->lowpc +
519 (fromindex * HASHFRACTION * sizeof(*m->froms));
520 for(toindex = m->froms[fromindex];
521 toindex != 0;
522 toindex = m->tos[toindex].link){
523 arc_data.size += sizeof(rawarc_order_t);
524 }
525 }
526 write(fd, &arc_data, sizeof(gmon_data_t));
527
528 for(fromindex = 0; fromindex < endfrom; fromindex++){
529 if(m->froms[fromindex] == 0){
530 continue;
531 }
532 frompc = m->lowpc +
533 (fromindex * HASHFRACTION * sizeof(*m->froms));
534 for(toindex = m->froms[fromindex];
535 toindex != 0;
536 toindex = m->tos[toindex].link){
537 #ifdef DEBUG
538 fprintf(stderr, "[monoutput] frompc %p selfpc %p "
539 "count %ld order %lu\n", frompc,
540 m->tos[toindex].selfpc,
541 m->tos[toindex].count, m->tos[toindex].order);
542 #endif
543 rawarc_order.raw_frompc = (uintptr_t)frompc;
544 rawarc_order.raw_selfpc = (uintptr_t)
545 m->tos[toindex].selfpc;
546 rawarc_order.raw_count = m->tos[toindex].count;
547 rawarc_order.raw_order = m->tos[toindex].order;
548 write(fd, &rawarc_order, sizeof(rawarc_order_t));
549 }
550 }
551 }
552 close(fd);
553 }
554
555 void
556 monitor(
557 char *lowpc,
558 char *highpc,
559 char *buf,
560 int bufsiz,
561 int nfunc) /* nfunc is not used; available for compatability only. */
562 {
563 intptr_t o;
564 gmonhdr_t *p;
565 mon_t *m;
566
567 moncontrol(0);
568 m = mon;
569 if(m == NULL)
570 return;
571 if(lowpc == 0){
572 moncontrol(0);
573 monoutput("gmon.out");
574 return;
575 }
576 m->sbuf = buf;
577 m->ssiz = bufsiz;
578 p = (gmonhdr_t *)buf;
579 memset(p, '\0', sizeof(gmonhdr_t));
580 p->lpc = (uintptr_t)lowpc;
581 p->hpc = (uintptr_t)highpc;
582 p->ncnt = m->ssiz;
583 p->version = GMONVERSION;
584 p->profrate = getprofhz();
585 bufsiz -= sizeof(gmonhdr_t);
586 if(bufsiz <= 0)
587 return;
588 o = highpc - lowpc;
589 if(bufsiz < o)
590 m->scale = ((float) bufsiz / o) * SCALE_1_TO_1;
591 else
592 m->scale = SCALE_1_TO_1;
593 moncontrol(1);
594 }
595
596 /*
597 * Control profiling
598 * profiling is what mcount checks to see if
599 * all the data structures are ready.
600 */
601 void
602 moncontrol(
603 int mode)
604 {
605 mon_t *m;
606 unsigned long i;
607
608 if(mode){
609 /* start */
610 m = mon;
611 if(m != NULL){
612 profil(m->sbuf + sizeof(gmonhdr_t),
613 m->ssiz - sizeof(gmonhdr_t),
614 (u_long)m->lowpc, m->scale);
615 for(i = 1; i < nmon; i++)
616 add_profil(mon[i].sbuf + sizeof(gmonhdr_t),
617 mon[i].ssiz - sizeof(gmonhdr_t),
618 (u_long)mon[i].lowpc, mon[i].scale);
619 profiling = 0;
620 }
621 }
622 else{
623 /* stop */
624 profil((char *)0, 0, 0, 0);
625 profiling = -1;
626 }
627 }
628
629 void
630 moncount(
631 char *frompc,
632 char *selfpc)
633 {
634 unsigned short *frompcindex;
635 tostruct_t *top, *prevtop;
636 unsigned long i, toindex;
637 mon_t *m;
638
639 m = mon;
640 if(m == NULL)
641 return;
642 /*
643 * Check that we are profiling and that we aren't recursively invoked.
644 * This should really be a test and set instruction in changing the
645 * value of profiling.
646 */
647 if(profiling)
648 return;
649 profiling++;
650
651
652 #ifdef DEBUG
653 fprintf(stderr, "[moncount] frompc %p selfpc %p\n", frompc, selfpc);
654 #endif
655 frompcindex = (unsigned short *)frompc;
656
657 /*
658 * check that frompcindex is a reasonable pc value.
659 * for example: signal catchers get called from the stack,
660 * not from text space. too bad.
661 */
662 for(i = 0; i < nmon; i++){
663 m = mon + i;
664 if((uintptr_t)frompcindex >= (uintptr_t)m->lowpc &&
665 (uintptr_t)frompcindex < (uintptr_t)m->highpc)
666 break;
667 }
668 if(i == nmon){
669 goto done;
670 }
671 else{
672 frompcindex = (unsigned short *)
673 ((uintptr_t)frompcindex - (uintptr_t)m->lowpc);
674 }
675 frompcindex =
676 &m->froms[((long)frompcindex) / (HASHFRACTION * sizeof(*m->froms))];
677 toindex = *frompcindex;
678 if(toindex == 0){
679 /*
680 * first time traversing this arc
681 */
682 toindex = ++m->tos[0].link;
683 if(toindex >= m->tolimit){
684 goto overflow;
685 }
686 *frompcindex = toindex;
687 top = &m->tos[toindex];
688 top->selfpc = (uintptr_t)selfpc;
689 top->count = 1;
690 top->link = 0;
691 top->order = ++order;
692 goto done;
693 }
694 top = &m->tos[toindex];
695 if(top->selfpc == (uintptr_t)selfpc){
696 /*
697 * arc at front of chain; usual case.
698 */
699 top->count++;
700 goto done;
701 }
702 /*
703 * have to go looking down chain for it.
704 * top points to what we are looking at,
705 * prevtop points to previous top.
706 * we know it is not at the head of the chain.
707 */
708 for(; /* goto done */; ){
709 if(top->link == 0){
710 /*
711 * top is end of the chain and none of the chain
712 * had top->selfpc == selfpc.
713 * so we allocate a new tostruct_t
714 * and link it to the head of the chain.
715 */
716 toindex = ++m->tos[0].link;
717 if(toindex >= m->tolimit){
718 goto overflow;
719 }
720 top = &m->tos[toindex];
721 top->selfpc = (uintptr_t)selfpc;
722 top->count = 1;
723 top->link = *frompcindex;
724 top->order = ++order;
725 *frompcindex = toindex;
726 goto done;
727 }
728 /*
729 * otherwise, check the next arc on the chain.
730 */
731 prevtop = top;
732 top = &m->tos[top->link];
733 if(top->selfpc == (uintptr_t)selfpc){
734 /*
735 * there it is.
736 * increment its count
737 * move it to the head of the chain.
738 */
739 top->count++;
740 toindex = prevtop->link;
741 prevtop->link = top->link;
742 top->link = *frompcindex;
743 *frompcindex = toindex;
744 goto done;
745 }
746 }
747 done:
748 profiling--;
749 return;
750
751 overflow:
752 profiling++; /* halt further profiling */
753 #define TOLIMIT "mcount: tos overflow\n"
754 write(2, TOLIMIT, sizeof(TOLIMIT) - 1);
755 }
756
757 /*
758 * Get the profiling rate.
759 */
760 static
761 long
762 getprofhz(void)
763 {
764 int mib[2];
765 size_t size;
766 struct clockinfo clockrate;
767
768 mib[0] = CTL_KERN;
769 mib[1] = KERN_CLOCKRATE;
770 clockrate.profhz = 1;
771 size = sizeof(clockrate);
772 if(sysctl(mib, 2, &clockrate, &size, NULL, 0) < 0)
773 ;
774 return(clockrate.profhz);
775 }