Jonathan Hays

Translating Hardware Exceptions to C++ Exceptions

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;

}