diff options
Diffstat (limited to 'src/client/windows/handler/exception_handler.h')
-rw-r--r-- | src/client/windows/handler/exception_handler.h | 118 |
1 files changed, 93 insertions, 25 deletions
diff --git a/src/client/windows/handler/exception_handler.h b/src/client/windows/handler/exception_handler.h index b24a37b7..f5ca31b9 100644 --- a/src/client/windows/handler/exception_handler.h +++ b/src/client/windows/handler/exception_handler.h @@ -67,27 +67,57 @@ #pragma warning( disable : 4530 ) #include <string> +#include <vector> namespace google_airbag { +using std::vector; using std::wstring; class ExceptionHandler { public: + // A callback function to run before Airbag performs any substantial + // processing of an exception. A FilterCallback is called before writing + // a minidump. context is the parameter supplied by the user as + // callback_context when the handler was created. + // + // If a FilterCallback returns true, Airbag will continue processing, + // attempting to write a minidump. If a FilterCallback returns false, Airbag + // will immediately report the exception as unhandled without writing a + // minidump, allowing another handler the opportunity to handle it. + typedef bool (*FilterCallback)(void *context); + // A callback function to run after the minidump has been written. // minidump_id is a unique id for the dump, so the minidump - // file is <dump_path>\<minidump_id>.dmp. succeeded indicates whether - // a minidump file was successfully written. - typedef void (*MinidumpCallback)(const wstring &minidump_id, - void *context, bool succeeded); + // file is <dump_path>\<minidump_id>.dmp. context is the parameter supplied + // by the user as callback_context when the handler was created. succeeded + // indicates whether a minidump file was successfully written. + // + // If an exception occurred and the callback returns true, Airbag will treat + // the exception as fully-handled, suppressing any other handlers from being + // notified of the exception. If the callback returns false, Airbag will + // treat the exception as unhandled, and allow another handler to handle it. + // If there are no other handlers, Airbag will report the exception to the + // system as unhandled, allowing a debugger or native crash dialog the + // opportunity to handle the exception. Most callback implementations + // should normally return the value of |succeeded|, or when they wish to + // not report an exception of handled, false. Callbacks will rarely want to + // return true directly (unless |succeeded| is true). + typedef bool (*MinidumpCallback)(const wchar_t *dump_path, + const wchar_t *minidump_id, + void *context, + bool succeeded); // Creates a new ExceptionHandler instance to handle writing minidumps. + // Before writing a minidump, the optional filter callback will be called. + // Its return value determines whether or not Airbag should write a minidump. // Minidump files will be written to dump_path, and the optional callback // is called after writing the dump file, as described above. // If install_handler is true, then a minidump will be written whenever // an unhandled exception occurs. If it is false, minidumps will only // be written when WriteMinidump is called. - ExceptionHandler(const wstring &dump_path, MinidumpCallback callback, + ExceptionHandler(const wstring &dump_path, + FilterCallback filter, MinidumpCallback callback, void *callback_context, bool install_handler); ~ExceptionHandler(); @@ -95,6 +125,7 @@ class ExceptionHandler { wstring dump_path() const { return dump_path_; } void set_dump_path(const wstring &dump_path) { dump_path_ = dump_path; + dump_path_c_ = dump_path_.c_str(); UpdateNextID(); // Necessary to put dump_path_ in next_minidump_path_. } @@ -147,56 +178,93 @@ class ExceptionHandler { // path of the next minidump to be written in next_minidump_path_. void UpdateNextID(); + FilterCallback filter_; MinidumpCallback callback_; void *callback_context_; + // The directory in which a minidump will be written, set by the dump_path + // argument to the constructor, or set_dump_path. wstring dump_path_; + + // The basename of the next minidump to be written, without the extension. wstring next_minidump_id_; + + // The full pathname of the next minidump to be written, including the file + // extension. wstring next_minidump_path_; + // Pointers to C-string representations of the above. These are set when + // the above wstring versions are set in order to avoid calling c_str during + // an exception, as c_str may attempt to allocate heap memory. These + // pointers are not owned by the ExceptionHandler object, but their lifetimes + // should be equivalent to the lifetimes of the associated wstring, provided + // that the wstrings are not altered. + const wchar_t *dump_path_c_; + const wchar_t *next_minidump_id_c_; + const wchar_t *next_minidump_path_c_; + HMODULE dbghelp_module_; MiniDumpWriteDump_type minidump_write_dump_; - ExceptionHandler *previous_handler_; // current_handler_ before us + // True if the ExceptionHandler installed an unhandled exception filter
+ // when created (with an install_handler parameter set to true).
+ bool installed_handler_;
+
+ // When installed_handler_ is true, previous_filter_ is the unhandled
+ // exception filter that was set prior to installing ExceptionHandler as
+ // the unhandled exception filter and pointing it to |this|. NULL indicates
+ // that there is no previous unhandled exception filter.
LPTOP_LEVEL_EXCEPTION_FILTER previous_filter_; - - // the currently-installed ExceptionHandler, of which there can be only 1 - static ExceptionHandler *current_handler_; - - // The exception handler thread, if one has been created. - static HANDLE handler_thread_; +
+ // The exception handler thread. + HANDLE handler_thread_; // The critical section enforcing the requirement that only one exception be - // handled at a time. - static CRITICAL_SECTION handler_critical_section_; + // handled by a handler at a time. + CRITICAL_SECTION handler_critical_section_; // Semaphores used to move exception handling between the exception thread // and the handler thread. handler_start_semaphore_ is signalled by the // exception thread to wake up the handler thread when an exception occurs. // handler_finish_semaphore_ is signalled by the handler thread to wake up // the exception thread when handling is complete. - static HANDLE handler_start_semaphore_; - static HANDLE handler_finish_semaphore_; + HANDLE handler_start_semaphore_; + HANDLE handler_finish_semaphore_; - // The next 3 fields are static data passed from the requesting thread to + // The next 2 fields contain data passed from the requesting thread to // the handler thread. - // The ExceptionHandler through which a request to write a dump was routed. - // This will be the same as current_handler_ for exceptions, but - // user-requested dumps may be routed through any live ExceptionHandler. - static ExceptionHandler *requesting_handler_; - // The thread ID of the thread requesting the dump (either the exception // thread or any other thread that called WriteMinidump directly). - static DWORD requesting_thread_id_; + DWORD requesting_thread_id_; // The exception info passed to the exception handler on the exception // thread, if an exception occurred. NULL for user-requested dumps. - static EXCEPTION_POINTERS *exception_info_; + EXCEPTION_POINTERS *exception_info_; // The return value of the handler, passed from the handler thread back to // the requesting thread. - static bool handler_return_value_; + bool handler_return_value_; + + // A stack of ExceptionHandler objects that have installed unhandled
+ // exception filters. This vector is used by HandleException to determine
+ // which ExceptionHandler object to route an exception to. When an
+ // ExceptionHandler is created with install_handler true, it will append
+ // itself to this list.
+ static vector<ExceptionHandler *> *handler_stack_;
+
+ // The index of the ExceptionHandler in handler_stack_ that will handle the
+ // next exception. Note that 0 means the last entry in handler_stack_, 1
+ // means the next-to-last entry, and so on. This is used by HandleException
+ // to support multiple stacked Airbag handlers.
+ static LONG handler_stack_index_;
+
+ // handler_stack_critical_section_ guards operations on handler_stack_ and
+ // handler_stack_index_.
+ static CRITICAL_SECTION handler_stack_critical_section_; + + // True when handler_stack_critical_section_ has been initialized. + static bool handler_stack_critical_section_initialized_; // disallow copy ctor and operator= explicit ExceptionHandler(const ExceptionHandler &); |