Читая статью Игра с ptrace , я нашел этот комментарий от пользователя, который также боролся с этим:
/* 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, ®s);
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, ®s);
}
}
}
rec = ptrace(PTRACE_CONT, child_waited, 1, NULL);
continue;
}