samplnx.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 867 行 · 第 1/2 页
C
867 行
/****************************************************************************
*
* 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: Linux performance sampling core. See Linux debugger trap
* file for additional reference.
*
****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include "sample.h"
#include "wmsg.h"
#include "smpstuff.h"
// Helper functions shared with debugger
#if defined( __386__ )
#define MD_x86
#elif defined( __PPC__ )
#define MD_ppc
#else
#error Unsupported CPU architecture
#endif
#include "exeelf.h"
#include "linuxcomm.h"
#if 0
#define dbg_printf( ... ) printf( __VA_ARGS__ )
#else
#define dbg_printf( ... )
#endif
#define BUFF_SIZE 2048
#ifndef __WATCOMC__
extern char **environ;
#endif
static void CodeLoad( char *name, u_long addr, samp_block_kinds kind );
static unsigned SleepTime;
static unsigned *SampleIndexP;
static unsigned *SampleCountP;
static samp_block **SamplesP;
static samp_block **CallGraphP;
static unsigned MaxThread = 1;
static pid_t SamplePid = 0; // pid to attach to
static pid_t Pid;
static bool Attached;
static pid_t OrigPGrp;
static int HaveRdebug; // flag indicating valid r_debug
static struct r_debug Rdebug; // copy of child's r_debug (if present)
static struct r_debug *DbgRdebug; // address of r_debug in child's space
static Elf32_Dyn *DbgDyn; // VA of child's dynamic section (if present)
static volatile bool TimerTicked;
static unsigned short FlatSeg = 1; // hardcoded value, no real segments
static bp_t Old_ld_bp;
static seg_offset CommonAddr;
typedef struct lli {
addr_off offset;
addr_off dbg_dyn_sect;
addr_off code_size;
char newly_unloaded : 1;
char newly_loaded : 1;
char filename[257]; // TODO: This should really be dynamic!
} lib_load_info;
static lib_load_info *ModuleInfo;
static int ModuleTop;
/*
* The following routines that keep track of loaded shared libraries were
* stolen from the trap file, but for the profiler's use we can simplify
* them a lot.
*/
/* Find a shared lib entry in the list */
static lib_load_info *FindLib( addr_off dynsection )
{
unsigned i;
for( i = 0; i < ModuleTop; ++i ) {
if( ModuleInfo[i].dbg_dyn_sect == dynsection )
return( &ModuleInfo[i] );
}
return( NULL );
}
static struct link_map *FindLibInLinkMap( pid_t pid, struct link_map *first_lmap, addr_off dyn_base )
{
struct link_map lmap;
struct link_map *dbg_lmap;
dbg_lmap = first_lmap;
while( dbg_lmap != NULL ) {
if( !GetLinkMap( pid, dbg_lmap, &lmap ) )
break;
if( (addr_off)lmap.l_ld == dyn_base )
return( dbg_lmap );
dbg_lmap = lmap.l_next;
}
return( NULL );
}
static void InitLibMap( void )
{
lib_load_info *lli;
ModuleInfo = malloc( sizeof( lib_load_info ) );
memset( ModuleInfo, 0, sizeof( lib_load_info ) );
ModuleTop = 1;
lli = &ModuleInfo[0];
lli->offset = 0; // main executable won't be relocated
lli->filename[0] = '\0';
}
static void FiniLibMap( void )
{
unsigned i;
for( i = 0; i < ModuleTop; ++i ) {
ModuleInfo[i].offset = 0;
ModuleInfo[i].dbg_dyn_sect = 0;
ModuleInfo[i].code_size = 0;
}
}
static void DoAddLib( pid_t pid, struct link_map *lmap )
{
lib_load_info *lli;
// inefficient code, but not called very often
ModuleTop++;
lli = malloc( ModuleTop * sizeof( lib_load_info ) );
memset( lli, 0, ModuleTop * sizeof( lib_load_info ) );
memcpy( lli, ModuleInfo, (ModuleTop - 1) * sizeof( lib_load_info ) );
free( ModuleInfo );
ModuleInfo = lli;
lli = &ModuleInfo[ModuleTop - 1];
lli->offset = lmap->l_addr;
lli->dbg_dyn_sect = (addr_off)lmap->l_ld;
dbg_strcpy( pid, lli->filename, lmap->l_name );
lli->offset = lmap->l_addr;
dbg_printf( "Added library, ofs/dyn = %p/%p'%s'\n", lmap->l_addr, (addr_off)lmap->l_ld, lli->filename );
// no name, not interested
if( lli->filename[0] != '\0' )
CodeLoad( lli->filename, lmap->l_addr, SAMP_CODE_LOAD );
}
static void DoRemoveLib( addr_off dynsection )
{
unsigned i;
for( i = 0; i < ModuleTop; ++i ) {
if( ModuleInfo[i].dbg_dyn_sect == dynsection ) {
dbg_printf( "Deleting library '%s'\n", ModuleInfo[i].filename );
ModuleInfo[i].offset = 0;
ModuleInfo[i].dbg_dyn_sect = 0;
ModuleInfo[i].code_size = 0;
break;
}
}
}
/*
* AddOneLib - called when dynamic linker is adding a library. Unfortunately
* we don't get told which library, so we just have to zip through the list
* until we find one we don't know about yet.
*/
static int AddLibrary( pid_t pid, struct link_map *first_lmap )
{
struct link_map lmap;
struct link_map *dbg_lmap;
int count = 0;
lib_load_info *lli;
dbg_lmap = first_lmap;
while( dbg_lmap != NULL ) {
if( !GetLinkMap( pid, dbg_lmap, &lmap ) )
break;
lli = FindLib( (addr_off)lmap.l_ld );
if( lli == NULL ) {
DoAddLib( pid, &lmap );
++count;
}
dbg_lmap = lmap.l_next;
}
return( count );
}
/*
* DelOneLib - called when dynamic linker is deleting a library. Unfortunately
* we don't get told which library, so we just have to zip through our list
* until we find out which one is suddenly missing.
*/
static int RemoveLibrary( pid_t pid, struct link_map *first_lmap )
{
int count = 0;
int i;
addr_off dyn_base;
for( i = 0; i < ModuleTop; ++i ) {
dyn_base = ModuleInfo[i].dbg_dyn_sect;
if( dyn_base != 0 ) {
if( FindLibInLinkMap( pid, first_lmap, dyn_base ) == NULL ) {
DoRemoveLib( dyn_base );
}
}
}
return( count );
}
unsigned NextThread( unsigned tid )
{
if( tid == MaxThread )
return( 0 );
Samples = SamplesP[ tid ];
SampleIndex = SampleIndexP[ tid ];
if( CallGraphMode ) {
CallGraph = CallGraphP[ tid ];
SampleCount = SampleCountP[ tid ];
}
return( tid + 1 );
}
void SetPid( char **cmd )
{
SamplePid = GetNumber( 1, INT_MAX, cmd, 10 );
}
void InitTimerRate( void )
{
SleepTime = 10; // default to 10 milliseconds
}
void SetTimerRate( char **cmd )
{
SleepTime = GetNumber( 1, 1000, cmd, 10 );
}
unsigned long TimerRate( void )
{
return( 1000 * SleepTime );
}
unsigned SafeMargin( void )
{
return( Ceiling - 10 );
}
int VersionCheck( void )
{
return( TRUE );
}
static void GrowArrays( unsigned tid )
{
unsigned max;
max = MaxThread;
SamplesP = realloc( SamplesP, tid * sizeof( void * ) );
SampleIndexP = realloc( SampleIndexP, tid * sizeof( void * ) );
if( CallGraphMode ) {
CallGraphP = realloc( CallGraphP, tid * sizeof( void * ) );
SampleCountP = realloc( SampleCountP, tid * sizeof( void * ) );
}
while( max < tid ) {
AllocSamples( max + 1 );
SamplesP[ max ] = Samples;
SampleIndexP[ max ] = SampleIndex;
if( CallGraphMode ) {
CallGraphP[ max ] = CallGraph;
SampleCountP[ max ] = SampleCount;
}
++max;
}
MaxThread = max;
}
void RecordSample( unsigned offset, unsigned tid )
{
samp_block *old_samples;
unsigned old_sample_index;
unsigned old_sample_count;
if( tid > MaxThread ) {
GrowArrays( tid );
}
--tid;
LastSampleIndex = SampleIndexP[ tid ];
if( SampleIndexP[ tid ] == 0 ) {
SamplesP[ tid ]->pref.tick = CurrTick;
if( CallGraphMode ) {
CallGraphP[ tid ]->pref.tick = CurrTick;
}
}
++CurrTick;
SamplesP[ tid ]->d.sample.sample[ SampleIndexP[ tid ] ].offset = offset;
SamplesP[ tid ]->d.sample.sample[ SampleIndexP[ tid ] ].segment = FlatSeg;
SampleIndexP[ tid ]++;
if( CallGraphMode ) {
SampleCountP[ tid ]++;
}
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 = SamplesP[ tid ]; /* it into storing the info */
SampleIndex = SampleIndexP[ tid ]; /* in the right place by */
SampleCount = SampleCountP[ tid ];
RecordCGraph(); /* changing its pointers */
SamplesP[ tid ] = Samples; /* and restoring them later */
SampleIndexP[ tid ] = SampleIndex;
SampleCountP[ tid ] = SampleCount;
Samples = old_samples;
SampleIndex = old_sample_index;
SampleCount = old_sample_count;
}
if( SampleIndexP[ tid ] >= Margin ) {
StopAndSave();
}
}
void GetCommArea( void )
{
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 {
ReadMem( Pid, &Comm, CommonAddr.offset, sizeof( Comm ) );
}
}
void ResetCommArea( void )
{
if( CommonAddr.segment != 0 ) { /* reset common variables */
Comm.pop_no = 0;
Comm.push_no = 0;
WriteMem( Pid, &Comm.pop_no, CommonAddr.offset + 11, 2 * sizeof( short ) );
}
}
void GetNextAddr( void )
{
struct {
unsigned long ptr;
seg cs;
off ip;
} stack_entry;
if( CommonAddr.segment == 0 ) {
CGraphOff = 0;
CGraphSeg = 0;
} else {
ReadMem( Pid, &stack_entry, Comm.cgraph_top, sizeof( stack_entry ) );
CGraphOff = stack_entry.ip;
CGraphSeg = stack_entry.cs;
Comm.cgraph_top = stack_entry.ptr;
}
}
void StopProg( void )
{
}
static void CodeLoad( char *name, u_long addr, samp_block_kinds kind )
{
seg_offset ovl;
ovl.offset = 0;
ovl.segment = 0;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?