| // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| // |
| // A class to make it easy to tag exception propagation boundaries and |
| // get crash reports of exceptions that pass over same. |
| // |
| // An exception barrier is used to report exceptions that pass through |
| // a boundary where exceptions shouldn't pass, such as e.g. COM interface |
| // boundaries. |
| // This is handy for any kind of plugin code, where if the exception passes |
| // through unhindered, it'll either be swallowed by an SEH exception handler |
| // above us on the stack, or be reported as an unhandled exception for |
| // the application hosting the plugin code. |
| // |
| // IMPORTANT NOTE: This class has crash_reporting disabled by default. To |
| // enable crash reporting call: |
| // |
| // @code |
| // ExceptionBarrierBase::set_crash_handling(true) |
| // @endcode |
| // |
| // somewhere in your initialization code. |
| // |
| // Then, to use this class, simply instantiate an ExceptionBarrier just inside |
| // the code boundary, like this: |
| // @code |
| // HRESULT SomeObject::SomeCOMMethod(...) { |
| // ExceptionBarrier report_crashes; |
| // |
| // ... other code here ... |
| // } |
| // @endcode |
| // |
| // There are three ExceptionBarrier types defined here: |
| // 1) ExceptionBarrier which reports all crashes it sees. |
| // 2) ExceptionBarrierReportOnlyModule which reports only crashes occurring |
| // in this module. |
| // 3) ExceptionBarrierCustomHandler which calls the handler set by a call |
| // to ExceptionBarrierCallCustomHandler::set_custom_handler(). Note that |
| // there is one custom handler for all ExceptionBarrierCallCustomHandler |
| // instances. If set_custom_handler() is never called, this places an |
| // SEH in the chain that just returns ExceptionContinueSearch. |
| |
| #ifndef CHROME_FRAME_EXCEPTION_BARRIER_H_ |
| #define CHROME_FRAME_EXCEPTION_BARRIER_H_ |
| |
| #include <windows.h> |
| |
| extern "C" IMAGE_DOS_HEADER __ImageBase; |
| |
| // This is the type dictated for an exception handler by the platform ABI |
| // @see _except_handler in excpt.h |
| typedef EXCEPTION_DISPOSITION (__cdecl* ExceptionHandlerFunc)( |
| struct _EXCEPTION_RECORD* exception_record, |
| void* establisher_frame, |
| struct _CONTEXT* context, |
| void* reserved); |
| |
| // The type of an exception record in the exception handler chain |
| struct EXCEPTION_REGISTRATION { |
| EXCEPTION_REGISTRATION* prev; |
| ExceptionHandlerFunc handler; |
| }; |
| |
| // This is our raw exception handler, it must be declared extern "C" to |
| // match up with the SAFESEH declaration in our corresponding ASM file. |
| extern "C" EXCEPTION_DISPOSITION __cdecl |
| ExceptionBarrierHandler(struct _EXCEPTION_RECORD* exception_record, |
| void* establisher_frame, |
| struct _CONTEXT* context, |
| void* reserved); |
| |
| // An alternate raw exception handler that reports crashes only for the current |
| // module. It must be declared extern "C" to match up with the SAFESEH |
| // declaration in our corresponding ASM file. |
| extern "C" EXCEPTION_DISPOSITION __cdecl |
| ExceptionBarrierReportOnlyModuleHandler( |
| struct _EXCEPTION_RECORD* exception_record, |
| void* establisher_frame, |
| struct _CONTEXT* context, |
| void* reserved); |
| |
| // An alternate raw exception handler that calls out to a custom handler. |
| // It must be declared extern "C" to match up with the SAFESEH declaration in |
| // our corresponding ASM file. |
| extern "C" EXCEPTION_DISPOSITION __cdecl |
| ExceptionBarrierCallCustomHandler( |
| struct _EXCEPTION_RECORD* exception_record, |
| void* establisher_frame, |
| struct _CONTEXT* context, |
| void* reserved); |
| |
| |
| // @name These are implemented in the associated .asm file |
| // @{ |
| extern "C" void WINAPI RegisterExceptionRecord( |
| EXCEPTION_REGISTRATION* registration, |
| ExceptionHandlerFunc func); |
| extern "C" void WINAPI UnregisterExceptionRecord( |
| EXCEPTION_REGISTRATION* registration); |
| // @} |
| |
| |
| // Traits classes for ExceptionBarrierT. |
| class EBTraitsBase { |
| public: |
| static void UnregisterException(EXCEPTION_REGISTRATION* registration) { |
| UnregisterExceptionRecord(registration); |
| } |
| }; |
| |
| class EBReportAllTraits : public EBTraitsBase { |
| public: |
| static void RegisterException(EXCEPTION_REGISTRATION* registration) { |
| RegisterExceptionRecord(registration, ExceptionBarrierHandler); |
| } |
| }; |
| |
| class EBReportOnlyThisModuleTraits : public EBTraitsBase { |
| public: |
| static void RegisterException(EXCEPTION_REGISTRATION* registration) { |
| RegisterExceptionRecord(registration, |
| ExceptionBarrierReportOnlyModuleHandler); |
| } |
| }; |
| |
| class EBCustomHandlerTraits : public EBTraitsBase { |
| public: |
| static void RegisterException(EXCEPTION_REGISTRATION* registration) { |
| RegisterExceptionRecord(registration, |
| ExceptionBarrierCallCustomHandler); |
| } |
| }; |
| |
| class ExceptionBarrierConfig { |
| public: |
| // Used to globally enable or disable crash handling by ExceptionBarrierBase |
| // instances. |
| static void set_enabled(bool enabled) { |
| s_enabled_ = enabled; |
| } |
| static bool enabled() { return s_enabled_; } |
| |
| // Whether crash reports are enabled. |
| static bool s_enabled_; |
| }; |
| |
| template <typename RegistrarTraits> |
| class ExceptionBarrierT { |
| public: |
| // Register the barrier in the SEH chain |
| ExceptionBarrierT() { |
| RegistrarTraits::RegisterException(®istration_); |
| } |
| |
| // Unregister on destruction |
| virtual ~ExceptionBarrierT() { |
| RegistrarTraits::UnregisterException(®istration_); |
| } |
| |
| protected: |
| // Our SEH frame |
| EXCEPTION_REGISTRATION registration_; |
| }; |
| |
| // This class allows for setting a custom exception handler function. The |
| // handler is shared among all instances. This class is intended to enable |
| // testing of the SEH registration. |
| template <typename RegistrarTraits> |
| class ExceptionBarrierCustomHandlerT : |
| public ExceptionBarrierT<typename RegistrarTraits> { |
| public: |
| // Signature of the handler function which gets notified when |
| // an exception propagates through a barrier. |
| typedef void (CALLBACK* CustomExceptionHandler)(EXCEPTION_POINTERS* ptrs); |
| |
| // Used to set a global custom handler used by all |
| // ExceptionBarrierCustomHandler instances. |
| static void set_custom_handler(CustomExceptionHandler handler) { |
| s_custom_handler_ = handler; |
| } |
| static CustomExceptionHandler custom_handler() { return s_custom_handler_; } |
| |
| private: |
| static CustomExceptionHandler s_custom_handler_; |
| }; |
| |
| // Convenience typedefs for the ExceptionBarrierT specializations. |
| typedef ExceptionBarrierT<EBReportAllTraits> ExceptionBarrier; |
| typedef ExceptionBarrierT<EBReportOnlyThisModuleTraits> |
| ExceptionBarrierReportOnlyModule; |
| typedef ExceptionBarrierCustomHandlerT<EBCustomHandlerTraits> |
| ExceptionBarrierCustomHandler; |
| |
| #endif // CHROME_FRAME_EXCEPTION_BARRIER_H_ |