编辑(取得进展):

我正在尝试追踪一个vsftpd守护进程。我有以下代码附加到守护程序。然后,它成功显示第一个产生的进程的PID。但是,对于此生成过程的子级,它返回的PID为2,3,.。该程序确实捕获了生成过程的退出,这使我觉得自己很接近。

有任何想法吗?

void * trace_process(void * pid){
    pid_t child = atoi((char *) pid);
    long orig_eax, eax;
    int status;
    int callmade = FALSE;
    long opt = PTRACE_O_TRACEFORK;
    long newpid;

    long trace = ptrace(PTRACE_ATTACH,child,NULL,NULL);
    ptrace(PTRACE_SETOPTIONS,child,NULL,opt);
    if(trace == FALSE)
        printf("Attached to %d\n",child);

    while(TRUE) {
        child = waitpid(-1, &status, __WALL);

        if (status >> 16 == PTRACE_EVENT_FORK) {
            ptrace(PTRACE_GETEVENTMSG, child, NULL, (long) &newpid);
            ptrace(PTRACE_SYSCALL, newpid, NULL, NULL);

            printf("Attached to offspring %ld\n", newpid);
        }
        else{
            if(WIFEXITED(status))
                printf("Child %d exited\n", child);
        }

        ptrace(PTRACE_SYSCALL,child, NULL, NULL);
    }
}

样本输出:
Attached to 2015 // daemon
Attached to offspring 5302 // new connection handler
Attached to offspring 2 // should be authenticator
Child 5303 exited       // authenticator exiting on successful login
Attached to offspring 3 // should be process serving files
Child 5304 exited       // logout: process serving files
Child 5302 exited       // connection closed
Attached to offspring 5305 // new connection handler
Attached to offspring 2    // ... repeat
Child 5306 exited
Attached to offspring 3
Child 5307 exited
Child 5305 exited

最佳答案

在阅读Playing with ptrace文章时,我从一个也为此苦苦挣扎的用户那里找到了this comment:

/* After struggled a long time, I got a true way to make my ptrace worked
 * correct with multi-thread application. Here're my sample codes, hope it
 * can help others whom have the same confusion. */

char trapCode[] = {0, 0, 0, 0};
int status;

ptrace(PTRACE_ATTACH, childProcess, NULL, NULL); //childProcess is the main thread
wait(NULL);

printf("\nchild %d created\n", childProcess);
fflush(stdout);

long ptraceOption = PTRACE_O_TRACECLONE;
ptrace(PTRACE_SETOPTIONS, childProcess, NULL, ptraceOption);

struct user_regs_struct regs;

for(unsigned int i = 0; i < m_breakPoints.size(); i++)
{
    BreakPoint_Info breakPointInfo = m_breakPoints[i];
    if(!breakPointInfo.m_enabled)
        continue;

    unsigned int index = breakPointInfo.m_checkPointIndex;
    if(m_bytesBackup.find(m_checkPoints[index].m_offset) != m_bytesBackup.end())
        continue;

    unsigned long readAddr = m_checkPoints[index].m_offset;
    One_Byte_With_Result *oneByte = new One_Byte_With_Result;
    getData(childProcess, readAddr, trapCode, 4);
    oneByte->m_char = trapCode[0];
    trapCode[0] = 0xcc;
    putData(childProcess, readAddr, trapCode, 4);

    m_bytesBackup.insert(std::make_pair(m_checkPoints[index].m_offset, oneByte));
}

std::set allThreads;
std::set::iterator allThreadsIter;
allThreads.insert(childProcess);

int rec = ptrace(PTRACE_CONT, childProcess, NULL, NULL);

while(true)
{
    pid_t child_waited = waitpid(-1, &status, __WALL);

    if(child_waited == -1)
        break;

    if(allThreads.find(child_waited) == allThreads.end())
    {
        printf("\nreceived unknown child %d\t", child_waited);
        break;
    }

    if(WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP)
    {
        pid_t new_child;
        if(((status >> 16) & 0xffff) == PTRACE_EVENT_CLONE)
        {
            if(ptrace(PTRACE_GETEVENTMSG, child_waited, 0, &new_child) != -1)
            {
                allThreads.insert(new_child);
                ptrace(PTRACE_CONT, new_child, 0, 0);

                printf("\nchild %d created\t", new_child);
            }

            ptrace(PTRACE_CONT, child_waited, 0, 0);
            continue;
        }
    }

    if(WIFEXITED(status))
    {
        allThreads.erase(child_waited);
        printf("\nchild %d exited with status %d\t", child_waited, WEXITSTATUS(status));

        if(allThreads.size() == 0)
            break;
    }
    else if(WIFSIGNALED(status))
    {
        allThreads.erase(child_waited);
        printf("\nchild %d killed by signal %d\t", child_waited, WTERMSIG(status));

        if(allThreads.size() == 0)
            break;
    }
    else if(WIFSTOPPED(status))
    {
        int stopCode = WSTOPSIG(status);
        if(stopCode == SIGTRAP)
        {
            ptrace(PTRACE_GETREGS, child_waited, NULL, &regs);
            unsigned long currentEip = regs.eip;
            //printf("%d\t%08x\n", child_waited, currentEip);

            Address_Bytes_Map::iterator iter = m_bytesBackup.find(currentEip - 1);
            if(iter != m_bytesBackup.end())
            {
                iter->second->m_result = true;

                regs.eip = regs.eip - 1;
                getData(child_waited, regs.eip, trapCode, 4);
                trapCode[0] = iter->second->m_char;
                putData(child_waited, regs.eip, trapCode, 4);
                rec = ptrace(PTRACE_SETREGS, child_waited, NULL, &regs);
            }
        }
    }

    rec = ptrace(PTRACE_CONT, child_waited, 1, NULL);

    continue;
}

关于c - 如何跟踪多线程应用程序?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/5477976/

10-10 14:56
查看更多