Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | // Copyright (c) 2006, Google Inc. |
michael@0 | 2 | // All rights reserved. |
michael@0 | 3 | // |
michael@0 | 4 | // Redistribution and use in source and binary forms, with or without |
michael@0 | 5 | // modification, are permitted provided that the following conditions are |
michael@0 | 6 | // met: |
michael@0 | 7 | // |
michael@0 | 8 | // * Redistributions of source code must retain the above copyright |
michael@0 | 9 | // notice, this list of conditions and the following disclaimer. |
michael@0 | 10 | // * Redistributions in binary form must reproduce the above |
michael@0 | 11 | // copyright notice, this list of conditions and the following disclaimer |
michael@0 | 12 | // in the documentation and/or other materials provided with the |
michael@0 | 13 | // distribution. |
michael@0 | 14 | // * Neither the name of Google Inc. nor the names of its |
michael@0 | 15 | // contributors may be used to endorse or promote products derived from |
michael@0 | 16 | // this software without specific prior written permission. |
michael@0 | 17 | // |
michael@0 | 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
michael@0 | 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
michael@0 | 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
michael@0 | 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
michael@0 | 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
michael@0 | 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
michael@0 | 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
michael@0 | 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
michael@0 | 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
michael@0 | 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
michael@0 | 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
michael@0 | 29 | |
michael@0 | 30 | // exception_handler.h: MacOS exception handler |
michael@0 | 31 | // This class can install a Mach exception port handler to trap most common |
michael@0 | 32 | // programming errors. If an exception occurs, a minidump file will be |
michael@0 | 33 | // generated which contains detailed information about the process and the |
michael@0 | 34 | // exception. |
michael@0 | 35 | |
michael@0 | 36 | #ifndef CLIENT_MAC_HANDLER_EXCEPTION_HANDLER_H__ |
michael@0 | 37 | #define CLIENT_MAC_HANDLER_EXCEPTION_HANDLER_H__ |
michael@0 | 38 | |
michael@0 | 39 | #include <mach/mach.h> |
michael@0 | 40 | #include <TargetConditionals.h> |
michael@0 | 41 | |
michael@0 | 42 | #include <string> |
michael@0 | 43 | |
michael@0 | 44 | #include "common/scoped_ptr.h" |
michael@0 | 45 | |
michael@0 | 46 | #if !TARGET_OS_IPHONE |
michael@0 | 47 | #include "client/mac/crash_generation/crash_generation_client.h" |
michael@0 | 48 | #endif |
michael@0 | 49 | |
michael@0 | 50 | namespace google_breakpad { |
michael@0 | 51 | |
michael@0 | 52 | using std::string; |
michael@0 | 53 | |
michael@0 | 54 | struct ExceptionParameters; |
michael@0 | 55 | |
michael@0 | 56 | enum HandlerThreadMessage { |
michael@0 | 57 | // Message ID telling the handler thread to write a dump. |
michael@0 | 58 | kWriteDumpMessage = 0, |
michael@0 | 59 | // Message ID telling the handler thread to write a dump and include |
michael@0 | 60 | // an exception stream. |
michael@0 | 61 | kWriteDumpWithExceptionMessage = 1, |
michael@0 | 62 | // Message ID telling the handler thread to quit. |
michael@0 | 63 | kShutdownMessage = 2 |
michael@0 | 64 | }; |
michael@0 | 65 | |
michael@0 | 66 | class ExceptionHandler { |
michael@0 | 67 | public: |
michael@0 | 68 | // A callback function to run before Breakpad performs any substantial |
michael@0 | 69 | // processing of an exception. A FilterCallback is called before writing |
michael@0 | 70 | // a minidump. context is the parameter supplied by the user as |
michael@0 | 71 | // callback_context when the handler was created. |
michael@0 | 72 | // |
michael@0 | 73 | // If a FilterCallback returns true, Breakpad will continue processing, |
michael@0 | 74 | // attempting to write a minidump. If a FilterCallback returns false, Breakpad |
michael@0 | 75 | // will immediately report the exception as unhandled without writing a |
michael@0 | 76 | // minidump, allowing another handler the opportunity to handle it. |
michael@0 | 77 | typedef bool (*FilterCallback)(void *context); |
michael@0 | 78 | |
michael@0 | 79 | // A callback function to run after the minidump has been written. |
michael@0 | 80 | // |minidump_id| is a unique id for the dump, so the minidump |
michael@0 | 81 | // file is <dump_dir>/<minidump_id>.dmp. |
michael@0 | 82 | // |context| is the value passed into the constructor. |
michael@0 | 83 | // |succeeded| indicates whether a minidump file was successfully written. |
michael@0 | 84 | // Return true if the exception was fully handled and breakpad should exit. |
michael@0 | 85 | // Return false to allow any other exception handlers to process the |
michael@0 | 86 | // exception. |
michael@0 | 87 | typedef bool (*MinidumpCallback)(const char *dump_dir, |
michael@0 | 88 | const char *minidump_id, |
michael@0 | 89 | void *context, bool succeeded); |
michael@0 | 90 | |
michael@0 | 91 | // A callback function which will be called directly if an exception occurs. |
michael@0 | 92 | // This bypasses the minidump file writing and simply gives the client |
michael@0 | 93 | // the exception information. |
michael@0 | 94 | typedef bool (*DirectCallback)( void *context, |
michael@0 | 95 | int exception_type, |
michael@0 | 96 | int exception_code, |
michael@0 | 97 | int exception_subcode, |
michael@0 | 98 | mach_port_t thread_name); |
michael@0 | 99 | |
michael@0 | 100 | // Creates a new ExceptionHandler instance to handle writing minidumps. |
michael@0 | 101 | // Minidump files will be written to dump_path, and the optional callback |
michael@0 | 102 | // is called after writing the dump file, as described above. |
michael@0 | 103 | // If install_handler is true, then a minidump will be written whenever |
michael@0 | 104 | // an unhandled exception occurs. If it is false, minidumps will only |
michael@0 | 105 | // be written when WriteMinidump is called. |
michael@0 | 106 | // If port_name is non-NULL, attempt to perform out-of-process dump generation |
michael@0 | 107 | // If port_name is NULL, in-process dump generation will be used. |
michael@0 | 108 | ExceptionHandler(const string &dump_path, |
michael@0 | 109 | FilterCallback filter, MinidumpCallback callback, |
michael@0 | 110 | void *callback_context, bool install_handler, |
michael@0 | 111 | const char *port_name); |
michael@0 | 112 | |
michael@0 | 113 | // A special constructor if we want to bypass minidump writing and |
michael@0 | 114 | // simply get a callback with the exception information. |
michael@0 | 115 | ExceptionHandler(DirectCallback callback, |
michael@0 | 116 | void *callback_context, |
michael@0 | 117 | bool install_handler); |
michael@0 | 118 | |
michael@0 | 119 | ~ExceptionHandler(); |
michael@0 | 120 | |
michael@0 | 121 | // Get and set the minidump path. |
michael@0 | 122 | string dump_path() const { return dump_path_; } |
michael@0 | 123 | void set_dump_path(const string &dump_path) { |
michael@0 | 124 | dump_path_ = dump_path; |
michael@0 | 125 | dump_path_c_ = dump_path_.c_str(); |
michael@0 | 126 | UpdateNextID(); // Necessary to put dump_path_ in next_minidump_path_. |
michael@0 | 127 | } |
michael@0 | 128 | |
michael@0 | 129 | // Writes a minidump immediately. This can be used to capture the |
michael@0 | 130 | // execution state independently of a crash. Returns true on success. |
michael@0 | 131 | bool WriteMinidump() { |
michael@0 | 132 | return WriteMinidump(false); |
michael@0 | 133 | } |
michael@0 | 134 | |
michael@0 | 135 | bool WriteMinidump(bool write_exception_stream); |
michael@0 | 136 | |
michael@0 | 137 | // Convenience form of WriteMinidump which does not require an |
michael@0 | 138 | // ExceptionHandler instance. |
michael@0 | 139 | static bool WriteMinidump(const string &dump_path, MinidumpCallback callback, |
michael@0 | 140 | void *callback_context) { |
michael@0 | 141 | return WriteMinidump(dump_path, false, callback, callback_context); |
michael@0 | 142 | } |
michael@0 | 143 | |
michael@0 | 144 | static bool WriteMinidump(const string &dump_path, |
michael@0 | 145 | bool write_exception_stream, |
michael@0 | 146 | MinidumpCallback callback, |
michael@0 | 147 | void *callback_context); |
michael@0 | 148 | |
michael@0 | 149 | // Write a minidump of child immediately. This can be used to capture |
michael@0 | 150 | // the execution state of a child process independently of a crash. |
michael@0 | 151 | static bool WriteMinidumpForChild(mach_port_t child, |
michael@0 | 152 | mach_port_t child_blamed_thread, |
michael@0 | 153 | const std::string &dump_path, |
michael@0 | 154 | MinidumpCallback callback, |
michael@0 | 155 | void *callback_context); |
michael@0 | 156 | |
michael@0 | 157 | // Returns whether out-of-process dump generation is used or not. |
michael@0 | 158 | bool IsOutOfProcess() const { |
michael@0 | 159 | #if TARGET_OS_IPHONE |
michael@0 | 160 | return false; |
michael@0 | 161 | #else |
michael@0 | 162 | return crash_generation_client_.get() != NULL; |
michael@0 | 163 | #endif |
michael@0 | 164 | } |
michael@0 | 165 | |
michael@0 | 166 | private: |
michael@0 | 167 | // Install the mach exception handler |
michael@0 | 168 | bool InstallHandler(); |
michael@0 | 169 | |
michael@0 | 170 | // Uninstall the mach exception handler (if any) |
michael@0 | 171 | bool UninstallHandler(bool in_exception); |
michael@0 | 172 | |
michael@0 | 173 | // Setup the handler thread, and if |install_handler| is true, install the |
michael@0 | 174 | // mach exception port handler |
michael@0 | 175 | bool Setup(bool install_handler); |
michael@0 | 176 | |
michael@0 | 177 | // Uninstall the mach exception handler (if any) and terminate the helper |
michael@0 | 178 | // thread |
michael@0 | 179 | bool Teardown(); |
michael@0 | 180 | |
michael@0 | 181 | // Send a mach message to the exception handler. Return true on |
michael@0 | 182 | // success, false otherwise. |
michael@0 | 183 | bool SendMessageToHandlerThread(HandlerThreadMessage message_id); |
michael@0 | 184 | |
michael@0 | 185 | // All minidump writing goes through this one routine. |
michael@0 | 186 | // |task_context| can be NULL. If not, it will be used to retrieve the |
michael@0 | 187 | // context of the current thread, instead of using |thread_get_state|. |
michael@0 | 188 | bool WriteMinidumpWithException(int exception_type, |
michael@0 | 189 | int exception_code, |
michael@0 | 190 | int exception_subcode, |
michael@0 | 191 | ucontext_t *task_context, |
michael@0 | 192 | mach_port_t thread_name, |
michael@0 | 193 | bool exit_after_write, |
michael@0 | 194 | bool report_current_thread); |
michael@0 | 195 | |
michael@0 | 196 | // When installed, this static function will be call from a newly created |
michael@0 | 197 | // pthread with |this| as the argument |
michael@0 | 198 | static void *WaitForMessage(void *exception_handler_class); |
michael@0 | 199 | |
michael@0 | 200 | // Signal handler for SIGABRT. |
michael@0 | 201 | static void SignalHandler(int sig, siginfo_t* info, void* uc); |
michael@0 | 202 | |
michael@0 | 203 | // disallow copy ctor and operator= |
michael@0 | 204 | explicit ExceptionHandler(const ExceptionHandler &); |
michael@0 | 205 | void operator=(const ExceptionHandler &); |
michael@0 | 206 | |
michael@0 | 207 | // Generates a new ID and stores it in next_minidump_id_, and stores the |
michael@0 | 208 | // path of the next minidump to be written in next_minidump_path_. |
michael@0 | 209 | void UpdateNextID(); |
michael@0 | 210 | |
michael@0 | 211 | // These functions will suspend/resume all threads except for the |
michael@0 | 212 | // reporting thread |
michael@0 | 213 | bool SuspendThreads(); |
michael@0 | 214 | bool ResumeThreads(); |
michael@0 | 215 | |
michael@0 | 216 | // The destination directory for the minidump |
michael@0 | 217 | string dump_path_; |
michael@0 | 218 | |
michael@0 | 219 | // The basename of the next minidump w/o extension |
michael@0 | 220 | string next_minidump_id_; |
michael@0 | 221 | |
michael@0 | 222 | // The full path to the next minidump to be written, including extension |
michael@0 | 223 | string next_minidump_path_; |
michael@0 | 224 | |
michael@0 | 225 | // Pointers to the UTF-8 versions of above |
michael@0 | 226 | const char *dump_path_c_; |
michael@0 | 227 | const char *next_minidump_id_c_; |
michael@0 | 228 | const char *next_minidump_path_c_; |
michael@0 | 229 | |
michael@0 | 230 | // The callback function and pointer to be passed back after the minidump |
michael@0 | 231 | // has been written |
michael@0 | 232 | FilterCallback filter_; |
michael@0 | 233 | MinidumpCallback callback_; |
michael@0 | 234 | void *callback_context_; |
michael@0 | 235 | |
michael@0 | 236 | // The callback function to be passed back when we don't want a minidump |
michael@0 | 237 | // file to be written |
michael@0 | 238 | DirectCallback directCallback_; |
michael@0 | 239 | |
michael@0 | 240 | // The thread that is created for the handler |
michael@0 | 241 | pthread_t handler_thread_; |
michael@0 | 242 | |
michael@0 | 243 | // The port that is waiting on an exception message to be sent, if the |
michael@0 | 244 | // handler is installed |
michael@0 | 245 | mach_port_t handler_port_; |
michael@0 | 246 | |
michael@0 | 247 | // These variables save the previous exception handler's data so that it |
michael@0 | 248 | // can be re-installed when this handler is uninstalled |
michael@0 | 249 | ExceptionParameters *previous_; |
michael@0 | 250 | |
michael@0 | 251 | // True, if we've installed the exception handler |
michael@0 | 252 | bool installed_exception_handler_; |
michael@0 | 253 | |
michael@0 | 254 | // True, if we're in the process of uninstalling the exception handler and |
michael@0 | 255 | // the thread. |
michael@0 | 256 | bool is_in_teardown_; |
michael@0 | 257 | |
michael@0 | 258 | // Save the last result of the last minidump |
michael@0 | 259 | bool last_minidump_write_result_; |
michael@0 | 260 | |
michael@0 | 261 | // A mutex for use when writing out a minidump that was requested on a |
michael@0 | 262 | // thread other than the exception handler. |
michael@0 | 263 | pthread_mutex_t minidump_write_mutex_; |
michael@0 | 264 | |
michael@0 | 265 | // True, if we're using the mutext to indicate when mindump writing occurs |
michael@0 | 266 | bool use_minidump_write_mutex_; |
michael@0 | 267 | |
michael@0 | 268 | // Old signal handler for SIGABRT. Used to be able to restore it when |
michael@0 | 269 | // uninstalling. |
michael@0 | 270 | scoped_ptr<struct sigaction> old_handler_; |
michael@0 | 271 | |
michael@0 | 272 | #if !TARGET_OS_IPHONE |
michael@0 | 273 | // Client for out-of-process dump generation. |
michael@0 | 274 | scoped_ptr<CrashGenerationClient> crash_generation_client_; |
michael@0 | 275 | #endif |
michael@0 | 276 | }; |
michael@0 | 277 | |
michael@0 | 278 | } // namespace google_breakpad |
michael@0 | 279 | |
michael@0 | 280 | #endif // CLIENT_MAC_HANDLER_EXCEPTION_HANDLER_H__ |