Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423/* * PROJECT: ReactOS Kernel * LICENSE: GPL - See COPYING in the top level directory * FILE: ntoskrnl/ps/debug.c * PURPOSE: Process Manager: Debugging Support (Set/Get Context) * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) * Thomas Weidenmueller (w3seek@reactos.org) */
/* INCLUDES ****************************************************************/
#include <ntoskrnl.h>#define NDEBUG#include <debug.h>
/* PRIVATE FUNCTIONS *********************************************************/
#if DBGVOIDNTAPIPspDumpThreads(BOOLEAN IncludeSystem){ PLIST_ENTRY CurrentThread, CurrentProcess; PEPROCESS Process; PETHREAD Thread; ULONG nThreads = 0;
/* Loop all Active Processes */ CurrentProcess = PsActiveProcessHead.Flink; while(CurrentProcess != &PsActiveProcessHead) { /* Get the process */ Process = CONTAINING_RECORD(CurrentProcess, EPROCESS, ActiveProcessLinks);
/* Skip the Initial Process if requested */ if((Process != PsInitialSystemProcess) || (Process == PsInitialSystemProcess && IncludeSystem)) { /* Loop all its threads */ CurrentThread = Process->ThreadListHead.Flink; while(CurrentThread != &Process->ThreadListHead) {
/* Get teh Thread */ Thread = CONTAINING_RECORD(CurrentThread, ETHREAD, ThreadListEntry); nThreads++;
/* Print the Info */ DbgPrint("State %u Affinity %08x Priority %d PID.TID %d.%d Name %.8s Stack:\n", Thread->Tcb.State, Thread->Tcb.Affinity, Thread->Tcb.Priority, Thread->Cid.UniqueProcess, Thread->Cid.UniqueThread, Thread->ThreadsProcess->ImageFileName);
/* Make sure it's not running */ if(Thread->Tcb.State == Ready || Thread->Tcb.State == Standby || Thread->Tcb.State == Waiting) {#ifdef _M_IX86 ULONG i = 0; PULONG Esp = (PULONG)Thread->Tcb.KernelStack; PULONG Ebp = (PULONG)Esp[4];
/* Print EBP */ DbgPrint("Ebp %p\n", Ebp);
/* Walk it */ while(Ebp != 0 && Ebp >= (PULONG)Thread->Tcb.StackLimit) { ULONG EbpContent[2]; ULONG MemoryCopied; NTSTATUS Status;
/* Get stack frame content */ Status = KdpCopyMemoryChunks((ULONG64)(ULONG_PTR)Ebp, EbpContent, sizeof(EbpContent), sizeof(EbpContent), MMDBG_COPY_UNSAFE, &MemoryCopied); if (!NT_SUCCESS(Status) || (MemoryCopied < sizeof(EbpContent))) { break; }
DbgPrint("%.8X %.8X%s", EbpContent[0], EbpContent[1], (i % 8) == 7 ? "\n" : " "); Ebp = (PULONG)EbpContent[0]; i++; }
/* Print a new line if there's nothing */ if((i % 8) != 0) DbgPrint("\n");#else DbgPrint("FIXME: Backtrace skipped on non-x86\n");#endif }
/* Move to the next Thread */ CurrentThread = CurrentThread->Flink; } }
/* Move to the next Process */ CurrentProcess = CurrentProcess->Flink; }}#endif
/* PUBLIC FUNCTIONS **********************************************************/
/* * @implemented */NTSTATUSNTAPIPsGetContextThread(IN PETHREAD Thread, IN OUT PCONTEXT ThreadContext, IN KPROCESSOR_MODE PreviousMode){ GET_SET_CTX_CONTEXT GetSetContext; ULONG Size = 0, Flags = 0; NTSTATUS Status;
/* Enter SEH */ _SEH2_TRY { /* Set default length */ Size = sizeof(CONTEXT);
/* Read the flags */ Flags = ProbeForReadUlong(&ThreadContext->ContextFlags);
#ifdef _M_IX86 /* Check if the caller wanted extended registers */ if ((Flags & CONTEXT_EXTENDED_REGISTERS) != CONTEXT_EXTENDED_REGISTERS) { /* Cut them out of the size */ Size = FIELD_OFFSET(CONTEXT, ExtendedRegisters); }#endif
/* Check if we came from user mode */ if (PreviousMode != KernelMode) { /* Probe the context */ ProbeForWrite(ThreadContext, Size, sizeof(ULONG)); } } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Return the exception code */ _SEH2_YIELD(return _SEH2_GetExceptionCode()); } _SEH2_END;
/* Initialize the wait event */ KeInitializeEvent(&GetSetContext.Event, NotificationEvent, FALSE);
/* Set the flags and previous mode */ RtlZeroMemory(&GetSetContext.Context, Size); GetSetContext.Context.ContextFlags = Flags; GetSetContext.Mode = PreviousMode;
/* Check if we're running in the same thread */ if (Thread == PsGetCurrentThread()) { /* Setup APC parameters manually */ GetSetContext.Apc.SystemArgument1 = NULL; GetSetContext.Apc.SystemArgument2 = Thread;
/* Enter a guarded region to simulate APC_LEVEL */ KeEnterGuardedRegion();
/* Manually call the APC */ PspGetOrSetContextKernelRoutine(&GetSetContext.Apc, NULL, NULL, &GetSetContext.Apc.SystemArgument1, &GetSetContext.Apc.SystemArgument2);
/* Leave the guarded region */ KeLeaveGuardedRegion();
/* We are done */ Status = STATUS_SUCCESS; } else { /* Initialize the APC */ KeInitializeApc(&GetSetContext.Apc, &Thread->Tcb, OriginalApcEnvironment, PspGetOrSetContextKernelRoutine, NULL, NULL, KernelMode, NULL);
/* Queue it as a Get APC */ if (!KeInsertQueueApc(&GetSetContext.Apc, NULL, Thread, 2)) { /* It was already queued, so fail */ Status = STATUS_UNSUCCESSFUL; } else { /* Wait for the APC to complete */ Status = KeWaitForSingleObject(&GetSetContext.Event, 0, KernelMode, FALSE, NULL); } }
_SEH2_TRY { /* Copy the context */ RtlCopyMemory(ThreadContext, &GetSetContext.Context, Size); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Get the exception code */ Status = _SEH2_GetExceptionCode(); } _SEH2_END;
/* Return status */ return Status;}
/* * @implemented */NTSTATUSNTAPIPsSetContextThread(IN PETHREAD Thread, IN OUT PCONTEXT ThreadContext, IN KPROCESSOR_MODE PreviousMode){ GET_SET_CTX_CONTEXT GetSetContext; ULONG Size = 0, Flags = 0; NTSTATUS Status;
/* Enter SEH */ _SEH2_TRY { /* Set default length */ Size = sizeof(CONTEXT);
/* Read the flags */ Flags = ProbeForReadUlong(&ThreadContext->ContextFlags);
#ifdef _M_IX86 /* Check if the caller wanted extended registers */ if ((Flags & CONTEXT_EXTENDED_REGISTERS) != CONTEXT_EXTENDED_REGISTERS) { /* Cut them out of the size */ Size = FIELD_OFFSET(CONTEXT, ExtendedRegisters); }#endif
/* Check if we came from user mode */ if (PreviousMode != KernelMode) { /* Probe the context */ ProbeForRead(ThreadContext, Size, sizeof(ULONG)); }
/* Copy the context */ RtlCopyMemory(&GetSetContext.Context, ThreadContext, Size); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Return the exception code */ _SEH2_YIELD(return _SEH2_GetExceptionCode()); } _SEH2_END;
/* Initialize the wait event */ KeInitializeEvent(&GetSetContext.Event, NotificationEvent, FALSE);
/* Set the flags and previous mode */ GetSetContext.Context.ContextFlags = Flags; GetSetContext.Mode = PreviousMode;
/* Check if we're running in the same thread */ if (Thread == PsGetCurrentThread()) { /* Setup APC parameters manually */ GetSetContext.Apc.SystemArgument1 = UlongToPtr(1); GetSetContext.Apc.SystemArgument2 = Thread;
/* Enter a guarded region to simulate APC_LEVEL */ KeEnterGuardedRegion();
/* Manually call the APC */ PspGetOrSetContextKernelRoutine(&GetSetContext.Apc, NULL, NULL, &GetSetContext.Apc.SystemArgument1, &GetSetContext.Apc.SystemArgument2);
/* Leave the guarded region */ KeLeaveGuardedRegion();
/* We are done */ Status = STATUS_SUCCESS; } else { /* Initialize the APC */ KeInitializeApc(&GetSetContext.Apc, &Thread->Tcb, OriginalApcEnvironment, PspGetOrSetContextKernelRoutine, NULL, NULL, KernelMode, NULL);
/* Queue it as a Get APC */ if (!KeInsertQueueApc(&GetSetContext.Apc, UlongToPtr(1), Thread, 2)) { /* It was already queued, so fail */ Status = STATUS_UNSUCCESSFUL; } else { /* Wait for the APC to complete */ Status = KeWaitForSingleObject(&GetSetContext.Event, 0, KernelMode, FALSE, NULL); } }
/* Return status */ return Status;}
NTSTATUSNTAPINtGetContextThread(IN HANDLE ThreadHandle, IN OUT PCONTEXT ThreadContext){ PETHREAD Thread; NTSTATUS Status; KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); PAGED_CODE();
/* Get the Thread Object */ Status = ObReferenceObjectByHandle(ThreadHandle, THREAD_GET_CONTEXT, PsThreadType, PreviousMode, (PVOID*)&Thread, NULL);
if (!NT_SUCCESS(Status)) return Status;
/* Make sure it's not a system thread */ if (Thread->SystemThread) { /* Fail */ Status = STATUS_INVALID_HANDLE; } else { /* Call the kernel API */ Status = PsGetContextThread(Thread, ThreadContext, PreviousMode); }
/* Dereference it and return */ ObDereferenceObject(Thread); return Status;}
NTSTATUSNTAPINtSetContextThread(IN HANDLE ThreadHandle, IN PCONTEXT ThreadContext){ PETHREAD Thread; NTSTATUS Status; KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); PAGED_CODE();
/* Get the Thread Object */ Status = ObReferenceObjectByHandle(ThreadHandle, THREAD_SET_CONTEXT, PsThreadType, PreviousMode, (PVOID*)&Thread, NULL);
if (!NT_SUCCESS(Status)) return Status;
/* Make sure it's not a system thread */ if (Thread->SystemThread) { /* Fail */ Status = STATUS_INVALID_HANDLE; } else { /* Call the kernel API */ Status = PsSetContextThread(Thread, ThreadContext, PreviousMode); }
/* Dereference it and return */ ObDereferenceObject(Thread); return Status;}
/* EOF */