Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PLT hook segfault from <__fentry__@plt> on GCC7 #100

Closed
Taeung opened this issue May 18, 2017 · 7 comments
Closed

PLT hook segfault from <__fentry__@plt> on GCC7 #100

Taeung opened this issue May 18, 2017 · 7 comments
Labels

Comments

@Taeung
Copy link
Collaborator

Taeung commented May 18, 2017

This problem is similar to #92 and #91 .
But this only -pg -mfentry case is like below.

  • Target program
$ cat  hello.c
#include <stdio.h>

void main()
{
	printf("hello\n");
}
  • Failed only -pg -mfentry case (with uftrace built by GCC7)
    (Sure, normal tracing and dynamic tracing are fine)
$ gcc -o hello -pg -mfentry hello.c

$ uftrace ./hello
child terminated by signal: 11: Segmentation fault
# DURATION    TID     FUNCTION
   1.741 us [14660] | __monstartup();
   1.519 us [14660] | __cxa_atexit();

  • With --no-libcall, there isn't segfault.
uftrace --no-libcall ./hello
hello
# DURATION    TID     FUNCTION
   2.212 us [15019] | main();

This problem is related to the 16-byte stack alignment required from GCC7 because of movaps.

$ gdb ./hello core
...
Core was generated by `./hello'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x00007fa62271d612 in plthook_entry (ret_addr=0x7fff69e186f0, child_idx=4, 
    module_id=140351523635560, regs=0x7fff69e186b0)
    at /home/taeung/git/uftrace/libmcount/plthook.c:429
429		struct ftrace_trigger tr = {
(gdb) disas
Dump of assembler code for function plthook_entry:
   0x00007fa62271d5f0 <+0>:	push   %r15
   0x00007fa62271d5f2 <+2>:	push   %r14
   0x00007fa62271d5f4 <+4>:	push   %r13
   0x00007fa62271d5f6 <+6>:	push   %r12
   0x00007fa62271d5f8 <+8>:	push   %rbp
   0x00007fa62271d5f9 <+9>:	push   %rbx
   0x00007fa62271d5fa <+10>:	pxor   %xmm0,%xmm0
   0x00007fa62271d5fe <+14>:	sub    $0x58,%rsp
   0x00007fa62271d602 <+18>:	lea    0x217318(%rip),%rax        # 0x7fa622934921 <mcount_setup_done>
   0x00007fa62271d609 <+25>:	movq   $0x0,0x40(%rsp)
=> 0x00007fa62271d612 <+34>:	movaps %xmm0,0x20(%rsp)
   0x00007fa62271d617 <+39>:	movzbl (%rax),%r13d
...
(gdb) p $rsp
$1 = (void *) 0x7fff69e18618

AYK, you can check "rsp % 16 != 0" (i.e. 0x7fff69e18618 % 16 = 0x8).

And I checked all values of rsp%16 at the very beginning of plt_hooker() each time it is called with GDB.

(gdb) set follow-fork-mode child
(gdb) b plt_hooker
Function "plt_hooker" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (plt_hooker) pending.
(gdb) r --no-pager ./hello
...
(gdb) bt
#0  0x00007ffff7bca3a4 in plt_hooker () from /usr/local/lib/libmcount-fast.so
#1  0x0000000000400539 in _start ()
(gdb) p $rsp
$1 = (void *) 0x7fffffffddf8
(gdb) c
Continuing.
...
(gdb) bt
#0  0x00007ffff7bca3a4 in plt_hooker () from /usr/local/lib/libmcount-fast.so
#1  0x0000000000400571 in __gmon_start__ ()
#2  0x00000000004004a5 in _init ()
#3  0x0000000200000001 in ?? ()
#4  0x0000000000400681 in __libc_csu_init ()
#5  0x00007ffff780f7bf in __libc_start_main (main=0x400637 <main>, argc=1, 
    argv=0x7fffffffde28, init=0x400650 <__libc_csu_init>, fini=<optimized out>, 
    rtld_fini=<optimized out>, stack_end=0x7fffffffde18) at ../csu/libc-start.c:247
#6  0x0000000000400539 in _start ()
(gdb) p $rsp
$2 = (void *) 0x7fffffffdcd8
(gdb) c
Continuing.
...
(gdb) p $rsp
$3 = (void *) 0x7fffffffdce8
(gdb) c
Continuing.
...
(gdb) bt
#0  0x00007ffff7bca3a4 in plt_hooker () from /usr/local/lib/libmcount-fast.so
#1  0x000000000040063c in main ()
(gdb) p $rsp
$4 = (void *) 0x7fffffffdd30
(gdb) c
Continuing.

Thread 2.1 "hello" received signal SIGSEGV, Segmentation fault.
0x00007ffff7bbf612 in plthook_entry (ret_addr=0x7fffffffdd40, child_idx=4, 
    module_id=140737354129768, regs=0x7fffffffdd00)
    at /home/taeung/git/uftrace/libmcount/plthook.c:429
429		struct ftrace_trigger tr = {
  1. <__libc_start_main@plt> case from _start()
    0x7fffffffddf8 % 16 = 0x8

  2. <__monstartup@plt> case from gmon_start()
    0x7fffffffdcd8 % 16 = 0x8

  3. <__cxa_atexit@plt> case from _init()
    0x7fffffffdce8 % 16 = 0x8

  4. <__fentry__@plt> case from main()
    0x7fffffffdd30 % 16 = 0x0

I thought plt_hooker() adjusts rsp for (rsp % 16 == 0) because of the 16-byte alignment,
but <__fentry__@plt> case is already "rsp % 16 == 0" before plt_hooker() is called.
So we need to add some if-else statement into arch/x86_64/plthook.S ?
Or, my investigation way is wrong ?

@Taeung Taeung changed the title Segfault of PLT hook from <__fentry__@plt> on GCC7 PLT hook segfault from <__fentry__@plt> on GCC7 May 18, 2017
@namhyung
Copy link
Owner

Thanks for the report. In principle, PLT hook should work same for both of mcount and __fentry__ cases.

But this is a special entry for the __fentry__ itself so we should prevent it from calling in the first place. I'll think about it.

@Taeung
Copy link
Collaborator Author

Taeung commented May 19, 2017

Okey. 😄

Taeung added a commit to Taeung/uftrace that referenced this issue May 19, 2017
If uftrace is built by GCC7, plthook_entry() has `movaps` insn.
So the stack pointer must be aligned on a 16-byte boundary.
This was handled by the commit 7b80ea8 ("mcount: Fix segfault on GCC7")

However, the commit didn't handle the below `-pg -mfentry` case:

  $ gcc -o hello -pg -mfentry hello.c

  $ uftrace ./hello
  child terminated by signal: 11: Segmentation fault
  # DURATION    TID     FUNCTION
     1.741 us [14660] | __monstartup();
     1.519 us [14660] | __cxa_atexit();

So fix it, this situation was mentioned on namhyung#100.

Signed-off-by: Taeung Song <treeze.taeung@gmail.com>
@namhyung
Copy link
Owner

I pushed the fix to check/plthook-fix-v1. Could you please verify it?

@Taeung
Copy link
Collaborator Author

Taeung commented May 20, 2017

Sure !

@Taeung
Copy link
Collaborator Author

Taeung commented May 20, 2017

Nice work, but the output is a bit changed.

$ gcc -o tests/t-abc -pg -mfentry tests/s-abc.c

$ uftrace tests/t-abc 
# DURATION    TID     FUNCTION
            [14886] | __libc_start_main() {
            [14886] |   main() {
            [14886] |     a() {
            [14886] |       b() {
   0.698 us [14886] |         c();
   1.313 us [14886] |       } /* b */
   1.550 us [14886] |     } /* a */
   1.778 us [14886] |   } /* main */

uftrace stopped tracing with remaining functions
================================================
task: 14886
[0] __libc_start_main

@namhyung
Copy link
Owner

Ah ok. Thanks for checking!

@Taeung
Copy link
Collaborator Author

Taeung commented May 20, 2017

I read the commits of your check/plthook-fix-v1 now.
From now on, target program can directly call mcount() or __fentry__()
without the help of _dl_runtime_resolve(), right ?
That's great. You got two rabbits !
I'll close my PR #101

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants