From df7c69952bd7e25993a09eccb00e206c65853874 Mon Sep 17 00:00:00 2001 From: Pavel Labath Date: Wed, 17 Jun 2015 18:38:49 +0000 Subject: [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 --- .../Plugins/Process/Linux/NativeProcessLinux.cpp | 65 +++++++++++++++++++++- 1 file changed, 63 insertions(+), 2 deletions(-) (limited to 'lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp') diff --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp index c18000035512..f6cefa9e001c 100644 --- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp +++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp @@ -18,6 +18,7 @@ // C++ Includes #include +#include #include #include #include @@ -52,14 +53,15 @@ #include #include +#include #include -#include #include #include #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(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 (); -- cgit v1.2.3