strace fails to trace call stack of clone from pthread_create

Zhouyang Jia jiazhouyang09 at gmail.com
Mon Nov 5 00:27:28 UTC 2018


Actually, I didn't pass anything special to fork(3) or pthread_create(3).
The source code is as follows:


$ cat test_fork.c

#include  <stdio.h>
#include  <sys/types.h>

#define   MAX_COUNT  200

void  ChildProcess(void);
void  ParentProcess(void);

void  main(void)
{
     pid_t  pid;

     pid = fork();
     if (pid == 0)
          ChildProcess();
     else
          ParentProcess();
}

void  ChildProcess(void)
{
     int   i;

     for (i = 1; i <= MAX_COUNT; i++)
          printf("   This line is from child, value = %d\n", i);
     printf("   *** Child process is done ***\n");
}

void  ParentProcess(void)
{
     int   i;

     for (i = 1; i <= MAX_COUNT; i++)
          printf("This line is from parent, value = %d\n", i);
     printf("*** Parent is done ***\n");
}



$ cat test_pthread.c
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

void *print_message_function( void *ptr );

int main()
{
     pthread_t thread1, thread2;
     const char *message1 = "Thread 1";
     const char *message2 = "Thread 2";
     int  iret1, iret2;

    /* Create independent threads each of which will execute function */

     iret1 = pthread_create( &thread1, NULL, print_message_function,
(void*) message1);
     if(iret1)
     {
         fprintf(stderr,"Error - pthread_create() return code: %d\n",iret1);
         exit(EXIT_FAILURE);
     }

     iret2 = pthread_create( &thread2, NULL, print_message_function,
(void*) message2);
     if(iret2)
     {
         fprintf(stderr,"Error - pthread_create() return code: %d\n",iret2);
         exit(EXIT_FAILURE);
     }

     printf("pthread_create() for thread 1 returns: %d\n",iret1);
     printf("pthread_create() for thread 2 returns: %d\n",iret2);

     /* Wait till threads are complete before main continues. Unless we  */
     /* wait we run the risk of executing an exit which will terminate   */
     /* the process and all threads before the threads have completed.   */

     pthread_join( thread1, NULL);
     pthread_join( thread2, NULL);

     exit(EXIT_SUCCESS);

     return 0;
}

void *print_message_function( void *ptr )
{
     char *message;
     message = (char *) ptr;
     printf("%s \n", message);
}

On Sun, Nov 4, 2018 at 1:44 PM Masatake YAMATO <yamato at redhat.com> wrote:

> On Fri, 2 Nov 2018 09:46:06 -0400, Zhouyang Jia <jiazhouyang09 at gmail.com>
> wrote:
> > FYI, I also found clone(2) from fork(3) works fine, while clone(2)
> > from pthread_create(3) has the bug.
> > So, I guess the problem might be caused by thread mechanism.
>
> Interesting. I'd like to see your source code of program for testing
> clone(2).
>
>        int clone(int (*fn)(void *), void *child_stack,
>                  int flags, void *arg, ...
>                  /* pid_t *ptid, void *newtls, pid_t *ctid */ );
>
> I wonder what you passed to `child_stack'.
>
> Masatake YAMATO
>
> > Best,
> > Zhouyang
> >
> > On Fri, Nov 2, 2018 at 2:49 AM Masatake YAMATO <yamato at redhat.com>
> wrote:
> >
> >> > Hi everyone,
> >> >
> >> > I find strace fails to trace call stack of clone syscall (called by
> >> > pthread_create) in both main thread and child thread.
> >> >
> >> > How to reproduce:
> >> >
> >> > Get a simple pthread_create example:
> >> > http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html
> >> > Compile: gcc -pthread test_pthread.c -o test_pthread
> >> > Trace: strace -k -ff -o test_pthread ./test_pthread
> >> >
> >> > In main thread:
> >> >     clone(child_stack=0x7f56c52b1ff0,
> >> >
> >>
> flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID,
> >> > parent_tidptr=0x7f56c52b29d0, tls=0x7f56c52b2700,
> >> > child_tidptr=0x7f56c52b29d0) = 69700
> >> >      > /lib/x86_64-linux-gnu/libc-2.23.so(clone+0x31) [0x1073e1]
> >> >
> >> > In child thread:
> >> >     set_robust_list(0x7f56c52b29e0, 24) = 0
> >> >      > /lib/x86_64-linux-gnu/libpthread-2.23.so(start_thread+0x64)
> >> [0x7654]
> >> >      > /lib/x86_64-linux-gnu/libc-2.23.so(clone+0x6d) [0x10741d]
> >> >
> >> > We can see the call stacks of both main thread and child thread start
> >> from
> >> > libc. Is there any way to get the call stack from the main function?
> I'm
> >> > not sure whether this is a bug or not.
> >>
> >> It looks a bug.
> >>
> >> About the most of all system calls, strace captures its stack trace
> after
> >> kernel executes the system call. However, about some system calls,
> >> caputirng
> >> after executing is not useful. I put makers "SE" on such a system call
> in
> >> syscallent.h. SE is defined as STACKTRACE_CAPTURE_ON_ENTER in code.
> >> I put SE markers on execve and _exit for exapmles.
> >>
> >> I should put the maker on clone, fork, and vfrok, too.
> >> Before writing this mail, I expected the bug you reported will be fixed
> by
> >> putting
> >> the marker on the system calls like:
> >>
> >> diff --git a/linux/x86_64/syscallent.h b/linux/x86_64/syscallent.h
> >> index 63ec52e8..2be891bd 100644
> >> --- a/linux/x86_64/syscallent.h
> >> +++ b/linux/x86_64/syscallent.h
> >> @@ -54,9 +54,9 @@
> >>  [ 53] = { 4,   TN,             SEN(socketpair),
> >> "socketpair"            },
> >>  [ 54] = { 5,   TN,             SEN(setsockopt),
> >> "setsockopt"            },
> >>  [ 55] = { 5,   TN,             SEN(getsockopt),
> >> "getsockopt"            },
> >> -[ 56] = { 5,   TP,             SEN(clone),                     "clone"
> >>              },
> >> -[ 57] = { 0,   TP,             SEN(fork),                      "fork"
> >>               },
> >> -[ 58] = { 0,   TP,             SEN(vfork),                     "vfork"
> >>              },
> >> +[ 56] = { 5,   TP|SE,          SEN(clone),                     "clone"
> >>              },
> >> +[ 57] = { 0,   TP|SE,          SEN(fork),                      "fork"
> >>               },
> >> +[ 58] = { 0,   TP|SE,          SEN(vfork),                     "vfork"
> >>              },
> >>  [ 59] = { 3,   TF|TP|SE|SI,    SEN(execve),                    "execve"
> >>               },
> >>  [ 60] = { 1,   TP|SE,          SEN(exit),                      "exit"
> >>               },
> >>  [ 61] = { 4,   TP,             SEN(wait4),                     "wait4"
> >>              },
> >>
> >>
> >> However, though I put the maker on them, I cannot get expected result
> >> either using libunwind or libdw.
> >>
> >> I read the implemention of the wrapper for clone systecall.
> >> It is not written in C but in x86-64 Assembly language.
> >> So I guess the frame structure(?) that the unwinder expects are
> >> not constructed when executing clone syscall. So unwinder
> >> cannot capture a stack trace in the context.
> >>
> >> I have to take much more time for understanding the issue.
> >>
> >> Masatake YAMATO
> >>
> >> > Thanks,
> >> > Zhouyang
> >>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.strace.io/pipermail/strace-devel/attachments/20181104/f53e52a4/attachment.html>


More information about the Strace-devel mailing list