/*** 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 #include #include #include #include #include #include #include #include #include #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= 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; iiSymCnt; 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; xiSymCnt; 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; xiSymCnt; 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; xiSymCnt ; 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; xiSymCnt ; 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; xiSymCnt; 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 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 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= 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