]> git.saurik.com Git - apple/libc.git/blame - gmon/gmon.c
Libc-594.9.4.tar.gz
[apple/libc.git] / gmon / gmon.c
CommitLineData
e9ce8d39 1/*
34e8f829 2 * Copyright (c) 1999, 2003, 2004, 2007, 2008 Apple Inc. All rights reserved.
e9ce8d39
A
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>
e9ce8d39
A
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>
224c7076 114#include <mach-o/getsect.h>
e9ce8d39
A
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 */
120extern void moninit(
121 void);
122extern void monaddition(
123 char *lowpc,
124 char *highpc);
125extern void moncount(
126 char *frompc,
127 char *selfpc);
128extern void monreset(
129 void);
130extern void monoutput(
131 const char *filename);
e9ce8d39
A
132
133static char profiling = -1; /* tas (test and set) location for NeXT */
134static char init = 0; /* set while moninit() is being serviced */
135
136static unsigned long order = 0; /* call order */
137
224c7076 138typedef struct {
e9ce8d39
A
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 */
224c7076 145 tostruct_t *tos;
e9ce8d39
A
146 long tolimit;
147 /* the pc-sample buffer, it's size and scale */
148 char *sbuf;
224c7076
A
149 long ssiz; /* includes the gmonhdr_t */
150 long scale;
151} mon_t;
152static mon_t *mon = NULL;
e9ce8d39
A
153static unsigned long nmon = 0;
154
155static void monsetup(
224c7076 156 mon_t *m,
e9ce8d39
A
157 char *lowpc,
158 char *highpc);
224c7076 159static long getprofhz(
e9ce8d39
A
160 void);
161
162void
163moninit(
164void)
165{
224c7076 166#ifndef __LP64__
e9ce8d39 167 const struct section *section;
224c7076
A
168#else
169 const struct section_64 *section;
170#endif
e9ce8d39
A
171 char *lowpc, *highpc;
172 unsigned long i;
173
174 monreset();
175 init = 1;
176
224c7076 177 section = getsectbyname("__TEXT", "__text");
e9ce8d39
A
178 lowpc = (char *)section->addr,
179 highpc = (char *)(section->addr + section->size);
180
181 if(mon == NULL){
224c7076 182 if((mon = malloc(sizeof(mon_t))) == NULL){
e9ce8d39
A
183 write(2, MSG, sizeof(MSG) - 1);
184 return;
185 }
186 nmon = 1;
224c7076 187 memset(mon, '\0', sizeof(mon_t));
e9ce8d39
A
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
224c7076
A
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
e9ce8d39
A
195 * in the list.
196 */
197 monsetup(mon, lowpc, highpc);
198
224c7076
A
199 profil(mon->sbuf + sizeof(gmonhdr_t),
200 mon->ssiz - sizeof(gmonhdr_t),
201 (u_long)mon->lowpc, mon->scale);
e9ce8d39 202 for(i = 1; i < nmon; i++)
224c7076
A
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);
e9ce8d39
A
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 */
b5d655f7 215 _dyld_moninit(monaddition);
e9ce8d39
A
216#endif
217}
218
219void
220monstartup(
221char *lowpc,
222char *highpc)
223{
224 monreset();
225 if(mon == NULL){
224c7076 226 if((mon = malloc(sizeof(mon_t))) == NULL){
e9ce8d39
A
227 write(2, MSG, sizeof(MSG) - 1);
228 return;
229 }
230 nmon = 1;
224c7076 231 memset(mon, '\0', sizeof(mon_t));
e9ce8d39
A
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 */
240void
241monaddition(
242char *lowpc,
243char *highpc)
244{
245 char save_profiling;
224c7076 246 mon_t *m;
e9ce8d39
A
247
248 if(mon == NULL){
249 monstartup(lowpc, highpc);
250 return;
251 }
252 save_profiling = profiling;
253 profiling = -1;
224c7076 254 if((mon = realloc(mon, (nmon + 1) * sizeof(mon_t))) == NULL){
e9ce8d39
A
255 write(2, MSG, sizeof(MSG) - 1);
256 return;
257 }
258 m = mon + nmon;
224c7076 259 memset(m, '\0', sizeof(mon_t));
e9ce8d39
A
260 nmon++;
261 monsetup(m, lowpc, highpc);
262 profiling = save_profiling;
263}
264
265static
266void
267monsetup(
224c7076 268mon_t *m,
e9ce8d39
A
269char *lowpc,
270char *highpc)
271{
224c7076 272 long monsize;
e9ce8d39
A
273 char *buffer;
274 kern_return_t ret;
224c7076
A
275 gmonhdr_t *p;
276 uintptr_t o;
e9ce8d39
A
277
278 /*
279 * round lowpc and highpc to multiples of the density we're using
224c7076 280 * so the rest of the scaling (here and in gprof) stays in longs.
e9ce8d39 281 */
224c7076 282 lowpc = (char *)ROUNDDOWN((uintptr_t)lowpc,
e9ce8d39
A
283 HISTFRACTION * sizeof(HISTCOUNTER));
284 m->lowpc = lowpc;
224c7076 285 highpc = (char *)ROUNDUP((uintptr_t)highpc,
e9ce8d39
A
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);
224c7076 308 monsize = (m->textsize / HISTFRACTION) + sizeof(gmonhdr_t);
e9ce8d39
A
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,
224c7076 322 (vm_size_t)(m->tolimit * sizeof(tostruct_t)));
e9ce8d39
A
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,
224c7076 332 (vm_size_t)(m->tolimit * sizeof(tostruct_t)),
e9ce8d39
A
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;
224c7076
A
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;
e9ce8d39
A
362 p->ncnt = m->ssiz;
363 p->version = GMONVERSION;
364 p->profrate = getprofhz();
365 o = highpc - lowpc;
224c7076
A
366 if((monsize - sizeof(gmonhdr_t)) < o)
367/* POSSIBLE BUG, if "(float) (monsize - sizeof(gmonhdr_t))/ o)" is zero
59e0d9fe
A
368 * then m->scale will be set to zero and the add_profil() call will disable
369 * profiling */
224c7076 370 m->scale = ((float) (monsize - sizeof(gmonhdr_t))/ o) *
e9ce8d39
A
371 SCALE_1_TO_1;
372 else
373 m->scale = SCALE_1_TO_1;
374
375 /* moncontrol(mode == 1) functionality */
376 if(!init)
224c7076
A
377 add_profil(m->sbuf + sizeof(gmonhdr_t),
378 m->ssiz - sizeof(gmonhdr_t),
379 (long)m->lowpc, m->scale);
e9ce8d39
A
380 }
381}
382
383void
384monreset(
385void)
386{
387 unsigned long i;
224c7076
A
388 mon_t *m;
389 gmonhdr_t *p;
e9ce8d39
A
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);
224c7076
A
398 p = (gmonhdr_t *)m->sbuf;
399 p->lpc = (uintptr_t)m->lowpc;
400 p->hpc = (uintptr_t)m->highpc;
e9ce8d39 401 p->ncnt = m->ssiz;
59e0d9fe
A
402 p->version = GMONVERSION;
403 p->profrate = getprofhz();
e9ce8d39
A
404 }
405 if(m->froms != NULL)
406 memset(m->froms, '\0', m->textsize / HASHFRACTION);
407 if(m->tos != NULL)
224c7076 408 memset(m->tos, '\0', m->tolimit * sizeof(tostruct_t));
e9ce8d39
A
409 }
410 order = 0;
411 moncontrol(1);
412}
413
414void
415monoutput(
416const char *filename)
417{
418 int fd;
224c7076
A
419 unsigned long i, fromindex, endfrom, toindex;
420 uint32_t magic;
421 gmon_data_t sample_data, arc_data, dyld_data;
e9ce8d39 422 char *frompc;
224c7076
A
423 rawarc_order_t rawarc_order;
424 mon_t *m;
425 uint32_t image_count;
426 intptr_t image_header;
e9ce8d39
A
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
224c7076 439#ifndef __LP64__
e9ce8d39 440 magic = GMON_MAGIC;
224c7076
A
441#else
442 magic = GMON_MAGIC_64;
443#endif
444 write(fd, &magic, sizeof(uint32_t));
e9ce8d39
A
445
446#if defined(__DYNAMIC__)
b5d655f7 447 {
e9ce8d39
A
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++){
224c7076
A
453 image_header = _dyld_get_image_header(i);
454 printf("\timage_header %p\n", image_header);
e9ce8d39
A
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 */
224c7076
A
462 dyld_data.type = GMONTYPE_DYLD2_STATE;
463 dyld_data.size = sizeof(uint32_t) +
464 sizeof(intptr_t) * (image_count - 1);
e9ce8d39
A
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 */
224c7076 473 write(fd, &dyld_data, sizeof(gmon_data_t));
e9ce8d39 474 image_count--;
224c7076 475 write(fd, &image_count, sizeof(uint32_t));
e9ce8d39
A
476 image_count++;
477 for(i = 1; i < image_count; i++){
34e8f829 478 image_header = (intptr_t)_dyld_get_image_header(i);
224c7076 479 write(fd, &image_header, sizeof(intptr_t));
e9ce8d39
A
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
224c7076 489 fprintf(stderr, "[monoutput] sbuf %p ssiz %d\n", m->sbuf, m->ssiz);
e9ce8d39
A
490#endif
491 sample_data.type = GMONTYPE_SAMPLES;
492 sample_data.size = m->ssiz;
224c7076 493 write(fd, &sample_data, sizeof(gmon_data_t));
e9ce8d39 494 /*
224c7076
A
495 * Write the gmonhdr_t and the pc-sample buffer. Note the
496 * gmonhdr_t is in sbuf at the beginning of sbuf already
e9ce8d39
A
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;
224c7076
A
507#ifdef DEBUG
508 fprintf(stderr, "[monoutput] raw arcs, total %lu\n", endfrom);
509#endif
e9ce8d39
A
510 for(fromindex = 0; fromindex < endfrom; fromindex++){
511 if(m->froms[fromindex] == 0){
512 continue;
513 }
224c7076
A
514#ifdef DEBUG
515 fprintf(stderr, "[monoutput] raw arc count at index[%lu] %u\n",
516 fromindex, m->froms[fromindex]);
517#endif
e9ce8d39
A
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){
224c7076 523 arc_data.size += sizeof(rawarc_order_t);
e9ce8d39
A
524 }
525 }
224c7076 526 write(fd, &arc_data, sizeof(gmon_data_t));
e9ce8d39
A
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
224c7076
A
538 fprintf(stderr, "[monoutput] frompc %p selfpc %p "
539 "count %ld order %lu\n", frompc,
540 m->tos[toindex].selfpc,
e9ce8d39
A
541 m->tos[toindex].count, m->tos[toindex].order);
542#endif
224c7076
A
543 rawarc_order.raw_frompc = (uintptr_t)frompc;
544 rawarc_order.raw_selfpc = (uintptr_t)
e9ce8d39
A
545 m->tos[toindex].selfpc;
546 rawarc_order.raw_count = m->tos[toindex].count;
547 rawarc_order.raw_order = m->tos[toindex].order;
224c7076 548 write(fd, &rawarc_order, sizeof(rawarc_order_t));
e9ce8d39
A
549 }
550 }
551 }
552 close(fd);
553}
554
555void
556monitor(
557char *lowpc,
558char *highpc,
559char *buf,
560int bufsiz,
561int nfunc) /* nfunc is not used; available for compatability only. */
562{
224c7076
A
563 intptr_t o;
564 gmonhdr_t *p;
565 mon_t *m;
e9ce8d39
A
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;
224c7076
A
578 p = (gmonhdr_t *)buf;
579 memset(p, '\0', sizeof(gmonhdr_t));
580 p->lpc = (uintptr_t)lowpc;
581 p->hpc = (uintptr_t)highpc;
e9ce8d39
A
582 p->ncnt = m->ssiz;
583 p->version = GMONVERSION;
584 p->profrate = getprofhz();
224c7076 585 bufsiz -= sizeof(gmonhdr_t);
e9ce8d39
A
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 */
601void
602moncontrol(
603int mode)
604{
224c7076 605 mon_t *m;
e9ce8d39
A
606 unsigned long i;
607
608 if(mode){
609 /* start */
610 m = mon;
611 if(m != NULL){
224c7076
A
612 profil(m->sbuf + sizeof(gmonhdr_t),
613 m->ssiz - sizeof(gmonhdr_t),
614 (u_long)m->lowpc, m->scale);
e9ce8d39 615 for(i = 1; i < nmon; i++)
224c7076
A
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);
e9ce8d39
A
619 profiling = 0;
620 }
621 }
622 else{
623 /* stop */
624 profil((char *)0, 0, 0, 0);
625 profiling = -1;
626 }
627}
628
629void
630moncount(
631char *frompc,
632char *selfpc)
633{
634 unsigned short *frompcindex;
224c7076 635 tostruct_t *top, *prevtop;
e9ce8d39 636 unsigned long i, toindex;
224c7076 637 mon_t *m;
e9ce8d39
A
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
224c7076 653 fprintf(stderr, "[moncount] frompc %p selfpc %p\n", frompc, selfpc);
e9ce8d39
A
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;
224c7076
A
664 if((uintptr_t)frompcindex >= (uintptr_t)m->lowpc &&
665 (uintptr_t)frompcindex < (uintptr_t)m->highpc)
e9ce8d39
A
666 break;
667 }
668 if(i == nmon){
669 goto done;
670 }
671 else{
672 frompcindex = (unsigned short *)
224c7076 673 ((uintptr_t)frompcindex - (uintptr_t)m->lowpc);
e9ce8d39
A
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];
224c7076 688 top->selfpc = (uintptr_t)selfpc;
e9ce8d39
A
689 top->count = 1;
690 top->link = 0;
691 top->order = ++order;
692 goto done;
693 }
694 top = &m->tos[toindex];
224c7076 695 if(top->selfpc == (uintptr_t)selfpc){
e9ce8d39
A
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.
224c7076 713 * so we allocate a new tostruct_t
e9ce8d39
A
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];
224c7076 721 top->selfpc = (uintptr_t)selfpc;
e9ce8d39
A
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];
224c7076 733 if(top->selfpc == (uintptr_t)selfpc){
e9ce8d39
A
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 }
747done:
748 profiling--;
749 return;
750
751overflow:
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 */
760static
224c7076 761long
e9ce8d39
A
762getprofhz(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}