test: ex/profile.c File Reference

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

# profile.c File Reference

`#include "exp.h"`

Go to the source code of this file.

## Classes

struct | _EPROFILE

## Defines

#define | ACTIVE_PROFILE_LIMIT 8

## Typedefs

typedef _EPROFILE | EPROFILE
typedef _EPROFILE * | PEPROFILE

## Functions

BOOLEAN | ExpProfileInitialization ()
VOID | ExpProfileDelete (IN PVOID Object)
NTSTATUS | NtCreateProfile (OUT PHANDLE ProfileHandle, IN HANDLE Process OPTIONAL, IN PVOID RangeBase, IN SIZE_T RangeSize, IN ULONG BucketSize, IN PULONG Buffer, IN ULONG BufferSize, IN KPROFILE_SOURCE ProfileSource, IN KAFFINITY Affinity)
NTSTATUS | NtStartProfile (IN HANDLE ProfileHandle)
NTSTATUS | NtStopProfile (IN HANDLE ProfileHandle)
NTSTATUS | NtSetIntervalProfile (IN ULONG Interval, IN KPROFILE_SOURCE Source)
NTSTATUS | NtQueryIntervalProfile (IN KPROFILE_SOURCE ProfileSource, OUT PULONG Interval)
NTSTATUS | NtQueryPerformanceCounter (OUT PLARGE_INTEGER PerformanceCounter, OUT PLARGE_INTEGER PerformanceFrequency OPTIONAL)

## Variables

POBJECT_TYPE | ExProfileObjectType
KMUTEX | ExpProfileStateMutex
ULONG | ExpCurrentProfileUsage = 0
GENERIC_MAPPING | ExpProfileMapping

## Define Documentation

#define ACTIVE_PROFILE_LIMIT 8

| Definition at line 64 of file ex/profile.c. Referenced by NtStartProfile().

## Typedef Documentation

typedef struct _EPROFILE EPROFILE

| Referenced by NtCreateProfile().

typedef struct _EPROFILE * PEPROFILE

| Referenced by ExpProfileDelete(), NtCreateProfile(), NtStartProfile(), and NtStopProfile().

## Function Documentation

VOID ExpProfileDelete | ( | IN PVOID | Object | ) |

Definition at line 145 of file ex/profile.c.

References ASSERT, ExFreePool(), FALSE, KeStopProfile(), _EPROFILE::LockedBufferAddress, _EPROFILE::Mdl, MmUnlockPages(), MmUnmapLockedPages(), NULL, ObDereferenceObject, PEPROFILE, _EPROFILE::Process, and _EPROFILE::ProfileObject.

Referenced by ExpProfileInitialization().

    00151                    :
    00152
    00153
    00154     This routine is called by the object management procedures whenever
    00155     the last reference to a profile object has been removed.  This routine
    00156     stops profiling, returns locked buffers and pages, dereferences the
    00157     specified process and returns.
    00158
    00159 Arguments:
    00160
    00161     Object - a pointer to the body of the profile object.
    00162
    00163 Return Value:
    00164
    00165     None.
    00166
    00167 --*/
    00168
    00169 {
    00170     PEPROFILE Profile;
    00171     BOOLEAN   State;
    00172     PEPROCESS ProcessAddress;
    00173
    00174     Profile = (PEPROFILE)Object;
    00175
    00176     if (Profile->LockedBufferAddress != NULL) {
    00177
    00178         //
    00179         // Stop profiling and unlock the buffers and deallocate pool.
    00180         //
    00181
    00182         State = KeStopProfile (Profile->ProfileObject);
    00183         ASSERT (State != FALSE);
    00184
    00185         MmUnmapLockedPages (Profile->LockedBufferAddress, Profile->Mdl);
    00186         MmUnlockPages (Profile->Mdl);
    00187         ExFreePool (Profile->ProfileObject);
    00188     }
    00189
    00190     if (Profile->Process != NULL) {
    00191         ProcessAddress = CONTAINING_RECORD(Profile->Process, EPROCESS, Pcb);
    00192         ObDereferenceObject ((PVOID)ProcessAddress);
    00193     }
    00194
    00195     return;
    00196 }

BOOLEAN ExpProfileInitialization | ( |  | ) |

Definition at line 79 of file ex/profile.c.

