blob: b24a37b75ba6392a2171ef9694c72e8f2915c73a [file] [log] [blame]
bryner1217c1f2006-09-27 01:00:32 +00001// Copyright (c) 2006, Google Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8// * Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above
11// copyright notice, this list of conditions and the following disclaimer
12// in the documentation and/or other materials provided with the
13// distribution.
14// * Neither the name of Google Inc. nor the names of its
15// contributors may be used to endorse or promote products derived from
16// this software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30// ExceptionHandler can write a minidump file when an exception occurs,
31// or when WriteMinidump() is called explicitly by your program.
32//
33// To have the exception handler write minidumps when an uncaught exception
34// (crash) occurs, you should create an instance early in the execution
35// of your program, and keep it around for the entire time you want to
36// have crash handling active (typically, until shutdown).
37//
38// If you want to write minidumps without installing the exception handler,
39// you can create an ExceptionHandler with install_handler set to false,
40// then call WriteMinidump. You can also use this technique if you want to
41// use different minidump callbacks for different call sites.
42//
43// In either case, a callback function is called when a minidump is written,
44// which receives the unqiue id of the minidump. The caller can use this
45// id to collect and write additional application state, and to launch an
46// external crash-reporting application.
47//
48// It is important that creation and destruction of ExceptionHandler objects
49// be nested cleanly, when using install_handler = true.
50// Avoid the following pattern:
51// ExceptionHandler *e = new ExceptionHandler(...);
52// ExceptionHandler *f = new ExceptionHandler(...);
53// delete e;
54// This will put the exception filter stack into an inconsistent state.
brynerf1400252006-09-28 19:35:08 +000055//
56// To use this library in your project, you will need to link against
mmentovai29401d22006-10-26 18:06:43 +000057// ole32.lib.
bryner1217c1f2006-09-27 01:00:32 +000058
59#ifndef CLIENT_WINDOWS_HANDLER_EXCEPTION_HANDLER_H__
60#define CLIENT_WINDOWS_HANDLER_EXCEPTION_HANDLER_H__
61
mmentovai29401d22006-10-26 18:06:43 +000062#include <Windows.h>
63#include <DbgHelp.h>
bryner1217c1f2006-09-27 01:00:32 +000064
mmentovai12a52452006-10-27 19:47:21 +000065#pragma warning( push )
66// Disable exception handler warnings.
67#pragma warning( disable : 4530 )
68
bryner1217c1f2006-09-27 01:00:32 +000069#include <string>
70
71namespace google_airbag {
72
73using std::wstring;
74
75class ExceptionHandler {
76 public:
77 // A callback function to run after the minidump has been written.
78 // minidump_id is a unique id for the dump, so the minidump
79 // file is <dump_path>\<minidump_id>.dmp. succeeded indicates whether
80 // a minidump file was successfully written.
81 typedef void (*MinidumpCallback)(const wstring &minidump_id,
82 void *context, bool succeeded);
83
84 // Creates a new ExceptionHandler instance to handle writing minidumps.
85 // Minidump files will be written to dump_path, and the optional callback
86 // is called after writing the dump file, as described above.
87 // If install_handler is true, then a minidump will be written whenever
88 // an unhandled exception occurs. If it is false, minidumps will only
89 // be written when WriteMinidump is called.
90 ExceptionHandler(const wstring &dump_path, MinidumpCallback callback,
91 void *callback_context, bool install_handler);
92 ~ExceptionHandler();
93
mmentovai1bff57e2006-10-27 16:10:55 +000094 // Get and set the minidump path.
95 wstring dump_path() const { return dump_path_; }
mmentovaied61ae02006-11-28 19:47:44 +000096 void set_dump_path(const wstring &dump_path) {
97 dump_path_ = dump_path;
98 UpdateNextID(); // Necessary to put dump_path_ in next_minidump_path_.
99 }
mmentovai1bff57e2006-10-27 16:10:55 +0000100
bryner1217c1f2006-09-27 01:00:32 +0000101 // Writes a minidump immediately. This can be used to capture the
102 // execution state independently of a crash. Returns true on success.
103 bool WriteMinidump();
104
105 // Convenience form of WriteMinidump which does not require an
106 // ExceptionHandler instance.
107 static bool WriteMinidump(const wstring &dump_path,
108 MinidumpCallback callback, void *callback_context);
109
110 private:
111 // Function pointer type for MiniDumpWriteDump, which is looked up
112 // dynamically.
113 typedef BOOL (WINAPI *MiniDumpWriteDump_type)(
114 HANDLE hProcess,
115 DWORD dwPid,
116 HANDLE hFile,
117 MINIDUMP_TYPE DumpType,
118 CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
119 CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
120 CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
121
mmentovaib2610192006-10-31 16:49:38 +0000122 // Runs the main loop for the exception handler thread.
123 static DWORD WINAPI ExceptionHandlerThreadMain(void *lpParameter);
bryner1217c1f2006-09-27 01:00:32 +0000124
mmentovaib2610192006-10-31 16:49:38 +0000125 // Called on the exception thread when an unhandled exception occurs.
126 // Signals the exception handler thread to handle the exception.
bryner1217c1f2006-09-27 01:00:32 +0000127 static LONG WINAPI HandleException(EXCEPTION_POINTERS *exinfo);
128
mmentovaib2610192006-10-31 16:49:38 +0000129 // This is called on the exception thread or on another thread that
130 // the user wishes to produce a dump from. It calls
131 // WriteMinidumpWithException on the handler thread, avoiding stack
132 // overflows and inconsistent dumps due to writing the dump from
133 // the exception thread. If the dump is requested as a result of an
134 // exception, exinfo contains exception information, otherwise, it
135 // is NULL.
136 bool WriteMinidumpOnHandlerThread(EXCEPTION_POINTERS *exinfo);
137
138 // This function does the actual writing of a minidump. It is called
139 // on the handler thread. requesting_thread_id is the ID of the thread
140 // that requested the dump. If the dump is requested as a result of
141 // an exception, exinfo contains exception information, otherwise,
142 // it is NULL.
143 bool WriteMinidumpWithException(DWORD requesting_thread_id,
144 EXCEPTION_POINTERS *exinfo);
145
mmentovaied61ae02006-11-28 19:47:44 +0000146 // Generates a new ID and stores it in next_minidump_id_, and stores the
147 // path of the next minidump to be written in next_minidump_path_.
bryner1217c1f2006-09-27 01:00:32 +0000148 void UpdateNextID();
149
150 MinidumpCallback callback_;
151 void *callback_context_;
152
153 wstring dump_path_;
mmentovai29401d22006-10-26 18:06:43 +0000154 wstring next_minidump_id_;
mmentovaied61ae02006-11-28 19:47:44 +0000155 wstring next_minidump_path_;
bryner1217c1f2006-09-27 01:00:32 +0000156
157 HMODULE dbghelp_module_;
158 MiniDumpWriteDump_type minidump_write_dump_;
159
160 ExceptionHandler *previous_handler_; // current_handler_ before us
161 LPTOP_LEVEL_EXCEPTION_FILTER previous_filter_;
162
163 // the currently-installed ExceptionHandler, of which there can be only 1
164 static ExceptionHandler *current_handler_;
165
mmentovaib2610192006-10-31 16:49:38 +0000166 // The exception handler thread, if one has been created.
167 static HANDLE handler_thread_;
168
169 // The critical section enforcing the requirement that only one exception be
170 // handled at a time.
171 static CRITICAL_SECTION handler_critical_section_;
172
173 // Semaphores used to move exception handling between the exception thread
174 // and the handler thread. handler_start_semaphore_ is signalled by the
175 // exception thread to wake up the handler thread when an exception occurs.
176 // handler_finish_semaphore_ is signalled by the handler thread to wake up
177 // the exception thread when handling is complete.
178 static HANDLE handler_start_semaphore_;
179 static HANDLE handler_finish_semaphore_;
180
181 // The next 3 fields are static data passed from the requesting thread to
182 // the handler thread.
183
184 // The ExceptionHandler through which a request to write a dump was routed.
185 // This will be the same as current_handler_ for exceptions, but
186 // user-requested dumps may be routed through any live ExceptionHandler.
187 static ExceptionHandler *requesting_handler_;
188
189 // The thread ID of the thread requesting the dump (either the exception
190 // thread or any other thread that called WriteMinidump directly).
191 static DWORD requesting_thread_id_;
192
193 // The exception info passed to the exception handler on the exception
194 // thread, if an exception occurred. NULL for user-requested dumps.
195 static EXCEPTION_POINTERS *exception_info_;
196
197 // The return value of the handler, passed from the handler thread back to
198 // the requesting thread.
199 static bool handler_return_value_;
200
bryner1217c1f2006-09-27 01:00:32 +0000201 // disallow copy ctor and operator=
202 explicit ExceptionHandler(const ExceptionHandler &);
203 void operator=(const ExceptionHandler &);
204};
205
206} // namespace google_airbag
207
mmentovai12a52452006-10-27 19:47:21 +0000208#pragma warning( pop )
209
bryner1217c1f2006-09-27 01:00:32 +0000210#endif // CLIENT_WINDOWS_HANDLER_EXCEPTION_HANDLER_H__