windows-nt/Source/XPSP1/NT/base/wow64/mscpu/compiler/dumpcd.c
2020-09-26 16:20:57 +08:00

718 lines
18 KiB
C

/*++
Copyright (c) 1996-2000 Microsoft Corporation
Module Name:
dumpcd.c
Abstract:
This module dumps the contents of the
entrypoint tree and translation cache to a file.
Author:
Dave Hastings (daveh) creation-date 02-May-1996
Revision History:
--*/
#ifdef CODEGEN_PROFILE
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <entrypt.h>
#include <coded.h>
extern PEPNODE intelRoot;
extern EPNODE _NIL;
ULONG ProfileFlags = 0;
BOOL
ProcessEntrypoint(
PENTRYPOINT Entrypoint
);
#define CODE_BUFFER_SIZE 8184
UCHAR IntelCodeBuffer[CODE_BUFFER_SIZE];
ULONG NativeCodeBuffer[CODE_BUFFER_SIZE];
#define STACK_DEPTH 200
ULONG DumpStack[STACK_DEPTH];
ULONG DumpStackTop;
#define STACK_RESET() DumpStackTop=0;
#define PUSH(x) { \
if (DumpStackTop == STACK_DEPTH-1) { \
CHAR ErrorString[80]; \
sprintf(ErrorString, "Error: Dump stack overflow\n"); \
OutputDebugString(ErrorString); \
goto Exit; \
} else { \
DumpStack[DumpStackTop] = x; \
DumpStackTop++; \
} \
}
#define POP(x) { \
if (DumpStackTop == 0) { \
CHAR ErrorString[80]; \
sprintf(ErrorString, "Error: Dump stack underflow\n"); \
OutputDebugString(ErrorString); \
goto Exit; \
} else { \
DumpStackTop--; \
x = DumpStack[DumpStackTop]; \
} \
}
BOOL CpuCodegenProfile = FALSE;
PCHAR CpuCodegenProfilePath = NULL;
HANDLE CpuCodegenProfileFile = INVALID_HANDLE_VALUE;
//
// Code Description file state
//
ULONG CurrentFileLocation;
ULONG CodeDescriptionFlags = 0;
VOID
InitCodegenProfile(
VOID
)
/*++
Routine Description:
This routine gets the configuration information from the registry
and creates the file to put the profile data into.
Arguments:
None.
Return Value:
None.
--*/
{
LONG RetVal;
DWORD KeyType;
DWORD ProfileEnabled;
DWORD BufferSize;
CHAR FileName[MAX_PATH];
LPTSTR CommandLine;
CODEDESCRIPTIONHEADER Header;
ULONG CommandLineLength;
ULONG BytesWritten;
BOOL Success;
HKEY Key;
//
// Find out if codegen profiling is enabled. If there is a problem
// with the value in the registry, we will be disabled by default.
//
RetVal = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
"System\\CurrentControlSet\\Control\\Wx86",
0,
KEY_READ,
&Key
);
BufferSize = sizeof(ProfileEnabled);
RetVal = RegQueryValueEx(
Key,
"CpuCodegenProfile",
NULL,
&KeyType,
(PVOID)&ProfileEnabled,
&BufferSize
);
if ((RetVal != ERROR_SUCCESS) || (KeyType != REG_DWORD)) {
OutputDebugString("Wx86Cpu: No CpuCodegenProfile value, or wrong type\n");
return;
}
CpuCodegenProfile = ProfileEnabled;
//
// Get the path to store the datafile to.
// First we get the size of the string (and verify that it is a string)
// Then we get the actual string.
//
BufferSize = 0;
RetVal = RegQueryValueEx(
Key,
"CpuCodegenProfilePath",
NULL,
&KeyType,
(PVOID)&ProfileEnabled,
&BufferSize
);
if ((RetVal != ERROR_MORE_DATA) || (KeyType != REG_SZ)) {
OutputDebugString("Wx86Cpu: Problem with CpuCodegenProfilePath\n");
CpuCodegenProfile = FALSE;
return;
}
CpuCodegenProfilePath = HeapAlloc(GetProcessHeap(), 0, BufferSize);
if (CpuCodegenProfilePath == NULL) {
OutputDebugString("Wx86Cpu: Can't allocate CpuCodegenProfilePath\n");
CpuCodegenProfile = FALSE;
return;
}
RetVal = RegQueryValueEx(
Key,
"CpuCodegenProfilePath",
NULL,
&KeyType,
CpuCodegenProfilePath,
&BufferSize
);
if ((RetVal != ERROR_SUCCESS) || (KeyType != REG_SZ)) {
//
// Something really bad just happened. Don't do the profiling
//
OutputDebugString("Wx86Cpu: Inexplicable problem with CpuCodegenProfilePath\n");
HeapFree(GetProcessHeap(), 0, CpuCodegenProfilePath);
CpuCodegenProfile = FALSE;
return;
}
//
// Create file for the data
//
RetVal = GetTempFileName(CpuCodegenProfilePath, "prf", 0, FileName);
if (RetVal == 0) {
OutputDebugString("Wx86Cpu: GetTempFileName failed\n");
HeapFree(GetProcessHeap(), 0, CpuCodegenProfilePath);
CpuCodegenProfile = FALSE;
return;
}
CpuCodegenProfileFile = CreateFile(
FileName,
GENERIC_WRITE,
0,
NULL,
TRUNCATE_EXISTING,
FILE_ATTRIBUTE_COMPRESSED,
NULL
);
if (CpuCodegenProfileFile == INVALID_HANDLE_VALUE) {
OutputDebugString("Wx86Cpu: Unable to create profile file\n");
HeapFree(GetProcessHeap(), 0, CpuCodegenProfilePath);
CpuCodegenProfile = FALSE;
return;
}
//
// Write the file header to the file
//
CommandLine = GetCommandLine();
CommandLineLength = strlen(CommandLine) + 1;
Header.CommandLineOffset = sizeof(CODEDESCRIPTIONHEADER);
Header.NextCodeDescriptionOffset = ((sizeof(CODEDESCRIPTIONHEADER) +
CommandLineLength) + 3) & ~3;
Header.DumpFileRev = CODEGEN_PROFILE_REV;
Header.StartTime = GetCurrentTime();
Success = WriteFile(
CpuCodegenProfileFile,
&Header,
sizeof(Header),
&BytesWritten,
NULL
);
if (!Success || (BytesWritten != sizeof(Header))) {
OutputDebugString("Wx86Cpu: Failed to write profile header\n");
CloseHandle(CpuCodegenProfileFile);
HeapFree(GetProcessHeap(), 0, CpuCodegenProfilePath);
CpuCodegenProfile = FALSE;
return;
}
Success = WriteFile(
CpuCodegenProfileFile,
CommandLine,
CommandLineLength,
&BytesWritten,
NULL
);
if (!Success || (BytesWritten != CommandLineLength)) {
OutputDebugString("Wx86Cpu: Failed to write profile header\n");
CloseHandle(CpuCodegenProfileFile);
HeapFree(GetProcessHeap(), 0, CpuCodegenProfilePath);
CpuCodegenProfile = FALSE;
return;
}
//
// Set the file position for the first code description
//
CurrentFileLocation = SetFilePointer(
CpuCodegenProfileFile,
Header.NextCodeDescriptionOffset,
NULL,
FILE_BEGIN
);
if (CurrentFileLocation != Header.NextCodeDescriptionOffset) {
OutputDebugString("Wx86Cpu: failed to update file position\n");
CloseHandle(CpuCodegenProfileFile);
HeapFree(GetProcessHeap(), 0, CpuCodegenProfilePath);
CpuCodegenProfile = FALSE;
return;
}
}
VOID
TerminateCodegenProfile(
VOID
)
/*++
Routine Description:
This function put in the terminating record and closes the file.
Arguments:
None
Return Value:
None.
--*/
{
CODEDESCRIPTION CodeDescription;
BOOL Success;
ULONG BytesWritten;
CHAR ErrorString[80];
if (!CpuCodegenProfile) {
return;
}
CodeDescription.NextCodeDescriptionOffset = 0xFFFFFFFF;
CodeDescription.TypeTag = PROFILE_TAG_EOF;
CodeDescription.CreationTime = GetCurrentTime();
Success = WriteFile(
CpuCodegenProfileFile,
&CodeDescription,
sizeof(CODEDESCRIPTION),
&BytesWritten,
NULL
);
if (!Success || (BytesWritten != sizeof(CODEDESCRIPTION))) {
sprintf(
ErrorString,
"Error: Could not write termination record, %lu\n",
ProxyGetLastError()
);
OutputDebugString(ErrorString);
}
CpuCodegenProfile = FALSE;
CloseHandle(CpuCodegenProfileFile);
}
VOID
DumpCodeDescriptions(
BOOL TCFlush
)
/*++
Routine Description:
This routine dumps out the entrypoints, and the corresponding code
to a file in binary form.
Return Value:
None.
--*/
{
NTSTATUS Status;
PEPNODE NextEntrypoint;
EPNODE Entrypoint;
ULONG Epcount = 0;
if (!CpuCodegenProfile) {
return;
}
//
// Get the root of the entrypoint tree
//
NextEntrypoint = intelRoot;
//
// Initialize stack
//
STACK_RESET();
PUSH(0);
//
// iterate over every entrypoint
//
while (NextEntrypoint != NULL) {
Entrypoint = *NextEntrypoint;
//
// Process the top level entrypoint
//
if (!ProcessEntrypoint(&Entrypoint.ep)){
goto Exit;
}
//
// Process the sub entrypoints
//
while (Entrypoint.ep.SubEP) {
Entrypoint.ep = *Entrypoint.ep.SubEP;
//
// Write the sub-entrypoint to the file
//
if (!ProcessEntrypoint(&Entrypoint.ep)){
goto Exit;
}
}
//
// Set up for future iterations
//
if (Entrypoint.intelRight != &_NIL) {
PUSH((ULONG)Entrypoint.intelRight);
}
if (Entrypoint.intelLeft != &_NIL) {
PUSH((ULONG)Entrypoint.intelLeft);
}
POP((ULONG)NextEntrypoint);
}
Exit: ;
if (TCFlush) {
CODEDESCRIPTION CodeDescription;
ULONG NextCodeDescriptionOffset;
BOOL Success;
ULONG BytesWritten;
CHAR ErrorString[80];
NextCodeDescriptionOffset = (CurrentFileLocation + sizeof(CODEDESCRIPTION)) & ~3;
CodeDescription.TypeTag = PROFILE_TAG_TCFLUSH;
CodeDescription.NextCodeDescriptionOffset = NextCodeDescriptionOffset;
CodeDescription.CreationTime = GetCurrentTime();
Success = WriteFile(
CpuCodegenProfileFile,
&CodeDescription,
sizeof(CODEDESCRIPTION),
&BytesWritten,
NULL
);
if (!Success || (BytesWritten != sizeof(CODEDESCRIPTION))) {
sprintf(
ErrorString,
"Error: Could not write code description, %lu\n",
ProxyGetLastError()
);
OutputDebugString(ErrorString);
return;
}
CurrentFileLocation = SetFilePointer(
CpuCodegenProfileFile,
NextCodeDescriptionOffset,
NULL,
FILE_BEGIN
);
if (CurrentFileLocation != (ULONG)NextCodeDescriptionOffset) {
sprintf(ErrorString, "Error: SetFilePointer didn't work\n");
OutputDebugString(ErrorString);
return;
}
}
}
BOOL
ProcessEntrypoint(
PENTRYPOINT Entrypoint
)
/*++
Routine Description:
This routine writes the description for this entrypoint to the file.
Arguments:
Entrypoint -- Supplies the entrypoint to describe
File -- Supplies the file to write to
Return Value:
True for success, False for failure
--*/
{
ULONG NativeCodeLength, IntelCodeLength;
CODEDESCRIPTION CodeDescription;
ULONG NextCodeDescriptionOffset;
NTSTATUS Status;
BOOL Success;
ULONG BytesWritten;
CHAR ErrorString[80];
//
// Create the code description
//
NativeCodeLength = ((ULONG)Entrypoint->nativeEnd - (ULONG)Entrypoint->nativeStart + 4) & ~3;
IntelCodeLength = (ULONG)Entrypoint->intelEnd - (ULONG)Entrypoint->intelStart + 1;
CodeDescription.NativeCodeOffset = CurrentFileLocation + sizeof(CODEDESCRIPTION);
CodeDescription.IntelCodeOffset = CodeDescription.NativeCodeOffset + NativeCodeLength;
NextCodeDescriptionOffset = (CodeDescription.IntelCodeOffset +
IntelCodeLength + 3) & ~3;
CodeDescription.NextCodeDescriptionOffset = NextCodeDescriptionOffset;
CodeDescription.IntelAddress = (ULONG)Entrypoint->intelStart;
CodeDescription.NativeAddress = (ULONG)Entrypoint->nativeStart;
CodeDescription.SequenceNumber = Entrypoint->SequenceNumber;
CodeDescription.ExecutionCount = Entrypoint->ExecutionCount;
CodeDescription.IntelCodeSize = IntelCodeLength;
CodeDescription.NativeCodeSize = NativeCodeLength;
CodeDescription.TypeTag = PROFILE_TAG_CODEDESCRIPTION;
CodeDescription.CreationTime = Entrypoint->CreationTime;
//
// Verify that we can get all of the Intel and Native code
//
if (
(IntelCodeLength / sizeof(IntelCodeBuffer[1]) > CODE_BUFFER_SIZE) ||
(NativeCodeLength) && (NativeCodeLength / sizeof(NativeCodeBuffer[1]) > CODE_BUFFER_SIZE)
) {
sprintf(ErrorString, "Error: Code buffers not big enough:N %lx:I %lx\n", NativeCodeLength, IntelCodeLength);
OutputDebugString(ErrorString);
return FALSE;
}
//
// Get the native code
//
if (NativeCodeLength) {
memcpy(NativeCodeBuffer, Entrypoint->nativeStart, NativeCodeLength);
}
//
// Get the Intel code
//
try {
memcpy(IntelCodeBuffer, Entrypoint->intelStart, IntelCodeLength);
} except (EXCEPTION_EXECUTE_HANDLER) {
//
// Apparently the intel code is no longer there. This happens
// if a dll gets unloaded
//
IntelCodeLength = 0;
CodeDescription.IntelCodeSize = 0;
CodeDescription.IntelCodeOffset = CodeDescription.NativeCodeOffset + NativeCodeLength;
NextCodeDescriptionOffset = (CodeDescription.IntelCodeOffset +
IntelCodeLength + 3) & ~3;
CodeDescription.NextCodeDescriptionOffset = NextCodeDescriptionOffset;
}
//
// Write code description to disk
//
Success = WriteFile(
CpuCodegenProfileFile,
&CodeDescription,
sizeof(CODEDESCRIPTION),
&BytesWritten,
NULL
);
if (!Success || (BytesWritten != sizeof(CODEDESCRIPTION))) {
sprintf(
ErrorString,
"Error: Could not write code description, %lu\n",
ProxyGetLastError()
);
OutputDebugString(ErrorString);
return FALSE;
}
//
// Write Native code to disk
//
if (NativeCodeLength) {
Success = WriteFile(
CpuCodegenProfileFile,
NativeCodeBuffer,
NativeCodeLength,
&BytesWritten,
NULL
);
if (!Success || (BytesWritten != NativeCodeLength)) {
sprintf(
ErrorString,
"Error: Could not write native code, %lu\n",
ProxyGetLastError()
);
OutputDebugString(ErrorString);
return FALSE;
}
}
//
// Write Intel code to disk
//
if (IntelCodeLength) {
Success = WriteFile(
CpuCodegenProfileFile,
IntelCodeBuffer,
IntelCodeLength,
&BytesWritten,
NULL
);
if (!Success || (BytesWritten != IntelCodeLength)) {
sprintf(
ErrorString,
"Error: Could not write native code, %lu\n",
ProxyGetLastError()
);
OutputDebugString(ErrorString);
return FALSE;
}
}
Success = WriteFile(
CpuCodegenProfileFile,
IntelCodeBuffer,
IntelCodeLength,
&BytesWritten,
NULL
);
if (!Success || (BytesWritten != IntelCodeLength)) {
sprintf(
ErrorString,
"Error: Could not write native code, %lu\n",
ProxyGetLastError()
);
OutputDebugString(ErrorString);
return FALSE;
}
//
// Update file pointer position
//
CurrentFileLocation = SetFilePointer(
CpuCodegenProfileFile,
NextCodeDescriptionOffset,
NULL,
FILE_BEGIN
);
if (CurrentFileLocation != (ULONG)NextCodeDescriptionOffset) {
sprintf(ErrorString, "Error: SetFilePointer didn't work\n");
OutputDebugString(ErrorString);
return FALSE;
}
return TRUE;
}
VOID
DumpAllocFailure(
VOID
)
/*++
Routine Description:
This routine adds an allocation failure record to the profile dump.
Arguments:
None.
Return Value:
None.
--*/
{
CODEDESCRIPTION CodeDescription;
BOOL Success;
ULONG BytesWritten;
CHAR ErrorString[80];
ULONG NextCodeDescriptionOffset;
if (!CpuCodegenProfile) {
return;
}
NextCodeDescriptionOffset = CurrentFileLocation + sizeof(CODEDESCRIPTION);
CodeDescription.NextCodeDescriptionOffset = NextCodeDescriptionOffset;
CodeDescription.TypeTag = PROFILE_TAG_TCALLOCFAIL;
CodeDescription.CreationTime = GetCurrentTime();
Success = WriteFile(
CpuCodegenProfileFile,
&CodeDescription,
sizeof(CODEDESCRIPTION),
&BytesWritten,
NULL
);
if (!Success || (BytesWritten != sizeof(CODEDESCRIPTION))) {
sprintf(
ErrorString,
"Error: Could not write termination record, %lu\n",
ProxyGetLastError()
);
OutputDebugString(ErrorString);
}
//
// Update file pointer position
//
CurrentFileLocation = SetFilePointer(
CpuCodegenProfileFile,
NextCodeDescriptionOffset,
NULL,
FILE_BEGIN
);
if (CurrentFileLocation != (ULONG)NextCodeDescriptionOffset) {
sprintf(ErrorString, "Error: SetFilePointer didn't work\n");
OutputDebugString(ErrorString);
}
}
#endif