References ExpProfileDelete(), ExpProfileMapping, ExpProfileStateMutex, ExProfileObjectType, KeInitializeMutex(), L, MUTEX_LEVEL_EX_PROFILE, NonPagedPool, NT_SUCCESS, NTSTATUS(), NULL, ObCreateObjectType(), RtlInitUnicodeString(), and Status.

    00084                    :
    00085
    00086     This function creates the profile object type descriptor at system
    00087     initialization and stores the address of the object type descriptor
    00088     in global storage.
    00089
    00090 Arguments:
    00091
    00092     None.
    00093
    00094 Return Value:
    00095
    00096     A value of TRUE is returned if the profile object type descriptor is
    00097     successfully initialized. Otherwise a value of FALSE is returned.
    00098
    00099 --*/
    00100
    00101 {
    00102
    00103     OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
    00104     NTSTATUS Status;
    00105     UNICODE_STRING TypeName;
    00106
    00107     //
    00108     // Initialize mutex for synchronizing start and stop operations.
    00109     //
    00110
    00111     KeInitializeMutex (&ExpProfileStateMutex, MUTEX_LEVEL_EX_PROFILE);
    00112
    00113     //
    00114     // Initialize string descriptor.
    00115     //
    00116
    00117     RtlInitUnicodeString(&TypeName, L"Profile");
    00118
    00119     //
    00120     // Create event object type descriptor.
    00121     //
    00122
    00123     RtlZeroMemory(&ObjectTypeInitializer,sizeof(ObjectTypeInitializer));
    00124     ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
    00125     ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK;
    00126     ObjectTypeInitializer.PoolType = NonPagedPool;
    00127     ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(EPROFILE);
    00128     ObjectTypeInitializer.ValidAccessMask = PROFILE_ALL_ACCESS;
    00129     ObjectTypeInitializer.DeleteProcedure = ExpProfileDelete;
    00130     ObjectTypeInitializer.GenericMapping = ExpProfileMapping;
    00131
    00132     Status = ObCreateObjectType(&TypeName,
    00133                                 &ObjectTypeInitializer,
    00134                                 (PSECURITY_DESCRIPTOR)NULL,
    00135                                 &ExProfileObjectType);
    00136
    00137     //
    00138     // If the event object type descriptor was successfully created, then
    00139     // return a value of TRUE. Otherwise return a value of FALSE.
    00140     //
    00141
    00142     return (BOOLEAN)(NT_SUCCESS(Status));
    00143 }
    VOID

NTSTATUS NtCreateProfile | ( | OUT PHANDLE | ProfileHandle,
|  | IN HANDLE Process | OPTIONAL,
|  | IN PVOID | RangeBase,
|  | IN SIZE_T | RangeSize,
|  | IN ULONG | BucketSize,
|  | IN PULONG | Buffer,
|  | IN ULONG | BufferSize,
|  | IN KPROFILE_SOURCE | ProfileSource,
|  | IN KAFFINITY | Affinity
| ) |

Definition at line 199 of file ex/profile.c.

References Buffer, BufferSize, DbgPrint, EPROFILE, EXCEPTION_EXECUTE_HANDLER, ExProfileObjectType, FALSE, Handle, KernelMode, KPROCESSOR_MODE, NT_SUCCESS, NTSTATUS(), NULL, ObCreateObject(), ObDereferenceObject, ObInsertObject(), ObjectAttributes, ObReferenceObjectByHandle(), _EPROCESS::Pcb, PEPROFILE, ProbeForWrite(), ProbeForWriteHandle, PsProcessType, SeSinglePrivilegeCheck(), SeSystemProfilePrivilege, Status, and USHORT.

