/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M Method: COBall::CImpIBall::Reset Summary: The Reset member method of the IBall interface implementation. Called by outside clients of a COBall object to reset the virtual ball. It is restored to the upper left corner. Args: RECT* pNewRect, Pointer to a RECT structure. Tells the COBall the bounding rectangle within which the ball can move. short nBallSize, The size of the ball in pixels. nBallSize == Width == Height meaning that a circle is assumed. Modifies: ... Returns: void M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ STDMETHODIMP COBall::CImpIBall::Reset( RECT* pNewRect, short nBallSize) { HRESULT hr = E_FAIL; int nDim, xDirection, yDirection; if (OwnThis()) { // Find the thread who is executing this and remember its color. FindThread(); m_xSkew = m_ySkew = BALL_MOVE_SKEW; m_WinRect.left = pNewRect->left; m_WinRect.top = pNewRect->top; m_WinRect.right = pNewRect->right; m_WinRect.bottom = pNewRect->bottom; nDim = nBallSize ? nBallSize : max(5, m_WinRect.right / 13); SetDimensions(nDim, nDim); SetPosition(0, 0); xDirection = ((lRandom() % m_xSkew) + m_xSkew); yDirection = ((lRandom() % m_ySkew) + m_ySkew); SetDirection(xDirection, yDirection); hr = NOERROR; UnOwnThis(); } return hr; }
void VScriptInstance::WaitSeconds(lua_State *pState, float seconds) { if (seconds<=0.f) return; VLuaThreadInfo* pInfo = FindThread(pState); pInfo->fWaitTime += seconds; SCRIPTINSTANCES.AddWaitingObject(this); }
/* * 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; } }
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); } }
/* * addAllWOWModules - add all modules as libraries. This is invoked if * WOW was already running, since we will get no * lib load notifications if it was. */ static void addAllWOWModules( void ) { MODULEENTRY me; thread_info *ti; IMAGE_NOTE im; int rc; ti = FindThread( DebugeeTid ); me.dwSize = sizeof( MODULEENTRY ); for( rc = pVDMModuleFirst( ProcessInfo.process_handle, ti->thread_handle, &me, NULL, 0 ); rc != 0 && strcmp( me.szModule, WOWAppInfo.modname ) != 0; rc = pVDMModuleNext( ProcessInfo.process_handle, ti->thread_handle, &me, NULL, 0 ) ) { memcpy( &im.Module, &me.szModule, sizeof( me.szModule ) ); memcpy( &im.FileName, &me.szExePath, sizeof( me.szExePath ) ); AddLib( TRUE, &im ); me.dwSize = sizeof( MODULEENTRY ); } }
/* * addKERNEL - add the KERNEL module to the library load (WOW) */ static void addKERNEL( void ) { #if 0 /* * there are bugs in the way VDMDBG.DLL implements some of this * stuff, so this is currently disabled */ MODULEENTRY me; thread_info *ti; IMAGE_NOTE im; int rc; ti = FindThread( DebugeeTid ); me.dwSize = sizeof( MODULEENTRY ); for( rc = pVDMModuleFirst( ProcessInfo.process_handle, ti->thread_handle, &me, NULL, 0 ); rc != 0; rc = pVDMModuleNext( ProcessInfo.process_handle, ti->thread_handle, &me, NULL, 0 ) ) { if( !memicmp( me.szModule, "KERNEL", 6 ) ) { memcpy( &im.Module, &me.szModule, sizeof( me.szModule ) ); memcpy( &im.FileName, &me.szExePath, sizeof( me.szExePath ) ); AddLib( TRUE, &im ); break; } me.dwSize = sizeof( MODULEENTRY ); } #else IMAGE_NOTE im; /* * this is a giant kludge, but it works. Since KERNEL is already * loaded in the WOW , we never get a DLL load notification, so * we can't show any symbols. This fakes up the necessary information */ strcpy( im.Module, "KERNEL" ); GetSystemDirectory( im.FileName, sizeof( im.FileName ) ); strcat( im.FileName, "\\KRNL386.EXE" ); AddLib( TRUE, &im ); #endif }
BOOL IsBigSel( WORD sel ) { #if defined( MD_axp ) | defined( MD_ppc ) return( TRUE ); #elif defined( MD_x86 ) || defined( MD_x64 ) thread_info *ti; LDT_ENTRY ldt; if( sel == FlatCS || sel == FlatDS ) { return( TRUE ); } ti = FindThread( DebugeeTid ); if( ti == NULL ) { return( TRUE ); } GetThreadSelectorEntry( ti->thread_handle, sel, &ldt ); return( ldt.HighWord.Bits.Default_Big ); #else #error IsBigSel not configured #endif }
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M Method: COBall::CImpIBall::Move Summary: The Move member method of this IBall interface implementation. Called by outside clients of a COBall object to advance the "motion" of this COBall virtual ball entity. Args: BOOL bAlive TRUE means stay alive; FALSE means don't move but die. Modifies: m_bAlive. Returns: BOOL TRUE means the move was done and the ball is still alive. FALSE means the move was not done and the ball has been killed. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ STDMETHODIMP COBall::CImpIBall::Move(BOOL bAlive, BOOL* bRet) { *bRet = FALSE; if (OwnThis()) { if (bAlive) { // Find thread that is now executing this code. Remember its Id and // assign it a color. If this thread previously visited here then // use its remembered values. In any case, set a color value in // m_crColor of its existing or newly assigned color. FindThread(); // Ask the Ball if it has hit any of the edges of the current window // rectangle. If so, it will recalculate its position and direction to // achieve a "bounce" effect in its motion the next time it is painted. CheckBounce(); // Calculate and set new ball position. if(m_bNewPosition) { m_bNewPosition = FALSE; m_XForm.Clear(); m_XForm.Trans(m_xPosition, m_yPosition); } else m_XForm.Trans(m_xDirection, m_yDirection); } else m_bAlive = FALSE; *bRet = m_bAlive; UnOwnThis(); } return S_OK; }
//----------------------------------------------------------------------------- // Process all signals we want to handle // signal - signal caught // siginfo - signal info // context - context void ProcessSignal(int signal, siginfo_t* info, void* context) { Thread* thread; // Thread for this signal int ret; switch(signal) { case SIGABRT: // Abort case SIGINT: // Interrupt (Ctrl+C from the user) case SIGPWR: // Power failure case SIGQUIT: // Quit case SIGTERM: // Termination // Normal exit //printf("Exit signal: %s\n", strsignal(signal)); _exitMain = true; // Exit the process break; case SIGBUS: // BUS error case SIGFPE: // Floating-point exception case SIGSEGV: // Segmentation violation case SIGSYS: // Bad system call case SIGILL: // Illegal instruction case SIGSTKFLT: // Stack fault case SIGXFSZ: // File size limit exceeded // Crash signal //printf("Crash signal: %s\n", strsignal(signal)); ret = FindThread(pthread_self(), thread); if(!ret) { thread->OnCrash(signal); } else { printf("Can't find the crashed thread\n"); abort(); } break; default: // Unhandled signal printf("Unhandled signal: %s\n", strsignal(signal)); abort(); // Exit the process now with a core dump } }
/* * ThreadCtlProc */ BOOL CALLBACK ThreadCtlProc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) { WORD cmd; ThreadCtlInfo *info; LRESULT index; char buf[200]; DWORD threadid; ThreadNode *thread; ProcNode *process; DWORD susp_cnt; DWORD rc; char *action; info = (ThreadCtlInfo *)GET_DLGDATA( hwnd ); switch( msg ) { case WM_INITDIALOG: info = MemAlloc( sizeof( ThreadCtlInfo ) ); if( !GetProcessInfo( lparam, &info->procinfo ) ) { RCsprintf( buf, STR_CANT_GET_PROC_INFO, info->procid ); MessageBox( hwnd, buf, AppName, MB_OK | MB_ICONEXCLAMATION ); SendMessage( hwnd, WM_CLOSE, 0, 0 ); } info->procid = lparam; ThreadDlg = hwnd; SET_DLGDATA( hwnd, info ); fillThreadCtl( hwnd, &info->procinfo, buf ); RCsprintf( buf, STR_THREAD_4_PROC_X, lparam ); SetDlgItemText( hwnd, THREAD_PROC_NAME, buf ); sprintf( buf, "(%s)", info->procinfo.name ); SetDlgItemText( hwnd, THREAD_PROC_PATH, buf ); SendDlgItemMessage( hwnd, THREAD_LIST, LB_SETCURSEL, 0, 0L ); index = SendDlgItemMessage( hwnd, THREAD_LIST, LB_GETCURSEL, 0, 0L ); if( index != LB_ERR ) { enableChoices( hwnd, TRUE ); } fillThreadInfo( hwnd, &info->procinfo ); break; case WM_COMMAND: cmd = LOWORD( wparam ); if( cmd == THREAD_SUSPEND || cmd == THREAD_RESUME || cmd == THREAD_KILL || cmd == THREAD_SET_PRIORITY ) { index = SendDlgItemMessage( hwnd, THREAD_LIST, LB_GETCURSEL, 0, 0L ); if( index == LB_ERR ) { RCMessageBox( hwnd, STR_NO_SELECTED_THREAD, AppName, MB_OK | MB_ICONEXCLAMATION ); break; } SendDlgItemMessage( hwnd, THREAD_LIST, LB_GETTEXT, (WPARAM)index, (LPARAM)(LPSTR)buf ); threadid = getThreadId( buf ); process = FindProcess( info->procinfo.pid ); thread = FindThread( process, threadid ); } switch( cmd ) { case IDOK: SendMessage( hwnd, WM_CLOSE, 0, 0L ); break; case THREAD_REFRESH: RefreshInfo(); if( GetProcessInfo( info->procid, &info->procinfo ) ) { fillThreadCtl( hwnd, &info->procinfo, buf ); fillThreadInfo( hwnd, &info->procinfo ); } else { action = AllocRCString( STR_REFRESH ); RCMessageBox( hwnd, STR_CANT_REFRESH_THRD, action, MB_OK | MB_ICONEXCLAMATION ); FreeRCString( action ); } break; case THREAD_SUSPEND: action = AllocRCString( STR_THREAD_SUSPEND ); if( thread == NULL ) { RCsprintf( buf, STR_CANT_GET_HDL_4_THD_X, threadid ); MessageBox( hwnd, buf, action, MB_OK | MB_ICONEXCLAMATION ); } else { susp_cnt = SuspendThread( thread->threadhdl ); if( susp_cnt == -1 ) { RCsprintf( buf, STR_CANT_SUSPEND_THRD_X, threadid ); MessageBox( hwnd, buf, action, MB_ICONQUESTION | MB_OK ); } else if( susp_cnt > 0 ) { RCsprintf( buf, STR_THREAD_ALREADY_SUSP, threadid, susp_cnt ); index = MessageBox( hwnd, buf, action, MB_ICONQUESTION | MB_YESNO ); if( index == IDNO ) { ResumeThread( thread->threadhdl ); } } SendMessage( hwnd, WM_COMMAND, THREAD_REFRESH, 0L ); } FreeRCString( action ); break; case THREAD_RESUME: action = AllocRCString( STR_RESUME ); if( thread == NULL ) { RCsprintf( buf, STR_THREAD_NOT_RESUMED , threadid ); MessageBox( hwnd, buf, action, MB_OK | MB_ICONEXCLAMATION ); } else { susp_cnt = ResumeThread( thread->threadhdl ); if( susp_cnt == -1 ) { RCsprintf( buf, STR_CANT_RESUME_THRD_X, threadid ); MessageBox( hwnd, buf, action, MB_ICONEXCLAMATION | MB_OK ); } else if( susp_cnt == 0 ) { RCsprintf( buf, STR_THRD_IS_NOT_SUSP, threadid ); MessageBox( hwnd, buf, action, MB_ICONEXCLAMATION | MB_OK ); } else if( susp_cnt > 1 ) { RCsprintf( buf, STR_SUSP_COUNT_DECREMENTED, threadid, susp_cnt ); MessageBox( hwnd, buf, action, MB_ICONEXCLAMATION | MB_OK ); } SendMessage( hwnd, WM_COMMAND, THREAD_REFRESH, 0L ); } FreeRCString( action ); break; case THREAD_KILL: action = AllocRCString( STR_KILL ); if( thread == NULL ) { RCsprintf( buf, STR_THRD_NOT_TERMINATED, threadid ); MessageBox( hwnd, buf, action, MB_OK | MB_ICONEXCLAMATION ); } else if( GetRetCode( hwnd, RETCD_THREAD, thread->threadid, &rc ) ) { if( !TerminateThread( thread->threadhdl, rc ) ) { RCsprintf( buf, STR_CANT_KILL_THRD_X, threadid ); MessageBox( hwnd, buf, action, MB_OK | MB_ICONEXCLAMATION ); } SendMessage( hwnd, WM_COMMAND, THREAD_REFRESH, 0L ); } FreeRCString( action ); break; case THREAD_SET_PRIORITY: // { // ThreadPriorityInfo prinfo; // // if( thread == NULL ) { // sprintf( buf, "Unable to get a handle for thread %08X.\n", // threadid ); // MessageBox( hwnd, buf, "Set Priority", // MB_OK | MB_ICONEXCLAMATION ); // } else { // prinfo.procid = info->procid; // prinfo.thread = thread; // prinfo.priority = GetThreadPriority( thread->threadhdl ); // prinfo.procinfo = &info->procinfo; // DialogBoxParam( Instance, "THREAD_PRIORITY_DLG", hwnd, // ThreadPriorityDlgProc, (DWORD)&prinfo ); // fillThreadInfo( hwnd, &info->procinfo ); // } // } // break; case THREAD_LIST: if( HIWORD( wparam ) == LBN_SELCHANGE ) { fillThreadInfo( hwnd, &info->procinfo ); } break; } break; case DR_TASK_LIST_CHANGE: /* make sure this process still exists */ //here if( FindProcess( info->procid ) == NULL ) { //here SendDlgItemMessage( hwnd, THREAD_LIST, LB_RESETCONTENT, 0, 0L ); //here enableChoices( hwnd, FALSE ); //here info->proc = NULL; //here } else { //here fillThreadCtl( hwnd, info->proc, buf ); //here } break; case WM_CLOSE: EndDialog( hwnd, 0 ); break; case WM_DESTROY: MemFree( info ); ThreadDlg = NULL; break; default: return( FALSE ); } return( TRUE ); }
/* * ExceptionProc */ BOOL CALLBACK ExceptionProc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) { WORD cmd; ExceptDlgInfo *info; ProcNode *procinfo; WORD tmp; address addr; info = FaultGetExceptDlgInfo( hwnd ); switch( msg ) { case WM_INITDIALOG: /* make sure this dialog always comes up on top of everything else */ SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE ); SetWindowPos( hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE ); centerDialog( hwnd ); info = MemAlloc( sizeof( ExceptDlgInfo ) ); info->dbinfo = (DEBUG_EVENT *)lparam; info->rc = 0; info->action = 0; SetWindowLong( hwnd, DWL_USER, (DWORD)info ); info->procinfo = FindProcess( info->dbinfo->dwProcessId ); info->threadinfo = FindThread( info->procinfo, info->dbinfo->dwThreadId ); info->module = ModuleFromAddr( info->procinfo, info->dbinfo->u.Exception.ExceptionRecord.ExceptionAddress ); if( info->threadinfo != NULL ) { AllocMadRegisters( &(info->regs) ); LoadMADRegisters( info->regs, info->threadinfo->threadhdl ); GetCurrAddr( &( info->init_ip ), info->regs ); } if( info->module == NULL ) { info->got_dbginfo = FALSE; } else { if( !LoadDbgInfo( info->module ) ) { info->got_dbginfo = FALSE; } else { info->got_dbginfo = TRUE; } } if( LogData.autolog ) { //Just create the log and exit tmp = ConfigData.exception_action; CheckDlgButton( hwnd, INT_TERMINATE, BST_CHECKED ); SendMessage( hwnd, WM_COMMAND, MAKELONG( INT_ACT_AND_LOG, BN_CLICKED ), (LPARAM)GetDlgItem( hwnd, INT_ACT_AND_LOG ) ); ConfigData.exception_action = tmp; } else { fillExceptionDlg( hwnd, info ); } setProcessHdl( info->procinfo->prochdl ); break; case WM_COMMAND: cmd = LOWORD( wparam ); switch( cmd ) { case INT_ACT_AND_LOG: MakeLog( info ); /* fall through */ case INT_ACT: if( IsDlgButtonChecked( hwnd, INT_TERMINATE ) ) { ConfigData.exception_action = INT_TERMINATE; // hp = OpenProcess( PROCESS_TERMINATE, FALSE, // info->dbinfo->dwProcessId ); procinfo = FindProcess( info->dbinfo->dwProcessId ); if( procinfo == NULL ) { RCMessageBox( hwnd, STR_CANT_TERMINATE_APP, AppName, MB_OK | MB_ICONEXCLAMATION ); } else { TerminateProcess( procinfo->prochdl, -1 ); // CloseHandle( hp ); info->rc = DBG_CONTINUE; info->action = INT_TERMINATE; SendMessage( hwnd, WM_CLOSE, 0, 0L ); } } else if( IsDlgButtonChecked( hwnd, INT_CHAIN_TO_NEXT ) ) { ConfigData.exception_action = INT_CHAIN_TO_NEXT; info->rc = DBG_EXCEPTION_NOT_HANDLED; info->action = INT_CHAIN_TO_NEXT; SendMessage( hwnd, WM_CLOSE, 0, 0L ); } else if( IsDlgButtonChecked( hwnd, INT_RESTART ) ) { ConfigData.exception_action = INT_RESTART; info->rc = DBG_CONTINUE; info->action = INT_RESTART; SendMessage( hwnd, WM_CLOSE, 0, 0L ); } break; case INT_REGISTERS: SetDisasmInfo( info->procinfo->prochdl, info->module ); StatShowSymbols = TRUE; if ( DoStatDialog( hwnd ) == 1 ){ StoreMADRegisters( info->regs, info->threadinfo->threadhdl ); GetCurrAddr(&addr,info->regs); SetIp( hwnd, &addr ); } LoadMADRegisters( info->regs, info->threadinfo->threadhdl ); break; case INT_LOG_OPTIONS: SetLogOptions( hwnd ); break; } break; case WM_CLOSE: if( info->rc == 0 ) { SendMessage( hwnd, WM_COMMAND, INT_ACT, 0L ); } else { if( info->got_dbginfo ) { UnloadDbgInfo( info->module ); } EndDialog( hwnd, info->rc ); } break; case WM_DESTROY: DeAllocMadRegisters( info->regs ); MemFree( info ); break; default: return( FALSE ); break; } return( TRUE ); }
/* * 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; } }
/* * executeUntilStart - run program until start address hit */ static BOOL executeUntilStart( BOOL was_running ) { HANDLE ph; opcode_type saved_opcode; opcode_type brk_opcode = BRKPOINT; LPVOID base; SIZE_T bytes; MYCONTEXT con; thread_info *ti; ph = DebugEvent.u.CreateProcessInfo.hProcess; if( !was_running ) { /* * if we are not debugging an already running app, then we * plant a breakpoint at the first instruction of our new app */ base = (LPVOID)DebugEvent.u.CreateProcessInfo.lpStartAddress; ReadProcessMemory( ph, base, (LPVOID)&saved_opcode, sizeof( saved_opcode ), &bytes ); WriteProcessMemory( ph, base, (LPVOID)&brk_opcode, sizeof( brk_opcode ), &bytes ); } else { // a trick to make app execute long enough to hit a breakpoint PostMessage( HWND_TOPMOST, WM_NULL, 0, 0L ); } for( ;; ) { /* * if we encounter anything but a break point, then we are in * trouble! */ if( DebugExecute( STATE_IGNORE_DEBUG_OUT | STATE_IGNORE_DEAD_THREAD, NULL, FALSE ) & COND_BREAK ) { ti = FindThread( DebugEvent.dwThreadId ); MyGetThreadContext( ti, &con ); if( was_running ) { AdjustIP( &con, sizeof( brk_opcode ) ); MySetThreadContext( ti, &con ); return( TRUE ); } if( StopForDLLs ) { /* * the user has asked us to stop before any DLL's run * their startup code (";dll"), so we do. */ WriteProcessMemory( ph, base, (LPVOID)&saved_opcode, sizeof( saved_opcode ), &bytes ); AdjustIP( &con, sizeof( brk_opcode ) ); MySetThreadContext( ti, &con ); return( TRUE ); } if( ( AdjustIP( &con, 0 ) == base ) ) { /* * we stopped at the applications starting address, * so we can offically declare that the app has loaded */ WriteProcessMemory( ph, base, (LPVOID)&saved_opcode, sizeof( saved_opcode ), &bytes ); return( TRUE ); } /* * skip this breakpoint and continue */ AdjustIP( &con, sizeof( brk_opcode ) ); MySetThreadContext( ti, &con ); } else { return( FALSE ); } } }
/* * AccLoadProg - create a new process for debugging */ trap_retval ReqProg_load( void ) { char *parm; char *src; char *dst; char *endsrc; char exe_name[PATH_MAX]; char ch; BOOL rc; int len; MYCONTEXT con; thread_info *ti; HANDLE handle; prog_load_req *acc; prog_load_ret *ret; header_info hi; WORD stack; WORD version; DWORD pid; DWORD pid_started; DWORD cr_flags; char *buff = NULL; size_t nBuffRequired = 0; char *dll_name; char *service_name; char *dll_destination; char *service_parm; acc = GetInPtr( 0 ); ret = GetOutPtr( 0 ); parm = GetInPtr( sizeof( *acc ) ); /* * reset status variables */ LastExceptionCode = -1; DebugString = NULL; DebugeeEnded = FALSE; RemoveAllThreads(); FreeLibList(); DidWaitForDebugEvent = FALSE; DebugeePid = 0; DebugeeTid = 0; SupportingExactBreakpoints = 0; /* * check if pid is specified */ ParseServiceStuff( parm, &dll_name, &service_name, &dll_destination, &service_parm ); pid = 0; src = parm; /* // Just to be really safe! */ nBuffRequired = GetTotalSize() + PATH_MAX + 16; if( NULL == ( buff = malloc( nBuffRequired ) ) ) { ret->err = ERROR_NOT_ENOUGH_MEMORY; return( sizeof( *ret ) ); } if( *src == '#' ) { src++; pid = strtoul( src, &endsrc, 16 ); if( pid == 0 ) { pid = -1; } strcpy( buff, endsrc ); } else { while( isdigit( *src ) ) { src++; } if( *src == 0 && src != parm ) { pid = atoi( parm ); } } /* * get program to debug. If the user has specified a pid, then * skip directly to doing a DebugActiveProcess */ IsWOW = FALSE; #if !defined( MD_x64 ) IsDOS = FALSE; #endif if( pid == 0 ) { if( FindFilePath( parm, exe_name, ExtensionList ) != 0 ) { ret->err = ERROR_FILE_NOT_FOUND; goto error_exit; } /* * Get type of application */ handle = CreateFile( (LPTSTR)exe_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 ); if( handle == INVALID_HANDLE_VALUE ) { ret->err = GetLastError(); goto error_exit; } GetFullPathName( exe_name, MAX_PATH, CurrEXEName, NULL ); /* * get the parm list */ if( strchr( CurrEXEName, ' ' ) != NULL ) { strcpy( buff, "\"" ); strcat( buff, CurrEXEName ); strcat( buff, "\"" ); } else { strcpy( buff, CurrEXEName ); } dst = &buff[strlen( buff )]; src = parm; while( *src != 0 ) { ++src; } // parm layout // <--parameters-->0<--program_name-->0<--arguments-->0 // for( len = GetTotalSize() - sizeof( *acc ) - (src - parm) - 1; len > 0; --len ) { ch = *src; if( ch == 0 ) { ch = ' '; } *dst = ch; ++dst; ++src; } *dst = 0; cr_flags = DEBUG_ONLY_THIS_PROCESS; if( !GetEXEHeader( handle, &hi, &stack ) ) { ret->err = GetLastError(); CloseHandle( handle ); goto error_exit; } if( hi.sig == EXE_PE ) { if( IS_PE64( hi.u.peh ) ) { DebugeeSubsystem = PE64( hi.u.peh ).subsystem; } else { DebugeeSubsystem = PE32( hi.u.peh ).subsystem; #if defined( MD_x64 ) IsWOW = TRUE; #endif } if( DebugeeSubsystem == SS_WINDOWS_CHAR ) { cr_flags |= CREATE_NEW_CONSOLE; } #if !defined( MD_x64 ) } else if( hi.sig == EXE_NE ) { IsWOW = TRUE; /* * find out the pid of WOW, if it is already running. */ pVDMEnumProcessWOW( EnumWOWProcessFunc, (LPARAM)&pid ); if( pid != 0 ) { version = LOWORD( GetVersion() ); if( LOBYTE( version ) == 3 && HIBYTE( version ) < 50 ) { int kill = MessageBox( NULL, TRP_NT_wow_warning, TRP_The_WATCOM_Debugger, MB_APPLMODAL + MB_YESNO ); if( kill == IDYES ) { DWORD axs = PROCESS_TERMINATE+STANDARD_RIGHTS_REQUIRED; HANDLE hprocess = OpenProcess( axs, FALSE, pid ); if( hprocess != 0 && TerminateProcess( hprocess, 0 ) ) { CloseHandle( hprocess ); pid = 0; } } } else { cr_flags |= CREATE_SEPARATE_WOW_VDM; pid = 0; // always start a new VDM. } } if( pid != 0 ) { ret->err = GetLastError(); CloseHandle( handle ); goto error_exit; } } else { IsDOS = TRUE; #endif } CloseHandle( handle ); } /* * start the debugee */ pid_started = pid; if( *dll_name ) { strcat( buff, LOAD_PROG_STR_DELIM ); strcat( buff, LOAD_PROG_STR_DLLNAME ); strcat( buff, dll_name ); } if( *service_name ) { strcat( buff, LOAD_PROG_STR_DELIM ); strcat( buff, LOAD_PROG_STR_SERVICE ); strcat( buff, service_name ); } if( *dll_destination ) { strcat( buff, LOAD_PROG_STR_DELIM ); strcat( buff, LOAD_PROG_STR_COPYDIR ); strcat( buff, dll_destination ); } if( *service_parm ) { strcat( buff, LOAD_PROG_STR_DELIM ); strcat( buff, LOAD_PROG_STR_SERVICEPARM ); strcat( buff, service_parm ); } ret->err = StartControlThread( buff, &pid_started, cr_flags ); if( ret->err != 0 ) { goto error_exit; } /* * CREATE_PROCESS_DEBUG_EVENT will always be the first debug event. * If it is not, then something is horribly wrong. */ rc = MyWaitForDebugEvent(); if( !rc || ( DebugEvent.dwDebugEventCode != CREATE_PROCESS_DEBUG_EVENT ) || ( DebugEvent.dwProcessId != pid_started ) ) { ret->err = GetLastError(); goto error_exit; } ProcessInfo.pid = DebugEvent.dwProcessId; ProcessInfo.process_handle = DebugEvent.u.CreateProcessInfo.hProcess; ProcessInfo.base_addr = DebugEvent.u.CreateProcessInfo.lpBaseOfImage; AddProcess( &hi ); AddThread( DebugEvent.dwThreadId, DebugEvent.u.CreateProcessInfo.hThread, DebugEvent.u.CreateProcessInfo.lpStartAddress ); DebugeePid = DebugEvent.dwProcessId; DebugeeTid = DebugEvent.dwThreadId; LastDebugEventTid = DebugEvent.dwThreadId; #if defined( MD_x86 ) #ifdef WOW if( IsWOW ) { ret->flags = LD_FLAG_IS_PROT; ret->err = 0; ret->task_id = DebugeePid; /* * we use our own CS and DS as the Flat CS and DS, for lack * of anything better */ FlatDS = GetDS(); FlatCS = GetCS(); if( !executeUntilVDMStart() ) { ret->err = GetLastError(); goto error_exit; } if( pid ) { addAllWOWModules(); } else { addKERNEL(); } /* * we save the starting CS:IP of the WOW app, since we will use * it to force execution of code later */ ti = FindThread( DebugeeTid ); MyGetThreadContext( ti, &con ); WOWAppInfo.segment = ( WORD ) con.SegCs; WOWAppInfo.offset = ( WORD ) con.Eip; con.SegSs = con.SegDs; // Wow lies about the stack segment. Reset it con.Esp = stack; MySetThreadContext( ti, &con ); } else if( IsDOS ) { // TODO! Clean up this code ret->flags = 0; //LD_FLAG_IS_PROT; ret->err = 0; ret->task_id = DebugeePid; /* * we use our own CS and DS as the Flat CS and DS, for lack * of anything better */ FlatDS = GetDS(); FlatCS = GetCS(); if( !executeUntilVDMStart() ) { ret->err = GetLastError(); goto error_exit; } #if 0 if( pid ) { addAllWOWModules(); } else { addKERNEL(); } #endif /* * we save the starting CS:IP of the WOW app, since we will use * it to force execution of code later */ ti = FindThread( DebugeeTid ); MyGetThreadContext( ti, &con ); WOWAppInfo.segment = ( WORD )con.SegCs; WOWAppInfo.offset = ( WORD )con.Eip; con.SegSs = con.SegDs; // Wow lies about the stack segment. Reset it con.Esp = stack; MySetThreadContext( ti, &con ); } else { #else { #endif #else { #endif LPVOID base; if( pid == 0 ) { base = (LPVOID)DebugEvent.u.CreateProcessInfo.lpStartAddress; } else { base = 0; } ret->flags = LD_FLAG_IS_PROT; ret->err = 0; ret->task_id = DebugeePid; if( executeUntilStart( pid != 0 ) ) { LPVOID old; /* * make the application load our DLL, so that we can have it * run code out of it. One small note: this will not work right * if the app does not load our DLL at the same address the * debugger loaded it at!!! */ ti = FindThread( DebugeeTid ); MyGetThreadContext( ti, &con ); old = (LPVOID)AdjustIP( &con, 0 ); if( base != 0 ) { SetIP( &con, base ); } MySetThreadContext( ti, &con ); SetIP( &con, old ); MySetThreadContext( ti, &con ); } ti = FindThread( DebugeeTid ); MyGetThreadContext( ti, &con ); #if defined( MD_x86 ) FlatCS = con.SegCs; FlatDS = con.SegDs; #endif ret->flags |= LD_FLAG_IS_BIG; } ret->flags |= LD_FLAG_HAVE_RUNTIME_DLLS; if( pid != 0 ) { ret->flags |= LD_FLAG_IS_STARTED; } ret->mod_handle = 0; error_exit: if( buff ) { free( buff ); buff = NULL; } return( sizeof( *ret ) ); } trap_retval ReqProg_kill( void ) { prog_kill_ret *ret; ret = GetOutPtr( 0 ); ret->err = 0; DelProcess( TRUE ); StopControlThread(); return( sizeof( *ret ) ); }
void ReaderTask(int fd, const char *id) { time_t dtime = 0; time_t ltime = 0; time_t itime = 0; time_t ftime = 0; time_t atime = 0; int counter = 0; int forceallcheck = 0; int check_disconn_counter = 0; TFd = fd; /* * [re]open RTStatus */ RTStatusOpen(RTStatus, ThisReaderFork * DOpts.ReaderThreads + 1, DOpts.ReaderThreads); /* * Since we setuid(), we won't core. This is for debugging */ if (CoreDebugOpt || (DOpts.ReaderCrashHandler != NULL && strcasecmp(DOpts.ReaderCrashHandler, "none") != 0)) { signal(SIGSEGV, sigSegVReader); signal(SIGBUS, sigSegVReader); signal(SIGFPE, sigSegVReader); signal(SIGILL, sigSegVReader); } signal(SIGHUP, sigHup); signal(SIGUSR1, sigUsr1); /* * Setup thread for passed pipe */ ResetThreads(); AddThread("reader", fd, -1, THREAD_READER, -1, 0); FD_SET(fd, &RFds); /* * Open KPDB database for active file */ if ((KDBActive = KPDBOpen(PatDbExpand(ReaderDActivePat), O_RDWR)) == NULL) { logit(LOG_CRIT, "Unable to open %s", PatDbExpand(ReaderDActivePat)); sleep(60); exit(1); } LoadExpireCtl(1); /* * Only startup connections to backend spools for reader threads */ if (!FeedOnlyServer) CheckServerConfig(time(NULL), 1); /* * Selection core */ while (!TerminatePending || NReadServAct || NumReaders) { /* * select core */ struct timeval tv; fd_set rfds = RFds; fd_set wfds = WFds; fd_set read_only_to_find_eof_fds; int i, sel_r; if (TerminatePending) { if (TerminateTime == 0) TerminateTime = time(NULL) + 2; if (TerminateTime < time(NULL) || !NumReaders) CanTerminate = 1; } /* * Get next scheduled timeout, no more then 2 seconds * (x 10 counter counts = 20 seconds max for {d,i,f}time * check) * * If we are terminating, then speed up the select to clear * out the connections. * */ if (TerminatePending) NextTimeout(&tv, 50); else NextTimeout(&tv, 2 * 1000); stprintf("%s readers=%02d spoolsrv=%d/%d postsrv=%d/%d", id, NumReaders, NReadServAct, NReadServers, NWriteServAct, NWriteServers ); /* Check for disconnected clients every 50 times through the loop */ FD_ZERO(&read_only_to_find_eof_fds); if (++check_disconn_counter == 50) { for (i = 0; i < MaxFds; ++i) { if (FD_ISSET(i, &wfds) && (!(FD_ISSET(i, &rfds)))) { FD_SET(i, &rfds); FD_SET(i, &read_only_to_find_eof_fds); } } check_disconn_counter = 0; } #if USE_AIO AIOUnblockSignal(); #endif sel_r = select(MaxFds, &rfds, &wfds, NULL, &tv); #if USE_AIO AIOBlockSignal(); #endif gettimeofday(&CurTime, NULL); if(sel_r < 0 && errno != EINTR) logit(LOG_CRIT, "select error: %s (rfds=0x%x, wfds=0x%x)", strerror(errno), rfds, wfds); /* * select is critical, don't make unnecessary system calls. Only * test the time every 10 selects (20 seconds worst case), and * only check for a new server configuration file every 60 seconds * after the initial load. This may rearrange THREAD_SPOOL and * THREAD_POST threads. * * We do not startup spool/post servers for feed-only forks * * However, flush overview cache even for feed-only forks. */ if (FeedOnlyServer <= 0) { if (++counter == 10) { time_t t = CurTime.tv_sec; if (ltime) { dtime += t - ltime; itime += t - ltime; ftime += t - ltime; atime += t - ltime; } /* * Check for server config change once a minute */ if (dtime < -5 || dtime >= 5) { if (!TerminatePending) CheckServerConfig(t, ServersTerminated); dtime = 0; } /* * Flush overview every 30 seconds to allow dexpireover to work */ if (ftime < -5 || ftime >= 30) { FlushOverCache(); LoadExpireCtl(0); ftime = 0; } /* * Poll all active descriptors once every 5 minutes. This * will work around a linux embrionic close bug that * doesn't wakeup select(), and is used to idle-timeout * connections. XXX */ if (itime < -5 || itime >= 300) { rfds = RFds; itime = 0; } /* * Force a check all of FD's every 30 seconds to handle * idle and session timeouts */ if (atime < -5 || atime >= 30) { forceallcheck = 1; atime = 0; } ltime = t; counter = 0; } } else { /* * For a feed-only server, we only flush the overview FD * cache every 5 minutes, and with a greater granularity. * It should cycle much faster than that normally, and this * is to prevent idle feed-only forks from keeping locks. * */ if (++counter == 10) { time_t t = CurTime.tv_sec; if (ltime) { ftime += t - ltime; } if (ftime < -5 || ftime >= 300) { FlushOverCache(); ftime = 0; } ltime = t; counter = 0; } } for (i = 0; i < MaxFds; ++i) { if (FD_ISSET(i, &rfds) && FD_ISSET(i, &read_only_to_find_eof_fds)) { char junk_byte; int ret_val; /* * This FD is not marked for reading, but select() claims * it has something to say. We don't actually want to read * from it, but we do want to close it if the associated * connection is dead. */ FD_CLR(i, &rfds); /* Use recv() with MSG_PEEK to see if it's closed. * We shouldn't block because we're O_NONBLOCK. */ ret_val = recv(i, &junk_byte, 1, MSG_PEEK); /* If ret_val is zero, this means the socket is closed. * Blast it. Otherwise, ignore it. */ if(ret_val == 0) { ForkDesc *desc; if((desc = FindThread(i, -1)) != NULL) { Connection *conn = desc->d_Data; if(conn) { NNTerminate(conn); DeleteConnection(conn); } DelThread(desc); } } } } for (i = 0; i < MaxFds; ++i) { if (forceallcheck || TerminatePending || FD_ISSET(i, &rfds) || FD_ISSET(i, &wfds)) { ForkDesc *desc; if ((desc = FindThread(i, -1)) != NULL) { Connection *conn = desc->d_Data; if (conn) { /* * handle output I/O (optimization) */ MBFlush(conn, &conn->co_TMBuf); conn->co_FCounter = 0; } /* * Function dispatch */ switch(desc->d_Type) { case THREAD_READER: if (FD_ISSET(i, &rfds) || FD_ISSET(i, &wfds)) HandleReaderMsg(desc); break; case THREAD_NNTP: /* client */ conn->co_Func(conn); if (conn->co_Auth.dr_ResultFlags & DR_REQUIRE_DNS) { /* Go back to parent for DNS check */ conn->co_Auth.dr_Code = 0; conn->co_TMBuf.mh_WEof = 1; } break; case THREAD_SPOOL: /* spool server */ case THREAD_POST: /* posting server */ conn->co_Func(conn); LogServerInfo(conn, TFd); break; default: /* panic */ break; } /* * do not call MBFlush after the function because the * function may be waiting for write data to drain and * we don't want to cause write data to drain here and * then not get a select wakeup later. * * check for connection termination */ if (conn) { int idleTimeout = 0; if (conn->co_Auth.dr_ReaderDef) { if (conn->co_Auth.dr_ReaderDef->rd_IdleTimeout && conn->co_LastActiveTime + conn->co_Auth.dr_ReaderDef->rd_IdleTimeout <= CurTime.tv_sec) { logit(LOG_INFO, "timeout idle %s", conn->co_Auth.dr_Host); MBLogPrintf(conn, &conn->co_TMBuf, "400 %s: Idle timeout.\r\n", conn->co_Auth.dr_VServerDef->vs_HostName ); idleTimeout = 1; NNTerminate(conn); } if (conn->co_Auth.dr_ReaderDef->rd_SessionTimeout && conn->co_SessionStartTime + conn->co_Auth.dr_ReaderDef->rd_SessionTimeout <= CurTime.tv_sec) { logit(LOG_INFO, "timeout session %s", conn->co_Auth.dr_Host); MBLogPrintf(conn, &conn->co_TMBuf, "400 %s: Session timeout.\r\n", conn->co_Auth.dr_VServerDef->vs_HostName ); idleTimeout = 1; NNTerminate(conn); } } if ((!conn->co_Auth.dr_Code && desc->d_Type == THREAD_NNTP) || idleTimeout || (conn->co_RMBuf.mh_REof && conn->co_TMBuf.mh_WEof && conn->co_TMBuf.mh_MBuf == NULL) || (TerminatePending && !(conn->co_Flags & COF_MAYNOTCLOSE)) ) { DeleteConnection(conn); DelThread(desc); } } } } } forceallcheck = 0; (void)ScanTimers(1, 0); if (CanTerminate) break; } RTStatusClose(); KPDBClose(KDBActive); exit(0); }