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