forked from OSchip/llvm-project
[NativeProcessLinux] Use fast memory reads, if the system supports it
Summary: Memory reads using the ptrace API need to be executed on a designated thread and in 4-byte increments. The process_vm_read syscall has no such requirements and it is about 50 times faster. This patch makes lldb-server use the faster API if the target kernel supports it. Kernel support for this feature is determined at runtime. Using process_vm_writev in the same manner is more complicated since this syscall (unlike ptrace) respects page protection settings and so it cannot be used to set a breakpoint, since code pages are typically read-only. However, memory writes are not currently a performance bottleneck as they happen much more rarely. Test Plan: all tests continue to pass Reviewers: ovyalov, vharron Subscribers: tberghammer, lldb-commits Differential Revision: http://reviews.llvm.org/D10488 llvm-svn: 239924
This commit is contained in:
parent
4fc603ded3
commit
df7c69952b
|
@ -0,0 +1,23 @@
|
|||
//===-- Uio.h ---------------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef liblldb_Host_linux_Uio_h_
|
||||
#define liblldb_Host_linux_Uio_h_
|
||||
|
||||
#include <sys/uio.h>
|
||||
|
||||
// Android does not define the process_vm_readv wrapper
|
||||
#ifdef __ANDROID_NDK__
|
||||
ssize_t process_vm_readv(::pid_t pid,
|
||||
const struct iovec *local_iov, unsigned long liovcnt,
|
||||
const struct iovec *remote_iov, unsigned long riovcnt,
|
||||
unsigned long flags);
|
||||
#endif
|
||||
|
||||
#endif // liblldb_Host_linux_Uio_h_
|
|
@ -11,12 +11,14 @@
|
|||
|
||||
#include <android/api-level.h>
|
||||
|
||||
#include <sys/syscall.h>
|
||||
#include <lldb/Host/linux/Uio.h>
|
||||
|
||||
#if __ANDROID_API__ < 21
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "lldb/Host/Time.h"
|
||||
|
@ -37,3 +39,11 @@ int posix_openpt(int flags)
|
|||
}
|
||||
|
||||
#endif
|
||||
|
||||
ssize_t process_vm_readv(::pid_t pid,
|
||||
const struct iovec *local_iov, unsigned long liovcnt,
|
||||
const struct iovec *remote_iov, unsigned long riovcnt,
|
||||
unsigned long flags)
|
||||
{
|
||||
return syscall(__NR_process_vm_readv, pid, local_iov, liovcnt, remote_iov, riovcnt, flags);
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
// C++ Includes
|
||||
#include <fstream>
|
||||
#include <mutex>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
@ -52,14 +53,15 @@
|
|||
#include <linux/unistd.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/user.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "lldb/Host/linux/Personality.h"
|
||||
#include "lldb/Host/linux/Ptrace.h"
|
||||
#include "lldb/Host/linux/Signalfd.h"
|
||||
#include "lldb/Host/linux/Uio.h"
|
||||
#include "lldb/Host/android/Android.h"
|
||||
|
||||
#define LLDB_PERSONALITY_GET_CURRENT_SETTINGS 0xffffffff
|
||||
|
@ -75,6 +77,40 @@ using namespace lldb_private::process_linux;
|
|||
using namespace llvm;
|
||||
|
||||
// Private bits we only need internally.
|
||||
|
||||
static bool ProcessVmReadvSupported()
|
||||
{
|
||||
static bool is_supported;
|
||||
static std::once_flag flag;
|
||||
|
||||
std::call_once(flag, [] {
|
||||
Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
|
||||
|
||||
uint32_t source = 0x47424742;
|
||||
uint32_t dest = 0;
|
||||
|
||||
struct iovec local, remote;
|
||||
remote.iov_base = &source;
|
||||
local.iov_base = &dest;
|
||||
remote.iov_len = local.iov_len = sizeof source;
|
||||
|
||||
// We shall try if cross-process-memory reads work by attempting to read a value from our own process.
|
||||
ssize_t res = process_vm_readv(getpid(), &local, 1, &remote, 1, 0);
|
||||
is_supported = (res == sizeof(source) && source == dest);
|
||||
if (log)
|
||||
{
|
||||
if (is_supported)
|
||||
log->Printf("%s: Detected kernel support for process_vm_readv syscall. Fast memory reads enabled.",
|
||||
__FUNCTION__);
|
||||
else
|
||||
log->Printf("%s: syscall process_vm_readv failed (error: %s). Fast memory reads disabled.",
|
||||
__FUNCTION__, strerror(errno));
|
||||
}
|
||||
});
|
||||
|
||||
return is_supported;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
const UnixSignals&
|
||||
|
@ -242,7 +278,6 @@ namespace
|
|||
log->Printf ("NativeProcessLinux::%s() [%p]:0x%lx (0x%lx)", __FUNCTION__,
|
||||
(void*)vm_addr, print_dst, (unsigned long)data);
|
||||
}
|
||||
|
||||
vm_addr += word_size;
|
||||
dst += word_size;
|
||||
}
|
||||
|
@ -3245,6 +3280,32 @@ NativeProcessLinux::RemoveWatchpoint (lldb::addr_t addr)
|
|||
Error
|
||||
NativeProcessLinux::ReadMemory (lldb::addr_t addr, void *buf, size_t size, size_t &bytes_read)
|
||||
{
|
||||
if (ProcessVmReadvSupported()) {
|
||||
// The process_vm_readv path is about 50 times faster than ptrace api. We want to use
|
||||
// this syscall if it is supported.
|
||||
|
||||
const ::pid_t pid = GetID();
|
||||
|
||||
struct iovec local_iov, remote_iov;
|
||||
local_iov.iov_base = buf;
|
||||
local_iov.iov_len = size;
|
||||
remote_iov.iov_base = reinterpret_cast<void *>(addr);
|
||||
remote_iov.iov_len = size;
|
||||
|
||||
bytes_read = process_vm_readv(pid, &local_iov, 1, &remote_iov, 1, 0);
|
||||
const bool success = bytes_read == size;
|
||||
|
||||
Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
|
||||
if (log)
|
||||
log->Printf ("NativeProcessLinux::%s using process_vm_readv to read %zd bytes from inferior address 0x%" PRIx64": %s",
|
||||
__FUNCTION__, size, addr, success ? "Success" : strerror(errno));
|
||||
|
||||
if (success)
|
||||
return Error();
|
||||
// else
|
||||
// the call failed for some reason, let's retry the read using ptrace api.
|
||||
}
|
||||
|
||||
ReadOperation op(addr, buf, size, bytes_read);
|
||||
m_monitor_up->DoOperation(&op);
|
||||
return op.GetError ();
|
||||
|
|
Loading…
Reference in New Issue