ReactOS 0.4.16-dev-289-g096a551
profile.c
Go to the documentation of this file.
1/*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel
4 * FILE: ntoskrnl/ex/profile.c
5 * PURPOSE: Support for Executive Profile Objects
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 * Thomas Weidenmueller
8 */
9
10/* INCLUDES *****************************************************************/
11
12#include <ntoskrnl.h>
13#define NDEBUG
14#include <debug.h>
15
16/* GLOBALS *******************************************************************/
17
20
22{
27};
28
29/* FUNCTIONS *****************************************************************/
30
31VOID
34{
35 PEPROFILE Profile;
37
38 /* Typecast the Object */
39 Profile = ObjectBody;
40
41 /* Check if there if the Profile was started */
42 if (Profile->LockedBufferAddress)
43 {
44 /* Stop the Profile */
46 ASSERT(State != FALSE);
47
48 /* Unmap the Locked Buffer */
49 MmUnmapLockedPages(Profile->LockedBufferAddress, Profile->Mdl);
50 MmUnlockPages(Profile->Mdl);
51 IoFreeMdl(Profile->Mdl);
53 }
54
55 /* Check if a Process is associated and reference it */
56 if (Profile->Process) ObDereferenceObject(Profile->Process);
57}
58
59CODE_SEG("INIT")
63{
64 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
67 DPRINT("Creating Profile Object Type\n");
68
69 /* Initialize the Mutex to lock the States */
71
72 /* Create the Event Pair Object Type */
73 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
74 RtlInitUnicodeString(&Name, L"Profile");
75 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
76 ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(KPROFILE);
77 ObjectTypeInitializer.GenericMapping = ExpProfileMapping;
78 ObjectTypeInitializer.PoolType = NonPagedPool;
79 ObjectTypeInitializer.DeleteProcedure = ExpDeleteProfile;
80 ObjectTypeInitializer.ValidAccessMask = PROFILE_ALL_ACCESS;
81 ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK;
82 Status = ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &ExProfileObjectType);
83 if (!NT_SUCCESS(Status)) return FALSE;
84 return TRUE;
85}
86
91 IN PVOID RangeBase,
92 IN SIZE_T RangeSize,
93 IN ULONG BucketSize,
96 IN KPROFILE_SOURCE ProfileSource,
98{
99 HANDLE hProfile;
100 PEPROFILE Profile;
101 PEPROCESS pProcess;
105 ULONG Log2 = 0;
106 ULONG_PTR Segment = 0;
107 PAGED_CODE();
108
109 /* Easy way out */
111
112 /* Check if this is a low-memory profile */
113 if ((!BucketSize) && (RangeBase < (PVOID)(0x10000)))
114 {
115 /* Validate size */
116 if (BufferSize < sizeof(ULONG)) return STATUS_INVALID_PARAMETER_7;
117
118 /* This will become a segmented profile object */
119 Segment = (ULONG_PTR)RangeBase;
120 RangeBase = 0;
121
122 /* Recalculate the bucket size */
123 BucketSize = RangeSize / (BufferSize / sizeof(ULONG));
124
125 /* Convert it to log2 */
126 BucketSize--;
127 while (BucketSize >>= 1) Log2++;
128 BucketSize += Log2 + 1;
129 }
130
131 /* Validate bucket size */
132 if ((BucketSize > 31) || (BucketSize < 2))
133 {
134 DPRINT1("Bucket size invalid\n");
136 }
137
138 /* Make sure that the buckets can map the range */
139 if ((RangeSize >> (BucketSize - 2)) > BufferSize)
140 {
141 DPRINT1("Bucket size too small\n");
143 }
144
145 /* Make sure that the range isn't too gigantic */
146 if (((ULONG_PTR)RangeBase + RangeSize) < RangeSize)
147 {
148 DPRINT1("Range too big\n");
150 }
151
152 /* Check if we were called from user-mode */
154 {
155 /* Entry SEH */
157 {
158 /* Make sure that the handle pointer is valid */
159 ProbeForWriteHandle(ProfileHandle);
160
161 /* Check if the buffer is valid */
164 sizeof(ULONG));
165 }
167 {
168 /* Return the exception code */
170 }
171 _SEH2_END;
172 }
173
174 /* Check if a process was specified */
175 if (Process)
176 {
177 /* Reference it */
182 (PVOID*)&pProcess,
183 NULL);
184 if (!NT_SUCCESS(Status)) return(Status);
185 }
186 else
187 {
188 /* Segmented profile objects cannot be used system-wide */
190
191 /* No process was specified, which means a System-Wide Profile */
192 pProcess = NULL;
193
194 /* For this, we need to check the Privilege */
196 {
197 DPRINT1("NtCreateProfile: Caller requires the SeSystemProfilePrivilege privilege!\n");
199 }
200 }
201
202 /* Create the object */
204 NULL,
205 0,
206 NULL,
207 NULL);
212 NULL,
213 sizeof(EPROFILE),
214 0,
215 sizeof(EPROFILE) + sizeof(KPROFILE),
216 (PVOID*)&Profile);
217 if (!NT_SUCCESS(Status))
218 {
219 /* Dereference the process object if it was specified */
220 if (pProcess) ObDereferenceObject(pProcess);
221
222 /* Return Status */
223 return Status;
224 }
225
226 /* Initialize it */
227 Profile->RangeBase = RangeBase;
228 Profile->RangeSize = RangeSize;
229 Profile->Buffer = Buffer;
230 Profile->BufferSize = BufferSize;
231 Profile->BucketSize = BucketSize;
232 Profile->LockedBufferAddress = NULL;
233 Profile->Segment = Segment;
234 Profile->ProfileSource = ProfileSource;
235 Profile->Affinity = Affinity;
236 Profile->Process = pProcess;
237
238 /* Insert into the Object Tree */
239 Status = ObInsertObject ((PVOID)Profile,
240 NULL,
242 0,
243 NULL,
244 &hProfile);
245
246 /* Check for Success */
247 if (!NT_SUCCESS(Status))
248 {
249 /* Dereference Process on failure */
250 if (pProcess) ObDereferenceObject(pProcess);
251 return Status;
252 }
253
254 /* Enter SEH */
256 {
257 /* Copy the created handle back to the caller*/
258 *ProfileHandle = hProfile;
259 }
261 {
263 }
264 _SEH2_END;
265
266 /* Return Status */
267 return Status;
268}
269
271NTAPI
273 OUT PLARGE_INTEGER PerformanceFrequency OPTIONAL)
274{
276 LARGE_INTEGER PerfFrequency;
278
279 /* Check if we were called from user-mode */
281 {
282 /* Entry SEH Block */
284 {
285 /* Make sure the counter and frequency are valid */
286 ProbeForWriteLargeInteger(PerformanceCounter);
287 if (PerformanceFrequency)
288 {
289 ProbeForWriteLargeInteger(PerformanceFrequency);
290 }
291 }
293 {
294 /* Return the exception code */
296 }
297 _SEH2_END;
298 }
299
300 /* Enter a new SEH Block */
302 {
303 /* Query the Kernel */
304 *PerformanceCounter = KeQueryPerformanceCounter(&PerfFrequency);
305
306 /* Return Frequency if requested */
307 if (PerformanceFrequency) *PerformanceFrequency = PerfFrequency;
308 }
310 {
311 /* Get the exception code */
313 }
314 _SEH2_END;
315
316 /* Return status to caller */
317 return Status;
318}
319
321NTAPI
323{
324 PEPROFILE Profile;
327 PVOID TempLockedBufferAddress;
329 PAGED_CODE();
330
331 /* Get the Object */
332 Status = ObReferenceObjectByHandle(ProfileHandle,
336 (PVOID*)&Profile,
337 NULL);
338 if (!NT_SUCCESS(Status)) return(Status);
339
340 /* To avoid a Race, wait on the Mutex */
342 Executive,
344 FALSE,
345 NULL);
346
347 /* The Profile can still be enabled though, so handle that */
348 if (Profile->LockedBufferAddress)
349 {
350 /* Release our lock, dereference and return */
352 ObDereferenceObject(Profile);
354 }
355
356 /* Allocate a Kernel Profile Object. */
358 sizeof(*ProfileObject),
360 if (!ProfileObject)
361 {
362 /* Out of memory, fail */
364 ObDereferenceObject(Profile);
366 }
367
368 /* Allocate the Mdl Structure */
369 Profile->Mdl = IoAllocateMdl(Profile->Buffer, Profile->BufferSize, FALSE, FALSE, NULL);
370
371 /* Protect this in SEH as we might raise an exception */
373 {
374 /* Probe and Lock for Write Access */
376 }
378 {
379 /* Release our lock, free the buffer, dereference and return */
381 ObDereferenceObject(Profile);
384 }
385 _SEH2_END;
386
387 /* Map the pages */
388 TempLockedBufferAddress = MmMapLockedPages(Profile->Mdl, KernelMode);
389
390 /* Initialize the Kernel Profile Object */
391 Profile->ProfileObject = ProfileObject;
393 &Profile->Process->Pcb,
394 Profile->RangeBase,
395 Profile->RangeSize,
396 Profile->BucketSize,
397 Profile->ProfileSource,
398 Profile->Affinity);
399
400 /* Start the Profiling */
401 KeStartProfile(ProfileObject, TempLockedBufferAddress);
402
403 /* Now it's safe to save this */
404 Profile->LockedBufferAddress = TempLockedBufferAddress;
405
406 /* Release mutex, dereference and return */
408 ObDereferenceObject(Profile);
409 return STATUS_SUCCESS;
410}
411
413NTAPI
414NtStopProfile(IN HANDLE ProfileHandle)
415{
416 PEPROFILE Profile;
419 PAGED_CODE();
420
421 /* Get the Object */
422 Status = ObReferenceObjectByHandle(ProfileHandle,
426 (PVOID*)&Profile,
427 NULL);
428 if (!NT_SUCCESS(Status)) return(Status);
429
430 /* Get the Mutex */
432 Executive,
434 FALSE,
435 NULL);
436
437 /* Make sure the Profile Object is really Started */
438 if (!Profile->LockedBufferAddress)
439 {
441 goto Exit;
442 }
443
444 /* Stop the Profile */
446
447 /* Unlock the Buffer */
448 MmUnmapLockedPages(Profile->LockedBufferAddress, Profile->Mdl);
449 MmUnlockPages(Profile->Mdl);
450 IoFreeMdl(Profile->Mdl);
452
453 /* Clear the Locked Buffer pointer, meaning the Object is Stopped */
454 Profile->LockedBufferAddress = NULL;
455
456Exit:
457 /* Release Mutex, Dereference and Return */
459 ObDereferenceObject(Profile);
460 return Status;
461}
462
464NTAPI
467{
469 ULONG ReturnInterval;
471 PAGED_CODE();
472
473 /* Check if we were called from user-mode */
475 {
476 /* Enter SEH Block */
478 {
479 /* Validate interval */
481 }
483 {
484 /* Return the exception code */
486 }
487 _SEH2_END;
488 }
489
490 /* Query the Interval */
491 ReturnInterval = (ULONG)KeQueryIntervalProfile(ProfileSource);
492
493 /* Enter SEH block for return */
495 {
496 /* Return the data */
497 *Interval = ReturnInterval;
498 }
500 {
501 /* Get the exception code */
503 }
504 _SEH2_END;
505
506 /* Return Success */
507 return Status;
508}
509
511NTAPI
514{
515 /* Let the Kernel do the job */
517
518 /* Nothing can go wrong */
519 return STATUS_SUCCESS;
520}
#define PAGED_CODE()
#define CODE_SEG(...)
#define STATUS_PRIVILEGE_NOT_HELD
Definition: DriverTester.h:9
unsigned char BOOLEAN
struct NameRec_ * Name
Definition: cdprocs.h:460
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
Definition: bufpool.h:45
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:36
#define BufferSize
Definition: mmc.h:75
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
ULONG_PTR KAFFINITY
Definition: compat.h:85
#define ULONG_PTR
Definition: config.h:101
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
#define KeWaitForSingleObject(pEvt, foo, a, b, c)
Definition: env_spec_w32.h:478
#define NonPagedPool
Definition: env_spec_w32.h:307
#define ExGetPreviousMode
Definition: ex.h:140
VOID NTAPI ProbeForWrite(IN PVOID Address, IN SIZE_T Length, IN ULONG Alignment)
Definition: exintrin.c:143
_Must_inspect_result_ _In_ PLARGE_INTEGER _In_ PLARGE_INTEGER _In_ ULONG _In_ PFILE_OBJECT _In_ PVOID Process
Definition: fsrtlfuncs.h:223
#define IoFreeMdl
Definition: fxmdl.h:89
#define IoAllocateMdl
Definition: fxmdl.h:88
Status
Definition: gdiplustypes.h:25
LARGE_INTEGER NTAPI KeQueryPerformanceCounter(IN PLARGE_INTEGER PerformanceFreq)
Definition: timer.c:138
LONG NTAPI ExSystemExceptionFilter(VOID)
Definition: harderr.c:349
#define PROCESS_QUERY_INFORMATION
Definition: pstypes.h:167
#define OBJ_OPENLINK
Definition: winternl.h:230
enum _KPROFILE_SOURCE KPROFILE_SOURCE
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
PVOID NTAPI MmMapLockedPages(IN PMDL Mdl, IN KPROCESSOR_MODE AccessMode)
Definition: mdlsup.c:818
VOID NTAPI MmProbeAndLockPages(IN PMDL Mdl, IN KPROCESSOR_MODE AccessMode, IN LOCK_OPERATION Operation)
Definition: mdlsup.c:931
VOID NTAPI MmUnlockPages(IN PMDL Mdl)
Definition: mdlsup.c:1435
VOID NTAPI MmUnmapLockedPages(IN PVOID BaseAddress, IN PMDL Mdl)
Definition: mdlsup.c:837
#define ASSERT(a)
Definition: mode.c:44
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1109
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
_In_ UINT _In_ UINT _In_ PNDIS_PACKET Source
Definition: ndis.h:3169
#define KernelMode
Definition: asm.h:34
#define PROFILE_ALL_ACCESS
Definition: extypes.h:131
#define PROFILE_CONTROL
Definition: extypes.h:130
struct _KPROFILE KPROFILE
@ ProfileObject
Definition: ketypes.h:429
DWORD Interval
Definition: netstat.c:30
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
#define STANDARD_RIGHTS_READ
Definition: nt_native.h:65
#define STANDARD_RIGHTS_WRITE
Definition: nt_native.h:66
#define STANDARD_RIGHTS_EXECUTE
Definition: nt_native.h:67
POBJECT_TYPE ExProfileObjectType
Definition: profile.c:18
NTSTATUS NTAPI NtQueryIntervalProfile(IN KPROFILE_SOURCE ProfileSource, OUT PULONG Interval)
Definition: profile.c:465
NTSTATUS NTAPI NtStopProfile(IN HANDLE ProfileHandle)
Definition: profile.c:414
NTSTATUS NTAPI NtCreateProfile(OUT PHANDLE ProfileHandle, IN HANDLE Process OPTIONAL, IN PVOID RangeBase, IN SIZE_T RangeSize, IN ULONG BucketSize, IN PVOID Buffer, IN ULONG BufferSize, IN KPROFILE_SOURCE ProfileSource, IN KAFFINITY Affinity)
Definition: profile.c:89
BOOLEAN NTAPI ExpInitializeProfileImplementation(VOID)
Definition: profile.c:62
NTSTATUS NTAPI NtStartProfile(IN HANDLE ProfileHandle)
Definition: profile.c:322
VOID NTAPI ExpDeleteProfile(PVOID ObjectBody)
Definition: profile.c:33
KMUTEX ExpProfileMutex
Definition: profile.c:19
GENERIC_MAPPING ExpProfileMapping
Definition: profile.c:21
NTSTATUS NTAPI NtQueryPerformanceCounter(OUT PLARGE_INTEGER PerformanceCounter, OUT PLARGE_INTEGER PerformanceFrequency OPTIONAL)
Definition: profile.c:272
NTSTATUS NTAPI NtSetIntervalProfile(IN ULONG Interval, IN KPROFILE_SOURCE Source)
Definition: profile.c:512
VOID NTAPI KeSetIntervalProfile(ULONG Interval, KPROFILE_SOURCE ProfileSource)
BOOLEAN NTAPI KeStopProfile(struct _KPROFILE *Profile)
ULONG NTAPI KeQueryIntervalProfile(KPROFILE_SOURCE ProfileSource)
VOID NTAPI KeInitializeProfile(struct _KPROFILE *Profile, struct _KPROCESS *Process, PVOID ImageBase, SIZE_T ImageSize, ULONG BucketSize, KPROFILE_SOURCE ProfileSource, KAFFINITY Affinity)
BOOLEAN NTAPI KeStartProfile(struct _KPROFILE *Profile, PVOID Buffer)
const LUID SeSystemProfilePrivilege
Definition: priv.c:30
VOID NTAPI KeInitializeMutex(IN PKMUTEX Mutex, IN ULONG Level)
Definition: mutex.c:67
LONG NTAPI KeReleaseMutex(IN PKMUTEX Mutex, IN BOOLEAN Wait)
Definition: mutex.c:189
POBJECT_TYPE PsProcessType
Definition: process.c:20
BOOLEAN NTAPI SeSinglePrivilegeCheck(_In_ LUID PrivilegeValue, _In_ KPROCESSOR_MODE PreviousMode)
Checks if a single privilege is present in the context of the calling thread.
Definition: priv.c:744
PVOID *typedef PHANDLE
Definition: ntsecpkg.h:455
#define STATUS_PROFILING_NOT_STOPPED
Definition: ntstatus.h:420
#define STATUS_INVALID_PARAMETER_7
Definition: ntstatus.h:481
#define STATUS_PROFILING_NOT_STARTED
Definition: ntstatus.h:419
#define L(x)
Definition: ntvdm.h:50
NTSTATUS NTAPI ObInsertObject(IN PVOID Object, IN PACCESS_STATE AccessState OPTIONAL, IN ACCESS_MASK DesiredAccess, IN ULONG ObjectPointerBias, OUT PVOID *NewObject OPTIONAL, OUT PHANDLE Handle)
Definition: obhandle.c:2935
NTSTATUS NTAPI ObCreateObject(IN KPROCESSOR_MODE ProbeMode OPTIONAL, IN POBJECT_TYPE Type, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN KPROCESSOR_MODE AccessMode, IN OUT PVOID ParseContext OPTIONAL, IN ULONG ObjectSize, IN ULONG PagedPoolCharge OPTIONAL, IN ULONG NonPagedPoolCharge OPTIONAL, OUT PVOID *Object)
Definition: oblife.c:1039
NTSTATUS NTAPI ObCreateObjectType(IN PUNICODE_STRING TypeName, IN POBJECT_TYPE_INITIALIZER ObjectTypeInitializer, IN PVOID Reserved, OUT POBJECT_TYPE *ObjectType)
Definition: oblife.c:1136
NTSTATUS NTAPI ObReferenceObjectByHandle(IN HANDLE Handle, IN ACCESS_MASK DesiredAccess, IN POBJECT_TYPE ObjectType, IN KPROCESSOR_MODE AccessMode, OUT PVOID *Object, OUT POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL)
Definition: obref.c:494
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:165
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:66
#define _SEH2_END
Definition: pseh2_64.h:155
#define _SEH2_TRY
Definition: pseh2_64.h:55
#define _SEH2_YIELD(__stmt)
Definition: pseh2_64.h:168
#define ProbeForWriteLargeInteger(Ptr)
Definition: probe.h:46
#define ProbeForWriteHandle(Ptr)
Definition: probe.h:43
#define ProbeForWriteUlong(Ptr)
Definition: probe.h:36
#define STATUS_SUCCESS
Definition: shellext.h:65
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:69
#define STATUS_BUFFER_OVERFLOW
Definition: shellext.h:66
#define DPRINT
Definition: sndvol32.h:73
static void Exit(void)
Definition: sock.c:1330
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
KPROCESS Pcb
Definition: pstypes.h:1263
KAFFINITY Affinity
Definition: extypes.h:566
PVOID LockedBufferAddress
Definition: extypes.h:562
PKPROFILE ProfileObject
Definition: extypes.h:561
ULONG BucketSize
Definition: extypes.h:560
PVOID RangeBase
Definition: extypes.h:556
ULONG BufferSize
Definition: extypes.h:559
ULONG_PTR Segment
Definition: extypes.h:564
SIZE_T RangeSize
Definition: extypes.h:557
PEPROCESS Process
Definition: extypes.h:555
KPROFILE_SOURCE ProfileSource
Definition: extypes.h:565
PMDL Mdl
Definition: extypes.h:563
PVOID Buffer
Definition: extypes.h:558
GENERIC_MAPPING GenericMapping
Definition: obtypes.h:358
OB_DELETE_METHOD DeleteProcedure
Definition: obtypes.h:369
ULONG DefaultNonPagedPoolCharge
Definition: obtypes.h:365
#define TAG_PROFILE
Definition: tag.h:30
uint32_t * PULONG
Definition: typedefs.h:59
#define NTAPI
Definition: typedefs.h:36
ULONG_PTR SIZE_T
Definition: typedefs.h:80
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define IN
Definition: typedefs.h:39
uint32_t ULONG
Definition: typedefs.h:59
#define OUT
Definition: typedefs.h:40
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
_In_ WDFMEMORY _Out_opt_ size_t * BufferSize
Definition: wdfmemory.h:254
_Inout_ PVOID Segment
Definition: exfuncs.h:1101
_In_ ULONG _In_ ULONG _In_ ULONG _Out_ PKIRQL _Out_ PKAFFINITY Affinity
Definition: halfuncs.h:174
@ Executive
Definition: ketypes.h:415
CCHAR KPROCESSOR_MODE
Definition: ketypes.h:7
@ IoWriteAccess
Definition: ketypes.h:864
#define ObDereferenceObject
Definition: obfuncs.h:203
_In_ KPROCESSOR_MODE PreviousMode
Definition: sefuncs.h:103