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 ength */ 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 GetSetContext.Context.ContextFlags = Flags; 150 GetSetContext.Mode = PreviousMode; 151 152 /* Check if we're running in the same thread */ 153 if (Thread == PsGetCurrentThread()) 154 { 155 /* Setup APC parameters manually */ 156 GetSetContext.Apc.SystemArgument1 = NULL; 157 GetSetContext.Apc.SystemArgument2 = Thread; 158 159 /* Enter a guarded region to simulate APC_LEVEL */ 160 KeEnterGuardedRegion(); 161 162 /* Manually call the APC */ 163 PspGetOrSetContextKernelRoutine(&GetSetContext.Apc, 164 NULL, 165 NULL, 166 &GetSetContext.Apc.SystemArgument1, 167 &GetSetContext.Apc.SystemArgument2); 168 169 /* Leave the guarded region */ 170 KeLeaveGuardedRegion(); 171 172 /* We are done */ 173 Status = STATUS_SUCCESS; 174 } 175 else 176 { 177 /* Initialize the APC */ 178 KeInitializeApc(&GetSetContext.Apc, 179 &Thread->Tcb, 180 OriginalApcEnvironment, 181 PspGetOrSetContextKernelRoutine, 182 NULL, 183 NULL, 184 KernelMode, 185 NULL); 186 187 /* Queue it as a Get APC */ 188 if (!KeInsertQueueApc(&GetSetContext.Apc, NULL, Thread, 2)) 189 { 190 /* It was already queued, so fail */ 191 Status = STATUS_UNSUCCESSFUL; 192 } 193 else 194 { 195 /* Wait for the APC to complete */ 196 Status = KeWaitForSingleObject(&GetSetContext.Event, 197 0, 198 KernelMode, 199 FALSE, 200 NULL); 201 } 202 } 203 204 _SEH2_TRY 205 { 206 /* Copy the context */ 207 RtlCopyMemory(ThreadContext, &GetSetContext.Context, Size); 208 } 209 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 210 { 211 /* Get the exception code */ 212 Status = _SEH2_GetExceptionCode(); 213 } 214 _SEH2_END; 215 216 /* Return status */ 217 return Status; 218 } 219 220 /* 221 * @implemented 222 */ 223 NTSTATUS 224 NTAPI 225 PsSetContextThread(IN PETHREAD Thread, 226 IN OUT PCONTEXT ThreadContext, 227 IN KPROCESSOR_MODE PreviousMode) 228 { 229 GET_SET_CTX_CONTEXT GetSetContext; 230 ULONG Size = 0, Flags = 0; 231 NTSTATUS Status; 232 233 /* Enter SEH */ 234 _SEH2_TRY 235 { 236 /* Set default length */ 237 Size = sizeof(CONTEXT); 238 239 /* Read the flags */ 240 Flags = ProbeForReadUlong(&ThreadContext->ContextFlags); 241 242 #ifdef _M_IX86 243 /* Check if the caller wanted extended registers */ 244 if ((Flags & CONTEXT_EXTENDED_REGISTERS) != 245 CONTEXT_EXTENDED_REGISTERS) 246 { 247 /* Cut them out of the size */ 248 Size = FIELD_OFFSET(CONTEXT, ExtendedRegisters); 249 } 250 #endif 251 252 /* Check if we came from user mode */ 253 if (PreviousMode != KernelMode) 254 { 255 /* Probe the context */ 256 ProbeForRead(ThreadContext, Size, sizeof(ULONG)); 257 } 258 259 /* Copy the context */ 260 RtlCopyMemory(&GetSetContext.Context, ThreadContext, Size); 261 } 262 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 263 { 264 /* Return the exception code */ 265 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 266 } 267 _SEH2_END; 268 269 /* Initialize the wait event */ 270 KeInitializeEvent(&GetSetContext.Event, NotificationEvent, FALSE); 271 272 /* Set the flags and previous mode */ 273 GetSetContext.Context.ContextFlags = Flags; 274 GetSetContext.Mode = PreviousMode; 275 276 /* Check if we're running in the same thread */ 277 if (Thread == PsGetCurrentThread()) 278 { 279 /* Setup APC parameters manually */ 280 GetSetContext.Apc.SystemArgument1 = UlongToPtr(1); 281 GetSetContext.Apc.SystemArgument2 = Thread; 282 283 /* Enter a guarded region to simulate APC_LEVEL */ 284 KeEnterGuardedRegion(); 285 286 /* Manually call the APC */ 287 PspGetOrSetContextKernelRoutine(&GetSetContext.Apc, 288 NULL, 289 NULL, 290 &GetSetContext.Apc.SystemArgument1, 291 &GetSetContext.Apc.SystemArgument2); 292 293 /* Leave the guarded region */ 294 KeLeaveGuardedRegion(); 295 296 /* We are done */ 297 Status = STATUS_SUCCESS; 298 } 299 else 300 { 301 /* Initialize the APC */ 302 KeInitializeApc(&GetSetContext.Apc, 303 &Thread->Tcb, 304 OriginalApcEnvironment, 305 PspGetOrSetContextKernelRoutine, 306 NULL, 307 NULL, 308 KernelMode, 309 NULL); 310 311 /* Queue it as a Get APC */ 312 if (!KeInsertQueueApc(&GetSetContext.Apc, UlongToPtr(1), Thread, 2)) 313 { 314 /* It was already queued, so fail */ 315 Status = STATUS_UNSUCCESSFUL; 316 } 317 else 318 { 319 /* Wait for the APC to complete */ 320 Status = KeWaitForSingleObject(&GetSetContext.Event, 321 0, 322 KernelMode, 323 FALSE, 324 NULL); 325 } 326 } 327 328 /* Return status */ 329 return Status; 330 } 331 332 NTSTATUS 333 NTAPI 334 NtGetContextThread(IN HANDLE ThreadHandle, 335 IN OUT PCONTEXT ThreadContext) 336 { 337 PETHREAD Thread; 338 NTSTATUS Status; 339 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 340 PAGED_CODE(); 341 342 /* Get the Thread Object */ 343 Status = ObReferenceObjectByHandle(ThreadHandle, 344 THREAD_GET_CONTEXT, 345 PsThreadType, 346 PreviousMode, 347 (PVOID*)&Thread, 348 NULL); 349 350 if (!NT_SUCCESS(Status)) return Status; 351 352 /* Make sure it's not a system thread */ 353 if (Thread->SystemThread) 354 { 355 /* Fail */ 356 Status = STATUS_INVALID_HANDLE; 357 } 358 else 359 { 360 /* Call the kernel API */ 361 Status = PsGetContextThread(Thread, ThreadContext, PreviousMode); 362 } 363 364 /* Dereference it and return */ 365 ObDereferenceObject(Thread); 366 return Status; 367 } 368 369 NTSTATUS 370 NTAPI 371 NtSetContextThread(IN HANDLE ThreadHandle, 372 IN PCONTEXT ThreadContext) 373 { 374 PETHREAD Thread; 375 NTSTATUS Status; 376 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 377 PAGED_CODE(); 378 379 /* Get the Thread Object */ 380 Status = ObReferenceObjectByHandle(ThreadHandle, 381 THREAD_SET_CONTEXT, 382 PsThreadType, 383 PreviousMode, 384 (PVOID*)&Thread, 385 NULL); 386 387 if (!NT_SUCCESS(Status)) return Status; 388 389 /* Make sure it's not a system thread */ 390 if (Thread->SystemThread) 391 { 392 /* Fail */ 393 Status = STATUS_INVALID_HANDLE; 394 } 395 else 396 { 397 /* Call the kernel API */ 398 Status = PsSetContextThread(Thread, ThreadContext, PreviousMode); 399 } 400 401 /* Dereference it and return */ 402 ObDereferenceObject(Thread); 403 return Status; 404 } 405 406 /* EOF */ 407