test: psctx.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# psctx.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1989  Microsoft Corporation
    00004
    00005 Module Name:
    00006
    00007     psctx.c
    00008
    00009 Abstract:
    00010
    00011     This procedure implements Get/Set Context Thread
    00012
    00013 Author:
    00014
    00015     Mark Lucovsky (markl) 25-May-1989
    00016
    00017 Revision History:
    00018
    00019 --*/
    00020
    00021 #include "psp.h"
    00022
    00023 VOID
    00024 PspQueueApcSpecialApc(
    00025     IN PKAPC Apc,
    00026     IN PKNORMAL_ROUTINE *NormalRoutine,
    00027     IN PVOID *NormalContext,
    00028     IN PVOID *SystemArgument1,
    00029     IN PVOID *SystemArgument2
    00030     );
    00031
    00032 #ifdef ALLOC_PRAGMA
    00033 #pragma alloc_text(PAGE, NtGetContextThread)
    00034 #pragma alloc_text(PAGE, NtSetContextThread)
    00035 #pragma alloc_text(PAGE, NtQueueApcThread)
    00036 #pragma alloc_text(PAGE, PspQueueApcSpecialApc )
    00037 #endif
    00038
    00039 VOID
    00040 PspQueueApcSpecialApc(
    00041     IN PKAPC Apc,
    00042     IN PKNORMAL_ROUTINE *NormalRoutine,
    00043     IN PVOID *NormalContext,
    00044     IN PVOID *SystemArgument1,
    00045     IN PVOID *SystemArgument2
    00046     )
    00047 {
    00048     PAGED_CODE();
    00049
    00050     ExFreePool(Apc);
    00051 }
    00052
    00053 NTSYSAPI
    00054 NTSTATUS
    00055 NTAPI
    00056 NtQueueApcThread(
    00057     IN HANDLE ThreadHandle,
    00058     IN PPS_APC_ROUTINE ApcRoutine,
    00059     IN PVOID ApcArgument1,
    00060     IN PVOID ApcArgument2,
    00061     IN PVOID ApcArgument3
    00062     )
    00063
    00064 /*++
    00065
    00066 Routine Description:
    00067
    00068     This function is used to queue a user-mode APC to the specified thread. The APC
    00069     will fire when the specified thread does an alertable wait
    00070
    00071 Arguments:
    00072
    00073     ThreadHandle - Supplies a handle to a thread object.  The caller
    00074         must have THREAD_SET_CONTEXT access to the thread.
    00075
    00076     ApcRoutine - Supplies the address of the APC routine to execute when the
    00077         APC fires.
    00078
    00079     ApcArgument1 - Supplies the first PVOID passed to the APC
    00080
    00081     ApcArgument2 - Supplies the second PVOID passed to the APC
    00082
    00083     ApcArgument3 - Supplies the third PVOID passed to the APC
    00084
    00085 Return Value:
    00086
    00087     Returns an NT Status code indicating success or failure of the API
    00088
    00089 --*/
    00090
    00091 {
    00092     PETHREAD Thread;
    00093     NTSTATUS st;
    00094     KPROCESSOR_MODE Mode;
    00095     KIRQL Irql;
    00096     PKAPC Apc;
    00097
    00098     PAGED_CODE();
    00099
    00100     Mode = KeGetPreviousMode();
    00101
    00102     st = ObReferenceObjectByHandle(
    00103             ThreadHandle,
    00104             THREAD_SET_CONTEXT,
    00105             PsThreadType,
    00106             Mode,
    00107             (PVOID *)&Thread,
    00108             NULL
    00109             );
    00110
    00111     if ( NT_SUCCESS(st) ) {
    00112         st = STATUS_SUCCESS;
    00113         if ( IS_SYSTEM_THREAD(Thread) ) {
    00114             st = STATUS_INVALID_HANDLE;
    00115             }
    00116         else {
    00117             Apc = ExAllocatePoolWithQuotaTag(
    00118                     (NonPagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE),
    00119                     sizeof(*Apc),
    00120                     'pasP'
    00121                     );
    00122
    00123             if ( !Apc ) {
    00124                 st = STATUS_NO_MEMORY;
    00125                 }
    00126             else {
    00127                 KeInitializeApc(
    00128                     Apc,
    00129                     &Thread->Tcb,
    00130                     OriginalApcEnvironment,
    00131                     PspQueueApcSpecialApc,
    00132                     NULL,
    00133                     (PKNORMAL_ROUTINE)ApcRoutine,
    00134                     UserMode,
    00135                     ApcArgument1
    00136                     );
    00137
    00138                 if ( !KeInsertQueueApc(Apc,ApcArgument2,ApcArgument3,0) ) {
    00139                     ExFreePool(Apc);
    00140                     st = STATUS_UNSUCCESSFUL;
    00141                     }
    00142                 }
    00143             }
    00144         ObDereferenceObject(Thread);
    00145         }
    00146
    00147     return st;
    00148 }
    00149
    00150 NTSTATUS
    00151 NtGetContextThread(
    00152     IN HANDLE ThreadHandle,
    00153     IN OUT PCONTEXT ThreadContext
    00154     )
    00155
    00156 /*++
    00157
    00158 Routine Description:
    00159
    00160     This function returns the usermode context of the specified thread. This
    00161     function will fail if the specified thread is a system thread. It will
    00162     return the wrong answer if the thread is a non-system thread that does
    00163     not execute in user-mode.
    00164
    00165 Arguments:
    00166
    00167     ThreadHandle - Supplies an open handle to the thread object from
    00168                    which to retrieve context information.  The handle
    00169                    must allow THREAD_GET_CONTEXT access to the thread.
    00170
    00171     ThreadContext - Supplies the address of a buffer that will receive
    00172                     the context of the specified thread.
    00173
    00174 Return Value:
    00175
    00176     None.
    00177
    00178 --*/
    00179
    00180 {
    00181
    00182     ULONG Alignment;
    00183     ULONG ContextFlags;
    00184     GETSETCONTEXT ContextFrame;
    00185     ULONG ContextLength;
    00186     KIRQL Irql;
    00187     KPROCESSOR_MODE Mode;
    00188     NTSTATUS Status;
    00189     PETHREAD Thread;
    00190
    00191     PAGED_CODE();
    00192
    00193     //
    00194     // Get previous mode and reference specified thread.
    00195     //
    00196
    00197     Mode = KeGetPreviousMode();
    00198     Status = ObReferenceObjectByHandle(ThreadHandle,
    00199                                    THREAD_GET_CONTEXT,
    00200                                    PsThreadType,
    00201                                    Mode,
    00202                                    (PVOID *)&Thread,
    00203                                    NULL);
    00204
    00205     //
    00206     // If the reference was successful, the check if the specified thread
    00207     // is a system thread.
    00208     //
    00209
    00210     if (NT_SUCCESS(Status)) {
    00211
    00212         //
    00213         // If the thread is not a system thread, then attempt to get the
    00214         // context of the thread.
    00215         //
    00216
    00217         if (IS_SYSTEM_THREAD(Thread) == FALSE) {
    00218
    00219             //
    00220             // Attempt to get the context of the specified thread.
    00221             //
    00222
    00223             try {
    00224
    00225                 //
    00226                 // Set the default alignment, capture the context flags,
    00227                 // and set the default size of the context record.
    00228                 //
    00229
    00230                 Alignment = CONTEXT_ALIGN;
    00231                 ContextFlags = ProbeAndReadUlong(&ThreadContext->ContextFlags);
    00232                 ContextLength = sizeof(CONTEXT);
    00233
    00234 #if defined(_X86_)
    00235                 //
    00236                 // CONTEXT_EXTENDED_REGISTERS is SET, then we want sizeof(CONTEXT) set above
    00237                 // otherwise (not set) we only want the old part of the context record.
    00238                 //
    00239                 if ((ContextFlags & CONTEXT_EXTENDED_REGISTERS) != CONTEXT_EXTENDED_REGISTERS) {
    00240                     ContextLength = FIELD_OFFSET(CONTEXT, ExtendedRegisters);
    00241                 }
    00242 #endif
    00243
    00244 #if defined(_MIPS_)
    00245
    00246                 //
    00247                 // The following code is included for backward compatibility
    00248                 // with old code that does not understand extended context
    00249                 // records on MIPS systems.
    00250                 //
    00251
    00252                 if ((ContextFlags & CONTEXT_EXTENDED_INTEGER) != CONTEXT_EXTENDED_INTEGER) {
    00253                     Alignment = sizeof(ULONG);
    00254                     ContextLength = FIELD_OFFSET(CONTEXT, ContextFlags) + 4;
    00255                 }
    00256
    00257 #endif
    00258
    00259                 if (Mode != KernelMode) {
    00260                     ProbeForWrite(ThreadContext, ContextLength, Alignment);
    00261                 }
    00262
    00263             } except(EXCEPTION_EXECUTE_HANDLER) {
    00264                 Status = GetExceptionCode();
    00265             }
    00266
    00267             //
    00268             // If an exception did not occur during the probe of the thread
    00269             // context, then get the context of the target thread.
    00270             //
    00271
    00272             if (NT_SUCCESS(Status)) {
    00273                 KeInitializeEvent(&ContextFrame.OperationComplete,
    00274                                   NotificationEvent,
    00275                                   FALSE);
    00276
    00277                 ContextFrame.Context.ContextFlags = ContextFlags;
    00278
    00279                 ContextFrame.Mode = Mode;
    00280                 if (Thread == PsGetCurrentThread()) {
    00281                     ContextFrame.Apc.SystemArgument1 = NULL;
    00282                     ContextFrame.Apc.SystemArgument2 = Thread;
    00283                     KeRaiseIrql(APC_LEVEL, &Irql);
    00284                     PspGetSetContextSpecialApc(&ContextFrame.Apc,
    00285                                                NULL,
    00286                                                NULL,
    00287                                                &ContextFrame.Apc.SystemArgument1,
    00288                                                &ContextFrame.Apc.SystemArgument2);
    00289
    00290                     KeLowerIrql(Irql);
    00291
    00292                     //
    00293                     // Move context to specfied context record. If an exception
    00294                     // occurs, then silently handle it and return success.
    00295                     //
    00296
    00297                     try {
    00298                         RtlMoveMemory(ThreadContext,
    00299                                       &ContextFrame.Context,
    00300                                       ContextLength);
    00301
    00302                     } except(EXCEPTION_EXECUTE_HANDLER) {
    00303                     }
    00304
    00305                 } else {
    00306                     KeInitializeApc(&ContextFrame.Apc,
    00307                                     &Thread->Tcb,
    00308                                     OriginalApcEnvironment,
    00309                                     PspGetSetContextSpecialApc,
    00310                                     NULL,
    00311                                     NULL,
    00312                                     KernelMode,
    00313                                     NULL);
    00314
    00315                     if (!KeInsertQueueApc(&ContextFrame.Apc, NULL, Thread, 2)) {
    00316                         Status = STATUS_UNSUCCESSFUL;
    00317
    00318                     } else {
    00319                         KeWaitForSingleObject(&ContextFrame.OperationComplete,
    00320                                               Executive,
    00321                                               KernelMode,
    00322                                               FALSE,
    00323                                               NULL);
    00324                         //
    00325                         // Move context to specfied context record. If an
    00326                         // exception occurs, then silently handle it and
    00327                         // return success.
    00328                         //
    00329
    00330                         try {
    00331                             RtlMoveMemory(ThreadContext,
    00332                                           &ContextFrame.Context,
    00333                                           ContextLength);
    00334
    00335                         } except(EXCEPTION_EXECUTE_HANDLER) {
    00336                         }
    00337                     }
    00338                 }
    00339             }
    00340
    00341         } else {
    00342             Status = STATUS_INVALID_HANDLE;
    00343         }
    00344
    00345         ObDereferenceObject(Thread);
    00346     }
    00347
    00348     return Status;
    00349 }
    00350
    00351 NTSTATUS
    00352 NtSetContextThread(
    00353     IN HANDLE ThreadHandle,
    00354     IN PCONTEXT ThreadContext
    00355     )
    00356
    00357 /*++
    00358
    00359 Routine Description:
    00360
    00361     This function sets the usermode context of the specified thread. This
    00362     function will fail if the specified thread is a system thread. It will
    00363     return the wrong answer if the thread is a non-system thread that does
    00364     not execute in user-mode.
    00365
    00366 Arguments:
    00367
    00368     ThreadHandle - Supplies an open handle to the thread object from
    00369                    which to retrieve context information.  The handle
    00370                    must allow THREAD_SET_CONTEXT access to the thread.
    00371
    00372     ThreadContext - Supplies the address of a buffer that contains new
    00373                     context for the specified thread.
    00374
    00375 Return Value:
    00376
    00377     None.
    00378
    00379 --*/
    00380
    00381 {
    00382
    00383     ULONG Alignment;
    00384     ULONG ContextFlags;
    00385     GETSETCONTEXT ContextFrame;
    00386     ULONG ContextLength;
    00387     KIRQL Irql;
    00388     KPROCESSOR_MODE Mode;
    00389     NTSTATUS Status;
    00390     PETHREAD Thread;
    00391
    00392     PAGED_CODE();
    00393
    00394     //
    00395     // Get previous mode and reference specified thread.
    00396     //
    00397
    00398     Mode = KeGetPreviousMode();
    00399     Status = ObReferenceObjectByHandle(ThreadHandle,
    00400                                        THREAD_SET_CONTEXT,
    00401                                        PsThreadType,
    00402                                        Mode,
    00403                                        (PVOID *)&Thread,
    00404                                        NULL);
    00405
    00406     //
    00407     // If the reference was successful, the check if the specified thread
    00408     // is a system thread.
    00409     //
    00410
    00411     if (NT_SUCCESS(Status)) {
    00412
    00413         //
    00414         // If the thread is not a system thread, then attempt to get the
    00415         // context of the thread.
    00416         //
    00417
    00418         if (IS_SYSTEM_THREAD(Thread) == FALSE) {
    00419
    00420             //
    00421             // Attempt to get the context of the specified thread.
    00422             //
    00423
    00424             try {
    00425
    00426                 //
    00427                 // Set the default alignment, capture the context flags,
    00428                 // and set the default size of the context record.
    00429                 //
    00430
    00431                 Alignment = CONTEXT_ALIGN;
    00432                 ContextFlags = ProbeAndReadUlong(&ThreadContext->ContextFlags);
    00433                 ContextLength = sizeof(CONTEXT);
    00434
    00435 #if defined(_X86_)
    00436                 //
    00437                 // CONTEXT_EXTENDED_REGISTERS is SET, then we want sizeof(CONTEXT) set above
    00438                 // otherwise (not set) we only want the old part of the context record.
    00439                 //
    00440                 if ((ContextFlags & CONTEXT_EXTENDED_REGISTERS) != CONTEXT_EXTENDED_REGISTERS) {
    00441                     ContextLength = FIELD_OFFSET(CONTEXT, ExtendedRegisters);
    00442                 }
    00443 #endif
    00444
    00445 #if defined(_MIPS_)
    00446
    00447                 //
    00448                 // The following code is included for backward compatibility
    00449                 // with old code that does not understand extended context
    00450                 // records on MIPS systems.
    00451                 //
    00452
    00453                 if ((ContextFlags & CONTEXT_EXTENDED_INTEGER) != CONTEXT_EXTENDED_INTEGER) {
    00454                     Alignment = sizeof(ULONG);
    00455                     ContextLength = FIELD_OFFSET(CONTEXT, ContextFlags) + 4;
    00456                 }
    00457
    00458 #endif
    00459
    00460                 if (Mode != KernelMode) {
    00461                     ProbeForRead(ThreadContext, ContextLength, Alignment);
    00462                 }
    00463
    00464                 RtlMoveMemory(&ContextFrame.Context, ThreadContext, ContextLength);
    00465
    00466             } except(EXCEPTION_EXECUTE_HANDLER) {
    00467                 Status = GetExceptionCode();
    00468             }
    00469
    00470             //
    00471             // If an exception did not occur during the probe of the thread
    00472             // context, then set the context of the target thread.
    00473             //
    00474
    00475             if (NT_SUCCESS(Status)) {
    00476                 KeInitializeEvent(&ContextFrame.OperationComplete,
    00477                                   NotificationEvent,
    00478                                   FALSE);
    00479
    00480                 ContextFrame.Context.ContextFlags = ContextFlags;
    00481
    00482                 ContextFrame.Mode = Mode;
    00483                 if (Thread == PsGetCurrentThread()) {
    00484                     ContextFrame.Apc.SystemArgument1 = (PVOID)1;
    00485                     ContextFrame.Apc.SystemArgument2 = Thread;
    00486                     KeRaiseIrql(APC_LEVEL, &Irql);
    00487                     PspGetSetContextSpecialApc(&ContextFrame.Apc,
    00488                                                NULL,
    00489                                                NULL,
    00490                                                &ContextFrame.Apc.SystemArgument1,
    00491                                                &ContextFrame.Apc.SystemArgument2);
    00492
    00493                     KeLowerIrql(Irql);
    00494
    00495                 } else {
    00496                     KeInitializeApc(&ContextFrame.Apc,
    00497                                     &Thread->Tcb,
    00498                                     OriginalApcEnvironment,
    00499                                     PspGetSetContextSpecialApc,
    00500                                     NULL,
    00501                                     NULL,
    00502                                     KernelMode,
    00503                                     NULL);
    00504
    00505                     if (!KeInsertQueueApc(&ContextFrame.Apc, (PVOID)1, Thread, 2)) {
    00506                         Status = STATUS_UNSUCCESSFUL;
    00507
    00508                     } else {
    00509                         KeWaitForSingleObject(&ContextFrame.OperationComplete,
    00510                                               Executive,
    00511                                               KernelMode,
    00512                                               FALSE,
    00513                                               NULL);
    00514                     }
    00515                 }
    00516             }
    00517
    00518         } else {
    00519             Status = STATUS_INVALID_HANDLE;
    00520         }
    00521
    00522         ObDereferenceObject(Thread);
    00523     }
    00524
    00525     return Status;
    00526 }