windows-nt/Source/XPSP1/NT/sdktools/psapi/profile.c

1030 lines
39 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <imagehlp.h>
#include <psapi.h>
#include <stdlib.h>
#include <stdio.h>
#define MAX_SYMNAME_SIZE 1024
CHAR symBuffer[sizeof(IMAGEHLP_SYMBOL)+MAX_SYMNAME_SIZE];
PIMAGEHLP_SYMBOL ThisSymbol = (PIMAGEHLP_SYMBOL) symBuffer;
CHAR LastSymBuffer[sizeof(IMAGEHLP_SYMBOL)+MAX_SYMNAME_SIZE];
PIMAGEHLP_SYMBOL LastSymbol = (PIMAGEHLP_SYMBOL) LastSymBuffer;
CHAR BadSymBuffer[sizeof(IMAGEHLP_SYMBOL)+MAX_SYMNAME_SIZE];
PIMAGEHLP_SYMBOL BadSymbol = (PIMAGEHLP_SYMBOL)BadSymBuffer;
BOOL UseLastSymbol;
typedef struct _PROFILE_BLOCK {
HANDLE Handle;
HANDLE SecondaryHandle;
PVOID ImageBase;
BOOL SymbolsLoaded;
PULONG CodeStart;
ULONG CodeLength;
PULONG Buffer;
PULONG SecondaryBuffer;
ULONG BufferSize;
ULONG TextNumber;
ULONG BucketSize;
PUNICODE_STRING ImageName;
char *ImageFileName;
} PROFILE_BLOCK;
ULONG ProfilePageSize;
#define MAX_BYTE_PER_LINE 72
#define MAX_PROFILE_COUNT 100
#define SYM_HANDLE ((HANDLE)UlongToPtr(0xffffffff))
PROFILE_BLOCK ProfileObject[MAX_PROFILE_COUNT+1];
ULONG NumberOfProfileObjects = 0;
ULONG ProfileInterval = 4882;
#define BUCKETSIZE 4
int PowerOfBytesCoveredPerBucket = 2;
CHAR SymbolSearchPathBuf[4096];
LPSTR SymbolSearchPath = SymbolSearchPathBuf;
BOOLEAN ShowAllHits = FALSE;
BOOLEAN fKernel = FALSE;
PCHAR OutputFile = "profile.out";
KPROFILE_SOURCE ProfileSource = ProfileTime;
KPROFILE_SOURCE SecondaryProfileSource = ProfileTime;
BOOLEAN UseSecondaryProfile = FALSE;
//
// define the mappings between arguments and KPROFILE_SOURCE types
//
typedef struct _PROFILE_SOURCE_MAPPING {
PCHAR Name;
KPROFILE_SOURCE Source;
} PROFILE_SOURCE_MAPPING, *PPROFILE_SOURCE_MAPPING;
PROFILE_SOURCE_MAPPING ProfileSourceMapping[] = {
{NULL,0}
};
VOID
PsParseCommandLine(
VOID
);
VOID
PsWriteProfileLine(
IN HANDLE ProfileHandle,
IN PSZ Line,
IN int nbytes
)
{
IO_STATUS_BLOCK IoStatusBlock;
NtWriteFile(
ProfileHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
Line,
(ULONG)nbytes,
NULL,
NULL
);
}
NTSTATUS
PsInitializeAndStartProfile(
VOID
)
{
HANDLE CurrentProcessHandle;
SIZE_T BufferSize;
PVOID ImageBase;
PULONG CodeStart;
ULONG CodeLength;
PULONG Buffer;
PPEB Peb;
PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
PUNICODE_STRING ImageName;
PLIST_ENTRY Next;
SYSTEM_BASIC_INFORMATION SystemInfo;
NTSTATUS status;
ULONG i;
CHAR Bogus[256];
CHAR *ImageFileName;
SIZE_T WsMin, WsMax;
ULONG ModuleNumber;
CHAR ModuleInfoBuffer[64000];
ULONG ReturnedLength;
PRTL_PROCESS_MODULES Modules;
PRTL_PROCESS_MODULE_INFORMATION Module;
BOOLEAN PreviousProfilePrivState;
BOOLEAN PreviousQuotaPrivState;
BOOLEAN Done = FALSE;
BOOLEAN DuplicateObject = FALSE;
//
// Get the page size.
//
status = NtQuerySystemInformation (SystemBasicInformation,
&SystemInfo,
sizeof(SystemInfo),
NULL);
if (!NT_SUCCESS(status)) {
return status;
}
//
// Load kernel modules
//
if (fKernel) {
status = NtQuerySystemInformation (
SystemModuleInformation,
ModuleInfoBuffer,
sizeof( ModuleInfoBuffer ),
&ReturnedLength);
if (!NT_SUCCESS(status)) {
DbgPrint("query system info failed status - %lx\n",status);
fKernel = FALSE;
} else {
Modules = (PRTL_PROCESS_MODULES)ModuleInfoBuffer;
Module = &Modules->Modules[ 0 ];
ModuleNumber = 0;
status = RtlAdjustPrivilege(
SE_SYSTEM_PROFILE_PRIVILEGE,
TRUE, //Enable
FALSE, //not impersonating
&PreviousProfilePrivState
);
if (!NT_SUCCESS(status) || status == STATUS_NOT_ALL_ASSIGNED) {
DbgPrint("Enable system profile privilege failed - status 0x%lx\n",
status);
}
status = RtlAdjustPrivilege(
SE_INCREASE_QUOTA_PRIVILEGE,
TRUE, //Enable
FALSE, //not impersonating
&PreviousQuotaPrivState
);
if (!NT_SUCCESS(status) || status == STATUS_NOT_ALL_ASSIGNED) {
DbgPrint("Unable to increase quota privilege (status=0x%lx)\n",
status);
}
}
}
ProfilePageSize = SystemInfo.PageSize;
//
// Locate all the executables in the address and create a
// seperate profile object for each one.
//
CurrentProcessHandle = NtCurrentProcess();
Peb = NtCurrentPeb();
Next = Peb->Ldr->InMemoryOrderModuleList.Flink;
while (!Done) {
if ( Next != &Peb->Ldr->InMemoryOrderModuleList) {
LdrDataTableEntry = (PLDR_DATA_TABLE_ENTRY) (CONTAINING_RECORD(
Next,
LDR_DATA_TABLE_ENTRY,
InMemoryOrderLinks
));
Next = Next->Flink;
ImageBase = LdrDataTableEntry->DllBase;
ImageName = &LdrDataTableEntry->BaseDllName;
CodeLength = LdrDataTableEntry->SizeOfImage;
CodeStart = (PULONG)ImageBase;
ImageFileName = HeapAlloc(GetProcessHeap(), 0, 256);
if (!ImageFileName) {
status = STATUS_NO_MEMORY;
return status;
}
status = RtlUnicodeToOemN( ImageFileName,
256,
&i,
ImageName->Buffer,
ImageName->Length
);
ImageFileName[i] = 0;
if (status != STATUS_SUCCESS) {
HeapFree(GetProcessHeap(), 0, ImageFileName);
continue;
}
} else
if (fKernel && (ModuleNumber < Modules->NumberOfModules)) {
ULONG cNameMBLength = lstrlen(&Module->FullPathName[Module->OffsetToFileName]) + 1;
ULONG cNameUCLength = cNameMBLength * sizeof(WCHAR);
ULONG cNameSize = cNameUCLength + sizeof(UNICODE_STRING);
ImageFileName = HeapAlloc(GetProcessHeap(), 0, cNameMBLength);
if (!ImageFileName) {
status = STATUS_NO_MEMORY;
return status;
}
lstrcpy(ImageFileName, &Module->FullPathName[Module->OffsetToFileName]);
ImageBase = Module->ImageBase;
CodeLength = Module->ImageSize;
CodeStart = (PULONG)ImageBase;
ImageName = HeapAlloc(GetProcessHeap(), 0, cNameSize);
if (!ImageName) {
status = STATUS_NO_MEMORY;
return status;
}
ImageName->Buffer = (WCHAR *)((PBYTE)ImageName + sizeof(UNICODE_STRING));
RtlMultiByteToUnicodeN(ImageName->Buffer, cNameUCLength, &i,
&Module->FullPathName[Module->OffsetToFileName],
cNameMBLength);
ImageName->Length = (USHORT)i;
Module++;
ModuleNumber++;
} else {
Done = TRUE;
break;
}
DuplicateObject = FALSE;
for (i = 0; i < NumberOfProfileObjects ; i++ ) {
if (ImageBase == ProfileObject[i].ImageBase)
DuplicateObject = TRUE;
}
if (DuplicateObject) {
continue;
}
ProfileObject[NumberOfProfileObjects].ImageBase = ImageBase;
ProfileObject[NumberOfProfileObjects].ImageName = ImageName;
ProfileObject[NumberOfProfileObjects].ImageFileName = ImageFileName;
ProfileObject[NumberOfProfileObjects].CodeLength = CodeLength;
ProfileObject[NumberOfProfileObjects].CodeStart = CodeStart;
ProfileObject[NumberOfProfileObjects].TextNumber = 1;
//
// Analyze the size of the code and create a reasonably sized
// profile object.
//
BufferSize = ((CodeLength * BUCKETSIZE) >> PowerOfBytesCoveredPerBucket) + 4;
Buffer = NULL;
status = NtAllocateVirtualMemory (CurrentProcessHandle,
(PVOID *)&Buffer,
0,
&BufferSize,
MEM_RESERVE | MEM_COMMIT,
PAGE_READWRITE);
if (!NT_SUCCESS(status)) {
DbgPrint ("RtlInitializeProfile : alloc VM failed %lx\n",status);
return status;
}
ProfileObject[NumberOfProfileObjects].Buffer = Buffer;
ProfileObject[NumberOfProfileObjects].BufferSize = (ULONG)BufferSize;
ProfileObject[NumberOfProfileObjects].BucketSize = PowerOfBytesCoveredPerBucket;
status = NtCreateProfile (
&ProfileObject[NumberOfProfileObjects].Handle,
CurrentProcessHandle,
ProfileObject[NumberOfProfileObjects].CodeStart,
ProfileObject[NumberOfProfileObjects].CodeLength,
ProfileObject[NumberOfProfileObjects].BucketSize,
ProfileObject[NumberOfProfileObjects].Buffer ,
ProfileObject[NumberOfProfileObjects].BufferSize,
ProfileSource,
(KAFFINITY)-1);
if (status != STATUS_SUCCESS) {
DbgPrint("create profile %wZ failed - status %lx\n",
ProfileObject[NumberOfProfileObjects].ImageName,status);
return status;
}
if (UseSecondaryProfile) {
Buffer = NULL;
status = NtAllocateVirtualMemory (CurrentProcessHandle,
(PVOID *)&Buffer,
0,
&BufferSize,
MEM_RESERVE | MEM_COMMIT,
PAGE_READWRITE);
if (!NT_SUCCESS(status)) {
DbgPrint ("RtlInitializeProfile : secondary alloc VM failed %lx\n",status);
return status;
}
ProfileObject[NumberOfProfileObjects].SecondaryBuffer = Buffer;
status = NtCreateProfile (
&ProfileObject[NumberOfProfileObjects].SecondaryHandle,
CurrentProcessHandle,
ProfileObject[NumberOfProfileObjects].CodeStart,
ProfileObject[NumberOfProfileObjects].CodeLength,
ProfileObject[NumberOfProfileObjects].BucketSize,
ProfileObject[NumberOfProfileObjects].SecondaryBuffer,
ProfileObject[NumberOfProfileObjects].BufferSize,
SecondaryProfileSource,
(KAFFINITY)-1);
if (status != STATUS_SUCCESS) {
DbgPrint("create profile %wZ failed - status %lx\n",
ProfileObject[NumberOfProfileObjects].ImageName,status);
return status;
}
}
NumberOfProfileObjects++;
if (NumberOfProfileObjects == MAX_PROFILE_COUNT) {
break;
}
}
NtSetIntervalProfile(ProfileInterval,ProfileSource);
if (UseSecondaryProfile) {
NtSetIntervalProfile(ProfileInterval,SecondaryProfileSource);
}
for (i = 0; i < NumberOfProfileObjects; i++) {
status = NtStartProfile (ProfileObject[i].Handle);
if (status == STATUS_WORKING_SET_QUOTA) {
//
// Increase the working set to lock down a bigger buffer.
//
GetProcessWorkingSetSize(CurrentProcessHandle,&WsMin,&WsMax);
WsMax += 10*ProfilePageSize + ProfileObject[i].BufferSize;
WsMin += 10*ProfilePageSize + ProfileObject[i].BufferSize;
SetProcessWorkingSetSize(CurrentProcessHandle,WsMin,WsMax);
status = NtStartProfile (ProfileObject[i].Handle);
}
if (status != STATUS_SUCCESS) {
DbgPrint("start profile %wZ failed - status %lx\n",
ProfileObject[i].ImageName, status);
return status;
}
if (UseSecondaryProfile) {
status = NtStartProfile (ProfileObject[i].SecondaryHandle);
if (status == STATUS_WORKING_SET_QUOTA) {
//
// Increase the working set to lock down a bigger buffer.
//
GetProcessWorkingSetSize(CurrentProcessHandle,&WsMin,&WsMax);
WsMax += 10*ProfilePageSize + ProfileObject[i].BufferSize;
WsMin += 10*ProfilePageSize + ProfileObject[i].BufferSize;
SetProcessWorkingSetSize(CurrentProcessHandle,WsMin,WsMax);
status = NtStartProfile (ProfileObject[i].SecondaryHandle);
}
if (status != STATUS_SUCCESS) {
DbgPrint("start secondary profile %wZ failed - status %lx\n",
ProfileObject[i].ImageName, status);
return status;
}
}
}
return status;
}
unsigned long
Percent(
unsigned long arg1,
unsigned long arg2,
unsigned long * Low
)
{
unsigned long iarg1 = arg1;
unsigned __int64 iarg2 = arg2 * 100000;
unsigned long diff, High;
diff = (unsigned long) (iarg2 / iarg1);
while (diff > 100000) {
diff /= 100000;
}
High = diff / 1000;
*Low = diff % 1000;
return(High);
}
NTSTATUS
PsStopAndAnalyzeProfile(
VOID
)
{
NTSTATUS status;
ULONG CountAtSymbol;
ULONG SecondaryCountAtSymbol;
NTSTATUS Status;
ULONG_PTR Va;
HANDLE ProfileHandle;
CHAR Line[512];
ULONG i, n, High, Low;
PULONG Buffer, BufferEnd, Counter, InitialCounter;
PULONG SecondaryBuffer;
PULONG SecondaryInitialCounter;
ULONG TotalCounts;
ULONG ByteCount;
IMAGEHLP_MODULE ModuleInfo;
SIZE_T dwDisplacement;
ModuleInfo.SizeOfStruct = sizeof(ModuleInfo);
__try {
// If there's a problem faulting in the symbol handler, just return.
//
// initialize the symbol handler
//
ThisSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
ThisSymbol->MaxNameLength = MAX_SYMNAME_SIZE;
LastSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
LastSymbol->MaxNameLength = MAX_SYMNAME_SIZE;
SymSetOptions( SYMOPT_UNDNAME | SYMOPT_CASE_INSENSITIVE | SYMOPT_OMAP_FIND_NEAREST);
SymInitialize( SYM_HANDLE, NULL, FALSE );
SymGetSearchPath( SYM_HANDLE, SymbolSearchPathBuf, sizeof(SymbolSearchPathBuf) );
ZeroMemory( BadSymBuffer, sizeof(BadSymBuffer) );
BadSymbol->Name[0] = (BYTE)lstrlen("No Symbol Found");
lstrcpy( &BadSymbol->Name[1], "No Symbol Found" );
BadSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
BadSymbol->MaxNameLength = MAX_SYMNAME_SIZE;
ProfileHandle = CreateFile(
OutputFile,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if ( ProfileHandle == INVALID_HANDLE_VALUE ) {
return STATUS_UNSUCCESSFUL;
}
for (i = 0; i < NumberOfProfileObjects; i++) {
Status = NtStopProfile (ProfileObject[i].Handle);
}
if (MAX_PROFILE_COUNT == NumberOfProfileObjects) {
n = sprintf(Line,"Overflowed the maximum number of "
"modules: %d\n",
MAX_PROFILE_COUNT
);
PsWriteProfileLine(ProfileHandle,Line,n);
}
//
// The new profiler
//
for (i = 0; i < NumberOfProfileObjects; i++) {
UseLastSymbol = FALSE;
CountAtSymbol = 0;
SecondaryCountAtSymbol = 0;
//
// Sum the total number of cells written.
//
BufferEnd = ProfileObject[i].Buffer + (
ProfileObject[i].BufferSize / sizeof(ULONG));
Buffer = ProfileObject[i].Buffer;
Counter = BufferEnd;
if (UseSecondaryProfile) {
SecondaryBuffer = ProfileObject[i].SecondaryBuffer;
}
TotalCounts = 0;
while (Counter > Buffer) {
Counter -= 1;
TotalCounts += *Counter;
}
if (!TotalCounts) {
// Don't bother wasting time loading symbols
continue;
}
if (SymLoadModule( SYM_HANDLE, NULL, ProfileObject[i].ImageFileName, NULL,
(DWORD_PTR)ProfileObject[i].ImageBase, 0)
&& SymGetModuleInfo(SYM_HANDLE, (DWORD_PTR)ProfileObject[i].ImageBase, &ModuleInfo)
&& (ModuleInfo.SymType != SymNone)
)
{
ProfileObject[i].SymbolsLoaded = TRUE;
} else {
ProfileObject[i].SymbolsLoaded = FALSE;
}
n= sprintf(Line,"%d,%wZ,Total%s\n",
TotalCounts,
ProfileObject[i].ImageName,
(ProfileObject[i].SymbolsLoaded) ? "" : " (NO SYMBOLS)"
);
PsWriteProfileLine(ProfileHandle,Line,n);
if (ProfileObject[i].SymbolsLoaded) {
InitialCounter = Buffer;
if (UseSecondaryProfile) {
SecondaryInitialCounter = SecondaryBuffer;
}
for ( Counter = Buffer; Counter < BufferEnd; Counter += 1 ) {
if ( *Counter ) {
//
// Now we have an an address relative to the buffer
// base.
//
Va = ((PUCHAR)Counter - (PUCHAR)Buffer);
Va = Va * ( 1 << (ProfileObject[i].BucketSize - 2));
//
// Add in the image base and the base of the
// code to get the Va in the image
//
Va = Va + (ULONG_PTR)ProfileObject[i].CodeStart;
if (SymGetSymFromAddr( SYM_HANDLE, Va, &dwDisplacement, ThisSymbol )) {
if ( UseLastSymbol && LastSymbol->Address == ThisSymbol->Address ) {
CountAtSymbol += *Counter;
if (UseSecondaryProfile) {
SecondaryCountAtSymbol += *(SecondaryBuffer + (Counter-Buffer));
}
} else {
if ( UseLastSymbol && LastSymbol->Address ) {
if ( CountAtSymbol || SecondaryCountAtSymbol) {
if (!UseSecondaryProfile) {
n= sprintf(Line,"%d,%wZ,%s (%08lx)\n",
CountAtSymbol,
ProfileObject[i].ImageName,
LastSymbol->Name,
LastSymbol->Address
);
} else {
if (SecondaryCountAtSymbol != 0) {
High = Percent(CountAtSymbol, SecondaryCountAtSymbol, &Low);
n = sprintf(Line,"%d,%d,%2.2d.%3.3d,%wZ,%s (%08lx)\n",
CountAtSymbol,
SecondaryCountAtSymbol,
High, Low,
ProfileObject[i].ImageName,
LastSymbol->Name,
LastSymbol->Address
);
} else {
n = sprintf(Line,"%d,%d, -- ,%wZ,%s (%08lx)\n",
CountAtSymbol,
SecondaryCountAtSymbol,
ProfileObject[i].ImageName,
LastSymbol->Name,
LastSymbol->Address
);
}
}
PsWriteProfileLine(ProfileHandle,Line,n);
if (ShowAllHits) {
while (InitialCounter < Counter) {
if (*InitialCounter) {
Va = ((PUCHAR)InitialCounter - (PUCHAR)Buffer);
Va = Va * (1 << (ProfileObject[i].BucketSize - 2));
Va = Va + (ULONG_PTR)ProfileObject[i].CodeStart;
if (!UseSecondaryProfile) {
n = sprintf(Line, "\t%p:%d\n",
Va,
*InitialCounter);
} else {
if (*SecondaryInitialCounter != 0) {
High = Percent(*InitialCounter, *SecondaryInitialCounter, &Low);
n = sprintf(Line, "\t%p:%d, %d, %2.2d.%3.3d\n",
Va,
*InitialCounter,
*SecondaryInitialCounter,
High, Low);
} else {
n = sprintf(Line, "\t%p:%d, %d, --\n",
Va,
*InitialCounter,
*SecondaryInitialCounter);
}
}
PsWriteProfileLine(ProfileHandle, Line, n);
}
++InitialCounter;
++SecondaryInitialCounter;
}
}
}
}
InitialCounter = Counter;
CountAtSymbol = *Counter;
if (UseSecondaryProfile) {
SecondaryInitialCounter = SecondaryBuffer + (Counter-Buffer);
SecondaryCountAtSymbol += *(SecondaryBuffer + (Counter-Buffer));
}
memcpy( LastSymBuffer, symBuffer, sizeof(symBuffer) );
UseLastSymbol = TRUE;
}
} else {
if (CountAtSymbol || SecondaryCountAtSymbol) {
if (!UseSecondaryProfile) {
n= sprintf(Line,"%d,%wZ,%s (%08lx)\n",
CountAtSymbol,
ProfileObject[i].ImageName,
LastSymbol->Name,
LastSymbol->Address
);
} else {
if (SecondaryCountAtSymbol != 0) {
High = Percent(CountAtSymbol, SecondaryCountAtSymbol, &Low);
n = sprintf(Line,"%d,%d,%2.2d.%3.3d,%wZ,%s (%08lx)\n",
CountAtSymbol,
SecondaryCountAtSymbol,
High, Low,
ProfileObject[i].ImageName,
LastSymbol->Name,
LastSymbol->Address
);
} else {
n = sprintf(Line,"%d,%d, -- ,%wZ,%s (%08lx)\n",
CountAtSymbol,
SecondaryCountAtSymbol,
ProfileObject[i].ImageName,
LastSymbol->Name,
LastSymbol->Address
);
}
}
PsWriteProfileLine(ProfileHandle,Line,n);
if (ShowAllHits) {
while (InitialCounter < Counter) {
if (*InitialCounter) {
Va = ((PUCHAR)InitialCounter - (PUCHAR)Buffer);
Va = Va * (1 << (ProfileObject[i].BucketSize - 2));
Va = Va + (ULONG_PTR)ProfileObject[i].CodeStart;
if (!UseSecondaryProfile) {
n = sprintf(Line, "\t%p:%d\n",
Va,
*InitialCounter);
} else {
if (*SecondaryInitialCounter != 0) {
High = Percent(*InitialCounter, *SecondaryInitialCounter, &Low);
n = sprintf(Line, "\t%p:%d, %d, %2.2d.%3.3d\n",
Va,
*InitialCounter,
*SecondaryInitialCounter,
High,Low);
} else {
n = sprintf(Line, "\t%p:%d, %d, --\n",
Va,
*InitialCounter,
*SecondaryInitialCounter);
}
}
PsWriteProfileLine(ProfileHandle, Line, n);
}
++InitialCounter;
++SecondaryInitialCounter;
}
}
InitialCounter = Counter;
CountAtSymbol = *Counter;
if (UseSecondaryProfile) {
SecondaryInitialCounter = SecondaryBuffer + (Counter-Buffer);
SecondaryCountAtSymbol += *(SecondaryBuffer + (Counter-Buffer));
}
memcpy( LastSymBuffer, BadSymBuffer, sizeof(BadSymBuffer) );
UseLastSymbol = TRUE;
}
else {
n = sprintf(Line,"%d,%wZ,Unknown (%p)\n",
CountAtSymbol,
ProfileObject[i].ImageName,
Va
);
PsWriteProfileLine(ProfileHandle, Line, n);
}
}
}
}
if ( CountAtSymbol || SecondaryCountAtSymbol ) {
if (!UseSecondaryProfile) {
n= sprintf(Line,"%d,%wZ,%s (%08lx)\n",
CountAtSymbol,
ProfileObject[i].ImageName,
LastSymbol->Name,
LastSymbol->Address
);
} else {
if (SecondaryCountAtSymbol != 0) {
High = Percent(CountAtSymbol, SecondaryCountAtSymbol, &Low);
n = sprintf(Line,"%d,%d,%2.2d.%3.3d,%wZ,%s (%08lx)\n",
CountAtSymbol,
SecondaryCountAtSymbol,
High, Low,
ProfileObject[i].ImageName,
LastSymbol->Name,
LastSymbol->Address
);
} else {
n = sprintf(Line,"%d,%d, -- ,%wZ,%s (%08lx)\n",
CountAtSymbol,
SecondaryCountAtSymbol,
ProfileObject[i].ImageName,
LastSymbol->Name,
LastSymbol->Address
);
}
}
PsWriteProfileLine(ProfileHandle,Line,n);
if (ShowAllHits) {
while (InitialCounter < Counter) {
if (*InitialCounter) {
Va = ((PUCHAR)InitialCounter - (PUCHAR)Buffer);
Va = Va * (1 << (ProfileObject[i].BucketSize - 2));
Va = Va + (ULONG_PTR)ProfileObject[i].CodeStart;
if (!UseSecondaryProfile) {
n = sprintf(Line, "\t%p:%d\n",
Va,
*InitialCounter);
} else {
if (*SecondaryInitialCounter != 0) {
High = Percent(*InitialCounter, *SecondaryInitialCounter, &Low);
n = sprintf(Line, "\t%p:%d, %d, %2.2d.%3.3d\n",
Va,
*InitialCounter,
*SecondaryInitialCounter,
High, Low);
} else {
n = sprintf(Line, "\t%p:%d, %d, --\n",
Va,
*InitialCounter,
*SecondaryInitialCounter);
}
}
PsWriteProfileLine(ProfileHandle, Line, n);
}
++InitialCounter;
++SecondaryInitialCounter;
}
}
}
SymUnloadModule( SYM_HANDLE, (DWORD_PTR)ProfileObject[i].ImageBase);
}
}
for (i = 0; i < NumberOfProfileObjects; i++) {
Buffer = ProfileObject[i].Buffer;
RtlZeroMemory(Buffer,ProfileObject[i].BufferSize);
}
CloseHandle(ProfileHandle);
} __except (EXCEPTION_EXECUTE_HANDLER) {
}
return STATUS_SUCCESS;
}
BOOLEAN
DllMain(
IN PVOID DllHandle,
IN ULONG Reason,
IN PCONTEXT Context OPTIONAL
)
{
switch ( Reason ) {
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(DllHandle);
if ( NtCurrentPeb()->ProcessParameters->Flags & RTL_USER_PROC_PROFILE_USER ) {
PsParseCommandLine();
PsInitializeAndStartProfile();
}
break;
case DLL_PROCESS_DETACH:
if ( NtCurrentPeb()->ProcessParameters->Flags & RTL_USER_PROC_PROFILE_USER ) {
PsStopAndAnalyzeProfile();
}
break;
}
return TRUE;
}
char *
Mystrtok (
char * string,
const char * control
)
{
unsigned char *str;
const unsigned char *ctrl = control;
unsigned char map[32];
int count;
static char *nextoken;
/* Clear control map */
for (count = 0; count < 32; count++)
map[count] = 0;
/* Set bits in delimiter table */
do {
map[*ctrl >> 3] |= (1 << (*ctrl & 7));
} while (*ctrl++);
/* Initialize str. If string is NULL, set str to the saved
* pointer (i.e., continue breaking tokens out of the string
* from the last strtok call) */
if (string)
str = string;
else
str = nextoken;
/* Find beginning of token (skip over leading delimiters). Note that
* there is no token iff this loop sets str to point to the terminal
* null (*str == '\0') */
while ( (map[*str >> 3] & (1 << (*str & 7))) && *str )
str++;
string = str;
/* Find the end of the token. If it is not the end of the string,
* put a null there. */
for ( ; *str ; str++ )
if ( map[*str >> 3] & (1 << (*str & 7)) ) {
*str++ = '\0';
break;
}
/* Update nextoken (or the corresponding field in the per-thread data
* structure */
nextoken = str;
/* Determine if a token has been found. */
if ( string == str )
return NULL;
else
return string;
}
VOID
PsParseCommandLine(
VOID
)
{
PCHAR CommandLine;
PCHAR Argument;
HANDLE MappingHandle;
PPROFILE_SOURCE_MAPPING ProfileMapping;
//
// The original command line is in a shared memory section
// named "ProfileStartupParameters"
//
MappingHandle = OpenFileMapping(FILE_MAP_WRITE,
FALSE,
"ProfileStartupParameters");
if (MappingHandle != NULL) {
CommandLine = MapViewOfFile(MappingHandle,
FILE_MAP_WRITE,
0,
0,
0);
if (!CommandLine) {
CloseHandle(MappingHandle);
return;
}
} else {
return;
}
Argument = Mystrtok(CommandLine," \t");
while (Argument != NULL) {
if ((Argument[0] == '-') ||
(Argument[0] == '/')) {
switch (Argument[1]) {
case 'a':
case 'A':
ShowAllHits = TRUE;
break;
case 'b':
case 'B':
PowerOfBytesCoveredPerBucket = atoi(&Argument[2]);
break;
case 'f':
case 'F':
//
// The arg area is unmapped so we copy the string
//
OutputFile = HeapAlloc(GetProcessHeap(), 0,
lstrlen(&Argument[2]) + 1);
lstrcpy(OutputFile, &Argument[2]);
case 'i':
case 'I':
ProfileInterval = atoi(&Argument[2]);
break;
case 'k':
case 'K':
fKernel = TRUE;
break;
case 's':
ProfileMapping = ProfileSourceMapping;
while (ProfileMapping->Name != NULL) {
if (_stricmp(ProfileMapping->Name, &Argument[2])==0) {
ProfileSource = ProfileMapping->Source;
break;
}
++ProfileMapping;
}
break;
case 'S':
ProfileMapping = ProfileSourceMapping;
while (ProfileMapping->Name != NULL) {
if (_stricmp(ProfileMapping->Name, &Argument[2])==0) {
SecondaryProfileSource = ProfileMapping->Source;
UseSecondaryProfile = TRUE;
break;
}
++ProfileMapping;
}
break;
}
}
Argument = Mystrtok(NULL," \t");
}
UnmapViewOfFile(CommandLine);
CloseHandle(MappingHandle);
}