sampaxp.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 709 行 · 第 1/2 页

C
709
字号
static void newThread( DWORD id, HANDLE th )
{
    threadInfo = realloc( threadInfo, (threadCount+1)* sizeof( thread_info ) );
    threadInfo[ threadCount ].id = id;
    threadInfo[ threadCount ].th = th;
    threadInfo[ threadCount ].live = TRUE;
    threadInfo[ threadCount ].index = threadCount;

    AllocSamples( id );
    threadInfo[ threadCount ].Samples = Samples;
    threadInfo[ threadCount ].SampleIndex = SampleIndex;
    if( CallGraphMode ) {
        threadInfo[ threadCount ].CallGraph = CallGraph;
        threadInfo[ threadCount ].SampleCount = SampleCount;
    }
    threadCount++;

} /* newThread */


/*
 * deadThread - a thread is dead
 */
static void deadThread( DWORD id )
{
    thread_info *ti;

    ti = getThreadInfo( id );
    if( ti != NULL ) {
        ti->live = FALSE;
    }

} /* deadThread */

/*
 * loadProg - load the task to sample
 */
static void loadProg( char *exe, char *cmdline )
{
    STARTUPINFO         sinfo;
    PROCESS_INFORMATION pinfo;
    int                 rc;

    memset( &sinfo, 0, sizeof( sinfo ) );
    sinfo.wShowWindow = SW_NORMAL;
    rc = CreateProcess( NULL,           /* application name */
                        cmdline,        /* command line */
                        NULL,           /* process attributes */
                        NULL,           /* thread attributes */
                        FALSE,          /* inherit handles */
                        DEBUG_PROCESS,//DEBUG_ONLY_THIS_PROCESS, /* creation flags */
                        NULL,           /* environment block */
                        NULL,           /* starting directory */
                        &sinfo,         /* startup info */
                        &pinfo          /* process info */
                    );
    if( !rc ) {
        internalError( MsgArray[MSG_SAMPLE_3-ERR_FIRST_MESSAGE] );
    }
    rc = WaitForDebugEvent( &debugEvent, -1 );
    if( !rc || (debugEvent.dwDebugEventCode != CREATE_PROCESS_DEBUG_EVENT) ||
                (debugEvent.dwProcessId != pinfo.dwProcessId) ) {
        internalError( MsgArray[MSG_SAMPLE_3-ERR_FIRST_MESSAGE] );
    }
    taskPid = debugEvent.dwProcessId;
    processHandle = debugEvent.u.CreateProcessInfo.hProcess;
    newThread( debugEvent.dwThreadId, debugEvent.u.CreateProcessInfo.hThread );
    codeLoad( debugEvent.u.CreateProcessInfo.hFile,
                (DWORD) debugEvent.u.CreateProcessInfo.lpBaseOfImage,
                exe,
                SAMP_MAIN_LOAD );

} /* loadProg */

/*
 * myGetThreadContext - get a thread's context
 */
static void myGetThreadContext( DWORD id, CONTEXT *pc )
{
    thread_info *ti;
    pc->ContextFlags = CONTEXT_TO_USE;
    ti = getThreadInfo( id );
    if( ti != NULL ) {
        GetThreadContext( ti->th, pc );
    }

} /* myGetThreadContext */

static void mySetThreadContext( DWORD id, CONTEXT *pc )
{
    thread_info *ti;
    pc->ContextFlags = CONTEXT_TO_USE;
    ti = getThreadInfo( id );
    if( ti != NULL ) {
        SetThreadContext( ti->th, pc );
    }

} /* mySetThreadContext */

/*
 * TimerThread - handle timer ticks
 */
DWORD __stdcall TimerThread( LPVOID parms )
{
    CONTEXT con;
    int i;
    uint_32 Fir;

    parms = parms;
    while( 1 ) {
        Sleep( sleepTime );
        if( doneSample ) {
            break;
        }
        timeOut = TRUE;
        for( i=0;i<threadCount;i++ ) {
            if( threadInfo[i].live ) {
                myGetThreadContext( threadInfo[i].id, &con );
                Fir = LODWORD( con.Fir );
                RecordSample( Fir, SEGMENT, threadInfo[i].id );
                timeOut = FALSE;
            }
        }
    }
    return( 0 );

} /* TimerThread */

