]> git.saurik.com Git - apple/libc.git/blame - gmon/gmon.c
Libc-498.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>
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 */
215 if(_dyld_present())
216 _dyld_moninit(monaddition);
217#endif
218}
219
220void
221monstartup(
222char *lowpc,
223char *highpc)
224{
225 monreset();
226 if(mon == NULL){
224c7076 227 if((mon = malloc(sizeof(mon_t))) == NULL){
e9ce8d39
A
228 write(2, MSG, sizeof(MSG) - 1);
229 return;
230 }
231 nmon = 1;
224c7076 232 memset(mon, '\0', sizeof(mon_t));
e9ce8d39
A
233 }
234 monsetup(mon, lowpc, highpc);
235}
236
237/*
238 * monaddtion() is used for adding additional pc ranges to profile. This is
239 * used for profiling dyld loaded code.
240 */
241void
242monaddition(
243char *lowpc,
244char *highpc)
245{
246 char save_profiling;
224c7076 247 mon_t *m;
e9ce8d39
A
248
249 if(mon == NULL){
250 monstartup(lowpc, highpc);
251 return;
252 }
253 save_profiling = profiling;
254 profiling = -1;
224c7076 255 if((mon = realloc(mon, (nmon + 1) * sizeof(mon_t))) == NULL){
e9ce8d39
A
256 write(2, MSG, sizeof(MSG) - 1);
257 return;
258 }
259 m = mon + nmon;
224c7076 260 memset(m, '\0', sizeof(mon_t));
e9ce8d39
A
261 nmon++;
262 monsetup(m, lowpc, highpc);
263 profiling = save_profiling;
264}
265
266static
267void
268monsetup(
224c7076 269mon_t *m,
e9ce8d39
A
270char *lowpc,
271char *highpc)
272{
224c7076 273 long monsize;
e9ce8d39
A
274 char *buffer;
275 kern_return_t ret;
224c7076
A
276 gmonhdr_t *p;
277 uintptr_t o;
e9ce8d39
A
278
279 /*
280 * round lowpc and highpc to multiples of the density we're using
224c7076 281 * so the rest of the scaling (here and in gprof) stays in longs.
e9ce8d39 282 */
224c7076 283 lowpc = (char *)ROUNDDOWN((uintptr_t)lowpc,
e9ce8d39
A
284 HISTFRACTION * sizeof(HISTCOUNTER));
285 m->lowpc = lowpc;
224c7076 286 highpc = (char *)ROUNDUP((uintptr_t)highpc,
e9ce8d39
A
287 HISTFRACTION * sizeof(HISTCOUNTER));
288 m->highpc = highpc;
289
290 if(m->froms)
291 vm_deallocate(mach_task_self(),
292 (vm_address_t)m->froms,
293 (vm_size_t)(m->textsize / HASHFRACTION));
294 m->textsize = highpc - lowpc;
295 ret = vm_allocate(mach_task_self(),
296 (vm_address_t *)&m->froms,
297 (vm_size_t)(m->textsize / HASHFRACTION),
298 TRUE);
299 if(ret != KERN_SUCCESS){
300 write(2, MSG, sizeof(MSG) - 1);
301 m->froms = 0;
302 return;
303 }
304
305 if(m->sbuf)
306 vm_deallocate(mach_task_self(),
307 (vm_address_t)m->sbuf,
308 (vm_size_t)m->ssiz);
224c7076 309 monsize = (m->textsize / HISTFRACTION) + sizeof(gmonhdr_t);
e9ce8d39
A
310 ret = vm_allocate(mach_task_self(),
311 (vm_address_t *)&buffer,
312 (vm_size_t)monsize,
313 TRUE);
314 if(ret != KERN_SUCCESS){
315 write(2, MSG, sizeof(MSG) - 1);
316 m->sbuf = 0;
317 return;
318 }
319
320 if(m->tos)
321 vm_deallocate(mach_task_self(),
322 (vm_address_t)m->tos,
224c7076 323 (vm_size_t)(m->tolimit * sizeof(tostruct_t)));
e9ce8d39
A
324 m->tolimit = m->textsize * ARCDENSITY / 100;
325 if(m->tolimit < MINARCS){
326 m->tolimit = MINARCS;
327 }
328 else if(m->tolimit > 65534){
329 m->tolimit = 65534;
330 }
331 ret = vm_allocate(mach_task_self(),
332 (vm_address_t *)&m->tos,
224c7076 333 (vm_size_t)(m->tolimit * sizeof(tostruct_t)),
e9ce8d39
A
334 TRUE);
335 if(ret != KERN_SUCCESS){
336 write(2, MSG, sizeof(MSG) - 1);
337 m->tos = 0;
338 return;
339 }
340 m->tos[0].link = 0; /* a nop since tos was vm_allocated and is zero */
341
342 /*
343 * If this is call to monsetup() was via monstartup() (m == mon) then
344 * it is using or reusing the first pc range and then the pc sample
345 * buffer can be setup by the system call profil() via monitor() via
346 * a moncontrol(1) call.
347 *
348 * Otherwise this is call to monsetup() was via monaddition() and a
349 * new system call is needed to add an additional pc sample buffer in
350 * the kernel.
351 */
352 if(m == mon && !init){
353 monitor(lowpc, highpc, buffer, monsize, m->tolimit);
354 }
355 else{
356 /* monitor() functionality */
357 m->sbuf = buffer;
358 m->ssiz = monsize;
224c7076
A
359 p = (gmonhdr_t *)m->sbuf;
360 memset(p, '\0', sizeof(gmonhdr_t));
361 p->lpc = (uintptr_t)m->lowpc;
362 p->hpc = (uintptr_t)m->highpc;
e9ce8d39
A
363 p->ncnt = m->ssiz;
364 p->version = GMONVERSION;
365 p->profrate = getprofhz();
366 o = highpc - lowpc;
224c7076
A
367 if((monsize - sizeof(gmonhdr_t)) < o)
368/* POSSIBLE BUG, if "(float) (monsize - sizeof(gmonhdr_t))/ o)" is zero
59e0d9fe
A
369 * then m->scale will be set to zero and the add_profil() call will disable
370 * profiling */
224c7076 371 m->scale = ((float) (monsize - sizeof(gmonhdr_t))/ o) *
e9ce8d39
A
372 SCALE_1_TO_1;
373 else
374 m->scale = SCALE_1_TO_1;
375
376 /* moncontrol(mode == 1) functionality */
377 if(!init)
224c7076
A
378 add_profil(m->sbuf + sizeof(gmonhdr_t),
379 m->ssiz - sizeof(gmonhdr_t),
380 (long)m->lowpc, m->scale);
e9ce8d39
A
381 }
382}
383
384void
385monreset(
386void)
387{
388 unsigned long i;
224c7076
A
389 mon_t *m;
390 gmonhdr_t *p;
e9ce8d39
A
391
392 moncontrol(0);
393 if(mon == NULL)
394 return;
395 for(i = 0; i < nmon; i++){
396 m = mon + i;
397 if(m->sbuf != NULL){
398 memset(m->sbuf, '\0', m->ssiz);
224c7076
A
399 p = (gmonhdr_t *)m->sbuf;
400 p->lpc = (uintptr_t)m->lowpc;
401 p->hpc = (uintptr_t)m->highpc;
e9ce8d39 402 p->ncnt = m->ssiz;
59e0d9fe
A
403 p->version = GMONVERSION;
404 p->profrate = getprofhz();
e9ce8d39
A
405 }
406 if(m->froms != NULL)
407 memset(m->froms, '\0', m->textsize / HASHFRACTION);
408 if(m->tos != NULL)
224c7076 409 memset(m->tos, '\0', m->tolimit * sizeof(tostruct_t));
e9ce8d39
A
410 }
411 order = 0;
412 moncontrol(1);
413}
414
415void
416monoutput(
417const char *filename)
418{
419 int fd;
224c7076
A
420 unsigned long i, fromindex, endfrom, toindex;
421 uint32_t magic;
422 gmon_data_t sample_data, arc_data, dyld_data;
e9ce8d39 423 char *frompc;
224c7076
A
424 rawarc_order_t rawarc_order;
425 mon_t *m;
426 uint32_t image_count;
427 intptr_t image_header;
e9ce8d39
A
428 char *image_name;
429
430 moncontrol(0);
431 m = mon;
432 if(m == NULL)
433 return;
434 fd = creat(filename, 0666);
435 if(fd < 0){
436 perror("mcount: gmon.out");
437 return;
438 }
439
224c7076 440#ifndef __LP64__
e9ce8d39 441 magic = GMON_MAGIC;
224c7076
A
442#else
443 magic = GMON_MAGIC_64;
444#endif
445 write(fd, &magic, sizeof(uint32_t));
e9ce8d39
A
446
447#if defined(__DYNAMIC__)
448 if(_dyld_present()){
449 image_count = _dyld_image_count();
450 if(image_count > 1){
451#ifdef DYLD_DEBUG
452 printf("image_count = %lu\n", image_count - 1);
453 for(i = 1; i < image_count; i++){
224c7076
A
454 image_header = _dyld_get_image_header(i);
455 printf("\timage_header %p\n", image_header);
e9ce8d39
A
456 image_name = _dyld_get_image_name(i);
457 printf("\timage_name %s\n", image_name);
458 }
459#endif
460 /*
461 * Calculate the dyld_data.size.
462 */
224c7076
A
463 dyld_data.type = GMONTYPE_DYLD2_STATE;
464 dyld_data.size = sizeof(uint32_t) +
465 sizeof(intptr_t) * (image_count - 1);
e9ce8d39
A
466 for(i = 1; i < image_count; i++){
467 image_name = _dyld_get_image_name(i);
468 dyld_data.size += strlen(image_name) + 1;
469 }
470
471 /*
472 * Write the dyld_data.
473 */
224c7076 474 write(fd, &dyld_data, sizeof(gmon_data_t));
e9ce8d39 475 image_count--;
224c7076 476 write(fd, &image_count, sizeof(uint32_t));
e9ce8d39
A
477 image_count++;
478 for(i = 1; i < image_count; i++){
224c7076
A
479 image_header = _dyld_get_image_header(i);
480 write(fd, &image_header, sizeof(intptr_t));
e9ce8d39
A
481 image_name = _dyld_get_image_name(i);
482 write(fd, image_name, strlen(image_name) + 1);
483 }
484 }
485 }
486#endif
487 for(i = 0; i < nmon; i++){
488 m = mon + i;
489#ifdef DEBUG
224c7076 490 fprintf(stderr, "[monoutput] sbuf %p ssiz %d\n", m->sbuf, m->ssiz);
e9ce8d39
A
491#endif
492 sample_data.type = GMONTYPE_SAMPLES;
493 sample_data.size = m->ssiz;
224c7076 494 write(fd, &sample_data, sizeof(gmon_data_t));
e9ce8d39 495 /*
224c7076
A
496 * Write the gmonhdr_t and the pc-sample buffer. Note the
497 * gmonhdr_t is in sbuf at the beginning of sbuf already
e9ce8d39
A
498 * filled in.
499 */
500 write(fd, m->sbuf, m->ssiz);
501
502 /*
503 * Now write out the raw arcs.
504 */
505 endfrom = m->textsize / (HASHFRACTION * sizeof(*m->froms));
506 arc_data.type = GMONTYPE_ARCS_ORDERS;
507 arc_data.size = 0;
224c7076
A
508#ifdef DEBUG
509 fprintf(stderr, "[monoutput] raw arcs, total %lu\n", endfrom);
510#endif
e9ce8d39
A
511 for(fromindex = 0; fromindex < endfrom; fromindex++){
512 if(m->froms[fromindex] == 0){
513 continue;
514 }
224c7076
A
515#ifdef DEBUG
516 fprintf(stderr, "[monoutput] raw arc count at index[%lu] %u\n",
517 fromindex, m->froms[fromindex]);
518#endif
e9ce8d39
A
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){
224c7076 524 arc_data.size += sizeof(rawarc_order_t);
e9ce8d39
A
525 }
526 }
224c7076 527 write(fd, &arc_data, sizeof(gmon_data_t));
e9ce8d39
A
528
529 for(fromindex = 0; fromindex < endfrom; fromindex++){
530 if(m->froms[fromindex] == 0){
531 continue;
532 }
533 frompc = m->lowpc +
534 (fromindex * HASHFRACTION * sizeof(*m->froms));
535 for(toindex = m->froms[fromindex];
536 toindex != 0;
537 toindex = m->tos[toindex].link){
538#ifdef DEBUG
224c7076
A
539 fprintf(stderr, "[monoutput] frompc %p selfpc %p "
540 "count %ld order %lu\n", frompc,
541 m->tos[toindex].selfpc,
e9ce8d39
A
542 m->tos[toindex].count, m->tos[toindex].order);
543#endif
224c7076
A
544 rawarc_order.raw_frompc = (uintptr_t)frompc;
545 rawarc_order.raw_selfpc = (uintptr_t)
e9ce8d39
A
546 m->tos[toindex].selfpc;
547 rawarc_order.raw_count = m->tos[toindex].count;
548 rawarc_order.raw_order = m->tos[toindex].order;
224c7076 549 write(fd, &rawarc_order, sizeof(rawarc_order_t));
e9ce8d39
A
550 }
551 }
552 }
553 close(fd);
554}
555
556void
557monitor(
558char *lowpc,
559char *highpc,
560char *buf,
561int bufsiz,
562int nfunc) /* nfunc is not used; available for compatability only. */
563{
224c7076
A
564 intptr_t o;
565 gmonhdr_t *p;
566 mon_t *m;
e9ce8d39
A
567
568 moncontrol(0);
569 m = mon;
570 if(m == NULL)
571 return;
572 if(lowpc == 0){
573 moncontrol(0);
574 monoutput("gmon.out");
575 return;
576 }
577 m->sbuf = buf;
578 m->ssiz = bufsiz;
224c7076
A
579 p = (gmonhdr_t *)buf;
580 memset(p, '\0', sizeof(gmonhdr_t));
581 p->lpc = (uintptr_t)lowpc;
582 p->hpc = (uintptr_t)highpc;
e9ce8d39
A
583 p->ncnt = m->ssiz;
584 p->version = GMONVERSION;
585 p->profrate = getprofhz();
224c7076 586 bufsiz -= sizeof(gmonhdr_t);
e9ce8d39
A
587 if(bufsiz <= 0)
588 return;
589 o = highpc - lowpc;
590 if(bufsiz < o)
591 m->scale = ((float) bufsiz / o) * SCALE_1_TO_1;
592 else
593 m->scale = SCALE_1_TO_1;
594 moncontrol(1);
595}
596
597/*
598 * Control profiling
599 * profiling is what mcount checks to see if
600 * all the data structures are ready.
601 */
602void
603moncontrol(
604int mode)
605{
224c7076 606 mon_t *m;
e9ce8d39
A
607 unsigned long i;
608
609 if(mode){
610 /* start */
611 m = mon;
612 if(m != NULL){
224c7076
A
613 profil(m->sbuf + sizeof(gmonhdr_t),
614 m->ssiz - sizeof(gmonhdr_t),
615 (u_long)m->lowpc, m->scale);
e9ce8d39 616 for(i = 1; i < nmon; i++)
224c7076
A
617 add_profil(mon[i].sbuf + sizeof(gmonhdr_t),
618 mon[i].ssiz - sizeof(gmonhdr_t),
619 (u_long)mon[i].lowpc, mon[i].scale);
e9ce8d39
A
620 profiling = 0;
621 }
622 }
623 else{
624 /* stop */
625 profil((char *)0, 0, 0, 0);
626 profiling = -1;
627 }
628}
629
630void
631moncount(
632char *frompc,
633char *selfpc)
634{
635 unsigned short *frompcindex;
224c7076 636 tostruct_t *top, *prevtop;
e9ce8d39 637 unsigned long i, toindex;
224c7076 638 mon_t *m;
e9ce8d39
A
639
640 m = mon;
641 if(m == NULL)
642 return;
643 /*
644 * Check that we are profiling and that we aren't recursively invoked.
645 * This should really be a test and set instruction in changing the
646 * value of profiling.
647 */
648 if(profiling)
649 return;
650 profiling++;
651
652
653#ifdef DEBUG
224c7076 654 fprintf(stderr, "[moncount] frompc %p selfpc %p\n", frompc, selfpc);
e9ce8d39
A
655#endif
656 frompcindex = (unsigned short *)frompc;
657
658 /*
659 * check that frompcindex is a reasonable pc value.
660 * for example: signal catchers get called from the stack,
661 * not from text space. too bad.
662 */
663 for(i = 0; i < nmon; i++){
664 m = mon + i;
224c7076
A
665 if((uintptr_t)frompcindex >= (uintptr_t)m->lowpc &&
666 (uintptr_t)frompcindex < (uintptr_t)m->highpc)
e9ce8d39
A
667 break;
668 }
669 if(i == nmon){
670 goto done;
671 }
672 else{
673 frompcindex = (unsigned short *)
224c7076 674 ((uintptr_t)frompcindex - (uintptr_t)m->lowpc);
e9ce8d39
A
675 }
676 frompcindex =
677 &m->froms[((long)frompcindex) / (HASHFRACTION * sizeof(*m->froms))];
678 toindex = *frompcindex;
679 if(toindex == 0){
680 /*
681 * first time traversing this arc
682 */
683 toindex = ++m->tos[0].link;
684 if(toindex >= m->tolimit){
685 goto overflow;
686 }
687 *frompcindex = toindex;
688 top = &m->tos[toindex];
224c7076 689 top->selfpc = (uintptr_t)selfpc;
e9ce8d39
A
690 top->count = 1;
691 top->link = 0;
692 top->order = ++order;
693 goto done;
694 }
695 top = &m->tos[toindex];
224c7076 696 if(top->selfpc == (uintptr_t)selfpc){
e9ce8d39
A
697 /*
698 * arc at front of chain; usual case.
699 */
700 top->count++;
701 goto done;
702 }
703 /*
704 * have to go looking down chain for it.
705 * top points to what we are looking at,
706 * prevtop points to previous top.
707 * we know it is not at the head of the chain.
708 */
709 for(; /* goto done */; ){
710 if(top->link == 0){
711 /*
712 * top is end of the chain and none of the chain
713 * had top->selfpc == selfpc.
224c7076 714 * so we allocate a new tostruct_t
e9ce8d39
A
715 * and link it to the head of the chain.
716 */
717 toindex = ++m->tos[0].link;
718 if(toindex >= m->tolimit){
719 goto overflow;
720 }
721 top = &m->tos[toindex];
224c7076 722 top->selfpc = (uintptr_t)selfpc;
e9ce8d39
A
723 top->count = 1;
724 top->link = *frompcindex;
725 top->order = ++order;
726 *frompcindex = toindex;
727 goto done;
728 }
729 /*
730 * otherwise, check the next arc on the chain.
731 */
732 prevtop = top;
733 top = &m->tos[top->link];
224c7076 734 if(top->selfpc == (uintptr_t)selfpc){
e9ce8d39
A
735 /*
736 * there it is.
737 * increment its count
738 * move it to the head of the chain.
739 */
740 top->count++;
741 toindex = prevtop->link;
742 prevtop->link = top->link;
743 top->link = *frompcindex;
744 *frompcindex = toindex;
745 goto done;
746 }
747 }
748done:
749 profiling--;
750 return;
751
752overflow:
753 profiling++; /* halt further profiling */
754#define TOLIMIT "mcount: tos overflow\n"
755 write(2, TOLIMIT, sizeof(TOLIMIT) - 1);
756}
757
758/*
759 * Get the profiling rate.
760 */
761static
224c7076 762long
e9ce8d39
A
763getprofhz(void)
764{
765 int mib[2];
766 size_t size;
767 struct clockinfo clockrate;
768
769 mib[0] = CTL_KERN;
770 mib[1] = KERN_CLOCKRATE;
771 clockrate.profhz = 1;
772 size = sizeof(clockrate);
773 if(sysctl(mib, 2, &clockrate, &size, NULL, 0) < 0)
774 ;
775 return(clockrate.profhz);
776}