Disclaimer:
This post comes from my old blog back in 2004. I’m reposting it here so that I don’t lose the content. The source was hand-written HTML so the formatting probably appears a bit off.
No matter how careful of a programmer you are, there will always be times when a hardware exception will occur in your code. Perhaps it was a third party component that was the culprit. Perhaps, it was a fellow co-worker that broke something. Or maybe it was Microsoft itself not playing fair with its documentation and/or implementations. Whatever the case, it is often very useful to be able to capture a run-time exception that was generated by the CPU. Sure, you can use a catch(…) to be your fail-safe, but wouldn’t it be great to be able to convert that exception that was generated by the hardware into a C++ exception? I created this class in order to do that very thing. In fact, this class was the basis for my super assert that I created, because I found that I could cause a hardware exception any time I wanted, and by using this C++ hardware exception container, I could access each thread’s stack frame at run-time. This would eventually enable me to perform a stack trace inside of an assert, but I will explain that more in a different tutorial. Anyway, I hope that this is useful to someone. I spent a while digging around in the mire that is Microsoft’s documentation before I put this together. Perhaps this will save someone else time in the future. Enjoy. -BossHogg #ifndef HARDWARE_EXCEPTION #define HARDWARE_EXCEPTION 1 enum HWExceptionType { eIllegalMemoryAccess = EXCEPTION_ACCESS_VIOLATION, eUnexpectedBreakpoint = EXCEPTION_BREAKPOINT, eDataTypeMisalignment = EXCEPTION_DATATYPE_MISALIGNMENT, eSingleStepInstruction = EXCEPTION_SINGLE_STEP, eArrayBoundsExceeded = EXCEPTION_ARRAY_BOUNDS_EXCEEDED, eDenormalFloat = EXCEPTION_FLT_DENORMAL_OPERAND, eFloatDivideByZero = EXCEPTION_FLT_DIVIDE_BY_ZERO, eFloatInexactResult = EXCEPTION_FLT_INEXACT_RESULT, eFloatInvalidOperation = EXCEPTION_FLT_INVALID_OPERATION, eFloatOverflow = EXCEPTION_FLT_OVERFLOW, eFloatStackCorrupted = EXCEPTION_FLT_STACK_CHECK, eFloatUnderflow = EXCEPTION_FLT_UNDERFLOW, eIntDivideByZero = EXCEPTION_INT_DIVIDE_BY_ZERO, eIntOverflow = EXCEPTION_INT_OVERFLOW, ePrivelegedInstruction = EXCEPTION_PRIV_INSTRUCTION, eUncontinuableException = EXCEPTION_NONCONTINUABLE_EXCEPTION }; class HWException { public: HWException(HWExceptionType aType, EXCEPTION_POINTERS* pExp): itsCategory(aType), itsPointers(pExp), itsLocation(pExp->ExceptionRecord->ExceptionAddress) { } HWExceptionType GetCategory() const {return itsCategory;} DWORD GetLocation() const {return itsLocation;} EXCEPTION_POINTERS* GetSysPointer()const {return itsPointers;} protected: HWExceptionType itsCategory; DWORD itsLocation; EXCEPTION_POINTERS* itsPointers; }; static void HWTranslateException(unsigned int u, EXCEPTION_POINTERS* pExp) { throw HWException((HWExceptionType)u,pExp); } #endif /////////////////////////////////////////////////////////////////////// Example usage: /////////////////////////////////////////////////////////////////////// #include "windows.h" #include "HWException.h" int main() { //Note, setting the exception translator must be done //on a per thread basis. _set_se_translator(HWTranslateException); try { //This will cause an access violation char* ptr = NULL; *ptr = 5; } catch (HWException& e) { //We can now know both the type and the //memory location of the instruction that //caused the exception. Cool! HWExceptionType exceptionType = e.GetCategory(); DWORD address = e.GetLocation(); } catch (...) { //If we got here, then it was some other kind //of C++ exception... } return 0; } |