]> git.saurik.com Git - apple/libc.git/blame - gmon/gmon.c
Libc-391.2.9.tar.gz
[apple/libc.git] / gmon / gmon.c
CommitLineData
e9ce8d39
A
1/*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
734aad71
A
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
e9ce8d39
A
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
734aad71
A
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.
e9ce8d39
A
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)
82static 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>
106extern const struct section *getsectbyname(
107 const char *segname,
108 const char *sectname);
109#include <monitor.h>
110#include <sys/types.h>
111#include <sys/gmon.h>
112#include <sys/param.h>
113#include <sys/sysctl.h>
114#include <mach/mach.h>
115#include <mach-o/loader.h>
116#include <mach-o/dyld.h>
117
118/*
119 * These are defined in here and these declarations need to be moved to libc.h
120 * where the other declarations for the monitor(3) routines are declared.
121 */
122extern void moninit(
123 void);
124extern void monaddition(
125 char *lowpc,
126 char *highpc);
127extern void moncount(
128 char *frompc,
129 char *selfpc);
130extern void monreset(
131 void);
132extern void monoutput(
133 const char *filename);
e9ce8d39
A
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)
59e0d9fe
A
366/* POSSIBLE BUG, if "(float) (monsize - sizeof(struct gmonhdr))/ o)" is zero
367 * then m->scale will be set to zero and the add_profil() call will disable
368 * profiling */
e9ce8d39
A
369 m->scale = ((float) (monsize - sizeof(struct gmonhdr))/ o) *
370 SCALE_1_TO_1;
371 else
372 m->scale = SCALE_1_TO_1;
373
374 /* moncontrol(mode == 1) functionality */
375 if(!init)
376 add_profil(m->sbuf + sizeof(struct gmonhdr),
377 m->ssiz - sizeof(struct gmonhdr),
378 (int)m->lowpc, m->scale);
379 }
380}
381
382void
383monreset(
384void)
385{
386 unsigned long i;
387 struct mon_t *m;
388 struct gmonhdr *p;
389
390 moncontrol(0);
391 if(mon == NULL)
392 return;
393 for(i = 0; i < nmon; i++){
394 m = mon + i;
395 if(m->sbuf != NULL){
396 memset(m->sbuf, '\0', m->ssiz);
397 p = (struct gmonhdr *)m->sbuf;
398 p->lpc = (unsigned long)m->lowpc;
399 p->hpc = (unsigned long)m->highpc;
400 p->ncnt = m->ssiz;
59e0d9fe
A
401 p->version = GMONVERSION;
402 p->profrate = getprofhz();
e9ce8d39
A
403 }
404 if(m->froms != NULL)
405 memset(m->froms, '\0', m->textsize / HASHFRACTION);
406 if(m->tos != NULL)
407 memset(m->tos, '\0', m->tolimit * sizeof (struct tostruct));
408 }
409 order = 0;
410 moncontrol(1);
411}
412
413void
414monoutput(
415const char *filename)
416{
417 int fd;
418 unsigned long magic, i, fromindex, endfrom, toindex;
419 struct gmon_data sample_data, arc_data, dyld_data;
420 char *frompc;
421 struct rawarc_order rawarc_order;
422 struct mon_t *m;
423 unsigned long image_count, vmaddr_slide;
424 char *image_name;
425
426 moncontrol(0);
427 m = mon;
428 if(m == NULL)
429 return;
430 fd = creat(filename, 0666);
431 if(fd < 0){
432 perror("mcount: gmon.out");
433 return;
434 }
435
436 magic = GMON_MAGIC;
437 write(fd, &magic, sizeof(unsigned long));
438
439#if defined(__DYNAMIC__)
440 if(_dyld_present()){
441 image_count = _dyld_image_count();
442 if(image_count > 1){
443#ifdef DYLD_DEBUG
444 printf("image_count = %lu\n", image_count - 1);
445 for(i = 1; i < image_count; i++){
446 vmaddr_slide = _dyld_get_image_vmaddr_slide(i);
447 printf("\tvmaddr_slide 0x%x\n", (unsigned int)vmaddr_slide);
448 image_name = _dyld_get_image_name(i);
449 printf("\timage_name %s\n", image_name);
450 }
451#endif
452 /*
453 * Calculate the dyld_data.size.
454 */
455 dyld_data.type = GMONTYPE_DYLD_STATE;
456 dyld_data.size = sizeof(unsigned long) +
457 sizeof(unsigned long) * (image_count - 1);
458 for(i = 1; i < image_count; i++){
459 image_name = _dyld_get_image_name(i);
460 dyld_data.size += strlen(image_name) + 1;
461 }
462
463 /*
464 * Write the dyld_data.
465 */
466 write(fd, &dyld_data, sizeof(struct gmon_data));
467 image_count--;
468 write(fd, &image_count, sizeof(unsigned long));
469 image_count++;
470 for(i = 1; i < image_count; i++){
471 vmaddr_slide = _dyld_get_image_vmaddr_slide(i);
472 write(fd, &vmaddr_slide, sizeof(unsigned long));
473 image_name = _dyld_get_image_name(i);
474 write(fd, image_name, strlen(image_name) + 1);
475 }
476 }
477 }
478#endif
479 for(i = 0; i < nmon; i++){
480 m = mon + i;
481#ifdef DEBUG
482 fprintf(stderr, "[monoutput] sbuf 0x%x ssiz %d\n",
483 m->sbuf, m->ssiz);
484#endif
485 sample_data.type = GMONTYPE_SAMPLES;
486 sample_data.size = m->ssiz;
487 write(fd, &sample_data, sizeof(struct gmon_data));
488 /*
489 * Write the gmonhdr struct and the pc-sample buffer. Note the
490 * gmonhdr struct is in sbuf at the beginning of sbuf already
491 * filled in.
492 */
493 write(fd, m->sbuf, m->ssiz);
494
495 /*
496 * Now write out the raw arcs.
497 */
498 endfrom = m->textsize / (HASHFRACTION * sizeof(*m->froms));
499 arc_data.type = GMONTYPE_ARCS_ORDERS;
500 arc_data.size = 0;
501 for(fromindex = 0; fromindex < endfrom; fromindex++){
502 if(m->froms[fromindex] == 0){
503 continue;
504 }
505 frompc = m->lowpc +
506 (fromindex * HASHFRACTION * sizeof(*m->froms));
507 for(toindex = m->froms[fromindex];
508 toindex != 0;
509 toindex = m->tos[toindex].link){
510 arc_data.size += sizeof(struct rawarc_order);
511 }
512 }
513 write(fd, &arc_data, sizeof(struct gmon_data));
514
515 for(fromindex = 0; fromindex < endfrom; fromindex++){
516 if(m->froms[fromindex] == 0){
517 continue;
518 }
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#ifdef DEBUG
525 fprintf(stderr, "[monoutput] frompc 0x%x selfpc 0x%x "
526 "count %ld order %lu\n", (unsigned int)frompc,
527 (unsigned int)m->tos[toindex].selfpc,
528 m->tos[toindex].count, m->tos[toindex].order);
529#endif
530 rawarc_order.raw_frompc = (unsigned long)frompc;
531 rawarc_order.raw_selfpc = (unsigned long)
532 m->tos[toindex].selfpc;
533 rawarc_order.raw_count = m->tos[toindex].count;
534 rawarc_order.raw_order = m->tos[toindex].order;
535 write(fd, &rawarc_order, sizeof(struct rawarc_order));
536 }
537 }
538 }
539 close(fd);
540}
541
542void
543monitor(
544char *lowpc,
545char *highpc,
546char *buf,
547int bufsiz,
548int nfunc) /* nfunc is not used; available for compatability only. */
549{
550 unsigned int o;
551 struct gmonhdr *p;
552 struct mon_t *m;
553
554 moncontrol(0);
555 m = mon;
556 if(m == NULL)
557 return;
558 if(lowpc == 0){
559 moncontrol(0);
560 monoutput("gmon.out");
561 return;
562 }
563 m->sbuf = buf;
564 m->ssiz = bufsiz;
565 p = (struct gmonhdr *)buf;
566 memset(p, '\0', sizeof(struct gmonhdr));
567 p->lpc = (unsigned long)lowpc;
568 p->hpc = (unsigned long)highpc;
569 p->ncnt = m->ssiz;
570 p->version = GMONVERSION;
571 p->profrate = getprofhz();
572 bufsiz -= sizeof(struct gmonhdr);
573 if(bufsiz <= 0)
574 return;
575 o = highpc - lowpc;
576 if(bufsiz < o)
577 m->scale = ((float) bufsiz / o) * SCALE_1_TO_1;
578 else
579 m->scale = SCALE_1_TO_1;
580 moncontrol(1);
581}
582
583/*
584 * Control profiling
585 * profiling is what mcount checks to see if
586 * all the data structures are ready.
587 */
588void
589moncontrol(
590int mode)
591{
592 struct mon_t *m;
593 unsigned long i;
594
595 if(mode){
596 /* start */
597 m = mon;
598 if(m != NULL){
599 profil(m->sbuf + sizeof(struct gmonhdr),
600 m->ssiz - sizeof(struct gmonhdr),
601 (int)m->lowpc, m->scale);
602 for(i = 1; i < nmon; i++)
603 add_profil(mon[i].sbuf + sizeof(struct gmonhdr),
604 mon[i].ssiz - sizeof(struct gmonhdr),
605 (int)mon[i].lowpc, mon[i].scale);
606 profiling = 0;
607 }
608 }
609 else{
610 /* stop */
611 profil((char *)0, 0, 0, 0);
612 profiling = -1;
613 }
614}
615
616void
617moncount(
618char *frompc,
619char *selfpc)
620{
621 unsigned short *frompcindex;
622 struct tostruct *top, *prevtop;
623 unsigned long i, toindex;
624 struct mon_t *m;
625
626 m = mon;
627 if(m == NULL)
628 return;
629 /*
630 * Check that we are profiling and that we aren't recursively invoked.
631 * This should really be a test and set instruction in changing the
632 * value of profiling.
633 */
634 if(profiling)
635 return;
636 profiling++;
637
638
639#ifdef DEBUG
640 fprintf(stderr, "[moncount] frompc 0x%x selfpc 0x%x\n",
641 (unsigned int)frompc, (unsigned int)selfpc);
642#endif
643 frompcindex = (unsigned short *)frompc;
644
645 /*
646 * check that frompcindex is a reasonable pc value.
647 * for example: signal catchers get called from the stack,
648 * not from text space. too bad.
649 */
650 for(i = 0; i < nmon; i++){
651 m = mon + i;
652 if((unsigned long)frompcindex >= (unsigned long)m->lowpc &&
653 (unsigned long)frompcindex < (unsigned long)m->highpc)
654 break;
655 }
656 if(i == nmon){
657 goto done;
658 }
659 else{
660 frompcindex = (unsigned short *)
661 ((unsigned long)frompcindex - (unsigned long)m->lowpc);
662 }
663 frompcindex =
664 &m->froms[((long)frompcindex) / (HASHFRACTION * sizeof(*m->froms))];
665 toindex = *frompcindex;
666 if(toindex == 0){
667 /*
668 * first time traversing this arc
669 */
670 toindex = ++m->tos[0].link;
671 if(toindex >= m->tolimit){
672 goto overflow;
673 }
674 *frompcindex = toindex;
675 top = &m->tos[toindex];
676 top->selfpc = (unsigned long)selfpc;
677 top->count = 1;
678 top->link = 0;
679 top->order = ++order;
680 goto done;
681 }
682 top = &m->tos[toindex];
683 if(top->selfpc == (unsigned long)selfpc){
684 /*
685 * arc at front of chain; usual case.
686 */
687 top->count++;
688 goto done;
689 }
690 /*
691 * have to go looking down chain for it.
692 * top points to what we are looking at,
693 * prevtop points to previous top.
694 * we know it is not at the head of the chain.
695 */
696 for(; /* goto done */; ){
697 if(top->link == 0){
698 /*
699 * top is end of the chain and none of the chain
700 * had top->selfpc == selfpc.
701 * so we allocate a new tostruct
702 * and link it to the head of the chain.
703 */
704 toindex = ++m->tos[0].link;
705 if(toindex >= m->tolimit){
706 goto overflow;
707 }
708 top = &m->tos[toindex];
709 top->selfpc = (unsigned long)selfpc;
710 top->count = 1;
711 top->link = *frompcindex;
712 top->order = ++order;
713 *frompcindex = toindex;
714 goto done;
715 }
716 /*
717 * otherwise, check the next arc on the chain.
718 */
719 prevtop = top;
720 top = &m->tos[top->link];
721 if(top->selfpc == (unsigned long)selfpc){
722 /*
723 * there it is.
724 * increment its count
725 * move it to the head of the chain.
726 */
727 top->count++;
728 toindex = prevtop->link;
729 prevtop->link = top->link;
730 top->link = *frompcindex;
731 *frompcindex = toindex;
732 goto done;
733 }
734 }
735done:
736 profiling--;
737 return;
738
739overflow:
740 profiling++; /* halt further profiling */
741#define TOLIMIT "mcount: tos overflow\n"
742 write(2, TOLIMIT, sizeof(TOLIMIT) - 1);
743}
744
745/*
746 * Get the profiling rate.
747 */
748static
749int
750getprofhz(void)
751{
752 int mib[2];
753 size_t size;
754 struct clockinfo clockrate;
755
756 mib[0] = CTL_KERN;
757 mib[1] = KERN_CLOCKRATE;
758 clockrate.profhz = 1;
759 size = sizeof(clockrate);
760 if(sysctl(mib, 2, &clockrate, &size, NULL, 0) < 0)
761 ;
762 return(clockrate.profhz);
763}