Example #1
0
/*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;
}
Example #2
0
void VScriptInstance::WaitSeconds(lua_State *pState, float seconds)
{
  if (seconds<=0.f)
    return;

  VLuaThreadInfo* pInfo = FindThread(pState);
  pInfo->fWaitTime += seconds;
  SCRIPTINSTANCES.AddWaitingObject(this);
}
Example #3
0
/*
 * 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;
	}
}
Example #4
0
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);
	}
}
Example #5
0
/*
 * 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 );
    }

}
Example #6
0
/*
 * 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

}
Example #7
0
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
}
Example #8
0
/*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;
}
Example #9
0
//-----------------------------------------------------------------------------
// 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
    }
}
Example #10
0
/*
 * 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 );
}
Example #11
0
/*
 * 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 );
}
Example #12
0
/*
 * 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;
	}
}
Example #13
0
/*
 * 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 );
        }
    }

}
Example #14
0
/*
 * 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 ) );
}
Example #15
0
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);
}