]> git.ipfire.org Git - thirdparty/glibc.git/blame - gmon/gmon.c
* nss/nsswitch.c (__nss_lookup_function): En/Decrypt cached
[thirdparty/glibc.git] / gmon / gmon.c
CommitLineData
11c981a9
RM
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.
11c981a9
RM
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 */
11c981a9
RM
29#include <sys/param.h>
30#include <sys/time.h>
31#include <sys/gmon.h>
b20e47cb 32#include <sys/gmon_out.h>
5ae9d168 33#include <sys/uio.h>
11c981a9 34
3996f34b 35#include <errno.h>
11c981a9
RM
36#include <stdio.h>
37#include <fcntl.h>
b20e47cb
RM
38#include <unistd.h>
39
40#include <stdio.h>
11c981a9
RM
41#include <stdlib.h>
42#include <string.h>
43#include <unistd.h>
66539a73 44#include <libc-internal.h>
fbb37d25 45#include <not-cancel.h>
d68171ed 46
8dcc6a3f
UD
47#ifdef USE_IN_LIBIO
48# include <wchar.h>
49#endif
50
100351c3
UD
51/* Head of basic-block list or NULL. */
52struct __bb *__bb_head attribute_hidden;
b20e47cb 53
0e47dbd0 54struct gmonparam _gmonparam attribute_hidden = { GMON_PROF_OFF };
11c981a9 55
b20e47cb
RM
56/*
57 * See profil(2) where this is described:
58 */
11c981a9 59static int s_scale;
11c981a9
RM
60#define SCALE_1_TO_1 0x10000L
61
fbb37d25 62#define ERR(s) write_not_cancel (STDERR_FILENO, s, sizeof (s) - 1)
b20e47cb 63
79937577
UD
64void moncontrol (int mode);
65void __moncontrol (int mode);
66static void write_hist (int fd) internal_function;
67static void write_call_graph (int fd) internal_function;
68static void write_bb_counts (int fd) internal_function;
11336c16 69
b20e47cb
RM
70/*
71 * Control profiling
72 * profiling is what mcount checks to see if
73 * all the data structures are ready.
74 */
75void
3996f34b 76__moncontrol (mode)
a68b0d31 77 int mode;
b20e47cb
RM
78{
79 struct gmonparam *p = &_gmonparam;
80
14e9dd67
UD
81 /* Don't change the state if we ran into an error. */
82 if (p->state == GMON_PROF_ERROR)
83 return;
84
b20e47cb
RM
85 if (mode)
86 {
87 /* start */
9a0a462c 88 __profil((void *) p->kcount, p->kcountsize, p->lowpc, s_scale);
b20e47cb
RM
89 p->state = GMON_PROF_ON;
90 }
91 else
92 {
93 /* stop */
9a0a462c 94 __profil(NULL, 0, 0, 0);
b20e47cb
RM
95 p->state = GMON_PROF_OFF;
96 }
97}
69173865 98weak_alias (__moncontrol, moncontrol)
11c981a9 99
11c981a9
RM
100
101void
3996f34b 102__monstartup (lowpc, highpc)
a68b0d31
UD
103 u_long lowpc;
104 u_long highpc;
11c981a9 105{
b20e47cb
RM
106 register int o;
107 char *cp;
108 struct gmonparam *p = &_gmonparam;
109
110 /*
111 * round lowpc and highpc to multiples of the density we're using
112 * so the rest of the scaling (here and in gprof) stays in ints.
113 */
114 p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER));
115 p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER));
116 p->textsize = p->highpc - p->lowpc;
69ac9d07 117 p->kcountsize = ROUNDUP(p->textsize / HISTFRACTION, sizeof(*p->froms));
b20e47cb
RM
118 p->hashfraction = HASHFRACTION;
119 p->log_hashfraction = -1;
9a0a462c
UD
120 /* The following test must be kept in sync with the corresponding
121 test in mcount.c. */
b20e47cb
RM
122 if ((HASHFRACTION & (HASHFRACTION - 1)) == 0) {
123 /* if HASHFRACTION is a power of two, mcount can use shifting
124 instead of integer division. Precompute shift amount. */
125 p->log_hashfraction = ffs(p->hashfraction * sizeof(*p->froms)) - 1;
126 }
127 p->fromssize = p->textsize / HASHFRACTION;
128 p->tolimit = p->textsize * ARCDENSITY / 100;
129 if (p->tolimit < MINARCS)
130 p->tolimit = MINARCS;
131 else if (p->tolimit > MAXARCS)
132 p->tolimit = MAXARCS;
133 p->tossize = p->tolimit * sizeof(struct tostruct);
11c981a9 134
0413b54c 135 cp = calloc (p->kcountsize + p->fromssize + p->tossize, 1);
b20e47cb
RM
136 if (! cp)
137 {
14e9dd67
UD
138 ERR("monstartup: out of memory\n");
139 p->tos = NULL;
140 p->state = GMON_PROF_ERROR;
b20e47cb
RM
141 return;
142 }
b20e47cb
RM
143 p->tos = (struct tostruct *)cp;
144 cp += p->tossize;
be5b0fbc 145 p->kcount = (HISTCOUNTER *)cp;
b20e47cb 146 cp += p->kcountsize;
be5b0fbc 147 p->froms = (ARCINDEX *)cp;
11c981a9 148
b20e47cb
RM
149 p->tos[0].link = 0;
150
151 o = p->highpc - p->lowpc;
d68171ed 152 if (p->kcountsize < (u_long) o)
b20e47cb 153 {
11c981a9 154#ifndef hp300
b20e47cb
RM
155 s_scale = ((float)p->kcountsize / o ) * SCALE_1_TO_1;
156#else
157 /* avoid floating point operations */
158 int quot = o / p->kcountsize;
159
160 if (quot >= 0x10000)
161 s_scale = 1;
162 else if (quot >= 0x100)
163 s_scale = 0x10000 / quot;
164 else if (o >= 0x800000)
165 s_scale = 0x1000000 / (o / (p->kcountsize >> 8));
166 else
167 s_scale = 0x1000000 / ((o << 8) / p->kcountsize);
11c981a9 168#endif
b20e47cb
RM
169 } else
170 s_scale = SCALE_1_TO_1;
11c981a9 171
3996f34b 172 __moncontrol(1);
11c981a9 173}
1ab18a5b 174weak_alias (__monstartup, monstartup)
11c981a9 175
b20e47cb
RM
176
177static void
dfd2257a 178internal_function
a68b0d31
UD
179write_hist (fd)
180 int fd;
11c981a9 181{
5ae9d168
UD
182 u_char tag = GMON_TAG_TIME_HIST;
183 struct gmon_hist_hdr thdr __attribute__ ((aligned (__alignof__ (char *))));
11c981a9 184
b20e47cb
RM
185 if (_gmonparam.kcountsize > 0)
186 {
5ae9d168
UD
187 struct iovec iov[3] =
188 {
189 { &tag, sizeof (tag) },
190 { &thdr, sizeof (struct gmon_hist_hdr) },
191 { _gmonparam.kcount, _gmonparam.kcountsize }
192 };
193
194 *(char **) thdr.low_pc = (char *) _gmonparam.lowpc;
195 *(char **) thdr.high_pc = (char *) _gmonparam.highpc;
3996f34b
UD
196 *(int32_t *) thdr.hist_size = (_gmonparam.kcountsize
197 / sizeof (HISTCOUNTER));
198 *(int32_t *) thdr.prof_rate = __profile_frequency ();
5ae9d168 199 strncpy (thdr.dimen, "seconds", sizeof (thdr.dimen));
b20e47cb 200 thdr.dimen_abbrev = 's';
11c981a9 201
fbb37d25 202 writev_not_cancel_no_status (fd, iov, 3);
b20e47cb 203 }
11c981a9
RM
204}
205
b20e47cb
RM
206
207static void
dfd2257a 208internal_function
a68b0d31
UD
209write_call_graph (fd)
210 int fd;
11c981a9 211{
e7fd8a39 212#define NARCS_PER_WRITEV 32
5ae9d168 213 u_char tag = GMON_TAG_CG_ARC;
e7fd8a39 214 struct gmon_cg_arc_record raw_arc[NARCS_PER_WRITEV]
5ae9d168 215 __attribute__ ((aligned (__alignof__ (char*))));
be5b0fbc 216 ARCINDEX from_index, to_index;
eb64f8cb 217 u_long from_len;
b20e47cb 218 u_long frompc;
e7fd8a39
UD
219 struct iovec iov[2 * NARCS_PER_WRITEV];
220 int nfilled;
b20e47cb 221
e7fd8a39 222 for (nfilled = 0; nfilled < NARCS_PER_WRITEV; ++nfilled)
5ae9d168 223 {
e7fd8a39
UD
224 iov[2 * nfilled].iov_base = &tag;
225 iov[2 * nfilled].iov_len = sizeof (tag);
5ae9d168 226
e7fd8a39
UD
227 iov[2 * nfilled + 1].iov_base = &raw_arc[nfilled];
228 iov[2 * nfilled + 1].iov_len = sizeof (struct gmon_cg_arc_record);
229 }
230
231 nfilled = 0;
5ae9d168 232 from_len = _gmonparam.fromssize / sizeof (*_gmonparam.froms);
b20e47cb
RM
233 for (from_index = 0; from_index < from_len; ++from_index)
234 {
235 if (_gmonparam.froms[from_index] == 0)
236 continue;
237
238 frompc = _gmonparam.lowpc;
239 frompc += (from_index * _gmonparam.hashfraction
5ae9d168 240 * sizeof (*_gmonparam.froms));
b20e47cb
RM
241 for (to_index = _gmonparam.froms[from_index];
242 to_index != 0;
243 to_index = _gmonparam.tos[to_index].link)
244 {
328c5f65
UD
245 struct arc
246 {
247 char *frompc;
248 char *selfpc;
249 int32_t count;
250 }
251 arc;
252
253 arc.frompc = (char *) frompc;
254 arc.selfpc = (char *) _gmonparam.tos[to_index].selfpc;
255 arc.count = _gmonparam.tos[to_index].count;
256 memcpy (raw_arc + nfilled, &arc, sizeof (raw_arc [0]));
e7fd8a39
UD
257
258 if (++nfilled == NARCS_PER_WRITEV)
3e5f5557 259 {
fbb37d25 260 writev_not_cancel_no_status (fd, iov, 2 * nfilled);
3e5f5557
UD
261 nfilled = 0;
262 }
11c981a9 263 }
b20e47cb 264 }
e7fd8a39 265 if (nfilled > 0)
fbb37d25 266 writev_not_cancel_no_status (fd, iov, 2 * nfilled);
11c981a9
RM
267}
268
b20e47cb
RM
269
270static void
dfd2257a 271internal_function
a68b0d31
UD
272write_bb_counts (fd)
273 int fd;
11c981a9 274{
b20e47cb 275 struct __bb *grp;
5ae9d168 276 u_char tag = GMON_TAG_BB_COUNT;
3e5f5557
UD
277 size_t ncounts;
278 size_t i;
b20e47cb 279
5ae9d168
UD
280 struct iovec bbhead[2] =
281 {
282 { &tag, sizeof (tag) },
283 { &ncounts, sizeof (ncounts) }
284 };
3e5f5557
UD
285 struct iovec bbbody[8];
286 size_t nfilled;
5ae9d168 287
3e5f5557
UD
288 for (i = 0; i < (sizeof (bbbody) / sizeof (bbbody[0])); i += 2)
289 {
290 bbbody[i].iov_len = sizeof (grp->addresses[0]);
291 bbbody[i + 1].iov_len = sizeof (grp->counts[0]);
292 }
5ae9d168 293
b20e47cb
RM
294 /* Write each group of basic-block info (all basic-blocks in a
295 compilation unit form a single group). */
296
297 for (grp = __bb_head; grp; grp = grp->next)
298 {
299 ncounts = grp->ncounts;
fbb37d25 300 writev_not_cancel_no_status (fd, bbhead, 2);
e7fd8a39 301 for (nfilled = i = 0; i < ncounts; ++i)
b20e47cb 302 {
3e5f5557
UD
303 if (nfilled > (sizeof (bbbody) / sizeof (bbbody[0])) - 2)
304 {
fbb37d25 305 writev_not_cancel_no_status (fd, bbbody, nfilled);
3e5f5557
UD
306 nfilled = 0;
307 }
308
309 bbbody[nfilled++].iov_base = (char *) &grp->addresses[i];
310 bbbody[nfilled++].iov_base = &grp->counts[i];
b20e47cb 311 }
e7fd8a39 312 if (nfilled > 0)
fbb37d25 313 writev_not_cancel_no_status (fd, bbbody, nfilled);
b20e47cb 314 }
11c981a9
RM
315}
316
317
0413b54c
UD
318static void
319write_gmon (void)
b20e47cb 320{
5ae9d168 321 struct gmon_hdr ghdr __attribute__ ((aligned (__alignof__ (int))));
14c44e2e
UD
322 int fd = -1;
323 char *env;
b20e47cb 324
b7eb7b0f
UD
325#ifndef O_NOFOLLOW
326# define O_NOFOLLOW 0
327#endif
328
14c44e2e
UD
329 env = getenv ("GMON_OUT_PREFIX");
330 if (env != NULL && !__libc_enable_secure)
b20e47cb 331 {
14c44e2e
UD
332 size_t len = strlen (env);
333 char buf[len + 20];
4c5b09ed 334 __snprintf (buf, sizeof (buf), "%s.%u", env, __getpid ());
fbb37d25 335 fd = open_not_cancel (buf, O_CREAT|O_TRUNC|O_WRONLY|O_NOFOLLOW, 0666);
14c44e2e
UD
336 }
337
338 if (fd == -1)
339 {
fbb37d25
UD
340 fd = open_not_cancel ("gmon.out", O_CREAT|O_TRUNC|O_WRONLY|O_NOFOLLOW,
341 0666);
14c44e2e
UD
342 if (fd < 0)
343 {
344 char buf[300];
345 int errnum = errno;
df6f8969 346 __fxprintf (NULL, "_mcleanup: gmon.out: %s\n",
df6f8969 347 __strerror_r (errnum, buf, sizeof buf));
14c44e2e
UD
348 return;
349 }
b20e47cb
RM
350 }
351
352 /* write gmon.out header: */
3996f34b 353 memset (&ghdr, '\0', sizeof (struct gmon_hdr));
5ae9d168 354 memcpy (&ghdr.cookie[0], GMON_MAGIC, sizeof (ghdr.cookie));
3996f34b 355 *(int32_t *) ghdr.version = GMON_VERSION;
fbb37d25 356 write_not_cancel (fd, &ghdr, sizeof (struct gmon_hdr));
b20e47cb
RM
357
358 /* write PC histogram: */
5ae9d168 359 write_hist (fd);
b20e47cb
RM
360
361 /* write call-graph: */
5ae9d168 362 write_call_graph (fd);
b20e47cb
RM
363
364 /* write basic-block execution counts: */
5ae9d168 365 write_bb_counts (fd);
b20e47cb 366
fbb37d25 367 close_not_cancel_no_status (fd);
0413b54c
UD
368}
369
370
371void
372__write_profiling (void)
373{
374 int save = _gmonparam.state;
375 _gmonparam.state = GMON_PROF_OFF;
376 if (save == GMON_PROF_ON)
377 write_gmon ();
378 _gmonparam.state = save;
379}
f5bf21a7
UD
380#ifndef SHARED
381/* This symbol isn't used anywhere in the DSO and it is not exported.
382 This would normally mean it should be removed to get the same API
383 in static libraries. But since profiling is special in static libs
384 anyway we keep it. But not when building the DSO since some
385 quality assurance tests will otherwise trigger. */
0413b54c 386weak_alias (__write_profiling, write_profiling)
f5bf21a7 387#endif
0413b54c
UD
388
389
390void
391_mcleanup (void)
392{
14e9dd67 393 __moncontrol (0);
0413b54c 394
14e9dd67 395 if (_gmonparam.state != GMON_PROF_ERROR)
0413b54c
UD
396 write_gmon ();
397
14e9dd67 398 /* free the memory. */
72e6cdfa 399 free (_gmonparam.tos);
b20e47cb 400}