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 "auto-target.h"
43 #include <fcntl.h> /* For creat. */
45 extern void monstartup (char *, char *);
46 extern void _mcleanup (void);
47 static void internal_mcount (char *, unsigned short *) __attribute__ ((used
));
48 static void moncontrol (int);
56 #define HISTFRACTION 2
57 #define HISTCOUNTER unsigned short
58 #define HASHFRACTION 1
69 unsigned long raw_frompc
;
70 unsigned long raw_selfpc
;
74 #define ROUNDDOWN(x, y) (((x) / (y)) * (y))
75 #define ROUNDUP(x, y) ((((x) + (y) - 1) / (y)) * (y))
77 /* froms is actually a bunch of unsigned shorts indexing tos. */
78 static int profiling
= 3;
79 static unsigned short *froms
;
80 static struct tostruct
*tos
= NULL
;
81 static long tolimit
= 0;
82 static char *s_lowpc
= NULL
;
83 static char *s_highpc
= NULL
;
84 static size_t s_textsize
= 0;
89 /* See profil(2) where this is describe (incorrectly). */
90 #define SCALE_1_TO_1 0x10000L
92 #define MSG "No space for profiling buffer(s)\n"
95 monstartup (char *lowpc
, char *highpc
)
101 /* Round lowpc and highpc to multiples of the density we're using
102 so the rest of the scaling (here and in gprof) stays in ints. */
103 lowpc
= (char *) ROUNDDOWN ((size_t) lowpc
,
104 HISTFRACTION
* sizeof (HISTCOUNTER
));
106 highpc
= (char *) ROUNDUP ((size_t) highpc
,
107 HISTFRACTION
* sizeof (HISTCOUNTER
));
109 s_textsize
= highpc
- lowpc
;
110 monsize
= (s_textsize
/ HISTFRACTION
) + sizeof (struct phdr
);
111 buffer
= sbrk (monsize
);
112 if (buffer
== (void *) -1) {
113 write (STDERR_FILENO
, MSG
, sizeof (MSG
) - 1);
116 froms
= sbrk (s_textsize
/ HASHFRACTION
);
117 if (froms
== (void *) -1) {
118 write (STDERR_FILENO
, MSG
, sizeof (MSG
) - 1);
122 tolimit
= s_textsize
* ARCDENSITY
/ 100;
123 if (tolimit
< MINARCS
) {
125 } else if (tolimit
> 65534) {
128 tos
= sbrk (tolimit
* sizeof (struct tostruct
));
129 if (tos
== (void *) -1) {
130 write (STDERR_FILENO
, MSG
, sizeof (MSG
) - 1);
138 ((struct phdr
*) buffer
)->lpc
= lowpc
;
139 ((struct phdr
*) buffer
)->hpc
= highpc
;
140 ((struct phdr
*) buffer
)->ncnt
= ssiz
;
141 monsize
-= sizeof (struct phdr
);
146 s_scale
= ((float) monsize
/ o
) * SCALE_1_TO_1
;
148 s_scale
= SCALE_1_TO_1
;
160 struct rawarc rawarc
;
162 const char *proffile
;
165 extern char **___Argv
;
169 if ((profdir
= getenv ("PROFDIR")) != NULL
) {
170 /* If PROFDIR contains a null value, no profiling output is produced. */
171 if (*profdir
== '\0') {
175 progname
= strrchr (___Argv
[0], '/');
176 if (progname
== NULL
)
177 progname
= ___Argv
[0];
181 sprintf (buf
, "%s/%ld.%s", profdir
, (long) getpid (), progname
);
184 proffile
= "gmon.out";
187 fd
= creat (proffile
, 0666);
193 fprintf (stderr
, "[mcleanup] sbuf %#x ssiz %d\n", sbuf
, ssiz
);
196 write (fd
, sbuf
, ssiz
);
197 endfrom
= s_textsize
/ (HASHFRACTION
* sizeof (*froms
));
198 for (fromindex
= 0; fromindex
< endfrom
; fromindex
++) {
199 if (froms
[fromindex
] == 0) {
202 frompc
= s_lowpc
+ (fromindex
* HASHFRACTION
* sizeof (*froms
));
203 for (toindex
= froms
[fromindex
];
205 toindex
= tos
[toindex
].link
) {
207 fprintf (stderr
, "[mcleanup] frompc %#x selfpc %#x count %d\n",
208 frompc
, tos
[toindex
].selfpc
, tos
[toindex
].count
);
210 rawarc
.raw_frompc
= (unsigned long) frompc
;
211 rawarc
.raw_selfpc
= (unsigned long) tos
[toindex
].selfpc
;
212 rawarc
.raw_count
= tos
[toindex
].count
;
213 write (fd
, &rawarc
, sizeof (rawarc
));
219 /* Solaris 2 libraries use _mcount. */
221 asm(".globl _mcount\n"
222 " .type _mcount, @function\n"
224 /* Save and restore the call-clobbered registers. */
228 " movl 12(%esp), %edx\n"
229 " movl 4(%ebp), %eax\n"
230 " call internal_mcount\n"
235 #elif defined __x86_64__
236 /* See GLIBC for additional information about this technique. */
237 asm(".globl _mcount\n"
238 " .type _mcount, @function\n"
240 /* The compiler calls _mcount after the prologue, and does not
241 save any of the registers. Therefore we must preserve all
242 seven registers which may contain function arguments. */
243 " subq $0x38, %rsp\n"
244 " movq %rax, (%rsp)\n"
245 " movq %rcx, 0x08(%rsp)\n"
246 " movq %rdx, 0x10(%rsp)\n"
247 " movq %rsi, 0x18(%rsp)\n"
248 " movq %rdi, 0x20(%rsp)\n"
249 " movq %r8, 0x28(%rsp)\n"
250 " movq %r9, 0x30(%rsp)\n"
251 /* Get SELFPC (pushed by the call to this function) and
252 FROMPCINDEX (via the frame pointer). */
253 " movq 0x38(%rsp), %rdi\n"
254 " movq 0x8(%rbp), %rsi\n"
255 " call internal_mcount\n"
256 /* Restore the saved registers. */
257 " movq 0x30(%rsp), %r9\n"
258 " movq 0x28(%rsp), %r8\n"
259 " movq 0x20(%rsp), %rdi\n"
260 " movq 0x18(%rsp), %rsi\n"
261 " movq 0x10(%rsp), %rdx\n"
262 " movq 0x08(%rsp), %rcx\n"
263 " movq (%rsp), %rax\n"
264 " addq $0x38, %rsp\n"
266 #elif defined __sparc__
267 /* The SPARC stack frame is only held together by the frame pointers
268 in the register windows. According to the SVR4 SPARC ABI
269 Supplement, Low Level System Information/Operating System
270 Interface/Software Trap Types, a type 3 trap will flush all of the
271 register windows to the stack, which will make it possible to walk
272 the frames and find the return addresses.
273 However, it seems awfully expensive to incur a trap (system
274 call) for every function call. It turns out that "call" simply puts
275 the return address in %o7 expecting the "save" in the procedure to
276 shift it into %i7; this means that before the "save" occurs, %o7
277 contains the address of the call to mcount, and %i7 still contains
278 the caller above that. The asm mcount here simply saves those
279 registers in argument registers and branches to internal_mcount,
280 simulating a call with arguments.
282 1) the branch to internal_mcount is hard coded; it should be
283 possible to tell asm to use the assembler-name of a symbol.
284 2) in theory, the function calling mcount could have saved %i7
285 somewhere and reused the register; in practice, I *think* this will
286 break longjmp (and maybe the debugger) but I'm not certain. (I take
287 some comfort in the knowledge that it will break the native mcount
289 3) if builtin_return_address worked, this could be portable.
290 However, it would really have to be optimized for arguments of 0
291 and 1 and do something like what we have here in order to avoid the
292 trap per function call performance hit.
293 4) the atexit and monsetup calls prevent this from simply
294 being a leaf routine that doesn't do a "save" (and would thus have
295 access to %o7 and %i7 directly) but the call to write() at the end
296 would have also prevented this.
298 -- [eichin:19920702.1107EST] */
299 asm(".global _mcount\n"
301 /* i7 == last ret, -> frompcindex. */
303 /* o7 == current ret, -> selfpc. */
305 " b,a internal_mcount\n");
309 internal_mcount (char *selfpc
, unsigned short *frompcindex
)
311 struct tostruct
*top
;
312 struct tostruct
*prevtop
;
314 static char already_setup
;
316 /* Only necessary without the Solaris CRTs or a proper gcrt1.o, otherwise
317 crtpg.o or gcrt1.o take care of that.
319 FIXME: What about _init vs. _start on sparc? */
320 #ifndef HAVE_SOLARIS_CRTS
327 /* <sys/vmparam.h> USERSTACK. */
328 monstartup ((char *) 0x8048000, etext
);
329 #elif defined __x86_64__
330 monstartup (NULL
, etext
);
331 #elif defined __sparc__
333 extern char _start
[];
336 monstartup (_start
< _init
? _start
: _init
, etext
);
341 #endif /* !HAVE_SOLARIS_CRTS */
342 /* Check that we are profiling and that we aren't recursively invoked. */
347 /* Check that frompcindex is a reasonable pc value. For example: signal
348 catchers get called from the stack, not from text space. too bad. */
349 frompcindex
= (unsigned short *) ((long) frompcindex
- (long) s_lowpc
);
350 if ((unsigned long) frompcindex
> s_textsize
) {
353 frompcindex
= &froms
[((long) frompcindex
) / (HASHFRACTION
* sizeof (*froms
))];
354 toindex
= *frompcindex
;
356 /* First time traversing this arc. */
357 toindex
= ++tos
[0].link
;
358 if (toindex
>= tolimit
) {
361 *frompcindex
= toindex
;
363 top
->selfpc
= selfpc
;
369 if (top
->selfpc
== selfpc
) {
370 /* arc at front of chain; usual case. */
374 /* Have to go looking down chain for it. Top points to what we are
375 looking at, prevtop points to previous top. We know it is not at the
376 head of the chain. */
377 for (; /* goto done */; ) {
378 if (top
->link
== 0) {
379 /* top is end of the chain and none of the chain had top->selfpc ==
380 selfpc, so we allocate a new tostruct and link it to the head of
382 toindex
= ++tos
[0].link
;
383 if (toindex
>= tolimit
) {
387 top
->selfpc
= selfpc
;
389 top
->link
= *frompcindex
;
390 *frompcindex
= toindex
;
393 /* Otherwise, check the next arc on the chain. */
395 top
= &tos
[top
->link
];
396 if (top
->selfpc
== selfpc
) {
397 /* There it is. Increment its count move it to the head of the
400 toindex
= prevtop
->link
;
401 prevtop
->link
= top
->link
;
402 top
->link
= *frompcindex
;
403 *frompcindex
= toindex
;
410 /* ... and fall through. */
412 /* Normal return restores saved registers. */
416 /* Halt further profiling. */
419 #define TOLIMIT "mcount: tos overflow\n"
420 write (STDERR_FILENO
, TOLIMIT
, sizeof (TOLIMIT
) - 1);
424 /* Control profiling. Profiling is what mcount checks to see if all the
425 data structures are ready. */
427 moncontrol (int mode
)
431 profil ((unsigned short *) (sbuf
+ sizeof (struct phdr
)),
432 ssiz
- sizeof (struct phdr
), (size_t) s_lowpc
, s_scale
);
436 profil ((unsigned short *) 0, 0, 0, 0);