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.
 
 
 
 
 
 

1028 lines
26 KiB

/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
csrdebug.c
Abstract:
This module implements CSR Debug Services.
Author:
Mark Lucovsky (markl) 02-Apr-1991
Revision History:
--*/
#include "csrsrv.h"
#include "ntrtl.h"
#define WIN32_CONSOLE_APP
#include <windows.h>
#include <ntsdexts.h>
PCSR_PROCESS CsrDebugProcessPtr;
BOOLEAN fWin32ServerDebugger = FALSE;
CLIENT_ID ClientIdWin32ServerDebugger;
PIMAGE_DEBUG_DIRECTORY
CsrpLocateDebugSection(
IN HANDLE ProcessHandle,
IN PVOID Base
);
NTSTATUS
CsrDebugProcess(
IN ULONG TargetProcessId,
IN PCLIENT_ID DebugUserInterface,
IN PCSR_ATTACH_COMPLETE_ROUTINE AttachCompleteRoutine
)
{
PLIST_ENTRY ListHead, ListNext;
PCSR_PROCESS Process;
NTSTATUS Status;
BOOLEAN ProcessFound = FALSE;
HANDLE ProcessHandle;
//
// only allow CSR debugging if it has not been disabled in the
// ntglobalflag
//
if ( TargetProcessId == -1 ) {
if (!(RtlGetNtGlobalFlags() & FLG_ENABLE_CSRDEBUG)) {
KdPrint(( "CSRSRV: CSR Debugging not enabled - NtGlobalFlag == %x\n", RtlGetNtGlobalFlags()));
return STATUS_ACCESS_DENIED;
}
}
//
// Locate the target process
//
AcquireProcessStructureLock();
ListHead = &CsrRootProcess->ListLink;
ListNext = ListHead->Flink;
while (ListNext != ListHead) {
Process = CONTAINING_RECORD( ListNext, CSR_PROCESS, ListLink );
if (Process->ClientId.UniqueProcess == (HANDLE)TargetProcessId
|| (TargetProcessId == -1 && CsrDebugProcessPtr == NULL)
) {
ProcessFound = TRUE;
if ( TargetProcessId == -1 ) {
CsrpServerDebugInitialize = TRUE;
Process = CsrInitializeCsrDebugProcess(NULL);
//
// Mark the process as being debugged
//
Process->DebugFlags = CSR_DEBUG_THIS_PROCESS;
Process->DebugUserInterface = *DebugUserInterface;
fWin32ServerDebugger = TRUE;
ClientIdWin32ServerDebugger = *DebugUserInterface;
}
else {
//
// Mark the process as being debugged
//
Process->DebugFlags = CSR_DEBUG_THIS_PROCESS;
Process->DebugUserInterface = *DebugUserInterface;
Process = CsrInitializeCsrDebugProcess(Process);
}
if ( !Process ) {
ReleaseProcessStructureLock();
return STATUS_NO_MEMORY;
}
CsrSuspendProcess(Process);
if ( TargetProcessId != -1 ) {
//
// Process is being debugged, so set up debug port
//
Status = NtSetInformationProcess(
Process->ProcessHandle,
ProcessDebugPort,
(PVOID)&CsrApiPort,
sizeof(HANDLE)
);
if ( !NT_SUCCESS(Status) ){
CsrResumeProcess(Process);
CsrTeardownCsrDebugProcess(Process);
ReleaseProcessStructureLock();
return Status;
}
}
else {
ProcessHandle = Process->ProcessHandle;
}
break;
}
ListNext = ListNext->Flink;
}
ReleaseProcessStructureLock();
if ( !ProcessFound ) {
return( STATUS_UNSUCCESSFUL );
}
Status = CsrSendProcessAndThreadEvents(Process,AttachCompleteRoutine);
CsrResumeProcess(Process);
CsrTeardownCsrDebugProcess(Process);
CsrpServerDebugInitialize = FALSE;
if ( NT_SUCCESS(Status) ) {
if ( TargetProcessId == -1 ) {
NtSetInformationProcess(
ProcessHandle,
ProcessDebugPort,
(PVOID)&CsrSmApiPort,
sizeof(HANDLE)
);
NtClose(ProcessHandle);
DbgBreakPoint();
}
}
return Status;
}
NTSTATUS
CsrSendProcessAndThreadEvents(
IN PCSR_PROCESS Process,
IN PCSR_ATTACH_COMPLETE_ROUTINE AttachCompleteRoutine
)
/*++
Routine Description:
This procedure sends the create process and create thread
debug events to the debug subsystem.
Arguments:
Process - Supplies the address of the process being debugged.
AttachCompleteRoutine - Supplies the address of the function in the
clients address space that is remote called to cause entry into
the debugger.
Return Value:
None.
--*/
{
PPEB Peb;
NTSTATUS Status;
PROCESS_BASIC_INFORMATION BasicInfo;
PLDR_DATA_TABLE_ENTRY LdrEntry;
LDR_DATA_TABLE_ENTRY LdrEntryData;
PLIST_ENTRY LdrHead,LdrNext;
PPEB_LDR_DATA Ldr;
PLIST_ENTRY ThreadListHead, ThreadListNext;
PCSR_THREAD Thread, FirstThread;
DBGKM_APIMSG m;
PDBGKM_CREATE_THREAD CreateThreadArgs;
PDBGKM_CREATE_PROCESS CreateProcessArgs;
PDBGKM_LOAD_DLL LoadDllArgs;
PVOID ImageBaseAddress;
HANDLE ReplyEvent;
Status = NtCreateEvent(
&ReplyEvent,
EVENT_ALL_ACCESS,
NULL,
SynchronizationEvent,
FALSE
);
if ( !NT_SUCCESS(Status) ) {
return Status;
}
Status = NtQueryInformationProcess(
Process->ProcessHandle,
ProcessBasicInformation,
&BasicInfo,
sizeof(BasicInfo),
NULL
);
if ( !NT_SUCCESS(Status) ) {
goto bail;
}
Peb = BasicInfo.PebBaseAddress;
//
// Ldr = Peb->Ldr
//
Status = NtReadVirtualMemory(
Process->ProcessHandle,
&Peb->Ldr,
&Ldr,
sizeof(Ldr),
NULL
);
if ( !NT_SUCCESS(Status) ) {
goto bail;
}
LdrHead = &Ldr->InLoadOrderModuleList;
//
// LdrNext = Head->Flink;
//
Status = NtReadVirtualMemory(
Process->ProcessHandle,
&LdrHead->Flink,
&LdrNext,
sizeof(LdrNext),
NULL
);
if ( !NT_SUCCESS(Status) ) {
goto bail;
}
if ( LdrNext != LdrHead ) {
//
// This is the entry data for the image.
//
LdrEntry = CONTAINING_RECORD(LdrNext,LDR_DATA_TABLE_ENTRY,InLoadOrderLinks);
Status = NtReadVirtualMemory(
Process->ProcessHandle,
LdrEntry,
&LdrEntryData,
sizeof(LdrEntryData),
NULL
);
if ( !NT_SUCCESS(Status) ) {
goto bail;
}
Status = NtReadVirtualMemory(
Process->ProcessHandle,
&Peb->ImageBaseAddress,
&ImageBaseAddress,
sizeof(ImageBaseAddress),
NULL
);
if ( !NT_SUCCESS(Status) ) {
goto bail;
}
LdrNext = LdrEntryData.InLoadOrderLinks.Flink;
}
else {
LdrEntry = NULL;
}
FirstThread = NULL;
ThreadListHead = &Process->ThreadList;
ThreadListNext = ThreadListHead->Flink;
while (ThreadListNext != ThreadListHead) {
Thread = CONTAINING_RECORD( ThreadListNext, CSR_THREAD, Link );
if ( !FirstThread ) {
FirstThread = Thread;
//
// Send the CreateProcess Message
//
CreateThreadArgs = &m.u.CreateProcessInfo.InitialThread;
CreateThreadArgs->SubSystemKey = 0;
CreateProcessArgs = &m.u.CreateProcessInfo;
CreateProcessArgs->SubSystemKey = 0;
CsrComputeImageInformation(
Process,
&LdrEntryData,
&CreateProcessArgs->BaseOfImage,
&CreateProcessArgs->DebugInfoFileOffset,
&CreateProcessArgs->DebugInfoSize
);
CsrOpenLdrEntry(
FirstThread,
Process,
&LdrEntryData,
&CreateProcessArgs->FileHandle
);
CreateThreadArgs->StartAddress = NULL;
DBGKM_FORMAT_API_MSG(m,DbgKmCreateProcessApi,sizeof(*CreateProcessArgs));
m.h.ClientId = Thread->ClientId;
DbgSsHandleKmApiMsg(&m,ReplyEvent);
Status = NtWaitForSingleObject(ReplyEvent,FALSE,NULL);
if ( !NT_SUCCESS(Status) ) {
goto bail;
}
}
else {
//
// Send the CreateThread Message
//
CreateThreadArgs = &m.u.CreateThread;
CreateThreadArgs->SubSystemKey = 0;
CreateThreadArgs->StartAddress = NULL;
DBGKM_FORMAT_API_MSG(m,DbgKmCreateThreadApi,sizeof(*CreateThreadArgs));
m.h.ClientId = Thread->ClientId;
DbgSsHandleKmApiMsg(&m,ReplyEvent);
Status = NtWaitForSingleObject(ReplyEvent,FALSE,NULL);
if ( !NT_SUCCESS(Status) ) {
goto bail;
}
}
ThreadListNext = ThreadListNext->Flink;
}
//
// Send all of the load module messages
//
while ( LdrNext != LdrHead ) {
LdrEntry = CONTAINING_RECORD(LdrNext,LDR_DATA_TABLE_ENTRY,InLoadOrderLinks);
Status = NtReadVirtualMemory(
Process->ProcessHandle,
LdrEntry,
&LdrEntryData,
sizeof(LdrEntryData),
NULL
);
if ( !NT_SUCCESS(Status) ) {
goto bail;
}
LoadDllArgs = &m.u.LoadDll;
CsrComputeImageInformation(
Process,
&LdrEntryData,
&LoadDllArgs->BaseOfDll,
&LoadDllArgs->DebugInfoFileOffset,
&LoadDllArgs->DebugInfoSize
);
CsrOpenLdrEntry(
FirstThread,
Process,
&LdrEntryData,
&LoadDllArgs->FileHandle
);
if ( LoadDllArgs->FileHandle ) {
DBGKM_FORMAT_API_MSG(m,DbgKmLoadDllApi,sizeof(*LoadDllArgs));
m.h.ClientId = FirstThread->ClientId;
DbgSsHandleKmApiMsg(&m,ReplyEvent);
Status = NtWaitForSingleObject(ReplyEvent,FALSE,NULL);
if ( !NT_SUCCESS(Status) ) {
goto bail;
}
}
LdrNext = LdrEntryData.InLoadOrderLinks.Flink;
}
bail:
NtClose(ReplyEvent);
return Status;
}
VOID
CsrComputeImageInformation(
IN PCSR_PROCESS Process,
IN PLDR_DATA_TABLE_ENTRY LdrEntry,
OUT PVOID *BaseOfImage,
OUT PULONG DebugInfoFileOffset,
OUT PULONG DebugInfoSize
)
/*++
Routine Description:
This function is called to compute the image base and
debug information from a ldr entry.
Arguments:
Process - Supplies the address of the process whose context this
information is to be calculated from.
LdrEntry - Supplies the address of the loader data table entry
whose info is being computed relative to. This pointer is
valid in the callers (current) context.
BaseOfImage - Returns the image's base.
DebugInfoFileOffset - Returns the offset of the debug info.
DebugInfoSize - Returns the size of the debug info.
Return Value:
None.
--*/
{
PIMAGE_DEBUG_DIRECTORY pDebugDir;
IMAGE_DEBUG_DIRECTORY DebugDir;
IMAGE_COFF_SYMBOLS_HEADER DebugInfo;
NTSTATUS Status;
*BaseOfImage = LdrEntry->DllBase;
pDebugDir = CsrpLocateDebugSection(
Process->ProcessHandle,
LdrEntry->DllBase
);
*DebugInfoFileOffset = 0;
*DebugInfoSize = 0;
if ( pDebugDir ) {
Status = NtReadVirtualMemory(
Process->ProcessHandle,
pDebugDir,
&DebugDir,
sizeof(IMAGE_DEBUG_DIRECTORY),
NULL
);
if ( !NT_SUCCESS(Status) ) {
return;
}
Status = NtReadVirtualMemory(
Process->ProcessHandle,
(PVOID)((ULONG)LdrEntry->DllBase + DebugDir.AddressOfRawData),
&DebugInfo,
sizeof(IMAGE_COFF_SYMBOLS_HEADER),
NULL
);
if ( !NT_SUCCESS(Status) ) {
return;
}
*DebugInfoFileOffset = DebugDir.PointerToRawData + DebugInfo.LvaToFirstSymbol;
*DebugInfoSize = DebugInfo.NumberOfSymbols;
}
else {
*DebugInfoFileOffset = 0;
*DebugInfoSize = 0;
}
}
PIMAGE_DEBUG_DIRECTORY
CsrpLocateDebugSection(
IN HANDLE ProcessHandle,
IN PVOID Base
)
{
PVOID ImageHeaderRawData;
PIMAGE_DOS_HEADER DosHeaderRawData;
PIMAGE_NT_HEADERS NtHeaders;
ULONG AllocSize, Addr;
NTSTATUS Status;
//
// Allocate a buffer, and read the image header from the
// target process
//
DosHeaderRawData = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ),
sizeof(IMAGE_DOS_HEADER));
if ( !DosHeaderRawData ) {
return NULL;
}
Status = NtReadVirtualMemory(
ProcessHandle,
Base,
DosHeaderRawData,
sizeof(IMAGE_DOS_HEADER),
NULL
);
AllocSize = DosHeaderRawData->e_lfanew + sizeof(IMAGE_NT_HEADERS);
RtlFreeHeap(RtlProcessHeap(), 0, DosHeaderRawData);
if ( !NT_SUCCESS(Status) ) {
return NULL;
}
ImageHeaderRawData = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), AllocSize);
if ( !ImageHeaderRawData ) {
return NULL;
}
Status = NtReadVirtualMemory(
ProcessHandle,
Base,
ImageHeaderRawData,
AllocSize,
NULL
);
if ( !NT_SUCCESS(Status) ){
RtlFreeHeap(RtlProcessHeap(),0,ImageHeaderRawData);
return NULL;
}
NtHeaders = RtlImageNtHeader(ImageHeaderRawData);
if ( NtHeaders ) {
Addr = (ULONG)NtHeaders->OptionalHeader.DataDirectory
[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;
if ( Addr ) {
Addr += (ULONG)Base;
}
}
else {
Addr = 0;
}
RtlFreeHeap(RtlProcessHeap(),0,ImageHeaderRawData);
return((PIMAGE_DEBUG_DIRECTORY)Addr);
}
VOID
CsrOpenLdrEntry(
IN PCSR_THREAD Thread,
IN PCSR_PROCESS Process,
IN PLDR_DATA_TABLE_ENTRY LdrEntry,
OUT PHANDLE FileHandle
)
/*++
Routine Description:
This function opens a handle to the image/dll file described
by the ldr entry in the context of the specified process.
Arguments:
Thread - Supplies the address of the first thread in the process
Process - Supplies the address of the process whose context this
file is to be opened in.
LdrEntry - Supplies the address of the loader data table entry
whose file is to be opened.
FileHandle - Returns a handle to the associated file
valid in the context of the process being attached to.
Return Value:
None.
--*/
{
UNICODE_STRING DosName;
UNICODE_STRING FileName;
NTSTATUS Status;
OBJECT_ATTRIBUTES Obja;
HANDLE LocalHandle;
IO_STATUS_BLOCK IoStatusBlock;
BOOLEAN TranslationStatus;
NTSTATUS ImpersonationStatus;
HANDLE NewToken;
*FileHandle = NULL;
DosName.Length = LdrEntry->FullDllName.Length;
DosName.MaximumLength = LdrEntry->FullDllName.MaximumLength;
DosName.Buffer = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), DosName.MaximumLength);
if ( !DosName.Buffer ) {
return;
}
Status = NtReadVirtualMemory(
Process->ProcessHandle,
LdrEntry->FullDllName.Buffer,
DosName.Buffer,
DosName.MaximumLength,
NULL
);
if ( !NT_SUCCESS(Status) ) {
RtlFreeHeap(RtlProcessHeap(),0,DosName.Buffer);
return;
}
//
// special case CSR
//
if ( RtlDetermineDosPathNameType_U(DosName.Buffer) == RtlPathTypeRooted ) {
InitializeObjectAttributes(
&Obja,
&DosName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
Status = NtOpenFile(
&LocalHandle,
(ACCESS_MASK)(GENERIC_READ | SYNCHRONIZE),
&Obja,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_SYNCHRONOUS_IO_NONALERT
);
RtlFreeHeap(RtlProcessHeap(),0,DosName.Buffer);
if ( !NT_SUCCESS(Status) ) {
return;
}
//
// The file is open in our context. Dup this to target processes context
// so that dbgss can dup it to the user interface
//
Status = NtDuplicateObject(
NtCurrentProcess(),
LocalHandle,
Process->ProcessHandle,
FileHandle,
0L,
0L,
DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES |
DUPLICATE_CLOSE_SOURCE
);
if ( !NT_SUCCESS(Status) ) {
*FileHandle = NULL;
}
return;
}
TranslationStatus = RtlDosPathNameToNtPathName_U(
DosName.Buffer,
&FileName,
NULL,
NULL
);
if ( !TranslationStatus ) {
RtlFreeHeap(RtlProcessHeap(),0,DosName.Buffer);
return;
}
InitializeObjectAttributes(
&Obja,
&FileName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
Status = NtOpenFile(
&LocalHandle,
(ACCESS_MASK)(GENERIC_READ | SYNCHRONIZE),
&Obja,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_SYNCHRONOUS_IO_NONALERT
);
if ( !NT_SUCCESS(Status) && Thread ) {
ImpersonationStatus = NtImpersonateThread(
NtCurrentThread(),
Thread->ThreadHandle,
&CsrSecurityQos
);
if ( NT_SUCCESS(ImpersonationStatus) ) {
Status = NtOpenFile(
&LocalHandle,
(ACCESS_MASK)(GENERIC_READ | SYNCHRONIZE),
&Obja,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_SYNCHRONOUS_IO_NONALERT
);
NewToken = NULL;
ImpersonationStatus = NtSetInformationThread(
NtCurrentThread(),
ThreadImpersonationToken,
(PVOID)&NewToken,
(ULONG)sizeof(HANDLE)
);
ASSERT( NT_SUCCESS(ImpersonationStatus) );
}
}
RtlFreeHeap(RtlProcessHeap(),0,DosName.Buffer);
RtlFreeHeap(RtlProcessHeap(),0,FileName.Buffer);
if ( !NT_SUCCESS(Status) ) {
return;
}
//
// The file is open in our context. Dup this to target processes context
// so that dbgss can dup it to the user interface
//
Status = NtDuplicateObject(
NtCurrentProcess(),
LocalHandle,
Process->ProcessHandle,
FileHandle,
0L,
0L,
DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES |
DUPLICATE_CLOSE_SOURCE
);
if ( !NT_SUCCESS(Status) ) {
*FileHandle = NULL;
return;
}
}
VOID
CsrSuspendProcess(
IN PCSR_PROCESS Process
)
/*++
Routine Description:
This procedure is called when doing a debug attach to suspend all
threads within the effected process.
Arguments:
Process - Supplies the address of the process to suspend.
Return Value:
None.
--*/
{
PLIST_ENTRY ListHead, ListNext;
PCSR_THREAD Thread;
NTSTATUS Status;
if ( Process == CsrDebugProcessPtr ) {
return;
}
//
// Now walk through the processes thread list and
// suspend all of its threads.
//
ListHead = &Process->ThreadList;
ListNext = ListHead->Flink;
while (ListNext != ListHead) {
Thread = CONTAINING_RECORD( ListNext, CSR_THREAD, Link );
NtSuspendThread(Thread->ThreadHandle,NULL);
ListNext = ListNext->Flink;
}
}
VOID
CsrResumeProcess(
IN PCSR_PROCESS Process
)
/*++
Routine Description:
This procedure is called when doing a debug attach to resume all
threads within the effected process.
Arguments:
Process - Supplies the address of the process to resume.
Return Value:
None.
--*/
{
PLIST_ENTRY ListHead, ListNext;
PCSR_THREAD Thread;
NTSTATUS Status;
if ( Process == CsrDebugProcessPtr ) {
return;
}
//
// Now walk through the processes thread list and
// suspend all of its threads.
//
ListHead = &Process->ThreadList;
ListNext = ListHead->Flink;
while (ListNext != ListHead) {
Thread = CONTAINING_RECORD( ListNext, CSR_THREAD, Link );
NtResumeThread(Thread->ThreadHandle,NULL);
ListNext = ListNext->Flink;
}
}
PCSR_PROCESS
CsrInitializeCsrDebugProcess(
PCSR_PROCESS TargetProcess
)
/*++
Routine Description:
This function is called to build a side process tree to use when
doing debug attaches.
After the attach completes, this structure is torn down.
Arguments:
Process - Supplies the address of the process to attach to. A value of
NULL indicates CSR.
Return Value:
Returns the address of the dummy CSR process.
--*/
{
PCSR_PROCESS Process;
OBJECT_ATTRIBUTES Obja;
PCSR_THREAD Thread;
PLIST_ENTRY ProcessListHead, ProcessListNext;
PLIST_ENTRY ThreadListHead, ThreadListNext;
PCSR_THREAD ThreadPtr;
PCSR_PROCESS ProcessPtr;
THREAD_BASIC_INFORMATION BasicInfo;
NTSTATUS Status;
PCSR_THREAD ServerThread;
Process = RtlAllocateHeap(RtlProcessHeap(),MAKE_TAG( PROCESS_TAG ),sizeof(*Process));
if (!Process) {
return NULL;
}
if ( TargetProcess == NULL ) {
CsrDebugProcessPtr = Process;
InitializeListHead(&Process->ThreadList);
Process->ClientId = NtCurrentTeb()->ClientId;
InitializeObjectAttributes(
&Obja,
NULL,
0,
NULL,
NULL
);
Status = NtOpenProcess(
&Process->ProcessHandle,
PROCESS_ALL_ACCESS,
&Obja,
&Process->ClientId
);
if ( !NT_SUCCESS(Status) ) {
RtlFreeHeap(RtlProcessHeap(),0,Process);
return NULL;
}
//
// Compute the threads. This is cumbersome. First we have to
// locate the static threads, then walk through the entire structure
// looking for threads with associated server threads.
//
ThreadListHead = &CsrRootProcess->ThreadList;
ThreadListNext = ThreadListHead->Flink;
while (ThreadListNext != ThreadListHead) {
ServerThread = CONTAINING_RECORD( ThreadListNext, CSR_THREAD, Link );
Thread = RtlAllocateHeap(RtlProcessHeap(),MAKE_TAG( PROCESS_TAG ),sizeof(*Thread));
if ( Thread ) {
Thread->ClientId = ServerThread->ClientId;
Thread->ThreadHandle = ServerThread->ThreadHandle;
InsertTailList( &Process->ThreadList, &Thread->Link );
}
ThreadListNext = ThreadListNext->Flink;
}
}
else {
//
// Regular non-csr process attach... Just copy the thread and
// process to a new set of structures
//
InitializeListHead(&Process->ThreadList);
Process->ClientId = TargetProcess->ClientId;
Process->ProcessHandle = TargetProcess->ProcessHandle;
ThreadListHead = &TargetProcess->ThreadList;
ThreadListNext = ThreadListHead->Flink;
while (ThreadListNext != ThreadListHead) {
ThreadPtr = CONTAINING_RECORD( ThreadListNext, CSR_THREAD, Link );
Thread = RtlAllocateHeap(RtlProcessHeap(),MAKE_TAG( PROCESS_TAG ),sizeof(*Thread));
if ( Thread ) {
Thread->ThreadHandle = ThreadPtr->ThreadHandle;
Thread->ClientId = ThreadPtr->ClientId;
InsertTailList( &Process->ThreadList, &Thread->Link );
}
ThreadListNext = ThreadListNext->Flink;
}
}
return Process;
}
VOID
CsrTeardownCsrDebugProcess(
PCSR_PROCESS TargetProcess
)
/*++
Routine Description:
This function is called after a debug attach to
a process is complete
It's purpose is to tear down the structure created in the
initialization phase.
Arguments:
TargetProcess - Supplies the address of the process to teardown.
Return Value:
None.
--*/
{
PCSR_PROCESS Process;
PLIST_ENTRY ThreadListHead, ThreadListNext;
PCSR_THREAD ThreadPtr;
NTSTATUS Status;
if ( TargetProcess == CsrDebugProcessPtr ) {
CsrDebugProcessPtr = (PCSR_PROCESS)-1;
}
Process = TargetProcess;
ThreadListHead = &Process->ThreadList;
ThreadListNext = ThreadListHead->Flink;
while (ThreadListNext != ThreadListHead) {
ThreadPtr = CONTAINING_RECORD( ThreadListNext, CSR_THREAD, Link );
ThreadListNext = ThreadListNext->Flink;
RemoveEntryList(&ThreadPtr->Link);
RtlFreeHeap(RtlProcessHeap(),0,ThreadPtr);
}
RtlFreeHeap(RtlProcessHeap(),0,Process);
}