// Copyright 2017 The Crashpad Authors // // 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. #ifndef CRASHPAD_SNAPSHOT_LINUX_PROCESS_READER_LINUX_H_ #define CRASHPAD_SNAPSHOT_LINUX_PROCESS_READER_LINUX_H_ #include #include #include #include #include #include "snapshot/elf/elf_image_reader.h" #include "snapshot/module_snapshot.h" #include "util/linux/address_types.h" #include "util/linux/memory_map.h" #include "util/linux/ptrace_connection.h" #include "util/linux/thread_info.h" #include "util/misc/initialization_state_dcheck.h" #include "util/posix/process_info.h" #include "util/process/process_memory.h" namespace crashpad { //! \brief Accesses information about another process, identified by a process //! ID. class ProcessReaderLinux { public: //! \brief Contains information about a thread that belongs to a process. struct Thread { Thread(); ~Thread(); //! \brief Initializes the thread's stack using \a stack_pointer instead of //! the stack pointer in \a thread_info. //! //! This method initializes \a stack_region_address and \a stack_region_size //! overwriting any values they previously contained. This is useful, for //! example, if the thread is currently in a signal handler context, which //! may execute on a different stack than was used before the signal was //! received. //! //! \param[in] reader A process reader for the target process. //! \param[in] stack_pointer The stack pointer for the stack to initialize. void InitializeStackFromSP(ProcessReaderLinux* reader, LinuxVMAddress stack_pointer); ThreadInfo thread_info; LinuxVMAddress stack_region_address; LinuxVMSize stack_region_size; std::string name; pid_t tid; int sched_policy; int static_priority; int nice_value; //! \brief `true` if `sched_policy`, `static_priority`, and `nice_value` are //! all valid. bool have_priorities; private: friend class ProcessReaderLinux; bool InitializePtrace(PtraceConnection* connection); void InitializeStack(ProcessReaderLinux* reader); }; //! \brief Contains information about a module loaded into a process. struct Module { Module(); ~Module(); //! \brief The pathname used to load the module from disk. std::string name; //! \brief An image reader for the module. //! //! The lifetime of this ElfImageReader is scoped to the lifetime of the //! ProcessReaderLinux that created it. //! //! This field may be `nullptr` if a reader could not be created for the //! module. ElfImageReader* elf_reader; //! \brief The module's type. ModuleSnapshot::ModuleType type; }; ProcessReaderLinux(); ProcessReaderLinux(const ProcessReaderLinux&) = delete; ProcessReaderLinux& operator=(const ProcessReaderLinux&) = delete; ~ProcessReaderLinux(); //! \brief Initializes this object. //! //! This method must be successfully called before calling any other method in //! this class and may only be called once. //! //! \param[in] connection A PtraceConnection to the target process. //! \return `true` on success. `false` on failure with a message logged. bool Initialize(PtraceConnection* connection); //! \brief Return `true` if the target task is a 64-bit process. bool Is64Bit() const { return is_64_bit_; } //! \brief Return the target process' process ID. pid_t ProcessID() const { return process_info_.ProcessID(); } //! \brief Return the target process' parent process ID. pid_t ParentProcessID() const { return process_info_.ParentProcessID(); } //! \brief Return a memory reader for the target process. const ProcessMemoryLinux* Memory() const { return connection_->Memory(); } //! \brief Return a memory map of the target process. MemoryMap* GetMemoryMap() { return &memory_map_; } //! \brief Determines the target process’ start time. //! //! \param[out] start_time The time that the process started. //! \return `true` on success with \a start_time set. Otherwise `false` with a //! message logged. bool StartTime(timeval* start_time) const; //! \brief Determines the target process’ execution time. //! //! \param[out] user_time The amount of time the process has executed code in //! user mode. //! \param[out] system_time The amount of time the process has executed code //! in system mode. //! //! \return `true` on success, `false` on failure, with a warning logged. On //! failure, \a user_time and \a system_time will be set to represent no //! time spent executing code in user or system mode. bool CPUTimes(timeval* user_time, timeval* system_time) const; //! \brief Return a vector of threads that are in the task process. If the //! main thread is able to be identified and traced, it will be placed at //! index `0`. const std::vector& Threads(); //! \return The modules loaded in the process. The first element (at index //! `0`) corresponds to the main executable. const std::vector& Modules(); //! \return On Android, the abort message that was passed to //! android_set_abort_message(). This is only available on Q or later. const std::string& AbortMessage(); private: void InitializeThreads(); void InitializeModules(); void InitializeAbortMessage(); template void ReadAbortMessage(const MemoryMap::Mapping* mapping); PtraceConnection* connection_; // weak ProcessInfo process_info_; MemoryMap memory_map_; std::vector threads_; std::vector modules_; std::string abort_message_; std::vector> elf_readers_; bool is_64_bit_; bool initialized_threads_; bool initialized_modules_; InitializationStateDcheck initialized_; }; } // namespace crashpad #endif // CRASHPAD_SNAPSHOT_LINUX_PROCESS_READER_LINUX_H_