1. 程式人生 > >linux之使用ptrace 跟蹤多執行緒程式

linux之使用ptrace 跟蹤多執行緒程式

1.ptrace 原型說明

 #include <sys/ptrace.h>
 long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);

 在使用PTRACE_TRACEME引數時,跟蹤多執行緒程式需要使用PTRACE_SETOPTIONS來設定ptrace相關屬性。

 PTRACE_SETOPTIONS 是將父程序內由data指向的值設定為ptrace 選項,data作為掩碼來解釋,由下面的標誌來指定:

    (1) PTRACE_O_EXITKILL:當跟蹤程序退出時,向所有被跟蹤程序傳送SIGKILL訊號將其退出,這個引數可以防止被跟蹤程序脫離跟蹤程序的控制。

    (2) PTRACE_O_TRACECLONE:被跟蹤程序在下一次呼叫clone()時將其停止,並自動跟蹤新產生的程序,新產生的程序剛開始收到SIGSTOP訊號。其新產生的程序的pid可以  

        通過PTRACE_GETEVENTMSG得到。

    (3) PTRACE_O_TRACEEXEC:被跟蹤程序在下一次呼叫exec()函式時使其停止。

    (4) PTRACE_O_TRACEEXIT:被跟蹤程序在退出是停止其執行,被跟蹤程序的退出狀態可通過PTRACE_GETEVENTMSG獲得。

    (5) PTRACE_O_TRACEFORK:被跟蹤程序在下次呼叫fork()時停止執行,並自動跟蹤新產生的程序,新產生的程序剛開始收到SIGSTOP訊號。其新產生的程序的pid可以  

        通過PTRACE_GETEVENTMSG得到。

    (6) PTRACE_O_TRACEVFORK:被跟蹤程序在下次呼叫vfork()時停止執行,並自動跟蹤新產生的程序,新產生的程序剛開始收到SIGSTOP訊號。其新產生的程序的pid可以  

          通過PTRACE_GETEVENTMSG得到。

  PTRACE_GETEVENTMSG:獲取剛剛發生的ptrace事件訊息,並存放在跟蹤程序由data指向的位置,addr引數被忽略。對於

  PTRACE_EVENT_FORK,PTRACE_EVENT_VFORK,PTRACE_EVENT_VFORKDOWN和PTRACE_EVENT_CLONE,data是新程序的pid.

#include <stdio.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <pthread.h>

void *thread_function(void *arg);
char message[] = "hello";
int main()
{
	int res;
	pthread_t a_thread;
	void *thread_result;
	res = pthread_create(&a_thread, NULL, thread_function, (void*) message);
	if (res != 0)
	{
		printf("Thread creation failed");
		exit(EXIT_FAILURE);
	}
	printf("Wait for thread to finish...\n");
	//等待上面執行緒結束
	res = pthread_join(a_thread, &thread_result);
	if (res != 0)
	{
		perror("Thread join failed");
		exit(EXIT_FAILURE);
	}
	printf("Thread joined, it returned %s\n", (char *) thread_result);
	exit(EXIT_SUCCESS);
	//return 0;
}

void *thread_function(void *arg)
{
	printf("thread_function is running ,Argument was %s\n", (char*)arg);
	pthread_exit("Thank you for the CPU time");
}
#include <stdio.h>
#include <sys/ptrace.h>
#include <sys/user.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>


//http://www.xuebuyuan.com/1572720.html
int main()
{
	pid_t child_pid;
	int status = 0;

	if ((child_pid = fork()) == 0) //子程序返回
	{
		ptrace(PTRACE_TRACEME, 0, NULL, NULL);
		execl("/bin/ping", "ping www.baidu.com", 0);//這個路徑需要更改
		printf("child process start failed...\n");
	}
	else
	{
		wait(NULL); //接收SIGTRAP訊號
		long ptraceOption = PTRACE_O_TRACECLONE;
		ptrace(PTRACE_SETOPTIONS, child_pid, NULL, ptraceOption); //設定ptrace屬性PTRACE_SETOPTIONS

		ptrace(PTRACE_CONT, child_pid, NULL, NULL);

		while (1)
		{
			printf("parent process wait child pid \n");
			pid_t child_waited = waitpid(-1, &status, __WALL);//等待接收訊號
         

			if (WIFSTOPPED(status))
			{
				printf("child %ld recvied signal %d\n", (long)child_waited, WSTOPSIG(status));
			}

			if (WIFSIGNALED(status))
			{
				printf("child %ld recvied signal %d\n", (long)child_waited, WTERMSIG(status));
			}

			if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP)
			{ //新執行緒被建立完成後,收到的訊號,或者遇到斷點時

				ptrace(PTRACE_CONT, child_waited, 1, NULL);
				continue;
			}

			if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP)
			{
			    //當一個執行緒建立另一個執行緒返回時,收到的訊號
				pid_t new_pid;
				if (((status >> 16) & 0xffff) == PTRACE_EVENT_CLONE)
				{
					if (ptrace(PTRACE_GETEVENTMSG, child_waited, 0, &new_pid)
					        != -1)
					{
						printf("thread %d created\n", new_pid);

					}

				}
			}

			if (child_waited == -1)
				break;

			if (WIFEXITED(status))
			{ //執行緒結束時,收到的訊號
				printf("thread %d exited with status %d\t\n",
					child_waited,
					WEXITSTATUS(status));
			}

			ptrace(PTRACE_CONT, child_waited, 1, NULL);
		}

	}

	return 0;
}