You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
224 lines
5.8 KiB
224 lines
5.8 KiB
/*
|
|
* Copyright 2002-2019 Intel Corporation.
|
|
*
|
|
* This software is provided to you as Sample Source Code as defined in the accompanying
|
|
* End User License Agreement for the Intel(R) Software Development Products ("Agreement")
|
|
* section 1.L.
|
|
*
|
|
* This software and the related documents are provided as is, with no express or implied
|
|
* warranties, other than those that are expressly stated in the License.
|
|
*/
|
|
|
|
/*! @file
|
|
* A test for callbacks around fork in jit mode.
|
|
* The test checks that
|
|
* - callbacks before/after fork are called
|
|
* - context in after-fork callback includes the correct child pid
|
|
*/
|
|
#include <stdio.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#if defined(TARGET_MAC)
|
|
#include <sys/syscall.h>
|
|
#else
|
|
#include <syscall.h>
|
|
#endif
|
|
|
|
#include "pin.H"
|
|
|
|
#include <iostream>
|
|
#include <fstream>
|
|
using std::ofstream;
|
|
using std::cerr;
|
|
using std::string;
|
|
using std::endl;
|
|
|
|
/* ===================================================================== */
|
|
|
|
KNOB<string> KnobOutputFile(KNOB_MODE_WRITEONCE, "pintool",
|
|
"o", "fork_jit_tool.out", "specify file name");
|
|
|
|
ofstream Out;
|
|
/* ===================================================================== */
|
|
|
|
INT32 Usage()
|
|
{
|
|
cerr <<
|
|
"This pin tool tests probe replacement.\n"
|
|
"\n";
|
|
cerr << KNOB_BASE::StringKnobSummary();
|
|
cerr << endl;
|
|
return -1;
|
|
}
|
|
|
|
|
|
pid_t childPid = 0;
|
|
PIN_LOCK pinLock;
|
|
ofstream childOut;
|
|
|
|
/*
|
|
* To make sure that before-fork callback works
|
|
*/
|
|
VOID BeforeFork(THREADID threadid, const CONTEXT* ctxt, VOID * arg)
|
|
{
|
|
PIN_GetLock(&pinLock, threadid+1);
|
|
Out << "TOOL: Before fork." << endl;
|
|
PIN_ReleaseLock(&pinLock);
|
|
}
|
|
|
|
/*
|
|
* To make sure that after-fork callback works
|
|
* and
|
|
* the context has the correct child pid in syscall-return register.
|
|
* The child pid value should be equal in after-fork and after-syscall
|
|
* callbacks.
|
|
*/
|
|
VOID AfterForkInParent(THREADID threadid, const CONTEXT* ctxt, VOID * arg)
|
|
{
|
|
pid_t parentPid = *(pid_t*)&arg;
|
|
PIN_GetLock(&pinLock, threadid+1);
|
|
Out << "TOOL: After fork in parent." << endl;
|
|
PIN_ReleaseLock(&pinLock);
|
|
if (PIN_GetPid() != parentPid)
|
|
{
|
|
cerr << "PIN_GetPid() fails in parent process" << endl;
|
|
exit(-1);
|
|
}
|
|
else
|
|
{
|
|
Out << "PIN_GetPid() is correct in parent process" << endl;
|
|
}
|
|
|
|
#ifdef TARGET_BSD
|
|
SYSCALL_STANDARD syscallStd = SYSCALL_STANDARD_IA32E_BSD;
|
|
#else
|
|
#if defined (TARGET_IA32E)
|
|
SYSCALL_STANDARD syscallStd = SYSCALL_STANDARD_IA32E_LINUX;
|
|
#else
|
|
#ifdef TARGET_MAC
|
|
SYSCALL_STANDARD syscallStd = SYSCALL_STANDARD_IA32_MAC;
|
|
#else
|
|
SYSCALL_STANDARD syscallStd = SYSCALL_STANDARD_IA32_LINUX;
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
pid_t afterForkChildPid = (pid_t)PIN_GetSyscallReturn(ctxt, syscallStd);
|
|
if (!childPid)
|
|
{
|
|
childPid = afterForkChildPid;
|
|
}
|
|
else if (childPid != afterForkChildPid)
|
|
{
|
|
cerr << "Child pid received in syscall-after callback " <<
|
|
childPid << " and child Pid in after-fork callback " <<
|
|
afterForkChildPid << " don't match " << endl;
|
|
exit(-1);
|
|
}
|
|
}
|
|
|
|
VOID OpenChildOutput()
|
|
{
|
|
if (!childOut.is_open())
|
|
{
|
|
char *outFileName = new char[KnobOutputFile.Value().size()+10];
|
|
sprintf(outFileName, "%s_%d", KnobOutputFile.Value().c_str(), PIN_GetPid());
|
|
childOut.open(outFileName);
|
|
}
|
|
}
|
|
|
|
VOID AfterForkInChild(THREADID threadid, const CONTEXT* ctxt, VOID * arg)
|
|
{
|
|
|
|
// After the fork, there is only one thread in the child process. It's possible
|
|
// that a different thread in the parent held this lock when the fork() happened.
|
|
// Since that thread does not exist in the child, it will never release the lock.
|
|
// Compensate by re-initializing the lock here in the child.
|
|
|
|
|
|
PIN_GetLock(&pinLock, threadid+1);
|
|
PIN_ReleaseLock(&pinLock);
|
|
|
|
pid_t parentPid = *(pid_t*)&arg;
|
|
|
|
OpenChildOutput();
|
|
|
|
childOut << "TOOL: After fork in child." << endl;
|
|
|
|
pid_t currentPid = PIN_GetPid();
|
|
|
|
if ((currentPid == parentPid) || (getppid() != parentPid))
|
|
{
|
|
cerr << "PIN_GetPid() fails in child process" << endl;
|
|
exit(-1);
|
|
}
|
|
else
|
|
{
|
|
childOut << "PIN_GetPid() is correct in child process" << endl;
|
|
}
|
|
childOut << "Child pid " << currentPid << endl;
|
|
|
|
}
|
|
|
|
UINT32 lastSyscall = (UINT32)(-1);
|
|
|
|
VOID SyscallBefore(THREADID tid, CONTEXT *ctxt, SYSCALL_STANDARD scStd,
|
|
VOID *arg)
|
|
{
|
|
lastSyscall = (UINT32)PIN_GetSyscallNumber(ctxt, scStd);
|
|
}
|
|
|
|
VOID SyscallAfter(THREADID tid, CONTEXT *ctxt, SYSCALL_STANDARD scStd,
|
|
VOID *arg)
|
|
{
|
|
pid_t parentPid = *(pid_t*)&arg;
|
|
pid_t currentPid = PIN_GetPid();
|
|
if ((
|
|
#if defined (TARGET_MAC) || defined (TARGET_BSD)
|
|
(lastSyscall == SYS_fork)
|
|
#else
|
|
(lastSyscall == SYS_fork) || (lastSyscall == SYS_clone)
|
|
#endif
|
|
)
|
|
&& (parentPid == currentPid))
|
|
{
|
|
//We are looking at ater-fork in parent
|
|
pid_t res = PIN_GetSyscallReturn(ctxt, scStd);
|
|
if (childPid)
|
|
{
|
|
if (res != childPid)
|
|
{
|
|
cerr << "Child pid received in after fork callback " <<
|
|
childPid << " and child Pid in syscall-after callback " <<
|
|
res << " don't match " << endl;
|
|
exit(-1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
int main(INT32 argc, CHAR **argv)
|
|
{
|
|
if( PIN_Init(argc,argv) )
|
|
{
|
|
return Usage();
|
|
}
|
|
|
|
PIN_InitLock(&pinLock);
|
|
|
|
Out.open(KnobOutputFile.Value().c_str());
|
|
|
|
unsigned long parentPid = (unsigned long)PIN_GetPid();
|
|
PIN_AddForkFunction(FPOINT_BEFORE, BeforeFork, (VOID*)parentPid);
|
|
PIN_AddForkFunction(FPOINT_AFTER_IN_PARENT, AfterForkInParent, (VOID *)parentPid);
|
|
PIN_AddForkFunction(FPOINT_AFTER_IN_CHILD, AfterForkInChild, (VOID*)parentPid);
|
|
PIN_AddSyscallEntryFunction(SyscallBefore, 0);
|
|
PIN_AddSyscallExitFunction(SyscallAfter, (VOID*)parentPid);
|
|
// Never returns
|
|
PIN_StartProgram();
|
|
|
|
return 0;
|
|
}
|