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