Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
进程A中的waitpid()可以';t在进程B中的pthread_create()在coredump之前创建的线程中捕获SIGTRAP_C_Multithreading_Unix_Signals_Ptrace - Fatal编程技术网

进程A中的waitpid()可以';t在进程B中的pthread_create()在coredump之前创建的线程中捕获SIGTRAP

进程A中的waitpid()可以';t在进程B中的pthread_create()在coredump之前创建的线程中捕获SIGTRAP,c,multithreading,unix,signals,ptrace,C,Multithreading,Unix,Signals,Ptrace,首先,启动进程B(请参见下面的mt.cpp),它将使用pthread\u create()创建一个线程。主线程和新线程的ppid、pid和tid将为进程A输出,然后它们都启动一个for循环并引发SIGTRAP,进程A中的waitpid()应捕捉到这一点 第二,使用进程B的pid启动进程A(参见下面的attach.cpp)。进程A将通过ptrace(ptrace\u attach,…)连接到进程B,然后使用while(true)中的waitpid()等待信号事件,调用ptrace(ptrace\u

首先,启动进程B(请参见下面的
mt.cpp
),它将使用
pthread\u create()
创建一个线程。主线程和新线程的
ppid
pid
tid
将为进程A输出,然后它们都启动一个for循环并引发
SIGTRAP
,进程A中的
waitpid()
应捕捉到这一点

第二,使用进程B的
pid
启动进程A(参见下面的
attach.cpp
)。进程A将通过
ptrace(ptrace\u attach,…)
连接到进程B,然后使用
while(true)
中的
waitpid()
等待信号事件,调用
ptrace(ptrace\u CONT,…)
如果获得
SIGTRAP
,或者,如果获得
SIGSTOP
,则中断循环

现在的问题是: 进程A可以捕获进程B的主线程引发的
SIGTRAP
,并成功调用
ptrace(ptrace\u CONT,…)
,然后进程B将继续按预期执行

但是

当进程B的新线程引发
SIGTRAP
时,进程A未能
ptrace(ptrace\u CONT,…)
使用
errmsg
“没有这样的进程”,因为进程B使用
errmsg
“跟踪/断点陷阱(内核转储)”转储了内核。 此外,
WIFSTOPPED(status)
变为false,
WIFSIGNALED(status)
变为true

我知道
SIGTRAP
的默认操作是终止进程,似乎
SIGTRAP
在终止操作之后而不是之前被转移到进程A,因此进程A没有机会继续进程B

我尝试了
gdb
而不是进程A,两个
SIGTRAP
都可以成功捕获并继续。因此,进程A的代码中一定有错误

下面是作为进程A执行的
attach.cpp

#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int main(int argc, char *argv[])
{   
  pid_t pid = 0;
  int ret = 0;
  int status = 0;

  if (argc > 1) {
    pid = atoi(argv[1]);
    printf("pid=%d\n", pid);
  }

  ret = ptrace(PTRACE_ATTACH, pid, NULL, NULL);
  printf("attach ret=%d\n", ret);

  waitpid(pid, &status, 0);
  ret = ptrace(PTRACE_CONT, pid, NULL, NULL);
  printf("cont ret=%d\n", ret);

  while (true) {
    ret = waitpid(pid, &status, WUNTRACED);
    printf("\nwaitpid ret=%d.\n", ret);

    int sig = 0; 
    if (WIFSIGNALED(status)) {
      printf("WIFSIGNALED\n");
      sig = WTERMSIG(status);
    } else if (WIFSTOPPED(status)) {
      printf("WIFSTOPPED\n");
      sig = WSTOPSIG(status);
    } else {
      printf("other status %d\n", status);
    }
    if (SIGTRAP == sig) {
      ret = ptrace(PTRACE_CONT, pid, NULL, NULL);
      printf("SIGTRAP cont ret=%d err=%s\n", ret, strerror(errno));
    } else if (SIGSTOP == sig) {
      ret = ptrace(PTRACE_DETACH, pid, NULL, NULL);
      printf("SIGSTOP detach ret=%d\n", ret);
      break;
    } else {
      printf("other signal %d\n", sig);
    }
    sleep(2);
  }

  return 0;
}
$ ./attach 30389
pid=30389
attach ret=0
cont ret=0

waitpid ret=30389.
WIFSTOPPED
SIGTRAP cont ret=0 err=Success

waitpid ret=30389.
WIFSIGNALED
SIGTRAP cont ret=-1 err=No such process
^C
结果如下:

  • 如果您想自己执行这两个程序,请确保在启动进程B后尽快启动进程A(连接)
过程B:

#include <stdio.h> 
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include <sys/syscall.h>

#define gettid() syscall(SYS_gettid)

void *func(void * arg)
{
  printf("child ppid=%d pid=%d tid=%d\n", getppid(), getpid(), gettid());
  int i = 0;
  for (; i < 5; i++) {
    printf("child loop i=%d\n", i);
    sleep(2);
  }

  printf("\nchild before SIGTRAP\n", gettid());
  raise(SIGTRAP);
  printf("child after SIGTRAP\n\n", gettid());

  for (; i < 8; i++) {
    printf("child loop i=%d\n", i);
    sleep(2);
  }

  return NULL;
}

