windows-nt/Source/XPSP1/NT/admin/pchealth/client/test/gpfme/fault.cpp
2020-09-26 16:20:57 +08:00

694 lines
17 KiB
C++

#include <windows.h>
#include "faultrep.h"
#include "util.h"
#include "stdio.h"
#include "malloc.h"
BOOL g_fDebug = FALSE;
enum EFaultType
{
eftAV = 0,
eftMisalign,
eftArrayBound,
eftStackOverflowFunc,
eftStackOverflowAlloc,
eftInstrPriv,
eftInstrBad,
eftIntDivZero,
eftIntOverflow,
eftFltDivZero,
eftFltOverflow,
eftFltUnderflow,
eftFltStack,
eftFltInexact,
eftFltDenormal,
eftFltInvalid,
eftExBadRet,
eftExNonCont,
};
// ***************************************************************************
void ShowUsage(void)
{
printf("\n");
printf("gpfme [command] [exception type]\n");
printf("\nCommand options:\n");
printf(" -a: Access violation (default if no command is specified)\n");
#ifndef _WIN64
printf(" -b: Array bound violation\n");
#endif
printf(" -i: Integer divide by 0 (default)\n");
printf(" -iz: Integer divide by 0\n");
printf(" -io: Integer overflow\n");
#ifdef _WIN64
printf(" -m: Data misalignment fault (not available on x86)\n");
#endif
printf(" -s: Stack overflow via infinite recursion (default) \n");
printf(" -sa: Stack overflow via alloca\n");
printf(" -sf: Stack overflow via infinite recursion\n");
printf(" -f: Floating point divide by 0 (default)\n");
printf(" -fi: Floating point inexact result\n");
printf(" -fn: Floating point invalid operation\n");
printf(" -fo: Floating point overflow\n");
printf(" -fu: Floating point underflow\n");
printf(" -fz: Floating point divide by 0\n");
printf(" -n: Execute privilidged instruction (default)\n");
printf(" -ni: Execute invalid instruction\n");
printf(" -np: Execute privilidged instruction\n");
}
// ***************************************************************************
LONG MyFilter(EXCEPTION_POINTERS *pep)
{
static BOOL fGotHere = FALSE;
EFaultRepRetVal frrv;
pfn_REPORTFAULT pfn = NULL;
HMODULE hmodFaultRep = NULL;
WCHAR szDebugger[2 * MAX_PATH];
BOOL fGotDbgr = FALSE;
char wszMsg[2048];
if (g_fDebug &&
(pep->ExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT ||
pep->ExceptionRecord->ExceptionCode == EXCEPTION_SINGLE_STEP))
return EXCEPTION_CONTINUE_SEARCH;
if (g_fDebug && fGotHere)
return EXCEPTION_CONTINUE_SEARCH;
fGotHere = TRUE;
if (g_fDebug)
DebugBreak();
if (GetProfileStringW(L"AeDebug", L"Debugger", NULL, szDebugger, sizeofSTRW(szDebugger) - 1))
fGotDbgr = TRUE;
hmodFaultRep = LoadLibrary("faultrep.dll");
if (hmodFaultRep != NULL)
{
pfn = (pfn_REPORTFAULT)GetProcAddress(hmodFaultRep, "ReportFault");
if (pfn != NULL)
{
frrv = (*pfn)(pep, fGotDbgr);
}
else
{
printf("Unable to get ReportFault function\n");
return EXCEPTION_CONTINUE_SEARCH;
}
}
else
{
printf("Unable to load faultrep.dll\n");
return EXCEPTION_CONTINUE_SEARCH;
}
switch(frrv)
{
case frrvOk:
printf("DW completed fine.\n");
break;
case frrvOkManifest:
printf("DW completed fine in manifest mode.\n");
break;
case frrvOkQueued:
printf("DW completed fine in queue mode.\n");
break;
case frrvLaunchDebugger:
printf("DW completed fine & says to launch debugger.\n");
break;
case frrvErrNoDW:
printf("DW could not be launched.\n");
break;
case frrvErr:
printf("An error occurred.\n");
break;
case frrvErrTimeout:
printf("Timed out waiting for DW to complete.\n");
break;
default:
printf("unexpected return value...\n");
break;
}
if (hmodFaultRep != NULL)
FreeLibrary(hmodFaultRep);
return EXCEPTION_EXECUTE_HANDLER;
};
// ***************************************************************************
void NukeStack(void)
{
DWORD rgdw[512];
DWORD a = 1;
// the compiler tries to be smart and not let me deliberately write a
// infinitely recursive function, so gotta do this to work around it.
if(a == 1)
NukeStack();
}
// ***************************************************************************
typedef DWORD (*FAULT_FN)(void);
void DoException(EFaultType eft)
{
switch(eft)
{
// access violation
default:
case eftAV:
{
int *p = NULL;
fprintf(stderr, "Generating an access violation\n");
*p = 1;
fprintf(stderr, "Error: No exception thrown.\n");
break;
}
#ifdef _WIN64
// data misalignment
case eftMisalign:
{
DWORD *pdw;
BYTE rg[8];
fprintf(stderr, "Generating an misalignment fault.\n");
pdw = (DWORD *)&rg[2];
*pdw = 1;
fprintf(stderr, "Error: No exception thrown.\n");
break;
}
#endif
#ifndef _WIN64
// array bounds failure
case eftArrayBound:
{
fprintf(stderr, "Generating an out-of-bounds exception\n");
__int64 li;
DWORD *pdw = (DWORD *)&li;
*pdw = 1;
pdw++;
*pdw = 2;
// bound will throw an 'array out of bounds' exception
_asm mov eax, 0
_asm bound eax, li
fprintf(stderr, "Error: No exception thrown.\n");
break;
}
#endif
// stack overflow
case eftStackOverflowFunc:
{
fprintf(stderr, "Generating an stack overflow via recursion\n");
NukeStack();
fprintf(stderr, "Error: No exception thrown.\n");
break;
}
// stack overflow
case eftStackOverflowAlloc:
{
LPVOID pv;
DWORD i;
fprintf(stderr, "Generating an stack overflow via alloca\n");
for (i = 0; i < 0xffffffff; i++)
pv = _alloca(512);
fprintf(stderr, "Error: No exception thrown.\n");
break;
}
// integer divide by 0
case eftIntDivZero:
{
DWORD x = 4, y = 0;
fprintf(stderr, "Generating an integer div by 0\n");
x = x / y;
fprintf(stderr, "Error: No exception thrown.\n");
break;
}
// integer overflow
case eftIntOverflow:
{
fprintf(stderr, "Generating an integer overflow\n");
#ifdef _WIN64
__int64 x = 0x7fffffffffffffff, y = 0x7fffffffffffffff;
x = x + y;
#else
DWORD x = 0x7fffffff, y = 0x7fffffff;
x = x + y;
_asm into
#endif
fprintf(stderr, "Error: No exception thrown.\n");
break;
}
// floating point divide by 0
case eftFltDivZero:
{
double x = 4.1, y = 0.0;
WORD wCtl, wCtlNew;
fprintf(stderr, "Generating an floating point div by 0\n");
#ifdef _WIN64
x = x / y;
#else
// got to unmask the floating point exceptions so that the
// processor doesn't handle them on it's own
_asm fnstcw wCtl
wCtlNew = wCtl & 0xffc0;
_asm fldcw wCtlNew
x = x / y;
_asm fldcw wCtl
#endif
fprintf(stderr, "Error: No exception thrown.\n");
break;
}
// floating point stack overflow
case eftFltStack:
{
double x;
WORD wCtl, wCtlNew;
fprintf(stderr, "Generating an floating point stack overflow\n");
#ifdef _WIN64
#else
// Got to unmask the floating point exceptions so that the
// processor doesn't handle them on it's own
_asm fnstcw wCtl
wCtlNew = wCtl & 0xffc0;
_asm fldcw wCtlNew
// there should be 8 floating point stack registers, so attempting
// to add a 9th element should nuke it
_asm fld x
_asm fld x
_asm fld x
_asm fld x
_asm fld x
_asm fld x
_asm fld x
_asm fld x
_asm fld x
_asm fldcw wCtl
#endif
fprintf(stderr, "Error: No exception thrown.\n");
break;
}
// floating point overflow
case eftFltOverflow:
{
double x = 1.0, y = 10.0;
WORD wCtl, wCtlNew;
DWORD i;
fprintf(stderr, "Generating an floating point overflow\n");
#ifdef _WIN64
#else
// Got to unmask the floating point exceptions so that the
// processor doesn't handle them on it's own
_asm fnstcw wCtl
wCtlNew = wCtl & 0xffe0;
_asm fldcw wCtlNew
#endif
for(i = 0; i < 100000; i++)
x = x * y;
fprintf(stderr, "Error: No exception thrown.\n");
break;
}
// floating point invalid op
case eftFltInvalid:
{
double x = 1.0, y = 10.0;
WORD wCtl, wCtlNew;
DWORD i;
#ifdef _WIN64
#else
// Got to unmask the floating point exceptions so that the
// processor doesn't handle them on it's own
_asm fnstcw wCtl
wCtlNew = wCtl & 0xffe0;
_asm fldcw wCtlNew
#endif
fprintf(stderr, "Generating an floating point invalid operation\n");
for(i = 0; i < 100000; i++)
x = x / y;
fprintf(stderr, "Error: No exception thrown.\n");
break;
}
// floating point inexact result
case eftFltInexact:
{
double x = 1.0, y = 10.0;
WORD wCtl, wCtlNew;
DWORD i;
#ifdef _WIN64
#else
// Got to unmask the floating point exceptions so that the
// processor doesn't handle them on it's own
_asm fnstcw wCtl
wCtlNew = wCtl & 0xffc0;
_asm fldcw wCtlNew
#endif
fprintf(stderr, "Generating an floating point underflow\n");
for(i = 0; i < 100000; i++)
x = x / y;
fprintf(stderr, "Error: No exception thrown.\n");
break;
}
// floating point denormal value
case eftFltDenormal:
{
double x = 1.0;
DWORD i;
WORD wCtl, wCtlNew;
BYTE rg[8] = { 1, 0, 0, 0, 0, 0, 6, 0 };
fprintf(stderr, "Generating a floating point denormal exception\n");
#ifdef _WIN64
#else
// Got to unmask the floating point exceptions so that the
// processor doesn't handle them on it's own
memcpy(&x, rg, 8);
_asm fnstcw wCtl
wCtlNew = wCtl & 0xf2fc;
_asm fldcw wCtlNew
_asm fld x
#endif
fprintf(stderr, "Error: No exception thrown.\n");
break;
}
// executing a privilidged instruction
case eftInstrPriv:
{
fprintf(stderr, "Generating an privilidged instruction exception\n");
#ifdef _WIN64
#else
// must be ring 0 to execute HLT
_asm hlt
#endif
fprintf(stderr, "Error: No exception thrown.\n");
break;
}
// executing an invalid instruction
case eftInstrBad:
{
FAULT_FN pfn;
BYTE rgc[2048];
FillMemory(rgc, sizeof(rgc), 0);
pfn = (FAULT_FN)(DWORD_PTR)rgc;
fprintf(stderr, "Generating an invalid instruction exception\n");
(*pfn)();
fprintf(stderr, "Error: No exception thrown.\n");
break;
}
case eftExNonCont:
{
fprintf(stderr, "Generating an non-continuable exception- **not implemented**\n");
fprintf(stderr, "Error: No exception thrown.\n");
break;
}
case eftExBadRet:
{
fprintf(stderr, "Generating an bad exception filter exception- **not implemented**\n");
fprintf(stderr, "Error: No exception thrown.\n");
break;
}
}
}
// ***************************************************************************
int __cdecl main(int argc, char **argv)
{
EFaultType eft = eftAV;
BOOL fCheckDebug = FALSE;
BOOL fUseTry = FALSE;
BOOL fUseFilter = FALSE;
if (argc >= 3 && (argv[2][0] == '/' || argv[2][0] == '-'))
{
switch(argv[2][1])
{
case 't':
case 'T':
if (argv[2][2] == 'D' || argv[2][2] == 'd')
g_fDebug = TRUE;
fUseTry = TRUE;
break;
case 'g':
case 'G':
if (argv[2][2] == 'D' || argv[2][2] == 'd')
g_fDebug = TRUE;
fUseFilter = TRUE;
break;
}
}
if (argc >= 2 && (argv[1][0] == '/' || argv[1][0] == '-'))
{
switch(argv[1][1])
{
case 't':
case 'T':
if (argv[1][2] == 'D' || argv[1][2] == 'd')
g_fDebug = TRUE;
fUseTry = TRUE;
break;
case 'g':
case 'G':
if (argv[1][2] == 'D' || argv[1][2] == 'd')
g_fDebug = TRUE;
fUseFilter = TRUE;
break;
// AV
default:
case 'a':
case 'A':
eft = eftAV;
break;
#ifndef _WIN64
// array bounds
case 'b':
case 'B':
eft = eftArrayBound;
break;
#endif
#ifdef _WIN64
// Misalignment
case 'm':
case 'M':
eft = eftMisalign;
break;
#endif
// Stack overflow
case 's':
case 'S':
switch(argv[1][2])
{
default:
case 'f':
case 'F':
eft = eftStackOverflowFunc;
break;
case 'a':
case 'A':
eft = eftStackOverflowAlloc;
break;
};
break;
// integer exceptions
case 'i':
case 'I':
switch(argv[1][2])
{
default:
case 'z':
case 'Z':
eft = eftIntDivZero;
break;
case 'o':
case 'O':
eft = eftIntOverflow;
break;
};
break;
// floating point exceptions
case 'f':
case 'F':
switch(argv[1][2])
{
default:
case 'z':
case 'Z':
eft = eftFltDivZero;
break;
case 'o':
case 'O':
eft = eftFltOverflow;
break;
case 'u':
case 'U':
eft = eftFltUnderflow;
break;
case 'S':
case 's':
eft = eftFltStack;
break;
case 'I':
case 'i':
eft = eftFltInexact;
break;
case 'D':
case 'd':
eft = eftFltDenormal;
break;
case 'N':
case 'n':
eft = eftFltInvalid;
break;
};
break;
// CPU instruction exceptions
case 'n':
case 'N':
switch(argv[1][2])
{
default:
case 'p':
case 'P':
eft = eftInstrPriv;
break;
case 'i':
case 'I':
eft = eftInstrBad;
break;
};
break;
case 'E':
case 'e':
switch(argv[1][2])
{
default:
case 'n':
case 'N':
eft = eftExNonCont;
break;
case 'i':
case 'I':
eft = eftExBadRet;
break;
};
break;
// help
case '?':
ShowUsage();
return 0;
}
}
else
{
eft = eftAV;
}
if (fUseFilter)
{
fUseTry = FALSE;
SetUnhandledExceptionFilter(MyFilter);
}
if (fUseTry)
{
__try
{
DoException(eft);
}
__except(MyFilter(GetExceptionInformation()))
{
}
}
else
{
DoException(eft);
}
return 0;
}