Referenced by main().

    00213                    :
    00214
    00215     This function creates a profile object.
    00216
    00217 Arguments:
    00218
    00219     ProfileHandle - Supplies a pointer to a variable that will receive
    00220                     the profile object handle.
    00221
    00222     Process - Optionally, supplies the handle to the process whose
    00223               address space to profile.  If the value is NULL (0), then
    00224               all address spaces are included in the profile.
    00225
    00226     RangeBase - Supplies the address of the first byte of the address
    00227                   space for which profiling information is to be collected.
    00228
    00229
    00230     RangeSize - Supplies the size of the range to profile in the
    00231                 address space.  RangeBase and RangeSize are interpreted
    00232                 such that RangeBase <= address < RangeBase+RangeSize
    00233                 will generate a profile hit.
    00234
    00235     BucketSize - Supplies the LOG base 2 of the size of the profiling
    00236                  bucket.  Thus, BucketSize = 2 yields four-byte
    00237                  buckets, BucketSize = 7 yields 128-byte buckets.
    00238                  All profile hits in a given bucket will increment
    00239                  the corresponding counter in Buffer.  Buckets
    00240                  cannot be smaller than a ULONG.  The acceptable range
    00241                  of this value is 2 to 30 inclusive.
    00242
    00243     Buffer - Supplies an array of ULONGs.  Each ULONG is a hit counter,
    00244              which records the number of hits of the corresponding
    00245              bucket.
    00246
    00247     BufferSize - Size in bytes of Buffer.
    00248
    00249     ProfileSource - Supplies the source for the profile interrupt
    00250
    00251     Affinity - Supplies the processor set for the profile interrupt
    00252
    00253 Return Value:
    00254
    00255     TBS
    00256
    00257 --*/
    00258
    00259 {
    00260
    00261     PEPROFILE Profile;
    00262     HANDLE Handle;
    00263     KPROCESSOR_MODE PreviousMode;
    00264     NTSTATUS Status;
    00265     PEPROCESS ProcessAddress;
    00266     OBJECT_ATTRIBUTES ObjectAttributes;
    00267     BOOLEAN HasPrivilege = FALSE;
    00268     ULONG Segment = FALSE;
    00269     USHORT PowerOf2;
    00270
    00271     //
    00272     // Verify that the base and size arguments are reasonable.
    00273     //
    00274
    00275     if (BufferSize == 0) {
    00276         return STATUS_INVALID_PARAMETER_7;
    00277     }
    00278
    00279 #ifdef i386
    00280     //
    00281     //        sleazy use of bucket size.  If bucket size is zero, and
    00282     //        RangeBase < 64K, then create a profile object to attach
    00283     //        to a non-flat code segment.  In this case, RangeBase is
    00284     //        the non-flat CS for this profile object.
    00285     //
    00286
    00287     if ((BucketSize == 0) && (RangeBase < (PVOID)(64 * 1024))) {
    00288
    00289         if (BufferSize < sizeof(ULONG)) {
    00290             return STATUS_INVALID_PARAMETER_7;
    00291         }
    00292
    00293         Segment = (ULONG)RangeBase;
    00294         RangeBase = 0;
    00295         BucketSize = RangeSize / (BufferSize / sizeof(ULONG));
    00296
    00297         //
    00298         // Convert Bucket size of log2(BucketSize)
    00299         //
    00300         PowerOf2 = 0;
    00301         BucketSize = BucketSize - 1;
    00302         while (BucketSize >>= 1) {
    00303             PowerOf2++;
    00304         }
    00305
    00306         BucketSize = PowerOf2 + 1;
    00307
    00308         if (BucketSize < 2) {
    00309             BucketSize = 2;
    00310         }
    00311     }
    00312 #endif
    00313
    00314     if ((BucketSize > 31) || (BucketSize < 2)) {
    00315         return STATUS_INVALID_PARAMETER;
    00316     }
    00317
    00318     if ((RangeSize >> (BucketSize - 2)) > BufferSize) {
    00319         return STATUS_BUFFER_TOO_SMALL;
    00320     }
    00321
    00322     if (((ULONG_PTR)RangeBase + RangeSize) < RangeSize) {
    00323         return STATUS_BUFFER_OVERFLOW;
    00324     }
    00325
    00326     //
    00327     // Establish an exception handler, probe the output handle address, and
    00328     // attempt to create a profile object. If the probe fails, then return the
    00329     // exception code as the service status. Otherwise return the status value
    00330     // returned by the object insertion routine.
    00331     //
    00332
    00333     try {
    00334         //
    00335         // Get previous processor mode and probe output handle address if
    00336         // necessary.
    00337         //
    00338
    00339         PreviousMode = KeGetPreviousMode ();
    00340
    00341         if (PreviousMode != KernelMode) {
    00342             ProbeForWriteHandle(ProfileHandle);
    00343
    00344             ProbeForWrite(Buffer,
    00345                           BufferSize,
    00346                           sizeof(ULONG));
    00347         }
    00348
    00349     //
    00350     // If an exception occurs during the probe of the output handle address,
    00351     // then always handle the exception and return the exception code as the
    00352     // status value.
    00353     //
    00354
    00355     } except (EXCEPTION_EXECUTE_HANDLER) {
    00356         return GetExceptionCode();
    00357     }
    00358
    00359 //
    00360 // TODO post NT5:
    00361 //
    00362 // Currently, if a process isn't specified, there is no privilege check if
    00363 //   RangeBase > MM_HIGHEST_USER_ADDRESS.
    00364 // The check for user-space addresses is SeSystemProfilePrivilege.
    00365 // Querying a specific process requires only PROCESS_QUERY_INFORMATION.
    00366 //
    00367 // The spec says:
    00368 //
    00369 //     Process - If specified, a handle to a process which describes the address space to profile.
    00370 //     If not present, then all address spaces are included in the profile.
    00371 //     Profiling a process requires PROCESS_QUERY_INFORMATION access to that process and
    00372 //     SeProfileSingleProcessPrivilege privilege.
    00373 //     Profiling all processes requires SeSystemProfilePrivilege privilege.
    00374 //
    00375 // So two changes appear needed.
    00376 //   A check on SeProfileSingleProcessPrivilege needs to be added to the single process case,
    00377 //   and SeSystemProfilePrivilege privilege should be required for both user and system address profiling.
    00378 //
    00379
    00380
    00381     if (!ARGUMENT_PRESENT(Process)) {
    00382
    00383         //
    00384         // Don't attach segmented profile objects to all processes
    00385         //
    00386
    00387         if (Segment) {
    00388             return STATUS_INVALID_PARAMETER;
    00389         }
    00390
    00391         //
    00392         // Profile all processes. Make sure that the specified
    00393         // address range is in system space, unless SeSystemProfilePrivilege.
    00394         //
    00395
    00396         if (RangeBase <= MM_HIGHEST_USER_ADDRESS) {
    00397
    00398             //
    00399             // Check for privilege before allowing a user to profile
    00400             // all processes and USER addresses.
    00401             //
    00402
    00403             if (PreviousMode != KernelMode) {
    00404                 HasPrivilege =  SeSinglePrivilegeCheck(
    00405                                     SeSystemProfilePrivilege,
    00406                                     PreviousMode
    00407                                     );
    00408
    00409                 if (!HasPrivilege) {
    00410 #if DBG
    00411                     DbgPrint("SeSystemProfilePrivilege needed to profile all USER addresses.\n");
    00412 #endif //DBG
    00413                     return( STATUS_PRIVILEGE_NOT_HELD );
    00414                 }
    00415
    00416             }
    00417         }
    00418
    00419         ProcessAddress = NULL;
    00420
    00421
    00422     } else {
    00423
    00424         //
    00425         // Reference the specified process.
    00426         //
    00427
    00428         Status = ObReferenceObjectByHandle ( Process,
    00429                                              PROCESS_QUERY_INFORMATION,
    00430                                              PsProcessType,
    00431                                              PreviousMode,
    00432                                              (PVOID *)&ProcessAddress,
    00433                                              NULL );
    00434
    00435         if (!NT_SUCCESS(Status)) {
    00436             return Status;
    00437         }
    00438     }
    00439
    00440     InitializeObjectAttributes( &ObjectAttributes,
    00441                                 NULL,
    00442                                 OBJ_EXCLUSIVE,
    00443                                 NULL,
    00444                                 NULL );
    00445
    00446     Status = ObCreateObject( KernelMode,
    00447                              ExProfileObjectType,
    00448                              &ObjectAttributes,
    00449                              PreviousMode,
    00450                              NULL,
    00451                              sizeof(EPROFILE),
    00452                              0,
    00453                              sizeof(EPROFILE) + sizeof(KPROFILE),
    00454                              (PVOID *)&Profile);
    00455
    00456     //
    00457     // If the profile object was successfully allocated, initialize
    00458     // the profile object.
    00459     //
    00460     if (NT_SUCCESS(Status)) {
    00461
    00462
    00463         if (ProcessAddress != NULL) {
    00464             Profile->Process = &ProcessAddress->Pcb;
    00465         } else {
    00466             Profile->Process = NULL;
    00467         }
    00468
    00469         Profile->RangeBase = RangeBase;
    00470         Profile->RangeSize = RangeSize;
    00471         Profile->Buffer = Buffer;
    00472         Profile->BufferSize = BufferSize;
    00473         Profile->BucketSize = BucketSize;
    00474         Profile->LockedBufferAddress = NULL;
    00475         Profile->Segment = Segment;
    00476         Profile->ProfileSource = ProfileSource;
    00477         Profile->Affinity = Affinity;
    00478
    00479         Status = ObInsertObject(Profile,
    00480                                 NULL,
    00481                                 PROFILE_CONTROL,
    00482                                 0,
    00483                                 (PVOID *)NULL,
    00484                                 &Handle);
    00485         //
    00486         // If the profile object was successfully inserted in the current
    00487         // process' handle table, then attempt to write the profile object
    00488         // handle value. If the write attempt fails, then do not report
    00489         // an error. When the caller attempts to access the handle value,
    00490         // an access violation will occur.
    00491         //
    00492         if (NT_SUCCESS(Status)) {
    00493             try {
    00494                 *ProfileHandle = Handle;
    00495             } except(EXCEPTION_EXECUTE_HANDLER) {
    00496             }
    00497         }
    00498     }
    00499
    00500     //
    00501     // If we failed, remove our reference to the process object.
    00502     //
    00503     if (!NT_SUCCESS(Status)) {
    00504         if (ProcessAddress != NULL) {
    00505             ObDereferenceObject ((PVOID)ProcessAddress);
    00506         }
    00507     }
    00508
    00509     //
    00510     // Return service status.
    00511     //
    00512
    00513     return Status;
    00514 }

