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;
}


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s