1. remove obsolete buffer size checks from NtQueryInformationProcess()
[reactos.git] / reactos / ntoskrnl / ex / profile.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /*
20 * PROJECT: ReactOS kernel
21 * FILE: ntoskrnl/nt/profile.c
22 * PURPOSE: Support for profiling
23 * PROGRAMMER: Nobody
24 * UPDATE HISTORY:
25 *
26 */
27
28 /* INCLUDES *****************************************************************/
29
30 #include <ntoskrnl.h>
31 #include <internal/debug.h>
32
33 /* TYPES ********************************************************************/
34
35 /* GLOBALS *******************************************************************/
36
37 POBJECT_TYPE EXPORTED ExProfileObjectType = NULL;
38
39 static GENERIC_MAPPING ExpProfileMapping = {
40 STANDARD_RIGHTS_READ,
41 STANDARD_RIGHTS_WRITE,
42 STANDARD_RIGHTS_EXECUTE,
43 STANDARD_RIGHTS_ALL};
44
45 /*
46 * Size of the profile hash table.
47 */
48 #define PROFILE_HASH_TABLE_SIZE (32)
49
50 /*
51 * Table of lists of per-process profiling data structures hashed by PID.
52 */
53 LIST_ENTRY ProcessProfileListHashTable[PROFILE_HASH_TABLE_SIZE];
54
55 /*
56 * Head of the list of profile data structures for the kernel.
57 */
58 LIST_ENTRY SystemProfileList;
59
60 /*
61 * Lock that protects the profiling data structures.
62 */
63 KSPIN_LOCK ProfileListLock;
64
65 /*
66 * Timer interrupts happen before we have initialized the profiling
67 * data structures so just ignore them before that.
68 */
69 BOOLEAN ProfileInitDone = FALSE;
70
71 VOID INIT_FUNCTION
72 ExpInitializeProfileImplementation(VOID)
73 {
74 ULONG i;
75
76 InitializeListHead(&SystemProfileList);
77
78 for (i = 0; i < PROFILE_HASH_TABLE_SIZE; i++)
79 {
80 InitializeListHead(&ProcessProfileListHashTable[i]);
81 }
82
83 KeInitializeSpinLock(&ProfileListLock);
84 ProfileInitDone = TRUE;
85
86 ExProfileObjectType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE));
87
88 RtlCreateUnicodeString(&ExProfileObjectType->TypeName, L"Profile");
89
90 ExProfileObjectType->Tag = TAG('P', 'R', 'O', 'F');
91 ExProfileObjectType->PeakObjects = 0;
92 ExProfileObjectType->PeakHandles = 0;
93 ExProfileObjectType->TotalObjects = 0;
94 ExProfileObjectType->TotalHandles = 0;
95 ExProfileObjectType->PagedPoolCharge = 0;
96 ExProfileObjectType->NonpagedPoolCharge = sizeof(KPROFILE);
97 ExProfileObjectType->Mapping = &ExpProfileMapping;
98 ExProfileObjectType->Dump = NULL;
99 ExProfileObjectType->Open = NULL;
100 ExProfileObjectType->Close = NULL;
101 ExProfileObjectType->Delete = KiDeleteProfile;
102 ExProfileObjectType->Parse = NULL;
103 ExProfileObjectType->Security = NULL;
104 ExProfileObjectType->QueryName = NULL;
105 ExProfileObjectType->OkayToClose = NULL;
106 ExProfileObjectType->Create = NULL;
107
108 ObpCreateTypeObject(ExProfileObjectType);
109 }
110
111 NTSTATUS STDCALL
112 NtCreateProfile(OUT PHANDLE ProfileHandle,
113 IN HANDLE Process OPTIONAL,
114 IN PVOID ImageBase,
115 IN ULONG ImageSize,
116 IN ULONG BucketSize,
117 IN PVOID Buffer,
118 IN ULONG BufferSize,
119 IN KPROFILE_SOURCE ProfileSource,
120 IN KAFFINITY Affinity)
121 {
122 HANDLE hProfile;
123 PKPROFILE Profile;
124 PEPROCESS pProcess;
125 KPROCESSOR_MODE PreviousMode;
126 OBJECT_ATTRIBUTES ObjectAttributes;
127 NTSTATUS Status = STATUS_SUCCESS;
128
129 PreviousMode = ExGetPreviousMode();
130
131 if(BufferSize == 0)
132 {
133 return STATUS_INVALID_PARAMETER_7;
134 }
135
136 if(PreviousMode != KernelMode)
137 {
138 _SEH_TRY
139 {
140 ProbeForWrite(ProfileHandle,
141 sizeof(HANDLE),
142 sizeof(ULONG));
143 ProbeForWrite(Buffer,
144 BufferSize,
145 sizeof(ULONG));
146 }
147 _SEH_HANDLE
148 {
149 Status = _SEH_GetExceptionCode();
150 }
151 _SEH_END;
152
153 if(!NT_SUCCESS(Status))
154 {
155 return Status;
156 }
157 }
158
159 /*
160 * Reference the associated process
161 */
162 if (Process != NULL)
163 {
164 Status = ObReferenceObjectByHandle(Process,
165 PROCESS_QUERY_INFORMATION,
166 PsProcessType,
167 PreviousMode,
168 (PVOID*)&pProcess,
169 NULL);
170 if (!NT_SUCCESS(Status))
171 {
172 return(Status);
173 }
174 }
175 else
176 {
177 pProcess = NULL;
178 if(!SeSinglePrivilegeCheck(SeSystemProfilePrivilege,
179 PreviousMode))
180 {
181 return STATUS_PRIVILEGE_NOT_HELD;
182 }
183 }
184
185 /*
186 * Check the parameters
187 */
188 if ((pProcess == NULL && ImageBase < (PVOID)KERNEL_BASE) ||
189 (pProcess != NULL && ImageBase >= (PVOID)KERNEL_BASE))
190 {
191 return(STATUS_INVALID_PARAMETER_3);
192 }
193 if (((ImageSize >> BucketSize) * 4) >= BufferSize)
194 {
195 return(STATUS_BUFFER_TOO_SMALL);
196 }
197 if (ProfileSource != ProfileTime)
198 {
199 return(STATUS_INVALID_PARAMETER_9);
200 }
201 if (Affinity != 0)
202 {
203 return(STATUS_INVALID_PARAMETER_10);
204 }
205
206 /*
207 * Create the object
208 */
209 InitializeObjectAttributes(&ObjectAttributes,
210 NULL,
211 0,
212 NULL,
213 NULL);
214
215 Status = ObCreateObject(KernelMode,
216 ExProfileObjectType,
217 &ObjectAttributes,
218 PreviousMode,
219 NULL,
220 sizeof(KPROFILE),
221 0,
222 0,
223 (PVOID*)&Profile);
224 if (!NT_SUCCESS(Status))
225 {
226 return(Status);
227 }
228
229 /*
230 * Initialize it
231 */
232 Profile->Base = ImageBase;
233 Profile->Size = ImageSize;
234 Profile->BucketShift = BucketSize;
235 Profile->BufferMdl = MmCreateMdl(NULL, Buffer, BufferSize);
236 if(Profile->BufferMdl == NULL) {
237 DPRINT("MmCreateMdl: Out of memory!");
238 ObDereferenceObject (Profile);
239 return(STATUS_NO_MEMORY);
240 }
241 MmProbeAndLockPages(Profile->BufferMdl, UserMode, IoWriteAccess);
242 Profile->Buffer = MmGetSystemAddressForMdl(Profile->BufferMdl);
243 Profile->BufferSize = BufferSize;
244 Profile->ProcessorMask = Affinity;
245 Profile->Started = FALSE;
246 Profile->Process = pProcess;
247
248 /*
249 * Insert the profile into the profile list data structures
250 */
251 KiInsertProfile(Profile);
252
253 Status = ObInsertObject ((PVOID)Profile,
254 NULL,
255 STANDARD_RIGHTS_ALL,
256 0,
257 NULL,
258 &hProfile);
259 if (!NT_SUCCESS(Status))
260 {
261 ObDereferenceObject (Profile);
262 return Status;
263 }
264
265 /*
266 * Copy the created handle back to the caller
267 */
268 _SEH_TRY
269 {
270 *ProfileHandle = hProfile;
271 }
272 _SEH_HANDLE
273 {
274 Status = _SEH_GetExceptionCode();
275 }
276 _SEH_END;
277
278 ObDereferenceObject(Profile);
279
280 return Status;
281 }
282
283 NTSTATUS STDCALL
284 NtQueryIntervalProfile(IN KPROFILE_SOURCE ProfileSource,
285 OUT PULONG Interval)
286 {
287 KPROCESSOR_MODE PreviousMode;
288 NTSTATUS Status = STATUS_SUCCESS;
289
290 PreviousMode = ExGetPreviousMode();
291
292 if(PreviousMode != KernelMode)
293 {
294 _SEH_TRY
295 {
296 ProbeForWrite(Interval,
297 sizeof(ULONG),
298 sizeof(ULONG));
299 }
300 _SEH_HANDLE
301 {
302 Status = _SEH_GetExceptionCode();
303 }
304 _SEH_END;
305
306 if(!NT_SUCCESS(Status))
307 {
308 return Status;
309 }
310 }
311
312 if (ProfileSource == ProfileTime)
313 {
314 ULONG ReturnInterval;
315
316 /* FIXME: What units does this use, for now nanoseconds */
317 ReturnInterval = 100;
318
319 _SEH_TRY
320 {
321 *Interval = ReturnInterval;
322 }
323 _SEH_HANDLE
324 {
325 Status = _SEH_GetExceptionCode();
326 }
327 _SEH_END;
328
329 return Status;
330 }
331 return STATUS_INVALID_PARAMETER_2;
332 }
333
334 NTSTATUS STDCALL
335 NtSetIntervalProfile(IN ULONG Interval,
336 IN KPROFILE_SOURCE Source)
337 {
338 return(STATUS_NOT_IMPLEMENTED);
339 }
340
341 NTSTATUS STDCALL
342 NtStartProfile(IN HANDLE ProfileHandle)
343 {
344 PKPROFILE Profile;
345 KPROCESSOR_MODE PreviousMode;
346 NTSTATUS Status;
347
348 PreviousMode = ExGetPreviousMode();
349
350 Status = ObReferenceObjectByHandle(ProfileHandle,
351 STANDARD_RIGHTS_ALL,
352 ExProfileObjectType,
353 PreviousMode,
354 (PVOID*)&Profile,
355 NULL);
356 if (!NT_SUCCESS(Status))
357 {
358 return(Status);
359 }
360 Profile->Started = TRUE;
361 ObDereferenceObject(Profile);
362 return(STATUS_SUCCESS);
363 }
364
365 NTSTATUS STDCALL
366 NtStopProfile(IN HANDLE ProfileHandle)
367 {
368 PKPROFILE Profile;
369 KPROCESSOR_MODE PreviousMode;
370 NTSTATUS Status;
371
372 PreviousMode = ExGetPreviousMode();
373
374 Status = ObReferenceObjectByHandle(ProfileHandle,
375 STANDARD_RIGHTS_ALL,
376 ExProfileObjectType,
377 PreviousMode,
378 (PVOID*)&Profile,
379 NULL);
380 if (!NT_SUCCESS(Status))
381 {
382 return(Status);
383 }
384 Profile->Started = FALSE;
385 ObDereferenceObject(Profile);
386 return(STATUS_SUCCESS);
387 }
388
389