NTSTATUS NtQueryIntervalProfile | ( | IN KPROFILE_SOURCE | ProfileSource,
|  | OUT PULONG | Interval
| ) |

Definition at line 788 of file ex/profile.c.

References EXCEPTION_EXECUTE_HANDLER, KeQueryIntervalProfile(), KernelMode, KPROCESSOR_MODE, and ProbeForWriteUlong.

    00795                    :
    00796
    00797     This routine queries the system-wide interval (and thus the profiling
    00798     rate) for profiling.
    00799
    00800 Arguments:
    00801
    00802     Source - Specifies the profile source to be queried.
    00803
    00804     Interval - Returns the sampling interval in 100ns units.
    00805
    00806 Return Value:
    00807
    00808     TBS
    00809
    00810 --*/
    00811
    00812 {
    00813     ULONG CapturedInterval;
    00814     KPROCESSOR_MODE PreviousMode;
    00815
    00816     PreviousMode = KeGetPreviousMode ();
    00817     if (PreviousMode != KernelMode) {
    00818
    00819         //
    00820         // Probe accessibility of user's buffer.
    00821         //
    00822
    00823         try {
    00824             ProbeForWriteUlong (Interval);
    00825
    00826         } except (EXCEPTION_EXECUTE_HANDLER) {
    00827
    00828             //
    00829             // If an exception occurs during the probe or capture
    00830             // of the initial values, then handle the exception and
    00831             // return the exception code as the status value.
    00832             //
    00833
    00834             return GetExceptionCode();
    00835         }
    00836     }
    00837
    00838     CapturedInterval = KeQueryIntervalProfile (ProfileSource);
    00839
    00840     try {
    00841         *Interval = CapturedInterval;
    00842
    00843     } except (EXCEPTION_EXECUTE_HANDLER) {
    00844         NOTHING;
    00845     }
    00846
    00847     return STATUS_SUCCESS;
    00848 }

