/*++

Copyright (c) 1996  Microsoft Corporation

Module Name:

    perfimag.c

Abstract:

    This file implements an Performance Object that presents
    Image details performance object data

Created:

    Bob Watson  22-Oct-1996

Revision History


--*/
//
//  Include Files
//
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <winperf.h>
#include <ntprfctr.h>
#include <perfutil.h>
#include "perfsprc.h"
#include "perfmsg.h"
#include "dataimag.h"

DWORD APIENTRY
BuildImageObject (
    IN OUT  LPVOID  *lppData,
    IN OUT  LPDWORD lpcbTotalBytes,
    IN OUT  LPDWORD lpNumObjectTypes,
    IN      BOOL    bLongImageName
)
/*++

Routine Description:

    This routine will return the data for the processor object

Arguments:

    IN OUT   LPVOID   *lppData
         IN: pointer to the address of the buffer to receive the completed
            PerfDataBlock and subordinate structures. This routine will
            append its data to the buffer starting at the point referenced
            by *lppData.
         OUT: points to the first byte after the data structure added by this
            routine. This routine updated the value at lppdata after appending
            its data.

    IN OUT   LPDWORD  lpcbTotalBytes
         IN: the address of the DWORD that tells the size in bytes of the
            buffer referenced by the lppData argument
         OUT: the number of bytes added by this routine is writted to the
            DWORD pointed to by this argument

    IN OUT   LPDWORD  NumObjectTypes
         IN: the address of the DWORD to receive the number of objects added
            by this routine
         OUT: the number of objects added by this routine is writted to the
            DWORD pointed to by this argument

    IN      BOOL    bLongImageName
            TRUE -- use the full path of the library file name in the instance
            FALSE - use only the file name in the instance

    Returns:

             0 if successful, else Win 32 error code of failure

--*/
{
    DWORD   TotalLen;            //  Length of the total return block

    PIMAGE_DATA_DEFINITION          pImageDataDefinition;
    PPERF_INSTANCE_DEFINITION       pPerfInstanceDefinition;
    PIMAGE_COUNTER_DATA             pICD;
    DWORD                           dwNumInstances;

    DWORD                           dwImageNameLength;

    DWORD                           dwProcessIndex;

    PPROCESS_VA_INFO                pThisProcess;
    PMODINFO                        pThisImage;

    dwNumInstances = 0;

    pImageDataDefinition = (IMAGE_DATA_DEFINITION *) *lppData;

    //
    //  Check for sufficient space for Image object type definition
    //

    TotalLen = sizeof(IMAGE_DATA_DEFINITION) +
               sizeof(PERF_INSTANCE_DEFINITION) +
               MAX_PROCESS_NAME_LENGTH +
               sizeof(IMAGE_COUNTER_DATA);

    if ( *lpcbTotalBytes < TotalLen ) {
        *lpcbTotalBytes = (DWORD) 0;
        *lpNumObjectTypes = (DWORD) 0;
        return ERROR_MORE_DATA;
    }

    //
    //  Define Page File data block
    //

    memcpy(pImageDataDefinition,
        &ImageDataDefinition,
        sizeof(IMAGE_DATA_DEFINITION));

    // update object title index if this is a Long Image object

    if (bLongImageName) {
        pImageDataDefinition->ImageObjectType.ObjectNameTitleIndex =
            LONG_IMAGE_OBJECT_TITLE_INDEX;
        pImageDataDefinition->ImageObjectType.ObjectHelpTitleIndex =
            LONG_IMAGE_OBJECT_TITLE_INDEX + 1;
    }

    pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *)
                                &pImageDataDefinition[1];

    // Now load data for each Image

    pThisProcess = pProcessVaInfo;
    dwProcessIndex = 0;
    TotalLen = sizeof(IMAGE_DATA_DEFINITION);

    while (pThisProcess) {

        pThisImage = pThisProcess->pMemBlockInfo;

        while (pThisImage) {

            dwImageNameLength = (bLongImageName ? pThisImage->LongInstanceName->Length :
                    pThisImage->InstanceName->Length);
            dwImageNameLength += sizeof(WCHAR);
            dwImageNameLength = QWORD_MULTIPLE(dwImageNameLength);
        
            // see if this instance will fit

            TotalLen += sizeof (PERF_INSTANCE_DEFINITION) +
                dwImageNameLength + 
//                (MAX_PROCESS_NAME_LENGTH + 1) * sizeof (WCHAR) +
                sizeof (DWORD) +
                sizeof (IMAGE_COUNTER_DATA);

            if ( *lpcbTotalBytes < TotalLen ) {
                *lpcbTotalBytes = (DWORD) 0;
                *lpNumObjectTypes = (DWORD) 0;
                return ERROR_MORE_DATA;
            }

            MonBuildInstanceDefinition (pPerfInstanceDefinition,
                (PVOID *) &pICD,
                EXPROCESS_OBJECT_TITLE_INDEX,
                dwProcessIndex,
                (DWORD)-1,
                (bLongImageName ? pThisImage->LongInstanceName->Buffer :
                    pThisImage->InstanceName->Buffer));

            pICD->CounterBlock.ByteLength = sizeof(IMAGE_COUNTER_DATA);

            pICD->ImageAddrNoAccess           = pThisImage->CommitVector[NOACCESS];
            pICD->ImageAddrReadOnly           = pThisImage->CommitVector[READONLY];
            pICD->ImageAddrReadWrite          = pThisImage->CommitVector[READWRITE];
            pICD->ImageAddrWriteCopy          = pThisImage->CommitVector[WRITECOPY];
            pICD->ImageAddrExecute            = pThisImage->CommitVector[EXECUTE];
            pICD->ImageAddrExecuteReadOnly    = pThisImage->CommitVector[EXECUTEREAD];
            pICD->ImageAddrExecuteReadWrite   = pThisImage->CommitVector[EXECUTEREADWRITE];
            pICD->ImageAddrExecuteWriteCopy   = pThisImage->CommitVector[EXECUTEWRITECOPY];

            pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *)&pICD[1];

            // adjust Total Length value to reflect ACTUAL size used

            TotalLen = (DWORD)((PCHAR) pPerfInstanceDefinition -
                (PCHAR) pImageDataDefinition);

            dwNumInstances++;

            pThisImage = pThisImage->pNextModule;
        }
        pThisProcess = pThisProcess->pNextProcess;
        dwProcessIndex++;
    }

    pImageDataDefinition->ImageObjectType.NumInstances += dwNumInstances;

    *lpcbTotalBytes =
        pImageDataDefinition->ImageObjectType.TotalByteLength =
            (DWORD)((PCHAR) pPerfInstanceDefinition -
            (PCHAR) pImageDataDefinition);

