Bug 21189 - gprof doesn't work with code built with PIE
Summary: gprof doesn't work with code built with PIE
Status: NEW
Alias: None
Product: binutils
Classification: Unclassified
Component: gprof (show other bugs)
Version: 2.28
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2017-02-21 10:14 UTC by Matthias Klose
Modified: 2017-02-22 17:34 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Matthias Klose 2017-02-21 10:14:21 UTC
[forwarded from https://bugs.debian.org/854704]

"""
Since --enabled-default-pie was enabled in Debian for GCC 6, gprof no longer
works. I run a simple program compiled with default flags and gprof's output is
empty.

$ cat infloop.c
int main() {
    for(long i = 0; i < 1000000000; i ++) {}
    return 0;
}
$ gcc infloop.c -o infloop -pg
$ time ./infloop

real    0m2.067s
user    0m2.064s
sys     0m0.004s
$ gprof ./infloop | grep main
$

However, when I compile the same program with any earlier version of gcc, such
as gcc 5.4.1, or with the option -no-pie to disable PIE, it works.

$ gcc-5 infloop.c -o infloop -pg
$ rm gmon.out
$ time ./infloop

real    0m2.041s
user    0m2.036s
sys     0m0.000s
$ gprof ./infloop | grep main
101.41      2.06     2.06                             main
$ gcc -no-pie infloop.c -o infloop -pg
$ rm gmon.out
$ time ./infloop

real    0m2.019s
user    0m2.016s
sys     0m0.000s
$ gprof ./infloop | grep main
101.41      2.03     2.03                             main
$

This is the case for more complex programs too: gprof simply outputs nothing
other than the help-text. It looks like gcc is correctly generating the
gmon.out file, since it gets quite large and contains non-zero values.

Since GCC 6 moved to --enable-default-pie, all executables are of type DYN (not
EXEC), like shared libraries, and may be loaded at any base address. I suspect
this is breaking gprof's symbol lookup functionality. For instance, 0 is now a
valid address within the DYN ELF file. A good workaround for now is -no-pie,
but it would be great to get this fixed since Debian GCC now defaults to PIE.
"""
Comment 1 Nick Clifton 2017-02-22 11:29:03 UTC
Hi Matthias,

> Since --enabled-default-pie was enabled in Debian for GCC 6, gprof no longer
> works.

I think that this might be a glibc bug.  Specifically in their implementation of mcount() for PIE environments.

Running "gprof -d infloop | grep main" shows that main starts at address 0x860:

  [get_src_info] 0x860 -> infloop.c:1 (main)
  [core_create_function_syms] 15 main 0x860

And that it covers 0x2f bytes:

  [symtab_finalize] 0x860-0x88f	main

But, the data in the gmon.out file us using much higher addresses:

  [hist_read_rec] n_lowpc 0x4004e0 n_highpc 0x400718 ncnt 144

  [assign_samples] bin_low_pc=0x40063a, bin_high_pc=0x40063e, bin_count=18
  [assign_samples] bin_low_pc=0x40063e, bin_high_pc=0x400642, bin_count=38
  [assign_samples] bin_low_pc=0x400646, bin_high_pc=0x40064a, bin_count=82
  [assign_samples] total_time 138.000000

Of course I may be wrong - I am not an expert on gprof - but it does look to me like the contents of the gmon.out file are wrong.

Alternatively maybe gprof needs a way compute a starting address bias for PIE executables.

Cheers
  Nick
Comment 2 H.J. Lu 2017-02-22 16:48:52 UTC
The load address of PIE is determined at run-time and changes for
each run.  But the format of gmon.out doesn't support the changing load
address.
Comment 3 Nick Clifton 2017-02-22 17:34:13 UTC
(In reply to H.J. Lu from comment #2)
> The load address of PIE is determined at run-time and changes for
> each run.  But the format of gmon.out doesn't support the changing load
> address.

All the more reason then for mcount() to adjust its output in order to allow
for the run-time address bias.