NTSTATUS NtQueryPerformanceCounter | ( | OUT PLARGE_INTEGER | PerformanceCounter,
|  | OUT PLARGE_INTEGER PerformanceFrequency | OPTIONAL
| ) |

Definition at line 851 of file ex/profile.c.

References EXCEPTION_EXECUTE_HANDLER, KeQueryPerformanceCounter(), KernelMode, KPROCESSOR_MODE, and ProbeForWrite().

Referenced by LdrpInitialize(), LdrpInitializeProcess(), LdrpMapDll(), NapDllInit(), and RtlpDebugPageHeapCreate().

    00858                    :
    00859
    00860     This function returns current value of performance counter and,
    00861     optionally, the frequency of the performance counter.
    00862
    00863     Performance frequency is the frequency of the performance counter
    00864     in Hertz, i.e., counts/second.  Note that this value is implementation
    00865     dependent.  If the implementation does not have hardware to support
    00866     performance timing, the value returned is 0.
    00867
    00868 Arguments:
    00869
    00870     PerformanceCounter - supplies the address of a variable to receive
    00871         the current Performance Counter value.
    00872
    00873     PerformanceFrequency - Optionally, supplies the address of a
    00874         variable to receive the performance counter frequency.
    00875
    00876 Return Value:
    00877
    00878     STATUS_ACCESS_VIOLATION or STATUS_SUCCESS.
    00879
    00880 --*/
    00881
    00882 {
    00883     KPROCESSOR_MODE PreviousMode;
    00884     LARGE_INTEGER KernelPerformanceFrequency;
    00885
    00886     PreviousMode = KeGetPreviousMode();
    00887     if (PreviousMode != KernelMode) {
    00888
    00889         //
    00890         // Probe accessibility of user's buffer.
    00891         //
    00892
    00893         try {
    00894             ProbeForWrite ( PerformanceCounter,
    00895                             sizeof (LARGE_INTEGER),
    00896                             sizeof (ULONG)
    00897                           );
    00898
    00899             if (ARGUMENT_PRESENT(PerformanceFrequency)) {
    00900                 ProbeForWrite ( PerformanceFrequency,
    00901                                 sizeof (LARGE_INTEGER),
    00902                                 sizeof (ULONG)
    00903                               );
    00904             }
    00905
    00906         } except (EXCEPTION_EXECUTE_HANDLER) {
    00907
    00908             //
    00909             // If an exception occurs during the probe or capture
    00910             // of the initial values, then handle the exception and
    00911             // return the exception code as the status value.
    00912             //
    00913
    00914             return GetExceptionCode();
    00915         }
    00916     }
    00917
    00918     try {
    00919         *PerformanceCounter = KeQueryPerformanceCounter (
    00920                                   (PLARGE_INTEGER)&KernelPerformanceFrequency );
    00921         if (ARGUMENT_PRESENT(PerformanceFrequency)) {
    00922             *PerformanceFrequency = KernelPerformanceFrequency;
    00923         }
    00924     } except (EXCEPTION_EXECUTE_HANDLER) {
    00925         return GetExceptionCode();
    00926     }
    00927
    00928     return STATUS_SUCCESS;
    00929 }
    }

