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