fuchsia: Add implemention of ProcessMemory

Bug: crashpad:196
Change-Id: I04a29afcbb16b5ef14d6f83d7af1d954f5164ee9
Reviewed-on: https://chromium-review.googlesource.com/868736
Reviewed-by: Mark Mentovai <mark@chromium.org>
Reviewed-by: Joshua Peraza <jperaza@chromium.org>
Commit-Queue: Scott Graham <scottmg@chromium.org>
This commit is contained in:
Scott Graham 2018-01-16 14:46:29 -08:00 committed by Commit Bot
parent 970ac5a636
commit 4d2414e38e
10 changed files with 214 additions and 50 deletions

View File

@ -276,6 +276,13 @@ static_library("util") {
"posix/process_info_linux.cc",
"process/process_memory_linux.cc",
"process/process_memory_linux.h",
]
}
if (crashpad_is_linux || crashpad_is_android || crashpad_is_fuchsia) {
sources += [
"process/process_memory.cc",
"process/process_memory.h",
# TODO: Port to all platforms.
"process/process_memory_range.cc",
@ -364,6 +371,8 @@ static_library("util") {
sources += [
"misc/paths_fuchsia.cc",
"net/http_transport_fuchsia.cc",
"process/process_memory_fuchsia.cc",
"process/process_memory_fuchsia.h",
]
}
@ -509,7 +518,11 @@ source_set("util_test") {
"linux/ptrace_broker_test.cc",
"linux/ptracer_test.cc",
"linux/scoped_ptrace_attach_test.cc",
]
}
if (crashpad_is_linux || crashpad_is_android || crashpad_is_fuchsia) {
sources += [
# TODO: Port to all platforms.
"process/process_memory_range_test.cc",
"process/process_memory_test.cc",

View File

@ -27,6 +27,8 @@
#include "util/win/address_types.h"
#elif defined(OS_LINUX) || defined(OS_ANDROID)
#include "util/linux/address_types.h"
#elif defined(OS_FUCHSIA)
#include <zircon/types.h>
#else
#error "Unhandled OS type"
#endif
@ -58,6 +60,11 @@ using VMSize = WinVMSize;
using VMAddress = LinuxVMAddress;
using VMSize = LinuxVMSize;
#elif defined(OS_FUCHSIA)
using VMAddress = zx_vaddr_t;
using VMSize = size_t;
#endif
//! \brief Type used to represent an offset from a VMAddress, potentially

View File

@ -0,0 +1,55 @@
// 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 "util/process/process_memory.h"
#include "base/logging.h"
namespace crashpad {
bool ProcessMemory::ReadCStringInternal(VMAddress address,
bool has_size,
size_t size,
std::string* string) const {
string->clear();
char buffer[4096];
do {
size_t read_size;
if (has_size) {
read_size = std::min(sizeof(buffer), size);
} else {
read_size = sizeof(buffer);
}
if (!Read(address, read_size, buffer)) {
break;
}
char* nul = static_cast<char*>(memchr(buffer, '\0', read_size));
if (nul != nullptr) {
string->append(buffer, nul - buffer);
return true;
}
string->append(buffer, read_size);
address += read_size;
size -= read_size;
} while (!has_size || size > 0);
LOG(ERROR) << "unterminated string";
return false;
}
} // namespace crashpad

View File

@ -102,7 +102,7 @@ class ProcessMemory {
virtual bool ReadCStringInternal(VMAddress address,
bool has_size,
size_t size,
std::string* string) const = 0;
std::string* string) const;
};
} // namespace crashpad

View File

@ -0,0 +1,57 @@
// 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 "util/process/process_memory_fuchsia.h"
#include <zircon/syscalls.h>
#include "base/logging.h"
#include "base/fuchsia/fuchsia_logging.h"
namespace crashpad {
ProcessMemoryFuchsia::ProcessMemoryFuchsia()
: ProcessMemory(), process_(), initialized_() {}
ProcessMemoryFuchsia::~ProcessMemoryFuchsia() {}
bool ProcessMemoryFuchsia::Initialize(zx_handle_t process) {
INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
process_ = process;
INITIALIZATION_STATE_SET_VALID(initialized_);
return true;
}
bool ProcessMemoryFuchsia::Read(VMAddress address,
size_t size,
void* buffer) const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
size_t actual;
zx_status_t status =
zx_process_read_memory(process_, address, buffer, size, &actual);
if (status != ZX_OK) {
ZX_LOG(ERROR, status) << "zx_process_read_memory";
return false;
}
if (actual != size) {
LOG(ERROR) << "zx_process_read_memory: short read";
return false;
}
return true;
}
} // namespace crashpad

View File