NTSTATUS NtSetIntervalProfile | ( | IN ULONG | Interval,
|  | IN KPROFILE_SOURCE | Source
| ) |

Definition at line 757 of file ex/profile.c.

References KeSetIntervalProfile().

    00764                    :
    00765
    00766     This routine allows the system-wide interval (and thus the profiling
    00767     rate) for profiling to be set.
    00768
    00769 Arguments:
    00770
    00771     Interval - Supplies the sampling interval in 100ns units.
    00772
    00773     Source - Specifies the profile source to be set.
    00774
    00775 Return Value:
    00776
    00777     TBS
    00778
    00779 --*/
    00780
    00781 {
    00782
    00783     KeSetIntervalProfile (Interval, Source);
    00784     return STATUS_SUCCESS;
    00785 }

NTSTATUS NtStartProfile | ( | IN HANDLE | ProfileHandle | ) |

Definition at line 517 of file ex/profile.c.

References ACTIVE_PROFILE_LIMIT, ASSERT, ExAllocatePoolWithTag, EXCEPTION_EXECUTE_HANDLER, Executive, ExFreePool(), ExpCurrentProfileUsage, ExpProfileStateMutex, ExProfileObjectType, FALSE, IoWriteAccess, KeInitializeProfile(), KeReleaseMutex(), KernelMode, KeStartProfile(), KeWaitForSingleObject(), KPROCESSOR_MODE, MmCached, MmInitializeMdl, MmMapLockedPagesSpecifyCache(), MmProbeAndLockPages(), MmSizeOfMdl(), MmUnlockPages(), MmUnmapLockedPages(), NonPagedPool, NormalPagePriority, NT_SUCCESS, NTSTATUS(), NULL, ObDereferenceObject, ObReferenceObjectByHandle(), PEPROFILE, ProfileObject, and Status.

