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