summaryrefslogtreecommitdiff
path: root/gmon
diff options
context:
space:
mode:
Diffstat (limited to 'gmon')
-rw-r--r--gmon/Makefile93
-rw-r--r--gmon/bb_exit_func.c74
-rw-r--r--gmon/bb_init_func.c53
-rw-r--r--gmon/gmon.c80
-rw-r--r--gmon/profil.c2
-rw-r--r--gmon/sprofil.c2
-rw-r--r--gmon/sys/gmon.h30
-rw-r--r--gmon/sys/gmon_out.h2
-rw-r--r--gmon/sys/profil.h2
-rw-r--r--gmon/tst-gmon-gprof.sh60
-rw-r--r--gmon/tst-gmon-pie.c1
-rw-r--r--gmon/tst-gmon-static-gprof.sh62
-rw-r--r--gmon/tst-gmon-static-pie.c1
-rw-r--r--gmon/tst-gmon-static.c1
-rw-r--r--gmon/tst-gmon.c50
-rw-r--r--gmon/tst-sprofil.c2
16 files changed, 333 insertions, 182 deletions
diff --git a/gmon/Makefile b/gmon/Makefile
index abb96d70d2..d94593c9d8 100644
--- a/gmon/Makefile
+++ b/gmon/Makefile
@@ -1,4 +1,4 @@
-# Copyright (C) 1995-2016 Free Software Foundation, Inc.
+# Copyright (C) 1995-2018 Free Software Foundation, Inc.
# This file is part of the GNU C Library.
# The GNU C Library is free software; you can redistribute it and/or
@@ -23,11 +23,9 @@ subdir := gmon
include ../Makeconfig
headers := sys/gmon.h sys/gmon_out.h sys/profil.h
-routines := gmon mcount profil sprofil bb_init_func bb_exit_func prof-freq
+routines := gmon mcount profil sprofil prof-freq
-elide-routines.os = bb_init_func bb_exit_func
-
-tests = tst-sprofil
+tests = tst-sprofil tst-gmon
ifeq ($(build-profile),yes)
tests += tst-profile-static
tests-static += tst-profile-static
@@ -35,9 +33,54 @@ tests-static += tst-profile-static
LDFLAGS-tst-profile-static = -profile
endif
+tests += tst-gmon-static
+tests-static += tst-gmon-static
+
+ifeq (yesyes,$(have-fpie)$(build-shared))
+tests += tst-gmon-pie
+tests-pie += tst-gmon-pie
+ifeq (yes,$(enable-static-pie))
+tests += tst-gmon-static-pie
+tests-static += tst-gmon-static-pie
+endif
+endif
+
# The mcount code won't work without a frame pointer.
CFLAGS-mcount.c := -fno-omit-frame-pointer
+CFLAGS-tst-gmon.c := -fno-omit-frame-pointer -pg
+tst-gmon-no-pie = yes
+CRT-tst-gmon := $(csu-objpfx)gcrt1.o
+tst-gmon-ENV := GMON_OUT_PREFIX=$(objpfx)tst-gmon.data
+ifeq ($(run-built-tests),yes)
+tests-special += $(objpfx)tst-gmon-gprof.out
+endif
+
+CFLAGS-tst-gmon-static.c := $(PIE-ccflag) -fno-omit-frame-pointer -pg
+CRT-tst-gmon-static := $(csu-objpfx)gcrt1.o
+tst-gmon-static-no-pie = yes
+tst-gmon-static-ENV := GMON_OUT_PREFIX=$(objpfx)tst-gmon-static.data
+ifeq ($(run-built-tests),yes)
+tests-special += $(objpfx)tst-gmon-static-gprof.out
+endif
+
+CFLAGS-tst-gmon-pie.c := $(PIE-ccflag) -fno-omit-frame-pointer -pg
+CRT-tst-gmon-pie := $(csu-objpfx)gcrt1.o
+tst-gmon-pie-ENV := GMON_OUT_PREFIX=$(objpfx)tst-gmon-pie.data
+ifeq ($(run-built-tests),yes)
+tests-special += $(objpfx)tst-gmon-pie-gprof.out
+endif
+
+ifeq (yes,$(enable-static-pie))
+CFLAGS-tst-gmon-static-pie.c := $(PIE-ccflag) -fno-omit-frame-pointer -pg
+CRT-tst-gmon-static-pie := $(csu-objpfx)grcrt1.o
+tst-gmon-static-pie-ENV := GMON_OUT_PREFIX=$(objpfx)tst-gmon-static-pie.data
+ifeq ($(run-built-tests),yes)
+tests-special += $(objpfx)tst-gmon-static-pie-gprof.out
+endif
+endif
+
+
include ../Rules
# We cannot compile mcount.c with -pg because that would
@@ -45,7 +88,7 @@ include ../Rules
# On systems where `profil' is not a system call, the same
# problem exists for the internal functions in profil.c.
-noprof := mcount
+noprof := mcount $(sysdep_noprof)
ifeq (,$(filter profil,$(unix-syscalls)))
noprof += profil sprofil
endif
@@ -53,3 +96,41 @@ endif
$(noprof:%=$(objpfx)%.op): %.op: %.o
rm -f $@
ln $< $@
+
+# GMON_OUTPUT_PREFIX only sets the output prefix. The actual file
+# name contains the PID as well.
+$(objpfx)tst-gmon.out: clean-tst-gmon-data
+clean-tst-gmon-data:
+ rm -f $(objpfx)tst-gmon.data.*
+
+$(objpfx)tst-gmon-gprof.out: tst-gmon-gprof.sh $(objpfx)tst-gmon.out
+ $(SHELL) $< $(GPROF) $(objpfx)tst-gmon $(objpfx)tst-gmon.data.* > $@; \
+ $(evaluate-test)
+
+$(objpfx)tst-gmon-static.out: clean-tst-gmon-static-data
+clean-tst-gmon-static-data:
+ rm -f $(objpfx)tst-gmon-static.data.*
+
+$(objpfx)tst-gmon-static-gprof.out: tst-gmon-static-gprof.sh \
+ $(objpfx)tst-gmon-static.out
+ $(SHELL) $< $(GPROF) $(objpfx)tst-gmon-static \
+ $(objpfx)tst-gmon-static.data.* > $@; \
+ $(evaluate-test)
+
+$(objpfx)tst-gmon-pie.out: clean-tst-gmon-pie-data
+clean-tst-gmon-pie-data:
+ rm -f $(objpfx)tst-gmon-pie.data.*
+
+$(objpfx)tst-gmon-pie-gprof.out: tst-gmon-gprof.sh $(objpfx)tst-gmon-pie.out
+ $(SHELL) $< $(GPROF) $(objpfx)tst-gmon-pie $(objpfx)tst-gmon-pie.data.* > $@; \
+ $(evaluate-test)
+
+$(objpfx)tst-gmon-static-pie.out: clean-tst-gmon-static-pie-data
+clean-tst-gmon-static-pie-data:
+ rm -f $(objpfx)tst-gmon-static-pie.data.*
+
+$(objpfx)tst-gmon-static-pie-gprof.out: tst-gmon-static-gprof.sh \
+ $(objpfx)tst-gmon-static-pie.out
+ $(SHELL) $< $(GPROF) $(objpfx)tst-gmon-static-pie \
+ $(objpfx)tst-gmon-static-pie.data.* > $@; \
+ $(evaluate-test)
diff --git a/gmon/bb_exit_func.c b/gmon/bb_exit_func.c
deleted file mode 100644
index d9c91bc282..0000000000
--- a/gmon/bb_exit_func.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/* Copyright (C) 1996-2016 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by David Mosberger (davidm@cs.arizona.edu).
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, see
- <http://www.gnu.org/licenses/>. */
-
-/* __bb_exit_func() dumps all the basic-block statistics linked into
- the __bb_head chain to .d files. */
-
-#include <sys/gmon.h>
-#include <sys/gmon_out.h>
-#include <sys/types.h>
-
-#include <stdio.h>
-#include <stdio_ext.h>
-#include <string.h>
-
-#define OUT_NAME "gmon.out"
-
-
-extern struct __bb *__bb_head attribute_hidden;
-
-
-void
-__bb_exit_func (void)
-{
- const int version = GMON_VERSION;
- struct gmon_hdr ghdr;
- struct __bb *ptr;
- FILE *fp;
- fp = fopen (OUT_NAME, "wb");
- if (!fp)
- {
- perror (OUT_NAME);
- return;
- }
- /* No threads use this stream. */
- __fsetlocking (fp, FSETLOCKING_BYCALLER);
-
- memcpy (&ghdr.cookie[0], GMON_MAGIC, 4);
- memcpy (&ghdr.version, &version, sizeof (version));
- fwrite_unlocked (&ghdr, sizeof (ghdr), 1, fp);
-
- for (ptr = __bb_head; ptr != 0; ptr = ptr->next)
- {
- u_int ncounts = ptr->ncounts;
- u_char tag;
- u_int i;
-
- tag = GMON_TAG_BB_COUNT;
- fwrite_unlocked (&tag, sizeof (tag), 1, fp);
- fwrite_unlocked (&ncounts, sizeof (ncounts), 1, fp);
-
- for (i = 0; i < ncounts; ++i)
- {
- fwrite_unlocked (&ptr->addresses[i], sizeof (ptr->addresses[0]), 1,
- fp);
- fwrite_unlocked (&ptr->counts[i], sizeof (ptr->counts[0]), 1, fp);
- }
- }
- fclose (fp);
-}
diff --git a/gmon/bb_init_func.c b/gmon/bb_init_func.c
deleted file mode 100644
index c635da77b4..0000000000
--- a/gmon/bb_init_func.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/* Copyright (C) 1996-2016 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by David Mosberger (davidm@cs.arizona.edu).
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, see
- <http://www.gnu.org/licenses/>. */
-
-/* __bb_init_func is invoked at the beginning of each function, before
- any registers have been saved. This generic routine should work
- provided that calling this function doesn't mangle the arguments
- passed to the function being called. If that's not the case, a
- system specific routine must be provided. */
-
-#include <sys/types.h>
-#include <sys/gmon.h>
-
-#include <stdlib.h>
-
-void
-__bb_init_func (struct __bb *bb)
-{
- struct gmonparam *p = &_gmonparam;
-
- if (bb->zero_word != 0)
- {
- return; /* handle common case quickly */
- }
-
- /* insert this basic-block into basic-block list: */
- bb->zero_word = 1;
- bb->next = __bb_head;
- __bb_head = bb;
-
- if (bb->next == 0 && p->state != GMON_PROF_ON)
- {
- /* we didn't register _mcleanup yet and pc profiling doesn't seem
- to be active, so let's register it now: */
- extern void *__dso_handle __attribute__ ((__weak__));
- __cxa_atexit ((void (*) (void *)) _mcleanup, NULL,
- &__dso_handle ? __dso_handle : NULL);
- }
-}
diff --git a/gmon/gmon.c b/gmon/gmon.c
index e9988c06c4..dee64803ad 100644
--- a/gmon/gmon.c
+++ b/gmon/gmon.c
@@ -46,6 +46,26 @@
#include <libc-internal.h>
#include <not-cancel.h>
+#ifdef PIC
+# include <link.h>
+
+static int
+callback (struct dl_phdr_info *info, size_t size, void *data)
+{
+ if (info->dlpi_name[0] == '\0')
+ {
+ /* The link map for the executable is created by calling
+ _dl_new_object with "" as filename. dl_iterate_phdr
+ calls the callback function with filename from the
+ link map as dlpi_name. */
+ u_long *load_address = data;
+ *load_address = (u_long) info->dlpi_addr;
+ return 1;
+ }
+
+ return 0;
+}
+#endif
/* Head of basic-block list or NULL. */
struct __bb *__bb_head attribute_hidden;
@@ -58,13 +78,14 @@ struct gmonparam _gmonparam attribute_hidden = { GMON_PROF_OFF };
static int s_scale;
#define SCALE_1_TO_1 0x10000L
-#define ERR(s) write_not_cancel (STDERR_FILENO, s, sizeof (s) - 1)
+#define ERR(s) __write_nocancel (STDERR_FILENO, s, sizeof (s) - 1)
void moncontrol (int mode);
void __moncontrol (int mode);
-static void write_hist (int fd) internal_function;
-static void write_call_graph (int fd) internal_function;
-static void write_bb_counts (int fd) internal_function;
+libc_hidden_proto (__moncontrol)
+static void write_hist (int fd, u_long load_address);
+static void write_call_graph (int fd, u_long load_address);
+static void write_bb_counts (int fd);
/*
* Control profiling
@@ -93,6 +114,7 @@ __moncontrol (int mode)
p->state = GMON_PROF_OFF;
}
}
+libc_hidden_def (__moncontrol)
weak_alias (__moncontrol, moncontrol)
@@ -171,8 +193,7 @@ weak_alias (__monstartup, monstartup)
static void
-internal_function
-write_hist (int fd)
+write_hist (int fd, u_long load_address)
{
u_char tag = GMON_TAG_TIME_HIST;
@@ -209,21 +230,20 @@ write_hist (int fd)
!= offsetof (struct gmon_hist_hdr, dimen_abbrev)))
abort ();
- thdr.low_pc = (char *) _gmonparam.lowpc;
- thdr.high_pc = (char *) _gmonparam.highpc;
+ thdr.low_pc = (char *) _gmonparam.lowpc - load_address;
+ thdr.high_pc = (char *) _gmonparam.highpc - load_address;
thdr.hist_size = _gmonparam.kcountsize / sizeof (HISTCOUNTER);
thdr.prof_rate = __profile_frequency ();
strncpy (thdr.dimen, "seconds", sizeof (thdr.dimen));
thdr.dimen_abbrev = 's';
- writev_not_cancel_no_status (fd, iov, 3);
+ __writev_nocancel_nostatus (fd, iov, 3);
}
}
static void
-internal_function
-write_call_graph (int fd)
+write_call_graph (int fd, u_long load_address)
{
#define NARCS_PER_WRITEV 32
u_char tag = GMON_TAG_CG_ARC;
@@ -266,25 +286,25 @@ write_call_graph (int fd)
}
arc;
- arc.frompc = (char *) frompc;
- arc.selfpc = (char *) _gmonparam.tos[to_index].selfpc;
+ arc.frompc = (char *) frompc - load_address;
+ arc.selfpc = ((char *) _gmonparam.tos[to_index].selfpc
+ - load_address);
arc.count = _gmonparam.tos[to_index].count;
memcpy (raw_arc + nfilled, &arc, sizeof (raw_arc [0]));
if (++nfilled == NARCS_PER_WRITEV)
{
- writev_not_cancel_no_status (fd, iov, 2 * nfilled);
+ __writev_nocancel_nostatus (fd, iov, 2 * nfilled);
nfilled = 0;
}
}
}
if (nfilled > 0)
- writev_not_cancel_no_status (fd, iov, 2 * nfilled);
+ __writev_nocancel_nostatus (fd, iov, 2 * nfilled);
}
static void
-internal_function
write_bb_counts (int fd)
{
struct __bb *grp;
@@ -312,12 +332,12 @@ write_bb_counts (int fd)
for (grp = __bb_head; grp; grp = grp->next)
{
ncounts = grp->ncounts;
- writev_not_cancel_no_status (fd, bbhead, 2);
+ __writev_nocancel_nostatus (fd, bbhead, 2);
for (nfilled = i = 0; i < ncounts; ++i)
{
if (nfilled > (sizeof (bbbody) / sizeof (bbbody[0])) - 2)
{
- writev_not_cancel_no_status (fd, bbbody, nfilled);
+ __writev_nocancel_nostatus (fd, bbbody, nfilled);
nfilled = 0;
}
@@ -325,7 +345,7 @@ write_bb_counts (int fd)
bbbody[nfilled++].iov_base = &grp->counts[i];
}
if (nfilled > 0)
- writev_not_cancel_no_status (fd, bbbody, nfilled);
+ __writev_nocancel_nostatus (fd, bbbody, nfilled);
}
}
@@ -336,22 +356,18 @@ write_gmon (void)
int fd = -1;
char *env;
-#ifndef O_NOFOLLOW
-# define O_NOFOLLOW 0
-#endif
-
env = getenv ("GMON_OUT_PREFIX");
if (env != NULL && !__libc_enable_secure)
{
size_t len = strlen (env);
char buf[len + 20];
__snprintf (buf, sizeof (buf), "%s.%u", env, __getpid ());
- fd = open_not_cancel (buf, O_CREAT|O_TRUNC|O_WRONLY|O_NOFOLLOW, 0666);
+ fd = __open_nocancel (buf, O_CREAT|O_TRUNC|O_WRONLY|O_NOFOLLOW, 0666);
}
if (fd == -1)
{
- fd = open_not_cancel ("gmon.out", O_CREAT|O_TRUNC|O_WRONLY|O_NOFOLLOW,
+ fd = __open_nocancel ("gmon.out", O_CREAT|O_TRUNC|O_WRONLY|O_NOFOLLOW,
0666);
if (fd < 0)
{
@@ -379,18 +395,24 @@ write_gmon (void)
memcpy (&ghdr.cookie[0], GMON_MAGIC, sizeof (ghdr.cookie));
ghdr.version = GMON_VERSION;
memset (ghdr.spare, '\0', sizeof (ghdr.spare));
- write_not_cancel (fd, &ghdr, sizeof (struct gmon_hdr));
+ __write_nocancel (fd, &ghdr, sizeof (struct gmon_hdr));
+
+ /* Get load_address to profile PIE. */
+ u_long load_address = 0;
+#ifdef PIC
+ __dl_iterate_phdr (callback, &load_address);
+#endif
/* write PC histogram: */
- write_hist (fd);
+ write_hist (fd, load_address);
/* write call-graph: */
- write_call_graph (fd);
+ write_call_graph (fd, load_address);
/* write basic-block execution counts: */
write_bb_counts (fd);
- close_not_cancel_no_status (fd);
+ __close_nocancel_nostatus (fd);
}
diff --git a/gmon/profil.c b/gmon/profil.c
index e1eff8bd0f..f0d138ca34 100644
--- a/gmon/profil.c
+++ b/gmon/profil.c
@@ -1,5 +1,5 @@
/* Low-level statistical profiling support function. Stub version.
- Copyright (C) 1995-2016 Free Software Foundation, Inc.
+ Copyright (C) 1995-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
diff --git a/gmon/sprofil.c b/gmon/sprofil.c
index 945cf18071..2f8dc23066 100644
--- a/gmon/sprofil.c
+++ b/gmon/sprofil.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2016 Free Software Foundation, Inc.
+/* Copyright (C) 2001-2018 Free Software Foundation, Inc.
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>.
This file is part of the GNU C Library.
diff --git a/gmon/sys/gmon.h b/gmon/sys/gmon.h
index 5b430abc3e..b4cc3b043a 100644
--- a/gmon/sys/gmon.h
+++ b/gmon/sys/gmon.h
@@ -117,7 +117,7 @@ extern struct __bb *__bb_head;
/*
* The type used to represent indices into gmonparam.tos[].
*/
-#define ARCINDEX u_long
+#define ARCINDEX unsigned long
/*
* Maximum number of arcs we want to allow.
@@ -130,7 +130,7 @@ extern struct __bb *__bb_head;
#define MAXARCS (1 << 20)
struct tostruct {
- u_long selfpc;
+ unsigned long selfpc;
long count;
ARCINDEX link;
};
@@ -140,9 +140,9 @@ struct tostruct {
* the called site and a count.
*/
struct rawarc {
- u_long raw_frompc;
- u_long raw_selfpc;
- long raw_count;
+ unsigned long raw_frompc;
+ unsigned long raw_selfpc;
+ long raw_count;
};
/*
@@ -156,17 +156,17 @@ struct rawarc {
*/
struct gmonparam {
long int state;
- u_short *kcount;
- u_long kcountsize;
+ unsigned short *kcount;
+ unsigned long kcountsize;
ARCINDEX *froms;
- u_long fromssize;
+ unsigned long fromssize;
struct tostruct *tos;
- u_long tossize;
+ unsigned long tossize;
long tolimit;
- u_long lowpc;
- u_long highpc;
- u_long textsize;
- u_long hashfraction;
+ unsigned long lowpc;
+ unsigned long highpc;
+ unsigned long textsize;
+ unsigned long hashfraction;
long log_hashfraction;
};
@@ -190,8 +190,8 @@ struct gmonparam {
__BEGIN_DECLS
/* Set up data structures and start profiling. */
-extern void __monstartup (u_long __lowpc, u_long __highpc) __THROW;
-extern void monstartup (u_long __lowpc, u_long __highpc) __THROW;
+extern void __monstartup (unsigned long __lowpc, unsigned long __highpc) __THROW;
+extern void monstartup (unsigned long __lowpc, unsigned long __highpc) __THROW;
/* Clean up profiling and write out gmon.out. */
extern void _mcleanup (void) __THROW;
diff --git a/gmon/sys/gmon_out.h b/gmon/sys/gmon_out.h
index b94879947f..de21d5559a 100644
--- a/gmon/sys/gmon_out.h
+++ b/gmon/sys/gmon_out.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996-2016 Free Software Foundation, Inc.
+/* Copyright (C) 1996-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by David Mosberger <davidm@cs.arizona.edu>.
diff --git a/gmon/sys/profil.h b/gmon/sys/profil.h
index 5790fe03b8..b993a658c5 100644
--- a/gmon/sys/profil.h
+++ b/gmon/sys/profil.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2016 Free Software Foundation, Inc.
+/* Copyright (C) 2001-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
diff --git a/gmon/tst-gmon-gprof.sh b/gmon/tst-gmon-gprof.sh
new file mode 100644
index 0000000000..1afec48b0b
--- /dev/null
+++ b/gmon/tst-gmon-gprof.sh
@@ -0,0 +1,60 @@
+#!/bin/sh
+# Check the output of gprof against a carfully crafted binary.
+# Copyright (C) 2017-2018 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, see
+# <http://www.gnu.org/licenses/>.
+
+LC_ALL=C
+export LC_ALL
+set -e
+exec 2>&1
+
+GPROF="$1"
+program="$2"
+data="$3"
+
+actual=$(mktemp)
+expected=$(mktemp)
+expected_dot=$(mktemp)
+cleanup () {
+ rm -f "$actual"
+ rm -f "$expected"
+ rm -f "$expected_dot"
+}
+trap cleanup 0
+
+cat > "$expected" <<EOF
+f1 2000
+f2 1000
+EOF
+
+# Special version for powerpc with function descriptors.
+cat > "$expected_dot" <<EOF
+.f1 2000
+.f2 1000
+EOF
+
+"$GPROF" -C "$program" "$data" \
+ | awk -F '[(): ]' '/executions/{print $5, $8}' \
+ | sort > "$actual"
+
+if cmp -s "$actual" "$expected_dot" \
+ || diff -u --label expected "$expected" --label actual "$actual" ; then
+ echo "PASS"
+else
+ echo "FAIL"
+ exit 1
+fi
diff --git a/gmon/tst-gmon-pie.c b/gmon/tst-gmon-pie.c
new file mode 100644
index 0000000000..1eef2583b6
--- /dev/null
+++ b/gmon/tst-gmon-pie.c
@@ -0,0 +1 @@
+#include "tst-gmon.c"
diff --git a/gmon/tst-gmon-static-gprof.sh b/gmon/tst-gmon-static-gprof.sh
new file mode 100644
index 0000000000..34dd952bf3
--- /dev/null
+++ b/gmon/tst-gmon-static-gprof.sh
@@ -0,0 +1,62 @@
+#!/bin/sh
+# Check the output of gprof against a carfully crafted static binary.
+# Copyright (C) 2017-2018 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, see
+# <http://www.gnu.org/licenses/>.
+
+LC_ALL=C
+export LC_ALL
+set -e
+exec 2>&1
+
+GPROF="$1"
+program="$2"
+data="$3"
+
+actual=$(mktemp)
+expected=$(mktemp)
+expected_dot=$(mktemp)
+cleanup () {
+ rm -f "$actual"
+ rm -f "$expected"
+ rm -f "$expected_dot"
+}
+trap cleanup 0
+
+cat > "$expected" <<EOF
+f1 2000
+f2 1000
+main 1
+EOF
+
+# Special version for powerpc with function descriptors.
+cat > "$expected_dot" <<EOF
+.f1 2000
+.f2 1000
+.main 1
+EOF
+
+"$GPROF" -C "$program" "$data" \
+ | awk -F '[(): ]' '/executions/{print $5, $8}' \
+ | sort > "$actual"
+
+if cmp -s "$actual" "$expected_dot" \
+ || diff -u --label expected "$expected" --label actual "$actual" ; then
+ echo "PASS"
+else
+ echo "FAIL"
+ exit 1
+fi
diff --git a/gmon/tst-gmon-static-pie.c b/gmon/tst-gmon-static-pie.c
new file mode 100644
index 0000000000..1eef2583b6
--- /dev/null
+++ b/gmon/tst-gmon-static-pie.c
@@ -0,0 +1 @@
+#include "tst-gmon.c"
diff --git a/gmon/tst-gmon-static.c b/gmon/tst-gmon-static.c
new file mode 100644
index 0000000000..1eef2583b6
--- /dev/null
+++ b/gmon/tst-gmon-static.c
@@ -0,0 +1 @@
+#include "tst-gmon.c"
diff --git a/gmon/tst-gmon.c b/gmon/tst-gmon.c
new file mode 100644
index 0000000000..ea2e55f608
--- /dev/null
+++ b/gmon/tst-gmon.c
@@ -0,0 +1,50 @@
+/* Test program for profiling information collection (_mcount/gprof).
+ Copyright (C) 2017-2018 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* This program does not use the test harness because we want tight
+ control over the call graph. */
+
+__attribute__ ((noinline, noclone, weak)) void
+f1 (void)
+{
+}
+
+__attribute__ ((noinline, noclone, weak)) void
+f2 (void)
+{
+ f1 ();
+ /* Prevent tail call. */
+ asm volatile ("");
+}
+
+__attribute__ ((noinline, noclone, weak)) void
+f3 (int count)
+{
+ for (int i = 0; i < count; ++i)
+ {
+ f1 ();
+ f2 ();
+ }
+}
+
+int
+main (void)
+{
+ f3 (1000);
+ return 0;
+}
diff --git a/gmon/tst-sprofil.c b/gmon/tst-sprofil.c
index 66cede9719..ac4d1c3f18 100644
--- a/gmon/tst-sprofil.c
+++ b/gmon/tst-sprofil.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2016 Free Software Foundation, Inc.
+/* Copyright (C) 2001-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>.