Windows NT 4.0 source code leak
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

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