mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1229 lines
23 KiB
1229 lines
23 KiB
/*++
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
dll32.c
|
|
|
|
Abstract:
|
|
|
|
This module contains code to handle the tracking of 32 bit dll loading and
|
|
unloading.
|
|
|
|
Author:
|
|
|
|
Dave Hastings (daveh) 23-Oct-1992
|
|
|
|
Revision History:
|
|
|
|
BUGBUG this should not be tied to PrintToSprofWindow!!
|
|
|
|
--*/
|
|
|
|
#include "sprofp.h"
|
|
|
|
//
|
|
// Internal constants
|
|
//
|
|
|
|
#define PROFILE_BUCKET_SIZE 6
|
|
|
|
//
|
|
// Internal structures
|
|
//
|
|
|
|
typedef struct _Module32 {
|
|
HANDLE FileHandle;
|
|
HANDLE FileMapping;
|
|
PVOID BaseOfMapping;
|
|
PUCHAR ImageName;
|
|
PVOID BaseOfImage;
|
|
ULONG BaseOfCode;
|
|
ULONG OffsetOfCode;
|
|
ULONG SizeOfCode;
|
|
HANDLE Process;
|
|
HANDLE ProfileObject;
|
|
PULONG ProfileBuffer;
|
|
ULONG ProfileBufferSize;
|
|
UCHAR ProfilingFlags;
|
|
UCHAR ReferenceCount;
|
|
} MODULE32, *PMODULE32;
|
|
|
|
//
|
|
// Internal Dll tracking structure
|
|
//
|
|
|
|
|
|
typedef struct _LoadedDll {
|
|
struct _LoadedDll *Flink;
|
|
struct _LoadedDll *Blink;
|
|
LOAD_DLL_DEBUG_INFO DllInfo;
|
|
HANDLE FileMapping;
|
|
PVOID BaseOfMapping;
|
|
PUCHAR ImageName;
|
|
ULONG BaseOfCode;
|
|
ULONG OffsetOfCode;
|
|
ULONG SizeOfCode;
|
|
HANDLE Process;
|
|
HANDLE ProfileObject;
|
|
PULONG ProfileBuffer;
|
|
ULONG ProfileBufferSize;
|
|
} LOADED_DLL, *PLOADED_DLL;
|
|
|
|
//
|
|
// List head
|
|
//
|
|
typedef struct _LoadedDllList {
|
|
PLOADED_DLL Flink;
|
|
PLOADED_DLL Blink;
|
|
} LOADED_DLL_LIST;
|
|
|
|
//
|
|
// Internal global variables
|
|
//
|
|
|
|
//
|
|
// List of loaded Dlls
|
|
//
|
|
LOADED_DLL_LIST DllList = {(PLOADED_DLL)&DllList,(PLOADED_DLL)&DllList};
|
|
|
|
//
|
|
// Flag to indicate whether we are initialized
|
|
//
|
|
static BOOL Initialized = FALSE;
|
|
|
|
//
|
|
// Critical section to protect the DllList
|
|
//
|
|
CRITICAL_SECTION DllListCriticalSection;
|
|
|
|
//
|
|
// Internal Functions
|
|
//
|
|
|
|
PVOID
|
|
MapImage(
|
|
IN HANDLE File,
|
|
OUT PHANDLE Section
|
|
);
|
|
|
|
VOID
|
|
UnMapImage(
|
|
IN PVOID MappingBase,
|
|
IN HANDLE Section
|
|
);
|
|
|
|
COMPAREFUNCTION
|
|
CompareModule32(
|
|
PVOID Data,
|
|
PVOID Key
|
|
);
|
|
|
|
PVOID
|
|
CreateModule32List(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine creates a 32 bit module list
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
Pointer to the module list
|
|
|
|
--*/
|
|
{
|
|
return CreateList(sizeof(MODULE32), (COMPAREFUNCTION)CompareModule32);
|
|
}
|
|
|
|
PVOID
|
|
CreateModule32(
|
|
PVOID ModuleList,
|
|
HANDLE Process,
|
|
IN LPLOAD_DLL_DEBUG_INFO LoadDll,
|
|
IN HANDLE OutputWindow
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine creates a module 32 object and adds it to the module list
|
|
|
|
Arguments:
|
|
|
|
ModuleList -- Supplies the module list
|
|
Process -- Supplies the handle of the process this module is loaded for
|
|
LoadDll -- Supplies the debug info on the dll
|
|
OutputWindow -- Supplies a handle to a window to output to
|
|
|
|
Return Value:
|
|
|
|
Pointer to a 32 bit module
|
|
|
|
--*/
|
|
{
|
|
PUCHAR ImageName;
|
|
HANDLE SectionHandle;
|
|
PVOID ImageBase;
|
|
MODULE32 Module;
|
|
UCHAR StringBuffer[256];
|
|
|
|
if ((ModuleList == NULL) || (LoadDll == NULL)) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Map the image into our address space for name and symbols
|
|
//
|
|
|
|
ImageBase = MapImage(
|
|
LoadDll->hFile,
|
|
&SectionHandle
|
|
);
|
|
|
|
if (!ImageBase) {
|
|
printf("Sprof: could not map image to get name and symbols.\n");
|
|
printf(
|
|
"Sprof: Dll at %lx will be profiled without symbols\n",
|
|
LoadDll->lpBaseOfDll
|
|
);
|
|
}
|
|
|
|
//
|
|
// Get the name of the Image
|
|
//
|
|
|
|
ImageName = GetImageName(ImageBase);
|
|
|
|
if (!ImageName) {
|
|
printf("Sprof: could not get image name.\n");
|
|
}
|
|
|
|
memset(&Module,0,sizeof(MODULE32));
|
|
Module.FileHandle = LoadDll->hFile;
|
|
Module.FileMapping = SectionHandle;
|
|
Module.BaseOfMapping = ImageBase;
|
|
Module.ImageName = ImageName;
|
|
Module.BaseOfImage = LoadDll->lpBaseOfDll;
|
|
Module.OffsetOfCode = GetImageCodeBase(ImageBase);
|
|
Module.BaseOfCode = Module.OffsetOfCode + (ULONG)Module.BaseOfImage;
|
|
Module.SizeOfCode = GetImageCodeSize(ImageBase);
|
|
Module.Process = Process;
|
|
Module.ReferenceCount = 1;
|
|
|
|
// bugbug errrors in insert
|
|
sprintf(StringBuffer,"%s loaded",ImageName);
|
|
PrintToSprofWindow(OutputWindow,StringBuffer);
|
|
|
|
return InsertDataInList(ModuleList, &Module);
|
|
|
|
}
|
|
|
|
BOOL
|
|
DestroyModule32(
|
|
PVOID ModuleList,
|
|
PVOID ModuleHandle,
|
|
HANDLE OutputWindow
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function destroys the specified 32 bit module
|
|
|
|
Arguments:
|
|
|
|
ModuleList -- Supplies the module list
|
|
Module -- Supplies the module
|
|
OutputWindow -- Supplies a window to print to
|
|
|
|
Return Value:
|
|
|
|
TRUE if the module was successfully removed
|
|
|
|
--*/
|
|
{
|
|
PMODULE32 Module;
|
|
UCHAR StringBuffer[256];
|
|
|
|
if ((ModuleList == NULL) || (ModuleHandle == NULL)) {
|
|
return FALSE;
|
|
}
|
|
|
|
Module = GetDataFromListItem(
|
|
ModuleList,
|
|
ModuleHandle
|
|
);
|
|
//
|
|
// Unmap the file
|
|
//
|
|
|
|
UnMapImage(Module->BaseOfMapping,Module->FileMapping);
|
|
|
|
//
|
|
// Free up the memory associated with this dll
|
|
//
|
|
|
|
sprintf(StringBuffer, "%s unloaded",Module->ImageName);
|
|
PrintToSprofWindow(OutputWindow, StringBuffer);
|
|
free(Module->ImageName);
|
|
|
|
return RemoveDataFromList(ModuleList, NULL, ModuleHandle);
|
|
}
|
|
|
|
PVOID
|
|
GetModule32(
|
|
PVOID ModuleList,
|
|
PVOID LoadAddress
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns a pointer to the module identified by address
|
|
|
|
Arguments:
|
|
|
|
ModuleList -- Supplies the list to look in
|
|
LoadAddress -- Identifies the module
|
|
|
|
Return Value:
|
|
|
|
Pointer to the Module
|
|
|
|
--*/
|
|
{
|
|
MODULE32 ModuleKey;
|
|
|
|
ModuleKey.BaseOfImage = LoadAddress;
|
|
|
|
return FindDataInList(ModuleList, &ModuleKey);
|
|
}
|
|
|
|
PVOID
|
|
EnumerateModule32(
|
|
PVOID ModuleList,
|
|
PVOID Module
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns a pointer to the next module in the list.
|
|
|
|
Arguments:
|
|
|
|
ModuleList -- Supplies a pointer to the module list
|
|
Module -- Supplies a pointer to the current module
|
|
|
|
Return Value:
|
|
|
|
Pointer to the next module
|
|
|
|
--*/
|
|
{
|
|
return TraverseList(ModuleList, Module);
|
|
}
|
|
|
|
BOOL
|
|
StartProfileModule32(
|
|
PVOID ModuleList,
|
|
PVOID ModuleHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine starts profiling for the specified 32 bit module
|
|
|
|
Arguments:
|
|
|
|
ModuleList -- Supplies the module list
|
|
ModuleHandle -- Supplies the Module to profile
|
|
|
|
Return Value:
|
|
|
|
True if profiling started
|
|
|
|
--*/
|
|
{
|
|
PMODULE32 Module;
|
|
NTSTATUS Status;
|
|
UCHAR MessageString[80];
|
|
|
|
if (ModuleHandle == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
Module = GetDataFromListItem(ModuleList, ModuleHandle);
|
|
|
|
if (!Module->ProfileObject) {
|
|
Module->ProfileBufferSize = ((Module->SizeOfCode +
|
|
(1 << (PROFILE_BUCKET_SIZE - 1))) /
|
|
(1 << PROFILE_BUCKET_SIZE)) * sizeof(ULONG);
|
|
Module->ProfileBuffer = malloc(Module->ProfileBufferSize);
|
|
|
|
if (!Module->ProfileBuffer) {
|
|
return FALSE;
|
|
}
|
|
|
|
memset(Module->ProfileBuffer, 0, Module->ProfileBufferSize);
|
|
|
|
Status = NtCreateProfile(
|
|
&(Module->ProfileObject),
|
|
Module->Process,
|
|
(PVOID)(Module->BaseOfCode),
|
|
Module->SizeOfCode,
|
|
PROFILE_BUCKET_SIZE,
|
|
Module->ProfileBuffer,
|
|
Module->ProfileBufferSize,
|
|
ProfileTime,
|
|
(KAFFINITY)-1);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
sprintf(
|
|
MessageString,
|
|
"Failed to create profile object for dll %s, error code %lx",
|
|
Module->ImageName,
|
|
Status
|
|
);
|
|
MessageBox(
|
|
NULL,
|
|
MessageString,
|
|
"Segmented Profiler",
|
|
MB_ICONSTOP | MB_OK
|
|
);
|
|
|
|
exit(0);
|
|
}
|
|
Module->ReferenceCount++;
|
|
}
|
|
|
|
Status = NtStartProfile(Module->ProfileObject);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
sprintf(
|
|
MessageString,
|
|
"Failed to create profile object for dll %s, error code %lx",
|
|
Module->ImageName,
|
|
Status
|
|
);
|
|
MessageBox(
|
|
NULL,
|
|
MessageString,
|
|
"Segmented Profiler",
|
|
MB_ICONSTOP | MB_OK
|
|
);
|
|
|
|
exit(0);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
StopProfileModule32(
|
|
PVOID ModuleList,
|
|
PVOID ModuleHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine stops profiling for the specified 32 bit module
|
|
|
|
Arguments:
|
|
|
|
ModuleList -- Supplies the module list
|
|
Module -- Supplies the module to profile
|
|
|
|
Return Value:
|
|
|
|
True if profiling stopped
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
PMODULE32 Module;
|
|
|
|
if (ModuleHandle == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
Module = GetDataFromListItem(ModuleList, ModuleHandle);
|
|
|
|
Status = NtStopProfile(((PMODULE32)Module)->ProfileObject);
|
|
//bugbug error handling
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
BOOL
|
|
DumpProfileModule32(
|
|
PVOID ModuleList,
|
|
PVOID ModuleHandle,
|
|
HANDLE OutputFile
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine stops profiling for the specified dll
|
|
|
|
Arguments:
|
|
|
|
ModuleList -- Supplies the module list
|
|
Module -- Supplies the module to profile
|
|
OutputFile -- Supplies the handle of a file to dump the info to
|
|
|
|
Return Value:
|
|
|
|
True if profiling dumped
|
|
|
|
--*/
|
|
{
|
|
ULONG i,BytesWritten;
|
|
BOOL Success;
|
|
PMODULE32 Module;
|
|
UCHAR SymbolName[80];
|
|
PVOID SymbolAddress = NULL;
|
|
UCHAR Buffer[256];
|
|
|
|
if (ModuleHandle == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
Module = GetDataFromListItem(ModuleList, ModuleHandle);
|
|
|
|
sprintf(
|
|
Buffer,
|
|
"\nProfile hits for module %s (bucket size %d)\n\n",
|
|
Module->ImageName,
|
|
(1 << PROFILE_BUCKET_SIZE)
|
|
);
|
|
|
|
Success = WriteFile(
|
|
OutputFile,
|
|
Buffer,
|
|
strlen(Buffer),
|
|
&BytesWritten,
|
|
NULL
|
|
);
|
|
|
|
if (!Success || (BytesWritten != strlen(Buffer))) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// dump information for each profile bucket
|
|
//
|
|
for (i = 0;i < (Module->ProfileBufferSize / sizeof(ULONG)); i++) {
|
|
|
|
//
|
|
// Don't print information for buckets that have no hits
|
|
//
|
|
if (Module->ProfileBuffer[i] == 0) {
|
|
continue;
|
|
}
|
|
|
|
Success = GetNearestSymbol(
|
|
(PVOID)((i * (1 << PROFILE_BUCKET_SIZE)) + Module->BaseOfCode),
|
|
Module->BaseOfImage,
|
|
Module->BaseOfMapping,
|
|
SymbolName,
|
|
&SymbolAddress
|
|
);
|
|
|
|
if (!Success) {
|
|
sprintf(
|
|
Buffer,
|
|
"%10ld hits at %lx\n",
|
|
Module->ProfileBuffer[i],
|
|
(ULONG)(1 << PROFILE_BUCKET_SIZE) * i + Module->BaseOfCode
|
|
);
|
|
} else {
|
|
sprintf(
|
|
Buffer,
|
|
"%10ld hits at %s + %lx\n",
|
|
Module->ProfileBuffer[i],
|
|
SymbolName,
|
|
Module->OffsetOfCode + i * (1 << PROFILE_BUCKET_SIZE) -
|
|
(ULONG)SymbolAddress
|
|
);
|
|
}
|
|
|
|
Success = WriteFile(
|
|
OutputFile,
|
|
Buffer,
|
|
strlen(Buffer),
|
|
&BytesWritten,
|
|
NULL
|
|
);
|
|
|
|
if (!Success || (BytesWritten != strlen(Buffer))) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Free profiling resources
|
|
//
|
|
|
|
NtClose(Module->ProfileObject);
|
|
free(Module->ProfileBuffer);
|
|
Module->ProfileObject = NULL;
|
|
Module->ProfileBuffer = NULL;
|
|
Module->ProfileBufferSize = 0;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
PVOID
|
|
MapImage(
|
|
IN HANDLE File,
|
|
OUT PHANDLE Section
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine maps the Dll into our address space so we can look
|
|
up the name and symbols.
|
|
|
|
Arguments:
|
|
|
|
File -- Supplies handle to File to map into memory
|
|
Section -- Returns handle of the file mapping object (section)
|
|
|
|
Return Value:
|
|
|
|
returns NULL if mapping fails.
|
|
Base of mapping otherwise
|
|
|
|
--*/
|
|
{
|
|
HANDLE SectionHandle;
|
|
PVOID MappingBase;
|
|
|
|
//
|
|
// Create the file mapping object to map the Dll
|
|
//
|
|
|
|
SectionHandle = CreateFileMapping(
|
|
File,
|
|
NULL,
|
|
PAGE_READONLY,
|
|
0L,
|
|
0L,
|
|
NULL
|
|
);
|
|
|
|
if (!SectionHandle) {
|
|
*Section = NULL;
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Map the Dll into our Address space
|
|
//
|
|
|
|
MappingBase = MapViewOfFile(
|
|
SectionHandle,
|
|
FILE_MAP_READ,
|
|
0L,
|
|
0L,
|
|
0L
|
|
);
|
|
|
|
if (!MappingBase) {
|
|
*Section = NULL;
|
|
CloseHandle(SectionHandle);
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Return the mapping information
|
|
//
|
|
*Section = SectionHandle;
|
|
return MappingBase;
|
|
}
|
|
|
|
VOID
|
|
UnMapImage(
|
|
IN PVOID MappingBase,
|
|
IN HANDLE Section
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine unmaps a dll from the sprof address space, and closes
|
|
the handle to the section
|
|
|
|
Arguments:
|
|
|
|
MappingBase -- Supplies the linear address of the mapping to remve
|
|
Section -- Supplies the handle to the section.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
UnmapViewOfFile(MappingBase);
|
|
CloseHandle(Section);
|
|
}
|
|
|
|
|
|
COMPAREFUNCTION
|
|
CompareModule32(
|
|
PVOID Data,
|
|
PVOID Key
|
|
)
|
|
{
|
|
return (ULONG)((PMODULE32)Data)->BaseOfImage -
|
|
(ULONG)((PMODULE32)Key)->BaseOfImage;
|
|
}
|
|
|
|
BOOL
|
|
DestroyModule32List(
|
|
PVOID ModuleList
|
|
)
|
|
{
|
|
// bugbug
|
|
return TRUE;
|
|
}
|
|
#if 0
|
|
PVOID
|
|
DllLoaded(
|
|
IN HANDLE Process,
|
|
IN HANDLE Thread,
|
|
IN LPLOAD_DLL_DEBUG_INFO LoadDll,
|
|
IN HANDLE OutputWindow
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine puts the loaded dll into the list
|
|
|
|
Arguments:
|
|
|
|
ProcessId -- Supplies the id of the process this dll was loaded for
|
|
ThreadId -- Supplies the id of the thread this dll was loaded for
|
|
LoadDll -- Supplies the information about the dll that was loaded
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PLOADED_DLL Dll;
|
|
PUCHAR ImageName;
|
|
HANDLE SectionHandle;
|
|
PVOID ImageBase;
|
|
BOOL Success;
|
|
UCHAR StringBuffer[256];
|
|
|
|
//
|
|
// Inialize if we haven't already
|
|
//
|
|
if (!Initialized) {
|
|
InitializeCriticalSection(
|
|
&DllListCriticalSection
|
|
);
|
|
Initialized = TRUE;
|
|
}
|
|
|
|
//
|
|
// Map the image into our address space for name and symbols
|
|
//
|
|
|
|
ImageBase = MapImage(
|
|
LoadDll->hFile,
|
|
&SectionHandle
|
|
);
|
|
|
|
if (!ImageBase) {
|
|
printf("Sprof: could not map image to get name and symbols.\n");
|
|
printf(
|
|
"Sprof: Dll at %lx will be profiled without symbols\n",
|
|
LoadDll->lpBaseOfDll
|
|
);
|
|
}
|
|
|
|
//
|
|
// Get the name of the Image
|
|
//
|
|
|
|
ImageName = GetImageName(ImageBase);
|
|
|
|
if (!ImageName) {
|
|
printf("Sprof: could not get image name.\n");
|
|
}
|
|
|
|
//
|
|
// Allocate a structure for the new dll
|
|
//
|
|
|
|
Dll = malloc(sizeof(LOADED_DLL));
|
|
|
|
//
|
|
// Initialize the structure for the new dll
|
|
//
|
|
|
|
memset(Dll,0,sizeof(LOADED_DLL));
|
|
Dll->DllInfo = *LoadDll;
|
|
Dll->FileMapping = SectionHandle;
|
|
Dll->BaseOfMapping = ImageBase;
|
|
Dll->ImageName = ImageName;
|
|
Dll->OffsetOfCode = GetImageCodeBase(ImageBase);
|
|
Dll->BaseOfCode = Dll->OffsetOfCode + (ULONG)(LoadDll->lpBaseOfDll);
|
|
Dll->SizeOfCode = GetImageCodeSize(ImageBase);
|
|
Dll->Process = Process;
|
|
|
|
|
|
//
|
|
// Put this dll into the list
|
|
//
|
|
|
|
Success = InsertDll(Dll);
|
|
if (!Success) {
|
|
printf(
|
|
"Sprof: could not insert dll %s into loaded dll list\n",
|
|
Dll->ImageName
|
|
);
|
|
}
|
|
|
|
sprintf(StringBuffer,"%s loaded",ImageName);
|
|
PrintToSprofWindow(OutputWindow,StringBuffer);
|
|
|
|
return Dll;
|
|
}
|
|
VOID
|
|
DllUnloaded(
|
|
IN HANDLE Process,
|
|
IN HANDLE Thread,
|
|
IN LPUNLOAD_DLL_DEBUG_INFO UnloadDll,
|
|
IN HANDLE OutputWindow
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine removes the dll from the loaded dll list.
|
|
|
|
Arguments:
|
|
|
|
ProcessId -- Supplies the id of the process the dll was unloaded for
|
|
ThreadId -- Supplies the id of the thead the dll was unloaded for
|
|
UnloadDll -- Supplies the info on the dll being unloaded
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PLOADED_DLL Dll;
|
|
UCHAR StringBuffer[256];
|
|
|
|
//
|
|
// Check to see if we have been initialized yet
|
|
//
|
|
if (!Initialized) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Remove the Dll from the loaded list
|
|
//
|
|
|
|
Dll = RemoveDllByAddress(UnloadDll->lpBaseOfDll);
|
|
|
|
if (!Dll) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Unmap the file
|
|
//
|
|
|
|
UnMapImage(Dll->BaseOfMapping,Dll->FileMapping);
|
|
|
|
//
|
|
// Free up the memory associated with this dll
|
|
//
|
|
|
|
sprintf(StringBuffer, "%s unloaded",Dll->ImageName);
|
|
PrintToSprofWindow(OutputWindow, StringBuffer);
|
|
free(Dll->ImageName);
|
|
free(Dll);
|
|
}
|
|
BOOL
|
|
InsertDll(
|
|
PLOADED_DLL Dll
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine puts a dll into the loaded dll list.
|
|
|
|
Arguments:
|
|
|
|
Dll -- Supplies a pointer to the dll information to insert
|
|
|
|
Return Value:
|
|
|
|
TRUE if the dll is inserted
|
|
FALSE otherwise (probably can't happen)
|
|
|
|
--*/
|
|
{
|
|
PLOADED_DLL CurrentDll;
|
|
|
|
EnterCriticalSection(&DllListCriticalSection);
|
|
|
|
CurrentDll = DllList.Flink;
|
|
|
|
while (CurrentDll->Flink != (PLOADED_DLL)&DllList) {
|
|
if (CurrentDll->DllInfo.lpBaseOfDll < Dll->DllInfo.lpBaseOfDll) {
|
|
break;
|
|
}
|
|
CurrentDll = CurrentDll->Flink;
|
|
}
|
|
|
|
Dll->Flink = CurrentDll->Flink;
|
|
Dll->Blink = CurrentDll;
|
|
CurrentDll->Flink->Blink = Dll;
|
|
CurrentDll->Flink = Dll;
|
|
|
|
LeaveCriticalSection(&DllListCriticalSection);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
PLOADED_DLL
|
|
RemoveDllByAddress(
|
|
PVOID DllBase
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine removes a dll from the loaded list.
|
|
|
|
Arguments:
|
|
|
|
DllBase -- Supplies the base address of the Dll
|
|
|
|
Return Value:
|
|
|
|
pointer to the Dll structure if found, or NULL
|
|
|
|
--*/
|
|
{
|
|
PLOADED_DLL CurrentDll;
|
|
|
|
CurrentDll = DllList.Flink;
|
|
|
|
while (CurrentDll->Flink != (PLOADED_DLL)&DllList) {
|
|
if (CurrentDll->DllInfo.lpBaseOfDll == DllBase) {
|
|
break;
|
|
}
|
|
CurrentDll = CurrentDll->Flink;
|
|
}
|
|
|
|
if (CurrentDll->DllInfo.lpBaseOfDll == DllBase) {
|
|
CurrentDll->Blink->Flink = CurrentDll->Flink;
|
|
CurrentDll->Flink->Blink = CurrentDll->Blink;
|
|
CurrentDll->Flink = NULL;
|
|
CurrentDll->Blink = NULL;
|
|
return CurrentDll;
|
|
} else {
|
|
return NULL;
|
|
}
|
|
}
|
|
PVOID
|
|
EnumerateDll(
|
|
PVOID CurrentDll
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns a pointer to the next dll in the dll chain
|
|
|
|
Arguments:
|
|
|
|
CurrentDll -- Supplies a pointer to the current dll.
|
|
|
|
Return Value:
|
|
|
|
Pointer to the next dll or null
|
|
|
|
--*/
|
|
{
|
|
PLOADED_DLL Dll;
|
|
|
|
if (CurrentDll == NULL) {
|
|
Dll = DllList.Flink;
|
|
} else {
|
|
Dll = ((PLOADED_DLL)CurrentDll)->Flink;
|
|
}
|
|
|
|
if (Dll != (PLOADED_DLL)&DllList) {
|
|
return Dll;
|
|
} else {
|
|
return NULL;
|
|
}
|
|
}
|
|
BOOL
|
|
StartProfileDll(
|
|
PVOID DllHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine starts profiling for the specified dll
|
|
|
|
Arguments:
|
|
|
|
Dll -- Supplies the dll to profile
|
|
|
|
Return Value:
|
|
|
|
True if profiling started
|
|
|
|
--*/
|
|
{
|
|
PLOADED_DLL Dll;
|
|
NTSTATUS Status;
|
|
UCHAR MessageString[80];
|
|
|
|
if (DllHandle == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
Dll = DllHandle;
|
|
if (!Dll->ProfileObject) {
|
|
Dll->ProfileBufferSize = ((Dll->SizeOfCode +
|
|
(1 << (PROFILE_BUCKET_SIZE - 1))) /
|
|
(1 << PROFILE_BUCKET_SIZE)) * sizeof(ULONG);
|
|
Dll->ProfileBuffer = malloc(Dll->ProfileBufferSize);
|
|
|
|
if (!Dll->ProfileBuffer) {
|
|
return FALSE;
|
|
}
|
|
|
|
memset(Dll->ProfileBuffer, 0, Dll->ProfileBufferSize);
|
|
|
|
Status = NtCreateProfile(
|
|
&(Dll->ProfileObject),
|
|
Dll->Process,
|
|
(PVOID)(Dll->BaseOfCode),
|
|
Dll->SizeOfCode,
|
|
PROFILE_BUCKET_SIZE,
|
|
Dll->ProfileBuffer,
|
|
Dll->ProfileBufferSize
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
sprintf(
|
|
MessageString,
|
|
"Failed to create profile object for dll %s, error code %lx",
|
|
Dll->ImageName,
|
|
Status
|
|
);
|
|
MessageBox(
|
|
NULL,
|
|
MessageString,
|
|
"Segmented Profiler",
|
|
MB_ICONSTOP | MB_OK
|
|
);
|
|
|
|
exit(0);
|
|
}
|
|
}
|
|
|
|
Status = NtStartProfile(Dll->ProfileObject);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
sprintf(
|
|
MessageString,
|
|
"Failed to create profile object for dll %s, error code %lx",
|
|
Dll->ImageName,
|
|
Status
|
|
);
|
|
MessageBox(
|
|
NULL,
|
|
MessageString,
|
|
"Segmented Profiler",
|
|
MB_ICONSTOP | MB_OK
|
|
);
|
|
|
|
exit(0);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
BOOL
|
|
StopProfileDll(
|
|
PVOID DllHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine stops profiling for the specified dll
|
|
|
|
Arguments:
|
|
|
|
Dll -- Supplies the dll to profile
|
|
|
|
Return Value:
|
|
|
|
True if profiling stopped
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
if (DllHandle == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
Status = NtStopProfile(((PLOADED_DLL)DllHandle)->ProfileObject);
|
|
//bugbug error handling
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
BOOL
|
|
DumpProfileDll(
|
|
PVOID DllHandle,
|
|
HANDLE OutputFile
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine stops profiling for the specified dll
|
|
|
|
Arguments:
|
|
|
|
Dll -- Supplies the dll to profile
|
|
OutputFile -- Supplies the handle of a file to dump the info to
|
|
|
|
Return Value:
|
|
|
|
True if profiling dumped
|
|
|
|
--*/
|
|
{
|
|
ULONG i,BytesWritten;
|
|
BOOL Success;
|
|
PLOADED_DLL Dll;
|
|
PUCHAR SymbolName = NULL;
|
|
PVOID SymbolAddress = NULL;
|
|
UCHAR Buffer[256];
|
|
|
|
if (DllHandle == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
Dll = DllHandle;
|
|
|
|
sprintf(Buffer, "\nProfile hits for module %s\n\n", Dll->ImageName);
|
|
Success = WriteFile(
|
|
OutputFile,
|
|
Buffer,
|
|
strlen(Buffer),
|
|
&BytesWritten,
|
|
NULL
|
|
);
|
|
|
|
if (!Success || (BytesWritten != strlen(Buffer))) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// dump information for each profile bucket
|
|
//
|
|
for (i = 0;i < (Dll->ProfileBufferSize / sizeof(ULONG)); i++) {
|
|
|
|
//
|
|
// Don't print information for buckets that have no hits
|
|
//
|
|
if (Dll->ProfileBuffer[i] == 0) {
|
|
continue;
|
|
}
|
|
|
|
Success = GetNearestSymbol(
|
|
(i * (1 << PROFILE_BUCKET_SIZE)) + Dll->BaseOfCode,
|
|
Dll->DllInfo.lpBaseOfDll,
|
|
Dll->BaseOfMapping,
|
|
&SymbolName,
|
|
&SymbolAddress
|
|
);
|
|
|
|
if (!Success) {
|
|
sprintf(
|
|
Buffer,
|
|
"%lx hits at +%lx\n",
|
|
Dll->ProfileBuffer[i],
|
|
(ULONG)(1 << PROFILE_BUCKET_SIZE)
|
|
);
|
|
} else {
|
|
sprintf(
|
|
Buffer,
|
|
"%lx hits at %s + %lx\n",
|
|
Dll->ProfileBuffer[i],
|
|
SymbolName,
|
|
Dll->OffsetOfCode + i * (1 << PROFILE_BUCKET_SIZE) -
|
|
(ULONG)SymbolAddress
|
|
);
|
|
}
|
|
|
|
Success = WriteFile(
|
|
OutputFile,
|
|
Buffer,
|
|
strlen(Buffer),
|
|
&BytesWritten,
|
|
NULL
|
|
);
|
|
|
|
if (!Success || (BytesWritten != strlen(Buffer))) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Free profiling resources
|
|
//
|
|
|
|
NtClose(Dll->ProfileObject);
|
|
free(Dll->ProfileBuffer);
|
|
Dll->ProfileObject = NULL;
|
|
Dll->ProfileBuffer = NULL;
|
|
Dll->ProfileBufferSize = 0;
|
|
|
|
return TRUE;
|
|
}
|
|
#endif
|