]> git.saurik.com Git - apple/libc.git/blob - gmon/gmon.c
a085e0942aa34cc942bb57b7f158c2627a9b0206
[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 extern 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 */
122 extern void moninit(
123 void);
124 extern void monaddition(
125 char *lowpc,
126 char *highpc);
127 extern void moncount(
128 char *frompc,
129 char *selfpc);
130 extern void monreset(
131 void);
132 extern void monoutput(
133 const char *filename);
134 extern int add_profil(char *, int, int, int);
135
136 static char profiling = -1; /* tas (test and set) location for NeXT */
137 static char init = 0; /* set while moninit() is being serviced */
138
139 static unsigned long order = 0; /* call order */
140
141 struct mon_t {
142 /* the address range and size this mon struct refers to */
143 char *lowpc;
144 char *highpc;
145 unsigned long textsize;
146 /* the data structures to support the arc's and their counts */
147 unsigned short *froms; /* froms is unsigned shorts indexing into tos */
148 struct tostruct *tos;
149 long tolimit;
150 /* the pc-sample buffer, it's size and scale */
151 char *sbuf;
152 int ssiz; /* includes the gmonhdr struct */
153 int scale;
154 };
155 static struct mon_t *mon = NULL;
156 static unsigned long nmon = 0;
157
158 static void monsetup(
159 struct mon_t *m,
160 char *lowpc,
161 char *highpc);
162 static int getprofhz(
163 void);
164
165 void
166 moninit(
167 void)
168 {
169 const struct section *section;
170 char *lowpc, *highpc;
171 unsigned long i;
172
173 monreset();
174 init = 1;
175
176 section = getsectbyname ("__TEXT", "__text");
177 lowpc = (char *)section->addr,
178 highpc = (char *)(section->addr + section->size);
179
180 if(mon == NULL){
181 if((mon = malloc(sizeof(struct mon_t))) == NULL){
182 write(2, MSG, sizeof(MSG) - 1);
183 return;
184 }
185 nmon = 1;
186 memset(mon, '\0', sizeof(struct mon_t));
187 }
188 /*
189 * To continue to make monstartup() and the functions that existed
190 * before adding multiple profiling areas working correctly the new
191 * calls to get the dyld loaded code profiled are made after
192 * the first mon_t struct is allocated so that they will not use the
193 * first mon_t and the old calls will always use the first mon_t struct
194 * in the list.
195 */
196 monsetup(mon, lowpc, highpc);
197
198 profil(mon->sbuf + sizeof(struct gmonhdr),
199 mon->ssiz - sizeof(struct gmonhdr),
200 (int)mon->lowpc, mon->scale);
201 for(i = 1; i < nmon; i++)
202 add_profil(mon[i].sbuf + sizeof(struct gmonhdr),
203 mon[i].ssiz - sizeof(struct gmonhdr),
204 (int)mon[i].lowpc, mon[i].scale);
205 init = 0;
206 profiling = 0;
207
208 #if defined(__DYNAMIC__)
209 /*
210 * Call _dyld_moninit() if the dyld is present. This is done after the
211 * above calls so the dynamic libraries will be added after the
212 * executable.
213 */
214 if(_dyld_present())
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(struct mon_t))) == NULL){
227 write(2, MSG, sizeof(MSG) - 1);
228 return;
229 }
230 nmon = 1;
231 memset(mon, '\0', sizeof(struct 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 struct 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(struct mon_t))) == NULL){
255 write(2, MSG, sizeof(MSG) - 1);
256 return;
257 }
258 m = mon + nmon;
259 memset(m, '\0', sizeof(struct mon_t));
260 nmon++;
261 monsetup(m, lowpc, highpc);
262 profiling = save_profiling;
263 }
264
265 static
266 void
267 monsetup(
268 struct mon_t *m,
269 char *lowpc,
270 char *highpc)
271 {
272 int monsize;
273 char *buffer;
274 kern_return_t ret;
275 struct gmonhdr *p;
276 unsigned int 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 ints.
281 */
282 lowpc = (char *)ROUNDDOWN((unsigned)lowpc,
283 HISTFRACTION * sizeof(HISTCOUNTER));
284 m->lowpc = lowpc;
285 highpc = (char *)ROUNDUP((unsigned)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(struct gmonhdr);
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(struct tostruct)));
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(struct tostruct)),
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 = (struct gmonhdr *)m->sbuf;
359 memset(p, '\0', sizeof(struct gmonhdr));
360 p->lpc = (unsigned long)m->lowpc;
361 p->hpc = (unsigned long)m->highpc;
362 p->ncnt = m->ssiz;
363 p->version = GMONVERSION;
364 p->profrate = getprofhz();
365 o = highpc - lowpc;
366 if((monsize - sizeof(struct gmonhdr)) < o)
367 m->scale = ((float) (monsize - sizeof(struct gmonhdr))/ o) *
368 SCALE_1_TO_1;
369 else
370 m->scale = SCALE_1_TO_1;
371
372 /* moncontrol(mode == 1) functionality */
373 if(!init)
374 add_profil(m->sbuf + sizeof(struct gmonhdr),
375 m->ssiz - sizeof(struct gmonhdr),
376 (int)m->lowpc, m->scale);
377 }
378 }
379
380 void
381 monreset(
382 void)
383 {
384 unsigned long i;
385 struct mon_t *m;
386 struct gmonhdr *p;
387
388 moncontrol(0);
389 if(mon == NULL)
390 return;
391 for(i = 0; i < nmon; i++){
392 m = mon + i;
393 if(m->sbuf != NULL){
394 memset(m->sbuf, '\0', m->ssiz);
395 p = (struct gmonhdr *)m->sbuf;
396 p->lpc = (unsigned long)m->lowpc;
397 p->hpc = (unsigned long)m->highpc;
398 p->ncnt = m->ssiz;
399 }
400 if(m->froms != NULL)
401 memset(m->froms, '\0', m->textsize / HASHFRACTION);
402 if(m->tos != NULL)
403 memset(m->tos, '\0', m->tolimit * sizeof (struct tostruct));
404 }
405 order = 0;
406 moncontrol(1);
407 }
408
409 void
410 monoutput(
411 const char *filename)
412 {
413 int fd;
414 unsigned long magic, i, fromindex, endfrom, toindex;
415 struct gmon_data sample_data, arc_data, dyld_data;
416 char *frompc;
417 struct rawarc_order rawarc_order;
418 struct mon_t *m;
419 unsigned long image_count, vmaddr_slide;
420 char *image_name;
421
422 moncontrol(0);
423 m = mon;
424 if(m == NULL)
425 return;
426 fd = creat(filename, 0666);
427 if(fd < 0){
428 perror("mcount: gmon.out");
429 return;
430 }
431
432 magic = GMON_MAGIC;
433 write(fd, &magic, sizeof(unsigned long));
434
435 #if defined(__DYNAMIC__)
436 if(_dyld_present()){
437 image_count = _dyld_image_count();
438 if(image_count > 1){
439 #ifdef DYLD_DEBUG
440 printf("image_count = %lu\n", image_count - 1);
441 for(i = 1; i < image_count; i++){
442 vmaddr_slide = _dyld_get_image_vmaddr_slide(i);
443 printf("\tvmaddr_slide 0x%x\n", (unsigned int)vmaddr_slide);
444 image_name = _dyld_get_image_name(i);
445 printf("\timage_name %s\n", image_name);
446 }
447 #endif
448 /*
449 * Calculate the dyld_data.size.
450 */
451 dyld_data.type = GMONTYPE_DYLD_STATE;
452 dyld_data.size = sizeof(unsigned long) +
453 sizeof(unsigned long) * (image_count - 1);
454 for(i = 1; i < image_count; i++){
455 image_name = _dyld_get_image_name(i);
456 dyld_data.size += strlen(image_name) + 1;
457 }
458
459 /*
460 * Write the dyld_data.
461 */
462 write(fd, &dyld_data, sizeof(struct gmon_data));
463 image_count--;
464 write(fd, &image_count, sizeof(unsigned long));
465 image_count++;
466 for(i = 1; i < image_count; i++){
467 vmaddr_slide = _dyld_get_image_vmaddr_slide(i);
468 write(fd, &vmaddr_slide, sizeof(unsigned long));
469 image_name = _dyld_get_image_name(i);
470 write(fd, image_name, strlen(image_name) + 1);
471 }
472 }
473 }
474 #endif
475 for(i = 0; i < nmon; i++){
476 m = mon + i;
477 #ifdef DEBUG
478 fprintf(stderr, "[monoutput] sbuf 0x%x ssiz %d\n",
479 m->sbuf, m->ssiz);
480 #endif
481 sample_data.type = GMONTYPE_SAMPLES;
482 sample_data.size = m->ssiz;
483 write(fd, &sample_data, sizeof(struct gmon_data));
484 /*
485 * Write the gmonhdr struct and the pc-sample buffer. Note the
486 * gmonhdr struct is in sbuf at the beginning of sbuf already
487 * filled in.
488 */
489 write(fd, m->sbuf, m->ssiz);
490
491 /*
492 * Now write out the raw arcs.
493 */
494 endfrom = m->textsize / (HASHFRACTION * sizeof(*m->froms));
495 arc_data.type = GMONTYPE_ARCS_ORDERS;
496 arc_data.size = 0;
497 for(fromindex = 0; fromindex < endfrom; fromindex++){
498 if(m->froms[fromindex] == 0){
499 continue;
500 }
501 frompc = m->lowpc +
502 (fromindex * HASHFRACTION * sizeof(*m->froms));
503 for(toindex = m->froms[fromindex];
504 toindex != 0;
505 toindex = m->tos[toindex].link){
506 arc_data.size += sizeof(struct rawarc_order);
507 }
508 }
509 write(fd, &arc_data, sizeof(struct gmon_data));
510
511 for(fromindex = 0; fromindex < endfrom; fromindex++){
512 if(m->froms[fromindex] == 0){
513 continue;
514 }
515 frompc = m->lowpc +
516 (fromindex * HASHFRACTION * sizeof(*m->froms));
517 for(toindex = m->froms[fromindex];
518 toindex != 0;
519 toindex = m->tos[toindex].link){
520 #ifdef DEBUG
521 fprintf(stderr, "[monoutput] frompc 0x%x selfpc 0x%x "
522 "count %ld order %lu\n", (unsigned int)frompc,
523 (unsigned int)m->tos[toindex].selfpc,
524 m->tos[toindex].count, m->tos[toindex].order);
525 #endif
526 rawarc_order.raw_frompc = (unsigned long)frompc;
527 rawarc_order.raw_selfpc = (unsigned long)
528 m->tos[toindex].selfpc;
529 rawarc_order.raw_count = m->tos[toindex].count;
530 rawarc_order.raw_order = m->tos[toindex].order;
531 write(fd, &rawarc_order, sizeof(struct rawarc_order));
532 }
533 }
534 }
535 close(fd);
536 }
537
538 void
539 monitor(
540 char *lowpc,
541 char *highpc,
542 char *buf,
543 int bufsiz,
544 int nfunc) /* nfunc is not used; available for compatability only. */
545 {
546 unsigned int o;
547 struct gmonhdr *p;
548 struct mon_t *m;
549
550 moncontrol(0);
551 m = mon;
552 if(m == NULL)
553 return;
554 if(lowpc == 0){
555 moncontrol(0);
556 monoutput("gmon.out");
557 return;
558 }
559 m->sbuf = buf;
560 m->ssiz = bufsiz;
561 p = (struct gmonhdr *)buf;
562 memset(p, '\0', sizeof(struct gmonhdr));
563 p->lpc = (unsigned long)lowpc;
564 p->hpc = (unsigned long)highpc;
565 p->ncnt = m->ssiz;
566 p->version = GMONVERSION;
567 p->profrate = getprofhz();
568 bufsiz -= sizeof(struct gmonhdr);
569 if(bufsiz <= 0)
570 return;
571 o = highpc - lowpc;
572 if(bufsiz < o)
573 m->scale = ((float) bufsiz / o) * SCALE_1_TO_1;
574 else
575 m->scale = SCALE_1_TO_1;
576 moncontrol(1);
577 }
578
579 /*
580 * Control profiling
581 * profiling is what mcount checks to see if
582 * all the data structures are ready.
583 */
584 void
585 moncontrol(
586 int mode)
587 {
588 struct mon_t *m;
589 unsigned long i;
590
591 if(mode){
592 /* start */
593 m = mon;
594 if(m != NULL){
595 profil(m->sbuf + sizeof(struct gmonhdr),
596 m->ssiz - sizeof(struct gmonhdr),
597 (int)m->lowpc, m->scale);
598 for(i = 1; i < nmon; i++)
599 add_profil(mon[i].sbuf + sizeof(struct gmonhdr),
600 mon[i].ssiz - sizeof(struct gmonhdr),
601 (int)mon[i].lowpc, mon[i].scale);
602 profiling = 0;
603 }
604 }
605 else{
606 /* stop */
607 profil((char *)0, 0, 0, 0);
608 profiling = -1;
609 }
610 }
611
612 void
613 moncount(
614 char *frompc,
615 char *selfpc)
616 {
617 unsigned short *frompcindex;
618 struct tostruct *top, *prevtop;
619 unsigned long i, toindex;
620 struct mon_t *m;
621
622 m = mon;
623 if(m == NULL)
624 return;
625 /*
626 * Check that we are profiling and that we aren't recursively invoked.
627 * This should really be a test and set instruction in changing the
628 * value of profiling.
629 */
630 if(profiling)
631 return;
632 profiling++;
633
634
635 #ifdef DEBUG
636 fprintf(stderr, "[moncount] frompc 0x%x selfpc 0x%x\n",
637 (unsigned int)frompc, (unsigned int)selfpc);
638 #endif
639 frompcindex = (unsigned short *)frompc;
640
641 /*
642 * check that frompcindex is a reasonable pc value.
643 * for example: signal catchers get called from the stack,
644 * not from text space. too bad.
645 */
646 for(i = 0; i < nmon; i++){
647 m = mon + i;
648 if((unsigned long)frompcindex >= (unsigned long)m->lowpc &&
649 (unsigned long)frompcindex < (unsigned long)m->highpc)
650 break;
651 }
652 if(i == nmon){
653 goto done;
654 }
655 else{
656 frompcindex = (unsigned short *)
657 ((unsigned long)frompcindex - (unsigned long)m->lowpc);
658 }
659 frompcindex =
660 &m->froms[((long)frompcindex) / (HASHFRACTION * sizeof(*m->froms))];
661 toindex = *frompcindex;
662 if(toindex == 0){
663 /*
664 * first time traversing this arc
665 */
666 toindex = ++m->tos[0].link;
667 if(toindex >= m->tolimit){
668 goto overflow;
669 }
670 *frompcindex = toindex;
671 top = &m->tos[toindex];
672 top->selfpc = (unsigned long)selfpc;
673 top->count = 1;
674 top->link = 0;
675 top->order = ++order;
676 goto done;
677 }
678 top = &m->tos[toindex];
679 if(top->selfpc == (unsigned long)selfpc){
680 /*
681 * arc at front of chain; usual case.
682 */
683 top->count++;
684 goto done;
685 }
686 /*
687 * have to go looking down chain for it.
688 * top points to what we are looking at,
689 * prevtop points to previous top.
690 * we know it is not at the head of the chain.
691 */
692 for(; /* goto done */; ){
693 if(top->link == 0){
694 /*
695 * top is end of the chain and none of the chain
696 * had top->selfpc == selfpc.
697 * so we allocate a new tostruct
698 * and link it to the head of the chain.
699 */
700 toindex = ++m->tos[0].link;
701 if(toindex >= m->tolimit){
702 goto overflow;
703 }
704 top = &m->tos[toindex];
705 top->selfpc = (unsigned long)selfpc;
706 top->count = 1;
707 top->link = *frompcindex;
708 top->order = ++order;
709 *frompcindex = toindex;
710 goto done;
711 }
712 /*
713 * otherwise, check the next arc on the chain.
714 */
715 prevtop = top;
716 top = &m->tos[top->link];
717 if(top->selfpc == (unsigned long)selfpc){
718 /*
719 * there it is.
720 * increment its count
721 * move it to the head of the chain.
722 */
723 top->count++;
724 toindex = prevtop->link;
725 prevtop->link = top->link;
726 top->link = *frompcindex;
727 *frompcindex = toindex;
728 goto done;
729 }
730 }
731 done:
732 profiling--;
733 return;
734
735 overflow:
736 profiling++; /* halt further profiling */
737 #define TOLIMIT "mcount: tos overflow\n"
738 write(2, TOLIMIT, sizeof(TOLIMIT) - 1);
739 }
740
741 /*
742 * Get the profiling rate.
743 */
744 static
745 int
746 getprofhz(void)
747 {
748 int mib[2];
749 size_t size;
750 struct clockinfo clockrate;
751
752 mib[0] = CTL_KERN;
753 mib[1] = KERN_CLOCKRATE;
754 clockrate.profhz = 1;
755 size = sizeof(clockrate);
756 if(sysctl(mib, 2, &clockrate, &size, NULL, 0) < 0)
757 ;
758 return(clockrate.profhz);
759 }