sampnt.c

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

C
681
字号
/****************************************************************************
*
*                            Open Watcom Project
*
*    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
*  ========================================================================
*
*    This file contains Original Code and/or Modifications of Original
*    Code as defined in and that are subject to the Sybase Open Watcom
*    Public License version 1.0 (the 'License'). You may not use this file
*    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
*    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
*    provided with the Original Code and Modifications, and is also
*    available at www.sybase.com/developer/opensource.
*
*    The Original Code and all software distributed under the License are
*    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
*    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
*    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
*    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
*    NON-INFRINGEMENT. Please see the License for the specific language
*    governing rights and limitations under the License.
*
*  ========================================================================
*
* Description:  Win32 performance sampling core.
*
****************************************************************************/


#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <ctype.h>
#include <string.h>
#include <i86.h>
#include <malloc.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "sample.h"
#include "wmsg.h"
#include "smpstuff.h"
#include "windows.h"
#include "exepe.h"
#include "exedos.h"


typedef struct {
    char        live;
    DWORD       id;
    HANDLE      th;
    unsigned    SampleIndex;
    DWORD       index;
    unsigned    SampleCount;
    samp_block  *Samples;
    samp_block  *CallGraph;
} thread_info;

#define EVENT_NAME      "tickevent"
#define BUFF_SIZE 2048
#define STACK_SIZE 4096
#define CONTEXT_TO_USE  CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS \
                        | CONTEXT_FLOATING_POINT

static char             utilBuff[BUFF_SIZE];
static ULONG            sleepTime;
static seg_offset       commonAddr;
static thread_info      *threadInfo;
static int              threadCount;
static DEBUG_EVENT      debugEvent;
static HANDLE           processHandle;
static DWORD            taskPid;
static BOOL             doneSample;
static BOOL             timeOut;

/*
 * getThreadInfo - get info about a specific thread id
 */
static thread_info *getThreadInfo( DWORD id )
{
    int i;

    for( i=0;i<threadCount;i++ ) {
        if( id == threadInfo[i].id ) {
            return( &threadInfo[i] );
        }
    }
    return( NULL );

} /* getThreadInfo */

/*
 * NextThread - set up so that we are at the next thread info
 */
unsigned NextThread( unsigned tid )
{
    if( tid == threadCount ) {
        return( 0 );
    }
    Samples = threadInfo[ tid ].Samples;
    SampleIndex = threadInfo[ tid ].SampleIndex;
    if( CallGraphMode ) {
        CallGraph = threadInfo[ tid ].CallGraph;
        SampleCount = threadInfo[ tid ].SampleCount;
    }
    return( tid+1 );

} /* NextThread */

void InitTimerRate( void )
{
    sleepTime = 55;
}

void SetTimerRate( char **cmd )
{
    sleepTime = GetNumber( 1, 1000, cmd, 10 );
}

unsigned long TimerRate( void )
{
    return( 1000L * sleepTime );
}

unsigned SafeMargin( void )
{
    return( Ceiling-10 );
}

int VersionCheck( void )
{
    return( TRUE );
}

/*
 * RecordSample - record a sample in a specific thread
 */
void RecordSample( unsigned offset, unsigned short segment, DWORD real_tid )
{
    samp_block  *old_samples;
    unsigned    old_sample_index;
    unsigned    old_sample_count;
    thread_info *ti;
    DWORD       tid;

    ti = getThreadInfo( real_tid );
    if( ti == NULL ) {
        return;
    }
    tid = ti->index;

    LastSampleIndex = ti->SampleIndex;
    if( ti->SampleIndex == 0 ) {
        ti->Samples->pref.tick = CurrTick;
        if( CallGraphMode ) {
            ti->CallGraph->pref.tick = CurrTick;
        }
    }
    ++CurrTick;
    ti->Samples->d.sample.sample[ ti->SampleIndex ].offset = offset;
    ti->Samples->d.sample.sample[ ti->SampleIndex ].segment = segment;
    ti->SampleIndex++;
    if( CallGraphMode ) {
        ti->SampleCount++;
    }
    if( CallGraphMode && tid == 0 ) {
        old_sample_count = SampleCount;
        old_samples = Samples;          /* since RecordCGraph isn't */
        old_sample_index = SampleIndex; /* used to threads, we fool */
        Samples = ti->Samples;          /* it into storing the info */
        SampleIndex = ti->SampleIndex;  /* in the right place by    */
        SampleCount = ti->SampleCount;
        RecordCGraph();                 /* changing its pointers    */
        ti->Samples = Samples;          /* and restoring them later */
        ti->SampleIndex = SampleIndex;
        ti->SampleCount = SampleCount;
        Samples = old_samples;
        SampleIndex = old_sample_index;
        SampleCount = old_sample_count;
    }
    if( ti->SampleIndex >= Margin ) {
        StopAndSave();
    }

} /* RecordSample */

