--- /dev/null
+//===-- 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_
#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"
}
#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);
+}
// C++ Includes
#include <fstream>
+#include <mutex>
#include <sstream>
#include <string>
#include <unordered_map>
#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
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&
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;
}
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 ();