mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-09 14:06:33 +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) {
|
||||
sources += [
|
||||
"android/android/api-level.cc",
|
||||
"android/android/api-level.h",
|
||||
"android/dlfcn_internal.cc",
|
||||
"android/dlfcn_internal.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',
|
||||
'sources': [
|
||||
'android/android/api-level.cc',
|
||||
'android/android/api-level.h',
|
||||
'android/dlfcn_internal.cc',
|
||||
'android/dlfcn_internal.h',
|
||||
'android/elf.h',
|
||||
|
@ -100,10 +100,9 @@ void LocateExecutable(PtraceConnection* connection,
|
||||
ASSERT_TRUE(memory_map.Initialize(connection));
|
||||
const MemoryMap::Mapping* phdr_mapping = memory_map.FindMapping(phdrs);
|
||||
ASSERT_TRUE(phdr_mapping);
|
||||
std::vector<const MemoryMap::Mapping*> possible_mappings =
|
||||
memory_map.FindFilePossibleMmapStarts(*phdr_mapping);
|
||||
ASSERT_EQ(possible_mappings.size(), 1u);
|
||||
*elf_address = possible_mappings[0]->range.Base();
|
||||
auto possible_mappings = memory_map.FindFilePossibleMmapStarts(*phdr_mapping);
|
||||
ASSERT_EQ(possible_mappings->Count(), 1u);
|
||||
*elf_address = possible_mappings->Next()->range.Base();
|
||||
}
|
||||
|
||||
#endif // OS_FUCHSIA
|
||||
|
@ -37,28 +37,13 @@
|
||||
#include "util/process/process_memory_range.h"
|
||||
|
||||
#if defined(OS_ANDROID)
|
||||
#include <sys/system_properties.h>
|
||||
#include <android/api-level.h>
|
||||
#endif
|
||||
|
||||
namespace crashpad {
|
||||
namespace test {
|
||||
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) {
|
||||
// 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
|
||||
@ -74,10 +59,10 @@ void TestAgainstTarget(PtraceConnection* connection) {
|
||||
|
||||
const MemoryMap::Mapping* phdr_mapping = mappings.FindMapping(phdrs);
|
||||
ASSERT_TRUE(phdr_mapping);
|
||||
std::vector<const MemoryMap::Mapping*> exe_mappings =
|
||||
mappings.FindFilePossibleMmapStarts(*phdr_mapping);
|
||||
ASSERT_EQ(exe_mappings.size(), 1u);
|
||||
LinuxVMAddress elf_address = exe_mappings[0]->range.Base();
|
||||
|
||||
auto exe_mappings = mappings.FindFilePossibleMmapStarts(*phdr_mapping);
|
||||
ASSERT_EQ(exe_mappings->Count(), 1u);
|
||||
LinuxVMAddress elf_address = exe_mappings->Next()->range.Base();
|
||||
|
||||
ProcessMemoryLinux memory;
|
||||
ASSERT_TRUE(memory.Initialize(connection->GetProcessID()));
|
||||
@ -94,7 +79,7 @@ void TestAgainstTarget(PtraceConnection* connection) {
|
||||
ASSERT_TRUE(debug.Initialize(range, debug_address));
|
||||
|
||||
#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);
|
||||
|
||||
EXPECT_NE(debug.Executable()->name.find("crashpad_snapshot_test"),
|
||||
@ -143,13 +128,13 @@ void TestAgainstTarget(PtraceConnection* connection) {
|
||||
mappings.FindMapping(module.dynamic_array);
|
||||
ASSERT_TRUE(dyn_mapping);
|
||||
|
||||
std::vector<const MemoryMap::Mapping*> possible_mappings =
|
||||
mappings.FindFilePossibleMmapStarts(*dyn_mapping);
|
||||
ASSERT_GE(possible_mappings.size(), 1u);
|
||||
auto possible_mappings = mappings.FindFilePossibleMmapStarts(*dyn_mapping);
|
||||
ASSERT_GE(possible_mappings->Count(), 1u);
|
||||
|
||||
std::unique_ptr<ElfImageReader> module_reader;
|
||||
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>();
|
||||
VMAddress dynamic_address;
|
||||
if (parsed_module->Initialize(range, mapping->range.Base()) &&
|
||||
|
@ -29,6 +29,10 @@
|
||||
#include "util/linux/auxiliary_vector.h"
|
||||
#include "util/linux/proc_stat_reader.h"
|
||||
|
||||
#if defined(OS_ANDROID)
|
||||
#include <android/api-level.h>
|
||||
#endif
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
namespace {
|
||||
@ -352,17 +356,15 @@ void ProcessReaderLinux::InitializeModules() {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<const MemoryMap::Mapping*> possible_mappings =
|
||||
auto possible_mappings =
|
||||
memory_map_.FindFilePossibleMmapStarts(*phdr_mapping);
|
||||
for (auto riter = possible_mappings.rbegin();
|
||||
riter != possible_mappings.rend();
|
||||
++riter) {
|
||||
auto mapping = *riter;
|
||||
const MemoryMap::Mapping* mapping = nullptr;
|
||||
while ((mapping = possible_mappings->Next())) {
|
||||
auto parsed_exe = std::make_unique<ElfImageReader>();
|
||||
if (parsed_exe->Initialize(
|
||||
range,
|
||||
mapping->range.Base(),
|
||||
/* verbose= */ possible_mappings.size() == 1) &&
|
||||
/* verbose= */ possible_mappings->Count() == 1) &&
|
||||
parsed_exe->GetProgramHeaderTableAddress() == phdrs) {
|
||||
exe_mapping = mapping;
|
||||
exe_reader = std::move(parsed_exe);
|
||||
@ -370,7 +372,8 @@ void ProcessReaderLinux::InitializeModules() {
|
||||
}
|
||||
}
|
||||
if (!exe_mapping) {
|
||||
LOG(ERROR) << "no exe mappings " << possible_mappings.size();
|
||||
LOG(ERROR) << "no exe mappings 0x" << std::hex
|
||||
<< phdr_mapping->range.Base();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -407,18 +410,30 @@ void ProcessReaderLinux::InitializeModules() {
|
||||
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);
|
||||
for (auto riter = possible_mappings.rbegin();
|
||||
riter != possible_mappings.rend();
|
||||
++riter) {
|
||||
auto mapping = *riter;
|
||||
#endif
|
||||
const MemoryMap::Mapping* mapping = nullptr;
|
||||
while ((mapping = possible_mappings->Next())) {
|
||||
auto parsed_module = std::make_unique<ElfImageReader>();
|
||||
VMAddress dynamic_address;
|
||||
if (parsed_module->Initialize(
|
||||
range,
|
||||
mapping->range.Base(),
|
||||
/* verbose= */ possible_mappings.size() == 1) &&
|
||||
/* verbose= */ possible_mappings->Count() == 1) &&
|
||||
parsed_module->GetDynamicArrayAddress(&dynamic_address) &&
|
||||
dynamic_address == entry.dynamic_array) {
|
||||
module_mapping = mapping;
|
||||
@ -427,7 +442,8 @@ void ProcessReaderLinux::InitializeModules() {
|
||||
}
|
||||
}
|
||||
if (!module_mapping) {
|
||||
LOG(ERROR) << "no module mappings " << possible_mappings.size();
|
||||
LOG(ERROR) << "no module mappings 0x" << std::hex
|
||||
<< dyn_mapping->range.Base();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -715,7 +715,7 @@ void ExpectTestModule(ProcessReaderLinux* reader,
|
||||
auto dynamic_mapping = reader->GetMemoryMap()->FindMapping(dynamic_addr);
|
||||
auto mappings =
|
||||
reader->GetMemoryMap()->FindFilePossibleMmapStarts(*dynamic_mapping);
|
||||
EXPECT_EQ(mappings.size(), 2u);
|
||||
EXPECT_EQ(mappings->Count(), 2u);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -204,6 +204,48 @@ ParseResult ParseMapsLine(DelimitedFileReader* maps_file_reader,
|
||||
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
|
||||
|
||||
MemoryMap::Mapping::Mapping()
|
||||
@ -296,7 +338,7 @@ const MemoryMap::Mapping* MemoryMap::FindMappingWithName(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<const MemoryMap::Mapping*> MemoryMap::FindFilePossibleMmapStarts(
|
||||
std::unique_ptr<MemoryMap::Iterator> MemoryMap::FindFilePossibleMmapStarts(
|
||||
const Mapping& mapping) const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
|
||||
@ -308,12 +350,12 @@ std::vector<const MemoryMap::Mapping*> MemoryMap::FindFilePossibleMmapStarts(
|
||||
for (const auto& candidate : mappings_) {
|
||||
if (mapping.Equals(candidate)) {
|
||||
possible_starts.push_back(&candidate);
|
||||
return possible_starts;
|
||||
return std::make_unique<SparseReverseIterator>(possible_starts);
|
||||
}
|
||||
}
|
||||
|
||||
LOG(ERROR) << "mapping not found";
|
||||
return std::vector<const Mapping*>();
|
||||
return std::make_unique<SparseReverseIterator>();
|
||||
}
|
||||
|
||||
#if defined(OS_ANDROID)
|
||||
@ -341,7 +383,7 @@ std::vector<const MemoryMap::Mapping*> MemoryMap::FindFilePossibleMmapStarts(
|
||||
possible_starts.push_back(&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);
|
||||
}
|
||||
if (mapping.Equals(candidate)) {
|
||||
return possible_starts;
|
||||
return std::make_unique<SparseReverseIterator>(possible_starts);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@ -76,6 +77,24 @@ class MemoryMap {
|
||||
//! it was obtained from.
|
||||
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
|
||||
//! segments.
|
||||
//!
|
||||
@ -99,10 +118,15 @@ class MemoryMap {
|
||||
//! 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(
|
||||
//! \return a reverse iterator over the possible mapping starts, starting from
|
||||
//! the mapping with highest base address.
|
||||
std::unique_ptr<Iterator> 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<Iterator> ReverseIteratorFrom(const Mapping& mapping) const;
|
||||
|
||||
private:
|
||||
std::vector<Mapping> mappings_;
|
||||
InitializationStateDcheck initialized_;
|
||||
|
@ -373,22 +373,20 @@ void ExpectFindFilePossibleMmapStarts(LinuxVMAddress mapping_start,
|
||||
ASSERT_NE(mapping1, mapping2);
|
||||
ASSERT_NE(mapping2, mapping3);
|
||||
|
||||
std::vector<const MemoryMap::Mapping*> mappings;
|
||||
|
||||
mappings = map.FindFilePossibleMmapStarts(*mapping1);
|
||||
ASSERT_EQ(mappings.size(), 1u);
|
||||
EXPECT_EQ(mappings[0], mapping1);
|
||||
auto mappings = map.FindFilePossibleMmapStarts(*mapping1);
|
||||
ASSERT_EQ(mappings->Count(), 1u);
|
||||
EXPECT_EQ(mappings->Next(), mapping1);
|
||||
|
||||
mappings = map.FindFilePossibleMmapStarts(*mapping2);
|
||||
ASSERT_EQ(mappings.size(), 1u);
|
||||
EXPECT_EQ(mappings[0], mapping2);
|
||||
ASSERT_EQ(mappings->Count(), 1u);
|
||||
EXPECT_EQ(mappings->Next(), mapping2);
|
||||
|
||||
mappings = map.FindFilePossibleMmapStarts(*mapping3);
|
||||
#if defined(OS_ANDROID)
|
||||
EXPECT_EQ(mappings.size(), 2u);
|
||||
EXPECT_EQ(mappings->Count(), 2u);
|
||||
#else
|
||||
ASSERT_EQ(mappings.size(), 1u);
|
||||
EXPECT_EQ(mappings[0], mapping1);
|
||||
ASSERT_EQ(mappings->Count(), 1u);
|
||||
EXPECT_EQ(mappings->Next(), mapping1);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -432,29 +430,30 @@ TEST(MemoryMap, FindFilePossibleMmapStarts) {
|
||||
ASSERT_NE(mapping1, mapping2);
|
||||
ASSERT_NE(mapping2, mapping3);
|
||||
|
||||
std::vector<const MemoryMap::Mapping*> mappings;
|
||||
|
||||
#if defined(OS_ANDROID)
|
||||
mappings = map.FindFilePossibleMmapStarts(*mapping1);
|
||||
EXPECT_EQ(mappings.size(), 1u);
|
||||
auto mappings = map.FindFilePossibleMmapStarts(*mapping1);
|
||||
EXPECT_EQ(mappings->Count(), 1u);
|
||||
EXPECT_EQ(mappings->Next(), mapping1);
|
||||
EXPECT_EQ(mappings->Next(), nullptr);
|
||||
|
||||
mappings = map.FindFilePossibleMmapStarts(*mapping2);
|
||||
EXPECT_EQ(mappings.size(), 2u);
|
||||
EXPECT_EQ(mappings->Count(), 2u);
|
||||
|
||||
mappings = map.FindFilePossibleMmapStarts(*mapping3);
|
||||
EXPECT_EQ(mappings.size(), 3u);
|
||||
EXPECT_EQ(mappings->Count(), 3u);
|
||||
#else
|
||||
mappings = map.FindFilePossibleMmapStarts(*mapping1);
|
||||
ASSERT_EQ(mappings.size(), 1u);
|
||||
EXPECT_EQ(mappings[0], mapping1);
|
||||
auto mappings = map.FindFilePossibleMmapStarts(*mapping1);
|
||||
ASSERT_EQ(mappings->Count(), 1u);
|
||||
EXPECT_EQ(mappings->Next(), mapping1);
|
||||
EXPECT_EQ(mappings->Next(), nullptr);
|
||||
|
||||
mappings = map.FindFilePossibleMmapStarts(*mapping2);
|
||||
ASSERT_EQ(mappings.size(), 1u);
|
||||
EXPECT_EQ(mappings[0], mapping1);
|
||||
ASSERT_EQ(mappings->Count(), 1u);
|
||||
EXPECT_EQ(mappings->Next(), mapping1);
|
||||
|
||||
mappings = map.FindFilePossibleMmapStarts(*mapping3);
|
||||
ASSERT_EQ(mappings.size(), 1u);
|
||||
EXPECT_EQ(mappings[0], mapping1);
|
||||
ASSERT_EQ(mappings->Count(), 1u);
|
||||
EXPECT_EQ(mappings->Next(), mapping1);
|
||||
#endif
|
||||
|
||||
#if defined(ARCH_CPU_64_BITS)
|
||||
@ -464,7 +463,9 @@ TEST(MemoryMap, FindFilePossibleMmapStarts) {
|
||||
#endif
|
||||
MemoryMap::Mapping bad_mapping;
|
||||
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
|
||||
@ -578,45 +579,45 @@ TEST(MemoryMap, FindFilePossibleMmapStarts_MultipleStarts) {
|
||||
ASSERT_TRUE(mapping);
|
||||
auto possible_starts = map.FindFilePossibleMmapStarts(*mapping);
|
||||
#if defined(OS_ANDROID)
|
||||
EXPECT_EQ(possible_starts.size(), 1u);
|
||||
EXPECT_EQ(possible_starts->Count(), 1u);
|
||||
#else
|
||||
EXPECT_EQ(possible_starts.size(), 0u);
|
||||
EXPECT_EQ(possible_starts->Count(), 0u);
|
||||
#endif
|
||||
|
||||
mapping = map.FindMapping(file_mapping1.addr_as<VMAddress>());
|
||||
ASSERT_TRUE(mapping);
|
||||
possible_starts = map.FindFilePossibleMmapStarts(*mapping);
|
||||
#if defined(OS_ANDROID)
|
||||
EXPECT_EQ(possible_starts.size(), 2u);
|
||||
EXPECT_EQ(possible_starts->Count(), 2u);
|
||||
#else
|
||||
EXPECT_EQ(possible_starts.size(), 1u);
|
||||
EXPECT_EQ(possible_starts->Count(), 1u);
|
||||
#endif
|
||||
|
||||
mapping = map.FindMapping(file_mapping2.addr_as<VMAddress>());
|
||||
ASSERT_TRUE(mapping);
|
||||
possible_starts = map.FindFilePossibleMmapStarts(*mapping);
|
||||
#if defined(OS_ANDROID)
|
||||
EXPECT_EQ(possible_starts.size(), 3u);
|
||||
EXPECT_EQ(possible_starts->Count(), 3u);
|
||||
#else
|
||||
EXPECT_EQ(possible_starts.size(), 2u);
|
||||
EXPECT_EQ(possible_starts->Count(), 2u);
|
||||
#endif
|
||||
|
||||
mapping = map.FindMapping(file_mapping3.addr_as<VMAddress>());
|
||||
ASSERT_TRUE(mapping);
|
||||
possible_starts = map.FindFilePossibleMmapStarts(*mapping);
|
||||
#if defined(OS_ANDROID)
|
||||
EXPECT_EQ(possible_starts.size(), 4u);
|
||||
EXPECT_EQ(possible_starts->Count(), 4u);
|
||||
#else
|
||||
EXPECT_EQ(possible_starts.size(), 3u);
|
||||
EXPECT_EQ(possible_starts->Count(), 3u);
|
||||
#endif
|
||||
|
||||
mapping = map.FindMapping(file_mapping4.addr_as<VMAddress>());
|
||||
ASSERT_TRUE(mapping);
|
||||
possible_starts = map.FindFilePossibleMmapStarts(*mapping);
|
||||
#if defined(OS_ANDROID)
|
||||
EXPECT_EQ(possible_starts.size(), 5u);
|
||||
EXPECT_EQ(possible_starts->Count(), 5u);
|
||||
#else
|
||||
EXPECT_EQ(possible_starts.size(), 4u);
|
||||
EXPECT_EQ(possible_starts->Count(), 4u);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user