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.
 
 
 
 
 
 

487 lines
11 KiB

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
Debug.c
Abstract:
This module routes debug events to the appropriate handlers
Author:
Dave Hastings (daveh) 30-Oct-1992
Revision History:
--*/
#include "sprofp.h"
#include "process.h"
struct _MyDebugInfo {
PUCHAR CommandLine;
ULONG Pid;
ULONG CreateFlags;
HANDLE OutputWindow;
} MyDebugInfo;
ULONG gProcessId = 0;
PVOID ProcessList = NULL;
PVOID ModuleList = NULL;
BOOL Profiling = FALSE;
extern ULONG DefaultProfileInterval;
ULONG
ComparePid(
PVOID Data,
PVOID Key
);
ULONG
CompareTid(
PVOID Data,
PVOID Key
);
HANDLE
StartDebugProcessing(
HANDLE OutputWindow,
PUCHAR CommandLine,
ULONG Pid,
ULONG CreateFlags
)
/*++
Routine Description:
This routine starts the processing of debug events. It creates a
thread to field debug event and create the appropriate process.
Arguments:
OutputWindow -- Supplies the handle of the window to output to
CommandLine -- Supplies optional command line to start
Pid -- Supplies optional process id to attach to
Return Value:
handle of thread created
--*/
{
ULONG ThreadId;
MyDebugInfo.CommandLine = CommandLine;
MyDebugInfo.Pid = Pid;
MyDebugInfo.CreateFlags = CreateFlags;
MyDebugInfo.OutputWindow = OutputWindow;
return CreateThread(
NULL,
0,
ProcessDebugEvents,
&MyDebugInfo,
0,
&ThreadId
);
}
ULONG
ProcessDebugEvents(
PVOID Parameters
)
/*++
Routine Description:
This routine handles debug events, and routes them to the appropriate
place
Arguments:
None.
Return Value:
None.
--*/
{
DEBUG_EVENT DebugEvent;
ULONG DebugResult;
HANDLE OutputWindow;
PVOID Process, Thread;
PVOID ThreadList;
PVOID Module;
OutputWindow = ((struct _MyDebugInfo *)Parameters)->OutputWindow;
// ModuleList = InitMod16(OutputWindow);
if (((struct _MyDebugInfo *)Parameters)->Pid) {
//
// Connect to an existing process
//
if (!DebugActiveProcess(((struct _MyDebugInfo *)Parameters)->Pid)) {
printf(
"Sprof: could not attach to process %lx, error %lx\n",
((struct _MyDebugInfo *)Parameters)->Pid,
GetLastError()
);
exit(-1);
}
} else {
PROCESS_INFORMATION ProcessInfo;
STARTUPINFO StartupInfo;
//
// Create the process to profile
//
StartupInfo.cb = sizeof(STARTUPINFO);
StartupInfo.lpReserved = NULL;
StartupInfo.lpDesktop = NULL;
StartupInfo.lpTitle = NULL;
StartupInfo.dwFlags = 0L;
StartupInfo.cbReserved2 = 0;
StartupInfo.lpReserved2 = NULL;
if (!
CreateProcess(
NULL, // no image file name
((struct _MyDebugInfo *)Parameters)->CommandLine, // command line from ParseArg..
NULL, // no process security
NULL, // no thread security
FALSE, // don't inherit handles
((struct _MyDebugInfo *)Parameters)->CreateFlags, // creation flags from Parse...
NULL, // use current env
NULL, // use current cd
&StartupInfo,
&ProcessInfo
)
) {
printf(
"Sprof: could not create process %s, error %lx\n",
((struct _MyDebugInfo *)Parameters)->CommandLine,
GetLastError()
);
exit(-1);
}
//
// Close the handles from create process, because we will get
// another set in the first debug event
//
CloseHandle(ProcessInfo.hProcess);
CloseHandle(ProcessInfo.hThread);
}
//
// Create a process list
//
ProcessList = CreateProcessList();
//
// Process Debug Events
//
while (1) {
if (!WaitForDebugEvent(&DebugEvent,INFINITE)) {
MessageBox(
OutputWindow,
"The profiler could not wait for debug events.",
"Segmented Profiler",
MB_ICONSTOP | MB_OK
);
printf(
"Sprof: could not wait for debug event, error %lx\n",
GetLastError()
);
exit(-1);
}
switch (DebugEvent.dwDebugEventCode) {
case CREATE_PROCESS_DEBUG_EVENT:
CreateProcessO(
ProcessList,
DebugEvent.dwProcessId,
DebugEvent.dwThreadId,
&(DebugEvent.u.CreateProcessInfo),
OutputWindow // bugbug
);
gProcessId = DebugEvent.dwProcessId;
DebugResult = DBG_CONTINUE;
break;
case CREATE_THREAD_DEBUG_EVENT:
Process = GetProcess(
ProcessList,
DebugEvent.dwProcessId
);
CreateThreadO(
GetProcessThreadList(ProcessList, Process),
DebugEvent.dwThreadId,
&(DebugEvent.u.CreateThread)
);
DebugResult = DBG_CONTINUE;
break;
case EXCEPTION_DEBUG_EVENT :
switch (DebugEvent.u.Exception.ExceptionRecord.ExceptionCode) {
case EXCEPTION_BREAKPOINT:
DebugResult = DBG_CONTINUE;
break;
case STATUS_VDM_EVENT:
//
// Look up the process
//
Process = GetProcess(ProcessList, DebugEvent.dwProcessId);
//
// Look up thread
//
ThreadList = GetProcessThreadList(ProcessList, Process);
Thread = GetThread(
ThreadList,
DebugEvent.dwThreadId
);
if (HandleVdmDebugEvent(
&DebugEvent,
GetProcessHandle(ProcessList, Process),
GetThreadHandle(ThreadList, Thread),
GetProcessModule16List(ProcessList, Process),
OutputWindow
)
) {
DebugResult = DBG_CONTINUE;
} else {
DebugResult = DBG_EXCEPTION_NOT_HANDLED;
}
break;
}
break;
case LOAD_DLL_DEBUG_EVENT :
//
// Look up the process
//
Process = GetProcess(ProcessList, DebugEvent.dwProcessId);
Module = CreateModule32(
GetProcessModule32List(ProcessList, Process),
GetProcessHandle(ProcessList, Process),
&DebugEvent.u.LoadDll,
OutputWindow
);
if (Profiling) {
StartProfileModule32(
GetProcessModule32List(ProcessList, Process),
Module
);
}
DebugResult = DBG_CONTINUE;
break;
case UNLOAD_DLL_DEBUG_EVENT :
//
// Look up the process
//
Process = GetProcess(ProcessList, DebugEvent.dwProcessId);
//
// Find the module
//
Module = GetModule32(
GetProcessModule32List(ProcessList, Process),
DebugEvent.u.UnloadDll.lpBaseOfDll
);
DestroyModule32(
GetProcessModule32List(ProcessList, Process),
Module,
OutputWindow
);
DebugResult = DBG_CONTINUE;
break;
default:
DebugResult = DBG_EXCEPTION_NOT_HANDLED;
}
if (!
ContinueDebugEvent(
DebugEvent.dwProcessId,
DebugEvent.dwThreadId,
DebugResult
)
) {
printf(
"Sprof: could not continue debug event, error %lx\n",
GetLastError()
);
return 1;
}
}
}
BOOL
StartProfiling(
VOID
)
/*++
Routine Description:
This routine starts profiling for all dlls
Arguments:
None
Return Value:
TRUE if profiling successfully started
--*/
{
PVOID CurrentModule;
PVOID ModuleList;
//
// This is the interval the rtl profile stuff uses
//
NtSetIntervalProfile(DefaultProfileInterval,ProfileTime);
ModuleList = GetProcessModule32List(
ProcessList,
GetProcess(ProcessList, gProcessId)
);
Profiling = TRUE;
CurrentModule = NULL;
while (CurrentModule = EnumerateModule32(ModuleList, CurrentModule)) {
if (!StartProfileModule32(ModuleList, CurrentModule)) {
return FALSE;
}
}
ModuleList = GetProcessModule16List(
ProcessList,
GetProcess(ProcessList, gProcessId)
);
return StartProfile16(ModuleList, GetProcessHandle(ProcessList, GetProcess(ProcessList,gProcessId)));
}
BOOL
StopProfiling(
VOID
)
/*++
Routine Description:
This routine stops profiling for all dlls
Arguments:
None
Return Value:
TRUE if profiling successfully stopped
--*/
{
PVOID CurrentModule;
PVOID ModuleList;
ModuleList = GetProcessModule32List(
ProcessList,
GetProcess(ProcessList, gProcessId)
);
Profiling = FALSE;
CurrentModule = NULL;
while (CurrentModule = EnumerateModule32(ModuleList, CurrentModule)) {
if (!StopProfileModule32(ModuleList, CurrentModule)) {
return FALSE;
}
}
ModuleList = GetProcessModule16List(
ProcessList,
GetProcess(ProcessList, gProcessId)
);
return StopProfile16(ModuleList);
}
BOOL
DumpProfiling(
HANDLE ProfileFile
)
/*++
Routine Description:
This routine dumps the profile information for all dlls
Arguments:
None
Return Value:
TRUE if profiling successfully dumped
--*/
{
PVOID CurrentModule;
PVOID ModuleList;
ModuleList = GetProcessModule32List(
ProcessList,
GetProcess(ProcessList, gProcessId)
);
CurrentModule = NULL;
while (CurrentModule = EnumerateModule32(ModuleList, CurrentModule)) {
if (!DumpProfileModule32(ModuleList, CurrentModule, ProfileFile)) {
return FALSE;
}
}
ModuleList = GetProcessModule16List(
ProcessList,
GetProcess(ProcessList, gProcessId)
);
DumpProfile16(ModuleList, ProfileFile);
return TRUE;
}