#if DBG
    if (*lpcbTotalBytes > TotalLen ) {
        DbgPrint ("\nPERFPROC: Image Perf Ctr. Instance Size Underestimated:");
        DbgPrint ("\nPERFPROC:   Estimated size: %d, Actual Size: %d", TotalLen, *lpcbTotalBytes);
    }
#endif

    *lppData = (LPVOID) pPerfInstanceDefinition;

    // increment number of objects in this data block
    *lpNumObjectTypes = 1;

    return ERROR_SUCCESS;
}

DWORD APIENTRY
CollectImageObjectData (
    IN OUT  LPVOID  *lppData,
    IN OUT  LPDWORD lpcbTotalBytes,
    IN OUT  LPDWORD lpNumObjectTypes
)
/*++

Routine Description:

    This routine will return the data for the processor object

Arguments:

   IN OUT   LPVOID   *lppData
         IN: pointer to the address of the buffer to receive the completed
            PerfDataBlock and subordinate structures. This routine will
            append its data to the buffer starting at the point referenced
            by *lppData.
         OUT: points to the first byte after the data structure added by this
            routine. This routine updated the value at lppdata after appending
            its data.

   IN OUT   LPDWORD  lpcbTotalBytes
         IN: the address of the DWORD that tells the size in bytes of the
            buffer referenced by the lppData argument
         OUT: the number of bytes added by this routine is writted to the
            DWORD pointed to by this argument

   IN OUT   LPDWORD  NumObjectTypes
         IN: the address of the DWORD to receive the number of objects added
            by this routine
         OUT: the number of objects added by this routine is writted to the
            DWORD pointed to by this argument

   Returns:

             0 if successful, else Win 32 error code of failure

--*/
{
    return BuildImageObject (
                lppData,
                lpcbTotalBytes,
                lpNumObjectTypes,
                FALSE); // use short names
}

DWORD APIENTRY
CollectLongImageObjectData (
    IN OUT  LPVOID  *lppData,
    IN OUT  LPDWORD lpcbTotalBytes,
    IN OUT  LPDWORD lpNumObjectTypes
)
/*++

Routine Description:

    This routine will return the data for the processor object

Arguments:

   IN OUT   LPVOID   *lppData
         IN: pointer to the address of the buffer to receive the completed
            PerfDataBlock and subordinate structures. This routine will
            append its data to the buffer starting at the point referenced
            by *lppData.
         OUT: points to the first byte after the data structure added by this
            routine. This routine updated the value at lppdata after appending
            its data.

   IN OUT   LPDWORD  lpcbTotalBytes
         IN: the address of the DWORD that tells the size in bytes of the
            buffer referenced by the lppData argument
         OUT: the number of bytes added by this routine is writted to the
            DWORD pointed to by this argument

   IN OUT   LPDWORD  NumObjectTypes
         IN: the address of the DWORD to receive the number of objects added
            by this routine
         OUT: the number of objects added by this routine is writted to the
            DWORD pointed to by this argument

   Returns:

             0 if successful, else Win 32 error code of failure

--*/
{
    return BuildImageObject (
                lppData,
                lpcbTotalBytes,
                lpNumObjectTypes,
                TRUE); // use long names
}
