Home | History | Annotate | Download | only in chrome_frame
      1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 //
      5 // A class to make it easy to tag exception propagation boundaries and
      6 // get crash reports of exceptions that pass over same.
      7 //
      8 // An exception barrier is used to report exceptions that pass through
      9 // a boundary where exceptions shouldn't pass, such as e.g. COM interface
     10 // boundaries.
     11 // This is handy for any kind of plugin code, where if the exception passes
     12 // through unhindered, it'll either be swallowed by an SEH exception handler
     13 // above us on the stack, or be reported as an unhandled exception for
     14 // the application hosting the plugin code.
     15 //
     16 // IMPORTANT NOTE: This class has crash_reporting disabled by default. To
     17 // enable crash reporting call:
     18 //
     19 // @code
     20 // ExceptionBarrierBase::set_crash_handling(true)
     21 // @endcode
     22 //
     23 // somewhere in your initialization code.
     24 //
     25 // Then, to use this class, simply instantiate an ExceptionBarrier just inside
     26 // the code boundary, like this:
     27 // @code
     28 // HRESULT SomeObject::SomeCOMMethod(...) {
     29 //   ExceptionBarrier report_crashes;
     30 //
     31 //   ... other code here ...
     32 // }
     33 // @endcode
     34 //
     35 // There are three ExceptionBarrier types defined here:
     36 //  1) ExceptionBarrier which reports all crashes it sees.
     37 //  2) ExceptionBarrierReportOnlyModule which reports only crashes occurring
     38 //     in this module.
     39 //  3) ExceptionBarrierCustomHandler which calls the handler set by a call
     40 //     to ExceptionBarrierCallCustomHandler::set_custom_handler(). Note that
     41 //     there is one custom handler for all ExceptionBarrierCallCustomHandler
     42 //     instances. If set_custom_handler() is never called, this places an
     43 //     SEH in the chain that just returns ExceptionContinueSearch.
     44 
     45 #ifndef CHROME_FRAME_EXCEPTION_BARRIER_H_
     46 #define CHROME_FRAME_EXCEPTION_BARRIER_H_
     47 
     48 #include <windows.h>
     49 
     50 extern "C" IMAGE_DOS_HEADER __ImageBase;
     51 
     52 // This is the type dictated for an exception handler by the platform ABI
     53 // @see _except_handler in excpt.h
     54 typedef EXCEPTION_DISPOSITION (__cdecl* ExceptionHandlerFunc)(
     55                                 struct _EXCEPTION_RECORD* exception_record,
     56                                 void*  establisher_frame,
     57                                 struct _CONTEXT* context,
     58                                 void*  reserved);
     59 
     60 // The type of an exception record in the exception handler chain
     61 struct EXCEPTION_REGISTRATION {
     62   EXCEPTION_REGISTRATION* prev;
     63   ExceptionHandlerFunc  handler;
     64 };
     65 
     66 // This is our raw exception handler, it must be declared extern "C" to
     67 // match up with the SAFESEH declaration in our corresponding ASM file.
     68 extern "C" EXCEPTION_DISPOSITION __cdecl
     69 ExceptionBarrierHandler(struct _EXCEPTION_RECORD* exception_record,
     70                         void* establisher_frame,
     71                         struct _CONTEXT* context,
     72                         void* reserved);
     73 
     74 // An alternate raw exception handler that reports crashes only for the current
     75 // module. It must be declared extern "C" to match up with the SAFESEH
     76 // declaration in our corresponding ASM file.
     77 extern "C" EXCEPTION_DISPOSITION __cdecl
     78 ExceptionBarrierReportOnlyModuleHandler(
     79     struct _EXCEPTION_RECORD* exception_record,
     80     void* establisher_frame,
     81     struct _CONTEXT* context,
     82     void* reserved);
     83 
     84 // An alternate raw exception handler that calls out to a custom handler.
     85 // It must be declared extern "C" to match up with the SAFESEH declaration in
     86 // our corresponding ASM file.
     87 extern "C" EXCEPTION_DISPOSITION __cdecl
     88 ExceptionBarrierCallCustomHandler(
     89     struct _EXCEPTION_RECORD* exception_record,
     90     void* establisher_frame,
     91     struct _CONTEXT* context,
     92     void* reserved);
     93 
     94 
     95 // @name These are implemented in the associated .asm file
     96 // @{
     97 extern "C" void WINAPI RegisterExceptionRecord(
     98                           EXCEPTION_REGISTRATION* registration,
     99                           ExceptionHandlerFunc func);
    100 extern "C" void WINAPI UnregisterExceptionRecord(
    101                           EXCEPTION_REGISTRATION* registration);
    102 // @}
    103 
    104 
    105 // Traits classes for ExceptionBarrierT.
    106 class EBTraitsBase {
    107  public:
    108   static void UnregisterException(EXCEPTION_REGISTRATION* registration) {
    109     UnregisterExceptionRecord(registration);
    110   }
    111 };
    112 
    113 class EBReportAllTraits : public EBTraitsBase {
    114  public:
    115   static void RegisterException(EXCEPTION_REGISTRATION* registration) {
    116     RegisterExceptionRecord(registration, ExceptionBarrierHandler);
    117   }
    118 };
    119 
    120 class EBReportOnlyThisModuleTraits : public EBTraitsBase {
    121  public:
    122   static void RegisterException(EXCEPTION_REGISTRATION* registration) {
    123     RegisterExceptionRecord(registration,
    124                             ExceptionBarrierReportOnlyModuleHandler);
    125   }
    126 };
    127 
    128 class EBCustomHandlerTraits : public EBTraitsBase {
    129  public:
    130   static void RegisterException(EXCEPTION_REGISTRATION* registration) {
    131     RegisterExceptionRecord(registration,
    132                             ExceptionBarrierCallCustomHandler);
    133   }
    134 };
    135 
    136 class ExceptionBarrierConfig {
    137  public:
    138   // Used to globally enable or disable crash handling by ExceptionBarrierBase
    139   // instances.
    140   static void set_enabled(bool enabled) {
    141     s_enabled_ = enabled;
    142   }
    143   static bool enabled() { return s_enabled_; }
    144 
    145   // Whether crash reports are enabled.
    146   static bool s_enabled_;
    147 };
    148 
    149 template <typename RegistrarTraits>
    150 class ExceptionBarrierT {
    151  public:
    152   // Register the barrier in the SEH chain
    153   ExceptionBarrierT() {
    154     RegistrarTraits::RegisterException(&registration_);
    155   }
    156 
    157   // Unregister on destruction
    158   virtual ~ExceptionBarrierT() {
    159     RegistrarTraits::UnregisterException(&registration_);
    160   }
    161 
    162  protected:
    163   // Our SEH frame
    164   EXCEPTION_REGISTRATION registration_;
    165 };
    166 
    167 // This class allows for setting a custom exception handler function. The
    168 // handler is shared among all instances. This class is intended to enable
    169 // testing of the SEH registration.
    170 template <typename RegistrarTraits>
    171 class ExceptionBarrierCustomHandlerT :
    172     public ExceptionBarrierT<typename RegistrarTraits> {
    173  public:
    174   // Signature of the handler function which gets notified when
    175   // an exception propagates through a barrier.
    176   typedef void (CALLBACK* CustomExceptionHandler)(EXCEPTION_POINTERS* ptrs);
    177 
    178   // Used to set a global custom handler used by all
    179   // ExceptionBarrierCustomHandler instances.
    180   static void set_custom_handler(CustomExceptionHandler handler) {
    181     s_custom_handler_ = handler;
    182   }
    183   static CustomExceptionHandler custom_handler() { return s_custom_handler_; }
    184 
    185  private:
    186   static CustomExceptionHandler s_custom_handler_;
    187 };
    188 
    189 // Convenience typedefs for the ExceptionBarrierT specializations.
    190 typedef ExceptionBarrierT<EBReportAllTraits> ExceptionBarrier;
    191 typedef ExceptionBarrierT<EBReportOnlyThisModuleTraits>
    192     ExceptionBarrierReportOnlyModule;
    193 typedef ExceptionBarrierCustomHandlerT<EBCustomHandlerTraits>
    194     ExceptionBarrierCustomHandler;
    195 
    196 #endif  // CHROME_FRAME_EXCEPTION_BARRIER_H_
    197