/*
 * SkipBreakpoint - increment Fir past a breakpoint
 */
static void SkipBreakpoint( DWORD tid )
{
    CONTEXT con;
    uint_32 Fir;
    unsigned_64 newFir;

    myGetThreadContext( tid, &con );
    Fir = LODWORD( con.Fir );
    newFir.u._32[0] = Fir+4;
    newFir.u._32[1] = 0;
    con.Fir = *((DWORDLONG *)&newFir);
    mySetThreadContext( tid, &con );

} /* SkipBreakpoint */


static unsigned GetString( int unicode, LPVOID p, char *buff, unsigned max )
{
    DWORD       len;

    --max;
    if( ReadProcessMemory( processHandle, p, buff, max, &len ) ) {
        buff[len] = '\0';
        return( len );
    }
    len = 0;
    if( unicode ) {
        for( ;; ) {
            if( max <= 1 ) break;
            if( !ReadProcessMemory( processHandle, p, buff, 2, NULL ) ) break;
            if( *(wchar_t *)buff == '\0' ) break;
            buff += sizeof( wchar_t );
            p = (wchar_t *)p + 1;
            max -= sizeof( wchar_t );
            len += sizeof( wchar_t );
        }
        *(wchar_t *)buff = '\0';
    } else {
        for( ;; ) {
            if( max == 0 ) break;
            if( !ReadProcessMemory( processHandle, p, buff, 1, NULL ) ) break;
            if( *(char *)buff == '\0' ) break;
            buff += sizeof( char );
            p = (char *)p + 1;
            max -= sizeof( char );
            len += sizeof( char );
        }
        *(char *)buff = '\0';
    }
    return( len );
}

static int GetDllName( LOAD_DLL_DEBUG_INFO *ld, char *buff, unsigned max )
{
    LPVOID      name;
    DWORD       len;
    wchar_t     *p;

    //NYI: spiffy up to scrounge around in the image
    if( ld->lpImageName == 0 ) return( FALSE );
    ReadProcessMemory( processHandle, ld->lpImageName, &name, sizeof( name ), &len );
    if( len != sizeof( name ) ) return( FALSE );
    if( name == 0 ) return( FALSE );
    len = GetString( ld->fUnicode, name, buff, max );
    if( len == 0 ) return( FALSE );
    if( ld->fUnicode ) {
        for( p = (wchar_t *)buff; *p != '\0'; ++p, ++buff ) {
            *buff = *p;
        }
        *buff = '\0';
    }
    return( TRUE );
}

/*
 * StartProg - start sampling a program
 */
