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 + -
显示快捷键?