michael@0: // Copyright (c) 2010 Google Inc. michael@0: // All rights reserved. michael@0: // michael@0: // Redistribution and use in source and binary forms, with or without michael@0: // modification, are permitted provided that the following conditions are michael@0: // met: michael@0: // michael@0: // * Redistributions of source code must retain the above copyright michael@0: // notice, this list of conditions and the following disclaimer. michael@0: // * Redistributions in binary form must reproduce the above michael@0: // copyright notice, this list of conditions and the following disclaimer michael@0: // in the documentation and/or other materials provided with the michael@0: // distribution. michael@0: // * Neither the name of Google Inc. nor the names of its michael@0: // contributors may be used to endorse or promote products derived from michael@0: // this software without specific prior written permission. michael@0: // michael@0: // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS michael@0: // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT michael@0: // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR michael@0: // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT michael@0: // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, michael@0: // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT michael@0: // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, michael@0: // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY michael@0: // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT michael@0: // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE michael@0: // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. michael@0: michael@0: #ifndef CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_ michael@0: #define CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_ michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include "client/linux/crash_generation/crash_generation_client.h" michael@0: #include "client/linux/handler/minidump_descriptor.h" michael@0: #include "client/linux/minidump_writer/minidump_writer.h" michael@0: #include "common/scoped_ptr.h" michael@0: #include "common/using_std_string.h" michael@0: #include "google_breakpad/common/minidump_format.h" michael@0: michael@0: namespace google_breakpad { michael@0: michael@0: // ExceptionHandler michael@0: // michael@0: // ExceptionHandler can write a minidump file when an exception occurs, michael@0: // or when WriteMinidump() is called explicitly by your program. michael@0: // michael@0: // To have the exception handler write minidumps when an uncaught exception michael@0: // (crash) occurs, you should create an instance early in the execution michael@0: // of your program, and keep it around for the entire time you want to michael@0: // have crash handling active (typically, until shutdown). michael@0: // (NOTE): There should be only be one this kind of exception handler michael@0: // object per process. michael@0: // michael@0: // If you want to write minidumps without installing the exception handler, michael@0: // you can create an ExceptionHandler with install_handler set to false, michael@0: // then call WriteMinidump. You can also use this technique if you want to michael@0: // use different minidump callbacks for different call sites. michael@0: // michael@0: // In either case, a callback function is called when a minidump is written, michael@0: // which receives the full path or file descriptor of the minidump. The michael@0: // caller can collect and write additional application state to that minidump, michael@0: // and launch an external crash-reporting application. michael@0: // michael@0: // Caller should try to make the callbacks as crash-friendly as possible, michael@0: // it should avoid use heap memory allocation as much as possible. michael@0: michael@0: class ExceptionHandler { michael@0: public: michael@0: // A callback function to run before Breakpad performs any substantial michael@0: // processing of an exception. A FilterCallback is called before writing michael@0: // a minidump. |context| is the parameter supplied by the user as michael@0: // callback_context when the handler was created. michael@0: // michael@0: // If a FilterCallback returns true, Breakpad will continue processing, michael@0: // attempting to write a minidump. If a FilterCallback returns false, michael@0: // Breakpad will immediately report the exception as unhandled without michael@0: // writing a minidump, allowing another handler the opportunity to handle it. michael@0: typedef bool (*FilterCallback)(void *context); michael@0: michael@0: // A callback function to run after the minidump has been written. michael@0: // |descriptor| contains the file descriptor or file path containing the michael@0: // minidump. |context| is the parameter supplied by the user as michael@0: // callback_context when the handler was created. |succeeded| indicates michael@0: // whether a minidump file was successfully written. michael@0: // michael@0: // If an exception occurred and the callback returns true, Breakpad will michael@0: // treat the exception as fully-handled, suppressing any other handlers from michael@0: // being notified of the exception. If the callback returns false, Breakpad michael@0: // will treat the exception as unhandled, and allow another handler to handle michael@0: // it. If there are no other handlers, Breakpad will report the exception to michael@0: // the system as unhandled, allowing a debugger or native crash dialog the michael@0: // opportunity to handle the exception. Most callback implementations michael@0: // should normally return the value of |succeeded|, or when they wish to michael@0: // not report an exception of handled, false. Callbacks will rarely want to michael@0: // return true directly (unless |succeeded| is true). michael@0: typedef bool (*MinidumpCallback)(const MinidumpDescriptor& descriptor, michael@0: void* context, michael@0: bool succeeded); michael@0: michael@0: // In certain cases, a user may wish to handle the generation of the minidump michael@0: // themselves. In this case, they can install a handler callback which is michael@0: // called when a crash has occurred. If this function returns true, no other michael@0: // processing of occurs and the process will shortly be crashed. If this michael@0: // returns false, the normal processing continues. michael@0: typedef bool (*HandlerCallback)(const void* crash_context, michael@0: size_t crash_context_size, michael@0: void* context); michael@0: michael@0: // Creates a new ExceptionHandler instance to handle writing minidumps. michael@0: // Before writing a minidump, the optional |filter| callback will be called. michael@0: // Its return value determines whether or not Breakpad should write a michael@0: // minidump. The minidump content will be written to the file path or file michael@0: // descriptor from |descriptor|, and the optional |callback| is called after michael@0: // writing the dump file, as described above. michael@0: // If install_handler is true, then a minidump will be written whenever michael@0: // an unhandled exception occurs. If it is false, minidumps will only michael@0: // be written when WriteMinidump is called. michael@0: // If |server_fd| is valid, the minidump is generated out-of-process. If it michael@0: // is -1, in-process generation will always be used. michael@0: ExceptionHandler(const MinidumpDescriptor& descriptor, michael@0: FilterCallback filter, michael@0: MinidumpCallback callback, michael@0: void *callback_context, michael@0: bool install_handler, michael@0: const int server_fd); michael@0: ~ExceptionHandler(); michael@0: michael@0: const MinidumpDescriptor& minidump_descriptor() const { michael@0: return minidump_descriptor_; michael@0: } michael@0: michael@0: void set_minidump_descriptor(const MinidumpDescriptor& descriptor) { michael@0: minidump_descriptor_ = descriptor; michael@0: } michael@0: michael@0: void set_crash_handler(HandlerCallback callback) { michael@0: crash_handler_ = callback; michael@0: } michael@0: michael@0: // Writes a minidump immediately. This can be used to capture the execution michael@0: // state independently of a crash. michael@0: // Returns true on success. michael@0: // If the ExceptionHandler has been created with a path, a new file is michael@0: // generated for each minidump. The file path can be retrieved in the michael@0: // MinidumpDescriptor passed to the MinidumpCallback or by accessing the michael@0: // MinidumpDescriptor directly from the ExceptionHandler (with michael@0: // minidump_descriptor()). michael@0: // If the ExceptionHandler has been created with a file descriptor, the file michael@0: // descriptor is repositioned to its beginning and the previous generated michael@0: // minidump is overwritten. michael@0: // Note that this method is not supposed to be called from a compromised michael@0: // context as it uses the heap. michael@0: bool WriteMinidump(); michael@0: michael@0: // Convenience form of WriteMinidump which does not require an michael@0: // ExceptionHandler instance. michael@0: static bool WriteMinidump(const string& dump_path, michael@0: MinidumpCallback callback, michael@0: void* callback_context); michael@0: michael@0: // Write a minidump of |child| immediately. This can be used to michael@0: // capture the execution state of |child| independently of a crash. michael@0: // Pass a meaningful |child_blamed_thread| to make that thread in michael@0: // the child process the one from which a crash signature is michael@0: // extracted. michael@0: // michael@0: // WARNING: the return of this function *must* happen before michael@0: // the code that will eventually reap |child| executes. michael@0: // Otherwise there's a pernicious race condition in which |child| michael@0: // exits, is reaped, another process created with its pid, then that michael@0: // new process dumped. michael@0: static bool WriteMinidumpForChild(pid_t child, michael@0: pid_t child_blamed_thread, michael@0: const string& dump_path, michael@0: MinidumpCallback callback, michael@0: void* callback_context); michael@0: michael@0: // This structure is passed to minidump_writer.h:WriteMinidump via an opaque michael@0: // blob. It shouldn't be needed in any user code. michael@0: struct CrashContext { michael@0: siginfo_t siginfo; michael@0: pid_t tid; // the crashing thread. michael@0: struct ucontext context; michael@0: #if !defined(__ARM_EABI__) michael@0: // #ifdef this out because FP state is not part of user ABI for Linux ARM. michael@0: struct _libc_fpstate float_state; michael@0: #endif michael@0: }; michael@0: michael@0: // Returns whether out-of-process dump generation is used or not. michael@0: bool IsOutOfProcess() const { michael@0: return crash_generation_client_.get() != NULL; michael@0: } michael@0: michael@0: // Add information about a memory mapping. This can be used if michael@0: // a custom library loader is used that maps things in a way michael@0: // that the linux dumper can't handle by reading the maps file. michael@0: void AddMappingInfo(const string& name, michael@0: const uint8_t identifier[sizeof(MDGUID)], michael@0: uintptr_t start_address, michael@0: size_t mapping_size, michael@0: size_t file_offset); michael@0: michael@0: // Register a block of memory of length bytes starting at address ptr michael@0: // to be copied to the minidump when a crash happens. michael@0: void RegisterAppMemory(void* ptr, size_t length); michael@0: michael@0: // Unregister a block of memory that was registered with RegisterAppMemory. michael@0: void UnregisterAppMemory(void* ptr); michael@0: michael@0: // Force signal handling for the specified signal. michael@0: bool SimulateSignalDelivery(int sig); michael@0: michael@0: // Report a crash signal from an SA_SIGINFO signal handler. michael@0: bool HandleSignal(int sig, siginfo_t* info, void* uc); michael@0: private: michael@0: // Save the old signal handlers and install new ones. michael@0: static bool InstallHandlersLocked(); michael@0: // Restore the old signal handlers. michael@0: static void RestoreHandlersLocked(); michael@0: michael@0: void PreresolveSymbols(); michael@0: bool GenerateDump(CrashContext *context); michael@0: void SendContinueSignalToChild(); michael@0: void WaitForContinueSignal(); michael@0: michael@0: static void SignalHandler(int sig, siginfo_t* info, void* uc); michael@0: static int ThreadEntry(void* arg); michael@0: bool DoDump(pid_t crashing_process, const void* context, michael@0: size_t context_size); michael@0: michael@0: const FilterCallback filter_; michael@0: const MinidumpCallback callback_; michael@0: void* const callback_context_; michael@0: michael@0: scoped_ptr crash_generation_client_; michael@0: michael@0: MinidumpDescriptor minidump_descriptor_; michael@0: michael@0: HandlerCallback crash_handler_; michael@0: michael@0: // The global exception handler stack. This is need becuase there may exist michael@0: // multiple ExceptionHandler instances in a process. Each will have itself michael@0: // registered in this stack. michael@0: static std::vector *handler_stack_; michael@0: static pthread_mutex_t handler_stack_mutex_; michael@0: michael@0: // We need to explicitly enable ptrace of parent processes on some michael@0: // kernels, but we need to know the PID of the cloned process before we michael@0: // can do this. We create a pipe which we can use to block the michael@0: // cloned process after creating it, until we have explicitly enabled michael@0: // ptrace. This is used to store the file descriptors for the pipe michael@0: int fdes[2]; michael@0: michael@0: // Callers can add extra info about mappings for cases where the michael@0: // dumper code cannot extract enough information from /proc//maps. michael@0: MappingList mapping_list_; michael@0: michael@0: // Callers can request additional memory regions to be included in michael@0: // the dump. michael@0: AppMemoryList app_memory_list_; michael@0: }; michael@0: michael@0: } // namespace google_breakpad michael@0: michael@0: #endif // CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_