[DRWTSN32] Print some extra exception info
[reactos.git] / ntoskrnl / ex / harderr.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ex/harderr.c
5 * PURPOSE: Error Functions and Status/Exception Dispatching/Raising
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 #define TAG_ERR ' rrE'
16
17 /* GLOBALS ******************************************************************/
18
19 BOOLEAN ExReadyForErrors = FALSE;
20 PVOID ExpDefaultErrorPort = NULL;
21 PEPROCESS ExpDefaultErrorPortProcess = NULL;
22
23 /* FUNCTIONS ****************************************************************/
24
25 /*++
26 * @name ExpSystemErrorHandler
27 *
28 * For now it's a stub
29 *
30 * @param ErrorStatus
31 * FILLME
32 *
33 * @param NumberOfParameters
34 * FILLME
35 *
36 * @param UnicodeStringParameterMask
37 * FILLME
38 *
39 * @param Parameters
40 * FILLME
41 *
42 * @param ValidResponseOptions
43 * FILLME
44 *
45 * @param Response
46 * FILLME
47 *
48 * @return None
49 *
50 * @remarks None
51 *
52 *--*/
53 NTSTATUS
54 NTAPI
55 ExpSystemErrorHandler(IN NTSTATUS ErrorStatus,
56 IN ULONG NumberOfParameters,
57 IN ULONG UnicodeStringParameterMask,
58 IN PULONG_PTR Parameters,
59 IN BOOLEAN Shutdown)
60 {
61 ULONG_PTR BugCheckParameters[MAXIMUM_HARDERROR_PARAMETERS] = {0, 0, 0, 0};
62 ULONG i;
63
64 /* Sanity check */
65 ASSERT(NumberOfParameters <= MAXIMUM_HARDERROR_PARAMETERS);
66
67 /*
68 * KeBugCheck expects MAXIMUM_HARDERROR_PARAMETERS parameters,
69 * but we might get called with less, so use a local buffer here.
70 */
71 for (i = 0; i < NumberOfParameters; i++)
72 {
73 /* Copy them over */
74 BugCheckParameters[i] = Parameters[i];
75 }
76
77 /* FIXME: STUB */
78 KeBugCheckEx(FATAL_UNHANDLED_HARD_ERROR,
79 ErrorStatus,
80 (ULONG_PTR)BugCheckParameters,
81 0,
82 0);
83 return STATUS_SUCCESS;
84 }
85
86 /*++
87 * @name ExpRaiseHardError
88 * @implemented
89 *
90 * See ExRaiseHardError and NtRaiseHardError, same parameters.
91 *
92 * This function performs the central work for both ExRaiseHardError
93 * and NtRaiseHardError. ExRaiseHardError is the service for kernel-mode
94 * that copies the parameters to user-mode, and NtRaiseHardError is the
95 * service for both kernel-mode and user-mode that performs parameters
96 * validation and capture if necessary.
97 *
98 *--*/
99 NTSTATUS
100 NTAPI
101 ExpRaiseHardError(IN NTSTATUS ErrorStatus,
102 IN ULONG NumberOfParameters,
103 IN ULONG UnicodeStringParameterMask,
104 IN PULONG_PTR Parameters,
105 IN ULONG ValidResponseOptions,
106 OUT PULONG Response)
107 {
108 NTSTATUS Status;
109 PEPROCESS Process = PsGetCurrentProcess();
110 PETHREAD Thread = PsGetCurrentThread();
111 UCHAR Buffer[PORT_MAXIMUM_MESSAGE_LENGTH];
112 PHARDERROR_MSG Message = (PHARDERROR_MSG)Buffer;
113 HANDLE PortHandle;
114 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
115
116 PAGED_CODE();
117
118 /* Check if this error will shutdown the system */
119 if (ValidResponseOptions == OptionShutdownSystem)
120 {
121 /*
122 * Check if we have the privileges.
123 *
124 * NOTE: In addition to the Shutdown privilege we also check whether
125 * the caller has the Tcb privilege. The purpose is to allow only
126 * SYSTEM processes to "shutdown" the system on hard errors (BSOD)
127 * while forbidding regular processes to do so. This behaviour differs
128 * from Windows, where any user-mode process, as soon as it has the
129 * Shutdown privilege, can trigger a hard-error BSOD.
130 */
131 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode) ||
132 !SeSinglePrivilegeCheck(SeShutdownPrivilege, PreviousMode))
133 {
134 /* No rights */
135 *Response = ResponseNotHandled;
136 return STATUS_PRIVILEGE_NOT_HELD;
137 }
138
139 /* Don't handle any new hard errors */
140 ExReadyForErrors = FALSE;
141 }
142
143 /* Check if hard errors are not disabled */
144 if (!Thread->HardErrorsAreDisabled)
145 {
146 /* Check if we can't do errors anymore, and this is serious */
147 if (!ExReadyForErrors && NT_ERROR(ErrorStatus))
148 {
149 /* Use the system handler */
150 ExpSystemErrorHandler(ErrorStatus,
151 NumberOfParameters,
152 UnicodeStringParameterMask,
153 Parameters,
154 (PreviousMode != KernelMode) ? TRUE : FALSE);
155 }
156 }
157
158 /*
159 * Enable hard error processing if it is enabled for the process
160 * or if the exception status forces it.
161 */
162 if ((Process->DefaultHardErrorProcessing & SEM_FAILCRITICALERRORS) ||
163 (ErrorStatus & HARDERROR_OVERRIDE_ERRORMODE))
164 {
165 /* Check if we have an exception port */
166 if (Process->ExceptionPort)
167 {
168 /* Use the port */
169 PortHandle = Process->ExceptionPort;
170 }
171 else
172 {
173 /* Use our default system port */
174 PortHandle = ExpDefaultErrorPort;
175 }
176 }
177 else
178 {
179 /* Don't process the error */
180 PortHandle = NULL;
181 }
182
183 /* If hard errors are disabled, do nothing */
184 if (Thread->HardErrorsAreDisabled) PortHandle = NULL;
185
186 /*
187 * If this is not the system thread, check whether hard errors are
188 * disabled for this thread on user-mode side, and if so, do nothing.
189 */
190 if (!Thread->SystemThread && (PortHandle != NULL))
191 {
192 /* Check if we have a TEB */
193 PTEB Teb = PsGetCurrentThread()->Tcb.Teb;
194 if (Teb)
195 {
196 _SEH2_TRY
197 {
198 if (Teb->HardErrorMode & RTL_SEM_FAILCRITICALERRORS)
199 {
200 PortHandle = NULL;
201 }
202 }
203 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
204 {
205 NOTHING;
206 }
207 _SEH2_END;
208 }
209 }
210
211 /* Now check if we have a port */
212 if (PortHandle == NULL)
213 {
214 /* Just return to caller */
215 *Response = ResponseReturnToCaller;
216 return STATUS_SUCCESS;
217 }
218
219 /* Check if this is the default process */
220 if (Process == ExpDefaultErrorPortProcess)
221 {
222 /* We can't handle the error, check if this is critical */
223 if (NT_ERROR(ErrorStatus))
224 {
225 /* It is, invoke the system handler */
226 ExpSystemErrorHandler(ErrorStatus,
227 NumberOfParameters,
228 UnicodeStringParameterMask,
229 Parameters,
230 (PreviousMode != KernelMode) ? TRUE : FALSE);
231
232 /* If we survived, return to caller */
233 *Response = ResponseReturnToCaller;
234 return STATUS_SUCCESS;
235 }
236 }
237
238 /* Setup the LPC Message */
239 Message->h.u1.Length = (sizeof(HARDERROR_MSG) << 16) |
240 (sizeof(HARDERROR_MSG) - sizeof(PORT_MESSAGE));
241 Message->h.u2.ZeroInit = 0;
242 Message->h.u2.s2.Type = LPC_ERROR_EVENT;
243 Message->Status = ErrorStatus & ~HARDERROR_OVERRIDE_ERRORMODE;
244 Message->ValidResponseOptions = ValidResponseOptions;
245 Message->UnicodeStringParameterMask = UnicodeStringParameterMask;
246 Message->NumberOfParameters = NumberOfParameters;
247 KeQuerySystemTime(&Message->ErrorTime);
248
249 /* Copy the parameters */
250 if (Parameters)
251 {
252 RtlMoveMemory(&Message->Parameters,
253 Parameters,
254 sizeof(ULONG_PTR) * NumberOfParameters);
255 }
256
257 /* Send the LPC Message */
258 Status = LpcRequestWaitReplyPort(PortHandle,
259 (PPORT_MESSAGE)Message,
260 (PPORT_MESSAGE)Message);
261 if (NT_SUCCESS(Status))
262 {
263 /* Check what kind of response we got */
264 if ((Message->Response != ResponseReturnToCaller) &&
265 (Message->Response != ResponseNotHandled) &&
266 (Message->Response != ResponseAbort) &&
267 (Message->Response != ResponseCancel) &&
268 (Message->Response != ResponseIgnore) &&
269 (Message->Response != ResponseNo) &&
270 (Message->Response != ResponseOk) &&
271 (Message->Response != ResponseRetry) &&
272 (Message->Response != ResponseYes) &&
273 (Message->Response != ResponseTryAgain) &&
274 (Message->Response != ResponseContinue))
275 {
276 /* Reset to a default one */
277 Message->Response = ResponseReturnToCaller;
278 }
279
280 /* Set the response */
281 *Response = Message->Response;
282 }
283 else
284 {
285 /* Set the response */
286 *Response = ResponseReturnToCaller;
287 }
288
289 /* Return status */
290 return Status;
291 }
292
293 /*++
294 * @name ExRaiseAccessViolation
295 * @implemented
296 *
297 * The ExRaiseAccessViolation routine can be used with structured exception
298 * handling to throw a driver-determined exception for a memory access
299 * violation that occurs when a driver processes I/O requests.
300 * See: http://msdn.microsoft.com/library/en-us/Kernel_r/hh/Kernel_r/k102_71b4c053-599c-4a6d-8a59-08aae6bdc534.xml.asp?frame=true
301 * http://www.osronline.com/ddkx/kmarch/k102_814i.htm
302 *
303 * @return None
304 *
305 * @remarks None
306 *
307 *--*/
308 VOID
309 NTAPI
310 ExRaiseAccessViolation(VOID)
311 {
312 /* Raise the Right Status */
313 RtlRaiseStatus(STATUS_ACCESS_VIOLATION);
314 }
315
316 /*++
317 * @name ExRaiseDatatypeMisalignment
318 * @implemented
319 *
320 * ExRaiseDatatypeMisalignment raises an exception with the exception
321 * code set to STATUS_DATATYPE_MISALIGNMENT
322 * See: MSDN / DDK
323 * http://www.osronline.com/ddkx/kmarch/k102_814i.htm
324 *
325 * @return None
326 *
327 * @remarks None
328 *
329 *--*/
330 VOID
331 NTAPI
332 ExRaiseDatatypeMisalignment(VOID)
333 {
334 /* Raise the Right Status */
335 RtlRaiseStatus(STATUS_DATATYPE_MISALIGNMENT);
336 }
337
338 /*++
339 * @name ExSystemExceptionFilter
340 * @implemented
341 *
342 * TODO: Add description
343 *
344 * @return FILLME
345 *
346 * @remarks None
347 *
348 *--*/
349 LONG
350 NTAPI
351 ExSystemExceptionFilter(VOID)
352 {
353 return KeGetPreviousMode() != KernelMode ?
354 EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH;
355 }
356
357 /*++
358 * @name ExRaiseHardError
359 * @implemented
360 *
361 * See NtRaiseHardError and ExpRaiseHardError.
362 *
363 * @param ErrorStatus
364 * Error Code
365 *
366 * @param NumberOfParameters
367 * Number of optional parameters in Parameters array
368 *
369 * @param UnicodeStringParameterMask
370 * Optional string parameter (can be only one per error code)
371 *
372 * @param Parameters
373 * Array of ULONG parameters for use in error message string
374 *
375 * @param ValidResponseOptions
376 * See HARDERROR_RESPONSE_OPTION for possible values description
377 *
378 * @param Response
379 * Pointer to HARDERROR_RESPONSE enumeration
380 *
381 * @return Status
382 *
383 *--*/
384 NTSTATUS
385 NTAPI
386 ExRaiseHardError(IN NTSTATUS ErrorStatus,
387 IN ULONG NumberOfParameters,
388 IN ULONG UnicodeStringParameterMask,
389 IN PULONG_PTR Parameters,
390 IN ULONG ValidResponseOptions,
391 OUT PULONG Response)
392 {
393 NTSTATUS Status;
394 SIZE_T Size;
395 UNICODE_STRING CapturedParams[MAXIMUM_HARDERROR_PARAMETERS];
396 ULONG i;
397 PVOID UserData = NULL;
398 PHARDERROR_USER_PARAMETERS UserParams;
399 PWSTR BufferBase;
400 ULONG SafeResponse = ResponseNotHandled;
401
402 PAGED_CODE();
403
404 /* Check if we have parameters */
405 if (Parameters)
406 {
407 /* Check if we have strings */
408 if (UnicodeStringParameterMask)
409 {
410 /* Calculate the required size */
411 Size = FIELD_OFFSET(HARDERROR_USER_PARAMETERS, Buffer[0]);
412
413 /* Loop each parameter */
414 for (i = 0; i < NumberOfParameters; i++)
415 {
416 /* Check if it's part of the mask */
417 if (UnicodeStringParameterMask & (1 << i))
418 {
419 /* Copy it */
420 RtlMoveMemory(&CapturedParams[i],
421 (PVOID)Parameters[i],
422 sizeof(UNICODE_STRING));
423
424 /* Increase the size */
425 Size += CapturedParams[i].MaximumLength;
426 }
427 }
428
429 /* Allocate the user data region */
430 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
431 &UserData,
432 0,
433 &Size,
434 MEM_COMMIT,
435 PAGE_READWRITE);
436 if (!NT_SUCCESS(Status))
437 {
438 /* Return failure */
439 *Response = ResponseNotHandled;
440 return Status;
441 }
442
443 /* Set the pointers to our data */
444 UserParams = UserData;
445 BufferBase = UserParams->Buffer;
446
447 /* Enter SEH block as we are writing to user-mode space */
448 _SEH2_TRY
449 {
450 /* Loop parameters again */
451 for (i = 0; i < NumberOfParameters; i++)
452 {
453 /* Check if we are in the mask */
454 if (UnicodeStringParameterMask & (1 << i))
455 {
456 /* Update the base */
457 UserParams->Parameters[i] = (ULONG_PTR)&UserParams->Strings[i];
458
459 /* Copy the string buffer */
460 RtlMoveMemory(BufferBase,
461 CapturedParams[i].Buffer,
462 CapturedParams[i].MaximumLength);
463
464 /* Set buffer */
465 CapturedParams[i].Buffer = BufferBase;
466
467 /* Copy the string structure */
468 UserParams->Strings[i] = CapturedParams[i];
469
470 /* Update the pointer */
471 BufferBase += CapturedParams[i].MaximumLength;
472 }
473 else
474 {
475 /* No need to copy any strings */
476 UserParams->Parameters[i] = Parameters[i];
477 }
478 }
479 }
480 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
481 {
482 /* Return the exception code */
483 Status = _SEH2_GetExceptionCode();
484 DPRINT1("ExRaiseHardError - Exception when writing data to user-mode, Status 0x%08lx\n", Status);
485 }
486 _SEH2_END;
487 }
488 else
489 {
490 /* Just keep the data as is */
491 UserData = Parameters;
492 }
493 }
494
495 /* Now call the worker function */
496 Status = ExpRaiseHardError(ErrorStatus,
497 NumberOfParameters,
498 UnicodeStringParameterMask,
499 UserData,
500 ValidResponseOptions,
501 &SafeResponse);
502
503 /* Check if we had done user-mode allocation */
504 if ((UserData) && (UserData != Parameters))
505 {
506 /* We did! Delete it */
507 Size = 0;
508 ZwFreeVirtualMemory(NtCurrentProcess(),
509 &UserData,
510 &Size,
511 MEM_RELEASE);
512 }
513
514 /* Return status and the response */
515 *Response = SafeResponse;
516 return Status;
517 }
518
519 /*++
520 * @name NtRaiseHardError
521 * @implemented
522 *
523 * This function sends HARDERROR_MSG LPC message to a hard-error listener,
524 * typically CSRSS.EXE. See NtSetDefaultHardErrorPort for more information.
525 * See also: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Error/NtRaiseHardError.html
526 *
527 * @param ErrorStatus
528 * Error Code
529 *
530 * @param NumberOfParameters
531 * Number of optional parameters in Parameters array
532 *
533 * @param UnicodeStringParameterMask
534 * Optional string parameter (can be only one per error code)
535 *
536 * @param Parameters
537 * Array of ULONG_PTR parameters for use in error message string
538 *
539 * @param ValidResponseOptions
540 * See HARDERROR_RESPONSE_OPTION for possible values description
541 *
542 * @param Response
543 * Pointer to HARDERROR_RESPONSE enumeration
544 *
545 * @return Status
546 *
547 * @remarks NtRaiseHardError constitutes an easy way to display messages
548 * in GUI without loading any Win32 API libraries.
549 *
550 *--*/
551 NTSTATUS
552 NTAPI
553 NtRaiseHardError(IN NTSTATUS ErrorStatus,
554 IN ULONG NumberOfParameters,
555 IN ULONG UnicodeStringParameterMask,
556 IN PULONG_PTR Parameters,
557 IN ULONG ValidResponseOptions,
558 OUT PULONG Response)
559 {
560 NTSTATUS Status = STATUS_SUCCESS;
561 PULONG_PTR SafeParams = NULL;
562 ULONG SafeResponse = ResponseNotHandled;
563 UNICODE_STRING SafeString;
564 ULONG i;
565 ULONG ParamSize = 0;
566 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
567
568 PAGED_CODE();
569
570 /* Validate parameter count */
571 if (NumberOfParameters > MAXIMUM_HARDERROR_PARAMETERS)
572 {
573 /* Fail */
574 return STATUS_INVALID_PARAMETER_2;
575 }
576
577 /* Make sure we have some at least */
578 if ((Parameters != NULL) && (NumberOfParameters == 0))
579 {
580 /* Fail */
581 return STATUS_INVALID_PARAMETER_2;
582 }
583
584 /* Check if we were called from user-mode */
585 if (PreviousMode != KernelMode)
586 {
587 /* First validate the responses */
588 switch (ValidResponseOptions)
589 {
590 /* Check all valid cases */
591 case OptionAbortRetryIgnore:
592 case OptionOk:
593 case OptionOkCancel:
594 case OptionRetryCancel:
595 case OptionYesNo:
596 case OptionYesNoCancel:
597 case OptionShutdownSystem:
598 case OptionOkNoWait:
599 case OptionCancelTryContinue:
600 break;
601
602 /* Anything else is invalid */
603 default:
604 return STATUS_INVALID_PARAMETER_4;
605 }
606
607 /* Check if we have parameters */
608 if (Parameters)
609 {
610 /* Calculate size of the parameters */
611 ParamSize = sizeof(ULONG_PTR) * NumberOfParameters;
612
613 /* Allocate a safe buffer */
614 SafeParams = ExAllocatePoolWithTag(PagedPool, ParamSize, TAG_ERR);
615 if (!SafeParams)
616 {
617 return STATUS_INSUFFICIENT_RESOURCES;
618 }
619 }
620
621 /* Enter SEH Block */
622 _SEH2_TRY
623 {
624 /* Validate the response pointer */
625 ProbeForWriteUlong(Response);
626
627 /* Check if we have parameters */
628 if (Parameters)
629 {
630 /* Validate the parameter pointers */
631 ProbeForRead(Parameters, ParamSize, sizeof(ULONG_PTR));
632
633 /* Copy them */
634 RtlCopyMemory(SafeParams, Parameters, ParamSize);
635
636 /* Now check if there's strings in it */
637 if (UnicodeStringParameterMask)
638 {
639 /* Loop every string */
640 for (i = 0; i < NumberOfParameters; i++)
641 {
642 /* Check if this parameter is a string */
643 if (UnicodeStringParameterMask & (1 << i))
644 {
645 /* Probe the structure */
646 ProbeForRead((PVOID)SafeParams[i],
647 sizeof(UNICODE_STRING),
648 sizeof(ULONG_PTR));
649
650 /* Capture it */
651 RtlCopyMemory(&SafeString,
652 (PVOID)SafeParams[i],
653 sizeof(UNICODE_STRING));
654
655 /* Probe the buffer */
656 ProbeForRead(SafeString.Buffer,
657 SafeString.MaximumLength,
658 sizeof(UCHAR));
659 }
660 }
661 }
662 }
663 }
664 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
665 {
666 /* Free captured buffer */
667 if (SafeParams) ExFreePoolWithTag(SafeParams, TAG_ERR);
668
669 /* Return the exception code */
670 _SEH2_YIELD(return _SEH2_GetExceptionCode());
671 }
672 _SEH2_END;
673
674 /* Call the system function directly, because we probed */
675 Status = ExpRaiseHardError(ErrorStatus,
676 NumberOfParameters,
677 UnicodeStringParameterMask,
678 SafeParams,
679 ValidResponseOptions,
680 &SafeResponse);
681
682 /* Free captured buffer */
683 if (SafeParams) ExFreePoolWithTag(SafeParams, TAG_ERR);
684
685 /* Enter SEH Block to return the response */
686 _SEH2_TRY
687 {
688 /* Return the response */
689 *Response = SafeResponse;
690 }
691 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
692 {
693 /* Get the exception code */
694 Status = _SEH2_GetExceptionCode();
695 }
696 _SEH2_END;
697 }
698 else
699 {
700 /* Reuse variable */
701 SafeParams = Parameters;
702
703 /*
704 * Call the Executive Function. It will probe
705 * and copy pointers to user-mode.
706 */
707 Status = ExRaiseHardError(ErrorStatus,
708 NumberOfParameters,
709 UnicodeStringParameterMask,
710 SafeParams,
711 ValidResponseOptions,
712 &SafeResponse);
713
714 /* Return the response */
715 *Response = SafeResponse;
716 }
717
718 /* Return status */
719 return Status;
720 }
721
722 /*++
723 * @name NtSetDefaultHardErrorPort
724 * @implemented
725 *
726 * NtSetDefaultHardErrorPort is typically called only once. After the call,
727 * the kernel sets a BOOLEAN flag named ExReadyForErrors to TRUE, and all other
728 * attempts to change the default port fail with STATUS_UNSUCCESSFUL error code.
729 * See: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Error/NtSetDefaultHardErrorPort.html
730 * https://web.archive.org/web/20070716133753/http://www.windowsitlibrary.com/Content/356/08/2.html
731 *
732 * @param PortHandle
733 * Handle to named port object
734 *
735 * @return Status
736 *
737 * @remarks Privileges: SE_TCB_PRIVILEGE
738 *
739 *--*/
740 NTSTATUS
741 NTAPI
742 NtSetDefaultHardErrorPort(IN HANDLE PortHandle)
743 {
744 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
745 NTSTATUS Status = STATUS_UNSUCCESSFUL;
746
747 PAGED_CODE();
748
749 /* Check if we have the privileges */
750 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
751 {
752 DPRINT1("NtSetDefaultHardErrorPort: Caller requires "
753 "the SeTcbPrivilege privilege!\n");
754 return STATUS_PRIVILEGE_NOT_HELD;
755 }
756
757 /* Only called once during bootup, make sure we weren't called yet */
758 if (!ExReadyForErrors)
759 {
760 /* Reference the hard-error port */
761 Status = ObReferenceObjectByHandle(PortHandle,
762 0,
763 LpcPortObjectType,
764 PreviousMode,
765 (PVOID*)&ExpDefaultErrorPort,
766 NULL);
767 if (NT_SUCCESS(Status))
768 {
769 /* Keep also a reference to the process handling the hard errors */
770 ExpDefaultErrorPortProcess = PsGetCurrentProcess();
771 ObReferenceObject(ExpDefaultErrorPortProcess);
772 ExReadyForErrors = TRUE;
773 Status = STATUS_SUCCESS;
774 }
775 }
776
777 /* Return status to caller */
778 return Status;
779 }
780
781 VOID
782 __cdecl
783 _purecall(VOID)
784 {
785 /* Not supported in Kernel Mode */
786 RtlRaiseStatus(STATUS_NOT_IMPLEMENTED);
787 }
788
789 /* EOF */