summaryrefslogtreecommitdiffstats
path: root/private/windbg/driver/crashdrv
diff options
context:
space:
mode:
Diffstat (limited to 'private/windbg/driver/crashdrv')
-rw-r--r--private/windbg/driver/crashdrv/crashdrv.c225
-rw-r--r--private/windbg/driver/crashdrv/crashdrv.h58
-rw-r--r--private/windbg/driver/crashdrv/crashdrv.rc11
-rw-r--r--private/windbg/driver/crashdrv/dirs1
-rw-r--r--private/windbg/driver/crashdrv/driver/makefile6
-rw-r--r--private/windbg/driver/crashdrv/driver/sources12
-rw-r--r--private/windbg/driver/crashdrv/tests.c266
-rw-r--r--private/windbg/driver/crashdrv/tests/install.c83
-rw-r--r--private/windbg/driver/crashdrv/tests/install.rc11
-rw-r--r--private/windbg/driver/crashdrv/tests/makefile6
-rw-r--r--private/windbg/driver/crashdrv/tests/makefile.inc3
-rw-r--r--private/windbg/driver/crashdrv/tests/sources17
-rw-r--r--private/windbg/driver/crashdrv/tests/test.c295
-rw-r--r--private/windbg/driver/crashdrv/tests/test.rc11
14 files changed, 1005 insertions, 0 deletions
diff --git a/private/windbg/driver/crashdrv/crashdrv.c b/private/windbg/driver/crashdrv/crashdrv.c
new file mode 100644
index 000000000..e81655b9c
--- /dev/null
+++ b/private/windbg/driver/crashdrv/crashdrv.c
@@ -0,0 +1,225 @@
+#include <ntddk.h>
+#include <string.h>
+#include "crashdrv.h"
+
+
+#define MEMSIZE 4096
+#define FCN(cc) ((cc >> 2) & 0xFFFFFF)
+#define DEVICE_NAME L"\\Device\\CrashDrv"
+#define DOSDEVICE_NAME L"\\DosDevices\\CrashDrv"
+
+
+typedef VOID (*PTESTFUNC)(PULONG ub);
+
+PTESTFUNC tests[] =
+ {
+ NULL,
+ CrashDrvBugCheck,
+ CrashDrvStackOverFlow,
+ CrashDrvSimpleTest,
+ CrashDrvExceptionTest,
+ CrashDrvHardError,
+ CrashSpecial
+ };
+
+#define MaxTests (sizeof(tests)/sizeof(PTESTFUNC))
+
+ULONG CrashDrvRequest;
+KEVENT CrashEvent;
+ULONG CrashRequest;
+PULONG Funk;
+
+
+NTSTATUS
+CrashDrvOpenClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+CrashDrvUnload(
+ IN PDRIVER_OBJECT DriverObject
+ );
+
+NTSTATUS
+CrashDrvIoControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+CrashThread(
+ PVOID Context
+ );
+
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+{
+ UNICODE_STRING DeviceName;
+ PDEVICE_OBJECT deviceObject;
+ NTSTATUS status;
+ UNICODE_STRING LinkObject;
+ WCHAR LinkName[80];
+ ULONG DeviceSize;
+ HANDLE ThreadHandle;
+
+
+ RtlInitUnicodeString( &DeviceName, DEVICE_NAME );
+ status = IoCreateDevice( DriverObject,
+ 0,
+ &DeviceName,
+ FILE_DEVICE_NULL,
+ 0,
+ FALSE,
+ &deviceObject );
+ if (!NT_SUCCESS( status )) {
+ return status;
+ }
+
+ LinkName[0] = UNICODE_NULL;
+
+ RtlInitUnicodeString(&LinkObject, LinkName);
+
+ LinkObject.MaximumLength = sizeof(LinkName);
+
+ RtlAppendUnicodeToString(&LinkObject, L"\\DosDevices");
+
+ DeviceSize = sizeof(L"\\Device") - sizeof(UNICODE_NULL);
+ DeviceName.Buffer += DeviceSize / sizeof(WCHAR);
+ DeviceName.Length -= (USHORT)DeviceSize;
+
+ RtlAppendUnicodeStringToString(&LinkObject, &DeviceName);
+
+ DeviceName.Buffer -= DeviceSize / sizeof(WCHAR);
+ DeviceName.Length += (USHORT)DeviceSize;
+
+ status = IoCreateSymbolicLink(&LinkObject, &DeviceName);
+
+ if (!NT_SUCCESS(status)) {
+ IoDeleteDevice( deviceObject );
+ return status;
+ }
+
+ DriverObject->MajorFunction[IRP_MJ_CREATE] = CrashDrvOpenClose;
+ DriverObject->MajorFunction[IRP_MJ_CLOSE] = CrashDrvOpenClose;
+ DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = CrashDrvIoControl;
+ DriverObject->DriverUnload = CrashDrvUnload;
+
+ KeInitializeEvent( &CrashEvent, NotificationEvent, FALSE );
+
+ Funk = ExAllocatePool( PagedPool, MEMSIZE );
+
+ status = PsCreateSystemThread(
+ &ThreadHandle,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ CrashThread,
+ NULL
+ );
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+CrashDrvOpenClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ Irp->IoStatus.Status = status;
+ Irp->IoStatus.Information = 0;
+ status = Irp->IoStatus.Status;
+ IoCompleteRequest( Irp, 0 );
+
+ return status;
+}
+
+VOID
+CrashDrvUnload(
+ IN PDRIVER_OBJECT DriverObject
+ )
+{
+ PDEVICE_OBJECT currentDevice = DriverObject->DeviceObject;
+ UNICODE_STRING fullLinkName;
+
+ while (currentDevice) {
+
+ RtlInitUnicodeString( &fullLinkName, DOSDEVICE_NAME );
+ IoDeleteSymbolicLink(&fullLinkName);
+ IoDeleteDevice(currentDevice);
+
+ currentDevice = DriverObject->DeviceObject;
+
+ }
+}
+
+NTSTATUS
+CrashDrvIoControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+ PULONG ub;
+
+
+ ub = (PULONG) MmGetSystemAddressForMdl( Irp->MdlAddress );
+
+ if (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_CRASHDRV_CHECK_REQUEST) {
+ ub[0] = CrashDrvRequest;
+ CrashDrvRequest = 0;
+ } else {
+ if (FCN(IrpSp->Parameters.DeviceIoControl.IoControlCode) > MaxTests) {
+ DbgBreakPoint();
+ } else {
+ tests[FCN(IrpSp->Parameters.DeviceIoControl.IoControlCode)]( ub );
+ }
+ }
+
+ Irp->IoStatus.Information = 0L;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest( Irp, 0 );
+
+ return Status;
+}
+
+
+VOID
+CrashThread(
+ PVOID Context
+ )
+{
+ while( TRUE ) {
+ KeWaitForSingleObject( &CrashEvent, Executive, KernelMode, FALSE, NULL );
+ KeResetEvent( &CrashEvent );
+ switch( CrashRequest ) {
+ case KMODE_EXCEPTION_NOT_HANDLED:
+ {
+ ULONG i,j;
+ i = 0;
+ j = 0;
+ i = j / i;
+ }
+ break;
+
+ case IRQL_NOT_LESS_OR_EQUAL:
+ {
+ KIRQL irql;
+ KeRaiseIrql( DISPATCH_LEVEL, &irql );
+ Funk[0] = 0;
+ KeLowerIrql( irql );
+ }
+ break;
+ }
+ }
+}
diff --git a/private/windbg/driver/crashdrv/crashdrv.h b/private/windbg/driver/crashdrv/crashdrv.h
new file mode 100644
index 000000000..e9d5e4027
--- /dev/null
+++ b/private/windbg/driver/crashdrv/crashdrv.h
@@ -0,0 +1,58 @@
+//
+// CrashDrv driver/test constants
+//
+
+#define FILE_DEVICE_CRASHDRV 0x00008000
+
+
+#define TEST_CHECK_REQUEST 0
+#define TEST_BUGCHECK 1
+#define TEST_STACK_OVERFLOW 2
+#define TEST_SIMPLE 3
+#define TEST_EXCEPTION 4
+#define TEST_HARDERR 5
+#define TEST_SPECIAL 6
+
+#define IOCTL_CRASHDRV_CHECK_REQUEST CTL_CODE(FILE_DEVICE_CRASHDRV, TEST_CHECK_REQUEST, METHOD_OUT_DIRECT,FILE_ANY_ACCESS)
+#define IOCTL_CRASHDRV_BUGCHECK CTL_CODE(FILE_DEVICE_CRASHDRV, TEST_BUGCHECK, METHOD_OUT_DIRECT,FILE_ANY_ACCESS)
+#define IOCTL_CRASHDRV_STACK_OVERFLOW CTL_CODE(FILE_DEVICE_CRASHDRV, TEST_STACK_OVERFLOW, METHOD_OUT_DIRECT,FILE_ANY_ACCESS)
+#define IOCTL_CRASHDRV_SIMPLE CTL_CODE(FILE_DEVICE_CRASHDRV, TEST_SIMPLE, METHOD_OUT_DIRECT,FILE_ANY_ACCESS)
+#define IOCTL_CRASHDRV_EXCEPTION CTL_CODE(FILE_DEVICE_CRASHDRV, TEST_EXCEPTION, METHOD_OUT_DIRECT,FILE_ANY_ACCESS)
+#define IOCTL_CRASHDRV_HARDERR CTL_CODE(FILE_DEVICE_CRASHDRV, TEST_HARDERR, METHOD_OUT_DIRECT,FILE_ANY_ACCESS)
+#define IOCTL_CRASHDRV_SPECIAL CTL_CODE(FILE_DEVICE_CRASHDRV, TEST_SPECIAL, METHOD_OUT_DIRECT,FILE_ANY_ACCESS)
+
+
+//
+// prototypes
+//
+
+VOID
+CrashDrvStackOverFlow(
+ PULONG ub
+ );
+
+VOID
+CrashDrvBugCheck(
+ PULONG ub
+ );
+
+VOID
+CrashDrvSimpleTest(
+ PULONG ub
+ );
+
+VOID
+CrashDrvExceptionTest(
+ PULONG ub
+ );
+
+VOID
+CrashDrvHardError(
+ PULONG ub
+ );
+
+VOID
+CrashSpecial(
+ PULONG ub
+ );
+
diff --git a/private/windbg/driver/crashdrv/crashdrv.rc b/private/windbg/driver/crashdrv/crashdrv.rc
new file mode 100644
index 000000000..4eeecf024
--- /dev/null
+++ b/private/windbg/driver/crashdrv/crashdrv.rc
@@ -0,0 +1,11 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "Crash Driver"
+#define VER_INTERNALNAME_STR "crashdrv.sys"
+
+#include "common.ver"
+
diff --git a/private/windbg/driver/crashdrv/dirs b/private/windbg/driver/crashdrv/dirs
new file mode 100644
index 000000000..b84056424
--- /dev/null
+++ b/private/windbg/driver/crashdrv/dirs
@@ -0,0 +1 @@
+DIRS=driver tests
diff --git a/private/windbg/driver/crashdrv/driver/makefile b/private/windbg/driver/crashdrv/driver/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/windbg/driver/crashdrv/driver/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/windbg/driver/crashdrv/driver/sources b/private/windbg/driver/crashdrv/driver/sources
new file mode 100644
index 000000000..b0b9ea22f
--- /dev/null
+++ b/private/windbg/driver/crashdrv/driver/sources
@@ -0,0 +1,12 @@
+MAJORCOMP=windbg
+MINORCOMP=driver
+
+TARGETNAME=crashdrv
+TARGETPATH=obj
+TARGETTYPE=DRIVER
+
+INCLUDES=$(BASEDIR)\private\ntos\inc
+
+SOURCES=..\crashdrv.c ..\tests.c ..\crashdrv.rc
+
+LINKER_FLAGS=-miscrdata
diff --git a/private/windbg/driver/crashdrv/tests.c b/private/windbg/driver/crashdrv/tests.c
new file mode 100644
index 000000000..d9e5143e1
--- /dev/null
+++ b/private/windbg/driver/crashdrv/tests.c
@@ -0,0 +1,266 @@
+#include <ntos.h>
+#include <nturtl.h>
+#include <ntexapi.h>
+
+extern KEVENT CrashEvent;
+extern ULONG CrashRequest;
+
+unsigned int fExcept1 = 0;
+unsigned int cTry1 = 0;
+unsigned int cRaise1pre = 0;
+unsigned int cRaise1post = 0;
+unsigned int cExcept1 = 0;
+unsigned int cFilter1 = 0;
+
+unsigned int fExcept2 = 0;
+unsigned int cTry2 = 0;
+unsigned int cRaise2pre = 0;
+unsigned int cRaise2post = 0;
+unsigned int cFinally2 = 0;
+
+unsigned int fExcept3 = 0;
+unsigned int cTry3 = 0;
+unsigned int cRaise3pre = 0;
+unsigned int cRaise3post = 0;
+unsigned int cExcept3 = 0;
+unsigned int cFilter3 = 0;
+
+unsigned int fExcept4 = 0;
+unsigned int cTry4 = 0;
+unsigned int cRaise4pre = 0;
+unsigned int cRaise4post = 0;
+unsigned int cFinally4 = 0;
+
+unsigned int fExcept5 = 0;
+unsigned int cTry5 = 0;
+unsigned int cRaise5pre = 0;
+unsigned int cRaise5post = 0;
+unsigned int cExcept5 = 0;
+unsigned int cFilter5 = 0;
+
+unsigned long GlobalVar = 0;
+
+int ExceptFilterFn5 (int ExceptCode)
+{
+ DbgPrint( "CrashDrv exception filter\n" );
+ cFilter5 ++;
+ return ExceptCode == 0x00003344 ? EXCEPTION_EXECUTE_HANDLER :
+ EXCEPTION_CONTINUE_EXECUTION ;
+}
+
+void function5 ()
+{
+ _try
+ {
+ cTry5 ++;
+ if (fExcept5)
+ {
+ cRaise5pre ++;
+ ExRaiseStatus( fExcept4 );
+ cRaise5post ++;
+ }
+ }
+ _except (ExceptFilterFn5 (GetExceptionCode ()))
+ {
+ cExcept5 ++;
+ }
+}
+
+void function4 ()
+{
+ _try
+ {
+ cTry4 ++;
+ function5 ();
+ if (fExcept4)
+ {
+ cRaise4pre ++;
+ ExRaiseStatus( fExcept4 );
+ cRaise4post ++;
+ }
+ }
+ _finally
+ {
+ cFinally4 ++;
+ }
+}
+
+int ExceptFilterFn3 (int ExceptCode)
+{
+ cFilter3 ++;
+ return ExceptCode == 0x00005678 ? EXCEPTION_EXECUTE_HANDLER :
+ EXCEPTION_CONTINUE_SEARCH ;
+}
+
+void function3 ()
+{
+ _try
+ {
+ cTry3 ++;
+ function4 ();
+ if (fExcept3)
+ {
+ cRaise3pre ++;
+ ExRaiseStatus( fExcept3 );
+ cRaise3post ++;
+ }
+ }
+ _except (ExceptFilterFn3 (GetExceptionCode ()))
+ {
+ cExcept3 ++;
+ }
+}
+
+void function2 ()
+{
+ _try
+ {
+ cTry2 ++;
+ function3 ();
+ if (fExcept2)
+ {
+ cRaise2pre ++;
+ ExRaiseStatus( fExcept2 );
+ cRaise2post ++;
+ }
+ }
+ _finally
+ {
+ cFinally2 ++;
+ }
+}
+
+int ExceptFilterMain (int ExceptCode)
+{
+ cFilter1 ++;
+ return ExceptCode == 0x00001010 ? EXCEPTION_EXECUTE_HANDLER :
+ ExceptCode == 0x00005678 ? EXCEPTION_CONTINUE_EXECUTION :
+ EXCEPTION_CONTINUE_SEARCH ;
+}
+
+VOID
+CrashDrvExceptionTest(
+ PULONG ub
+ )
+{
+ int i = 0;
+
+ while ( i++ < 10 ) {
+ _try {
+ cTry1 ++;
+ function2 ();
+ if (fExcept1) {
+ cRaise1pre ++;
+ ExRaiseStatus( fExcept1 );
+ cRaise1post ++;
+ }
+ }
+ _except (ExceptFilterMain (GetExceptionCode ())) {
+ cExcept1 ++;
+ }
+ fExcept1 = 0;
+ fExcept2 = 0;
+ fExcept3 = 0;
+ fExcept4 = 0;
+ fExcept5 = 0;
+ }
+}
+
+VOID
+CrashDrvSimpleTest(
+ PULONG ub
+ )
+{
+ int i = 0;
+ int j = 0;
+ int k = 0;
+ GlobalVar = 69;
+ i = 1;
+ j = 2;
+ k = 3;
+}
+
+VOID
+CrashDrvStackOverFlow(
+ PULONG ub
+ )
+{
+}
+
+VOID
+CrashDrvBugCheck(
+ PULONG ub
+ )
+{
+ KeBugCheck( 0x69696969 );
+}
+
+VOID
+CrashDrvHardError(
+ PULONG ub
+ )
+{
+ NTSTATUS Status;
+ NTSTATUS ErrorCode;
+ ULONG Response;
+
+
+ ErrorCode = STATUS_SYSTEM_PROCESS_TERMINATED;
+
+ Status = ExRaiseHardError(
+ ErrorCode,
+ 0,
+ 0,
+ NULL,
+ OptionShutdownSystem,
+ &Response
+ );
+
+ return;
+}
+
+
+ULONG CurrentWatchPoint=0;
+
+VOID
+AsyncSetBreakPoint(
+ ULONG LinearAddress
+ )
+{
+#ifdef i386
+ CurrentWatchPoint = LinearAddress;
+
+ _asm {
+ mov eax, LinearAddress
+ mov dr0, eax
+ mov eax, 10303h
+ mov dr7, eax
+ }
+#endif
+}
+
+VOID
+AsyncRemoveBreakPoint(
+ ULONG LinearAddress
+ )
+{
+#ifdef i386
+ CurrentWatchPoint = 0;
+
+ _asm {
+ mov eax, 0
+ mov dr7, eax
+ }
+#endif
+}
+
+#pragma optimize ( "", on )
+
+VOID
+CrashSpecial(
+ PULONG ub
+ )
+{
+ CrashRequest = ub[0];
+ KeSetEvent( &CrashEvent, 0, FALSE );
+}
diff --git a/private/windbg/driver/crashdrv/tests/install.c b/private/windbg/driver/crashdrv/tests/install.c
new file mode 100644
index 000000000..1f67de05d
--- /dev/null
+++ b/private/windbg/driver/crashdrv/tests/install.c
@@ -0,0 +1,83 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ install.c
+
+Abstract:
+
+ This module contains the code that implements a driver installation
+
+Author:
+
+ Wesley Witt (wesw) 1-Oct-1993
+
+Environment:
+
+ User mode
+
+Notes:
+
+Revision History:
+
+
+--*/
+
+#include <windows.h>
+#include <winsvc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define SERVICE_NAME "CrashDrv"
+#define DRIVER_NAME "\\systemroot\\system32\\drivers\\CrashDrv.sys"
+
+
+void _cdecl main( void )
+{
+ SC_HANDLE hService;
+ SC_HANDLE hOldService;
+ SERVICE_STATUS ServStat;
+ CHAR buf[MAX_PATH];
+
+
+ if( !( hService = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS ) ) ) {
+ printf( "Error: Could not open handle to service manager for CrashDrv driver; error code = %u\n", GetLastError() );
+ return;
+ }
+ if( hOldService = OpenService( hService, SERVICE_NAME, SERVICE_ALL_ACCESS ) ) {
+ if( ! ControlService( hOldService, SERVICE_CONTROL_STOP, & ServStat ) ) {
+ int fError = GetLastError();
+ if( ( fError != ERROR_SERVICE_NOT_ACTIVE ) && ( fError != ERROR_INVALID_SERVICE_CONTROL ) ) {
+ printf( "Error: Could not stop %s service; error code = %u\n", SERVICE_NAME, fError );
+ return;
+ }
+ }
+ if( ! DeleteService( hOldService ) ) {
+ printf( "Error: Could not delete old service for %s driver; error code = %u\n", SERVICE_NAME, GetLastError() );
+ return;
+ }
+ if( ! CloseServiceHandle( hOldService ) ) {
+ printf( "Error: Could not delete old service for %s driver; error code = %u\n", SERVICE_NAME, GetLastError() );
+ return;
+ }
+ }
+ if( ! CreateService( hService, SERVICE_NAME, SERVICE_NAME, SERVICE_ALL_ACCESS, SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START,
+ SERVICE_ERROR_NORMAL, DRIVER_NAME, "Extended base", NULL, NULL, NULL, NULL ) ) {
+ int fError = GetLastError();
+ if( fError != ERROR_SERVICE_EXISTS ) {
+ printf( "Error: Could not create %s service; error code = %u\n", SERVICE_NAME, fError );
+ return;
+ }
+ }
+ if( ! CloseServiceHandle( hService ) ) {
+ printf( "Error: Could not close handle to service manager for %s driver; error code = %u\n", SERVICE_NAME, GetLastError() );
+ return;
+ }
+
+ GetEnvironmentVariable( "systemroot", buf, sizeof(buf) );
+ strcat( buf, "\\system32\\drivers\\CrashDrv.sys" );
+ CopyFile( "CrashDrv.sys", buf, FALSE );
+}
diff --git a/private/windbg/driver/crashdrv/tests/install.rc b/private/windbg/driver/crashdrv/tests/install.rc
new file mode 100644
index 000000000..34b3cfa93
--- /dev/null
+++ b/private/windbg/driver/crashdrv/tests/install.rc
@@ -0,0 +1,11 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Microsoft\256 Kernel Crash Driver Install Utility"
+
+#define VER_INTERNALNAME_STR "install.exe"
+#define VER_ORIGINALFILENAME_STR "install.exe"
+
+#include <common.ver>
diff --git a/private/windbg/driver/crashdrv/tests/makefile b/private/windbg/driver/crashdrv/tests/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/windbg/driver/crashdrv/tests/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/windbg/driver/crashdrv/tests/makefile.inc b/private/windbg/driver/crashdrv/tests/makefile.inc
new file mode 100644
index 000000000..577865208
--- /dev/null
+++ b/private/windbg/driver/crashdrv/tests/makefile.inc
@@ -0,0 +1,3 @@
+obj\$(TARGET_DIRECTORY)\test.res: test.rc
+
+obj\$(TARGET_DIRECTORY)\install.res: install.rc
diff --git a/private/windbg/driver/crashdrv/tests/sources b/private/windbg/driver/crashdrv/tests/sources
new file mode 100644
index 000000000..049a81ec4
--- /dev/null
+++ b/private/windbg/driver/crashdrv/tests/sources
@@ -0,0 +1,17 @@
+MAJORCOMP=windbg
+MINORCOMP=driver
+
+TARGETNAME=crashdrv
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+INCLUDES=$(BASEDIR)\private\ntos\inc;..\
+
+SOURCES=
+
+UMTYPE=console
+UMAPPL=test*install
+UMRES=$(@R).res
+
+NTTARGETFILE0=obj\*\test.res \
+ obj\*\install.res
diff --git a/private/windbg/driver/crashdrv/tests/test.c b/private/windbg/driver/crashdrv/tests/test.c
new file mode 100644
index 000000000..68b13fad8
--- /dev/null
+++ b/private/windbg/driver/crashdrv/tests/test.c
@@ -0,0 +1,295 @@
+#include <windows.h>
+#include <winioctl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "crashdrv.h"
+
+#define CRASHDRV_DEVICE "\\\\.\\CrashDrv"
+#define KMODE_EXCEPTION_NOT_HANDLED ((ULONG)0x0000001EL)
+#define IRQL_NOT_LESS_OR_EQUAL ((ULONG)0x0000000AL)
+
+typedef struct _TESTINFO {
+ DWORD CtlCode;
+ DWORD TestNum;
+ LPSTR Description;
+} TESTINFO, *LPTESTINFO;
+
+TESTINFO TestInformation[] =
+ {
+ 0, 0, NULL,
+ (DWORD)IOCTL_CRASHDRV_BUGCHECK, TEST_BUGCHECK, "Bugcheck",
+ (DWORD)IOCTL_CRASHDRV_STACK_OVERFLOW, TEST_STACK_OVERFLOW, "Stack overflow",
+ (DWORD)IOCTL_CRASHDRV_SIMPLE, TEST_SIMPLE, "Simple",
+ (DWORD)IOCTL_CRASHDRV_EXCEPTION, TEST_EXCEPTION, "Exception",
+ (DWORD)IOCTL_CRASHDRV_HARDERR, TEST_HARDERR, "Hard error",
+ (DWORD)IOCTL_CRASHDRV_SPECIAL, TEST_SPECIAL, "Special"
+ };
+
+#define MaxTests (sizeof(TestInformation)/sizeof(TESTINFO))
+
+DWORD IoctlBuf[16];
+DWORD TestNumber;
+
+VOID GetCommandLineArgs(VOID);
+VOID Usage(VOID);
+DWORD CrashDrvCheckRequest(HANDLE);
+BOOL StartCrashDrvService(VOID);
+
+void _cdecl
+main( void )
+{
+ HANDLE hCrashDrv;
+ DWORD rq;
+ DWORD ReturnedByteCount;
+
+
+ ZeroMemory( IoctlBuf, sizeof(IoctlBuf) );
+
+ GetCommandLineArgs();
+
+ if (!StartCrashDrvService()) {
+ return;
+ }
+
+ hCrashDrv = CreateFile( CRASHDRV_DEVICE,
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL
+ );
+
+ if ( hCrashDrv == INVALID_HANDLE_VALUE ) {
+ printf("Could not open the CrashDrv device (%d)\n",GetLastError());
+ ExitProcess(1);
+ }
+
+ printf("Successfuly opened the CrashDrv device\n");
+
+ if (TestNumber) {
+ if (TestNumber > MaxTests) {
+ printf( "invalid test number\n" );
+ Usage();
+ }
+ if (!DeviceIoControl(
+ hCrashDrv,
+ TestInformation[TestNumber].CtlCode,
+ NULL,
+ 0,
+ IoctlBuf,
+ sizeof(IoctlBuf),
+ &ReturnedByteCount,
+ NULL
+ )) {
+ printf( "call to driver failed <ec=%d>\n", GetLastError() );
+ }
+ return;
+ }
+
+ while( TRUE ) {
+
+ rq = CrashDrvCheckRequest( hCrashDrv );
+
+ if (rq) {
+ if (!DeviceIoControl(
+ hCrashDrv,
+ CTL_CODE(FILE_DEVICE_CRASHDRV, rq, METHOD_BUFFERED,FILE_ANY_ACCESS),
+ NULL,
+ 0,
+ IoctlBuf,
+ sizeof(IoctlBuf),
+ &ReturnedByteCount,
+ NULL
+ )) {
+ printf( "call to driver failed <ec=%d>\n", GetLastError() );
+ }
+ }
+
+ Sleep(500);
+ }
+
+ CloseHandle( hCrashDrv );
+ return;
+}
+
+
+DWORD
+CrashDrvCheckRequest(
+ HANDLE hCrashDrv
+ )
+{
+ DWORD ReturnedByteCount;
+ BOOL rc;
+
+
+ ZeroMemory( IoctlBuf, sizeof(IoctlBuf) );
+
+ rc = DeviceIoControl(
+ hCrashDrv,
+ (DWORD)IOCTL_CRASHDRV_CHECK_REQUEST,
+ NULL,
+ 0,
+ IoctlBuf,
+ sizeof(IoctlBuf),
+ &ReturnedByteCount,
+ NULL
+ );
+
+ return IoctlBuf[0];
+}
+
+
+VOID
+Usage(
+ VOID
+ )
+{
+ DWORD i;
+
+ printf( "usage: TEST [options]\n" );
+ printf( " [-?] Display this message\n" );
+ printf( " [-t test-number] Execute a test\n" );
+ for (i=1; i<MaxTests; i++) {
+ printf( " #%d %s\n", i, TestInformation[i].Description );
+ }
+ ExitProcess(0);
+}
+
+
+VOID
+GetCommandLineArgs(
+ VOID
+ )
+{
+ char *lpstrCmd = GetCommandLine();
+ UCHAR ch;
+ DWORD i = 0;
+ char buf[10];
+
+ // skip over program name
+ do {
+ ch = *lpstrCmd++;
+ }
+ while (ch != ' ' && ch != '\t' && ch != '\0');
+
+ // skip over any following white space
+ while (ch == ' ' || ch == '\t') {
+ ch = *lpstrCmd++;
+ }
+
+ // process each switch character '-' as encountered
+
+ while (ch == '-' || ch == '/') {
+ ch = tolower(*lpstrCmd++);
+ // process multiple switch characters as needed
+ do {
+ switch (ch) {
+ case 't':
+ i=0;
+ ch = *lpstrCmd++;
+ while (ch == ' ' || ch == '\t') {
+ ch = *lpstrCmd++;
+ }
+ while (ch != ' ' && ch != '\0' && ch != ',') {
+ buf[i++] = ch;
+ ch = *lpstrCmd++;
+ }
+ buf[i] = 0;
+ TestNumber = atoi( buf );
+ if (ch == ',') {
+ i=0;
+ ch = *lpstrCmd++;
+ while (ch != ' ' && ch != '\0') {
+ buf[i++] = ch;
+ ch = *lpstrCmd++;
+ }
+ buf[i] = 0;
+ IoctlBuf[0] = atoi( buf );
+ if (TestNumber == TEST_SPECIAL) {
+ if (IoctlBuf[0] == 1) {
+ IoctlBuf[0] = KMODE_EXCEPTION_NOT_HANDLED;
+ }
+ if (IoctlBuf[0] == 2) {
+ IoctlBuf[0] = IRQL_NOT_LESS_OR_EQUAL;
+ }
+ }
+ }
+ break;
+
+ case '?':
+ Usage();
+ ch = *lpstrCmd++;
+ break;
+
+ default:
+ return;
+ }
+ } while (ch != ' ' && ch != '\t' && ch != '\0');
+
+ while (ch == ' ' || ch == '\t') {
+ ch = *lpstrCmd++;
+ }
+ }
+
+ return;
+}
+
+
+BOOL
+StartCrashDrvService(
+ VOID
+ )
+{
+ SERVICE_STATUS ssStatus;
+ DWORD dwOldCheckPoint;
+ SC_HANDLE schService;
+ SC_HANDLE schSCManager;
+
+
+ schSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
+ if (schSCManager == NULL) {
+ printf( "could not open service controller database\n" );
+ return FALSE;
+ }
+
+ schService = OpenService( schSCManager, "CrashDrv", SERVICE_ALL_ACCESS );
+ if (schService == NULL) {
+ printf( "CrashDrv service is not installed, run install.exe\n" );
+ return FALSE;
+ }
+
+ if (!StartService( schService, 0, NULL )) {
+ if (GetLastError() == ERROR_SERVICE_ALREADY_RUNNING) {
+ printf( "CrashDrv service already running\n" );
+ return TRUE;
+ }
+ printf( "CrashDrv service could not be started\n" );
+ return FALSE;
+ }
+
+ if (!QueryServiceStatus( schService, &ssStatus)) {
+ printf( "CrashDrv service could not be started\n" );
+ return FALSE;
+ }
+
+ while (ssStatus.dwCurrentState != SERVICE_RUNNING) {
+ dwOldCheckPoint = ssStatus.dwCheckPoint;
+ Sleep(ssStatus.dwWaitHint);
+ if (!QueryServiceStatus( schService, &ssStatus)) {
+ break;
+ }
+ if (dwOldCheckPoint >= ssStatus.dwCheckPoint) {
+ break;
+ }
+ }
+
+ if (ssStatus.dwCurrentState == SERVICE_RUNNING)
+ printf("CrashDrv service started\n");
+ else {
+ printf("CrashDrv service not started: \n");
+ }
+
+ CloseServiceHandle(schService);
+}
diff --git a/private/windbg/driver/crashdrv/tests/test.rc b/private/windbg/driver/crashdrv/tests/test.rc
new file mode 100644
index 000000000..8c4cc9dc4
--- /dev/null
+++ b/private/windbg/driver/crashdrv/tests/test.rc
@@ -0,0 +1,11 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Microsoft\256 Kernel Crash Driver Tester"
+
+#define VER_INTERNALNAME_STR "test.exe"
+#define VER_ORIGINALFILENAME_STR "test.exe"
+
+#include <common.ver>