OLD | NEW |
| (Empty) |
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(®istration_); | |
155 } | |
156 | |
157 // Unregister on destruction | |
158 virtual ~ExceptionBarrierT() { | |
159 RegistrarTraits::UnregisterException(®istration_); | |
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_ | |
OLD | NEW |