2017-06-14 141 views
0

如果我有这样的代码:PTRACE_TRACEME的范围是什么?

void child() { 
    do_something(); 
    ptrace(PTRACE_TRACEME, 0, 0, 0); 
    do_some_other_things(); 
} 

然后将do_something()由家长进行跟踪?

我在linux文档中发现,没有这种东西。它只是说这应该在tracee中被调用。

PTRACE_TRACEME

表明,该过程是要由它的父进行跟踪。如果其父 不希望跟踪它,则 进程可能不应该发出此请求。 (PID,地址和数据 忽略)。

回答

1

一个更好的解释见How Debuggers Work Part 1,但总的来说,没有,也不会直到tracee接收的信号跟踪do_something()函数。

ptrace的调用来自同一人ptrace的你引用的描述:

一个进程可以通过调用fork(2),并具有 所产生的孩子做一个 启动跟踪PTRACE_TRACEME,后面(通常)由execve(2)。或者,一个进程可以开始使用PTRACE_ATTACH或PTRACE_SEIZE跟踪另一个进程。

被跟踪时,即使信号 被忽略,每次信号传递时,tracee都会停止。 (SIGKILL有个例外,它有其通常的作用)。在下一次waitpid(2)调用(或相关的“等待”系统调用之一)时,跟踪器将会通知 ;该呼叫 将返回一个状态值,其中包含指示 tracee中停止原因的信息。

当tracee调用exec时,它会收到一个信号,这就是它停止的原因。

要illustrace,示踪程序mainer.c没有铃铛或口哨声:

//mainer.c 
#include <stdio.h> 
#include <sys/types.h> 
#include <sys/wait.h> 
#include <sys/ptrace.h> 
#include <sys/user.h> 
#include <unistd.h> 

int main(int argc, char ** argv) 
{ 
     pid_t child_pid; 
     char * programname = argv[1]; 

     child_pid = fork(); 
     if (child_pid == 0) 
     { 
       ptrace(PTRACE_TRACEME, 0, 0, 0); 
       execl(programname, programname, NULL); 
     } 

     else if (child_pid > 0) 
     { 
      int status; 

      wait(&status); 

      while (WIFSTOPPED(status)) 
      { 
        struct user_regs_struct regs; 
        ptrace(PTRACE_GETREGS, child_pid, 0, &regs); 
        unsigned instr = (PTRACE_PEEKTEXT, child_pid, regs.eip, 0); 
        printf("EIP = 0x%08x, instr = 0x%08x\n", regs.eip, instr); 

        ptrace(PTRACE_SINGLESTEP, child_pid, 0, 0); 

        wait(&status); 
      } 

     } 
} 

当tracee命中EXEC,它将接收信号,并且控制传递给家长,谁正在等待。 大会程序追查,但只是跟踪一个C程序时,提取有用的东西就太多打算:

; hello.asm 
section .text 
    global _start 

_start: 
    mov edx,len1 
    mov ecx,hello1 
    mov ebx,1 
    mov eax,4 

    int 0x80 


    mov edx,len2 
    mov ecx,hello2 
    mov ebx,1 
    mov eax,4 

    int 0x80 

    mov eax,1 
    int 0x80 

section .data 
    hello1 db "Hello",0xA 
    len1 equ $ - hello1 

    hello2 db "World",0xA 
    len2 equ $ - hello2 

运行此,./mainer hello

EIP = 0x08048080, instr = 0x00000000 
EIP = 0x08048085, instr = 0x00000000 
EIP = 0x0804808a, instr = 0x00000000 
EIP = 0x0804808f, instr = 0x00000000 
EIP = 0x08048094, instr = 0x00000000 
Hello 
EIP = 0x08048096, instr = 0x00000000 
EIP = 0x0804809b, instr = 0x00000000 
EIP = 0x080480a0, instr = 0x00000000 
EIP = 0x080480a5, instr = 0x00000000 
EIP = 0x080480aa, instr = 0x00000000 
World 
EIP = 0x080480ac, instr = 0x00000000 
EIP = 0x080480b1, instr = 0x00000000 

如果我们修改mainer.c所以孩子进程在调用do_something()之前调用跟踪的结果完全相同。这就是我如何修改它,如果你喜欢结果是一样的,你可以确认自己。

#include <stdio.h> 
#include <sys/types.h> 
#include <sys/wait.h> 
#include <sys/ptrace.h> 
#include <sys/user.h> 
#include <unistd.h> 

int do_something(void)  //added this function 
{ 
     printf("Doing something"); 
     return 0; 
} 


int main(int argc, char ** argv) 
{ 
     pid_t child_pid; 
     char * programname = argv[1]; 

     child_pid = fork(); 
     if (child_pid == 0) 
     { 
       ptrace(PTRACE_TRACEME, 0, 0, 0); 
       do_something();  //added this function call 
       execl(programname, programname, NULL); 
     } 

     else if (child_pid > 0) 
     { 
      int status; 

      wait(&status); 

      while (WIFSTOPPED(status)) 
      { 
        struct user_regs_struct regs; 
        ptrace(PTRACE_GETREGS, child_pid, 0, &regs); 
        unsigned instr = (PTRACE_PEEKTEXT, child_pid, regs.eip, 0); 
        printf("EIP = 0x%08x, instr = 0x%08x\n", regs.eip, instr); 

        ptrace(PTRACE_SINGLESTEP, child_pid, 0, 0); 

        wait(&status); 
      } 

     } 
} 

所以tracee不会停止,直到它接收到的信号,这是当它调用exec,并调用功能,不产生对tracee的信号会发生什么,但也有其他的方式来发送发信号给追踪者并开始追踪,尽管他们不像执行和等待那样整洁。