// 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_UTIL_LINUX_MEMORY_MAP_H_ #define CRASHPAD_UTIL_LINUX_MEMORY_MAP_H_ #include #include #include #include #include "util/linux/address_types.h" #include "util/linux/checked_linux_address_range.h" #include "util/linux/ptrace_connection.h" #include "util/misc/initialization_state_dcheck.h" namespace crashpad { //! \brief Accesses information about mapped memory in another process. //! //! The target process must be stopped to guarantee correct mappings. If the //! target process is not stopped, mappings may be invalid after the return from //! Initialize(), and even mappings existing at the time Initialize() was called //! may not be found. class MemoryMap { public: //! \brief Information about a mapped region of memory. struct Mapping { Mapping(); bool Equals(const Mapping& other) const; std::string name; CheckedLinuxAddressRange range; off64_t offset; dev_t device; ino_t inode; bool readable; bool writable; bool executable; bool shareable; }; MemoryMap(); ~MemoryMap(); //! \brief Initializes this object with information about the mapped memory //! regions in the process connected via \a connection. //! //! This method must be called successfully prior to calling any other method //! in this class. This method may only be called once. //! //! \param[in] connection A connection to the process create a map for. //! //! \return `true` on success, `false` on failure with a message logged. bool Initialize(PtraceConnection* connection); //! \return The Mapping containing \a address or `nullptr` if no match is //! found. The caller does not take ownership of this object. It is scoped //! to the lifetime of the MemoryMap object that it was obtained from. const Mapping* FindMapping(LinuxVMAddress address) const; //! \return The Mapping with the lowest base address whose name is \a name or //! `nullptr` if no match is found. The caller does not take ownership of //! this object. It is scoped to the lifetime of the MemoryMap object that //! it was obtained from. const Mapping* FindMappingWithName(const std::string& name) const; //! \brief Given a range to be read from the target process, returns a vector //! of ranges, representing the readable portions of the original range. //! //! \param[in] range The range being identified. //! //! \return A vector of ranges corresponding to the portion of \a range that //! is readable based on the memory map. std::vector> GetReadableRanges( const CheckedRange& range) const; //! \brief An abstract base class for iterating over ordered sets of mappings //! in a MemoryMap. class Iterator { public: virtual ~Iterator() = default; //! \return the mapping pointed to by the iterator and advance the iterator //! to the next mapping. If there are no more mappings, this method //! returns `nullptr` on all subsequent invocations. virtual const Mapping* Next() = 0; //! \return the number of mappings remaining. virtual unsigned int Count() = 0; protected: Iterator() = default; }; //! \brief Find possible initial mappings of files mapped over several //! segments. //! //! Executables and libaries are typically loaded into several mappings with //! varying permissions for different segments. Portions of an ELF file may //! be mapped multiple times as part of loading the file, for example, when //! initializing GNU_RELRO segments. //! //! This method searches for mappings at or below \a mapping in memory that //! are mapped from the same file as \a mapping from offset 0. //! //! On Android, ELF modules may be loaded from within a zipfile, so this //! method may return mappings whose offset is not 0. //! //! This method is intended to help identify the possible base address for //! loaded modules, but it is the caller's responsibility to determine which //! returned mapping is correct. //! //! If \a mapping does not refer to a valid mapping, an empty vector will be //! returned and a message will be logged. If \a mapping is found but does not //! map a file, \a mapping is returned in \a possible_starts. //! //! \param[in] mapping A Mapping whose series to find the start of. //! \return a reverse iterator over the possible mapping starts, starting from //! the mapping with highest base address. std::unique_ptr FindFilePossibleMmapStarts( const Mapping& mapping) const; //! \return A reverse iterator over all mappings in the MemoryMap from \a //! mapping to the start of the MemoryMap. std::unique_ptr ReverseIteratorFrom(const Mapping& mapping) const; private: std::vector mappings_; PtraceConnection* connection_; InitializationStateDcheck initialized_; }; } // namespace crashpad #endif // CRASHPAD_UTIL_LINUX_MEMORY_MAP_H_