2 * Copyright (c) 1991 The Regents of the University of California.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. [rescinded 22 July 1999]
14 * 4. Neither the name of the University nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 /* Mangled into a form that works on Solaris 2/SPARC by Mark Eichin
32 * for Cygnus Support, July 1992.
34 * Modified to support Solaris 2/x86 by J.W.Hawtin <oolon@ankh.org>, 14/8/96.
36 * It must be used in conjunction with sol2-gc1.S, which is used to start
37 * and stop process monitoring.
42 #include <fcntl.h> /* For creat. */
44 extern void monstartup (char *, char *);
45 extern void _mcleanup (void);
47 static void internal_mcount (void) __attribute__ ((used
));
49 static void internal_mcount (char *, unsigned short *) __attribute__ ((used
));
51 static void moncontrol (int);
59 #define HISTFRACTION 2
60 #define HISTCOUNTER unsigned short
61 #define HASHFRACTION 1
72 unsigned long raw_frompc
;
73 unsigned long raw_selfpc
;
77 #define ROUNDDOWN(x, y) (((x) / (y)) * (y))
78 #define ROUNDUP(x, y) ((((x) + (y) - 1) / (y)) * (y))
80 /* froms is actually a bunch of unsigned shorts indexing tos. */
81 static int profiling
= 3;
82 static unsigned short *froms
;
83 static struct tostruct
*tos
= NULL
;
84 static long tolimit
= 0;
85 static char *s_lowpc
= NULL
;
86 static char *s_highpc
= NULL
;
87 static size_t s_textsize
= 0;
92 /* See profil(2) where this is describe (incorrectly). */
93 #define SCALE_1_TO_1 0x10000L
95 #define MSG "No space for profiling buffer(s)\n"
98 monstartup (char *lowpc
, char *highpc
)
104 /* Round lowpc and highpc to multiples of the density we're using
105 so the rest of the scaling (here and in gprof) stays in ints. */
106 lowpc
= (char *) ROUNDDOWN ((size_t) lowpc
,
107 HISTFRACTION
* sizeof (HISTCOUNTER
));
109 highpc
= (char *) ROUNDUP ((size_t) highpc
,
110 HISTFRACTION
* sizeof (HISTCOUNTER
));
112 s_textsize
= highpc
- lowpc
;
113 monsize
= (s_textsize
/ HISTFRACTION
) + sizeof (struct phdr
);
114 buffer
= sbrk (monsize
);
115 if (buffer
== (void *) -1) {
116 write (STDERR_FILENO
, MSG
, sizeof (MSG
));
119 froms
= sbrk (s_textsize
/ HASHFRACTION
);
120 if (froms
== (void *) -1) {
121 write (STDERR_FILENO
, MSG
, sizeof (MSG
));
125 tolimit
= s_textsize
* ARCDENSITY
/ 100;
126 if (tolimit
< MINARCS
) {
128 } else if (tolimit
> 65534) {
131 tos
= sbrk (tolimit
* sizeof (struct tostruct
));
132 if (tos
== (void *) -1) {
133 write (STDERR_FILENO
, MSG
, sizeof (MSG
));
141 ((struct phdr
*) buffer
)->lpc
= lowpc
;
142 ((struct phdr
*) buffer
)->hpc
= highpc
;
143 ((struct phdr
*) buffer
)->ncnt
= ssiz
;
144 monsize
-= sizeof (struct phdr
);
149 s_scale
= ((float) monsize
/ o
) * SCALE_1_TO_1
;
151 s_scale
= SCALE_1_TO_1
;
163 struct rawarc rawarc
;
165 const char *proffile
;
168 extern char **___Argv
;
172 if ((profdir
= getenv ("PROFDIR")) != NULL
) {
173 /* If PROFDIR contains a null value, no profiling output is produced. */
174 if (*profdir
== '\0') {
178 progname
= strrchr (___Argv
[0], '/');
179 if (progname
== NULL
)
180 progname
= ___Argv
[0];
184 sprintf (buf
, "%s/%ld.%s", profdir
, (long) getpid (), progname
);
187 proffile
= "gmon.out";
190 fd
= creat (proffile
, 0666);
196 fprintf (stderr
, "[mcleanup] sbuf %#x ssiz %d\n", sbuf
, ssiz
);
199 write (fd
, sbuf
, ssiz
);
200 endfrom
= s_textsize
/ (HASHFRACTION
* sizeof (*froms
));
201 for (fromindex
= 0; fromindex
< endfrom
; fromindex
++) {
202 if (froms
[fromindex
] == 0) {
205 frompc
= s_lowpc
+ (fromindex
* HASHFRACTION
* sizeof (*froms
));
206 for (toindex
= froms
[fromindex
];
208 toindex
= tos
[toindex
].link
) {
210 fprintf (stderr
, "[mcleanup] frompc %#x selfpc %#x count %d\n",
211 frompc
, tos
[toindex
].selfpc
, tos
[toindex
].count
);
213 rawarc
.raw_frompc
= (unsigned long) frompc
;
214 rawarc
.raw_selfpc
= (unsigned long) tos
[toindex
].selfpc
;
215 rawarc
.raw_count
= tos
[toindex
].count
;
216 write (fd
, &rawarc
, sizeof (rawarc
));
222 /* Solaris 2 libraries use _mcount. */
224 asm(".globl _mcount\n"
226 " jmp internal_mcount\n");
227 #elif defined __x86_64__
228 /* See GLIBC for additional information about this technique. */
229 asm(".globl _mcount\n"
230 " .type _mcount, @function\n"
232 /* The compiler calls _mcount after the prologue, and does not
233 save any of the registers. Therefore we must preserve all
234 seven registers which may contain function arguments. */
235 " subq $0x38, %rsp\n"
236 " movq %rax, (%rsp)\n"
237 " movq %rcx, 0x08(%rsp)\n"
238 " movq %rdx, 0x10(%rsp)\n"
239 " movq %rsi, 0x18(%rsp)\n"
240 " movq %rdi, 0x20(%rsp)\n"
241 " movq %r8, 0x28(%rsp)\n"
242 " movq %r9, 0x30(%rsp)\n"
243 /* Get SELFPC (pushed by the call to this function) and
244 FROMPCINDEX (via the frame pointer). */
245 " movq 0x38(%rsp), %rdi\n"
246 " movq 0x8(%rbp), %rsi\n"
247 " call internal_mcount\n"
248 /* Restore the saved registers. */
249 " movq 0x30(%rsp), %r9\n"
250 " movq 0x28(%rsp), %r8\n"
251 " movq 0x20(%rsp), %rdi\n"
252 " movq 0x18(%rsp), %rsi\n"
253 " movq 0x10(%rsp), %rdx\n"
254 " movq 0x08(%rsp), %rcx\n"
255 " movq (%rsp), %rax\n"
256 " addq $0x38, %rsp\n"
258 #elif defined __sparc__
259 /* The SPARC stack frame is only held together by the frame pointers
260 in the register windows. According to the SVR4 SPARC ABI
261 Supplement, Low Level System Information/Operating System
262 Interface/Software Trap Types, a type 3 trap will flush all of the
263 register windows to the stack, which will make it possible to walk
264 the frames and find the return addresses.
265 However, it seems awfully expensive to incur a trap (system
266 call) for every function call. It turns out that "call" simply puts
267 the return address in %o7 expecting the "save" in the procedure to
268 shift it into %i7; this means that before the "save" occurs, %o7
269 contains the address of the call to mcount, and %i7 still contains
270 the caller above that. The asm mcount here simply saves those
271 registers in argument registers and branches to internal_mcount,
272 simulating a call with arguments.
274 1) the branch to internal_mcount is hard coded; it should be
275 possible to tell asm to use the assembler-name of a symbol.
276 2) in theory, the function calling mcount could have saved %i7
277 somewhere and reused the register; in practice, I *think* this will
278 break longjmp (and maybe the debugger) but I'm not certain. (I take
279 some comfort in the knowledge that it will break the native mcount
281 3) if builtin_return_address worked, this could be portable.
282 However, it would really have to be optimized for arguments of 0
283 and 1 and do something like what we have here in order to avoid the
284 trap per function call performance hit.
285 4) the atexit and monsetup calls prevent this from simply
286 being a leaf routine that doesn't do a "save" (and would thus have
287 access to %o7 and %i7 directly) but the call to write() at the end
288 would have also prevented this.
290 -- [eichin:19920702.1107EST] */
291 asm(".global _mcount\n"
293 /* i7 == last ret, -> frompcindex. */
295 /* o7 == current ret, -> selfpc. */
297 " b,a internal_mcount\n");
302 internal_mcount (void)
304 internal_mcount (char *selfpc
, unsigned short *frompcindex
)
307 struct tostruct
*top
;
308 struct tostruct
*prevtop
;
310 static char already_setup
;
314 unsigned short *frompcindex
;
316 /* Find the return address for mcount and the return address for mcount's
319 /* selfpc = pc pushed by mcount call.
320 This identifies the function that was just entered. */
321 selfpc
= (void *) __builtin_return_address (0);
322 /* frompcindex = pc in preceding frame.
323 This identifies the caller of the function just entered. */
324 frompcindex
= (void *) __builtin_return_address (1);
333 /* <sys/vmparam.h> USERSTACK. */
334 monstartup ((char *) 0x8048000, etext
);
335 #elif defined __x86_64__
336 monstartup (NULL
, etext
);
337 #elif defined __sparc__
339 extern char _start
[];
342 monstartup (_start
< _init
? _start
: _init
, etext
);
347 /* Check that we are profiling and that we aren't recursively invoked. */
352 /* Check that frompcindex is a reasonable pc value. For example: signal
353 catchers get called from the stack, not from text space. too bad. */
354 frompcindex
= (unsigned short *) ((long) frompcindex
- (long) s_lowpc
);
355 if ((unsigned long) frompcindex
> s_textsize
) {
358 frompcindex
= &froms
[((long) frompcindex
) / (HASHFRACTION
* sizeof (*froms
))];
359 toindex
= *frompcindex
;
361 /* First time traversing this arc. */
362 toindex
= ++tos
[0].link
;
363 if (toindex
>= tolimit
) {
366 *frompcindex
= toindex
;
368 top
->selfpc
= selfpc
;
374 if (top
->selfpc
== selfpc
) {
375 /* arc at front of chain; usual case. */
379 /* Have to go looking down chain for it. Top points to what we are
380 looking at, prevtop points to previous top. We know it is not at the
381 head of the chain. */
382 for (; /* goto done */; ) {
383 if (top
->link
== 0) {
384 /* top is end of the chain and none of the chain had top->selfpc ==
385 selfpc, so we allocate a new tostruct and link it to the head of
387 toindex
= ++tos
[0].link
;
388 if (toindex
>= tolimit
) {
392 top
->selfpc
= selfpc
;
394 top
->link
= *frompcindex
;
395 *frompcindex
= toindex
;
398 /* Otherwise, check the next arc on the chain. */
400 top
= &tos
[top
->link
];
401 if (top
->selfpc
== selfpc
) {
402 /* There it is. Increment its count move it to the head of the
405 toindex
= prevtop
->link
;
406 prevtop
->link
= top
->link
;
407 top
->link
= *frompcindex
;
408 *frompcindex
= toindex
;
415 /* ... and fall through. */
417 /* Normal return restores saved registers. */
421 /* Halt further profiling. */
424 #define TOLIMIT "mcount: tos overflow\n"
425 write (STDERR_FILENO
, TOLIMIT
, sizeof (TOLIMIT
));
429 /* Control profiling. Profiling is what mcount checks to see if all the
430 data structures are ready. */
432 moncontrol (int mode
)
436 profil ((unsigned short *) (sbuf
+ sizeof (struct phdr
)),
437 ssiz
- sizeof (struct phdr
), (size_t) s_lowpc
, s_scale
);
441 profil ((unsigned short *) 0, 0, 0, 0);