Referenced by main().

    00523                    :
    00524
    00525     The NtStartProfile routine starts the collecting data for the
    00526     specified profile object.  This involved allocating nonpaged
    00527     pool to lock the specified buffer in memory, creating a kernel
    00528     profile object and starting collecting on that profile object.
    00529
    00530 Arguments:
    00531
    00532     ProfileHandle - Supplies the profile handle to start profiling on.
    00533
    00534 Return Value:
    00535
    00536     TBS
    00537
    00538 --*/
    00539
    00540 {
    00541
    00542     KPROCESSOR_MODE PreviousMode;
    00543     NTSTATUS Status;
    00544     PEPROFILE Profile;
    00545     PKPROFILE ProfileObject;
    00546     PVOID LockedVa;
    00547     BOOLEAN State;
    00548
    00549     PreviousMode = KeGetPreviousMode();
    00550
    00551     Status = ObReferenceObjectByHandle( ProfileHandle,
    00552                                         PROFILE_CONTROL,
    00553                                         ExProfileObjectType,
    00554                                         PreviousMode,
    00555                                         (PVOID *)&Profile,
    00556                                         NULL);
    00557     if (!NT_SUCCESS(Status)) {
    00558         return Status;
    00559     }
    00560
    00561     //
    00562     // Acquire the profile state mutex so two threads can't
    00563     // operate on the same profile object simultaneously.
    00564     //
    00565
    00566     KeWaitForSingleObject( &ExpProfileStateMutex,
    00567                            Executive,
    00568                            KernelMode,
    00569                            FALSE,
    00570                            (PLARGE_INTEGER)NULL);
    00571
    00572     //
    00573     // Make sure profiling is not already enabled.
    00574     //
    00575
    00576     if (Profile->LockedBufferAddress != NULL) {
    00577         KeReleaseMutex (&ExpProfileStateMutex, FALSE);
    00578         ObDereferenceObject ((PVOID)Profile);
    00579         return STATUS_PROFILING_NOT_STOPPED;
    00580     }
    00581
    00582     if (ExpCurrentProfileUsage == ACTIVE_PROFILE_LIMIT) {
    00583         KeReleaseMutex (&ExpProfileStateMutex, FALSE);
    00584         ObDereferenceObject ((PVOID)Profile);
    00585         return STATUS_PROFILING_AT_LIMIT;
    00586     }
    00587
    00588     ProfileObject = ExAllocatePoolWithTag (NonPagedPool,
    00589                                     MmSizeOfMdl(Profile->Buffer,
    00590                                                 Profile->BufferSize) +
    00591                                         sizeof(KPROFILE),
    00592                                         'forP');
    00593
    00594     if (ProfileObject == NULL) {
    00595         KeReleaseMutex (&ExpProfileStateMutex, FALSE);
    00596         ObDereferenceObject ((PVOID)Profile);
    00597         return STATUS_INSUFFICIENT_RESOURCES;
    00598     }
    00599
    00600     Profile->Mdl = (PMDL)(ProfileObject + 1);
    00601     Profile->ProfileObject = ProfileObject;
    00602
    00603     //
    00604     // Probe and lock the specified buffer.
    00605     //
    00606
    00607     MmInitializeMdl(Profile->Mdl, Profile->Buffer, Profile->BufferSize);
    00608
    00609     try {
    00610
    00611         LockedVa = NULL;
    00612
    00613         MmProbeAndLockPages (Profile->Mdl,
    00614                              PreviousMode,
    00615                              IoWriteAccess );
    00616
    00617         LockedVa = (PVOID)43;  // flag to notice MmMapLockedPages failed.
    00618
    00619         LockedVa = MmMapLockedPagesSpecifyCache (Profile->Mdl,
    00620                                                  KernelMode,
    00621                                                  MmCached,
    00622                                                  NULL,
    00623                                                  FALSE,
    00624                                                  NormalPagePriority);
    00625
    00626     } except (EXCEPTION_EXECUTE_HANDLER) {
    00627
    00628         if (LockedVa == (PVOID)43 ) {
    00629             MmUnlockPages (Profile->Mdl);
    00630         }
    00631         ExFreePool (ProfileObject);
    00632         KeReleaseMutex (&ExpProfileStateMutex, FALSE);
    00633         ObDereferenceObject ((PVOID)Profile);
    00634         return GetExceptionCode();
    00635     }
    00636
    00637     if (LockedVa == NULL) {
    00638         MmUnlockPages (Profile->Mdl);
    00639         ExFreePool (ProfileObject);
    00640         KeReleaseMutex (&ExpProfileStateMutex, FALSE);
    00641         ObDereferenceObject ((PVOID)Profile);
    00642         return STATUS_INSUFFICIENT_RESOURCES;
    00643     }
    00644
    00645     //
    00646     // Initialize the profile object.
    00647     //
    00648
    00649     KeInitializeProfile (ProfileObject,
    00650                          Profile->Process,
    00651                          Profile->RangeBase,
    00652                          Profile->RangeSize,
    00653                          Profile->BucketSize,
    00654                          Profile->Segment,
    00655                          Profile->ProfileSource,
    00656                          Profile->Affinity);
    00657     try {
    00658         State = KeStartProfile (ProfileObject, LockedVa);
    00659         ASSERT (State != FALSE);
    00660
    00661     } except (EXCEPTION_EXECUTE_HANDLER) {
    00662
    00663         MmUnlockPages (Profile->Mdl);
    00664         MmUnmapLockedPages (LockedVa, Profile->Mdl);
    00665         ExFreePool (ProfileObject);
    00666         KeReleaseMutex (&ExpProfileStateMutex, FALSE);
    00667         ObDereferenceObject ((PVOID)Profile);
    00668         return GetExceptionCode();
    00669     }
    00670
    00671     Profile->LockedBufferAddress = LockedVa;
    00672
    00673     KeReleaseMutex (&ExpProfileStateMutex, FALSE);
    00674     ObDereferenceObject ((PVOID)Profile);
    00675
    00676     return STATUS_SUCCESS;
    00677 }

