Fix mtrace stack overflow bug
[kopensolaris-gnu/glibc.git] / gmon / gmon.c
1 /*-
2  * Copyright (c) 1983, 1992, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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  * 4. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 #include <sys/param.h>
30 #include <sys/time.h>
31 #include <sys/gmon.h>
32 #include <sys/gmon_out.h>
33 #include <sys/uio.h>
34
35 #include <errno.h>
36 #include <stdio.h>
37 #include <fcntl.h>
38 #include <unistd.h>
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <unistd.h>
44 #include <libc-internal.h>
45 #include <not-cancel.h>
46
47 #ifdef USE_IN_LIBIO
48 # include <wchar.h>
49 #endif
50
51 /*  Head of basic-block list or NULL. */
52 struct __bb *__bb_head attribute_hidden;
53
54 struct gmonparam _gmonparam attribute_hidden = { GMON_PROF_OFF };
55
56 /*
57  * See profil(2) where this is described:
58  */
59 static int      s_scale;
60 #define         SCALE_1_TO_1    0x10000L
61
62 #undef ERR
63 #define ERR(s) write_not_cancel (STDERR_FILENO, s, sizeof (s) - 1)
64
65 void moncontrol (int mode);
66 void __moncontrol (int mode);
67 static void write_hist (int fd) internal_function;
68 static void write_call_graph (int fd) internal_function;
69 static void write_bb_counts (int fd) internal_function;
70
71 /*
72  * Control profiling
73  *      profiling is what mcount checks to see if
74  *      all the data structures are ready.
75  */
76 void
77 __moncontrol (mode)
78      int mode;
79 {
80   struct gmonparam *p = &_gmonparam;
81
82   /* Don't change the state if we ran into an error.  */
83   if (p->state == GMON_PROF_ERROR)
84     return;
85
86   if (mode)
87     {
88       /* start */
89       __profil((void *) p->kcount, p->kcountsize, p->lowpc, s_scale);
90       p->state = GMON_PROF_ON;
91     }
92   else
93     {
94       /* stop */
95       __profil(NULL, 0, 0, 0);
96       p->state = GMON_PROF_OFF;
97     }
98 }
99 weak_alias (__moncontrol, moncontrol)
100
101
102 void
103 __monstartup (lowpc, highpc)
104      u_long lowpc;
105      u_long highpc;
106 {
107   register int o;
108   char *cp;
109   struct gmonparam *p = &_gmonparam;
110
111   /*
112    * round lowpc and highpc to multiples of the density we're using
113    * so the rest of the scaling (here and in gprof) stays in ints.
114    */
115   p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER));
116   p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER));
117   p->textsize = p->highpc - p->lowpc;
118   p->kcountsize = ROUNDUP(p->textsize / HISTFRACTION, sizeof(*p->froms));
119   p->hashfraction = HASHFRACTION;
120   p->log_hashfraction = -1;
121   /* The following test must be kept in sync with the corresponding
122      test in mcount.c.  */
123   if ((HASHFRACTION & (HASHFRACTION - 1)) == 0) {
124       /* if HASHFRACTION is a power of two, mcount can use shifting
125          instead of integer division.  Precompute shift amount. */
126       p->log_hashfraction = ffs(p->hashfraction * sizeof(*p->froms)) - 1;
127   }
128   p->fromssize = p->textsize / HASHFRACTION;
129   p->tolimit = p->textsize * ARCDENSITY / 100;
130   if (p->tolimit < MINARCS)
131     p->tolimit = MINARCS;
132   else if (p->tolimit > MAXARCS)
133     p->tolimit = MAXARCS;
134   p->tossize = p->tolimit * sizeof(struct tostruct);
135
136   cp = calloc (p->kcountsize + p->fromssize + p->tossize, 1);
137   if (! cp)
138     {
139       ERR("monstartup: out of memory\n");
140       p->tos = NULL;
141       p->state = GMON_PROF_ERROR;
142       return;
143     }
144   p->tos = (struct tostruct *)cp;
145   cp += p->tossize;
146   p->kcount = (HISTCOUNTER *)cp;
147   cp += p->kcountsize;
148   p->froms = (ARCINDEX *)cp;
149
150   p->tos[0].link = 0;
151
152   o = p->highpc - p->lowpc;
153   if (p->kcountsize < (u_long) o)
154     {
155 #ifndef hp300
156       s_scale = ((float)p->kcountsize / o ) * SCALE_1_TO_1;
157 #else
158       /* avoid floating point operations */
159       int quot = o / p->kcountsize;
160
161       if (quot >= 0x10000)
162         s_scale = 1;
163       else if (quot >= 0x100)
164         s_scale = 0x10000 / quot;
165       else if (o >= 0x800000)
166         s_scale = 0x1000000 / (o / (p->kcountsize >> 8));
167       else
168         s_scale = 0x1000000 / ((o << 8) / p->kcountsize);
169 #endif
170     } else
171       s_scale = SCALE_1_TO_1;
172
173   __moncontrol(1);
174 }
175 weak_alias (__monstartup, monstartup)
176
177
178 static void
179 internal_function
180 write_hist (fd)
181      int fd;
182 {
183   u_char tag = GMON_TAG_TIME_HIST;
184   struct gmon_hist_hdr thdr __attribute__ ((aligned (__alignof__ (char *))));
185
186   if (_gmonparam.kcountsize > 0)
187     {
188       struct iovec iov[3] =
189         {
190           { &tag, sizeof (tag) },
191           { &thdr, sizeof (struct gmon_hist_hdr) },
192           { _gmonparam.kcount, _gmonparam.kcountsize }
193         };
194
195       *(char **) thdr.low_pc = (char *) _gmonparam.lowpc;
196       *(char **) thdr.high_pc = (char *) _gmonparam.highpc;
197       *(int32_t *) thdr.hist_size = (_gmonparam.kcountsize
198                                      / sizeof (HISTCOUNTER));
199       *(int32_t *) thdr.prof_rate = __profile_frequency ();
200       strncpy (thdr.dimen, "seconds", sizeof (thdr.dimen));
201       thdr.dimen_abbrev = 's';
202
203       writev_not_cancel_no_status (fd, iov, 3);
204     }
205 }
206
207
208 static void
209 internal_function
210 write_call_graph (fd)
211      int fd;
212 {
213 #define NARCS_PER_WRITEV        32
214   u_char tag = GMON_TAG_CG_ARC;
215   struct gmon_cg_arc_record raw_arc[NARCS_PER_WRITEV]
216     __attribute__ ((aligned (__alignof__ (char*))));
217   ARCINDEX from_index, to_index;
218   u_long from_len;
219   u_long frompc;
220   struct iovec iov[2 * NARCS_PER_WRITEV];
221   int nfilled;
222
223   for (nfilled = 0; nfilled < NARCS_PER_WRITEV; ++nfilled)
224     {
225       iov[2 * nfilled].iov_base = &tag;
226       iov[2 * nfilled].iov_len = sizeof (tag);
227
228       iov[2 * nfilled + 1].iov_base = &raw_arc[nfilled];
229       iov[2 * nfilled + 1].iov_len = sizeof (struct gmon_cg_arc_record);
230     }
231
232   nfilled = 0;
233   from_len = _gmonparam.fromssize / sizeof (*_gmonparam.froms);
234   for (from_index = 0; from_index < from_len; ++from_index)
235     {
236       if (_gmonparam.froms[from_index] == 0)
237         continue;
238
239       frompc = _gmonparam.lowpc;
240       frompc += (from_index * _gmonparam.hashfraction
241                  * sizeof (*_gmonparam.froms));
242       for (to_index = _gmonparam.froms[from_index];
243            to_index != 0;
244            to_index = _gmonparam.tos[to_index].link)
245         {
246           struct arc
247             {
248               char *frompc;
249               char *selfpc;
250               int32_t count;
251             }
252           arc;
253
254           arc.frompc = (char *) frompc;
255           arc.selfpc = (char *) _gmonparam.tos[to_index].selfpc;
256           arc.count  = _gmonparam.tos[to_index].count;
257           memcpy (raw_arc + nfilled, &arc, sizeof (raw_arc [0]));
258
259           if (++nfilled == NARCS_PER_WRITEV)
260             {
261               writev_not_cancel_no_status (fd, iov, 2 * nfilled);
262               nfilled = 0;
263             }
264         }
265     }
266   if (nfilled > 0)
267     writev_not_cancel_no_status (fd, iov, 2 * nfilled);
268 }
269
270
271 static void
272 internal_function
273 write_bb_counts (fd)
274      int fd;
275 {
276   struct __bb *grp;
277   u_char tag = GMON_TAG_BB_COUNT;
278   size_t ncounts;
279   size_t i;
280
281   struct iovec bbhead[2] =
282     {
283       { &tag, sizeof (tag) },
284       { &ncounts, sizeof (ncounts) }
285     };
286   struct iovec bbbody[8];
287   size_t nfilled;
288
289   for (i = 0; i < (sizeof (bbbody) / sizeof (bbbody[0])); i += 2)
290     {
291       bbbody[i].iov_len = sizeof (grp->addresses[0]);
292       bbbody[i + 1].iov_len = sizeof (grp->counts[0]);
293     }
294
295   /* Write each group of basic-block info (all basic-blocks in a
296      compilation unit form a single group). */
297
298   for (grp = __bb_head; grp; grp = grp->next)
299     {
300       ncounts = grp->ncounts;
301       writev_not_cancel_no_status (fd, bbhead, 2);
302       for (nfilled = i = 0; i < ncounts; ++i)
303         {
304           if (nfilled > (sizeof (bbbody) / sizeof (bbbody[0])) - 2)
305             {
306               writev_not_cancel_no_status (fd, bbbody, nfilled);
307               nfilled = 0;
308             }
309
310           bbbody[nfilled++].iov_base = (char *) &grp->addresses[i];
311           bbbody[nfilled++].iov_base = &grp->counts[i];
312         }
313       if (nfilled > 0)
314         writev_not_cancel_no_status (fd, bbbody, nfilled);
315     }
316 }
317
318
319 static void
320 write_gmon (void)
321 {
322     struct gmon_hdr ghdr __attribute__ ((aligned (__alignof__ (int))));
323     int fd = -1;
324     char *env;
325
326 #ifndef O_NOFOLLOW
327 # define O_NOFOLLOW     0
328 #endif
329
330     env = getenv ("GMON_OUT_PREFIX");
331     if (env != NULL && !__libc_enable_secure)
332       {
333         size_t len = strlen (env);
334         char buf[len + 20];
335         __snprintf (buf, sizeof (buf), "%s.%u", env, __getpid ());
336         fd = open_not_cancel (buf, O_CREAT|O_TRUNC|O_WRONLY|O_NOFOLLOW, 0666);
337       }
338
339     if (fd == -1)
340       {
341         fd = open_not_cancel ("gmon.out", O_CREAT|O_TRUNC|O_WRONLY|O_NOFOLLOW,
342                               0666);
343         if (fd < 0)
344           {
345             char buf[300];
346             int errnum = errno;
347             __fxprintf (NULL, "_mcleanup: gmon.out: %s\n",
348                         __strerror_r (errnum, buf, sizeof buf));
349             return;
350           }
351       }
352
353     /* write gmon.out header: */
354     memset (&ghdr, '\0', sizeof (struct gmon_hdr));
355     memcpy (&ghdr.cookie[0], GMON_MAGIC, sizeof (ghdr.cookie));
356     *(int32_t *) ghdr.version = GMON_VERSION;
357     write_not_cancel (fd, &ghdr, sizeof (struct gmon_hdr));
358
359     /* write PC histogram: */
360     write_hist (fd);
361
362     /* write call-graph: */
363     write_call_graph (fd);
364
365     /* write basic-block execution counts: */
366     write_bb_counts (fd);
367
368     close_not_cancel_no_status (fd);
369 }
370
371
372 void
373 __write_profiling (void)
374 {
375   int save = _gmonparam.state;
376   _gmonparam.state = GMON_PROF_OFF;
377   if (save == GMON_PROF_ON)
378     write_gmon ();
379   _gmonparam.state = save;
380 }
381 #ifndef SHARED
382 /* This symbol isn't used anywhere in the DSO and it is not exported.
383    This would normally mean it should be removed to get the same API
384    in static libraries.  But since profiling is special in static libs
385    anyway we keep it.  But not when building the DSO since some
386    quality assurance tests will otherwise trigger.  */
387 weak_alias (__write_profiling, write_profiling)
388 #endif
389
390
391 void
392 _mcleanup (void)
393 {
394   __moncontrol (0);
395
396   if (_gmonparam.state != GMON_PROF_ERROR)
397     write_gmon ();
398
399   /* free the memory. */
400   if (_gmonparam.tos != NULL)
401     free (_gmonparam.tos);
402 }