void StartProg( char *cmd, char *prog, char *args )
{
    DWORD       code;
    DWORD       tid;
    CONTEXT     con;
    BOOL        waiting_for_first_bp;
    DWORD       len;
    DWORD       continue_how;
    BOOL        rc;
    DWORD       ttid;
    HANDLE      tth;
    int         i;
    uint_32     Fir;

    cmd = cmd;

    strcpy( utilBuff, prog );
    len = strlen( utilBuff );
    utilBuff[ len++ ] = ' ';
    for( i=0;i<args[0];i++ ) {
        utilBuff[len++] = args[i+1];
    }
    utilBuff[len] = 0;

    loadProg( prog, utilBuff );
    tid = debugEvent.dwThreadId;

    tth = CreateThread( NULL, 2048, (LPVOID) TimerThread, NULL,
                0, &ttid );
    if( !tth ) {
        internalError( MsgArray[MSG_SAMPLE_3-ERR_FIRST_MESSAGE] );
    }
    /* Attempt to ensure that we can record our samples in one shot */
    SetThreadPriority( tth, THREAD_PRIORITY_TIME_CRITICAL );

    Output( MsgArray[MSG_SAMPLE_1-ERR_FIRST_MESSAGE] );
    Output( prog );
    Output( "\r\n" );

    waiting_for_first_bp = TRUE;
    continue_how = DBG_CONTINUE;

    while( 1 ) {
        ContinueDebugEvent( taskPid, tid, continue_how );
        rc = WaitForDebugEvent( &debugEvent, -1 );
        continue_how = DBG_CONTINUE;
        tid = debugEvent.dwThreadId;
        switch( debugEvent.dwDebugEventCode ) {
        case EXCEPTION_DEBUG_EVENT:
            code = debugEvent.u.Exception.ExceptionRecord.ExceptionCode;
            switch( code ) {
            case STATUS_SINGLE_STEP:
                if( timeOut ) {
                    myGetThreadContext( tid, &con );
                    Fir = LODWORD( con.Fir );
                    RecordSample( Fir, SEGMENT, tid );
                    timeOut = FALSE;
                }
                break;
            case STATUS_BREAKPOINT:
                /* Skip past the breakpoint in the startup code */
                if( waiting_for_first_bp ) {
                    SkipBreakpoint( tid );
                    waiting_for_first_bp = FALSE;
                }
                break;
            case STATUS_DATATYPE_MISALIGNMENT:
            case STATUS_ACCESS_VIOLATION:
            case STATUS_IN_PAGE_ERROR:
            case STATUS_NO_MEMORY:
            case STATUS_ILLEGAL_INSTRUCTION:
            case STATUS_NONCONTINUABLE_EXCEPTION:
            case STATUS_INVALID_DISPOSITION:
            case STATUS_ARRAY_BOUNDS_EXCEEDED:
            case STATUS_FLOAT_DENORMAL_OPERAND:
            case STATUS_FLOAT_DIVIDE_BY_ZERO:
            case STATUS_FLOAT_INVALID_OPERATION:
            case STATUS_FLOAT_OVERFLOW:
            case STATUS_FLOAT_STACK_CHECK:
            case STATUS_FLOAT_UNDERFLOW:
            case STATUS_INTEGER_DIVIDE_BY_ZERO:
            case STATUS_INTEGER_OVERFLOW:
            case STATUS_PRIVILEGED_INSTRUCTION:
            case STATUS_STACK_OVERFLOW:
            case STATUS_CONTROL_C_EXIT:
                if( debugEvent.u.Exception.dwFirstChance ) {
                    continue_how = DBG_EXCEPTION_NOT_HANDLED;
                } else {
                    Output( MsgArray[MSG_SAMPLE_4-ERR_FIRST_MESSAGE] );
                    Output( "\r\n" );
                    doneSample = TRUE;
                    TerminateProcess( processHandle, 0 );
                    report();
                    return;
                }
                break;
            default:
                continue_how = DBG_EXCEPTION_NOT_HANDLED;
                break;
            }
            break;
        case LOAD_DLL_DEBUG_EVENT:
            if( GetDllName( &debugEvent.u.LoadDll, utilBuff, sizeof( utilBuff ) ) ) {
                codeLoad( debugEvent.u.LoadDll.hFile,
                            (DWORD) debugEvent.u.LoadDll.lpBaseOfDll,
                            utilBuff,
                            SAMP_CODE_LOAD );
            }
            break;
        case CREATE_THREAD_DEBUG_EVENT:
            newThread( debugEvent.dwThreadId, debugEvent.u.CreateThread.hThread );
            break;
        case EXIT_THREAD_DEBUG_EVENT:
            deadThread( debugEvent.dwThreadId );
            break;
        case EXIT_PROCESS_DEBUG_EVENT:
            doneSample = TRUE;
//          TerminateProcess( processHandle, 0 ); - already gone!!
            report();
            return;
        }
    }

} /* StartProg */

void SysDefaultOptions( void ) { }

void SysParseOptions( char c, char **cmd )
{
    char buff[2];

    switch( c ) {
    case 'r':
        SetTimerRate( cmd );
        break;
    default:
        Output( MsgArray[MSG_INVALID_OPTION-ERR_FIRST_MESSAGE] );
        buff[0] = c;
        buff[1] = '\0';
        Output( buff );
        Output( "\r\n" );
        fatal();
        break;
    }
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?