NTSTATUS NtStopProfile | ( | IN HANDLE | ProfileHandle | ) |

Definition at line 680 of file ex/profile.c.

References ASSERT, Executive, ExFreePool(), ExpProfileStateMutex, ExProfileObjectType, FALSE, KeReleaseMutex(), KernelMode, KeStopProfile(), KeWaitForSingleObject(), KPROCESSOR_MODE, MmUnlockPages(), MmUnmapLockedPages(), NT_SUCCESS, NTSTATUS(), NULL, ObDereferenceObject, ObReferenceObjectByHandle(), PEPROFILE, and Status.

Referenced by main().

    00686                    :
    00687
    00688     The NtStopProfile routine stops collecting data for the
    00689     specified profile object.  This involves stopping the data
    00690     collection on the profile object, unlocking the locked buffers,
    00691     and deallocating the pool for the MDL and profile object.
    00692
    00693 Arguments:
    00694
    00695     ProfileHandle - Supplies a the profile handle to stop profiling.
    00696
    00697 Return Value:
    00698
    00699     TBS
    00700
    00701 --*/
    00702
    00703 {
    00704
    00705     PEPROFILE Profile;
    00706     KPROCESSOR_MODE PreviousMode;
    00707     NTSTATUS Status;
    00708     BOOLEAN State;
    00709
    00710     PreviousMode = KeGetPreviousMode();
    00711
    00712     Status = ObReferenceObjectByHandle( ProfileHandle,
    00713                                         PROFILE_CONTROL,
    00714                                         ExProfileObjectType,
    00715                                         PreviousMode,
    00716                                         (PVOID *)&Profile,
    00717                                         NULL);
    00718
    00719     if (!NT_SUCCESS(Status)) {
    00720         return Status;
    00721     }
    00722
    00723     KeWaitForSingleObject( &ExpProfileStateMutex,
    00724                            Executive,
    00725                            KernelMode,
    00726                            FALSE,
    00727                            (PLARGE_INTEGER)NULL);
    00728
    00729     //
    00730     // Check to see if profiling is not active.
    00731     //
    00732
    00733     if (Profile->LockedBufferAddress == NULL) {
    00734         KeReleaseMutex (&ExpProfileStateMutex, FALSE);
    00735         ObDereferenceObject ((PVOID)Profile);
    00736         return STATUS_PROFILING_NOT_STARTED;
    00737     }
    00738
    00739     //
    00740     // Stop profiling and unlock the buffer.
    00741     //
    00742
    00743     State = KeStopProfile (Profile->ProfileObject);
    00744     ASSERT (State != FALSE);
    00745
    00746     MmUnmapLockedPages (Profile->LockedBufferAddress, Profile->Mdl);
    00747     MmUnlockPages (Profile->Mdl);
    00748     ExFreePool (Profile->ProfileObject);
    00749     Profile->LockedBufferAddress = NULL;
    00750     KeReleaseMutex (&ExpProfileStateMutex, FALSE);
    00751
    00752     ObDereferenceObject ((PVOID)Profile);
    00753     return STATUS_SUCCESS;
    00754 }

## Variable Documentation

ULONG ExpCurrentProfileUsage = 0

| Definition at line 55 of file ex/profile.c. Referenced by NtStartProfile().

GENERIC_MAPPING ExpProfileMapping

Initial value:

     {
        STANDARD_RIGHTS_READ | PROFILE_CONTROL,
        STANDARD_RIGHTS_WRITE | PROFILE_CONTROL,
        STANDARD_RIGHTS_EXECUTE | PROFILE_CONTROL,
        PROFILE_ALL_ACCESS
    }

Definition at line 57 of file ex/profile.c.

Referenced by ExpProfileInitialization().

KMUTEX ExpProfileStateMutex

| Definition at line 53 of file ex/profile.c. Referenced by ExpProfileInitialization(), NtStartProfile(), and NtStopProfile().

POBJECT_TYPE ExProfileObjectType

| Definition at line 51 of file ex/profile.c. Referenced by ExpProfileInitialization(), NtCreateProfile(), NtStartProfile(), and NtStopProfile().