windows-nt/Source/XPSP1/NT/sdktools/wst/wstdll/wst.c
2020-09-26 16:20:57 +08:00

3199 lines
98 KiB
C

/*** 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