diff options
author | Pavel Labath <labath@google.com> | 2015-06-17 18:38:49 +0000 |
---|---|---|
committer | Pavel Labath <labath@google.com> | 2015-06-17 18:38:49 +0000 |
commit | df7c69952bd7e25993a09eccb00e206c65853874 (patch) | |
tree | 052201aff8fd8e55cbe6742598c16ca9ed975dc7 | |
parent | 4fc603ded3efb5d238f9355458a5722a7bf54e59 (diff) | |
download | bcm5719-llvm-df7c69952bd7e25993a09eccb00e206c65853874.tar.gz bcm5719-llvm-df7c69952bd7e25993a09eccb00e206c65853874.zip |
[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
-rw-r--r-- | lldb/include/lldb/Host/linux/Uio.h | 23 | ||||
-rw-r--r-- | lldb/source/Host/android/LibcGlue.cpp | 12 | ||||
-rw-r--r-- | lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp | 65 |
3 files changed, 97 insertions, 3 deletions
diff --git a/lldb/include/lldb/Host/linux/Uio.h b/lldb/include/lldb/Host/linux/Uio.h new file mode 100644 index 00000000000..5f2be074f54 --- /dev/null +++ b/lldb/include/lldb/Host/linux/Uio.h @@ -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_ diff --git a/lldb/source/Host/android/LibcGlue.cpp b/lldb/source/Host/android/LibcGlue.cpp index d443a92724e..d127d6b01ad 100644 --- a/lldb/source/Host/android/LibcGlue.cpp +++ b/lldb/source/Host/android/LibcGlue.cpp @@ -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); +} diff --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp index c1800003551..f6cefa9e001 100644 --- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp +++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp @@ -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 (); |