/* * MemoryWrite, StackWrite * If store occurs and that address was used for read, make a log */ VOID MemoryWrite(ADDRINT memaddr, ADDRINT writesize) { treeNode *node; ADDRINT startoffset, endoffset; PIN_RWMutexReadLock(&data_lock); node = FindAddressInRange(data_root, memaddr); PIN_RWMutexUnlock(&data_lock); if(node && node->usedforread == TRUE) { startoffset = memaddr - node->address + node->offset; endoffset = memaddr - node->address + node->offset + writesize; fprintf(trace, "%x%lx:%s:%lx:%lx:D\n", pid, node->readid, node->path, startoffset, endoffset); fflush(trace); return; } PIN_RWMutexReadLock(&malloc_lock); node = FindAddressInRange(malloc_root, memaddr); PIN_RWMutexUnlock(&malloc_lock); if(node && node->usedforread == TRUE) { startoffset = memaddr - node->address + node->offset; endoffset = memaddr - node->address + node->offset + writesize; fprintf(trace, "%x%lx:%s:%lx:%lx:M\n", pid, node->readid, node->path, startoffset, endoffset); fflush(trace); return; } }
/* * ThreadStart * Called when every single thread starts * Insert new thread to BST */ VOID ThreadStart(THREADID threadIndex, CONTEXT *ctxt, INT32 flags, VOID *v) { PIN_THREAD_UID threadid = PIN_ThreadUid(); PIN_RWMutexWriteLock(&thread_lock); root_thread = InsertThread(threadid, root_thread); PIN_RWMutexUnlock(&thread_lock); }
/* * ThreadFini * Called when every single thread ends * Delete the thread from BST */ VOID ThreadFini(THREADID threadIndex, const CONTEXT *ctxt, INT32 code, VOID *v) { PIN_THREAD_UID threadid = PIN_ThreadUid(); PIN_RWMutexWriteLock(&thread_lock); root_thread = DeleteThread(threadid, root_thread); PIN_RWMutexUnlock(&thread_lock); }
static void DoTestReaderTryStress(THREAD_INFO *info, UINT32 *done) { // Try to acquire / release PIN_RWMUTEX as a reader using "try" as fast as possible. if (PIN_RWMutexTryReadLock(&RWMutex)) PIN_RWMutexUnlock(&RWMutex); CheckIfDone(info, done); }
static void DoTestReaderStress(THREAD_INFO *info, UINT32 *done) { // This test just tries to acquire and release PIN_RWMUTEX as fast as possible // as a reader lock. PIN_RWMutexReadLock(&RWMutex); PIN_RWMutexUnlock(&RWMutex); CheckIfDone(info, done); }
static void DoTestWriterStress(THREAD_INFO *info, UINT32 *done) { // This test just tries to acquire and release PIN_RWMUTEX as fast as possible // as a writer lock to see if we can provoke a deadlock due to missing a wakeup. PIN_RWMutexWriteLock(&RWMutex); PIN_RWMutexUnlock(&RWMutex); CheckIfDone(info, done); }
static void DoTestReaderWriterIntegrity(THREAD_INFO *info, UINT32 *done) { // This test checks that a "writer" thread can never hold the lock while // there is an active reader. if (info->_workerId & 1) { // Reader thread. // PIN_RWMutexReadLock(&RWMutex); ATOMIC::OPS::Increment(&ActiveReaders, 1); if (ATOMIC::OPS::Load(&IsActiveWriter)) { std::cout << "Reader got lock while there is an active writer" << std::endl; PIN_ExitProcess(1); } ATOMIC::OPS::Delay(DELAY_COUNT); ATOMIC::OPS::Increment(&ActiveReaders, -1); PIN_RWMutexUnlock(&RWMutex); } else { // Writer thread. // PIN_RWMutexWriteLock(&RWMutex); ATOMIC::OPS::Store<BOOL>(&IsActiveWriter, TRUE); if (ATOMIC::OPS::Load(&ActiveReaders) != 0) { std::cout << "Writer has lock while there are active readers" << std::endl; PIN_ExitProcess(1); } ATOMIC::OPS::Delay(DELAY_COUNT); ATOMIC::OPS::Store<BOOL>(&IsActiveWriter, FALSE); PIN_RWMutexUnlock(&RWMutex); } CheckIfDone(info, done); }
static void DoTestReaderWriterStress(THREAD_INFO *info, UINT32 *done) { // This test uses a mix of "reader" and "writer" threads to acquire and // release the PIN_RWMUTEX as fast as possible. if (info->_workerId & 1) { // Reader thread. // PIN_RWMutexReadLock(&RWMutex); PIN_RWMutexUnlock(&RWMutex); } else { // Writer thread. // PIN_RWMutexWriteLock(&RWMutex); PIN_RWMutexUnlock(&RWMutex); } CheckIfDone(info, done); }
/* * Malloc, Realloc * Catchs Memory allocations and insert the information to BST * Info : Address, Size */ VOID * Malloc( CONTEXT * context, AFUNPTR orgFuncptr, size_t size) { VOID * ret; PIN_CallApplicationFunction( context, PIN_ThreadId(), CALLINGSTD_DEFAULT, orgFuncptr, PIN_PARG(void *), &ret, PIN_PARG(size_t), size, PIN_PARG_END() ); PIN_RWMutexWriteLock(&malloc_lock); malloc_root = InsertMAddress(malloc_root, (ADDRINT)ret, size, 0); PIN_RWMutexUnlock(&malloc_lock); return ret; }
/* * Fini * Called when process ends * Clean up mems & locks */ VOID Fini(INT32 code, VOID *v) { PIN_RWMutexWriteLock(&malloc_lock); while(malloc_root != NULL) malloc_root = DeleteAddress(malloc_root, malloc_root->address); PIN_RWMutexUnlock(&malloc_lock); PIN_RWMutexWriteLock(&data_lock); while(data_root != NULL) data_root = DeleteAddress(data_root, data_root->address); PIN_RWMutexUnlock(&data_lock); PIN_RWMutexWriteLock(&thread_lock); while(root_thread != NULL) root_thread = DeleteThread(root_thread->tid, root_thread); PIN_RWMutexUnlock(&thread_lock); PIN_RWMutexFini(&thread_lock); PIN_RWMutexFini(&data_lock); PIN_RWMutexFini(&malloc_lock); PIN_MutexFini(&readid_lock); fclose(trace); }
/* * Return * Called when native procedure returns * Delete read info of removed stack area */ VOID Return(ADDRINT sp) { PIN_THREAD_UID threadid = PIN_ThreadUid(); PIN_RWMutexReadLock(&thread_lock); THREAD* thread = FindThread(threadid); PIN_RWMutexUnlock(&thread_lock); treeNode *node = FindMinAddress(thread->stack); if(node == NULL) return; while(node->address <= sp) { thread->stack = DeleteAddress(thread->stack, node->address); node = FindMinAddress(thread->stack); if(node == NULL) return; } }
/* * Free * Delete Allocation Info from BST */ VOID Free( CONTEXT * context, AFUNPTR orgFuncptr, void * ptr) { if(ptr != NULL) { if(!FindAddress(malloc_root, (ADDRINT)ptr)) { PIN_RWMutexWriteLock(&malloc_lock); malloc_root = DeleteMAddress(malloc_root, (ADDRINT)ptr); PIN_RWMutexUnlock(&malloc_lock); } } PIN_CallApplicationFunction( context, PIN_ThreadId(), CALLINGSTD_DEFAULT, orgFuncptr, PIN_PARG(void), PIN_PARG(void *), ptr, PIN_PARG_END() ); }
VOID StackWrite(ADDRINT memaddr, ADDRINT writesize) { treeNode *node; PIN_THREAD_UID threadid = PIN_ThreadUid(); ADDRINT startoffset, endoffset; PIN_RWMutexReadLock(&thread_lock); THREAD* thread = FindThread(threadid); PIN_RWMutexUnlock(&thread_lock); node = FindAddressInRange(thread->stack, memaddr); if(node && node->usedforread == TRUE) { startoffset = memaddr - node->address + node->offset; endoffset = memaddr - node->address + node->offset + writesize; fprintf(trace, "%x%lx:%s:%lx:%lx:S\n", pid, node->readid, node->path, startoffset, endoffset); fflush(trace); } }
static void DoTestWriterIntegrity(THREADID tid, THREAD_INFO *info, UINT32 *done) { // This test checks to see if two writer threads can be in the PIN_RWMUTEX mutex // simultaneously. PIN_RWMutexWriteLock(&RWMutex); THREADID owner = HasLock; HasLock = tid; if (owner != INVALID_THREADID) { std::cout << "Two writer theads in rwmutex simultaneously: " << std::dec << tid << " and " << owner << std::endl; PIN_ExitProcess(1); } ATOMIC::OPS::Delay(DELAY_COUNT); HasLock = INVALID_THREADID; PIN_RWMutexUnlock(&RWMutex); CheckIfDone(info, done); }
/* * SysBefore * Our focus is on "read" syscall, so it traces only read-like syscalls - read, readv, pread, preadv */ VOID SysBefore(ADDRINT ip, ADDRINT num, ADDRINT arg0, ADDRINT arg1, ADDRINT arg2, ADDRINT arg3, ADDRINT arg4, ADDRINT arg5, ADDRINT sp) { treeNode *node; struct stat stat; off_t offset; char buf[2][MAX_BUFSIZE]; int tmp; int i; long unsigned int readid; long unsigned int size; struct iovec *vec; PIN_THREAD_UID threadid = PIN_ThreadUid(); PIN_RWMutexReadLock(&thread_lock); THREAD* thread = FindThread(threadid); PIN_RWMutexUnlock(&thread_lock); assert(thread); switch(num) { case SYS_READ: case SYS_PREAD64: //arg0 : fd //arg1 : buf addr //arg2 : buf size //stdin if(arg0 == 0) break; //Get the path of current file sprintf(buf[0], "/proc/self/fd/%d", (int)arg0); tmp = readlink(buf[0], buf[1], MAX_BUFSIZE); //Skip socket, pipe, proc filesystem, etc if(buf[1][0] != '/') break; if(strncmp(buf[1], "/proc", 5) == 0) break; else if(strncmp(buf[1], "/dev/urandom", 12)== 0) break; buf[1][tmp] = '\0'; if(num == SYS_READ) { //If SYS_READ, we have to find out current file pointer offset = lseek((int)arg0, 0, SEEK_CUR); if(offset+1 == 0) offset = 0; } else { //Or pread case, file pointer is given offset = arg3; } //Get the file size size = fstat((int)arg0, &stat); assert(size == 0); size = stat.st_size; if(offset+arg2 > size) size = size - offset; else size = arg2; if(size <= 0) break; //Get Unique ID for each Read readid = GetReadId(); sprintf(thread->buffer, "%s:%lx:%lx:%lx:", buf[1], offset, size, stat.st_size); /* * Add Read Info to Data Structure * * Find the buffer address in malloc BST * if found, write the info to it * else * Buffer is in stack or data segment */ PIN_RWMutexReadLock(&malloc_lock); node = FindAddressInRange(malloc_root, arg1); PIN_RWMutexUnlock(&malloc_lock); if(node != NULL) { node->usedforread = TRUE; node->offset = offset; node->fd = (int)arg0; if(node->path != NULL) free(node->path); node->path = strdup(buf[1]); node->size = size; node->readid = readid; strcat(thread->buffer, "M"); } else if(arg1 >= sp - pagesize) { thread->stack = InsertSAddress(thread->stack, arg1, (int)arg0, size, offset, buf[1], readid); strcat(thread->buffer, "S"); } else { PIN_RWMutexWriteLock(&data_lock); data_root = InsertDAddress(data_root, arg1, (int)arg0, size, offset, buf[1], readid); PIN_RWMutexUnlock(&data_lock); strcat(thread->buffer, "D"); } fprintf(trace, "%s\n", thread->buffer); fflush(trace); break; case SYS_PREADV: case SYS_READV: //arg0 : fd //arg1 : iov //arg2 : iovcnt //iovec.iov_base : address //iovec.iov_len : length //stdin if(arg0 == 0) break; sprintf(buf[0], "/proc/self/fd/%d", (int)arg0); tmp = readlink(buf[0], buf[1], MAX_BUFSIZE); if(buf[1][0] != '/') break; if(strncmp(buf[1], "/proc", 5) == 0) break; readid = GetReadId(); buf[1][tmp] = '\0'; if(num == SYS_READV) { offset = lseek((int)arg0, 0, SEEK_CUR); if(offset+1 == 0) offset = 0; } else offset = arg3; size = fstat((int)arg0, &stat); assert(size == 0); vec = (struct iovec *)arg1; for(i=0; i < (int)arg2; i++) { size = stat.st_size; if(offset+vec[i].iov_len > size) size = size - offset; else size = vec[i].iov_len; if(size <= 0) continue; PIN_RWMutexReadLock(&malloc_lock); node = FindAddressInRange(malloc_root, (ADDRINT)vec[i].iov_base); PIN_RWMutexUnlock(&malloc_lock); sprintf(thread->buffer, "%s:%lx:%lx:%lx:",buf[1], offset, size, stat.st_size); if(node != NULL) { strcat(thread->buffer, "M"); node->usedforread = TRUE; node->offset = offset; node->fd = (int)arg0; if(node->path != NULL) free(node->path); node->path = strdup(buf[1]); node->size = size; node->readid = readid; } else if(arg1 >= sp - pagesize) { strcat(thread->buffer, "S"); thread->stack = InsertSAddress(thread->stack, arg1, (int)arg0, size, offset, buf[1], readid); } else { strcat(thread->buffer, "D"); PIN_RWMutexWriteLock(&data_lock); data_root = InsertDAddress(data_root, arg1, (int)arg0, size, offset, buf[1], readid); PIN_RWMutexUnlock(&data_lock); } fprintf(trace, "%s\n", thread->buffer); fflush(trace); } break; /* case SYS_WRITE: case SYS_PWRITE64: if(arg0 == 1 || arg0 == 2) break; if(num == SYS_WRITE) { offset = lseek((int)arg0, 0, SEEK_CUR); if(offset + 1 == 0) offset = 0; } else offset = arg3; sprintf(thread->buffer, "%lx:%lx:%lx:%lx:%lx:", num, arg0, arg1, arg2, offset); break; case SYS_PWRITEV: case SYS_WRITEV: //stdin if(arg0 == 0) break; sprintf(buf[0], "/proc/self/fd/%d", (int)arg0); tmp = readlink(buf[0], buf[1], MAX_BUFSIZE); buf[1][tmp] = '\0'; if(num == SYS_PWRITEV) { offset = lseek((int)arg0, 0, SEEK_CUR); if(offset + 1 == 0) offset = 0; } else offset = arg3; vec = (struct iovec *)arg1; for(i=0; i < (int)arg2; i++) { sprintf(thread->buffer, "%lx:%lx:%lx:%lx:%lx:", num, arg0, (ADDRINT)vec[i].iov_base, vec[i].iov_len, offset); } break; */ default : break; } }
static void DoTestTryLocks(UINT32 *done) { // This is a collection of single-thread tests that make sure that the // various "try" operations succeed or fail as expected. BOOL gotLock = PIN_MutexTryLock(&Mutex); if (!gotLock) { std::cout << "Failure on uncontended PIN_MutexTryLock" << std::endl; PIN_ExitProcess(1); } gotLock = PIN_MutexTryLock(&Mutex); if (gotLock) { std::cout << "PIN_MutexTryLock was able to get a lock twice" << std::endl; PIN_ExitProcess(1); } gotLock = PIN_RWMutexTryWriteLock(&RWMutex); if (!gotLock) { std::cout << "Failure on uncontended PIN_RWMutexTryWriteLock" << std::endl; PIN_ExitProcess(1); } gotLock = PIN_RWMutexTryWriteLock(&RWMutex); if (gotLock) { std::cout << "PIN_RWMutexTryWriteLock was able to get a lock twice" << std::endl; PIN_ExitProcess(1); } gotLock = PIN_RWMutexTryReadLock(&RWMutex); if (gotLock) { std::cout << "PIN_RWMutexTryReadLock was able to get a lock when writer owns it" << std::endl; PIN_ExitProcess(1); } PIN_RWMutexUnlock(&RWMutex); gotLock = PIN_RWMutexTryReadLock(&RWMutex); if (!gotLock) { std::cout << "Failure on uncontended PIN_RWMutexTryReadLock" << std::endl; PIN_ExitProcess(1); } gotLock = PIN_RWMutexTryReadLock(&RWMutex); if (!gotLock) { std::cout << "Unable to get a reader lock twice" << std::endl; PIN_ExitProcess(1); } PIN_SemaphoreSet(&Sem1); if (!PIN_SemaphoreIsSet(&Sem1)) { std::cout << "Expected 'set' status from PIN_SemaphoreIsSet" << std::endl; PIN_ExitProcess(1); } PIN_SemaphoreClear(&Sem1); if (PIN_SemaphoreIsSet(&Sem1)) { std::cout << "Expected 'clear' status from PIN_SemaphoreIsSet" << std::endl; PIN_ExitProcess(1); } if (PIN_SemaphoreTimedWait(&Sem1, 1)) { std::cout << "Expected PIN_SemaphoreTimedWait to time-out" << std::endl; PIN_ExitProcess(1); } *done = 1; }