int main(void)
{
  printf("parent ppid=%d pid=%d tid=%d\n", getppid(), getpid(), gettid());
  pthread_t tid;
  pthread_create(&tid, NULL, func, NULL);

  int i = 0;
  for (; i < 3; i++) {
    printf("parent loop i=%d\n", i);
    sleep(2);
  }

  printf("\nparent before SIGTRAP\n", gettid());
  raise(SIGTRAP);
  printf("parent after SIGTRAP\n\n", gettid());

  for (; i < 10; i++) {
    printf("parent loop i=%d\n", i);
    sleep(2);
  }

  pthread_join(tid, NULL);

  return 0;
}
$ ./mt
parent ppid=12238 pid=30389 tid=30389
parent loop i=0
child ppid=12238 pid=30389 tid=30390
child loop i=0
parent loop i=1
child loop i=1
parent loop i=2
child loop i=2

parent before SIGTRAP
child loop i=3
parent after SIGTRAP

parent loop i=3
child loop i=4
parent loop i=4

child before SIGTRAP
Trace/breakpoint trap (core dumped)
过程A:

#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int main(int argc, char *argv[])
{   
  pid_t pid = 0;
  int ret = 0;
  int status = 0;

  if (argc > 1) {
    pid = atoi(argv[1]);
    printf("pid=%d\n", pid);
  }

  ret = ptrace(PTRACE_ATTACH, pid, NULL, NULL);
  printf("attach ret=%d\n", ret);

  waitpid(pid, &status, 0);
  ret = ptrace(PTRACE_CONT, pid, NULL, NULL);
  printf("cont ret=%d\n", ret);

  while (true) {
    ret = waitpid(pid, &status, WUNTRACED);
    printf("\nwaitpid ret=%d.\n", ret);

    int sig = 0; 
    if (WIFSIGNALED(status)) {
      printf("WIFSIGNALED\n");
      sig = WTERMSIG(status);
    } else if (WIFSTOPPED(status)) {
      printf("WIFSTOPPED\n");
      sig = WSTOPSIG(status);
    } else {
      printf("other status %d\n", status);
    }
    if (SIGTRAP == sig) {
      ret = ptrace(PTRACE_CONT, pid, NULL, NULL);
      printf("SIGTRAP cont ret=%d err=%s\n", ret, strerror(errno));
    } else if (SIGSTOP == sig) {
      ret = ptrace(PTRACE_DETACH, pid, NULL, NULL);
      printf("SIGSTOP detach ret=%d\n", ret);
      break;
    } else {
      printf("other signal %d\n", sig);
    }
    sleep(2);
  }

  return 0;
}
$ ./attach 30389
pid=30389
attach ret=0
cont ret=0

waitpid ret=30389.
WIFSTOPPED
SIGTRAP cont ret=0 err=Success

waitpid ret=30389.
WIFSIGNALED
SIGTRAP cont ret=-1 err=No such process
^C

Linux
PTRACE\u ATTACH
请求,尽管其参数名为pid,但将只跟踪该线程

您可以通过将此函数添加到程序并在两个线程中调用它来验证这一点:

#define trprefix "TracerPid:"

int tracerpid()
{
  char stfile[100], buf[512];
  sprintf(stfile, "/proc/self/task/%d/status", (int)gettid());
  int trpid = -1;
  FILE *st = fopen(stfile, "r");
  if (st != NULL) {
    while (fgets(buf, sizeof buf, st) != NULL) {
      if (strncmp(buf, trprefix, strlen(trprefix)) == 0)
        trpid = atoi(buf+strlen(trprefix));
    }
    fclose(st);
  }
  return trpid;
}
您将看到父线程的跟踪器PID是“附加”进程的跟踪器PID,而子线程的跟踪器PID是0

当子线程引发
SIGTRAP
时,线程没有跟踪器,因此将采取
SIGTRAP
的默认操作-整个进程将被终止。这就是为什么跟踪程序说waitpid返回了
wifsignalid

要解决此问题,请执行以下操作:

  • 在“mt”程序中,将调用移动到
    pthread_create
    to be,使其位于第一个延迟循环之后,这将给您足够的时间在创建新线程之前连接到进程

  • 将其添加到
    ptrace(ptrace\u attach,…)之后的“attach”程序中;waitpid(…)

    errno = 0;
    ret = ptrace(PTRACE_SETOPTIONS, pid, NULL, PTRACE_O_TRACECLONE);
    printf("setoptions ret=%d err=%s\n", ret, strerror(errno));
    
    PTRACE\u O\u TRACECLONE
    选项将允许您的程序跟踪目标通过
    clone
    创建的每个线程

  • 将所有
    waitpid(pid,…)
    转换为
    waitpid(-1,…)
    ,以便程序等待任何线程


我添加了C标志。尽管询问者说
.cpp
文件,但代码是C。