1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/ps/debug.c 5 * PURPOSE: Process Manager: Debugging Support (Set/Get Context) 6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7 * Thomas Weidenmueller (w3seek@reactos.org) 8 */ 9 10 /* INCLUDES ****************************************************************/ 11 12 #include <ntoskrnl.h> 13 #define NDEBUG 14 #include <debug.h> 15 16 /* PRIVATE FUNCTIONS *********************************************************/ 17 18 #if DBG 19 VOID 20 NTAPI 21 PspDumpThreads(BOOLEAN IncludeSystem) 22 { 23 PLIST_ENTRY CurrentThread, CurrentProcess; 24 PEPROCESS Process; 25 PETHREAD Thread; 26 ULONG nThreads = 0; 27 28 /* Loop all Active Processes */ 29 CurrentProcess = PsActiveProcessHead.Flink; 30 while(CurrentProcess != &PsActiveProcessHead) 31 { 32 /* Get the process */ 33 Process = CONTAINING_RECORD(CurrentProcess, EPROCESS, ActiveProcessLinks); 34 35 /* Skip the Initial Process if requested */ 36 if((Process != PsInitialSystemProcess) || 37 (Process == PsInitialSystemProcess && IncludeSystem)) 38 { 39 /* Loop all its threads */ 40 CurrentThread = Process->ThreadListHead.Flink; 41 while(CurrentThread != &Process->ThreadListHead) 42 { 43 44 /* Get teh Thread */ 45 Thread = CONTAINING_RECORD(CurrentThread, ETHREAD, ThreadListEntry); 46 nThreads++; 47 48 /* Print the Info */ 49 DbgPrint("State %u Affinity %08x Priority %d PID.TID %d.%d Name %.8s Stack: \n", 50 Thread->Tcb.State, 51 Thread->Tcb.Affinity, 52 Thread->Tcb.Priority, 53 Thread->Cid.UniqueProcess, 54 Thread->Cid.UniqueThread, 55 Thread->ThreadsProcess->ImageFileName); 56 57 /* Make sure it's not running */ 58 if(Thread->Tcb.State == Ready || 59 Thread->Tcb.State == Standby || 60 Thread->Tcb.State == Waiting) 61 { 62 #ifdef _M_IX86 63 ULONG i = 0; 64 PULONG Esp = (PULONG)Thread->Tcb.KernelStack; 65 PULONG Ebp = (PULONG)Esp[4]; 66 67 /* Print EBP */ 68 DbgPrint("Ebp %p\n", Ebp); 69 70 /* Walk it */ 71 while(Ebp != 0 && Ebp >= (PULONG)Thread->Tcb.StackLimit) 72 { 73 /* Print what's on the stack */ 74 DbgPrint("%.8X %.8X%s", Ebp[0], Ebp[1], (i % 8) == 7 ? "\n" : " "); 75 Ebp = (PULONG)Ebp[0]; 76 i++; 77 } 78 79 /* Print a new line if there's nothing */ 80 if((i % 8) != 0) DbgPrint("\n"); 81 #else 82 DbgPrint("FIXME: Backtrace skipped on non-x86\n"); 83 #endif 84 } 85 86 /* Move to the next Thread */ 87 CurrentThread = CurrentThread->Flink; 88 } 89 } 90 91 /* Move to the next Process */ 92 CurrentProcess = CurrentProcess->Flink; 93 } 94 } 95 #endif 96 97 /* PUBLIC FUNCTIONS **********************************************************/ 98 99 /* 100 * @implemented 101 */ 102 NTSTATUS 103 NTAPI 104 PsGetContextThread(IN PETHREAD Thread, 105 IN OUT PCONTEXT ThreadContext, 106 IN KPROCESSOR_MODE PreviousMode) 107 { 108 GET_SET_CTX_CONTEXT GetSetContext; 109 ULONG Size = 0, Flags = 0; 110 NTSTATUS Status; 111 112 /* Enter SEH */ 113 _SEH2_TRY 114 { 115 /* Set default length */ 116 Size = sizeof(CONTEXT); 117 118 /* Read the flags */ 119 Flags = ProbeForReadUlong(&ThreadContext->ContextFlags); 120 121 #ifdef _M_IX86 122 /* Check if the caller wanted extended registers */ 123 if ((Flags & CONTEXT_EXTENDED_REGISTERS) != 124 CONTEXT_EXTENDED_REGISTERS) 125 { 126 /* Cut them out of the size */ 127 Size = FIELD_OFFSET(CONTEXT, ExtendedRegisters); 128 } 129 #endif 130 131 /* Check if we came from user mode */ 132 if (PreviousMode != KernelMode) 133 { 134 /* Probe the context */ 135 ProbeForWrite(ThreadContext, Size, sizeof(ULONG)); 136 } 137 } 138 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 139 { 140 /* Return the exception code */ 141 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 142 } 143 _SEH2_END; 144 145 /* Initialize the wait event */ 146 KeInitializeEvent(&GetSetContext.Event, NotificationEvent, FALSE); 147 148 /* Set the flags and previous mode */ 149 RtlZeroMemory(&GetSetContext.Context, Size); 150 GetSetContext.Context.ContextFlags = Flags; 151 GetSetContext.Mode = PreviousMode; 152 153 /* Check if we're running in the same thread */ 154 if (Thread == PsGetCurrentThread()) 155 { 156 /* Setup APC parameters manually */ 157 GetSetContext.Apc.SystemArgument1 = NULL; 158 GetSetContext.Apc.SystemArgument2 = Thread; 159 160 /* Enter a guarded region to simulate APC_LEVEL */ 161 KeEnterGuardedRegion(); 162 163 /* Manually call the APC */ 164 PspGetOrSetContextKernelRoutine(&GetSetContext.Apc, 165 NULL, 166 NULL, 167 &GetSetContext.Apc.SystemArgument1, 168 &GetSetContext.Apc.SystemArgument2); 169 170 /* Leave the guarded region */ 171 KeLeaveGuardedRegion(); 172 173 /* We are done */ 174 Status = STATUS_SUCCESS; 175 } 176 else 177 { 178 /* Initialize the APC */ 179 KeInitializeApc(&GetSetContext.Apc, 180 &Thread->Tcb, 181 OriginalApcEnvironment, 182 PspGetOrSetContextKernelRoutine, 183 NULL, 184 NULL, 185 KernelMode, 186 NULL); 187 188 /* Queue it as a Get APC */ 189 if (!KeInsertQueueApc(&GetSetContext.Apc, NULL, Thread, 2)) 190 { 191 /* It was already queued, so fail */ 192 Status = STATUS_UNSUCCESSFUL; 193 } 194 else 195 { 196 /* Wait for the APC to complete */ 197 Status = KeWaitForSingleObject(&GetSetContext.Event, 198 0, 199 KernelMode, 200 FALSE, 201 NULL); 202 } 203 } 204 205 _SEH2_TRY 206 { 207 /* Copy the context */ 208 RtlCopyMemory(ThreadContext, &GetSetContext.Context, Size); 209 } 210 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 211 { 212 /* Get the exception code */ 213 Status = _SEH2_GetExceptionCode(); 214 } 215 _SEH2_END; 216 217 /* Return status */ 218 return Status; 219 } 220 221 /* 222 * @implemented 223 */ 224 NTSTATUS 225 NTAPI 226 PsSetContextThread(IN PETHREAD Thread, 227 IN OUT PCONTEXT ThreadContext, 228 IN KPROCESSOR_MODE PreviousMode) 229 { 230 GET_SET_CTX_CONTEXT GetSetContext; 231 ULONG Size = 0, Flags = 0; 232 NTSTATUS Status; 233 234 /* Enter SEH */ 235 _SEH2_TRY 236 { 237 /* Set default length */ 238 Size = sizeof(CONTEXT); 239 240 /* Read the flags */ 241 Flags = ProbeForReadUlong(&ThreadContext->ContextFlags); 242 243 #ifdef _M_IX86 244 /* Check if the caller wanted extended registers */ 245 if ((Flags & CONTEXT_EXTENDED_REGISTERS) != 246 CONTEXT_EXTENDED_REGISTERS) 247 { 248 /* Cut them out of the size */ 249 Size = FIELD_OFFSET(CONTEXT, ExtendedRegisters); 250 } 251 #endif 252 253 /* Check if we came from user mode */ 254 if (PreviousMode != KernelMode) 255 { 256 /* Probe the context */ 257 ProbeForRead(ThreadContext, Size, sizeof(ULONG)); 258 } 259 260 /* Copy the context */ 261 RtlCopyMemory(&GetSetContext.Context, ThreadContext, Size); 262 } 263 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 264 { 265 /* Return the exception code */ 266 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 267 } 268 _SEH2_END; 269 270 /* Initialize the wait event */ 271 KeInitializeEvent(&GetSetContext.Event, NotificationEvent, FALSE); 272 273 /* Set the flags and previous mode */ 274 GetSetContext.Context.ContextFlags = Flags; 275 GetSetContext.Mode = PreviousMode; 276 277 /* Check if we're running in the same thread */ 278 if (Thread == PsGetCurrentThread()) 279 { 280 /* Setup APC parameters manually */ 281 GetSetContext.Apc.SystemArgument1 = UlongToPtr(1); 282 GetSetContext.Apc.SystemArgument2 = Thread; 283 284 /* Enter a guarded region to simulate APC_LEVEL */ 285 KeEnterGuardedRegion(); 286 287 /* Manually call the APC */ 288 PspGetOrSetContextKernelRoutine(&GetSetContext.Apc, 289 NULL, 290 NULL, 291 &GetSetContext.Apc.SystemArgument1, 292 &GetSetContext.Apc.SystemArgument2); 293 294 /* Leave the guarded region */ 295 KeLeaveGuardedRegion(); 296 297 /* We are done */ 298 Status = STATUS_SUCCESS; 299 } 300 else 301 { 302 /* Initialize the APC */ 303 KeInitializeApc(&GetSetContext.Apc, 304 &Thread->Tcb, 305 OriginalApcEnvironment, 306 PspGetOrSetContextKernelRoutine, 307 NULL, 308 NULL, 309 KernelMode, 310 NULL); 311 312 /* Queue it as a Get APC */ 313 if (!KeInsertQueueApc(&GetSetContext.Apc, UlongToPtr(1), Thread, 2)) 314 { 315 /* It was already queued, so fail */ 316 Status = STATUS_UNSUCCESSFUL; 317 } 318 else 319 { 320 /* Wait for the APC to complete */ 321 Status = KeWaitForSingleObject(&GetSetContext.Event, 322 0, 323 KernelMode, 324 FALSE, 325 NULL); 326 } 327 } 328 329 /* Return status */ 330 return Status; 331 } 332 333 NTSTATUS 334 NTAPI 335 NtGetContextThread(IN HANDLE ThreadHandle, 336 IN OUT PCONTEXT ThreadContext) 337 { 338 PETHREAD Thread; 339 NTSTATUS Status; 340 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 341 PAGED_CODE(); 342 343 /* Get the Thread Object */ 344 Status = ObReferenceObjectByHandle(ThreadHandle, 345 THREAD_GET_CONTEXT, 346 PsThreadType, 347 PreviousMode, 348 (PVOID*)&Thread, 349 NULL); 350 351 if (!NT_SUCCESS(Status)) return Status; 352 353 /* Make sure it's not a system thread */ 354 if (Thread->SystemThread) 355 { 356 /* Fail */ 357 Status = STATUS_INVALID_HANDLE; 358 } 359 else 360 { 361 /* Call the kernel API */ 362 Status = PsGetContextThread(Thread, ThreadContext, PreviousMode); 363 } 364 365 /* Dereference it and return */ 366 ObDereferenceObject(Thread); 367 return Status; 368 } 369 370 NTSTATUS 371 NTAPI 372 NtSetContextThread(IN HANDLE ThreadHandle, 373 IN PCONTEXT ThreadContext) 374 { 375 PETHREAD Thread; 376 NTSTATUS Status; 377 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 378 PAGED_CODE(); 379 380 /* Get the Thread Object */ 381 Status = ObReferenceObjectByHandle(ThreadHandle, 382 THREAD_SET_CONTEXT, 383 PsThreadType, 384 PreviousMode, 385 (PVOID*)&Thread, 386 NULL); 387 388 if (!NT_SUCCESS(Status)) return Status; 389 390 /* Make sure it's not a system thread */ 391 if (Thread->SystemThread) 392 { 393 /* Fail */ 394 Status = STATUS_INVALID_HANDLE; 395 } 396 else 397 { 398 /* Call the kernel API */ 399 Status = PsSetContextThread(Thread, ThreadContext, PreviousMode); 400 } 401 402 /* Dereference it and return */ 403 ObDereferenceObject(Thread); 404 return Status; 405 } 406 407 /* EOF */ 408