mirror of
https://github.com/chromium/crashpad.git
synced 2025-01-22 07:29:36 +08:00
52ff1accbb
The general strategy used by Crashpad to determine loaded modules is to read the link_map to get the addresses of the dynamic arrays for all loaded modules. Those addresses can then be used to query the MemoryMap to locate the module's mappings, and in particular the base mapping from which Crashpad can parse the entire loaded ELF file. ELF modules are typically loaded in several mappings with varying permissions for different segments. The previous strategy used to find the base mapping for a module was to search backwards from the mapping for the dynamic array until a mapping from file offset 0 was found for the same file. This fails when the file is mapped multiple times from file offset 0, which can happen if the first page of the file contains a GNU_RELRO segment. This new strategy queries the MemoryMap for ALL mappings associated with the dynamic array's mapping, mapped from offset 0. The consumer (process_reader_linux.cc) can then determine which mapping is the correct base by attempting to parse a module at that address and corroborating the PT_DYNAMIC or program header table address from the parsed module with the values Crashpad gets from the link_map or auxiliary vector. Bug: crashpad:30 Change-Id: Ibfcbba512e8fccc8c65afef734ea5640b71e9f70 Reviewed-on: https://chromium-review.googlesource.com/1139396 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org>
109 lines
4.1 KiB
C++
109 lines
4.1 KiB
C++
// Copyright 2017 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.
|
|
|
|
#ifndef CRASHPAD_UTIL_LINUX_MEMORY_MAP_H_
|
|
#define CRASHPAD_UTIL_LINUX_MEMORY_MAP_H_
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#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;
|
|
off_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 Find Mappings that share a Mapping's file, mapped from offset 0.
|
|
//!
|
|
//! 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.
|
|
//!
|
|
//! 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 vector of the possible mapping starts.
|
|
std::vector<const Mapping*> FindFilePossibleMmapStarts(
|
|
const Mapping& mapping) const;
|
|
|
|
private:
|
|
std::vector<Mapping> mappings_;
|
|
InitializationStateDcheck initialized_;
|
|
};
|
|
|
|
} // namespace crashpad
|
|
|
|
#endif // CRASHPAD_UTIL_LINUX_MEMORY_MAP_H_
|