| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef CHROME_FRAME_CRASH_REPORTING_VECTORED_HANDLER_H_ | 5 #ifndef CHROME_FRAME_CRASH_REPORTING_VECTORED_HANDLER_H_ |
| 6 #define CHROME_FRAME_CRASH_REPORTING_VECTORED_HANDLER_H_ | 6 #define CHROME_FRAME_CRASH_REPORTING_VECTORED_HANDLER_H_ |
| 7 | 7 |
| 8 // Base class for VectoredHandlerT just to hold some members (independent of | |
| 9 // template parameter) | |
| 10 class VectoredHandlerBase { | |
| 11 public: | |
| 12 // For RtlCaptureStackBackTrace MSDN says: | |
| 13 // Windows Server 2003 and Windows XP: The sum of the FramesToSkip and | |
| 14 // FramesToCapture parameters must be less than 64. | |
| 15 // In practice (on XPSP2) it has to be less than 63, hence leaving us with | |
| 16 // max back trace of 62. | |
| 17 static const DWORD max_back_trace = 62; | |
| 18 static unsigned long g_exceptions_seen; | |
| 19 protected: | |
| 20 static void* g_handler; | |
| 21 }; | |
| 22 | 8 |
| 23 DECLSPEC_SELECTANY void* VectoredHandlerBase::g_handler; | 9 #if !defined(_M_IX86) |
| 24 DECLSPEC_SELECTANY unsigned long VectoredHandlerBase::g_exceptions_seen; | 10 #error only x86 is supported for now. |
| 11 #endif |
| 25 | 12 |
| 26 // The E class is supposed to provide external/API functions. Using template | |
| 27 // make testability easier. It shall confirm the following concept/archetype: | |
| 28 // void* Register(PVECTORED_EXCEPTION_HANDLER, | |
| 29 // const void* module_start, const void* module_end) | |
| 30 // Registers Vectored Exception Handler, non-unittest implementation shall call | |
| 31 // ::AddVectoredExceptionHandler Win32 API | |
| 32 // ULONG Unregister(void*) - ::RemoveVectoredExceptionHandler Win32 API | |
| 33 // int IsOurModule(const void* address) - | |
| 34 // void WriteDump(EXCEPTION_POINTERS*) - | |
| 35 // WORD RtlCaptureStackBackTrace(..) - same as Win32 API | |
| 36 // EXCEPTION_REGISTRATION_RECORD* RtlpGetExceptionList() - same as Win32 API | |
| 37 // You may want to derive own External class by deriving from | |
| 38 // VEHExternalBase helper (see below). | |
| 39 // Create dump policy: | 13 // Create dump policy: |
| 40 // 1. Scan SEH chain, if there is a handler/filter that belongs to our | 14 // 1. Scan SEH chain, if there is a handler/filter that belongs to our |
| 41 // module - assume we expect this one and hence do nothing here. | 15 // module - assume we expect this one and hence do nothing here. |
| 42 // 2. If the address of the exception is in our module - create dump. | 16 // 2. If the address of the exception is in our module - create dump. |
| 43 // 3. If our module is in somewhere in callstack - create dump. | 17 // 3. If our module is in somewhere in callstack - create dump. |
| 44 template <class E> | 18 // The E class is supposed to provide external/API functions. Using template |
| 45 class VectoredHandlerT : public VectoredHandlerBase { | 19 // make testability easier. It shall confirm the following concept/archetype: |
| 20 //struct E { |
| 21 // void WriteDump(EXCEPTION_POINTERS* p) { |
| 22 // } |
| 23 // |
| 24 // // Used mainly to ignore exceptions from IsBadRead/Write/Ptr. |
| 25 // int ShouldIgnoreException(const EXCEPTION_POINTERS* exptr) { |
| 26 // return 0; |
| 27 // } |
| 28 // |
| 29 // // Retrieve the SEH list head. |
| 30 // EXCEPTION_REGISTRATION_RECORD* RtlpGetExceptionList() { |
| 31 // return NULL; |
| 32 // } |
| 33 // |
| 34 // // Get the stack trace as correctly as possible. |
| 35 // WORD RtlCaptureStackBackTrace(DWORD FramesToSkip, DWORD FramesToCapture, |
| 36 // void** BackTrace, DWORD* BackTraceHash) { |
| 37 // return 0; |
| 38 // } |
| 39 // |
| 40 // // Check whether the stack guard page is in place. |
| 41 // int StackOverflow(EXCEPTION_POINTERS* p) { |
| 42 // return 0; |
| 43 // } |
| 44 // |
| 45 // int IsOurModule(const void* address) { |
| 46 // return 0; |
| 47 // } |
| 48 //}; |
| 49 // The methods shall be placed in .text$veh_m |
| 50 template <typename E> |
| 51 class VectoredHandlerT { |
| 46 public: | 52 public: |
| 47 static void* Register(const void* module_start, const void* module_end) { | 53 VectoredHandlerT(E* api); |
| 48 g_exceptions_seen = 0; | 54 ~VectoredHandlerT(); |
| 49 g_handler = E::Register(&VectoredHandler, module_start, module_end); | 55 |
| 50 return g_handler; | 56 // TODO(stoyan): Come with better way to skip initial stack frames. |
| 57 FORCEINLINE LONG Handler(EXCEPTION_POINTERS* exceptionInfo); |
| 58 long get_exceptions_seen() const { |
| 59 return exceptions_seen_; |
| 51 } | 60 } |
| 52 | 61 |
| 53 static ULONG Unregister() { | 62 private: |
| 54 if (g_handler) | 63 BOOL ModuleHasInstalledSEHFilter(); |
| 55 return E::Unregister(g_handler); | 64 E* api_; |
| 56 return 0; | 65 long exceptions_seen_; |
| 66 }; |
| 67 |
| 68 // Maintains start and end address of a single module of interest. If we want |
| 69 // do check for multiple modules, this class has to be extended to support a |
| 70 // list of modules (DLLs). |
| 71 struct ModuleOfInterest { |
| 72 // The callback from VectoredHandlerT::Handler(). |
| 73 inline int IsOurModule(const void* address) { |
| 74 return (start_ <= address && address < end_); |
| 57 } | 75 } |
| 58 | 76 |
| 59 static LONG WINAPI VectoredHandler(EXCEPTION_POINTERS* exceptionInfo); | 77 // Helpers. |
| 60 private: | 78 inline void SetModule(const void* module_start, const void* module_end) { |
| 61 static BOOL ModuleHasInstalledSEHFilter(); | 79 start_ = module_start; |
| 80 end_ = module_end; |
| 81 } |
| 82 |
| 83 inline void SetCurrentModule() { |
| 84 // Find current module boundaries. |
| 85 const void* start = &__ImageBase; |
| 86 const char* s = reinterpret_cast<const char*>(start); |
| 87 const IMAGE_NT_HEADERS32* nt = reinterpret_cast<const IMAGE_NT_HEADERS32*> |
| 88 (s + __ImageBase.e_lfanew); |
| 89 const void* end = s + nt->OptionalHeader.SizeOfImage; |
| 90 SetModule(start, end); |
| 91 } |
| 92 |
| 93 const void* start_; |
| 94 const void* end_; |
| 62 }; | 95 }; |
| 63 | 96 |
| 64 // Handy class supposed to act as a base class for classes used as template | 97 struct ModuleOfInterestWithExcludedRegion : public ModuleOfInterest { |
| 65 // parameter of VectoredHandlerT<E> | 98 inline int IsOurModule(const void* address) { |
| 66 class VEHTraitsBase { | 99 return (start_ <= address && address < end_) && |
| 67 public: | 100 (address < special_region_start_ || special_region_end_ <= address); |
| 68 static const void* g_module_start; | |
| 69 static const void* g_module_end; | |
| 70 | |
| 71 static inline int IsOurModule(const void* address) { | |
| 72 return (g_module_start <= address && address < g_module_end); | |
| 73 } | 101 } |
| 74 | 102 |
| 75 static inline void SetModule(const void* module_start, | 103 inline void SetExcludedRegion(const void* start, const void* end) { |
| 76 const void* module_end) { | 104 special_region_start_ = start; |
| 77 g_module_start = module_start; | 105 special_region_end_ = end; |
| 78 g_module_end = module_end; | |
| 79 } | 106 } |
| 80 | 107 |
| 81 static bool ShouldIgnoreException(const EXCEPTION_POINTERS* exceptionInfo) { | 108 const void* special_region_start_; |
| 82 return false; | 109 const void* special_region_end_; |
| 83 } | |
| 84 }; | 110 }; |
| 85 | 111 |
| 86 DECLSPEC_SELECTANY const void* VEHTraitsBase::g_module_start; | |
| 87 DECLSPEC_SELECTANY const void* VEHTraitsBase::g_module_end; | |
| 88 | 112 |
| 89 class Win32VEHTraits; | |
| 90 typedef class VectoredHandlerT<Win32VEHTraits> VectoredHandler; | |
| 91 #endif // CHROME_FRAME_CRASH_REPORTING_VECTORED_HANDLER_H_ | 113 #endif // CHROME_FRAME_CRASH_REPORTING_VECTORED_HANDLER_H_ |
| OLD | NEW |