You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3198 lines
101 KiB
3198 lines
101 KiB
/*** WST.C - Working Set Tuner Data Collection Program.
|
|
*
|
|
*
|
|
* Title:
|
|
*
|
|
* WST- Working Set Tuner Data Collection Program.
|
|
*
|
|
* Copyright (c) 1992-1994, Microsoft Corporation.
|
|
* Reza Baghai.
|
|
*
|
|
* Description:
|
|
*
|
|
* The Working Set Tuner tool is organized as follows:
|
|
*
|
|
* o WST.c ........ Tools main body
|
|
* o WST.h
|
|
* o WST.def
|
|
*
|
|
*
|
|
*
|
|
* Design/Implementation Notes
|
|
*
|
|
* The following defines can be used to control output of all the
|
|
* debugging information to the debugger via KdPrint() for the checked
|
|
* builds:
|
|
*
|
|
* (All debugging options are undefined for free/retail builds)
|
|
*
|
|
* PPC
|
|
* ---
|
|
*
|
|
* PPC experiences problems when reading symbols in CRTDLL.dll
|
|
*
|
|
* #ifdef INFODBG : Displays messages to indicate when data dumping/
|
|
* clearing operations are completed. It has no effect
|
|
* on timing. *DEFAULT*
|
|
*
|
|
* #ifdef SETUPDBG : Displays messages during memory management and
|
|
* symbol lookup operations. It has some affect
|
|
* on timing whenever a chuck of memory is committed.
|
|
*
|
|
* #ifdef C6 : Generate code using C6 compiler. C6 compiler
|
|
* calls _mcount() as the profiling routine where as
|
|
* C8 calls _penter().
|
|
*
|
|
*
|
|
*
|
|
*
|
|
* Modification History:
|
|
*
|
|
* 92.07.28 RezaB -- Created
|
|
* 94.02.08 a-honwah -- ported to MIPS and ALPHA
|
|
* 98.04.28 DerrickG (mdg) -- QFE:
|
|
* - use private grow-on-demand heap for Wststrdup() - large symbol count
|
|
* - remove unused code associated with patching - reduce irrelevant mem usage
|
|
* - modify WSP file format for large symbol count (long vs. short)
|
|
* - modify TMI file write routine for arbitrary function name sizes
|
|
* - added UnmapDebugInformation() to release symbols from DBGHELP
|
|
* - eliminated dump for modules with no symbols
|
|
* - modified WST.INI parsing code for more robust section recognition
|
|
* - added MaxSnaps WST.INI entry in [Time Interval] section to control
|
|
* memory allocated for snapshot data
|
|
* - Modified SetSymbolSearchPath() to put current directory first in
|
|
* search path per standard - see docs for SymInitialize()
|
|
* - Removed unused internal version number (it's already in the .rc)
|
|
*
|
|
*/
|
|
|
|
#if DBG
|
|
//
|
|
// Don't do anything for the checked builds, let it be controlled from the
|
|
// sources file.
|
|
//
|
|
#else
|
|
//
|
|
// Disable all debugging options.
|
|
//
|
|
#undef INFODBG
|
|
#undef SETUPDBG
|
|
#define SdPrint(_x_)
|
|
#define IdPrint(_x_)
|
|
#endif
|
|
|
|
#ifdef SETUPDBG
|
|
#define SdPrint(_x_) DbgPrint _x_
|
|
#else
|
|
#define SdPrint(_x_)
|
|
#endif
|
|
|
|
#ifdef INFODBG
|
|
#define IdPrint(_x_) DbgPrint _x_
|
|
#else
|
|
#define IdPrint(_x_)
|
|
#endif
|
|
|
|
|
|
|
|
/* * * * * * * * * * * * * I N C L U D E F I L E S * * * * * * * * * * */
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <ntcsrsrv.h>
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <excpt.h>
|
|
|
|
#include <windows.h>
|
|
|
|
#include <dbghelp.h>
|
|
|
|
#include "wst.h"
|
|
#include "wstexp.h"
|
|
|
|
#if defined(_AMD64_)
|
|
|
|
VOID
|
|
penter (
|
|
VOID
|
|
)
|
|
|
|
{
|
|
return;
|
|
}
|
|
|
|
#endif
|
|
|
|
#if defined(ALPHA) || defined(AXP64)
|
|
#define REG_BUFFER_SIZE (sizeof(DWORDLONG) * 64)
|
|
#elif defined(IA64)
|
|
#define REG_BUFFER_SIZE sizeof(CONTEXT) / sizeof(DWORDLONG)
|
|
#endif
|
|
|
|
|
|
#if defined(ALPHA) || defined(IA64)
|
|
//typedef double DWORDLONG; // bobw not needed in NT5
|
|
void SaveAllRegs (DWORDLONG *pSaveRegs) ;
|
|
void RestoreAllRegs (DWORDLONG *pSaveRegs) ;
|
|
void penter(void);
|
|
#endif
|
|
|
|
void SetSymbolSearchPath (void);
|
|
LPSTR lpSymbolSearchPath = NULL;
|
|
#define NO_CALLER 10L
|
|
|
|
/* * * * * * * * * * G L O B A L D E C L A R A T I O N S * * * * * * * * */
|
|
|
|
|
|
/* * * * * * * * * * F U N C T I O N P R O T O T Y P E S * * * * * * * * */
|
|
|
|
BOOLEAN WSTMain (IN PVOID DllHandle, ULONG Reason,
|
|
IN PCONTEXT Context OPTIONAL);
|
|
|
|
BOOLEAN WstDllInitializations (void);
|
|
|
|
void WstRecordInfo (DWORD_PTR dwAddress, DWORD_PTR dwPrevAddress);
|
|
|
|
void WstGetSymbols (PIMG pCurImg, PSZ pszImageName, PVOID pvImageBase,
|
|
ULONG ulCodeLength,
|
|
PIMAGE_COFF_SYMBOLS_HEADER DebugInfo);
|
|
|
|
void WstDllCleanups (void);
|
|
|
|
INT WstAccessXcptFilter (ULONG ulXcptNo, PEXCEPTION_POINTERS pXcptPtr);
|
|
|
|
HANDLE WstInitWspFile (PIMG pImg);
|
|
|
|
void WstClearBitStrings (PIMG pImg);
|
|
|
|
void WstDumpData (PIMG pImg);
|
|
|
|
void WstRotateWsiMem (PIMG pImg);
|
|
|
|
void WstWriteTmiFile (PIMG pImg);
|
|
|
|
int WstCompare (PWSP, PWSP);
|
|
void WstSort (WSP wsp[], INT iLeft, INT iRight);
|
|
int WstBCompare (DWORD_PTR *, PWSP);
|
|
PWSP WstBSearch (DWORD_PTR dwAddr, WSP wspCur[], INT n);
|
|
void WstSwap (WSP wsp[], INT i, INT j);
|
|
|
|
DWORD WstDumpThread (PVOID pvArg);
|
|
DWORD WstClearThread (PVOID pvArg);
|
|
DWORD WstPauseThread (PVOID pvArg);
|
|
|
|
void WstDataOverFlow(void);
|
|
|
|
#ifdef BATCHING
|
|
BOOL WstOpenBatchFile (VOID);
|
|
#endif
|
|
|
|
#if defined(_PPC_)
|
|
//BOOL WINAPI _CRT_INIT(HINSTANCE, DWORD, LPVOID);
|
|
#endif
|
|
|
|
|
|
/* * * * * * * * * * * G L O B A L V A R I A B L E S * * * * * * * * * */
|
|
|
|
HANDLE hWspSec;
|
|
PULONG pulShared;
|
|
HANDLE hSharedSec;
|
|
HANDLE hWstHeap = NULL; // mdg 4/98 for private heap
|
|
|
|
IMG aImg [MAX_IMAGES];
|
|
int iImgCnt;
|
|
|
|
HANDLE hGlobalSem;
|
|
HANDLE hLocalSem;
|
|
HANDLE hDoneEvent;
|
|
HANDLE hDumpEvent;
|
|
HANDLE hClearEvent;
|
|
HANDLE hPauseEvent;
|
|
HANDLE hDumpThread;
|
|
HANDLE hClearThread;
|
|
HANDLE hPauseThread;
|
|
DWORD DumpClientId;
|
|
DWORD ClearClientId;
|
|
DWORD PauseClientId;
|
|
PSZ pszBaseAppImageName;
|
|
PSZ pszFullAppImageName;
|
|
WSTSTATE WstState = NOT_STARTED;
|
|
char achPatchBuffer [PATCHFILESZ+1] = "???";
|
|
PULONG pulWsiBits;
|
|
PULONG pulWspBits;
|
|
PULONG pulCurWsiBits;
|
|
static UINT uiTimeSegs= 0;
|
|
ULONG ulSegSize;
|
|
ULONG ulMaxSnapULONGs = (MAX_SNAPS_DFLT + 31) / 32; // mdg 98/3
|
|
ULONG ulSnaps = 0L;
|
|
ULONG ulBitCount = 0L;
|
|
LARGE_INTEGER liStart;
|
|
int iTimeInterval = 0; // mdg 98/3
|
|
BOOL fInThread = FALSE;
|
|
ULONG ulThdStackSize = 16*PAGE_SIZE;
|
|
BOOL fPatchImage = FALSE;
|
|
SECURITY_DESCRIPTOR SecDescriptor;
|
|
LARGE_INTEGER liOverhead = {0L, 0L};
|
|
|
|
#ifdef BATCHING
|
|
HANDLE hBatchFile;
|
|
BOOL fBatch = TRUE;
|
|
#endif
|
|
|
|
|
|
|
|
/* * * * * * E X P O R T E D G L O B A L V A R I A B L E S * * * * * */
|
|
/* none */
|
|
|
|
|
|
|
|
|
|
|
|
/****************************** W S T M a i n *******************************
|
|
*
|
|
* WSTMain () -
|
|
* This is the DLL entry routine. It performs
|
|
* DLL's initializations and cleanup.
|
|
*
|
|
* ENTRY -none-
|
|
*
|
|
* EXIT -none-
|
|
*
|
|
* RETURN TRUE if successful
|
|
* FALSE otherwise.
|
|
*
|
|
* WARNING:
|
|
* -none-
|
|
*
|
|
* COMMENT:
|
|
* -none-
|
|
*
|
|
*/
|
|
|
|
BOOLEAN WSTMain (IN PVOID DllHandle,
|
|
ULONG Reason,
|
|
IN PCONTEXT Context OPTIONAL)
|
|
|
|
{
|
|
DllHandle; // avoid compiler warnings
|
|
Context; // avoid compiler warnings
|
|
|
|
|
|
if (Reason == DLL_PROCESS_ATTACH) {
|
|
//
|
|
// Initialize the DLL data
|
|
//
|
|
#if defined(_PPC_LIBC)
|
|
if (!_CRT_INIT(DllHandle, Reason, Context))
|
|
return(FALSE);
|
|
#endif
|
|
KdPrint (("WST: DLL_PROCESS_ATTACH\n"));
|
|
WstDllInitializations ();
|
|
} else if (Reason == DLL_PROCESS_DETACH) {
|
|
//
|
|
// Cleanup time
|
|
//
|
|
#if defined(_PPC_LIBC)
|
|
if (!_CRT_INIT(DllHandle, Reason, Context))
|
|
return(FALSE);
|
|
#endif
|
|
KdPrint (("WST: DLL_PROCESS_DETACH\n"));
|
|
WstDllCleanups ();
|
|
}
|
|
#if defined(DBG)
|
|
else {
|
|
KdPrint (("WST: DLL_PROCESS_??\n")); // mdg 98/3
|
|
}
|
|
#endif // DBG
|
|
|
|
return (TRUE);
|
|
|
|
} /* WSTMain() */
|
|
|
|
/****************** W s t s t r d u p ****************************
|
|
*
|
|
* Wststrdup () -
|
|
* Allocate a memory and then duplicate a string
|
|
* It is here because we don't want to use strdup in crtdll.dll
|
|
*
|
|
* ENTRY LPSTR
|
|
*
|
|
* EXIT LPSTR
|
|
*
|
|
* RETURN NULL if failed
|
|
* LPSTR is success
|
|
*
|
|
* WARNING:
|
|
* -none-
|
|
*
|
|
* COMMENT:
|
|
* -none-
|
|
*
|
|
*/
|
|
LPSTR Wststrdup (LPTSTR lpInput)
|
|
// No NULL return ever - throws exception if low on memory
|
|
{
|
|
size_t StringLen;
|
|
LPSTR lpOutput;
|
|
|
|
#if defined(DBG)
|
|
if (NULL == lpInput) {
|
|
KdPrint (("WST: Wststrdup() - NULL pointer\n")); // mdg 98/3
|
|
return NULL;
|
|
}
|
|
#endif
|
|
if (NULL == hWstHeap) {
|
|
hWstHeap = HeapCreate( HEAP_GENERATE_EXCEPTIONS, 1, 0 ); // Create min size growable heap
|
|
}
|
|
StringLen = strlen( lpInput ) + 1;
|
|
lpOutput = HeapAlloc( hWstHeap, HEAP_GENERATE_EXCEPTIONS, StringLen );
|
|
if (lpOutput)
|
|
CopyMemory( lpOutput, lpInput, StringLen );
|
|
|
|
return lpOutput;
|
|
}
|
|
|
|
|
|
|
|
/****************** W s t D l l I n i t i a l i z a t i o n s ***************
|
|
*
|
|
* WstDllInitializations () -
|
|
* Performs the following initializations:
|
|
*
|
|
* o Create LOCAL semaphore (not named)
|
|
* o Create/Open global storage for WST data
|
|
* o Locate all the executables/DLLs in the address and
|
|
* grab all the symbols
|
|
* o Sort the symbol list
|
|
* o Set the profiling flag to TRUE
|
|
*
|
|
*
|
|
* ENTRY -none-
|
|
*
|
|
* EXIT -none-
|
|
*
|
|
* RETURN TRUE if successful
|
|
* FALSE otherwise.
|
|
*
|
|
* WARNING:
|
|
* -none-
|
|
*
|
|
* COMMENT:
|
|
* -none-
|
|
*
|
|
*/
|
|
|
|
BOOLEAN WstDllInitializations ()
|
|
{
|
|
DWORD_PTR dwAddr = 0L;
|
|
DWORD dwPrevAddr = 0L;
|
|
ANSI_STRING ObjName;
|
|
UNICODE_STRING UnicodeName;
|
|
OBJECT_ATTRIBUTES ObjAttributes;
|
|
PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
|
|
PPEB Peb;
|
|
PSZ ImageName;
|
|
PLIST_ENTRY Next;
|
|
ULONG ExportSize;
|
|
PIMAGE_EXPORT_DIRECTORY ExportDirectory;
|
|
STRING ImageStringName;
|
|
LARGE_INTEGER AllocationSize;
|
|
SIZE_T ulViewSize;
|
|
LARGE_INTEGER liOffset = {0L, 0L};
|
|
HANDLE hIniFile;
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK iostatus;
|
|
char achTmpImageName [32];
|
|
PCHAR pchPatchExes = "";
|
|
PCHAR pchPatchImports = "";
|
|
PCHAR pchPatchCallers = "";
|
|
PCHAR pchTimeInterval = "";
|
|
PVOID ImageBase;
|
|
ULONG CodeLength;
|
|
LARGE_INTEGER liFreq;
|
|
PIMG pImg;
|
|
PIMAGE_NT_HEADERS pImageNtHeader;
|
|
TCHAR atchProfObjsName[160] = PROFOBJSNAME;
|
|
PTEB pteb = NtCurrentTeb();
|
|
LARGE_INTEGER liStartTicks;
|
|
LARGE_INTEGER liEndTicks;
|
|
ULONG ulElapsed;
|
|
PCHAR pchEntry;
|
|
int i; // To match "->iSymCnt"
|
|
#ifndef _WIN64
|
|
PIMAGE_DEBUG_INFORMATION pImageDbgInfo = NULL;
|
|
#endif
|
|
|
|
|
|
/*
|
|
***
|
|
*/
|
|
|
|
SetSymbolSearchPath();
|
|
|
|
// Create public share security descriptor for all the named objects
|
|
//
|
|
|
|
Status = RtlCreateSecurityDescriptor (
|
|
&SecDescriptor,
|
|
SECURITY_DESCRIPTOR_REVISION1
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDllInitializations() - "
|
|
"RtlCreateSecurityDescriptor failed - 0x%lx\n", Status)); // mdg 98/3
|
|
return (FALSE);
|
|
}
|
|
|
|
Status = RtlSetDaclSecurityDescriptor (
|
|
&SecDescriptor, // SecurityDescriptor
|
|
TRUE, // DaclPresent
|
|
NULL, // Dacl
|
|
FALSE // DaclDefaulted
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDllInitializations() - "
|
|
"RtlSetDaclSecurityDescriptor failed - 0x%lx\n", Status)); // mdg 98/3
|
|
return (FALSE);
|
|
}
|
|
|
|
|
|
/*
|
|
***
|
|
*/
|
|
|
|
// Initialization for GLOBAL semaphore creation (named)
|
|
//
|
|
RtlInitString (&ObjName, GLOBALSEMNAME);
|
|
Status = RtlAnsiStringToUnicodeString (&UnicodeName, &ObjName, TRUE);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDllInitializations() - "
|
|
"RtlAnsiStringToUnicodeString failed - 0x%lx\n", Status));
|
|
return (FALSE);
|
|
}
|
|
|
|
InitializeObjectAttributes (&ObjAttributes,
|
|
&UnicodeName,
|
|
OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
&SecDescriptor);
|
|
|
|
// Create GLOBAL semaphore
|
|
//
|
|
Status = NtCreateSemaphore (&hGlobalSem,
|
|
SEMAPHORE_QUERY_STATE |
|
|
SEMAPHORE_MODIFY_STATE |
|
|
SYNCHRONIZE,
|
|
&ObjAttributes,
|
|
1L,
|
|
1L);
|
|
|
|
RtlFreeUnicodeString (&UnicodeName); // HWC 11/93
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDllInitializations() - "
|
|
"GLOBAL semaphore creation failed - 0x%lx\n", Status)); // mdg 98/3
|
|
return (FALSE);
|
|
}
|
|
|
|
|
|
/*
|
|
***
|
|
*/
|
|
|
|
// Create LOCAL semaphore (not named - only for this process context)
|
|
//
|
|
Status = NtCreateSemaphore (&hLocalSem,
|
|
SEMAPHORE_QUERY_STATE |
|
|
SEMAPHORE_MODIFY_STATE |
|
|
SYNCHRONIZE,
|
|
NULL,
|
|
1L,
|
|
1L);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDllInitializations() - "
|
|
"LOCAL semaphore creation failed - 0x%lx\n", // mdg 98/3
|
|
Status));
|
|
return (FALSE);
|
|
}
|
|
|
|
|
|
/*
|
|
***
|
|
*/
|
|
|
|
// Initialize for allocating shared memory
|
|
//
|
|
RtlInitString(&ObjName, SHAREDNAME);
|
|
Status = RtlAnsiStringToUnicodeString(&UnicodeName, &ObjName, TRUE);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDllInitializations() - "
|
|
"RtlAnsiStringToUnicodeString() failed - 0x%lx\n", Status));
|
|
return (FALSE);
|
|
}
|
|
|
|
InitializeObjectAttributes(&ObjAttributes,
|
|
&UnicodeName,
|
|
OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
&SecDescriptor);
|
|
|
|
AllocationSize.HighPart = 0;
|
|
AllocationSize.LowPart = PAGE_SIZE;
|
|
|
|
// Create a read-write section
|
|
//
|
|
Status = NtCreateSection(&hSharedSec,
|
|
SECTION_MAP_READ | SECTION_MAP_WRITE,
|
|
&ObjAttributes,
|
|
&AllocationSize,
|
|
PAGE_READWRITE,
|
|
SEC_RESERVE,
|
|
NULL);
|
|
RtlFreeUnicodeString (&UnicodeName); // HWC 11/93
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDllInitializations() - "
|
|
"NtCreateSection() failed - 0x%lx\n", Status));
|
|
return (FALSE);
|
|
}
|
|
|
|
ulViewSize = AllocationSize.LowPart;
|
|
pulShared = NULL;
|
|
|
|
// Map the section - commit all
|
|
//
|
|
Status = NtMapViewOfSection (hSharedSec,
|
|
NtCurrentProcess(),
|
|
(PVOID *)&pulShared,
|
|
0L,
|
|
PAGE_SIZE,
|
|
NULL,
|
|
&ulViewSize,
|
|
ViewUnmap,
|
|
0L,
|
|
PAGE_READWRITE);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDllInitializations() - "
|
|
"NtMapViewOfSection() failed - 0x%lx\n", Status));
|
|
return (FALSE);
|
|
}
|
|
|
|
*pulShared = 0L;
|
|
|
|
/*
|
|
***
|
|
*/
|
|
|
|
hIniFile = CreateFile (
|
|
WSTINIFILE, // The filename
|
|
GENERIC_READ, // Desired access
|
|
FILE_SHARE_READ, // Shared Access
|
|
NULL, // Security Access
|
|
OPEN_EXISTING, // Read share access
|
|
FILE_ATTRIBUTE_NORMAL, // Open option
|
|
NULL); // No template file
|
|
|
|
if (hIniFile == INVALID_HANDLE_VALUE) {
|
|
KdPrint (("WST: WstDllInitializations() - "
|
|
"Error openning %s - 0x%lx\n", WSTINIFILE, GetLastError()));
|
|
return (FALSE);
|
|
}
|
|
|
|
Status = NtReadFile(hIniFile, // DLL patch file handle
|
|
0L, // Event - optional
|
|
NULL, // Completion routine - optional
|
|
NULL, // Completion routine argument - optional
|
|
&iostatus, // Completion status
|
|
(PVOID)achPatchBuffer, // Buffer to receive data
|
|
PATCHFILESZ, // Bytes to read
|
|
&liOffset, // Byte offset - optional
|
|
0L); // Target process - optional
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDllInitializations() - "
|
|
"Error reading %s - 0x%lx\n", WSTINIFILE, Status));
|
|
return (FALSE);
|
|
} else if (iostatus.Information >= PATCHFILESZ) {
|
|
KdPrint (("WST: WstDllInitializations() - "
|
|
"initialization file buffer too small (%lu)\n", PATCHFILESZ));
|
|
return (FALSE);
|
|
} else {
|
|
achPatchBuffer [iostatus.Information] = '\0';
|
|
_strupr (achPatchBuffer);
|
|
|
|
// Allow for headers to appear in any order in .INI or be absent
|
|
pchPatchExes = strstr( achPatchBuffer, PATCHEXELIST );
|
|
pchPatchImports = strstr( achPatchBuffer, PATCHIMPORTLIST );
|
|
pchTimeInterval = strstr( achPatchBuffer, TIMEINTERVALIST );
|
|
if (pchPatchExes != NULL) {
|
|
if (pchPatchExes > achPatchBuffer)
|
|
*(pchPatchExes - 1) = '\0';
|
|
} else {
|
|
pchPatchExes = "";
|
|
}
|
|
if (pchPatchImports != NULL) {
|
|
if (pchPatchImports > achPatchBuffer)
|
|
*(pchPatchImports - 1) = '\0';
|
|
} else {
|
|
pchPatchImports = "";
|
|
}
|
|
if (pchTimeInterval != NULL) {
|
|
const char * pSnapsEntry = strstr( pchTimeInterval, MAX_SNAPS_ENTRY );
|
|
|
|
if (pchTimeInterval > achPatchBuffer)
|
|
*(pchTimeInterval - 1) = '\0';
|
|
if (pSnapsEntry) {
|
|
long lSnapsEntry =
|
|
atol( pSnapsEntry + sizeof( MAX_SNAPS_ENTRY ) - 1 );
|
|
if (lSnapsEntry > 0)
|
|
ulMaxSnapULONGs = (lSnapsEntry + 31) / 32;
|
|
}
|
|
} else {
|
|
pchTimeInterval = "";
|
|
}
|
|
}
|
|
|
|
NtClose (hIniFile);
|
|
|
|
SdPrint (("WST: WstDllInitializations() - Patching info:\n"));
|
|
SdPrint (("WST: -- %s\n", pchPatchExes));
|
|
SdPrint (("WST: -- %s\n", pchPatchImports));
|
|
SdPrint (("WST: -- %s\n", pchTimeInterval));
|
|
|
|
|
|
/*
|
|
***
|
|
*/
|
|
|
|
// Initialize for allocating global storage for WSPs
|
|
//
|
|
_ui64toa ((ULONG64)pteb->ClientId.UniqueProcess, atchProfObjsName+75, 10);
|
|
_ui64toa ((ULONG64)pteb->ClientId.UniqueThread, atchProfObjsName+105, 10);
|
|
strcat (atchProfObjsName, atchProfObjsName+75);
|
|
strcat (atchProfObjsName, atchProfObjsName+105);
|
|
|
|
SdPrint (("WST: WstDllInitializations() - %s\n", atchProfObjsName));
|
|
|
|
RtlInitString(&ObjName, atchProfObjsName);
|
|
Status = RtlAnsiStringToUnicodeString(&UnicodeName, &ObjName, TRUE);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDllInitializations() - "
|
|
"RtlAnsiStringToUnicodeString() failed - 0x%lx\n", Status));
|
|
return (FALSE);
|
|
}
|
|
|
|
InitializeObjectAttributes (&ObjAttributes,
|
|
&UnicodeName,
|
|
OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
&SecDescriptor);
|
|
|
|
AllocationSize.HighPart = 0;
|
|
AllocationSize.LowPart = MEMSIZE;
|
|
|
|
// Create a read-write section
|
|
//
|
|
Status =NtCreateSection(&hWspSec,
|
|
SECTION_MAP_READ | SECTION_MAP_WRITE,
|
|
&ObjAttributes,
|
|
&AllocationSize,
|
|
PAGE_READWRITE,
|
|
SEC_RESERVE,
|
|
NULL);
|
|
|
|
RtlFreeUnicodeString (&UnicodeName); // HWC 11/93
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDllInitializations() - "
|
|
"NtCreateSection() failed - 0x%lx\n", Status));
|
|
return (FALSE);
|
|
}
|
|
|
|
ulViewSize = AllocationSize.LowPart;
|
|
pImg = &aImg[0];
|
|
pImg->pWsp = NULL;
|
|
|
|
// Map the section - commit the first 4 * COMMIT_SIZE pages
|
|
//
|
|
Status = NtMapViewOfSection(hWspSec,
|
|
NtCurrentProcess(),
|
|
(PVOID *)&(pImg->pWsp),
|
|
0L,
|
|
COMMIT_SIZE * 4,
|
|
NULL,
|
|
&ulViewSize,
|
|
ViewUnmap,
|
|
0L,
|
|
PAGE_READWRITE);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDllInitializations() - "
|
|
"NtMapViewOfSection() failed - 0x%lx\n", Status));
|
|
return (FALSE);
|
|
}
|
|
|
|
try /* EXCEPT - to handle access violation exception. */ {
|
|
//
|
|
// Locate all the executables/DLLs in the address and get their symbols
|
|
//
|
|
BOOL fTuneApp = FALSE; // Set if whole app is to be tuned
|
|
iImgCnt = 0;
|
|
Peb = NtCurrentPeb();
|
|
Next = Peb->Ldr->InMemoryOrderModuleList.Flink;
|
|
|
|
for (; Next != &Peb->Ldr->InMemoryOrderModuleList; Next = Next->Flink) {
|
|
IdPrint (("WST: WstDllInitializations() - Walking module chain: 0x%lx\n", Next));
|
|
LdrDataTableEntry =
|
|
(PLDR_DATA_TABLE_ENTRY)
|
|
(CONTAINING_RECORD(Next,LDR_DATA_TABLE_ENTRY,InMemoryOrderLinks));
|
|
|
|
ImageBase = LdrDataTableEntry->DllBase;
|
|
if ( Peb->ImageBaseAddress == ImageBase ) {
|
|
|
|
RtlUnicodeStringToAnsiString (&ImageStringName,
|
|
&LdrDataTableEntry->BaseDllName,
|
|
TRUE);
|
|
ImageName = ImageStringName.Buffer;
|
|
pszBaseAppImageName = ImageStringName.Buffer;
|
|
|
|
RtlUnicodeStringToAnsiString (&ImageStringName,
|
|
&LdrDataTableEntry->FullDllName,
|
|
TRUE);
|
|
pszFullAppImageName = ImageStringName.Buffer;
|
|
//
|
|
// Skip the object directory name (if any)
|
|
//
|
|
if ( (pszFullAppImageName = strchr(pszFullAppImageName, ':')) ) {
|
|
pszFullAppImageName--;
|
|
} else {
|
|
pszFullAppImageName = pszBaseAppImageName;
|
|
}
|
|
IdPrint (("WST: WstDllInitializations() - FullAppImageName: %s\n", pszFullAppImageName));
|
|
} else {
|
|
ExportDirectory =
|
|
(PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData (
|
|
ImageBase,
|
|
TRUE,
|
|
IMAGE_DIRECTORY_ENTRY_EXPORT,
|
|
&ExportSize);
|
|
|
|
ImageName = (PSZ)((ULONG_PTR)ImageBase + ExportDirectory->Name);
|
|
IdPrint (("WST: WstDllInitializations() - ImageName: %s\n", ImageName));
|
|
}
|
|
|
|
pImageNtHeader = RtlImageNtHeader (ImageBase);
|
|
|
|
_strupr (strcpy (achTmpImageName, ImageName));
|
|
pchEntry = strstr (pchPatchExes, achTmpImageName);
|
|
if (pchEntry) {
|
|
if (*(pchEntry-1) == ';') {
|
|
pchEntry = NULL;
|
|
} else if ( Peb->ImageBaseAddress == ImageBase )
|
|
fTuneApp = TRUE;
|
|
}
|
|
|
|
if ( strcmp (achTmpImageName, WSTDLL) && (pchEntry || fTuneApp) ) {
|
|
if ( !fPatchImage )
|
|
fPatchImage = TRUE;
|
|
//
|
|
// Locate the code range.
|
|
//
|
|
pImg->pszName = Wststrdup (ImageName);
|
|
pImg->ulCodeStart = 0L;
|
|
pImg->ulCodeEnd = 0L;
|
|
pImg->iSymCnt = 0;
|
|
|
|
#ifndef _WIN64
|
|
pImageDbgInfo = MapDebugInformation (0L,
|
|
ImageName,
|
|
lpSymbolSearchPath,
|
|
(DWORD)ImageBase);
|
|
|
|
if (pImageDbgInfo == NULL) {
|
|
IdPrint (("WST: WstDllInitializations() - "
|
|
"No symbols for %s\n", ImageName));
|
|
} else if ( pImageDbgInfo->CoffSymbols == NULL ) {
|
|
IdPrint (("WST: WstDllInitializations() - "
|
|
"No coff symbols for %s\n", ImageName));
|
|
} else {
|
|
PIMAGE_COFF_SYMBOLS_HEADER DebugInfo;
|
|
|
|
DebugInfo = pImageDbgInfo->CoffSymbols;
|
|
if (DebugInfo->LvaToFirstSymbol == 0L) {
|
|
IdPrint (("WST: WstDllInitializations() - "
|
|
"Virtual Address to coff symbols not set for %s\n",
|
|
ImageName));
|
|
} else {
|
|
CodeLength = (DebugInfo->RvaToLastByteOfCode -
|
|
DebugInfo->RvaToFirstByteOfCode) - 1;
|
|
pImg->ulCodeStart = (ULONG)ImageBase +
|
|
DebugInfo->RvaToFirstByteOfCode;
|
|
pImg->ulCodeEnd = pImg->ulCodeStart + CodeLength;
|
|
IdPrint(( "WST: WstDllInitializations() - %ul total symbols\n", DebugInfo->NumberOfSymbols ));
|
|
WstGetSymbols (pImg, ImageName, ImageBase, CodeLength,
|
|
DebugInfo);
|
|
}
|
|
// mdg 98/3
|
|
// Must release debug information - should not stay around cluttering up memory!
|
|
if (!UnmapDebugInformation( pImageDbgInfo ))
|
|
KdPrint(("WST: WstDllInitializations() - failure in UnmapDebugInformation()\n"));
|
|
pImageDbgInfo = NULL;
|
|
} // if pImageDbgInfo->CoffSymbols != NULL
|
|
#endif // _WIN64
|
|
|
|
IdPrint (("WST: WstDllInitializations() - @ 0x%08lx "
|
|
"image #%d = %s; %d symbols extracted\n", (ULONG)ImageBase, iImgCnt,
|
|
ImageName, pImg->iSymCnt));
|
|
pImg->pWsp[pImg->iSymCnt].pszSymbol = UNKNOWN_SYM;
|
|
pImg->pWsp[pImg->iSymCnt].ulFuncAddr = UNKNOWN_ADDR;
|
|
pImg->pWsp[pImg->iSymCnt].ulBitString = 0; // mdg 98/3
|
|
pImg->pWsp[pImg->iSymCnt].ulCodeLength = 0; // mdg 98/3
|
|
(pImg->iSymCnt)++;
|
|
|
|
//
|
|
// Set wsi.
|
|
//
|
|
pImg->pulWsi = pImg->pulWsiNxt = (PULONG)
|
|
(pImg->pWsp + pImg->iSymCnt);
|
|
RtlZeroMemory (pImg->pulWsi,
|
|
pImg->iSymCnt * ulMaxSnapULONGs * sizeof(ULONG));
|
|
|
|
|
|
//
|
|
// Set wsp.
|
|
//
|
|
pImg->pulWsp = (PULONG)(pImg->pulWsi +
|
|
(pImg->iSymCnt * ulMaxSnapULONGs));
|
|
RtlZeroMemory (pImg->pulWsp,
|
|
pImg->iSymCnt * ulMaxSnapULONGs * sizeof(ULONG));
|
|
|
|
//
|
|
// Sort wsp & set code lengths
|
|
//
|
|
WstSort (pImg->pWsp, 0, pImg->iSymCnt-1);
|
|
//
|
|
// Last symbol length is set to be the same as length of
|
|
// (n-1)th symbol or remaining code length of module
|
|
//
|
|
i = pImg->iSymCnt - 1; // mdg 98/3 (assert pImg->iSymCnt is at least 1)
|
|
if (i--) { // Test count & set index to top symbol
|
|
pImg->pWsp[i].ulCodeLength = (ULONG)(
|
|
i ? pImg->pWsp[i].ulFuncAddr - pImg->pWsp[i - 1].ulFuncAddr
|
|
: pImg->ulCodeEnd + 1 - pImg->pWsp[i].ulFuncAddr);
|
|
|
|
while (i-- > 0) { // Enumerate symbols & set index
|
|
pImg->pWsp[i].ulCodeLength = (ULONG)(pImg->pWsp[i+1].ulFuncAddr -
|
|
pImg->pWsp[i].ulFuncAddr);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Setup next pWsp
|
|
//
|
|
(pImg+1)->pWsp = (PWSP)(pImg->pulWsp +
|
|
(pImg->iSymCnt * ulMaxSnapULONGs));
|
|
iImgCnt++;
|
|
pImg++;
|
|
|
|
if (iImgCnt == MAX_IMAGES) {
|
|
KdPrint(("WST: WstDllInitialization() - Not enough "
|
|
"space allocated for all images\n"));
|
|
return (FALSE);
|
|
}
|
|
}
|
|
|
|
} // if (Next != &Peb->Ldr->InMemoryOrderModuleList)
|
|
} // try
|
|
//
|
|
// + : transfer control to the handler (EXCEPTION_EXECUTE_HANDLER)
|
|
// 0 : continue search (EXCEPTION_CONTINUE_SEARCH)
|
|
// - : dismiss exception & continue (EXCEPTION_CONTINUE_EXECUTION)
|
|
//
|
|
except ( WstAccessXcptFilter (GetExceptionCode(), GetExceptionInformation()) )
|
|
{
|
|
//
|
|
// Should never get here since filter never returns
|
|
// EXCEPTION_EXECUTE_HANDLER.
|
|
//
|
|
KdPrint (("WST: WstDllInitializations() - *LOGIC ERROR* - "
|
|
"Inside the EXCEPT: (xcpt=0x%lx)\n", GetExceptionCode()));
|
|
}
|
|
/*
|
|
***
|
|
*/
|
|
|
|
//
|
|
// Get the frequency
|
|
//
|
|
NtQueryPerformanceCounter (&liStart, &liFreq);
|
|
|
|
if (strlen(pchTimeInterval) > (sizeof(TIMEINTERVALIST)+1)) // mdg 98/3
|
|
iTimeInterval = atoi (pchTimeInterval+sizeof(TIMEINTERVALIST)+1);
|
|
if ( iTimeInterval == 0 ) {
|
|
//
|
|
// Use the default value
|
|
//
|
|
iTimeInterval = TIMESEG;
|
|
}
|
|
ulSegSize = iTimeInterval * (liFreq.LowPart / 1000);
|
|
|
|
#ifdef BATCHING
|
|
fBatch = WstOpenBatchFile();
|
|
#endif
|
|
|
|
SdPrint (("WST: Time interval: Millisecs=%d Ticks=%lu\n",
|
|
iTimeInterval, ulSegSize));
|
|
|
|
if (fPatchImage) {
|
|
|
|
// Initialization for DONE event creation
|
|
//
|
|
RtlInitString (&ObjName, DONEEVENTNAME);
|
|
Status = RtlAnsiStringToUnicodeString (&UnicodeName, &ObjName, TRUE);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDllInitializations() - "
|
|
"RtlAnsiStringToUnicodeString failed - 0x%lx\n", Status));
|
|
return (FALSE);
|
|
}
|
|
|
|
InitializeObjectAttributes (&ObjAttributes,
|
|
&UnicodeName,
|
|
OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
&SecDescriptor);
|
|
// Create DONE event
|
|
//
|
|
Status = NtCreateEvent (&hDoneEvent,
|
|
EVENT_QUERY_STATE |
|
|
EVENT_MODIFY_STATE |
|
|
SYNCHRONIZE,
|
|
&ObjAttributes,
|
|
NotificationEvent,
|
|
TRUE);
|
|
RtlFreeUnicodeString (&UnicodeName); // HWC 11/93
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDllInitializations() - "
|
|
"DONE event creation failed - 0x%lx\n", Status)); // mdg 98/3
|
|
return (FALSE);
|
|
}
|
|
|
|
|
|
// Initialization for DUMP event creation
|
|
//
|
|
RtlInitString (&ObjName, DUMPEVENTNAME);
|
|
Status = RtlAnsiStringToUnicodeString (&UnicodeName, &ObjName, TRUE);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDllInitializations() - "
|
|
"RtlAnsiStringToUnicodeString failed - 0x%lx\n", Status));
|
|
return (FALSE);
|
|
}
|
|
|
|
InitializeObjectAttributes (&ObjAttributes,
|
|
&UnicodeName,
|
|
OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
&SecDescriptor);
|
|
// Create DUMP event
|
|
//
|
|
Status = NtCreateEvent (&hDumpEvent,
|
|
EVENT_QUERY_STATE |
|
|
EVENT_MODIFY_STATE |
|
|
SYNCHRONIZE,
|
|
&ObjAttributes,
|
|
NotificationEvent,
|
|
FALSE);
|
|
RtlFreeUnicodeString (&UnicodeName); // HWC 11/93
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDllInitializations() - "
|
|
"DUMP event creation failed - 0x%lx\n", Status)); // mdg 98/3
|
|
return (FALSE);
|
|
}
|
|
|
|
|
|
// Initialization for CLEAR event creation
|
|
//
|
|
RtlInitString (&ObjName, CLEAREVENTNAME);
|
|
Status = RtlAnsiStringToUnicodeString (&UnicodeName, &ObjName, TRUE);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDllInitializations() - "
|
|
"RtlAnsiStringToUnicodeString failed - 0x%lx\n", Status));
|
|
return (FALSE);
|
|
}
|
|
|
|
InitializeObjectAttributes (&ObjAttributes,
|
|
&UnicodeName,
|
|
OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
&SecDescriptor);
|
|
|
|
// Create CLEAR event
|
|
//
|
|
Status = NtCreateEvent (&hClearEvent,
|
|
EVENT_QUERY_STATE |
|
|
EVENT_MODIFY_STATE |
|
|
SYNCHRONIZE,
|
|
&ObjAttributes,
|
|
NotificationEvent,
|
|
FALSE);
|
|
RtlFreeUnicodeString (&UnicodeName); // HWC 11/93
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDllInitializations() - "
|
|
"CLEAR event creation failed - 0x%lx\n", Status)); // mdg 98/3
|
|
return (FALSE);
|
|
}
|
|
|
|
|
|
// Initialization for PAUSE event creation
|
|
//
|
|
RtlInitString (&ObjName, PAUSEEVENTNAME);
|
|
Status = RtlAnsiStringToUnicodeString (&UnicodeName, &ObjName, TRUE);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDllInitializations() - "
|
|
"RtlAnsiStringToUnicodeString failed - 0x%lx\n", Status));
|
|
return (FALSE);
|
|
}
|
|
|
|
InitializeObjectAttributes (&ObjAttributes,
|
|
&UnicodeName,
|
|
OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
&SecDescriptor);
|
|
// Create PAUSE event
|
|
//
|
|
Status = NtCreateEvent (&hPauseEvent,
|
|
EVENT_QUERY_STATE |
|
|
EVENT_MODIFY_STATE |
|
|
SYNCHRONIZE,
|
|
&ObjAttributes,
|
|
NotificationEvent,
|
|
FALSE);
|
|
RtlFreeUnicodeString (&UnicodeName); // HWC 11/93
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDllInitializations() - "
|
|
"PAUSE event creation failed - 0x%lx\n", Status)); // mdg 98/3
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// Calculate excess overhead for WstRecordInfo
|
|
//
|
|
liOverhead.HighPart = 0L;
|
|
liOverhead.LowPart = 0xFFFFFFFF;
|
|
for (i=0; i < NUM_ITERATIONS; i++) {
|
|
NtQueryPerformanceCounter (&liStartTicks, NULL);
|
|
//
|
|
WSTUSAGE(NtCurrentTeb()) = 0L;
|
|
|
|
#ifdef i386
|
|
_asm
|
|
{
|
|
push edi
|
|
mov edi, dword ptr [ebp+4]
|
|
mov dwAddr, edi
|
|
mov edi, dword ptr [ebp+8]
|
|
mov dwPrevAddr, edi
|
|
pop edi
|
|
}
|
|
#endif
|
|
|
|
#if defined(ALPHA) || defined(IA64)
|
|
{
|
|
PULONG pulAddr;
|
|
DWORDLONG SaveRegisters [REG_BUFFER_SIZE] ;
|
|
|
|
SaveAllRegs (SaveRegisters);
|
|
|
|
pulAddr = (PULONG) dwAddr;
|
|
pulAddr -= 1;
|
|
|
|
RestoreAllRegs (SaveRegisters);
|
|
}
|
|
#elif defined(_X86_)
|
|
SaveAllRegs ();
|
|
RestoreAllRegs ();
|
|
#endif
|
|
WSTUSAGE(NtCurrentTeb()) = 0L;
|
|
Status = NtWaitForSingleObject (hLocalSem, FALSE, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDllInitilizations() - "
|
|
"Wait for LOCAL semaphore failed - 0x%lx\n", Status));
|
|
}
|
|
liStart.QuadPart = liStart.QuadPart - liStart.QuadPart ;
|
|
liStart.QuadPart = liStart.QuadPart + liStart.QuadPart ;
|
|
liStart.QuadPart = liStart.QuadPart + liStart.QuadPart ;
|
|
|
|
Status = NtReleaseSemaphore (hLocalSem, 1, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDllInitializations() - "
|
|
"Error releasing LOCAL semaphore - 0x%lx\n", Status));
|
|
}
|
|
WSTUSAGE(NtCurrentTeb()) = 0L;
|
|
//
|
|
NtQueryPerformanceCounter (&liEndTicks, NULL);
|
|
ulElapsed = liEndTicks.LowPart - liStartTicks.LowPart;
|
|
if (ulElapsed < liOverhead.LowPart) {
|
|
liOverhead.LowPart = ulElapsed;
|
|
}
|
|
}
|
|
SdPrint (("WST: WstDllInitializations() - WstRecordInfo() overhead = %lu\n",
|
|
liOverhead.LowPart));
|
|
|
|
// Start monitor threads
|
|
//
|
|
hDumpThread = CreateThread (
|
|
NULL, // no security attribute
|
|
(DWORD)1024L, // initial stack size
|
|
(LPTHREAD_START_ROUTINE)WstDumpThread, // thread starting address
|
|
NULL, // no argument for the thread
|
|
(DWORD)0, // no creation flag
|
|
&DumpClientId); // address for thread id
|
|
hClearThread = CreateThread (
|
|
NULL, // no security attribute
|
|
(DWORD)1024L, // initial stack size
|
|
(LPTHREAD_START_ROUTINE)WstClearThread, // thread starting address
|
|
NULL, // no argument for the thread
|
|
(DWORD)0, // no creation flag
|
|
&ClearClientId); // address for thread id
|
|
hPauseThread = CreateThread (
|
|
NULL, // no security attribute
|
|
(DWORD)1024L, // initial stack size
|
|
(LPTHREAD_START_ROUTINE)WstPauseThread, // thread starting address
|
|
NULL, // no argument for the thread
|
|
(DWORD)0, // no creation flag
|
|
&PauseClientId); // address for thread id
|
|
|
|
NtQueryPerformanceCounter (&liStart, NULL);
|
|
WstState = STARTED;
|
|
}
|
|
|
|
return (TRUE);
|
|
|
|
} /* WstDllInitializations () */
|
|
|
|
|
|
|
|
|
|
|
|
/****************************** _ p e n t e r ******************************
|
|
*
|
|
* _penter() / _mcount() -
|
|
* This is the main profiling routine. This routine is called
|
|
* upon entry of each routine in the profiling DLL/EXE.
|
|
*
|
|
* ENTRY -none-
|
|
*
|
|
* EXIT -none-
|
|
*
|
|
* RETURN -none-
|
|
*
|
|
* WARNING:
|
|
* -none-
|
|
*
|
|
* COMMENT:
|
|
* Compiling apps with -Gp option trashs EAX initially.
|
|
*
|
|
*/
|
|
#ifdef i386
|
|
void __cdecl _penter ()
|
|
#elif defined(ALPHA) || defined(IA64) || defined(_AMD64_)
|
|
void c_penter (ULONG_PTR dwPrevious, ULONG_PTR dwCurrent)
|
|
#endif
|
|
{
|
|
DWORD_PTR dwAddr;
|
|
DWORD_PTR dwPrevAddr;
|
|
ULONG_PTR ulInWst ;
|
|
#if defined(ALPHA) || defined(_AXP64_) || defined(IA64)
|
|
PULONG pulAddr;
|
|
DWORDLONG SaveRegisters [REG_BUFFER_SIZE];
|
|
SaveAllRegs(SaveRegisters) ;
|
|
#endif
|
|
|
|
dwAddr = 0L;
|
|
dwPrevAddr = 0L;
|
|
ulInWst = WSTUSAGE(NtCurrentTeb());
|
|
|
|
if (WstState != STARTED) {
|
|
goto Exit0;
|
|
} else if (ulInWst) {
|
|
goto Exit0;
|
|
}
|
|
|
|
|
|
//
|
|
// Put the address of the calling function into var dwAddr
|
|
//
|
|
#ifdef i386
|
|
_asm
|
|
{
|
|
push edi
|
|
mov edi, dword ptr [ebp+4]
|
|
mov dwAddr, edi
|
|
mov edi, dword ptr [ebp+8]
|
|
mov dwPrevAddr, edi
|
|
pop edi
|
|
}
|
|
#endif
|
|
|
|
#if defined(ALPHA) || defined(IA64)
|
|
dwPrevAddr = NO_CALLER;
|
|
dwAddr = dwCurrent;
|
|
// GetCaller (&dwAddr, 0x0220); // FIXFIX StackSize
|
|
|
|
// now check if we are calling from the stub we created
|
|
pulAddr = (PULONG) dwAddr;
|
|
pulAddr -= 1;
|
|
|
|
if (*(pulAddr) == 0x681b4000 &&
|
|
(*(pulAddr + 1) == 0xa75e0008) &&
|
|
(*(pulAddr + 8) == 0xfefe55aa) ) {
|
|
|
|
// get the address that we will go after the penter function
|
|
dwAddr = *(pulAddr + 4) & 0x0000ffff;
|
|
if (*(pulAddr + 5) & 0x00008000) {
|
|
// fix the address since we have to add one when
|
|
// we created our stub code
|
|
dwAddr -= 1;
|
|
}
|
|
dwAddr = dwAddr << 16;
|
|
dwAddr |= *(pulAddr + 5) & 0x0000ffff;
|
|
|
|
// get the caller to the stub
|
|
dwPrevAddr = dwPrevious;
|
|
// GetStubCaller (&dwPrevAddr, 0x0220); // FIXFIX StackSize
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
//
|
|
// Call WstRecordInfo for this API
|
|
//
|
|
#ifdef i386
|
|
SaveAllRegs ();
|
|
#endif
|
|
|
|
WstRecordInfo (dwAddr, dwPrevAddr);
|
|
|
|
#ifdef i386
|
|
RestoreAllRegs ();
|
|
#endif
|
|
|
|
|
|
Exit0:
|
|
|
|
#if defined(ALPHA) || defined(IA64)
|
|
RestoreAllRegs (SaveRegisters);
|
|
#endif
|
|
|
|
return;
|
|
} /* _penter() / _mcount()*/
|
|
|
|
void __cdecl _mcount ()
|
|
{
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/************************* W s t R e c o r d I n f o ************************
|
|
*
|
|
* WstRecordInfo (dwAddress) -
|
|
*
|
|
* ENTRY dwAddress - Address of the routine just called
|
|
*
|
|
* EXIT -none-
|
|
*
|
|
* RETURN -none-
|
|
*
|
|
* WARNING:
|
|
* -none-
|
|
*
|
|
* COMMENT:
|
|
* -none-
|
|
*
|
|
*/
|
|
|
|
void WstRecordInfo (DWORD_PTR dwAddress, DWORD_PTR dwPrevAddress)
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
INT x;
|
|
INT i, iIndex;
|
|
PWSP pwspTmp;
|
|
LARGE_INTEGER liNow, liTmp;
|
|
LARGE_INTEGER liElapsed;
|
|
CHAR *pszSym;
|
|
|
|
#ifdef BATCHING
|
|
CHAR szBatchBuf[128];
|
|
DWORD dwCache;
|
|
DWORD dwHits;
|
|
DWORD dwBatch;
|
|
IO_STATUS_BLOCK ioStatus;
|
|
#endif
|
|
|
|
|
|
WSTUSAGE(NtCurrentTeb()) = 1;
|
|
|
|
//
|
|
// Wait for the semaphore object to suspend execution of other threads
|
|
//
|
|
Status = NtWaitForSingleObject (hLocalSem, FALSE, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstRecordInfo() - "
|
|
"Wait for LOCAL semaphore failed - 0x%lx\n", Status));
|
|
}
|
|
|
|
NtQueryPerformanceCounter(&liNow, NULL);
|
|
liElapsed.QuadPart = liNow.QuadPart - liStart.QuadPart ;
|
|
|
|
|
|
// SdPrint(("WST: WstRecordInfo() - Elapsed time: %ld\n", liElapsed.LowPart));
|
|
|
|
//
|
|
// WstBSearch is a binary find function that will return the address of
|
|
// the wsp record we want
|
|
//
|
|
|
|
// SdPrint(("WST: WstRecordInfo() - Preparing for WstBSearch of 0x%lx\n",
|
|
// dwAddress-5));
|
|
|
|
pwspTmp = NULL;
|
|
for (i=0; i<iImgCnt; i++) {
|
|
if ( (dwAddress >= aImg[i].ulCodeStart) &&
|
|
(dwAddress < aImg[i].ulCodeEnd) ) {
|
|
#ifdef i386
|
|
pwspTmp = WstBSearch(dwAddress-5, aImg[i].pWsp, aImg[i].iSymCnt);
|
|
if (!pwspTmp) {
|
|
pwspTmp = WstBSearch(UNKNOWN_ADDR, aImg[i].pWsp, aImg[i].iSymCnt);
|
|
}
|
|
#else
|
|
// the following works for both MIPS and ALPHA
|
|
|
|
pwspTmp = WstBSearch(dwAddress, aImg[i].pWsp, aImg[i].iSymCnt);
|
|
if (!pwspTmp) {
|
|
// symbol not found
|
|
pwspTmp = WstBSearch(UNKNOWN_ADDR, aImg[i].pWsp, aImg[i].iSymCnt);
|
|
}
|
|
#endif
|
|
break;
|
|
}
|
|
}
|
|
iIndex = i;
|
|
|
|
if (pwspTmp) {
|
|
pszSym = pwspTmp->pszSymbol;
|
|
pwspTmp->ulBitString |= 1;
|
|
} else {
|
|
SdPrint (("WST: WstRecordInfo() - LOGIC ERROR - Completely bogus addr = 0x%08lx\n",
|
|
dwAddress)); // We could also get here if moduled compiled with -Gh but no COFF symbols available
|
|
}
|
|
|
|
if (liElapsed.LowPart >= ulSegSize) {
|
|
SdPrint(("WST: WstRecordInfo() - ulSegSize expired; "
|
|
"Preparing to shift the BitStrings\n"));
|
|
|
|
if (ulBitCount < 31) {
|
|
for (i=0; i<iImgCnt; i++) {
|
|
for (x=0; x < aImg[i].iSymCnt ; x++ ) {
|
|
aImg[i].pWsp[x].ulBitString <<= 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
liElapsed.LowPart = 0L;
|
|
ulBitCount++;
|
|
NtQueryPerformanceCounter(&liStart, NULL);
|
|
liNow = liStart;
|
|
|
|
if (ulBitCount == 32) {
|
|
SdPrint(("WST: WstRecordInfo() - Dump Bit Strings\n"));
|
|
for (i=0; i<iImgCnt; i++) {
|
|
for (x=0; x < aImg[i].iSymCnt ; x++ ) {
|
|
aImg[i].pulWsiNxt[x] = aImg[i].pWsp[x].ulBitString;
|
|
aImg[i].pWsp[x].ulBitString = 0L;
|
|
}
|
|
aImg[i].pulWsiNxt += aImg[i].iSymCnt;
|
|
}
|
|
ulSnaps++;
|
|
ulBitCount = 0;
|
|
if (ulSnaps == ulMaxSnapULONGs) {
|
|
KdPrint (("WST: WstRecordInfo() - No more space available"
|
|
" for next time snap data!\n"));
|
|
//
|
|
// Dump and clear the data
|
|
//
|
|
WstDataOverFlow();
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef BATCHING
|
|
//
|
|
// The following code will get the current batching information
|
|
// if the DLL was compiled with the BATCHING variable set. You
|
|
// should not have this variable set if you are tuning GDI.
|
|
//
|
|
if (fBatch) {
|
|
GdiGetCsInfo(&dwHits, &dwBatch, &dwCache);
|
|
|
|
if (dwHits)
|
|
GdiResetCsInfo();
|
|
|
|
if (dwBatch == 10)
|
|
GdiResetCsInfo();
|
|
|
|
while (*(pszSym++) != '_');
|
|
|
|
sprintf(szBatchBuf, "%s:%s,%ld,%ld,%ld\n",
|
|
aImg[iIndex].pszName, pszSym, dwHits, dwBatch, dwCache);
|
|
Status = NtWriteFile(hBatchFile,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&ioStatus,
|
|
szBatchBuf,
|
|
strlen(szBatchBuf),
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstRecodInfo() - "
|
|
"NtWriteFile() failed on hBatchFile - 0x%lx\n", Status));
|
|
}
|
|
}//Batching info
|
|
#endif
|
|
|
|
|
|
//
|
|
// We call NtQueryPerformanceCounter here to account for the overhead
|
|
// required for doing our work
|
|
//
|
|
NtQueryPerformanceCounter(&liTmp, NULL);
|
|
liElapsed.QuadPart = liTmp.QuadPart - liNow.QuadPart ;
|
|
liStart.QuadPart = liStart.QuadPart + liElapsed.QuadPart ;
|
|
liStart.QuadPart = liStart.QuadPart + liOverhead.QuadPart ;
|
|
|
|
//
|
|
// Release semaphore to continue execution of other threads
|
|
//
|
|
Status = NtReleaseSemaphore (hLocalSem, 1, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstRecordInfo () - "
|
|
"Error releasing LOCAL semaphore - 0x%lx\n", Status));
|
|
}
|
|
|
|
WSTUSAGE(NtCurrentTeb()) = 0L;
|
|
|
|
} /* WstRecordInfo () */
|
|
|
|
|
|
|
|
|
|
|
|
/******************** W s t C l e a r B i t S t r i n g *********************
|
|
*
|
|
* Function: WstClearBitStrings (pImg)
|
|
*
|
|
* Purpose: This function clears the BitString for each symbol.
|
|
*
|
|
* Parameters: pImg - Current image data structure pointer
|
|
*
|
|
* Returns: -none-
|
|
*
|
|
* History: 8-3-92 Marklea - created
|
|
*
|
|
*/
|
|
|
|
void WstClearBitStrings (PIMG pImg)
|
|
{
|
|
UINT uiLshft = 0;
|
|
INT x;
|
|
|
|
|
|
//
|
|
// Since we are completed with the profile, we need to create a
|
|
// DWORD out of the balance of the bitString. We do this by left
|
|
// shifting the bitstring by difference between the bitCount and
|
|
// 32.
|
|
//
|
|
if (ulBitCount < 32) {
|
|
uiLshft =(UINT)(31 - ulBitCount);
|
|
for (x=0; x < pImg->iSymCnt; x++) {
|
|
pImg->pWsp[x].ulBitString <<= uiLshft;
|
|
pImg->pulWsiNxt[x] = pImg->pWsp[x].ulBitString;
|
|
}
|
|
pImg->pulWsiNxt += pImg->iSymCnt;
|
|
}
|
|
|
|
|
|
} /* WstClearBitStrings () */
|
|
|
|
|
|
|
|
|
|
|
|
/*********************** W s t I n i t W s p F i l e ***********************
|
|
*
|
|
* Function: WstInitWspFile (pImg)
|
|
*
|
|
* Purpose: This function will create a WSP file and dump the header
|
|
* information for the file.
|
|
*
|
|
* Parameters: pImg - Current image data structure pointer
|
|
*
|
|
* Returns: Handle to the WSP file.
|
|
*
|
|
* History: 8-3-92 Marklea - created
|
|
*
|
|
*/
|
|
|
|
HANDLE WstInitWspFile (PIMG pImg)
|
|
{
|
|
CHAR szOutFile [256] = WSTROOT;
|
|
CHAR szModName [128] = {0};
|
|
PCHAR pDot;
|
|
CHAR szExt [5] = "WSP";
|
|
WSPHDR wsphdr;
|
|
DWORD dwBytesWritten;
|
|
BOOL fRet;
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
int iExt = 0;
|
|
|
|
//
|
|
// Prepare the filename path
|
|
//
|
|
strcat (szOutFile, pImg->pszName);
|
|
|
|
//
|
|
// Open the file for binary output.
|
|
//
|
|
pImg->fDumpAll = TRUE;
|
|
while (iExt < 256) {
|
|
strcpy ((strchr(szOutFile,'.'))+1, szExt);
|
|
hFile = CreateFile ( szOutFile, // WSP file handle
|
|
GENERIC_WRITE |
|
|
GENERIC_READ, // Desired access
|
|
0L, // Read share access
|
|
NULL, // No EaBuffer
|
|
CREATE_NEW,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
0); // EaBuffer length
|
|
if (hFile != INVALID_HANDLE_VALUE) {
|
|
IdPrint(("WST: WstInitWspFile() - WSP file name: %s\n",
|
|
szOutFile));
|
|
if (iExt != 0) {
|
|
pImg->fDumpAll = FALSE;
|
|
}
|
|
break;
|
|
}
|
|
iExt++;
|
|
sprintf (szExt, "W%02x", iExt);
|
|
}
|
|
if (iExt == 256) {
|
|
KdPrint (("WST: WstInitWspFile() - "
|
|
"Error creating %s - 0x%lx\n", szOutFile,
|
|
GetLastError()));
|
|
return (hFile);
|
|
}
|
|
|
|
//
|
|
// Fill a WSP header structure
|
|
//
|
|
|
|
strcpy(szModName, pImg->pszName);
|
|
pDot = strchr(szModName, '.');
|
|
if (pDot)
|
|
strcpy(pDot, "");
|
|
|
|
strcpy(wsphdr.chFileSignature, "WSP");
|
|
wsphdr.ulTimeStamp = 0L;
|
|
wsphdr.usId = 0;
|
|
wsphdr.ulApiCount = 0;
|
|
wsphdr.ulSetSymbols = pImg->ulSetSymbols;
|
|
wsphdr.ulModNameLen = strlen(szModName);
|
|
wsphdr.ulSegSize = (ULONG)iTimeInterval;
|
|
wsphdr.ulOffset = wsphdr.ulModNameLen + (ULONG)sizeof(WSPHDR);
|
|
wsphdr.ulSnaps = ulSnaps;
|
|
|
|
//
|
|
// Write header and module name
|
|
//
|
|
fRet = WriteFile(hFile, // Wsp file handle
|
|
(PVOID)&wsphdr, // Buffer of data
|
|
(ULONG)sizeof(WSPHDR), // Bytes to write
|
|
&dwBytesWritten, // Bytes written
|
|
NULL);
|
|
|
|
if (!fRet) {
|
|
KdPrint (("WST: WstInitWspFile() - "
|
|
"Error writing to %s - 0x%lx\n", szOutFile,
|
|
GetLastError));
|
|
return (NULL);
|
|
}
|
|
|
|
fRet = WriteFile (hFile, // Wsp file handle
|
|
(PVOID)szModName, // Buffer of data
|
|
(ULONG)strlen(szModName), // Bytes to write
|
|
&dwBytesWritten,
|
|
NULL);
|
|
if (!fRet) {
|
|
KdPrint (("WST: WstInitWspFile() - "
|
|
"Error writing to %s - 0x%lx\n", szOutFile,
|
|
GetLastError()));
|
|
return (NULL);
|
|
}
|
|
|
|
return (hFile);
|
|
|
|
} /* WstInitWspFile () */
|
|
|
|
|
|
|
|
|
|
|
|
/************************** W s t D u m p D a t a **************************
|
|
*
|
|
* Function: WstDumpData (pImg)
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Parameters: pImg - Current image data structure pointer
|
|
*
|
|
* Returns: NONE
|
|
*
|
|
* History: 8-3-92 Marklea - created
|
|
*
|
|
*/
|
|
|
|
void WstDumpData (PIMG pImg)
|
|
{
|
|
INT x = 0;
|
|
DWORD dwBytesWritten;
|
|
BOOL fRet;
|
|
HANDLE hWspFile;
|
|
|
|
|
|
if ( !(hWspFile = WstInitWspFile(pImg)) ) {
|
|
KdPrint (("WST: WstDumpData() - Error creating WSP file.\n"));
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Write all the symbols with any bits set
|
|
//
|
|
for (x=0; x<pImg->iSymCnt; x++) {
|
|
if (pImg->pWsp[x].ulBitString) {
|
|
fRet = WriteFile(
|
|
hWspFile, // Wsp file handle
|
|
(PVOID)(pImg->pulWsp+(x*ulSnaps)), // Buffer of data
|
|
ulSnaps * sizeof(ULONG), // Bytes to write
|
|
&dwBytesWritten, // Bytes written
|
|
NULL); // Optional
|
|
if (!fRet) {
|
|
KdPrint (("WST: WstDumpData() - "
|
|
"Error writing to WSP file - 0x%lx\n",
|
|
GetLastError()));
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// Now write all the symbols with no bits set
|
|
//
|
|
if (pImg->fDumpAll) {
|
|
for (x=0; x<pImg->iSymCnt; x++) {
|
|
if (pImg->pWsp[x].ulBitString == 0L) {
|
|
fRet = WriteFile(
|
|
hWspFile, // Wsp file handle
|
|
(PVOID)(pImg->pulWsp+(x*ulSnaps)), // Buffer of data
|
|
ulSnaps * sizeof(ULONG), // Bytes to write
|
|
&dwBytesWritten, // Bytes written
|
|
NULL); // Optional
|
|
if (!fRet) {
|
|
KdPrint (("WST: WstDumpData() - "
|
|
"Error writing to WSP file - 0x%lx\n",
|
|
GetLastError()));
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fRet = CloseHandle(hWspFile);
|
|
if (!fRet) {
|
|
KdPrint (("WST: WstDumpData() - "
|
|
"Error closing %s - 0x%lx\n", "WSI file",
|
|
GetLastError()));
|
|
return;
|
|
}
|
|
|
|
} /* WstDumpData () */
|
|
|
|
|
|
|
|
|
|
|
|
/************************ W s t W r i t e T m i F i l e **********************
|
|
*
|
|
* Function: WstWriteTmiFile (pImg)
|
|
*
|
|
* Purpose: Write all the symbole info for the current image to its TMI
|
|
* file.
|
|
*
|
|
*
|
|
* Parameters: pImg - Current image data structure pointer
|
|
*
|
|
* Returns: -none-
|
|
*
|
|
* History: 8-5-92 Marklea - created
|
|
*
|
|
*/
|
|
|
|
void WstWriteTmiFile (PIMG pImg)
|
|
{
|
|
CHAR szOutFile [256] = WSTROOT;
|
|
CHAR szBuffer [256];
|
|
CHAR szExt [5] = "TMI";
|
|
HANDLE hTmiFile;
|
|
INT x;
|
|
DWORD dwBytesWritten;
|
|
BOOL fRet;
|
|
int iExt = 0;
|
|
PSZ pszSymbol;
|
|
ULONG nSymbolLen;
|
|
|
|
|
|
//
|
|
// Prepare the filename path
|
|
//
|
|
strcat (szOutFile, pImg->pszName);
|
|
|
|
//
|
|
// Open the file for binary output.
|
|
//
|
|
pImg->fDumpAll = TRUE;
|
|
KdPrint (("WST: WstWriteTmiFile() - creating TMI for %s\n", szOutFile));
|
|
while (iExt < 256) {
|
|
strcpy ((strchr(szOutFile,'.'))+1, szExt);
|
|
hTmiFile = CreateFile ( szOutFile, // TMI file handle
|
|
GENERIC_WRITE |
|
|
GENERIC_READ, // Desired access
|
|
0L, // Read share access
|
|
NULL, // No EaBuffer
|
|
CREATE_NEW,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
0); // EaBuffer length
|
|
if (hTmiFile != INVALID_HANDLE_VALUE) {
|
|
IdPrint(("WST: WstWriteTmiFile() - TMI file name: %s\n",
|
|
szOutFile));
|
|
if (iExt != 0) {
|
|
pImg->fDumpAll = FALSE;
|
|
}
|
|
break;
|
|
}
|
|
iExt++;
|
|
sprintf (szExt, "T%02x", iExt);
|
|
}
|
|
if (iExt == 256) {
|
|
KdPrint (("WST: WstWriteTmiFile() - "
|
|
"Error creating %s - 0x%lx\n", szOutFile,
|
|
GetLastError()));
|
|
return;
|
|
}
|
|
|
|
sprintf(szBuffer, "/* %s for NT */\n"
|
|
"/* Total Symbols= %lu */\n"
|
|
"DO NOT DELETE\n"
|
|
"%d\n"
|
|
"TDFID = 0\n",
|
|
pImg->pszName,
|
|
pImg->fDumpAll ? pImg->iSymCnt : pImg->ulSetSymbols,
|
|
iTimeInterval);
|
|
//
|
|
// Write header
|
|
//
|
|
fRet = WriteFile(hTmiFile, // Tmi file handle
|
|
(PVOID)szBuffer, // Buffer of data
|
|
(ULONG)strlen(szBuffer), // Bytes to write
|
|
&dwBytesWritten, // Bytes written
|
|
NULL);
|
|
|
|
if (!fRet) {
|
|
KdPrint (("WST: WstWriteTmiFile() - "
|
|
"Error writing to %s - 0x%lx\n", szOutFile,
|
|
GetLastError));
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Dump all the symbols with set bits.
|
|
//
|
|
IdPrint (("WST: WstWriteTmiFile() - Dumping set symbols...\n"));
|
|
for (x=0; x<pImg->iSymCnt ; x++) {
|
|
if (pImg->pWsp[x].ulBitString) {
|
|
pszSymbol =
|
|
(pImg->pWsp[x].pszSymbol);
|
|
nSymbolLen = strlen( pszSymbol ); // mdg 98/4
|
|
|
|
sprintf(szBuffer, "%ld 0000:%08lx 0x%lx %lu ", // mdg 98/4
|
|
(LONG)x, pImg->pWsp[x].ulFuncAddr,
|
|
pImg->pWsp[x].ulCodeLength, nSymbolLen);
|
|
//
|
|
// Write symbol line
|
|
//
|
|
fRet = WriteFile(hTmiFile, // Tmi file handle
|
|
(PVOID)szBuffer, // Buffer of data
|
|
(ULONG)strlen(szBuffer), // Bytes to write
|
|
&dwBytesWritten, // Bytes written
|
|
NULL)
|
|
&& WriteFile(hTmiFile, // Tmi file handle
|
|
(PVOID)pszSymbol, // Buffer of data
|
|
nSymbolLen, // Bytes to write
|
|
&dwBytesWritten, // Bytes written
|
|
NULL)
|
|
&& WriteFile(hTmiFile, // Tmi file handle
|
|
(PVOID)"\n", // Buffer of data
|
|
1, // Bytes to write
|
|
&dwBytesWritten, // Bytes written
|
|
NULL);
|
|
|
|
if (!fRet) {
|
|
KdPrint (("WST: WstWriteTmiFile() - "
|
|
"Error writing to %s - 0x%lx\n", szOutFile,
|
|
GetLastError));
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// Now dump all the symbols without any bits set.
|
|
//
|
|
IdPrint (("WST: WstWriteTmiFile() - Dumping unset symbols...\n"));
|
|
if (pImg->fDumpAll) {
|
|
for (x=0; x<pImg->iSymCnt ; x++ ) {
|
|
if (!pImg->pWsp[x].ulBitString) {
|
|
pszSymbol =
|
|
(pImg->pWsp[x].pszSymbol);
|
|
nSymbolLen = strlen( pszSymbol ); // mdg 98/4
|
|
sprintf(szBuffer, "%ld 0000:%08lx 0x%lx %lu ", // mdg 98/4
|
|
(LONG)x, pImg->pWsp[x].ulFuncAddr,
|
|
pImg->pWsp[x].ulCodeLength, nSymbolLen);
|
|
//
|
|
// Write symbol line
|
|
//
|
|
fRet = WriteFile(hTmiFile, // Tmi file handle
|
|
(PVOID)szBuffer, // Buffer of data
|
|
(ULONG)strlen(szBuffer), // Bytes to write
|
|
&dwBytesWritten, // Bytes written
|
|
NULL)
|
|
&& WriteFile(hTmiFile, // Tmi file handle
|
|
(PVOID)pszSymbol, // Buffer of data
|
|
nSymbolLen, // Bytes to write
|
|
&dwBytesWritten, // Bytes written
|
|
NULL)
|
|
&& WriteFile(hTmiFile, // Tmi file handle
|
|
(PVOID)"\n", // Buffer of data
|
|
1, // Bytes to write
|
|
&dwBytesWritten, // Bytes written
|
|
NULL);
|
|
|
|
if (!fRet) {
|
|
KdPrint (("WST: WstWriteTmiFile() - "
|
|
"Error writing to %s - 0x%lx\n", szOutFile,
|
|
GetLastError));
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fRet = CloseHandle(hTmiFile);
|
|
if (!fRet) {
|
|
KdPrint (("WST: WstWriteTmiFile() - "
|
|
"Error closing %s - 0x%lx\n", szOutFile, GetLastError()));
|
|
return;
|
|
}
|
|
|
|
} /* WstWriteTmiFile () */
|
|
|
|
|
|
|
|
|
|
|
|
/*********************** W s t R o t a t e W s i M e m ***********************
|
|
*
|
|
* Function: WstRotateWsiMem (pImg)
|
|
*
|
|
* Purpose:
|
|
*
|
|
*
|
|
* Parameters: pImg - Current image data structure pointer
|
|
*
|
|
* Returns: -none-
|
|
*
|
|
* History: 8-5-92 Marklea - created
|
|
*
|
|
*/
|
|
|
|
void WstRotateWsiMem (PIMG pImg)
|
|
{
|
|
ULONG ulCurSnap;
|
|
ULONG ulOffset;
|
|
int x;
|
|
PULONG pulWsp;
|
|
|
|
|
|
pulWsp = pImg->pulWsp;
|
|
pImg->ulSetSymbols = 0;
|
|
|
|
for (x=0; x<pImg->iSymCnt; x++) {
|
|
ulOffset = 0L;
|
|
ulCurSnap = 0L;
|
|
pImg->pWsp[x].ulBitString = 0L;
|
|
|
|
while (ulCurSnap < ulSnaps) {
|
|
|
|
ulOffset = (ULONG)x + ((ULONG)pImg->iSymCnt * ulCurSnap);
|
|
*pulWsp = *(pImg->pulWsi + ulOffset);
|
|
pImg->pWsp[x].ulBitString |= (*pulWsp);
|
|
pulWsp++;
|
|
ulCurSnap++;
|
|
}
|
|
|
|
if (pImg->pWsp[x].ulBitString) {
|
|
/*
|
|
SdPrint (("WST: WstRotateWsiMem() - set: %s\n",
|
|
pImg->pWsp[x].pszSymbol));
|
|
*/
|
|
(pImg->ulSetSymbols)++;
|
|
}
|
|
}
|
|
|
|
IdPrint (("WST: WstRotateWsiMem() - Number of set symbols = %lu\n",
|
|
pImg->ulSetSymbols));
|
|
|
|
} /* WstRotateWsiMwm () */
|
|
|
|
|
|
|
|
|
|
|
|
/*********************** W s t G e t S y m b o l s *************************
|
|
*
|
|
* WstGetSymbols (pCurWsp, pszImageName, pvImageBase, ulCodeLength, DebugInfo)
|
|
* This routine stores all the symbols for the current
|
|
* image into pCurWsp
|
|
*
|
|
* ENTRY upCurWsp - Pointer to current WSP structure
|
|
* pszImageName - Pointer to image name
|
|
* pvImageBase - Current image base address
|
|
* ulCodeLength - Current image code length
|
|
* DebugInfo - Pointer to the coff debug info structure
|
|
*
|
|
* EXIT -none-
|
|
*
|
|
* RETURN -none-
|
|
*
|
|
* WARNING:
|
|
* -none-
|
|
*
|
|
* COMMENT:
|
|
* -none-
|
|
*
|
|
*/
|
|
#ifndef _WIN64
|
|
|
|
void WstGetSymbols (PIMG pCurImg,
|
|
PSZ pszImageName,
|
|
PVOID pvImageBase,
|
|
ULONG ulCodeLength,
|
|
PIMAGE_COFF_SYMBOLS_HEADER DebugInfo)
|
|
{
|
|
IMAGE_SYMBOL Symbol;
|
|
PIMAGE_SYMBOL SymbolEntry;
|
|
PUCHAR StringTable;
|
|
ULONG i;
|
|
char achTmp[9];
|
|
PWSP pCurWsp;
|
|
PSZ ptchSymName;
|
|
|
|
|
|
pCurWsp = pCurImg->pWsp;
|
|
achTmp[8] = '\0';
|
|
|
|
//
|
|
// Crack the COFF symbol table
|
|
//
|
|
SymbolEntry = (PIMAGE_SYMBOL)
|
|
((ULONG)DebugInfo + DebugInfo->LvaToFirstSymbol);
|
|
StringTable = (PUCHAR)((ULONG)DebugInfo + DebugInfo->LvaToFirstSymbol +
|
|
DebugInfo->NumberOfSymbols * (ULONG)IMAGE_SIZEOF_SYMBOL);
|
|
|
|
//
|
|
// Loop through all symbols in the symbol table.
|
|
//
|
|
for (i = 0; i < DebugInfo->NumberOfSymbols; i++) {
|
|
//
|
|
// Skip thru aux symbols..
|
|
//
|
|
RtlMoveMemory (&Symbol, SymbolEntry, IMAGE_SIZEOF_SYMBOL);
|
|
|
|
if (Symbol.SectionNumber == 1) { //code section
|
|
if (ISFCN( Symbol.Type )) { // mdg 98/3 Also picks up WEAK_EXTERNAL functions
|
|
//
|
|
// This symbol is within the code.
|
|
//
|
|
pCurImg->iSymCnt++;
|
|
pCurWsp->ulBitString = 0L;
|
|
pCurWsp->ulFuncAddr = Symbol.Value + (ULONG)pvImageBase;
|
|
if (Symbol.N.Name.Short) {
|
|
strncpy (achTmp, (PSZ)&(Symbol.N.Name.Short), 8);
|
|
#ifdef i386
|
|
// only need to strip leading underscore for i386.
|
|
// mips and alpha are ok.
|
|
if (achTmp[0] == '_') {
|
|
pCurWsp->pszSymbol = Wststrdup (&achTmp[1]);
|
|
} else {
|
|
pCurWsp->pszSymbol = Wststrdup (achTmp);
|
|
}
|
|
#else
|
|
pCurWsp->pszSymbol = Wststrdup (achTmp);
|
|
#endif
|
|
} else {
|
|
ptchSymName = (PSZ)&StringTable[Symbol.N.Name.Long];
|
|
#ifdef i386
|
|
// only need to strip leading underscore for i386.
|
|
// mips and alpha are ok.
|
|
if (*ptchSymName == '_') {
|
|
ptchSymName++;
|
|
}
|
|
#endif
|
|
|
|
pCurWsp->pszSymbol = Wststrdup (ptchSymName);
|
|
}
|
|
|
|
// IdPrint(( "WST: WstGetSymbols() - 0x%lx = %s\n", pCurWsp->ulFuncAddr, pCurWsp->pszSymbol ));
|
|
|
|
pCurWsp++;
|
|
}
|
|
}
|
|
SymbolEntry = (PIMAGE_SYMBOL)((ULONG)SymbolEntry + IMAGE_SIZEOF_SYMBOL);
|
|
}
|
|
|
|
} /* WstGetSymbols () */
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/*********************** W s t D l l C l e a n u p s ***********************
|
|
*
|
|
* WstDllCleanups () -
|
|
* Dumps the end data, closes all semaphores and events, and
|
|
* closes DUMP, CLEAR & PAUSE thread handles.
|
|
*
|
|
* ENTRY -none-
|
|
*
|
|
* EXIT -none-
|
|
*
|
|
* RETURN -none-
|
|
*
|
|
* WARNING:
|
|
* -none-
|
|
*
|
|
* COMMENT:
|
|
* -none-
|
|
*
|
|
*/
|
|
|
|
void WstDllCleanups ()
|
|
{
|
|
NTSTATUS Status;
|
|
int i;
|
|
|
|
|
|
if (WstState != NOT_STARTED) {
|
|
WstState = STOPPED;
|
|
|
|
IdPrint(("WST: WstDllCleanups() - Outputting data...\n")); // mdg 98/3
|
|
|
|
if (ulBitCount != 0L) {
|
|
ulSnaps++;
|
|
}
|
|
|
|
//
|
|
// Get the GLOBAL semaphore.. (valid accross all process contexts)
|
|
//
|
|
Status = NtWaitForSingleObject (hGlobalSem, FALSE, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDllCleanups() - "
|
|
"ERROR - Wait for GLOBAL semaphore failed - 0x%lx\n",
|
|
Status));
|
|
}
|
|
for (i=0; i<iImgCnt; i++) {
|
|
if (aImg[i].iSymCnt > 1) { // Don't dump modules w/o symbols (the 1 is UNKNOWN) mdg 98/4
|
|
WstClearBitStrings (&aImg[i]);
|
|
WstRotateWsiMem (&aImg[i]);
|
|
WstDumpData (&aImg[i]);
|
|
WstWriteTmiFile (&aImg[i]);
|
|
}
|
|
}
|
|
//
|
|
// Release the GLOBAL semaphore so other processes can dump data
|
|
//
|
|
Status = NtReleaseSemaphore (hGlobalSem, 1, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDllCleanups() - "
|
|
"Error releasing GLOBAL semaphore - 0x%lx\n", Status));
|
|
}
|
|
|
|
IdPrint(("WST: WstDllCleanups() - ...Done.\n"));
|
|
}
|
|
|
|
if (fInThread) {
|
|
(*pulShared)--;
|
|
fInThread = FALSE;
|
|
if ( (int)*pulShared <= 0L ) {
|
|
Status = NtSetEvent (hDoneEvent, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDllCleanups() - "
|
|
"ERROR - Setting DONE event failed - 0x%lx\n", Status));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Unmap and close shared block section
|
|
//
|
|
Status = NtUnmapViewOfSection (NtCurrentProcess(), (PVOID)pulShared);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDllCleanups() - "
|
|
"ERROR - NtUnmapViewOfSection() - 0x%lx\n", Status));
|
|
}
|
|
|
|
Status = NtClose(hSharedSec);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDllCleanups() - "
|
|
"ERROR - NtClose() - 0x%lx\n", Status));
|
|
}
|
|
|
|
// Unmap and close WSP section
|
|
//
|
|
Status = NtUnmapViewOfSection (NtCurrentProcess(), (PVOID)aImg[0].pWsp);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDllCleanups() - "
|
|
"ERROR - NtUnmapViewOfSection() - 0x%lx\n", Status));
|
|
}
|
|
|
|
Status = NtClose(hWspSec);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDllCleanups() - "
|
|
"ERROR - NtClose() - 0x%lx\n", Status));
|
|
}
|
|
// Free private heap
|
|
//
|
|
if (NULL != hWstHeap) {
|
|
if (!HeapDestroy( hWstHeap )) { // Eliminate private heap & allocations
|
|
KdPrint (("WST: WstDllCleanups() -"
|
|
"ERROR - HeapDestroy() - 0x%lx\n", GetLastError()));
|
|
}
|
|
}
|
|
|
|
// Close GLOBAL semaphore
|
|
//
|
|
Status = NtClose (hGlobalSem);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDllCleanups() - "
|
|
"ERROR - Could not close the GLOBAL semaphore - 0x%lx\n",
|
|
Status));
|
|
}
|
|
|
|
//
|
|
// Close LOCAL semaphore
|
|
//
|
|
Status = NtClose (hLocalSem);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDllCleanups() - "
|
|
"ERROR - Could not close the LOCAL semaphore - 0x%lx\n",
|
|
Status));
|
|
}
|
|
|
|
if (fPatchImage) {
|
|
//
|
|
// Close all events
|
|
//
|
|
NtClose (hDoneEvent);
|
|
NtClose (hDumpEvent);
|
|
NtClose (hClearEvent);
|
|
NtClose (hPauseEvent);
|
|
|
|
//
|
|
// Close thread handles - threads are terminated during DLL detaching
|
|
// process.
|
|
//
|
|
CloseHandle (hDumpThread);
|
|
CloseHandle (hClearThread);
|
|
CloseHandle (hPauseThread);
|
|
|
|
}
|
|
|
|
|
|
} /* WstDllCleanups () */
|
|
|
|
|
|
|
|
|
|
|
|
/******************* W s t A c c e s s X c p t F i l t e r ******************
|
|
*
|
|
* WstAccessXcptFilter (ulXcptNo, pXcptInfoPtr) -
|
|
* Commits COMMIT_SIZE more pages of memory if exception is access
|
|
* violation.
|
|
*
|
|
* ENTRY ulXcptNo - exception number
|
|
* pXcptInfoPtr - exception report record info pointer
|
|
*
|
|
* EXIT -none-
|
|
*
|
|
* RETURN EXCEPTIONR_CONTINUE_EXECUTION : if access violation exception
|
|
* and mem committed successfully
|
|
* EXCEPTION_CONTINUE_SEARCH : if non-access violation exception
|
|
* or cannot commit more memory
|
|
* WARNING:
|
|
* -none-
|
|
*
|
|
* COMMENT:
|
|
* -none-
|
|
*
|
|
*/
|
|
|
|
INT WstAccessXcptFilter (ULONG ulXcptNo, PEXCEPTION_POINTERS pXcptPtr)
|
|
{
|
|
NTSTATUS Status;
|
|
SIZE_T ulSize = COMMIT_SIZE;
|
|
PVOID pvMem = (PVOID)pXcptPtr->ExceptionRecord->ExceptionInformation[1];
|
|
|
|
|
|
if (ulXcptNo != EXCEPTION_ACCESS_VIOLATION) {
|
|
return (EXCEPTION_CONTINUE_SEARCH);
|
|
} else {
|
|
Status = NtAllocateVirtualMemory (NtCurrentProcess(),
|
|
&pvMem,
|
|
0L,
|
|
&ulSize,
|
|
MEM_COMMIT,
|
|
PAGE_READWRITE);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstAccessXcptFilter() - "
|
|
"Error committing more memory @ 0x%08lx - 0x%08lx "
|
|
"- TEB=0x%08lx\n", pvMem, Status, NtCurrentTeb()));
|
|
return (EXCEPTION_CONTINUE_SEARCH);
|
|
} else {
|
|
SdPrint (("WST: WstAccessXcptFilter() - "
|
|
"Committed %d more pages @ 0x%08lx - TEB=0x%08lx\n",
|
|
COMMIT_SIZE/PAGE_SIZE, pvMem, NtCurrentTeb()));
|
|
}
|
|
|
|
return (EXCEPTION_CONTINUE_EXECUTION);
|
|
}
|
|
|
|
} /* WstAccessXcptFilter () */
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
/******* S O R T / S E A R C H U T I L I T Y F U N C T I O N S *********/
|
|
/*****************************************************************************/
|
|
|
|
|
|
/************************* W s t C o m p a r e *****************************
|
|
*
|
|
* Function: WstCompare(PVOID val1,PVOID val2)
|
|
*
|
|
* Purpose: Compare values for qsort
|
|
*
|
|
*
|
|
* Parameters: PVOID
|
|
*
|
|
* Returns: -1 if val1 < val2
|
|
* 1 if val1 > val2
|
|
* 0 if val1 == val2
|
|
*
|
|
* History: 8-3-92 Marklea - created
|
|
*
|
|
*/
|
|
|
|
int WstCompare (PWSP val1, PWSP val2)
|
|
{
|
|
return (val1->ulFuncAddr < val2->ulFuncAddr ? -1:
|
|
val1->ulFuncAddr == val2->ulFuncAddr ? 0:
|
|
1);
|
|
|
|
} /* WstComapre () */
|
|
|
|
|
|
|
|
|
|
|
|
/*********************** W s t B C o m p a r e ********************************
|
|
*
|
|
* Function: WstBCompare(PDWORD pdwVal1, PVOID val2)
|
|
*
|
|
* Purpose: Compare values for Binary search
|
|
*
|
|
*
|
|
* Parameters: PVOID
|
|
*
|
|
* Returns: -1 if val1 < val2
|
|
* 1 if val1 > val2
|
|
* 0 if val1 == val2
|
|
*
|
|
* History: 8-3-92 Marklea - created
|
|
*
|
|
*/
|
|
|
|
int WstBCompare (DWORD_PTR *pdwVal1, PWSP val2)
|
|
{
|
|
#if defined(_X86_)
|
|
return (*pdwVal1 < val2->ulFuncAddr ? -1:
|
|
*pdwVal1 == val2->ulFuncAddr ? 0:
|
|
1);
|
|
#elif defined(ALPHA) || defined(IA64) || defined(_AMD64_)
|
|
int dwCompareCode = 0;
|
|
|
|
if (*pdwVal1 < val2->ulFuncAddr) {
|
|
dwCompareCode = -1;
|
|
} else if (*pdwVal1 >= val2->ulFuncAddr + val2->ulCodeLength) {
|
|
dwCompareCode = 1;
|
|
}
|
|
return (dwCompareCode);
|
|
#endif
|
|
|
|
} /* WstBCompare () */
|
|
|
|
|
|
|
|
|
|
/*********************** W s t S o r t **************************************
|
|
*
|
|
* Function: WstSort(WSP wsp[], INT iLeft, INT iRight)
|
|
*
|
|
* Purpose: Sort WSP array for binary search
|
|
*
|
|
*
|
|
* Parameters: wsp[] Pointer to WSP array
|
|
* iLeft Left most index value for array
|
|
* iRight Rightmost index value for array
|
|
*
|
|
* Returns: NONE
|
|
*
|
|
* History: 8-4-92 Marklea - created
|
|
*
|
|
*/
|
|
|
|
void WstSort (WSP wsp[], INT iLeft, INT iRight)
|
|
{
|
|
INT i, iLast;
|
|
|
|
|
|
if (iLeft >= iRight) {
|
|
return;
|
|
}
|
|
|
|
|
|
WstSwap(wsp, iLeft, (iLeft + iRight)/2);
|
|
|
|
iLast = iLeft;
|
|
|
|
for (i=iLeft+1; i <= iRight ; i++ ) {
|
|
if (WstCompare(&wsp[i], &wsp[iLeft]) < 0) {
|
|
if (!wsp[i].ulFuncAddr) {
|
|
SdPrint(("WST: WstSort() - Error in symbol list ulFuncAddr: "
|
|
"0x%lx [%d]\n", wsp[i].ulFuncAddr, i));
|
|
}
|
|
WstSwap(wsp, ++iLast, i);
|
|
}
|
|
}
|
|
|
|
WstSwap(wsp, iLeft, iLast);
|
|
WstSort(wsp, iLeft, iLast-1);
|
|
WstSort(wsp, iLast+1, iRight);
|
|
|
|
} /* WstSort () */
|
|
|
|
|
|
|
|
|
|
|
|
/*********************** W s t S w a p **************************************
|
|
*
|
|
* Function: WstSwap(WSP wsp[], INT i, INT j)
|
|
*
|
|
* Purpose: Helper function for WstSort to swap WSP array values
|
|
*
|
|
*
|
|
* Parameters: wsp[] Pointer to WSP array
|
|
* i index value to swap to
|
|
* i index value to swap from
|
|
*
|
|
* Returns: NONE
|
|
*
|
|
* History: 8-4-92 Marklea - created
|
|
*
|
|
*/
|
|
|
|
void WstSwap (WSP wsp[], INT i, INT j)
|
|
{
|
|
WSP wspTmp;
|
|
|
|
|
|
wspTmp = wsp[i];
|
|
wsp[i] = wsp[j];
|
|
wsp[j] = wspTmp;
|
|
|
|
} /* WstSwap () */
|
|
|
|
|
|
|
|
|
|
|
|
/*********************** W s t B S e a r c h *******************************
|
|
*
|
|
* Function: WstBSearch(DWORD dwAddr, WSP wspCur[], INT n)
|
|
*
|
|
* Purpose: Binary search function for finding a match in the WSP array
|
|
*
|
|
*
|
|
* Parameters: dwAddr Address of calling function
|
|
* wspCur[]Pointer to WSP containg value to match with dwAddr
|
|
* n Number of elements in WSP array
|
|
*
|
|
* Returns: PWSP Pointer to matching WSP
|
|
*
|
|
* History: 8-5-92 Marklea - created
|
|
*
|
|
*/
|
|
|
|
PWSP WstBSearch (DWORD_PTR dwAddr, WSP wspCur[], INT n)
|
|
{
|
|
int i;
|
|
ULONG ulHigh = n;
|
|
ULONG ulLow = 0;
|
|
ULONG ulMid;
|
|
|
|
while (ulLow < ulHigh) {
|
|
ulMid = ulLow + (ulHigh - ulLow) /2;
|
|
if ((i = WstBCompare(&dwAddr, &wspCur[ulMid])) < 0) {
|
|
ulHigh = ulMid;
|
|
} else if (i > 0) {
|
|
ulLow = ulMid + 1;
|
|
} else {
|
|
return (&wspCur[ulMid]);
|
|
}
|
|
}
|
|
|
|
return (NULL);
|
|
|
|
} /* WstBSearch () */
|
|
|
|
|
|
|
|
|
|
/************************** W s t D u m p t h r e a d ***********************
|
|
*
|
|
* WstDumpThread (pvArg) -
|
|
* This routine is executed as the DUMP notification thread.
|
|
* It will wait on an event before calling the dump routine.
|
|
*
|
|
* ENTRY pvArg - thread's single argument
|
|
*
|
|
* EXIT -none-
|
|
*
|
|
* RETURN 0
|
|
*
|
|
* WARNING:
|
|
* -none-
|
|
*
|
|
* COMMENT:
|
|
* Leaves profiling turned off.
|
|
*
|
|
*/
|
|
|
|
#if _MSC_FULL_VER >= 13008827
|
|
#pragma warning(push)
|
|
#pragma warning(disable:4715) // Not all control paths return (due to infinite loop)
|
|
#endif
|
|
|
|
DWORD WstDumpThread (PVOID pvArg)
|
|
{
|
|
NTSTATUS Status;
|
|
int i;
|
|
|
|
|
|
pvArg; // prevent compiler warnings
|
|
|
|
|
|
SdPrint (("WST: WstDumpThread() started.. TEB=0x%lx\n", NtCurrentTeb()));
|
|
|
|
for (;;) {
|
|
//
|
|
// Wait for the DUMP event..
|
|
//
|
|
Status = NtWaitForSingleObject (hDumpEvent, FALSE, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDumpThread() - "
|
|
"ERROR - Wait for DUMP event failed - 0x%lx\n", Status));
|
|
}
|
|
Status = NtResetEvent (hDoneEvent, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDumpThread() - "
|
|
"ERROR - Resetting DONE event failed - 0x%lx\n", Status));
|
|
}
|
|
fInThread = TRUE;
|
|
(*pulShared)++;
|
|
if (WstState != NOT_STARTED) {
|
|
|
|
IdPrint (("WST: Profiling stopped & DUMPing data... \n"));
|
|
|
|
// Stop profiling
|
|
//
|
|
WstState = NOT_STARTED;
|
|
|
|
// Dump the data
|
|
//
|
|
if (ulBitCount != 0L) {
|
|
ulSnaps++;
|
|
}
|
|
|
|
//
|
|
// Get the GLOBAL semaphore.. (valid accross all process contexts)
|
|
//
|
|
Status = NtWaitForSingleObject (hGlobalSem, FALSE, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDumpThread() - "
|
|
"ERROR - Wait for GLOBAL semaphore failed - 0x%lx\n",
|
|
Status));
|
|
}
|
|
for (i=0; i<iImgCnt; i++) {
|
|
if (aImg[i].iSymCnt > 1) { // Don't dump modules w/o symbols (the 1 is UNKNOWN) mdg 98/4
|
|
WstClearBitStrings (&aImg[i]);
|
|
WstRotateWsiMem (&aImg[i]);
|
|
WstDumpData (&aImg[i]);
|
|
WstWriteTmiFile (&aImg[i]);
|
|
}
|
|
}
|
|
//
|
|
// Release the GLOBAL semaphore so other processes can dump data
|
|
//
|
|
Status = NtReleaseSemaphore (hGlobalSem, 1, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDumpThread() - "
|
|
"Error releasing GLOBAL semaphore - 0x%lx\n", Status));
|
|
}
|
|
|
|
IdPrint (("WST: ...data DUMPed & profiling stopped.\n"));
|
|
}
|
|
|
|
(*pulShared)--;
|
|
if ( *pulShared == 0L ) {
|
|
Status = NtSetEvent (hDoneEvent, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDumpThread() - "
|
|
"ERROR - Setting DONE event failed - 0x%lx\n",
|
|
Status));
|
|
}
|
|
}
|
|
|
|
fInThread = FALSE;
|
|
}
|
|
|
|
return 0;
|
|
|
|
} /* WstDumpThread () */
|
|
|
|
|
|
|
|
/************************ W s t C l e a r T h r e a d ***********************
|
|
*
|
|
* WstClearThread (hNotifyEvent) -
|
|
* This routine is executed as the CLEAR notification thread.
|
|
* It will wait on an event before calling the clear routine
|
|
* and restarting profiling.
|
|
*
|
|
* ENTRY pvArg - thread's single argument
|
|
*
|
|
* EXIT -none-
|
|
*
|
|
* RETURN -none-
|
|
*
|
|
* WARNING:
|
|
* -none-
|
|
*
|
|
* COMMENT:
|
|
* -none-
|
|
*
|
|
*/
|
|
|
|
DWORD WstClearThread (PVOID pvArg)
|
|
{
|
|
NTSTATUS Status;
|
|
int i;
|
|
|
|
|
|
pvArg; // prevent compiler warnings
|
|
|
|
|
|
SdPrint (("WST: WstClearThread() started.. TEB=0x%lx\n", NtCurrentTeb()));
|
|
|
|
for (;;) {
|
|
//
|
|
// Wait for the CLEAR event..
|
|
//
|
|
Status = NtWaitForSingleObject (hClearEvent, FALSE, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstClearThread() - "
|
|
"Wait for CLEAR event failed - 0x%lx\n", Status));
|
|
}
|
|
Status = NtResetEvent (hDoneEvent, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstClearThread() - "
|
|
"ERROR - Resetting DONE event failed - 0x%lx\n", Status));
|
|
}
|
|
fInThread = TRUE;
|
|
(*pulShared)++;
|
|
|
|
IdPrint (("WST: Profiling stopped & CLEARing data...\n"));
|
|
|
|
// Stop profiling while clearing data
|
|
//
|
|
WstState = STOPPED;
|
|
|
|
// Clear WST info
|
|
//
|
|
ulBitCount = 0L;
|
|
ulSnaps = 0L;
|
|
|
|
for (i=0; i<iImgCnt; i++) {
|
|
aImg[i].pulWsiNxt = aImg[i].pulWsi;
|
|
RtlZeroMemory (aImg[i].pulWsi,
|
|
aImg[i].iSymCnt * ulMaxSnapULONGs * sizeof(ULONG));
|
|
RtlZeroMemory (aImg[i].pulWsp,
|
|
aImg[i].iSymCnt * ulMaxSnapULONGs * sizeof(ULONG));
|
|
}
|
|
NtQueryPerformanceCounter (&liStart, NULL);
|
|
|
|
// Resume profiling
|
|
//
|
|
WstState = STARTED;
|
|
|
|
IdPrint (("WST: ...data is CLEARed & profiling restarted.\n"));
|
|
(*pulShared)--;
|
|
if ( *pulShared == 0L ) {
|
|
Status = NtSetEvent (hDoneEvent, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstClearThread() - "
|
|
"ERROR - Setting DONE event failed - 0x%lx\n",
|
|
Status));
|
|
}
|
|
}
|
|
|
|
fInThread = FALSE;
|
|
}
|
|
|
|
return 0;
|
|
|
|
} /* WstClearThread () */
|
|
|
|
|
|
/************************ W s t P a u s e T h r e a d ***********************
|
|
*
|
|
* WstPauseThread (hNotifyEvent) -
|
|
* This routine is executed as the PAUSE notification thread.
|
|
* It will wait on an event before pausing the profiling.
|
|
*
|
|
* ENTRY pvArg - thread's single argument
|
|
*
|
|
* EXIT -none-
|
|
*
|
|
* RETURN -none-
|
|
*
|
|
* WARNING:
|
|
* -none-
|
|
*
|
|
* COMMENT:
|
|
* -none-
|
|
*
|
|
*/
|
|
|
|
DWORD WstPauseThread (PVOID pvArg)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
|
|
pvArg; // prevent compiler warnings
|
|
|
|
|
|
SdPrint (("WST: WstPauseThread() started.. TEB=0x%lx\n", NtCurrentTeb()));
|
|
|
|
for (;;) {
|
|
//
|
|
// Wait for the PASUE event..
|
|
//
|
|
Status = NtWaitForSingleObject (hPauseEvent, FALSE, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstPauseThread() - "
|
|
"Wait for PAUSE event failed - 0x%lx\n", Status));
|
|
}
|
|
Status = NtResetEvent (hDoneEvent, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstPauseThread() - "
|
|
"ERROR - Resetting DONE event failed - 0x%lx\n", Status));
|
|
}
|
|
fInThread = TRUE;
|
|
(*pulShared)++;
|
|
if (WstState == STARTED) {
|
|
//
|
|
// Stop profiling
|
|
//
|
|
WstState = STOPPED;
|
|
|
|
IdPrint (("WST: Profiling stopped.\n"));
|
|
}
|
|
|
|
(*pulShared)--;
|
|
if ( *pulShared == 0L ) {
|
|
Status = NtSetEvent (hDoneEvent, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstPauseThread() - "
|
|
"ERROR - Setting DONE event failed - 0x%lx\n",
|
|
Status));
|
|
}
|
|
}
|
|
|
|
fInThread = FALSE;
|
|
}
|
|
|
|
return 0;
|
|
|
|
} /* WstPauseThread () */
|
|
|
|
|
|
#if _MSC_FULL_VER >= 13008827
|
|
#pragma warning(pop)
|
|
#endif
|
|
|
|
|
|
/*********************** W s t D a t a O v e r F l o w **********************
|
|
*
|
|
* WstDataOverFlow () -
|
|
* This routine is called upon lack of space for storing next
|
|
* time snap data. It dumps and then clears the WST data.
|
|
*
|
|
* ENTRY -none-
|
|
*
|
|
* EXIT -none-
|
|
*
|
|
* RETURN -none-
|
|
*
|
|
* WARNING:
|
|
* -none-
|
|
*
|
|
* COMMENT:
|
|
* -none-
|
|
*
|
|
*/
|
|
|
|
void WstDataOverFlow(void)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Dump data
|
|
//
|
|
Status = NtResetEvent (hDoneEvent, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDataOverFlow() - "
|
|
"ERROR - Resetting DONE event failed - 0x%lx\n", Status));
|
|
}
|
|
Status = NtPulseEvent (hDumpEvent, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDataOverFlow() - NtPulseEvent() "
|
|
"failed for DUMP event - %lx\n", Status));
|
|
}
|
|
Status = NtWaitForSingleObject (hDoneEvent, FALSE, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDataOverFlow() - NtWaitForSingleObject() "
|
|
"failed for DONE event - %lx\n", Status));
|
|
}
|
|
|
|
//
|
|
// Clear data
|
|
//
|
|
Status = NtResetEvent (hDoneEvent, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDataOverFlow() - "
|
|
"ERROR - Resetting DONE event failed - 0x%lx\n", Status));
|
|
}
|
|
Status = NtPulseEvent (hClearEvent, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDataOverFlow() - NtPulseEvent() "
|
|
"failed for CLEAR event - %lx\n", Status));
|
|
}
|
|
//
|
|
// Wait for the DONE event..
|
|
//
|
|
Status = NtWaitForSingleObject (hDoneEvent, FALSE, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstDataOverFlow() - NtWaitForSingleObject() "
|
|
"failed for DONE event - %lx\n", Status));
|
|
}
|
|
} /* WstDataOverFlow() */
|
|
|
|
|
|
|
|
#ifdef BATCHING
|
|
|
|
BOOL WstOpenBatchFile(VOID)
|
|
{
|
|
NTSTATUS Status;
|
|
ANSI_STRING ObjName;
|
|
UNICODE_STRING UnicodeName;
|
|
OBJECT_ATTRIBUTES ObjAttributes;
|
|
IO_STATUS_BLOCK iostatus;
|
|
RtlInitString(&ObjName, "\\Device\\Harddisk0\\Partition1\\wst\\BATCH.TXT");
|
|
Status = RtlAnsiStringToUnicodeString(&UnicodeName, &ObjName, TRUE);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstOpenBatchFile() - "
|
|
"RtlAnsiStringToUnicodeString() failed - 0x%lx\n", Status));
|
|
return (FALSE);
|
|
}
|
|
|
|
InitializeObjectAttributes (&ObjAttributes,
|
|
&UnicodeName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
&SecDescriptor);
|
|
|
|
Status = NtCreateFile(&hBatchFile,
|
|
GENERIC_WRITE | SYNCHRONIZE, // Desired access
|
|
&ObjAttributes, // Object attributes
|
|
&iostatus, // Completion status
|
|
NULL,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
FILE_SHARE_WRITE,
|
|
FILE_OVERWRITE_IF,
|
|
FILE_SEQUENTIAL_ONLY | // Open option
|
|
FILE_SYNCHRONOUS_IO_NONALERT,
|
|
NULL,
|
|
0L);
|
|
|
|
RtlFreeUnicodeString (&UnicodeName); // HWC 11/93
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint (("WST: WstOpenBatchFile() - "
|
|
"NtCreateFile() failed - 0x%lx\n", Status));
|
|
return (FALSE);
|
|
}
|
|
return(TRUE);
|
|
|
|
} /* WstOpenBatchFile () */
|
|
|
|
#endif
|
|
|
|
|
|
/******************* S e t S y m b o l S e a r c h P a t h ******************
|
|
*
|
|
* SetSymbolSearchPath ()
|
|
* Return complete search path for symbols files (.dbg)
|
|
*
|
|
* ENTRY -none-
|
|
*
|
|
* EXIT -none-
|
|
*
|
|
* RETURN -none-
|
|
*
|
|
* WARNING:
|
|
* -none-
|
|
*
|
|
* COMMENT:
|
|
* "lpSymbolSearchPath" global LPSTR variable will point to the
|
|
* search path.
|
|
*/
|
|
#define FilePathLen 256
|
|
|
|
void SetSymbolSearchPath (void)
|
|
{
|
|
CHAR SymPath[FilePathLen];
|
|
CHAR AltSymPath[FilePathLen];
|
|
CHAR SysRootPath[FilePathLen];
|
|
LPSTR lpSymPathEnv=SymPath;
|
|
LPSTR lpAltSymPathEnv=AltSymPath;
|
|
LPSTR lpSystemRootEnv=SysRootPath;
|
|
ULONG cbSymPath;
|
|
DWORD dw;
|
|
HANDLE hMemoryHandle;
|
|
|
|
SymPath[0] = AltSymPath[0] = SysRootPath[0] = '\0';
|
|
|
|
cbSymPath = 18;
|
|
if (GetEnvironmentVariable("_NT_SYMBOL_PATH", SymPath, sizeof(SymPath))) {
|
|
cbSymPath += strlen(lpSymPathEnv) + 1;
|
|
}
|
|
|
|
if (GetEnvironmentVariable("_NT_ALT_SYMBOL_PATH", AltSymPath, sizeof(AltSymPath))) {
|
|
cbSymPath += strlen(lpAltSymPathEnv) + 1;
|
|
}
|
|
|
|
if (GetEnvironmentVariable("SystemRoot", SysRootPath, sizeof(SysRootPath))) {
|
|
cbSymPath += strlen(lpSystemRootEnv) + 1;
|
|
}
|
|
|
|
hMemoryHandle = GlobalAlloc (GHND, cbSymPath+1);
|
|
if (!hMemoryHandle) {
|
|
return;
|
|
}
|
|
|
|
lpSymbolSearchPath = GlobalLock (hMemoryHandle);
|
|
if (!lpSymbolSearchPath) {
|
|
GlobalFree( hMemoryHandle ); // mdg 98/3
|
|
return;
|
|
}
|
|
|
|
|
|
strcat(lpSymbolSearchPath,".");
|
|
|
|
if (*lpAltSymPathEnv) {
|
|
dw = GetFileAttributes(lpAltSymPathEnv);
|
|
if ( dw != 0xffffffff && dw & FILE_ATTRIBUTE_DIRECTORY ) {
|
|
strcat(lpSymbolSearchPath,";");
|
|
strcat(lpSymbolSearchPath,lpAltSymPathEnv);
|
|
}
|
|
}
|
|
if (*lpSymPathEnv) {
|
|
dw = GetFileAttributes(lpSymPathEnv);
|
|
if ( dw != 0xffffffff && dw & FILE_ATTRIBUTE_DIRECTORY ) {
|
|
strcat(lpSymbolSearchPath,";");
|
|
strcat(lpSymbolSearchPath,lpSymPathEnv);
|
|
}
|
|
}
|
|
if (*lpSystemRootEnv) {
|
|
dw = GetFileAttributes(lpSystemRootEnv);
|
|
if ( dw != 0xffffffff && dw & FILE_ATTRIBUTE_DIRECTORY ) {
|
|
strcat(lpSymbolSearchPath,";");
|
|
strcat(lpSymbolSearchPath,lpSystemRootEnv);
|
|
}
|
|
}
|
|
|
|
} /* SetSymbolSearchPath () */
|
|
|
|
#ifdef i386
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: SaveAllRegs
|
|
//
|
|
// Synopsis: Save all regs.
|
|
//
|
|
// Arguments: nothing
|
|
//
|
|
// Returns: none
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
Naked void SaveAllRegs(void)
|
|
{
|
|
_asm
|
|
{
|
|
push ebp
|
|
mov ebp,esp ; Remember where we are during this stuff
|
|
; ebp = Original esp - 4
|
|
|
|
push eax ; Save all regs that we think we might
|
|
push ebx ; destroy
|
|
push ecx
|
|
push edx
|
|
push esi
|
|
push edi
|
|
pushfd
|
|
push ds
|
|
push es
|
|
push ss
|
|
push fs
|
|
push gs
|
|
|
|
mov eax,[ebp+4] ; Grab Return Address
|
|
push eax ; Put Return Address on Stack so we can RET
|
|
|
|
mov ebp,[ebp+0] ; Restore original ebp
|
|
|
|
//
|
|
// This is how the stack looks like before the RET statement
|
|
//
|
|
// +-----------+
|
|
// | Ret Addr | + 3ch CurrentEBP + 4
|
|
// +-----------+
|
|
// | Org ebp | + 38h CurrentEBP + 0
|
|
// +-----------+
|
|
// | eax | + 34h
|
|
// +-----------+
|
|
// | ebx | + 30h
|
|
// +-----------+
|
|
// | ecx | + 2ch
|
|
// +-----------+
|
|
// | edx | + 24h
|
|
// +-----------+
|
|
// | esi | + 20h
|
|
// +-----------+
|
|
// | edi | + 1ch
|
|
// +-----------+
|
|
// | eflags | + 18h
|
|
// +-----------+
|
|
// | ds | + 14h
|
|
// +-----------+
|
|
// | es | + 10h
|
|
// +-----------+
|
|
// | ss | + ch
|
|
// +-----------+
|
|
// | fs | + 8h
|
|
// +-----------+
|
|
// | gs | + 4h
|
|
// +-----------+
|
|
// | Ret Addr | ESP + 0h
|
|
// +-----------+
|
|
|
|
ret
|
|
}
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: RestoreAllRegs
|
|
//
|
|
// Synopsis: restore all regs
|
|
//
|
|
// Arguments: nothing
|
|
//
|
|
// Returns: none
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
Naked void RestoreAllRegs(void)
|
|
{
|
|
_asm
|
|
{
|
|
//
|
|
// This is how the stack looks like upon entering this routine
|
|
//
|
|
// +-----------+
|
|
// | Ret Addr | + 38h [ RetAddr for SaveAllRegs() ]
|
|
// +-----------+
|
|
// | Org ebp | + 34h
|
|
// +-----------+
|
|
// | eax | + 30h
|
|
// +-----------+
|
|
// | ebx | + 2Ch
|
|
// +-----------+
|
|
// | ecx | + 28h
|
|
// +-----------+
|
|
// | edx | + 24h
|
|
// +-----------+
|
|
// | esi | + 20h
|
|
// +-----------+
|
|
// | edi | + 1Ch
|
|
// +-----------+
|
|
// | eflags | + 18h
|
|
// +-----------+
|
|
// | ds | + 14h
|
|
// +-----------+
|
|
// | es | + 10h
|
|
// +-----------+
|
|
// | ss | + Ch
|
|
// +-----------+
|
|
// | fs | + 8h
|
|
// +-----------+
|
|
// | gs | + 4h
|
|
// +-----------+
|
|
// | Ret EIP | ESP + 0h [ RetAddr for RestoreAllRegs() ]
|
|
// +-----------+
|
|
//
|
|
|
|
|
|
push ebp ; Save a temporary copy of original BP
|
|
mov ebp,esp ; BP = Original SP + 4
|
|
|
|
//
|
|
// This is how the stack looks like NOW!
|
|
//
|
|
// +-----------+
|
|
// | Ret Addr | + 3Ch [ RetAddr for SaveAllRegs() ]
|
|
// +-----------+
|
|
// | Org ebp | + 38h [ EBP before SaveAllRegs() ]
|
|
// +-----------+
|
|
// | eax | + 34h
|
|
// +-----------+
|
|
// | ebx | + 30h
|
|
// +-----------+
|
|
// | ecx | + 2Ch
|
|
// +-----------+
|
|
// | edx | + 28h
|
|
// +-----------+
|
|
// | esi | + 24h
|
|
// +-----------+
|
|
// | edi | + 20h
|
|
// +-----------+
|
|
// | eflags | + 1Ch
|
|
// +-----------+
|
|
// | ds | + 18h
|
|
// +-----------+
|
|
// | es | + 14h
|
|
// +-----------+
|
|
// | ss | + 10h
|
|
// +-----------+
|
|
// | fs | + Ch
|
|
// +-----------+
|
|
// | gs | + 8h
|
|
// +-----------+
|
|
// | Ret EIP | ESP + 4h [ RetAddr for RestoreAllRegs() ]
|
|
// +-----------+
|
|
// | EBP | ESP + 0h or EBP + 0h
|
|
// +-----------+
|
|
//
|
|
|
|
pop eax ; Get Original EBP
|
|
mov [ebp+38h],eax ; Put it in the original EBP place
|
|
; This EBP is the EBP before calling
|
|
; RestoreAllRegs()
|
|
pop eax ; Get ret address forRestoreAllRegs ()
|
|
mov [ebp+3Ch],eax ; Put Return Address on Stack
|
|
|
|
pop gs ; Restore all regs
|
|
pop fs
|
|
pop ss
|
|
pop es
|
|
pop ds
|
|
popfd
|
|
pop edi
|
|
pop esi
|
|
pop edx
|
|
pop ecx
|
|
pop ebx
|
|
pop eax
|
|
pop ebp
|
|
|
|
ret
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|