/* * PROJECT: ReactOS Kernel * LICENSE: GPL - See COPYING in the top level directory * FILE: ntoskrnl/dbgk/dbgkutil.c * PURPOSE: User-Mode Debugging Support, Internal Debug Functions. * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) */ /* INCLUDES ******************************************************************/ #include #define NDEBUG #include /* FUNCTIONS *****************************************************************/ HANDLE NTAPI DbgkpSectionToFileHandle(IN PVOID Section) { NTSTATUS Status; POBJECT_NAME_INFORMATION FileName; OBJECT_ATTRIBUTES ObjectAttributes; IO_STATUS_BLOCK IoStatusBlock; HANDLE Handle; PAGED_CODE(); /* Get the filename of the section */ Status = MmGetFileNameForSection(Section, &FileName); if (!NT_SUCCESS(Status)) return NULL; /* Initialize object attributes */ InitializeObjectAttributes(&ObjectAttributes, &FileName->Name, OBJ_CASE_INSENSITIVE | OBJ_FORCE_ACCESS_CHECK | OBJ_KERNEL_HANDLE, NULL, NULL); /* Open the file */ Status = ZwOpenFile(&Handle, GENERIC_READ | SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT); /* Free the name and return the handle if we succeeded */ ExFreePool(FileName); if (!NT_SUCCESS(Status)) return NULL; return Handle; } BOOLEAN NTAPI DbgkpSuspendProcess(VOID) { PAGED_CODE(); /* Make sure this isn't a deleted process */ if (!PsGetCurrentProcess()->ProcessDelete) { /* Freeze all the threads */ KeFreezeAllThreads(); return TRUE; } else { /* No suspend was done */ return FALSE; } } VOID NTAPI DbgkpResumeProcess(VOID) { PAGED_CODE(); /* Thaw all the threads */ KeThawAllThreads(); } VOID NTAPI DbgkCreateThread(IN PETHREAD Thread, IN PVOID StartAddress) { PEPROCESS Process = PsGetCurrentProcess(); ULONG ProcessFlags; IMAGE_INFO ImageInfo; PIMAGE_NT_HEADERS NtHeader; POBJECT_NAME_INFORMATION ModuleName; UNICODE_STRING NtDllName; NTSTATUS Status; PVOID DebugPort; DBGKM_MSG ApiMessage; PDBGKM_CREATE_THREAD CreateThread = &ApiMessage.CreateThread; PDBGKM_CREATE_PROCESS CreateProcess = &ApiMessage.CreateProcess; PDBGKM_LOAD_DLL LoadDll = &ApiMessage.LoadDll; OBJECT_ATTRIBUTES ObjectAttributes; IO_STATUS_BLOCK IoStatusBlock; PTEB Teb; PAGED_CODE(); /* Sanity check */ ASSERT(Thread == PsGetCurrentThread()); /* Try ORing in the create reported and image notify flags */ ProcessFlags = PspSetProcessFlag(Process, PSF_CREATE_REPORTED_BIT | PSF_IMAGE_NOTIFY_DONE_BIT); /* Check if we were the first to set them or if another thread raced us */ if (!(ProcessFlags & PSF_IMAGE_NOTIFY_DONE_BIT) && (PsImageNotifyEnabled)) { /* It hasn't.. set up the image info for the process */ ImageInfo.Properties = 0; ImageInfo.ImageAddressingMode = IMAGE_ADDRESSING_MODE_32BIT; ImageInfo.ImageBase = Process->SectionBaseAddress; ImageInfo.ImageSize = 0; ImageInfo.ImageSelector = 0; ImageInfo.ImageSectionNumber = 0; /* Get the NT Headers */ NtHeader = RtlImageNtHeader(Process->SectionBaseAddress); if (NtHeader) { /* Set image size */ ImageInfo.ImageSize = NtHeader->OptionalHeader.SizeOfImage; } /* Get the image name */ Status = MmGetFileNameForSection(Process->SectionObject, &ModuleName); if (NT_SUCCESS(Status)) { /* Call the notify routines and free the name */ PspRunLoadImageNotifyRoutines(&ModuleName->Name, Process->UniqueProcessId, &ImageInfo); ExFreePool(ModuleName); } else { /* Call the notify routines */ PspRunLoadImageNotifyRoutines(NULL, Process->UniqueProcessId, &ImageInfo); } /* Setup the info for ntdll.dll */ ImageInfo.Properties = 0; ImageInfo.ImageAddressingMode = IMAGE_ADDRESSING_MODE_32BIT; ImageInfo.ImageBase = PspSystemDllBase; ImageInfo.ImageSize = 0; ImageInfo.ImageSelector = 0; ImageInfo.ImageSectionNumber = 0; /* Get the NT Headers */ NtHeader = RtlImageNtHeader(PspSystemDllBase); if (NtHeader) { /* Set image size */ ImageInfo.ImageSize = NtHeader->OptionalHeader.SizeOfImage; } /* Call the notify routines */ RtlInitUnicodeString(&NtDllName, L"\\SystemRoot\\System32\\ntdll.dll"); PspRunLoadImageNotifyRoutines(&NtDllName, Process->UniqueProcessId, &ImageInfo); } /* Fail if we have no port */ DebugPort = Process->DebugPort; if (!DebugPort) return; /* Check if create was not already reported */ if (!(ProcessFlags & PSF_CREATE_REPORTED_BIT)) { /* Setup the information structure for the new thread */ CreateProcess->InitialThread.SubSystemKey = 0; CreateProcess->InitialThread.StartAddress = NULL; /* And for the new process */ CreateProcess->SubSystemKey = 0; CreateProcess->FileHandle = DbgkpSectionToFileHandle(Process-> SectionObject); CreateProcess->BaseOfImage = Process->SectionBaseAddress; CreateProcess->DebugInfoFileOffset = 0; CreateProcess->DebugInfoSize = 0; /* Get the NT Header */ NtHeader = RtlImageNtHeader(Process->SectionBaseAddress); if (NtHeader) { /* Fill out data from the header */ CreateProcess->InitialThread.StartAddress = (PVOID)((ULONG_PTR)NtHeader->OptionalHeader.ImageBase + NtHeader->OptionalHeader.AddressOfEntryPoint); CreateProcess->DebugInfoFileOffset = NtHeader->FileHeader. PointerToSymbolTable; CreateProcess->DebugInfoSize = NtHeader->FileHeader. NumberOfSymbols; } /* Setup the API Message */ ApiMessage.h.u1.Length = sizeof(DBGKM_MSG) << 16 | (8 + sizeof(DBGKM_CREATE_PROCESS)); ApiMessage.h.u2.ZeroInit = 0; ApiMessage.h.u2.s2.Type = LPC_DEBUG_EVENT; ApiMessage.ApiNumber = DbgKmCreateProcessApi; /* Send the message */ DbgkpSendApiMessage(&ApiMessage, FALSE); /* Close the handle */ ObCloseHandle(CreateProcess->FileHandle, KernelMode); /* Setup the parameters */ LoadDll->BaseOfDll = PspSystemDllBase; LoadDll->DebugInfoFileOffset = 0; LoadDll->DebugInfoSize = 0; LoadDll->NamePointer = NULL; /* Get the NT Headers */ NtHeader = RtlImageNtHeader(PspSystemDllBase); if (NtHeader) { /* Fill out debug information */ LoadDll->DebugInfoFileOffset = NtHeader-> FileHeader.PointerToSymbolTable; LoadDll->DebugInfoSize = NtHeader->FileHeader.NumberOfSymbols; } /* Get the TEB */ Teb = Thread->Tcb.Teb; if (Teb) { /* Copy the system library name and link to it */ wcsncpy(Teb->StaticUnicodeBuffer, L"ntdll.dll", sizeof(Teb->StaticUnicodeBuffer) / sizeof(WCHAR)); Teb->NtTib.ArbitraryUserPointer = Teb->StaticUnicodeBuffer; /* Return it in the debug event as well */ LoadDll->NamePointer = &Teb->NtTib.ArbitraryUserPointer; } /* Get a handle */ InitializeObjectAttributes(&ObjectAttributes, &PsNtDllPathName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE | OBJ_FORCE_ACCESS_CHECK, NULL, NULL); Status = ZwOpenFile(&LoadDll->FileHandle, GENERIC_READ | SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT); if (NT_SUCCESS(Status)) { /* Setup the API Message */ ApiMessage.h.u1.Length = sizeof(DBGKM_MSG) << 16 | (8 + sizeof(DBGKM_LOAD_DLL)); ApiMessage.h.u2.ZeroInit = 0; ApiMessage.h.u2.s2.Type = LPC_DEBUG_EVENT; ApiMessage.ApiNumber = DbgKmLoadDllApi; /* Send the message */ DbgkpSendApiMessage(&ApiMessage, TRUE); /* Close the handle */ ObCloseHandle(LoadDll->FileHandle, KernelMode); } } else { /* Otherwise, do it just for the thread */ CreateThread->SubSystemKey = 0; CreateThread->StartAddress = StartAddress; /* Setup the API Message */ ApiMessage.h.u1.Length = sizeof(DBGKM_MSG) << 16 | (8 + sizeof(DBGKM_CREATE_THREAD)); ApiMessage.h.u2.ZeroInit = 0; ApiMessage.h.u2.s2.Type = LPC_DEBUG_EVENT; ApiMessage.ApiNumber = DbgKmCreateThreadApi; /* Send the message */ DbgkpSendApiMessage(&ApiMessage, TRUE); } } VOID NTAPI DbgkExitProcess(IN NTSTATUS ExitStatus) { DBGKM_MSG ApiMessage; PDBGKM_EXIT_PROCESS ExitProcess = &ApiMessage.ExitProcess; PEPROCESS Process = PsGetCurrentProcess(); PETHREAD Thread = PsGetCurrentThread(); PAGED_CODE(); /* Check if this thread is hidden, doesn't have a debug port, or died */ if ((Thread->HideFromDebugger) || !(Process->DebugPort) || (Thread->DeadThread)) { /* Don't notify the debugger */ return; } /* Set the exit status */ ExitProcess->ExitStatus = ExitStatus; /* Setup the API Message */ ApiMessage.h.u1.Length = sizeof(DBGKM_MSG) << 16 | (8 + sizeof(DBGKM_EXIT_PROCESS)); ApiMessage.h.u2.ZeroInit = 0; ApiMessage.h.u2.s2.Type = LPC_DEBUG_EVENT; ApiMessage.ApiNumber = DbgKmExitProcessApi; /* Set the current exit time */ KeQuerySystemTime(&Process->ExitTime); /* Send the message */ DbgkpSendApiMessage(&ApiMessage, FALSE); } VOID NTAPI DbgkExitThread(IN NTSTATUS ExitStatus) { DBGKM_MSG ApiMessage; PDBGKM_EXIT_THREAD ExitThread = &ApiMessage.ExitThread; PEPROCESS Process = PsGetCurrentProcess(); PETHREAD Thread = PsGetCurrentThread(); BOOLEAN Suspended; PAGED_CODE(); /* Check if this thread is hidden, doesn't have a debug port, or died */ if ((Thread->HideFromDebugger) || !(Process->DebugPort) || (Thread->DeadThread)) { /* Don't notify the debugger */ return; } /* Set the exit status */ ExitThread->ExitStatus = ExitStatus; /* Setup the API Message */ ApiMessage.h.u1.Length = sizeof(DBGKM_MSG) << 16 | (8 + sizeof(DBGKM_EXIT_THREAD)); ApiMessage.h.u2.ZeroInit = 0; ApiMessage.h.u2.s2.Type = LPC_DEBUG_EVENT; ApiMessage.ApiNumber = DbgKmExitThreadApi; /* Suspend the process */ Suspended = DbgkpSuspendProcess(); /* Send the message */ DbgkpSendApiMessage(&ApiMessage, FALSE); /* Resume the process if needed */ if (Suspended) DbgkpResumeProcess(); } VOID NTAPI DbgkMapViewOfSection(IN PVOID Section, IN PVOID BaseAddress, IN ULONG SectionOffset, IN ULONG_PTR ViewSize) { DBGKM_MSG ApiMessage; PDBGKM_LOAD_DLL LoadDll = &ApiMessage.LoadDll; PEPROCESS Process = PsGetCurrentProcess(); PETHREAD Thread = PsGetCurrentThread(); PIMAGE_NT_HEADERS NtHeader; PAGED_CODE(); DBGKTRACE(DBGK_PROCESS_DEBUG, "Section: %p. Base: %p\n", Section, BaseAddress); /* Check if this thread is kernel, hidden or doesn't have a debug port */ if ((ExGetPreviousMode() == KernelMode) || (Thread->HideFromDebugger) || !(Process->DebugPort)) { /* Don't notify the debugger */ return; } /* Setup the parameters */ LoadDll->FileHandle = DbgkpSectionToFileHandle(Section); LoadDll->BaseOfDll = BaseAddress; LoadDll->DebugInfoFileOffset = 0; LoadDll->DebugInfoSize = 0; LoadDll->NamePointer = &NtCurrentTeb()->NtTib.ArbitraryUserPointer; /* Get the NT Headers */ NtHeader = RtlImageNtHeader(BaseAddress); if (NtHeader) { /* Fill out debug information */ LoadDll->DebugInfoFileOffset = NtHeader->FileHeader. PointerToSymbolTable; LoadDll->DebugInfoSize = NtHeader->FileHeader.NumberOfSymbols; } /* Setup the API Message */ ApiMessage.h.u1.Length = sizeof(DBGKM_MSG) << 16 | (8 + sizeof(DBGKM_LOAD_DLL)); ApiMessage.h.u2.ZeroInit = 0; ApiMessage.h.u2.s2.Type = LPC_DEBUG_EVENT; ApiMessage.ApiNumber = DbgKmLoadDllApi; /* Send the message */ DbgkpSendApiMessage(&ApiMessage, TRUE); /* Close the handle */ ObCloseHandle(LoadDll->FileHandle, KernelMode); } VOID NTAPI DbgkUnMapViewOfSection(IN PVOID BaseAddress) { DBGKM_MSG ApiMessage; PDBGKM_UNLOAD_DLL UnloadDll = &ApiMessage.UnloadDll; PEPROCESS Process = PsGetCurrentProcess(); PETHREAD Thread = PsGetCurrentThread(); PAGED_CODE(); /* Check if this thread is kernel, hidden or doesn't have a debug port */ if ((ExGetPreviousMode() == KernelMode) || (Thread->HideFromDebugger) || !(Process->DebugPort)) { /* Don't notify the debugger */ return; } /* Set the DLL Base */ UnloadDll->BaseAddress = BaseAddress; /* Setup the API Message */ ApiMessage.h.u1.Length = sizeof(DBGKM_MSG) << 16 | (8 + sizeof(DBGKM_UNLOAD_DLL)); ApiMessage.h.u2.ZeroInit = 0; ApiMessage.h.u2.s2.Type = LPC_DEBUG_EVENT; ApiMessage.ApiNumber = DbgKmUnloadDllApi; /* Send the message */ DbgkpSendApiMessage(&ApiMessage, TRUE); }