Sync to trunk revision 63857.
[reactos.git] / dll / ntdll / csr / capture.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: dll/ntdll/csr/capture.c
5 * PURPOSE: Routines for probing and capturing CSR API Messages
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 #include <ntdll.h>
13
14 #define NDEBUG
15 #include <debug.h>
16
17 /* GLOBALS ********************************************************************/
18
19 extern HANDLE CsrPortHeap;
20
21 /* FUNCTIONS ******************************************************************/
22
23 /*
24 * @implemented
25 */
26 VOID
27 NTAPI
28 CsrProbeForRead(IN PVOID Address,
29 IN ULONG Length,
30 IN ULONG Alignment)
31 {
32 volatile UCHAR *Pointer;
33 UCHAR Data;
34
35 /* Validate length */
36 if (Length == 0) return;
37
38 /* Validate alignment */
39 if ((ULONG_PTR)Address & (Alignment - 1))
40 {
41 /* Raise exception if it doesn't match */
42 RtlRaiseStatus(STATUS_DATATYPE_MISALIGNMENT);
43 }
44
45 /* Probe first byte */
46 Pointer = Address;
47 Data = *Pointer;
48
49 /* Probe last byte */
50 Pointer = (PUCHAR)Address + Length - 1;
51 Data = *Pointer;
52 (void)Data;
53 }
54
55 /*
56 * @implemented
57 */
58 VOID
59 NTAPI
60 CsrProbeForWrite(IN PVOID Address,
61 IN ULONG Length,
62 IN ULONG Alignment)
63 {
64 volatile UCHAR *Pointer;
65
66 /* Validate length */
67 if (Length == 0) return;
68
69 /* Validate alignment */
70 if ((ULONG_PTR)Address & (Alignment - 1))
71 {
72 /* Raise exception if it doesn't match */
73 RtlRaiseStatus(STATUS_DATATYPE_MISALIGNMENT);
74 }
75
76 /* Probe first byte */
77 Pointer = Address;
78 *Pointer = *Pointer;
79
80 /* Probe last byte */
81 Pointer = (PUCHAR)Address + Length - 1;
82 *Pointer = *Pointer;
83 }
84
85 /*
86 * @implemented
87 */
88 PCSR_CAPTURE_BUFFER
89 NTAPI
90 CsrAllocateCaptureBuffer(IN ULONG ArgumentCount,
91 IN ULONG BufferSize)
92 {
93 PCSR_CAPTURE_BUFFER CaptureBuffer;
94
95 /* Validate size */
96 if (BufferSize >= MAXLONG) return NULL;
97
98 /* Add the size of the header and for each offset to the pointers */
99 BufferSize += FIELD_OFFSET(CSR_CAPTURE_BUFFER, PointerOffsetsArray) +
100 (ArgumentCount * sizeof(ULONG_PTR));
101
102 /* Align it to a 4-byte boundary */
103 BufferSize = (BufferSize + 3) & ~3;
104
105 /* Add the size of the alignment padding for each argument */
106 BufferSize += ArgumentCount * 3;
107
108 /* Allocate memory from the port heap */
109 CaptureBuffer = RtlAllocateHeap(CsrPortHeap, HEAP_ZERO_MEMORY, BufferSize);
110 if (CaptureBuffer == NULL) return NULL;
111
112 /* Initialize the header */
113 CaptureBuffer->Size = BufferSize;
114 CaptureBuffer->PointerCount = 0;
115
116 /* Initialize all the offsets */
117 RtlZeroMemory(CaptureBuffer->PointerOffsetsArray,
118 ArgumentCount * sizeof(ULONG_PTR));
119
120 /* Point to the start of the free buffer */
121 CaptureBuffer->BufferEnd = (PVOID)((ULONG_PTR)CaptureBuffer->PointerOffsetsArray +
122 ArgumentCount * sizeof(ULONG_PTR));
123
124 /* Return the address of the buffer */
125 return CaptureBuffer;
126 }
127
128 /*
129 * @implemented
130 */
131 ULONG
132 NTAPI
133 CsrAllocateMessagePointer(IN OUT PCSR_CAPTURE_BUFFER CaptureBuffer,
134 IN ULONG MessageLength,
135 OUT PVOID* CapturedData)
136 {
137 if (MessageLength == 0)
138 {
139 *CapturedData = NULL;
140 CapturedData = NULL;
141 }
142 else
143 {
144 /* Set the capture data at our current available buffer */
145 *CapturedData = CaptureBuffer->BufferEnd;
146
147 /* Validate the size */
148 if (MessageLength >= MAXLONG) return 0;
149
150 /* Align it to a 4-byte boundary */
151 MessageLength = (MessageLength + 3) & ~3;
152
153 /* Move our available buffer beyond this space */
154 CaptureBuffer->BufferEnd = (PVOID)((ULONG_PTR)CaptureBuffer->BufferEnd + MessageLength);
155 }
156
157 /* Write down this pointer in the array and increase the count */
158 CaptureBuffer->PointerOffsetsArray[CaptureBuffer->PointerCount++] = (ULONG_PTR)CapturedData;
159
160 /* Return the aligned length */
161 return MessageLength;
162 }
163
164 /*
165 * @implemented
166 */
167 VOID
168 NTAPI
169 CsrCaptureMessageBuffer(IN OUT PCSR_CAPTURE_BUFFER CaptureBuffer,
170 IN PVOID MessageBuffer OPTIONAL,
171 IN ULONG MessageLength,
172 OUT PVOID* CapturedData)
173 {
174 /* Simply allocate a message pointer in the buffer */
175 CsrAllocateMessagePointer(CaptureBuffer, MessageLength, CapturedData);
176
177 /* Check if there was any data */
178 if (!MessageBuffer || !MessageLength) return;
179
180 /* Copy the data into the buffer */
181 RtlMoveMemory(*CapturedData, MessageBuffer, MessageLength);
182 }
183
184 /*
185 * @implemented
186 */
187 VOID
188 NTAPI
189 CsrFreeCaptureBuffer(IN PCSR_CAPTURE_BUFFER CaptureBuffer)
190 {
191 /* Free it from the heap */
192 RtlFreeHeap(CsrPortHeap, 0, CaptureBuffer);
193 }
194
195 /*
196 * @implemented
197 */
198 VOID
199 NTAPI
200 CsrCaptureMessageString(IN OUT PCSR_CAPTURE_BUFFER CaptureBuffer,
201 IN PCSTR String OPTIONAL,
202 IN ULONG StringLength,
203 IN ULONG MaximumLength,
204 OUT PSTRING CapturedString)
205 {
206 ASSERT(CapturedString != NULL);
207
208 /*
209 * If we don't have a string, initialize an empty one,
210 * otherwise capture the given string.
211 */
212 if (!String)
213 {
214 CapturedString->Length = 0;
215 CapturedString->MaximumLength = (USHORT)MaximumLength;
216
217 /* Allocate a pointer for it */
218 CsrAllocateMessagePointer(CaptureBuffer,
219 MaximumLength,
220 (PVOID*)&CapturedString->Buffer);
221 }
222 else
223 {
224 /* Cut-off the string length if needed */
225 if (StringLength > MaximumLength)
226 StringLength = MaximumLength;
227
228 CapturedString->Length = (USHORT)StringLength;
229
230 /* Allocate a buffer and get its size */
231 CapturedString->MaximumLength =
232 (USHORT)CsrAllocateMessagePointer(CaptureBuffer,
233 MaximumLength,
234 (PVOID*)&CapturedString->Buffer);
235
236 /* If the string has data, copy it into the buffer */
237 if (StringLength)
238 RtlMoveMemory(CapturedString->Buffer, String, StringLength);
239 }
240
241 /* Null-terminate the string if we don't take up the whole space */
242 if (CapturedString->Length < CapturedString->MaximumLength)
243 CapturedString->Buffer[CapturedString->Length] = '\0';
244 }
245
246 static VOID
247 CsrCaptureMessageUnicodeStringInPlace(IN OUT PCSR_CAPTURE_BUFFER CaptureBuffer,
248 IN PUNICODE_STRING String)
249 {
250 ASSERT(String != NULL);
251
252 /* This is a way to capture the UNICODE string, since (Maximum)Length are also in bytes */
253 CsrCaptureMessageString(CaptureBuffer,
254 (PCSTR)String->Buffer,
255 String->Length,
256 String->MaximumLength,
257 (PSTRING)String);
258
259 /* Null-terminate the string */
260 if (String->MaximumLength >= String->Length + sizeof(WCHAR))
261 {
262 String->Buffer[String->Length / sizeof(WCHAR)] = L'\0';
263 }
264 }
265
266 /*
267 * @implemented
268 */
269 NTSTATUS
270 NTAPI
271 CsrCaptureMessageMultiUnicodeStringsInPlace(OUT PCSR_CAPTURE_BUFFER* CaptureBuffer,
272 IN ULONG StringsCount,
273 IN PUNICODE_STRING* MessageStrings)
274 {
275 ULONG Count;
276
277 if (!CaptureBuffer) return STATUS_INVALID_PARAMETER;
278
279 /* Allocate a new capture buffer if we don't have one already */
280 if (!*CaptureBuffer)
281 {
282 /* Compute the required size for the capture buffer */
283 ULONG Size = 0;
284
285 Count = 0;
286 while (Count < StringsCount)
287 {
288 if (MessageStrings[Count])
289 Size += MessageStrings[Count]->MaximumLength;
290
291 ++Count;
292 }
293
294 /* Allocate the capture buffer */
295 *CaptureBuffer = CsrAllocateCaptureBuffer(StringsCount, Size);
296 if (!*CaptureBuffer) return STATUS_NO_MEMORY;
297 }
298
299 /* Now capture each UNICODE string */
300 Count = 0;
301 while (Count < StringsCount)
302 {
303 if (MessageStrings[Count])
304 CsrCaptureMessageUnicodeStringInPlace(*CaptureBuffer, MessageStrings[Count]);
305
306 ++Count;
307 }
308
309 return STATUS_SUCCESS;
310 }
311
312 /*
313 * @implemented
314 */
315 PLARGE_INTEGER
316 NTAPI
317 CsrCaptureTimeout(IN ULONG Milliseconds,
318 OUT PLARGE_INTEGER Timeout)
319 {
320 /* Validate the time */
321 if (Milliseconds == -1) return NULL;
322
323 /* Convert to relative ticks */
324 Timeout->QuadPart = Int32x32To64(Milliseconds, -10000);
325 return Timeout;
326 }
327
328 /* EOF */