@ -0,0 +1,56 @@
// 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_UTIL_PROCESS_PROCESS_MEMORY_FUCHSIA_H_
#define CRASHPAD_UTIL_PROCESS_PROCESS_MEMORY_FUCHSIA_H_
#include <zircon/types.h>
#include <string>
#include "base/macros.h"
#include "util/misc/address_types.h"
#include "util/misc/initialization_state_dcheck.h"
#include "util/process/process_memory.h"
namespace crashpad {
//! \brief Accesses the memory of another Fuchsia process.
class ProcessMemoryFuchsia final : public ProcessMemory {
public:
ProcessMemoryFuchsia();
~ProcessMemoryFuchsia();
//! \brief Initializes this object to read the memory of a process by handle.
//!
//! This method must be called successfully prior to calling any other method
//! in this class.
//!
//! \param[in] pid The handle to the target process.
//!
//! \return `true` on success, `false` on failure with a message logged.
bool Initialize(zx_handle_t process);
bool Read(VMAddress address, size_t size, void* buffer) const override;
private:
zx_handle_t process_;
InitializationStateDcheck initialized_;
DISALLOW_COPY_AND_ASSIGN(ProcessMemoryFuchsia);
};
} // namespace crashpad
#endif // CRASHPAD_UTIL_PROCESS_PROCESS_MEMORY_FUCHSIA_H_

View File

@ -27,11 +27,12 @@
namespace crashpad {
ProcessMemoryLinux::ProcessMemoryLinux()
: ProcessMemory(), mem_fd_(), pid_(-1) {}
: ProcessMemory(), mem_fd_(), pid_(-1), initialized_() {}
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_);
@ -40,12 +41,14 @@ bool ProcessMemoryLinux::Initialize(pid_t pid) {
PLOG(ERROR) << "open";
return false;
}
INITIALIZATION_STATE_SET_VALID(initialized_);
return true;
}
bool ProcessMemoryLinux::Read(VMAddress address,
size_t size,
void* buffer) const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
DCHECK(mem_fd_.is_valid());
char* buffer_c = static_cast<char*>(buffer);
@ -68,47 +71,4 @@ bool ProcessMemoryLinux::Read(VMAddress address,
return true;
}
bool ProcessMemoryLinux::ReadCStringInternal(VMAddress address,
bool has_size,
size_t size,
std::string* string) const {
DCHECK(mem_fd_.is_valid());
string->clear();
char buffer[4096];
do {
size_t read_size;
if (has_size) {
read_size = std::min(sizeof(buffer), size);
} else {
read_size = sizeof(buffer);
}
ssize_t bytes_read;
bytes_read =
HANDLE_EINTR(pread64(mem_fd_.get(), buffer, read_size, address));
if (bytes_read < 0) {
PLOG(ERROR) << "pread64";
return false;
}
if (bytes_read == 0) {
break;
}
DCHECK_LE(static_cast<size_t>(bytes_read), read_size);
char* nul = static_cast<char*>(memchr(buffer, '\0', bytes_read));
if (nul != nullptr) {
string->append(buffer, nul - buffer);
return true;
}
string->append(buffer, bytes_read);
address += bytes_read;
size -= bytes_read;
} while (!has_size || size > 0);
LOG(ERROR) << "unterminated string";
return false;
}
} // namespace crashpad

View File

@ -22,6 +22,7 @@
#include "base/files/scoped_file.h"
#include "base/macros.h"
#include "util/misc/address_types.h"
#include "util/misc/initialization_state_dcheck.h"
#include "util/process/process_memory.h"
namespace crashpad {
@ -46,13 +47,9 @@ class ProcessMemoryLinux final : public ProcessMemory {
bool Read(VMAddress address, size_t size, void* buffer) const override;
private:
bool ReadCStringInternal(VMAddress address,
bool has_size,
size_t size,
std::string* string) const override;
base::ScopedFD mem_fd_;
pid_t pid_;
InitializationStateDcheck initialized_;
DISALLOW_COPY_AND_ASSIGN(ProcessMemoryLinux);
};

View File

@ -22,7 +22,14 @@
#include "build/build_config.h"
#include "gtest/gtest.h"
#include "util/misc/from_pointer_cast.h"
#if defined(OS_FUCHSIA)
#include <zircon/process.h>
#include "util/process/process_memory_fuchsia.h"
#else
#include "util/process/process_memory_linux.h"
#endif
namespace crashpad {
namespace test {
@ -34,6 +41,11 @@ struct TestObject {
} kTestObject = {"string1", "string2"};
TEST(ProcessMemoryRange, Basic) {
#if defined(OS_FUCHSIA)
ProcessMemoryFuchsia memory;
ASSERT_TRUE(memory.Initialize(zx_process_self()));
constexpr bool is_64_bit = true;
#else
pid_t pid = getpid();
#if defined(ARCH_CPU_64_BITS)
constexpr bool is_64_bit = true;
@ -43,6 +55,7 @@ TEST(ProcessMemoryRange, Basic) {
ProcessMemoryLinux memory;
ASSERT_TRUE(memory.Initialize(pid));
#endif // OS_FUCHSIA
ProcessMemoryRange range;
ASSERT_TRUE(range.Initialize(&memory, is_64_bit));

View File

@ -32,6 +32,10 @@ namespace crashpad {
namespace test {
namespace {
// TODO(scottmg): https://crashpad.chromium.org/bug/196. Multiprocess isn't
// ported yet.
#if !defined(OS_FUCHSIA)
class TargetProcessTest : public Multiprocess {
public:
TargetProcessTest() : Multiprocess() {}
@ -400,6 +404,8 @@ TEST(ProcessMemory, ReadCStringSizeLimitedUnmappedForked) {
test.RunAgainstForked();
}
#endif // !defined(OS_FUCHSIA)
} // namespace
} // namespace test
} // namespace crashpad