| // Copyright 2021 The Crashpad Authors. All rights reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include <stdint.h> |
| |
| #include <map> |
| #include <string> |
| #include <vector> |
| |
| #include "base/files/file_path.h" |
| #include "handler/mac/crash_report_exception_handler.h" |
| #include "snapshot/ios/process_snapshot_ios_intermediate_dump.h" |
| #include "util/ios/ios_intermediate_dump_writer.h" |
| #include "util/ios/ios_system_data_collector.h" |
| #include "util/misc/initialization_state_dcheck.h" |
| |
| namespace crashpad { |
| namespace internal { |
| |
| //! \brief Manage intermediate minidump generation, and own the crash report |
| //! upload thread and database. |
| class InProcessHandler { |
| public: |
| InProcessHandler(); |
| ~InProcessHandler(); |
| InProcessHandler(const InProcessHandler&) = delete; |
| InProcessHandler& operator=(const InProcessHandler&) = delete; |
| |
| //! \brief Initializes the in-process handler. |
| //! |
| //! This method must be called only once, and must be successfully called |
| //! before any other method in this class may be called. |
| //! |
| //! \param[in] database The path to a Crashpad database. |
| //! \param[in] url The URL of an upload server. |
| //! \param[in] annotations Process annotations to set in each crash report. |
| //! \return `true` if a handler to a pending intermediate dump could be |
| //! opened. |
| bool Initialize(const base::FilePath& database, |
| const std::string& url, |
| const std::map<std::string, std::string>& annotations); |
| |
| //! \brief Generate an intermediate dump from a signal handler exception. |
| //! |
| //! \param[in] system_data An object containing various system data points. |
| //! \param[in] siginfo A pointer to a `siginfo_t` object received by a signal |
| //! handler. |
| //! \param[in] context A pointer to a `ucontext_t` object received by a |
| //! signal. |
| void DumpExceptionFromSignal(const IOSSystemDataCollector& system_data, |
| siginfo_t* siginfo, |
| ucontext_t* context); |
| |
| //! \brief Generate an intermediate dump from a mach exception. |
| //! |
| //! \param[in] system_data An object containing various system data points. |
| //! \param[in] behavior |
| //! \param[in] thread |
| //! \param[in] exception |
| //! \param[in] code |
| //! \param[in] code_count |
| //! \param[in,out] flavor |
| //! \param[in] old_state |
| //! \param[in] old_state_count |
| void DumpExceptionFromMachException(const IOSSystemDataCollector& system_data, |
| exception_behavior_t behavior, |
| thread_t thread, |
| exception_type_t exception, |
| const mach_exception_data_type_t* code, |
| mach_msg_type_number_t code_count, |
| thread_state_flavor_t flavor, |
| ConstThreadState old_state, |
| mach_msg_type_number_t old_state_count); |
| |
| //! \brief Generate an intermediate dump from an uncaught NSException. |
| //! |
| //! When the ObjcExceptionPreprocessor does not detect an NSException as it is |
| //! thrown, the last-chance uncaught exception handler passes a list of call |
| //! stack frame addresses. Record them in the intermediate dump so a minidump |
| //! with a 'fake' call stack is generated. |
| //! |
| //! \param[in] system_data An object containing various system data points. |
| //! \param[in] frames An array of call stack frame addresses. |
| //! \param[in] num_frames The number of frames in |frames|. |
| void DumpExceptionFromNSExceptionFrames( |
| const IOSSystemDataCollector& system_data, |
| const uint64_t* frames, |
| const size_t num_frames); |
| |
| //! \brief Requests that the handler convert all intermediate dumps into |
| //! minidumps and trigger an upload if possible. |
| //! |
| //! \param[in] annotations Process annotations to set in each crash report. |
| void ProcessIntermediateDumps( |
| const std::map<std::string, std::string>& annotations); |
| |
| //! \brief Requests that the handler convert a specific intermediate dump into |
| //! a minidump and trigger an upload if possible. |
| //! |
| //! \param[in] path Path to the specific intermediate dump. |
| //! \param[in] annotations Process annotations to set in each crash report. |
| void ProcessIntermediateDump( |
| const base::FilePath& path, |
| const std::map<std::string, std::string>& annotations = {}); |
| |
| //! \brief Requests that the handler begin in-process uploading of any |
| //! pending reports. |
| void StartProcessingPendingReports(); |
| |
| //! \brief Helper that swaps out the InProcessHandler's |writer_| with an |
| //! alternate writer so DumpWithContext does not interfere with the |
| //! |writer_| created on startup. This is useful for -DumpWithoutCrash, |
| //! which may write to an alternate location. |
| class ScopedAlternateWriter { |
| public: |
| ScopedAlternateWriter(InProcessHandler* handler); |
| ~ScopedAlternateWriter(); |
| ScopedAlternateWriter(const ScopedAlternateWriter&) = delete; |
| ScopedAlternateWriter& operator=(const ScopedAlternateWriter&) = delete; |
| //! \brief Open's an alternate dump writer in the same directory as the |
| //! default InProcessHandler's dump writer, so the file will be |
| //! processed with -ProcessIntermediateDumps() |
| bool Open(); |
| |
| //! \brief Open's an alternate dump writer in the client provided |path|. |
| //! The file will only be processed by calling |
| //! ProcessIntermediateDump(path) |
| bool OpenAtPath(const base::FilePath& path); |
| |
| //! \brief The path of the alternate dump writer. |
| const base::FilePath& path() { return path_; } |
| |
| private: |
| InProcessHandler* handler_; |
| std::unique_ptr<IOSIntermediateDumpWriter> original_writer_; |
| base::FilePath path_; |
| }; |
| |
| private: |
| //! \brief Helper to start and end intermediate reports. |
| class ScopedReport { |
| public: |
| ScopedReport(IOSIntermediateDumpWriter* writer, |
| const IOSSystemDataCollector& system_data, |
| const uint64_t* frames = nullptr, |
| const size_t num_frames = 0); |
| ~ScopedReport() {} |
| ScopedReport(const ScopedReport&) = delete; |
| ScopedReport& operator=(const ScopedReport&) = delete; |
| |
| private: |
| IOSIntermediateDumpWriter::ScopedRootMap rootMap_; |
| }; |
| |
| std::unique_ptr<IOSIntermediateDumpWriter> GetWriter() { |
| return std::move(writer_); |
| } |
| |
| void SetWriter(std::unique_ptr<IOSIntermediateDumpWriter> writer) { |
| writer_ = std::move(writer); |
| } |
| |
| void SetOpenNewFileAfterReport(bool open_new_file_after_report) { |
| open_new_file_after_report_ = open_new_file_after_report; |
| } |
| |
| void ProcessIntermediateDumpWithCompleteAnnotations( |
| const base::FilePath& file, |
| const std::map<std::string, std::string>& annotations); |
| void SaveSnapshot(ProcessSnapshotIOSIntermediateDump& process_snapshot); |
| std::vector<base::FilePath> PendingFiles(); |
| bool OpenNewFile(); |
| void PostReportCleanup(); |
| |
| bool upload_thread_started_ = false; |
| bool open_new_file_after_report_ = true; |
| std::map<std::string, std::string> annotations_; |
| base::FilePath base_dir_; |
| base::FilePath current_file_; |
| std::unique_ptr<IOSIntermediateDumpWriter> writer_; |
| std::unique_ptr<IOSIntermediateDumpWriter> alternate_mach_writer_; |
| std::unique_ptr<CrashReportUploadThread> upload_thread_; |
| std::unique_ptr<CrashReportDatabase> database_; |
| InitializationStateDcheck initialized_; |
| }; |
| |
| } // namespace internal |
| } // namespace crashpad |