Figure 1: CallMonitor hook implementation

// Copyright (c) 1998 John Panzer.  Permission is granted to
// use, copy, modify, distribute, and sell this source code as 
// long as this copyright notice appears in all source files.
#include <windows.h>
#include <imagehlp.h>
#include <stdio.h>
#include "CallMon.h"

using namespace std;

typedef CallMonitor::ADDR ADDR;

// Processor-specific offset from
// _penter return address to start of
// caller.
static const unsigned OFFSET_CALL_BYTES=5;

// Start of MSVC-specific code

// _pexit is called upon return from
// an instrumented function.
static void _pexit()
{
    CallMonitor::TICKS endTime;
    CallMonitor::queryTicks(&endTime);
    ADDR framePtr,parentFramePtr;

    // Retrieve parent stack frame to pass
    // to exitProcedure
    __asm mov DWORD PTR [framePtr], ebp
    parentFramePtr = ((ADDR *)framePtr)[0];

    CallMonitor::threadObj().exitProcedure(
            parentFramePtr,
            &((ADDR*)framePtr)[3],endTime);
}

// An entry point to which all instrumented
// function returns are redirected.  
static void __declspec(naked) _pexitThunk()
{
    // Push placeholder return address
    __asm push 0     
    // Protect original return value
    __asm push eax   
    _pexit();
    // Restore original return value
    __asm pop eax    
    // Return using new address set by _pexit
    __asm ret        
}

// _penter is called on entry to each client function
extern "C" __declspec(dllexport)
void _penter()
{
    CallMonitor::TICKS entryTime;
    CallMonitor::queryTicks(&entryTime); // Track entry time

    ADDR framePtr;
    __asm mov DWORD PTR [framePtr], ebp

    CallMonitor::threadObj().enterProcedure(
        (ADDR)((unsigned *)framePtr)[0],
        (ADDR)((unsigned *)framePtr)[1]-OFFSET_CALL_BYTES,
        (ADDR*)&((unsigned *)framePtr)[2],
        entryTime);
}
// End of MSVC-specific code

//End of File