Construct ProcessMemoryLinux using PtraceConnection

Update ProcessMemoryLinux to be constructed from PtraceConnection
instead of being Initialize()d with a pid_t.

This allows consolidating PtraceClient's BrokeredMemory with
ProcessMemoryLinux and providing the PtraceConnection as a alternative
to the memory file (previously only done for brokered connections).

Change-Id: I1363e208030eaf595fb8051e9a2c6b255c1f9886
Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3072402
Reviewed-by: Mark Mentovai <mark@chromium.org>
Commit-Queue: Joshua Peraza <jperaza@chromium.org>
This commit is contained in:
Joshua Peraza 2021-08-10 14:55:25 -07:00 committed by Crashpad LUCI CQ
parent d5d78c1469
commit 78bcb55e1c
19 changed files with 183 additions and 129 deletions

View File

@ -30,6 +30,10 @@
#include "util/misc/from_pointer_cast.h"
#include "util/process/process_memory_native.h"
#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
#include "test/linux/fake_ptrace_connection.h"
#endif
namespace crashpad {
namespace test {
namespace {
@ -102,8 +106,14 @@ void ExpectCrashpadInfo(ProcessType process,
VMAddress extra_memory_address,
VMAddress simple_annotations_address,
VMAddress annotations_list_address) {
#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
FakePtraceConnection connection;
ASSERT_TRUE(connection.Initialize(process));
ProcessMemoryLinux memory(&connection);
#else
ProcessMemoryNative memory;
ASSERT_TRUE(memory.Initialize(process));
#endif
ProcessMemoryRange range;
ASSERT_TRUE(range.Initialize(&memory, is_64_bit));

View File

@ -32,6 +32,10 @@
#include "util/misc/from_pointer_cast.h"
#include "util/process/process_memory_native.h"
#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
#include "test/linux/fake_ptrace_connection.h"
#endif
namespace crashpad {
namespace test {
namespace {
@ -90,8 +94,14 @@ void ExpectAnnotations(ProcessType process,
bool is_64_bit,
VMAddress simple_map_address,
VMAddress annotation_list_address) {
#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
FakePtraceConnection connection;
ASSERT_TRUE(connection.Initialize(process));
ProcessMemoryLinux memory(&connection);
#else
ProcessMemoryNative memory;
ASSERT_TRUE(memory.Initialize(process));
#endif
ProcessMemoryRange range;
ASSERT_TRUE(range.Initialize(&memory, is_64_bit));

View File

@ -127,21 +127,22 @@ void ReadThisExecutableInTarget(ProcessType process,
constexpr bool am_64_bit = false;
#endif // ARCH_CPU_64_BITS
ProcessMemoryNative memory;
ASSERT_TRUE(memory.Initialize(process));
ProcessMemoryRange range;
ASSERT_TRUE(range.Initialize(&memory, am_64_bit));
VMAddress elf_address;
#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
FakePtraceConnection connection;
ASSERT_TRUE(connection.Initialize(process));
ProcessMemoryLinux memory(&connection);
LocateExecutable(&connection, &memory, &elf_address);
#elif defined(OS_FUCHSIA)
ProcessMemoryFuchsia memory;
ASSERT_TRUE(memory.Initialize(process));
LocateExecutable(process, &memory, &elf_address);
#endif
ASSERT_NO_FATAL_FAILURE();
ProcessMemoryRange range;
ASSERT_TRUE(range.Initialize(&memory, am_64_bit));
ElfImageReader reader;
ASSERT_TRUE(reader.Initialize(range, elf_address));
@ -191,8 +192,15 @@ void ReadLibcInTarget(ProcessType process,
constexpr bool am_64_bit = false;
#endif // ARCH_CPU_64_BITS
#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
FakePtraceConnection connection;
ASSERT_TRUE(connection.Initialize(process));
ProcessMemoryLinux memory(&connection);
#else
ProcessMemoryNative memory;
ASSERT_TRUE(memory.Initialize(process));
#endif
ProcessMemoryRange range;
ASSERT_TRUE(range.Initialize(&memory, am_64_bit));

View File

@ -83,8 +83,7 @@ void TestAgainstTarget(PtraceConnection* connection) {
ASSERT_EQ(exe_mappings->Count(), 1u);
LinuxVMAddress elf_address = exe_mappings->Next()->range.Base();
ProcessMemoryLinux memory;
ASSERT_TRUE(memory.Initialize(connection->GetProcessID()));
ProcessMemoryLinux memory(connection);
ProcessMemoryRange range;
ASSERT_TRUE(range.Initialize(&memory, connection->Is64Bit()));

View File

@ -20,6 +20,10 @@
#include "util/misc/from_pointer_cast.h"
#include "util/process/process_memory_linux.h"
#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
#include "test/linux/fake_ptrace_connection.h"
#endif
namespace crashpad {
namespace test {
namespace {
@ -27,11 +31,12 @@ namespace {
class AllowedAnnotationsTest : public testing::Test {
public:
void SetUp() override {
ASSERT_TRUE(memory_.Initialize(getpid()));
ASSERT_TRUE(connection_.Initialize(getpid()));
#if defined(ARCH_CPU_64_BITS)
ASSERT_TRUE(range_.Initialize(&memory_, true));
ASSERT_TRUE(range_.Initialize(connection_.Memory(), true));
#else
ASSERT_TRUE(range_.Initialize(&memory_, false));
ASSERT_TRUE(range_.Initialize(connection_.Memory(), false));
#endif
}
@ -41,7 +46,7 @@ class AllowedAnnotationsTest : public testing::Test {
range_, FromPointerCast<VMAddress>(address), &allowed_annotations_);
}
ProcessMemoryLinux memory_;
FakePtraceConnection connection_;
ProcessMemoryRange range_;
std::vector<std::string> allowed_annotations_;
};

View File

@ -83,12 +83,7 @@ bool FakePtraceConnection::ReadFileContents(const base::FilePath& path,
ProcessMemory* FakePtraceConnection::Memory() {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
if (!memory_) {
auto mem = std::make_unique<ProcessMemoryLinux>();
if (mem->Initialize(pid_)) {
memory_ = std::move(mem);
} else {
ADD_FAILURE();
}
memory_ = std::make_unique<ProcessMemoryLinux>(this);
}
return memory_.get();
}
@ -99,5 +94,12 @@ bool FakePtraceConnection::Threads(std::vector<pid_t>* threads) {
return false;
}
ssize_t FakePtraceConnection::ReadUpTo(VMAddress address,
size_t size,
void* buffer) {
NOTREACHED();
return false;
}
} // namespace test
} // namespace crashpad

View File

@ -65,6 +65,9 @@ class FakePtraceConnection : public PtraceConnection {
//! \todo Not yet implemented.
bool Threads(std::vector<pid_t>* threads) override;
//! \\todo Not yet implemented.
ssize_t ReadUpTo(VMAddress address, size_t size, void* buffer) override;
private:
std::set<pid_t> attachments_;
std::unique_ptr<ProcessMemoryLinux> memory_;

View File

@ -95,8 +95,7 @@ void TestAgainstCloneOrSelf(pid_t pid) {
ASSERT_TRUE(aux.GetValue(AT_EGID, &egid));
EXPECT_EQ(egid, getegid());
ProcessMemoryLinux memory;
ASSERT_TRUE(memory.Initialize(pid));
ProcessMemoryLinux memory(&connection);
LinuxVMAddress platform_addr;
ASSERT_TRUE(aux.GetValue(AT_PLATFORM, &platform_addr));

View File

@ -39,10 +39,6 @@ bool DirectPtraceConnection::Initialize(pid_t pid) {
}
pid_ = pid;
if (!memory_.Initialize(pid)) {
return false;
}
INITIALIZATION_STATE_SET_VALID(initialized_);
return true;
}
@ -79,7 +75,10 @@ bool DirectPtraceConnection::ReadFileContents(const base::FilePath& path,
ProcessMemory* DirectPtraceConnection::Memory() {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return &memory_;
if (!memory_) {
memory_ = std::make_unique<ProcessMemoryLinux>(this);
}
return memory_.get();
}
bool DirectPtraceConnection::Threads(std::vector<pid_t>* threads) {
@ -87,4 +86,10 @@ bool DirectPtraceConnection::Threads(std::vector<pid_t>* threads) {
return ReadThreadIDs(pid_, threads);
}
ssize_t DirectPtraceConnection::ReadUpTo(VMAddress address,
size_t size,
void* buffer) {
return ptracer_.ReadUpTo(pid_, address, size, static_cast<char*>(buffer));
}
} // namespace crashpad

View File

@ -57,10 +57,11 @@ class DirectPtraceConnection : public PtraceConnection {
std::string* contents) override;
ProcessMemory* Memory() override;
bool Threads(std::vector<pid_t>* threads) override;
ssize_t ReadUpTo(VMAddress, size_t size, void* buffer) override;
private:
std::vector<std::unique_ptr<ScopedPtraceAttach>> attachments_;
ProcessMemoryLinux memory_;
std::unique_ptr<ProcessMemory> memory_;
pid_t pid_;
Ptracer ptracer_;
InitializationStateDcheck initialized_;

View File

@ -151,8 +151,7 @@ class SameBitnessTest : public Multiprocess {
broker_thread.Start();
PtraceClient client;
ASSERT_TRUE(client.Initialize(
client_sock.get(), ChildPID(), /* try_direct_memory= */ false));
ASSERT_TRUE(client.Initialize(client_sock.get(), ChildPID()));
EXPECT_EQ(client.GetProcessID(), ChildPID());
@ -177,32 +176,26 @@ class SameBitnessTest : public Multiprocess {
ASSERT_TRUE(client.GetThreadInfo(child2_tid, &info2));
EXPECT_EQ(info2.thread_specific_data_address, child2_tls);
ProcessMemory* memory = client.Memory();
ASSERT_TRUE(memory);
auto buffer = std::make_unique<char[]>(mapping_.len());
ASSERT_TRUE(memory->Read(
mapping_.addr_as<VMAddress>(), mapping_.len(), buffer.get()));
auto expected_buffer = mapping_.addr_as<char*>();
for (size_t index = 0; index < mapping_.len(); ++index) {
EXPECT_EQ(buffer[index], expected_buffer[index]);
}
char first;
ASSERT_TRUE(
memory->Read(mapping_.addr_as<VMAddress>(), sizeof(first), &first));
ASSERT_EQ(
client.ReadUpTo(mapping_.addr_as<VMAddress>(), sizeof(first), &first),
1);
EXPECT_EQ(first, expected_buffer[0]);
char last;
ASSERT_TRUE(memory->Read(mapping_.addr_as<VMAddress>() + mapping_.len() - 1,
sizeof(last),
&last));
ASSERT_EQ(
client.ReadUpTo(mapping_.addr_as<VMAddress>() + mapping_.len() - 1,
sizeof(last),
&last),
1);
EXPECT_EQ(last, expected_buffer[mapping_.len() - 1]);
char unmapped;
EXPECT_FALSE(memory->Read(mapping_.addr_as<VMAddress>() + mapping_.len(),
EXPECT_EQ(client.ReadUpTo(mapping_.addr_as<VMAddress>() + mapping_.len(),
sizeof(unmapped),
&unmapped));
&unmapped),
-1);
std::string file_root = file_dir.value() + '/';
broker.SetFileRoot(file_root.c_str());

View File

@ -143,7 +143,7 @@ PtraceClient::~PtraceClient() {
}
}
bool PtraceClient::Initialize(int sock, pid_t pid, bool try_direct_memory) {
bool PtraceClient::Initialize(int sock, pid_t pid) {
INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
sock_ = sock;
pid_ = pid;
@ -166,16 +166,6 @@ bool PtraceClient::Initialize(int sock, pid_t pid, bool try_direct_memory) {
}
is_64_bit_ = is_64_bit == ExceptionHandlerProtocol::kBoolTrue;
if (try_direct_memory) {
auto direct_mem = std::make_unique<ProcessMemoryLinux>();
if (direct_mem->Initialize(pid)) {
memory_.reset(direct_mem.release());
}
}
if (!memory_) {
memory_ = std::make_unique<BrokeredMemory>(this);
}
INITIALIZATION_STATE_SET_VALID(initialized_);
return true;
}
@ -260,6 +250,9 @@ bool PtraceClient::ReadFileContents(const base::FilePath& path,
ProcessMemory* PtraceClient::Memory() {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
if (!memory_) {
memory_ = std::make_unique<ProcessMemoryLinux>(this);
}
return memory_.get();
}
@ -308,20 +301,7 @@ bool PtraceClient::Threads(std::vector<pid_t>* threads) {
return true;
}
PtraceClient::BrokeredMemory::BrokeredMemory(PtraceClient* client)
: ProcessMemory(), client_(client) {}
PtraceClient::BrokeredMemory::~BrokeredMemory() = default;
ssize_t PtraceClient::BrokeredMemory::ReadUpTo(VMAddress address,
size_t size,
void* buffer) const {
return client_->ReadUpTo(address, size, buffer);
}
ssize_t PtraceClient::ReadUpTo(VMAddress address,
size_t size,
void* buffer) const {
ssize_t PtraceClient::ReadUpTo(VMAddress address, size_t size, void* buffer) {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
char* buffer_c = reinterpret_cast<char*>(buffer);

View File

@ -46,11 +46,8 @@ class PtraceClient : public PtraceConnection {
//! ownership of the socket.
//! \param[in] pid The process ID of the process to form a PtraceConnection
//! with.
//! \param[in] try_direct_memory If `true` the client will attempt to support
//! memory reading operations by directly acessing the target process'
//! /proc/[pid]/mem file.
//! \return `true` on success. `false` on failure with a message logged.
bool Initialize(int sock, pid_t pid, bool try_direct_memory = true);
bool Initialize(int sock, pid_t pid);
// PtraceConnection:
@ -62,24 +59,9 @@ class PtraceClient : public PtraceConnection {
std::string* contents) override;
ProcessMemory* Memory() override;
bool Threads(std::vector<pid_t>* threads) override;
ssize_t ReadUpTo(VMAddress address, size_t size, void* buffer) override;
private:
class BrokeredMemory : public ProcessMemory {
public:
explicit BrokeredMemory(PtraceClient* client);
~BrokeredMemory();
ssize_t ReadUpTo(VMAddress address,
size_t size,
void* buffer) const override;
private:
PtraceClient* client_;
DISALLOW_COPY_AND_ASSIGN(BrokeredMemory);
};
ssize_t ReadUpTo(VMAddress address, size_t size, void* buffer) const;
bool SendFilePath(const char* path, size_t length);
std::unique_ptr<ProcessMemory> memory_;

View File

@ -73,6 +73,20 @@ class PtraceConnection {
//! this method returns `false`, \a threads may contain a partial list of
//! thread IDs.
virtual bool Threads(std::vector<pid_t>* threads) = 0;
//! \brief Copies memory from the connected process into a caller-provided
//! buffer in the current process, up to a maximum number of bytes.
//!
//! \param[in] address The address, in the connected process' address space,
//! of the memory region to copy.
//! \param[in] size The maximum size, in bytes, of the memory region to copy.
//! \a buffer must be at least this size.
//! \param[out] buffer The buffer into which the contents of the other
//! process' memory will be copied.
//!
//! \return the number of bytes copied, 0 if there is no more data to read, or
//! -1 on failure with a message logged.
virtual ssize_t ReadUpTo(VMAddress address, size_t size, void* buffer) = 0;
};
} // namespace crashpad

View File

@ -27,38 +27,37 @@
namespace crashpad {
ProcessMemoryLinux::ProcessMemoryLinux()
: ProcessMemory(), mem_fd_(), pid_(-1), initialized_() {}
ProcessMemoryLinux::ProcessMemoryLinux(PtraceConnection* connection)
: ProcessMemory(), mem_fd_() {
char path[32];
snprintf(path, sizeof(path), "/proc/%d/mem", connection->GetProcessID());
mem_fd_.reset(HANDLE_EINTR(open(path, O_RDONLY | O_NOCTTY | O_CLOEXEC)));
if (mem_fd_.is_valid()) {
read_up_to_ = [this](VMAddress address, size_t size, void* buffer) {
ssize_t bytes_read =
HANDLE_EINTR(pread64(mem_fd_.get(), buffer, size, address));
if (bytes_read < 0) {
PLOG(ERROR) << "pread64";
}
return bytes_read;
};
return;
}
read_up_to_ = std::bind(&PtraceConnection::ReadUpTo,
connection,
std::placeholders::_1,
std::placeholders::_2,
std::placeholders::_3);
}
ProcessMemoryLinux::~ProcessMemoryLinux() {}
bool ProcessMemoryLinux::Initialize(pid_t pid) {
INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
pid_ = pid;
char path[32];
snprintf(path, sizeof(path), "/proc/%d/mem", pid_);
mem_fd_.reset(HANDLE_EINTR(open(path, O_RDONLY | O_NOCTTY | O_CLOEXEC)));
if (!mem_fd_.is_valid()) {
PLOG(ERROR) << "open";
return false;
}
INITIALIZATION_STATE_SET_VALID(initialized_);
return true;
}
ssize_t ProcessMemoryLinux::ReadUpTo(VMAddress address,
size_t size,
void* buffer) const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
DCHECK(mem_fd_.is_valid());
DCHECK_LE(size, size_t{std::numeric_limits<ssize_t>::max()});
ssize_t bytes_read =
HANDLE_EINTR(pread64(mem_fd_.get(), buffer, size, address));
if (bytes_read < 0) {
PLOG(ERROR) << "pread64";
}
return bytes_read;
return read_up_to_(address, size, buffer);
}
} // namespace crashpad

View File

@ -17,12 +17,13 @@
#include <sys/types.h>
#include <functional>
#include <string>
#include "base/files/scoped_file.h"
#include "base/macros.h"
#include "util/linux/ptrace_connection.h"
#include "util/misc/address_types.h"
#include "util/misc/initialization_state_dcheck.h"
#include "util/process/process_memory.h"
namespace crashpad {
@ -30,26 +31,14 @@ namespace crashpad {
//! \brief Accesses the memory of another Linux process.
class ProcessMemoryLinux final : public ProcessMemory {
public:
ProcessMemoryLinux();
explicit ProcessMemoryLinux(PtraceConnection* connection);
~ProcessMemoryLinux();
//! \brief Initializes this object to read the memory of a process whose ID
//! is \a pid.
//!
//! This method must be called successfully prior to calling any other method
//! in this class.
//!
//! \param[in] pid The process ID of a target process.
//!
//! \return `true` on success, `false` on failure with a message logged.
bool Initialize(pid_t pid);
private:
ssize_t ReadUpTo(VMAddress address, size_t size, void* buffer) const override;
std::function<ssize_t(VMAddress, size_t, void*)> read_up_to_;
base::ScopedFD mem_fd_;
pid_t pid_;
InitializationStateDcheck initialized_;
DISALLOW_COPY_AND_ASSIGN(ProcessMemoryLinux);
};

View File

@ -23,6 +23,10 @@
#include "util/misc/from_pointer_cast.h"
#include "util/process/process_memory_native.h"
#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
#include "test/linux/fake_ptrace_connection.h"
#endif
namespace crashpad {
namespace test {
namespace {
@ -39,8 +43,14 @@ TEST(ProcessMemoryRange, Basic) {
constexpr bool is_64_bit = false;
#endif // ARCH_CPU_64_BITS
#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
FakePtraceConnection connection;
ASSERT_TRUE(connection.Initialize(GetSelfProcess()));
ProcessMemoryLinux memory(&connection);
#else
ProcessMemoryNative memory;
ASSERT_TRUE(memory.Initialize(GetSelfProcess()));
#endif // OS_ANDROID || OS_LINUX || OS_CHROMEOS
ProcessMemoryRange range;
ASSERT_TRUE(range.Initialize(&memory, is_64_bit));

View File

@ -19,13 +19,23 @@
#include "util/misc/from_pointer_cast.h"
#include "util/process/process_memory_native.h"
#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
#include "test/linux/fake_ptrace_connection.h"
#endif
namespace crashpad {
namespace test {
namespace {
TEST(ProcessMemorySanitized, DenyDisallowedMemory) {
#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
FakePtraceConnection connection;
ASSERT_TRUE(connection.Initialize(GetSelfProcess()));
ProcessMemoryLinux memory(&connection);
#else
ProcessMemoryNative memory;
ASSERT_TRUE(memory.Initialize(GetSelfProcess()));
#endif // OS_ANDROID || OS_LINUX || OS_CHROMEOS
char c = 42;
char out;
@ -41,8 +51,14 @@ TEST(ProcessMemorySanitized, DenyDisallowedMemory) {
}
TEST(ProcessMemorySanitized, AllowedMemory) {
#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
FakePtraceConnection connection;
ASSERT_TRUE(connection.Initialize(GetSelfProcess()));
ProcessMemoryLinux memory(&connection);
#else
ProcessMemoryNative memory;
ASSERT_TRUE(memory.Initialize(GetSelfProcess()));
#endif // OS_ANDROID || OS_LINUX || OS_CHROMEOS
char str[4] = "ABC";
char out[4];

View File

@ -34,6 +34,11 @@
#include "test/mac/mach_multiprocess.h"
#endif // defined(OS_APPLE)
#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
#include "test/linux/fake_ptrace_connection.h"
#include "util/linux/direct_ptrace_connection.h"
#endif // OS_ANDROID || OS_LINUX || OS_CHROMEOS
namespace crashpad {
namespace test {
namespace {
@ -148,8 +153,14 @@ class ReadTest : public MultiprocessAdaptor {
}
void DoTest(ProcessType process, size_t region_size, VMAddress address) {
#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
FakePtraceConnection connection;
ASSERT_TRUE(connection.Initialize(process));
ProcessMemoryLinux memory(&connection);
#else
ProcessMemoryNative memory;
ASSERT_TRUE(memory.Initialize(process));
#endif // OS_ANDROID || OS_LINUX || OS_CHROMEOS
std::unique_ptr<char[]> result(new char[region_size]);
@ -328,8 +339,14 @@ class ReadCStringTest : public MultiprocessAdaptor {
VMAddress local_empty_address,
VMAddress local_short_address,
VMAddress long_string_address) {
#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
FakePtraceConnection connection;
ASSERT_TRUE(connection.Initialize(process));
ProcessMemoryLinux memory(&connection);
#else
ProcessMemoryNative memory;
ASSERT_TRUE(memory.Initialize(process));
#endif // OS_ANDROID || OS_LINUX || OS_CHROMEOS
Compare(memory, const_empty_address, kConstCharEmpty);
Compare(memory, const_short_address, kConstCharShort);
@ -399,8 +416,14 @@ class ReadUnmappedTest : public MultiprocessAdaptor {
}
void DoTest(ProcessType process, VMAddress address) {
#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
DirectPtraceConnection connection;
ASSERT_TRUE(connection.Initialize(process));
ProcessMemoryLinux memory(&connection);
#else
ProcessMemoryNative memory;
ASSERT_TRUE(memory.Initialize(process));
#endif // OS_ANDROID || OS_LINUX || OS_CHROMEOS
VMAddress page_addr1 = address;
VMAddress page_addr2 = page_addr1 + base::GetPageSize();
@ -525,8 +548,14 @@ class ReadCStringUnmappedTest : public MultiprocessAdaptor {
void DoTest(ProcessType process,
const std::vector<StringDataInChildProcess>& strings) {
#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
DirectPtraceConnection connection;
ASSERT_TRUE(connection.Initialize(process));
ProcessMemoryLinux memory(&connection);
#else
ProcessMemoryNative memory;
ASSERT_TRUE(memory.Initialize(process));
#endif // OS_ANDROID || OS_LINUX || OS_CHROMEOS
std::string result;
result.reserve(kChildProcessStringLength + 1);