void GetCommArea( void )
{
    DWORD       len;

    if( commonAddr.segment == 0 ) {     /* can't get the common region yet */
        Comm.cgraph_top = 0;
        Comm.top_ip = 0;
        Comm.top_cs = 0;
        Comm.pop_no = 0;
        Comm.push_no = 0;
        Comm.in_hook = 1;       /* don't record this sample */
    } else {
        ReadProcessMemory( processHandle, (LPVOID) commonAddr.offset, &Comm,
                                sizeof( Comm ), &len );
    }
}

void ResetCommArea( void )
{
    DWORD       len;

    if( commonAddr.segment != 0 ) {
        Comm.pop_no = 0;
        Comm.push_no = 0;
        WriteProcessMemory( processHandle, (LPVOID) (commonAddr.offset + 11),
                        &Comm.pop_no, 4, &len );
    }
}

void GetNextAddr( void )
{
    struct {
        unsigned long   ptr;
        seg             cs;
        off             ip;
    } stack_entry;
    DWORD       len;

    if( commonAddr.segment == 0 ) {
        CGraphOff = 0;
        CGraphSeg = 0;
    } else {
        ReadProcessMemory( processHandle, (LPVOID) Comm.cgraph_top,
                        &stack_entry, sizeof( stack_entry ), &len );
        CGraphOff = stack_entry.ip;
        CGraphSeg = stack_entry.cs;
        Comm.cgraph_top = stack_entry.ptr;
    }
}

void StopProg( void ) {}

static void internalError( char *str )
{
    Output( MsgArray[MSG_SAMPLE_2-ERR_FIRST_MESSAGE] );
    Output( str );
    Output( "\r\n" );
    _exit( -1 );
}

/*
 * seekRead - seek to a specified spot in the file, and read some data
 */
static BOOL seekRead( HANDLE handle, DWORD newpos, void *buff, WORD size )
{
    int         rc;
    DWORD       bytes;

    rc = SetFilePointer( handle, newpos, 0, SEEK_SET );
    if( rc == -1 ) {
        return( FALSE );
    }
    rc = ReadFile( handle, buff, size, &bytes, NULL );
    if( !rc ) {
        return( FALSE );
    }
    if( bytes != size ) {
        return( FALSE );
    }
    return( TRUE );

} /* seekRead */

/*
 * getPEHeader - get the header of the .EXE
 */
static int getPEHeader( HANDLE handle, pe_header *peh )
{
    WORD                data;
    WORD                sig;
    DWORD               nh_offset;

    if( !seekRead( handle, 0x00, &data, sizeof( data ) ) ) {
        return( FALSE );
    }
    if( data != DOS_SIGNATURE ) {
        return( FALSE );
    }

    if( !seekRead( handle, 0x18, &data, sizeof( data ) ) ) {
        return( FALSE );
    }

    if( !seekRead( handle, 0x3c, &nh_offset, sizeof( unsigned_32 ) ) ) {
        return( FALSE );
    }

    if( !seekRead( handle, nh_offset, &sig, sizeof( sig ) ) ) {
        return( FALSE );
    }
    if( sig != PE_SIGNATURE ) {
        return( FALSE );
    }

    if( !seekRead( handle, nh_offset, peh, sizeof( pe_header ) ) ) {
        return( FALSE );
    }
    return( TRUE );

} /* getPEHeader */

/*
 * codeLoad - handle the loading of a new DLL/EXE
 */
static void codeLoad( HANDLE handle, DWORD base, char *name,
                        samp_block_kinds kind )
{
    seg_offset          ovl;
    int                 i;
    pe_object           obj;
    WORD                seg;
    DWORD               offset;
    DWORD               bytes;
    pe_header           peh;

    name = name;

    ovl.offset = 0;
    ovl.segment = 0;
    WriteCodeLoad( ovl, name, kind );
    if( !getPEHeader( handle, &peh ) ) {
        return;
    }
    for( i=0;i<peh.num_objects;i++ ) {
        ReadFile( handle, &obj, sizeof( obj ), &bytes, NULL );
        if( obj.flags & (PE_OBJ_CODE | PE_OBJ_EXECUTABLE ) ) {
            seg = FP_SEG( codeLoad );
        } else {
            seg = FP_SEG( &seg );
        }
        offset = (DWORD) base + obj.rva;
        WriteAddrMap( i+1, seg, offset );
    }

⌨️ 快捷键说明

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