mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-10 06:36:02 +00:00
android/linux: Support modules with shared relros on Android
Add MemoryMap::Iterator to support different strategies for locating the start of module mappings on Android and Linux. Beginning with API 21, Bionic provides android_dlopen_ext() which allows passing a file descriptor with an existing relro segment to the loader. This means that the mapping containing the dynamic segment could have a name, device, and inode which are different than the other mappings for the module. The revised strategy for Android at API 21+ is to search all mappings in reverse order from they dynamic array mapping until a module is parsed with the expected dynamic array address. Linux and Android 20- continue to select mappings using the device, inode, and file offsets of the mappings. Bug: crashpad:268 Change-Id: I30e95e51cb6874c00875d2a9c57f1249877736d4 Reviewed-on: https://chromium-review.googlesource.com/c/1374375 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org>
This commit is contained in:
parent
8b6f158d20
commit
2afe6dc210
@ -75,6 +75,8 @@ compat_target("compat") {
|
|||||||
|
|
||||||
if (crashpad_is_android) {
|
if (crashpad_is_android) {
|
||||||
sources += [
|
sources += [
|
||||||
|
"android/android/api-level.cc",
|
||||||
|
"android/android/api-level.h",
|
||||||
"android/dlfcn_internal.cc",
|
"android/dlfcn_internal.cc",
|
||||||
"android/dlfcn_internal.h",
|
"android/dlfcn_internal.h",
|
||||||
"android/elf.h",
|
"android/elf.h",
|
||||||
|
50
compat/android/android/api-level.cc
Normal file
50
compat/android/android/api-level.cc
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
// Copyright 2018 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 <android/api-level.h>
|
||||||
|
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/system_properties.h>
|
||||||
|
|
||||||
|
#include "dlfcn_internal.h"
|
||||||
|
|
||||||
|
#if __ANDROID_API__ < 29
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
int android_get_device_api_level() {
|
||||||
|
using FuncType = int (*)();
|
||||||
|
static const FuncType bionic_get_device_api_level =
|
||||||
|
reinterpret_cast<FuncType>(
|
||||||
|
crashpad::internal::Dlsym(RTLD_NEXT, "android_get_device_api_level"));
|
||||||
|
|
||||||
|
if (bionic_get_device_api_level) {
|
||||||
|
return bionic_get_device_api_level();
|
||||||
|
}
|
||||||
|
|
||||||
|
char api_string[PROP_VALUE_MAX];
|
||||||
|
int length = __system_property_get("ro.build.version.sdk", api_string);
|
||||||
|
if (length <= 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int api_level = atoi(api_string);
|
||||||
|
return api_level > 0 ? api_level : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // extern "C"
|
||||||
|
|
||||||
|
#endif // __ANDROID_API__ < 29
|
38
compat/android/android/api-level.h
Normal file
38
compat/android/android/api-level.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
// Copyright 2018 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_COMPAT_ANDROID_ANDROID_API_LEVEL_H_
|
||||||
|
#define CRASHPAD_COMPAT_ANDROID_ANDROID_API_LEVEL_H_
|
||||||
|
|
||||||
|
#include_next <android/api-level.h>
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
|
||||||
|
#if __ANDROID_API__ < 29
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Returns the API level of the device or -1 if it can't be determined. This
|
||||||
|
// function is provided by Bionic at API 29.
|
||||||
|
int android_get_device_api_level();
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // __ANDROID_API__ < 29
|
||||||
|
|
||||||
|
#endif // CRASHPAD_COMPAT_ANDROID_ANDROID_API_LEVEL_H_
|
@ -20,6 +20,8 @@
|
|||||||
{
|
{
|
||||||
'target_name': 'crashpad_compat',
|
'target_name': 'crashpad_compat',
|
||||||
'sources': [
|
'sources': [
|
||||||
|
'android/android/api-level.cc',
|
||||||
|
'android/android/api-level.h',
|
||||||
'android/dlfcn_internal.cc',
|
'android/dlfcn_internal.cc',
|
||||||
'android/dlfcn_internal.h',
|
'android/dlfcn_internal.h',
|
||||||
'android/elf.h',
|
'android/elf.h',
|
||||||
|
@ -100,10 +100,9 @@ void LocateExecutable(PtraceConnection* connection,
|
|||||||
ASSERT_TRUE(memory_map.Initialize(connection));
|
ASSERT_TRUE(memory_map.Initialize(connection));
|
||||||
const MemoryMap::Mapping* phdr_mapping = memory_map.FindMapping(phdrs);
|
const MemoryMap::Mapping* phdr_mapping = memory_map.FindMapping(phdrs);
|
||||||
ASSERT_TRUE(phdr_mapping);
|
ASSERT_TRUE(phdr_mapping);
|
||||||
std::vector<const MemoryMap::Mapping*> possible_mappings =
|
auto possible_mappings = memory_map.FindFilePossibleMmapStarts(*phdr_mapping);
|
||||||
memory_map.FindFilePossibleMmapStarts(*phdr_mapping);
|
ASSERT_EQ(possible_mappings->Count(), 1u);
|
||||||
ASSERT_EQ(possible_mappings.size(), 1u);
|
*elf_address = possible_mappings->Next()->range.Base();
|
||||||
*elf_address = possible_mappings[0]->range.Base();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // OS_FUCHSIA
|
#endif // OS_FUCHSIA
|
||||||
|
@ -37,28 +37,13 @@
|
|||||||
#include "util/process/process_memory_range.h"
|
#include "util/process/process_memory_range.h"
|
||||||
|
|
||||||
#if defined(OS_ANDROID)
|
#if defined(OS_ANDROID)
|
||||||
#include <sys/system_properties.h>
|
#include <android/api-level.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace crashpad {
|
namespace crashpad {
|
||||||
namespace test {
|
namespace test {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
#if defined(OS_ANDROID)
|
|
||||||
int AndroidRuntimeAPI() {
|
|
||||||
char api_string[PROP_VALUE_MAX];
|
|
||||||
int length = __system_property_get("ro.build.version.sdk", api_string);
|
|
||||||
if (length <= 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int api_level;
|
|
||||||
bool success =
|
|
||||||
base::StringToInt(base::StringPiece(api_string, length), &api_level);
|
|
||||||
return success ? api_level : -1;
|
|
||||||
}
|
|
||||||
#endif // OS_ANDROID
|
|
||||||
|
|
||||||
void TestAgainstTarget(PtraceConnection* connection) {
|
void TestAgainstTarget(PtraceConnection* connection) {
|
||||||
// Use ElfImageReader on the main executable which can tell us the debug
|
// Use ElfImageReader on the main executable which can tell us the debug
|
||||||
// address. glibc declares the symbol _r_debug in link.h which we can use to
|
// address. glibc declares the symbol _r_debug in link.h which we can use to
|
||||||
@ -74,10 +59,10 @@ void TestAgainstTarget(PtraceConnection* connection) {
|
|||||||
|
|
||||||
const MemoryMap::Mapping* phdr_mapping = mappings.FindMapping(phdrs);
|
const MemoryMap::Mapping* phdr_mapping = mappings.FindMapping(phdrs);
|
||||||
ASSERT_TRUE(phdr_mapping);
|
ASSERT_TRUE(phdr_mapping);
|
||||||
std::vector<const MemoryMap::Mapping*> exe_mappings =
|
|
||||||
mappings.FindFilePossibleMmapStarts(*phdr_mapping);
|
auto exe_mappings = mappings.FindFilePossibleMmapStarts(*phdr_mapping);
|
||||||
ASSERT_EQ(exe_mappings.size(), 1u);
|
ASSERT_EQ(exe_mappings->Count(), 1u);
|
||||||
LinuxVMAddress elf_address = exe_mappings[0]->range.Base();
|
LinuxVMAddress elf_address = exe_mappings->Next()->range.Base();
|
||||||
|
|
||||||
ProcessMemoryLinux memory;
|
ProcessMemoryLinux memory;
|
||||||
ASSERT_TRUE(memory.Initialize(connection->GetProcessID()));
|
ASSERT_TRUE(memory.Initialize(connection->GetProcessID()));
|
||||||
@ -94,7 +79,7 @@ void TestAgainstTarget(PtraceConnection* connection) {
|
|||||||
ASSERT_TRUE(debug.Initialize(range, debug_address));
|
ASSERT_TRUE(debug.Initialize(range, debug_address));
|
||||||
|
|
||||||
#if defined(OS_ANDROID)
|
#if defined(OS_ANDROID)
|
||||||
const int android_runtime_api = AndroidRuntimeAPI();
|
const int android_runtime_api = android_get_device_api_level();
|
||||||
ASSERT_GE(android_runtime_api, 1);
|
ASSERT_GE(android_runtime_api, 1);
|
||||||
|
|
||||||
EXPECT_NE(debug.Executable()->name.find("crashpad_snapshot_test"),
|
EXPECT_NE(debug.Executable()->name.find("crashpad_snapshot_test"),
|
||||||
@ -143,13 +128,13 @@ void TestAgainstTarget(PtraceConnection* connection) {
|
|||||||
mappings.FindMapping(module.dynamic_array);
|
mappings.FindMapping(module.dynamic_array);
|
||||||
ASSERT_TRUE(dyn_mapping);
|
ASSERT_TRUE(dyn_mapping);
|
||||||
|
|
||||||
std::vector<const MemoryMap::Mapping*> possible_mappings =
|
auto possible_mappings = mappings.FindFilePossibleMmapStarts(*dyn_mapping);
|
||||||
mappings.FindFilePossibleMmapStarts(*dyn_mapping);
|
ASSERT_GE(possible_mappings->Count(), 1u);
|
||||||
ASSERT_GE(possible_mappings.size(), 1u);
|
|
||||||
|
|
||||||
std::unique_ptr<ElfImageReader> module_reader;
|
std::unique_ptr<ElfImageReader> module_reader;
|
||||||
const MemoryMap::Mapping* module_mapping = nullptr;
|
const MemoryMap::Mapping* module_mapping = nullptr;
|
||||||
for (const auto mapping : possible_mappings) {
|
const MemoryMap::Mapping* mapping = nullptr;
|
||||||
|
while ((mapping = possible_mappings->Next())) {
|
||||||
auto parsed_module = std::make_unique<ElfImageReader>();
|
auto parsed_module = std::make_unique<ElfImageReader>();
|
||||||
VMAddress dynamic_address;
|
VMAddress dynamic_address;
|
||||||
if (parsed_module->Initialize(range, mapping->range.Base()) &&
|
if (parsed_module->Initialize(range, mapping->range.Base()) &&
|
||||||
|
@ -29,6 +29,10 @@
|
|||||||
#include "util/linux/auxiliary_vector.h"
|
#include "util/linux/auxiliary_vector.h"
|
||||||
#include "util/linux/proc_stat_reader.h"
|
#include "util/linux/proc_stat_reader.h"
|
||||||
|
|
||||||
|
#if defined(OS_ANDROID)
|
||||||
|
#include <android/api-level.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace crashpad {
|
namespace crashpad {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@ -352,17 +356,15 @@ void ProcessReaderLinux::InitializeModules() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<const MemoryMap::Mapping*> possible_mappings =
|
auto possible_mappings =
|
||||||
memory_map_.FindFilePossibleMmapStarts(*phdr_mapping);
|
memory_map_.FindFilePossibleMmapStarts(*phdr_mapping);
|
||||||
for (auto riter = possible_mappings.rbegin();
|
const MemoryMap::Mapping* mapping = nullptr;
|
||||||
riter != possible_mappings.rend();
|
while ((mapping = possible_mappings->Next())) {
|
||||||
++riter) {
|
|
||||||
auto mapping = *riter;
|
|
||||||
auto parsed_exe = std::make_unique<ElfImageReader>();
|
auto parsed_exe = std::make_unique<ElfImageReader>();
|
||||||
if (parsed_exe->Initialize(
|
if (parsed_exe->Initialize(
|
||||||
range,
|
range,
|
||||||
mapping->range.Base(),
|
mapping->range.Base(),
|
||||||
/* verbose= */ possible_mappings.size() == 1) &&
|
/* verbose= */ possible_mappings->Count() == 1) &&
|
||||||
parsed_exe->GetProgramHeaderTableAddress() == phdrs) {
|
parsed_exe->GetProgramHeaderTableAddress() == phdrs) {
|
||||||
exe_mapping = mapping;
|
exe_mapping = mapping;
|
||||||
exe_reader = std::move(parsed_exe);
|
exe_reader = std::move(parsed_exe);
|
||||||
@ -370,7 +372,8 @@ void ProcessReaderLinux::InitializeModules() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!exe_mapping) {
|
if (!exe_mapping) {
|
||||||
LOG(ERROR) << "no exe mappings " << possible_mappings.size();
|
LOG(ERROR) << "no exe mappings 0x" << std::hex
|
||||||
|
<< phdr_mapping->range.Base();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -407,18 +410,30 @@ void ProcessReaderLinux::InitializeModules() {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<const MemoryMap::Mapping*> possible_mappings =
|
#if defined(OS_ANDROID)
|
||||||
|
// Beginning at API 21, Bionic provides android_dlopen_ext() which allows
|
||||||
|
// passing a file descriptor with an existing relro segment to the loader.
|
||||||
|
// This means that the mapping attributes of dyn_mapping may be unrelated
|
||||||
|
// to the attributes of the other mappings for the module. In this case,
|
||||||
|
// search all mappings in reverse order from dyn_mapping until a module is
|
||||||
|
// parsed whose dynamic address matches the value in the debug link.
|
||||||
|
static int api_level = android_get_device_api_level();
|
||||||
|
auto possible_mappings =
|
||||||
|
(api_level >= 21 || api_level < 0)
|
||||||
|
? memory_map_.ReverseIteratorFrom(*dyn_mapping)
|
||||||
|
: memory_map_.FindFilePossibleMmapStarts(*dyn_mapping);
|
||||||
|
#else
|
||||||
|
auto possible_mappings =
|
||||||
memory_map_.FindFilePossibleMmapStarts(*dyn_mapping);
|
memory_map_.FindFilePossibleMmapStarts(*dyn_mapping);
|
||||||
for (auto riter = possible_mappings.rbegin();
|
#endif
|
||||||
riter != possible_mappings.rend();
|
const MemoryMap::Mapping* mapping = nullptr;
|
||||||
++riter) {
|
while ((mapping = possible_mappings->Next())) {
|
||||||
auto mapping = *riter;
|
|
||||||
auto parsed_module = std::make_unique<ElfImageReader>();
|
auto parsed_module = std::make_unique<ElfImageReader>();
|
||||||
VMAddress dynamic_address;
|
VMAddress dynamic_address;
|
||||||
if (parsed_module->Initialize(
|
if (parsed_module->Initialize(
|
||||||
range,
|
range,
|
||||||
mapping->range.Base(),
|
mapping->range.Base(),
|
||||||
/* verbose= */ possible_mappings.size() == 1) &&
|
/* verbose= */ possible_mappings->Count() == 1) &&
|
||||||
parsed_module->GetDynamicArrayAddress(&dynamic_address) &&
|
parsed_module->GetDynamicArrayAddress(&dynamic_address) &&
|
||||||
dynamic_address == entry.dynamic_array) {
|
dynamic_address == entry.dynamic_array) {
|
||||||
module_mapping = mapping;
|
module_mapping = mapping;
|
||||||
@ -427,7 +442,8 @@ void ProcessReaderLinux::InitializeModules() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!module_mapping) {
|
if (!module_mapping) {
|
||||||
LOG(ERROR) << "no module mappings " << possible_mappings.size();
|
LOG(ERROR) << "no module mappings 0x" << std::hex
|
||||||
|
<< dyn_mapping->range.Base();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -715,7 +715,7 @@ void ExpectTestModule(ProcessReaderLinux* reader,
|
|||||||
auto dynamic_mapping = reader->GetMemoryMap()->FindMapping(dynamic_addr);
|
auto dynamic_mapping = reader->GetMemoryMap()->FindMapping(dynamic_addr);
|
||||||
auto mappings =
|
auto mappings =
|
||||||
reader->GetMemoryMap()->FindFilePossibleMmapStarts(*dynamic_mapping);
|
reader->GetMemoryMap()->FindFilePossibleMmapStarts(*dynamic_mapping);
|
||||||
EXPECT_EQ(mappings.size(), 2u);
|
EXPECT_EQ(mappings->Count(), 2u);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -204,6 +204,48 @@ ParseResult ParseMapsLine(DelimitedFileReader* maps_file_reader,
|
|||||||
return ParseResult::kSuccess;
|
return ParseResult::kSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SparseReverseIterator : public MemoryMap::Iterator {
|
||||||
|
public:
|
||||||
|
SparseReverseIterator(const std::vector<const MemoryMap::Mapping*>& mappings)
|
||||||
|
: mappings_(mappings), riter_(mappings_.rbegin()){};
|
||||||
|
|
||||||
|
SparseReverseIterator() : mappings_(), riter_(mappings_.rend()) {}
|
||||||
|
|
||||||
|
// Iterator:
|
||||||
|
const MemoryMap::Mapping* Next() override {
|
||||||
|
return riter_ == mappings_.rend() ? nullptr : *(riter_++);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int Count() override { return mappings_.rend() - riter_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<const MemoryMap::Mapping*> mappings_;
|
||||||
|
std::vector<const MemoryMap::Mapping*>::reverse_iterator riter_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(SparseReverseIterator);
|
||||||
|
};
|
||||||
|
|
||||||
|
class FullReverseIterator : public MemoryMap::Iterator {
|
||||||
|
public:
|
||||||
|
FullReverseIterator(
|
||||||
|
std::vector<MemoryMap::Mapping>::const_reverse_iterator rbegin,
|
||||||
|
std::vector<MemoryMap::Mapping>::const_reverse_iterator rend)
|
||||||
|
: riter_(rbegin), rend_(rend) {}
|
||||||
|
|
||||||
|
// Iterator:
|
||||||
|
const MemoryMap::Mapping* Next() override {
|
||||||
|
return riter_ == rend_ ? nullptr : &*riter_++;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int Count() override { return rend_ - riter_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<MemoryMap::Mapping>::const_reverse_iterator riter_;
|
||||||
|
std::vector<MemoryMap::Mapping>::const_reverse_iterator rend_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(FullReverseIterator);
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
MemoryMap::Mapping::Mapping()
|
MemoryMap::Mapping::Mapping()
|
||||||
@ -296,7 +338,7 @@ const MemoryMap::Mapping* MemoryMap::FindMappingWithName(
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<const MemoryMap::Mapping*> MemoryMap::FindFilePossibleMmapStarts(
|
std::unique_ptr<MemoryMap::Iterator> MemoryMap::FindFilePossibleMmapStarts(
|
||||||
const Mapping& mapping) const {
|
const Mapping& mapping) const {
|
||||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||||
|
|
||||||
@ -308,12 +350,12 @@ std::vector<const MemoryMap::Mapping*> MemoryMap::FindFilePossibleMmapStarts(
|
|||||||
for (const auto& candidate : mappings_) {
|
for (const auto& candidate : mappings_) {
|
||||||
if (mapping.Equals(candidate)) {
|
if (mapping.Equals(candidate)) {
|
||||||
possible_starts.push_back(&candidate);
|
possible_starts.push_back(&candidate);
|
||||||
return possible_starts;
|
return std::make_unique<SparseReverseIterator>(possible_starts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG(ERROR) << "mapping not found";
|
LOG(ERROR) << "mapping not found";
|
||||||
return std::vector<const Mapping*>();
|
return std::make_unique<SparseReverseIterator>();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(OS_ANDROID)
|
#if defined(OS_ANDROID)
|
||||||
@ -341,7 +383,7 @@ std::vector<const MemoryMap::Mapping*> MemoryMap::FindFilePossibleMmapStarts(
|
|||||||
possible_starts.push_back(&candidate);
|
possible_starts.push_back(&candidate);
|
||||||
}
|
}
|
||||||
if (mapping.Equals(candidate)) {
|
if (mapping.Equals(candidate)) {
|
||||||
return possible_starts;
|
return std::make_unique<SparseReverseIterator>(possible_starts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -359,12 +401,23 @@ std::vector<const MemoryMap::Mapping*> MemoryMap::FindFilePossibleMmapStarts(
|
|||||||
possible_starts.push_back(&candidate);
|
possible_starts.push_back(&candidate);
|
||||||
}
|
}
|
||||||
if (mapping.Equals(candidate)) {
|
if (mapping.Equals(candidate)) {
|
||||||
return possible_starts;
|
return std::make_unique<SparseReverseIterator>(possible_starts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG(ERROR) << "mapping not found";
|
LOG(ERROR) << "mapping not found";
|
||||||
return std::vector<const Mapping*>();
|
return std::make_unique<SparseReverseIterator>();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<MemoryMap::Iterator> MemoryMap::ReverseIteratorFrom(
|
||||||
|
const Mapping& target) const {
|
||||||
|
for (auto riter = mappings_.crbegin(); riter != mappings_.rend(); ++riter) {
|
||||||
|
if (riter->Equals(target)) {
|
||||||
|
return std::make_unique<FullReverseIterator>(riter, mappings_.rend());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::make_unique<FullReverseIterator>(mappings_.rend(),
|
||||||
|
mappings_.rend());
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace crashpad
|
} // namespace crashpad
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -76,6 +77,24 @@ class MemoryMap {
|
|||||||
//! it was obtained from.
|
//! it was obtained from.
|
||||||
const Mapping* FindMappingWithName(const std::string& name) const;
|
const Mapping* FindMappingWithName(const std::string& name) 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
|
//! \brief Find possible initial mappings of files mapped over several
|
||||||
//! segments.
|
//! segments.
|
||||||
//!
|
//!
|
||||||
@ -99,10 +118,15 @@ class MemoryMap {
|
|||||||
//! map a file, \a mapping is returned in \a possible_starts.
|
//! map a file, \a mapping is returned in \a possible_starts.
|
||||||
//!
|
//!
|
||||||
//! \param[in] mapping A Mapping whose series to find the start of.
|
//! \param[in] mapping A Mapping whose series to find the start of.
|
||||||
//! \return a vector of the possible mapping starts.
|
//! \return a reverse iterator over the possible mapping starts, starting from
|
||||||
std::vector<const Mapping*> FindFilePossibleMmapStarts(
|
//! the mapping with highest base address.
|
||||||
|
std::unique_ptr<Iterator> FindFilePossibleMmapStarts(
|
||||||
const Mapping& mapping) const;
|
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<Iterator> ReverseIteratorFrom(const Mapping& mapping) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<Mapping> mappings_;
|
std::vector<Mapping> mappings_;
|
||||||
InitializationStateDcheck initialized_;
|
InitializationStateDcheck initialized_;
|
||||||
|
@ -373,22 +373,20 @@ void ExpectFindFilePossibleMmapStarts(LinuxVMAddress mapping_start,
|
|||||||
ASSERT_NE(mapping1, mapping2);
|
ASSERT_NE(mapping1, mapping2);
|
||||||
ASSERT_NE(mapping2, mapping3);
|
ASSERT_NE(mapping2, mapping3);
|
||||||
|
|
||||||
std::vector<const MemoryMap::Mapping*> mappings;
|
auto mappings = map.FindFilePossibleMmapStarts(*mapping1);
|
||||||
|
ASSERT_EQ(mappings->Count(), 1u);
|
||||||
mappings = map.FindFilePossibleMmapStarts(*mapping1);
|
EXPECT_EQ(mappings->Next(), mapping1);
|
||||||
ASSERT_EQ(mappings.size(), 1u);
|
|
||||||
EXPECT_EQ(mappings[0], mapping1);
|
|
||||||
|
|
||||||
mappings = map.FindFilePossibleMmapStarts(*mapping2);
|
mappings = map.FindFilePossibleMmapStarts(*mapping2);
|
||||||
ASSERT_EQ(mappings.size(), 1u);
|
ASSERT_EQ(mappings->Count(), 1u);
|
||||||
EXPECT_EQ(mappings[0], mapping2);
|
EXPECT_EQ(mappings->Next(), mapping2);
|
||||||
|
|
||||||
mappings = map.FindFilePossibleMmapStarts(*mapping3);
|
mappings = map.FindFilePossibleMmapStarts(*mapping3);
|
||||||
#if defined(OS_ANDROID)
|
#if defined(OS_ANDROID)
|
||||||
EXPECT_EQ(mappings.size(), 2u);
|
EXPECT_EQ(mappings->Count(), 2u);
|
||||||
#else
|
#else
|
||||||
ASSERT_EQ(mappings.size(), 1u);
|
ASSERT_EQ(mappings->Count(), 1u);
|
||||||
EXPECT_EQ(mappings[0], mapping1);
|
EXPECT_EQ(mappings->Next(), mapping1);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -432,29 +430,30 @@ TEST(MemoryMap, FindFilePossibleMmapStarts) {
|
|||||||
ASSERT_NE(mapping1, mapping2);
|
ASSERT_NE(mapping1, mapping2);
|
||||||
ASSERT_NE(mapping2, mapping3);
|
ASSERT_NE(mapping2, mapping3);
|
||||||
|
|
||||||
std::vector<const MemoryMap::Mapping*> mappings;
|
|
||||||
|
|
||||||
#if defined(OS_ANDROID)
|
#if defined(OS_ANDROID)
|
||||||
mappings = map.FindFilePossibleMmapStarts(*mapping1);
|
auto mappings = map.FindFilePossibleMmapStarts(*mapping1);
|
||||||
EXPECT_EQ(mappings.size(), 1u);
|
EXPECT_EQ(mappings->Count(), 1u);
|
||||||
|
EXPECT_EQ(mappings->Next(), mapping1);
|
||||||
|
EXPECT_EQ(mappings->Next(), nullptr);
|
||||||
|
|
||||||
mappings = map.FindFilePossibleMmapStarts(*mapping2);
|
mappings = map.FindFilePossibleMmapStarts(*mapping2);
|
||||||
EXPECT_EQ(mappings.size(), 2u);
|
EXPECT_EQ(mappings->Count(), 2u);
|
||||||
|
|
||||||
mappings = map.FindFilePossibleMmapStarts(*mapping3);
|
mappings = map.FindFilePossibleMmapStarts(*mapping3);
|
||||||
EXPECT_EQ(mappings.size(), 3u);
|
EXPECT_EQ(mappings->Count(), 3u);
|
||||||
#else
|
#else
|
||||||
mappings = map.FindFilePossibleMmapStarts(*mapping1);
|
auto mappings = map.FindFilePossibleMmapStarts(*mapping1);
|
||||||
ASSERT_EQ(mappings.size(), 1u);
|
ASSERT_EQ(mappings->Count(), 1u);
|
||||||
EXPECT_EQ(mappings[0], mapping1);
|
EXPECT_EQ(mappings->Next(), mapping1);
|
||||||
|
EXPECT_EQ(mappings->Next(), nullptr);
|
||||||
|
|
||||||
mappings = map.FindFilePossibleMmapStarts(*mapping2);
|
mappings = map.FindFilePossibleMmapStarts(*mapping2);
|
||||||
ASSERT_EQ(mappings.size(), 1u);
|
ASSERT_EQ(mappings->Count(), 1u);
|
||||||
EXPECT_EQ(mappings[0], mapping1);
|
EXPECT_EQ(mappings->Next(), mapping1);
|
||||||
|
|
||||||
mappings = map.FindFilePossibleMmapStarts(*mapping3);
|
mappings = map.FindFilePossibleMmapStarts(*mapping3);
|
||||||
ASSERT_EQ(mappings.size(), 1u);
|
ASSERT_EQ(mappings->Count(), 1u);
|
||||||
EXPECT_EQ(mappings[0], mapping1);
|
EXPECT_EQ(mappings->Next(), mapping1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(ARCH_CPU_64_BITS)
|
#if defined(ARCH_CPU_64_BITS)
|
||||||
@ -464,7 +463,9 @@ TEST(MemoryMap, FindFilePossibleMmapStarts) {
|
|||||||
#endif
|
#endif
|
||||||
MemoryMap::Mapping bad_mapping;
|
MemoryMap::Mapping bad_mapping;
|
||||||
bad_mapping.range.SetRange(is_64_bit, 0, 1);
|
bad_mapping.range.SetRange(is_64_bit, 0, 1);
|
||||||
EXPECT_EQ(map.FindFilePossibleMmapStarts(bad_mapping).size(), 0u);
|
mappings = map.FindFilePossibleMmapStarts(bad_mapping);
|
||||||
|
EXPECT_EQ(mappings->Count(), 0u);
|
||||||
|
EXPECT_EQ(mappings->Next(), nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make the second page an anonymous mapping
|
// Make the second page an anonymous mapping
|
||||||
@ -578,45 +579,45 @@ TEST(MemoryMap, FindFilePossibleMmapStarts_MultipleStarts) {
|
|||||||
ASSERT_TRUE(mapping);
|
ASSERT_TRUE(mapping);
|
||||||
auto possible_starts = map.FindFilePossibleMmapStarts(*mapping);
|
auto possible_starts = map.FindFilePossibleMmapStarts(*mapping);
|
||||||
#if defined(OS_ANDROID)
|
#if defined(OS_ANDROID)
|
||||||
EXPECT_EQ(possible_starts.size(), 1u);
|
EXPECT_EQ(possible_starts->Count(), 1u);
|
||||||
#else
|
#else
|
||||||
EXPECT_EQ(possible_starts.size(), 0u);
|
EXPECT_EQ(possible_starts->Count(), 0u);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
mapping = map.FindMapping(file_mapping1.addr_as<VMAddress>());
|
mapping = map.FindMapping(file_mapping1.addr_as<VMAddress>());
|
||||||
ASSERT_TRUE(mapping);
|
ASSERT_TRUE(mapping);
|
||||||
possible_starts = map.FindFilePossibleMmapStarts(*mapping);
|
possible_starts = map.FindFilePossibleMmapStarts(*mapping);
|
||||||
#if defined(OS_ANDROID)
|
#if defined(OS_ANDROID)
|
||||||
EXPECT_EQ(possible_starts.size(), 2u);
|
EXPECT_EQ(possible_starts->Count(), 2u);
|
||||||
#else
|
#else
|
||||||
EXPECT_EQ(possible_starts.size(), 1u);
|
EXPECT_EQ(possible_starts->Count(), 1u);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
mapping = map.FindMapping(file_mapping2.addr_as<VMAddress>());
|
mapping = map.FindMapping(file_mapping2.addr_as<VMAddress>());
|
||||||
ASSERT_TRUE(mapping);
|
ASSERT_TRUE(mapping);
|
||||||
possible_starts = map.FindFilePossibleMmapStarts(*mapping);
|
possible_starts = map.FindFilePossibleMmapStarts(*mapping);
|
||||||
#if defined(OS_ANDROID)
|
#if defined(OS_ANDROID)
|
||||||
EXPECT_EQ(possible_starts.size(), 3u);
|
EXPECT_EQ(possible_starts->Count(), 3u);
|
||||||
#else
|
#else
|
||||||
EXPECT_EQ(possible_starts.size(), 2u);
|
EXPECT_EQ(possible_starts->Count(), 2u);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
mapping = map.FindMapping(file_mapping3.addr_as<VMAddress>());
|
mapping = map.FindMapping(file_mapping3.addr_as<VMAddress>());
|
||||||
ASSERT_TRUE(mapping);
|
ASSERT_TRUE(mapping);
|
||||||
possible_starts = map.FindFilePossibleMmapStarts(*mapping);
|
possible_starts = map.FindFilePossibleMmapStarts(*mapping);
|
||||||
#if defined(OS_ANDROID)
|
#if defined(OS_ANDROID)
|
||||||
EXPECT_EQ(possible_starts.size(), 4u);
|
EXPECT_EQ(possible_starts->Count(), 4u);
|
||||||
#else
|
#else
|
||||||
EXPECT_EQ(possible_starts.size(), 3u);
|
EXPECT_EQ(possible_starts->Count(), 3u);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
mapping = map.FindMapping(file_mapping4.addr_as<VMAddress>());
|
mapping = map.FindMapping(file_mapping4.addr_as<VMAddress>());
|
||||||
ASSERT_TRUE(mapping);
|
ASSERT_TRUE(mapping);
|
||||||
possible_starts = map.FindFilePossibleMmapStarts(*mapping);
|
possible_starts = map.FindFilePossibleMmapStarts(*mapping);
|
||||||
#if defined(OS_ANDROID)
|
#if defined(OS_ANDROID)
|
||||||
EXPECT_EQ(possible_starts.size(), 5u);
|
EXPECT_EQ(possible_starts->Count(), 5u);
|
||||||
#else
|
#else
|
||||||
EXPECT_EQ(possible_starts.size(), 4u);
|
EXPECT_EQ(possible_starts->Count(), 4u);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user