dnl Process this file with autoconf to produce a configure script.
dnl Configure input file for elfutils. -*-autoconf-*-
dnl
-dnl Copyright (C) 1996-2017 Red Hat, Inc.
+dnl Copyright (C) 1996-2018 Red Hat, Inc.
dnl
dnl This file is part of elfutils.
dnl
AC_CONFIG_AUX_DIR([config])
AC_CONFIG_FILES([config/Makefile])
-AC_COPYRIGHT([Copyright (C) 1996-2017 The elfutils developers.])
+AC_COPYRIGHT([Copyright (C) 1996-2018 The elfutils developers.])
AC_PREREQ(2.63) dnl Minimum Autoconf version required.
dnl We use GNU make extensions; automake 1.10 defaults to -Wportability.
[#define _GNU_SOURCE
#include <string.h>])
+AC_CHECK_FUNCS([process_vm_readv])
+
AC_CHECK_LIB([stdc++], [__cxa_demangle], [dnl
AC_DEFINE([USE_DEMANGLE], [1], [Defined if demangling is enabled])])
AM_CONDITIONAL(DEMANGLE, test "x$ac_cv_lib_stdcpp___cxa_demangle" = "xyes")
/* Internal definitions for libdwfl.
- Copyright (C) 2005-2015 Red Hat, Inc.
+ Copyright (C) 2005-2015, 2018 Red Hat, Inc.
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
size_t arange; /* Index in Dwarf_Aranges. */
};
+#define __LIBDWFL_REMOTE_MEM_CACHE_SIZE 4096
+/* Structure for caching remote memory reads as used by __libdwfl_pid_arg. */
+struct __libdwfl_remote_mem_cache
+{
+ Dwarf_Addr addr; /* Remote address. */
+ Dwarf_Off len; /* Zero if cleared, otherwise likely 4K. */
+ unsigned char buf[__LIBDWFL_REMOTE_MEM_CACHE_SIZE]; /* The actual cache. */
+};
/* Structure used for keeping track of ptrace attaching a thread.
Shared by linux-pid-attach and linux-proc-maps. If it has been setup
DIR *dir;
/* Elf for /proc/PID/exe. Set to NULL if it couldn't be opened. */
Elf *elf;
+ /* Remote memory cache, NULL if there is no memory cached.
+ Should be cleared on detachment (because that makes the thread
+ runnable and the cache invalid). */
+ struct __libdwfl_remote_mem_cache *mem_cache;
/* fd for /proc/PID/exe. Set to -1 if it couldn't be opened. */
int elf_fd;
/* It is 0 if not used. */
/* Get Dwarf Frame state for target live PID process.
- Copyright (C) 2013, 2014, 2015 Red Hat, Inc.
+ Copyright (C) 2013, 2014, 2015, 2018 Red Hat, Inc.
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
#include "libdwflP.h"
#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/uio.h>
#include <fcntl.h>
#include <dirent.h>
#include <unistd.h>
return true;
}
+#ifdef HAVE_PROCESS_VM_READV
+/* Note that the result word size depends on the architecture word size.
+ That is sizeof long. */
+static bool
+read_cached_memory (struct __libdwfl_pid_arg *pid_arg,
+ Dwarf_Addr addr, Dwarf_Word *result)
+{
+ /* Let the ptrace fallback deal with the corner case of the address
+ possibly crossing a page boundery. */
+ if ((addr & ((Dwarf_Addr)__LIBDWFL_REMOTE_MEM_CACHE_SIZE - 1))
+ > (Dwarf_Addr)__LIBDWFL_REMOTE_MEM_CACHE_SIZE - sizeof (unsigned long))
+ return false;
+
+ struct __libdwfl_remote_mem_cache *mem_cache = pid_arg->mem_cache;
+ if (mem_cache == NULL)
+ {
+ size_t mem_cache_size = sizeof (struct __libdwfl_remote_mem_cache);
+ mem_cache = (struct __libdwfl_remote_mem_cache *) malloc (mem_cache_size);
+ if (mem_cache == NULL)
+ return false;
+
+ mem_cache->addr = 0;
+ mem_cache->len = 0;
+ pid_arg->mem_cache = mem_cache;
+ }
+
+ unsigned char *d;
+ if (addr >= mem_cache->addr && addr - mem_cache->addr < mem_cache->len)
+ {
+ d = &mem_cache->buf[addr - mem_cache->addr];
+ if ((((uintptr_t) d) & (sizeof (unsigned long) - 1)) == 0)
+ *result = *(unsigned long *) d;
+ else
+ memcpy (result, d, sizeof (unsigned long));
+ return true;
+ }
+
+ struct iovec local, remote;
+ mem_cache->addr = addr & ~((Dwarf_Addr)__LIBDWFL_REMOTE_MEM_CACHE_SIZE - 1);
+ local.iov_base = mem_cache->buf;
+ local.iov_len = __LIBDWFL_REMOTE_MEM_CACHE_SIZE;
+ remote.iov_base = (void *) (uintptr_t) mem_cache->addr;
+ remote.iov_len = __LIBDWFL_REMOTE_MEM_CACHE_SIZE;
+
+ ssize_t res = process_vm_readv (pid_arg->tid_attached,
+ &local, 1, &remote, 1, 0);
+ if (res != __LIBDWFL_REMOTE_MEM_CACHE_SIZE)
+ {
+ mem_cache->len = 0;
+ return false;
+ }
+
+ mem_cache->len = res;
+ d = &mem_cache->buf[addr - mem_cache->addr];
+ if ((((uintptr_t) d) & (sizeof (unsigned long) - 1)) == 0)
+ *result = *(unsigned long *) d;
+ else
+ memcpy (result, d, sizeof (unsigned long));
+ return true;
+}
+#endif /* HAVE_PROCESS_VM_READV */
+
+static void
+clear_cached_memory (struct __libdwfl_pid_arg *pid_arg)
+{
+ struct __libdwfl_remote_mem_cache *mem_cache = pid_arg->mem_cache;
+ if (mem_cache != NULL)
+ mem_cache->len = 0;
+}
+
+/* Note that the result word size depends on the architecture word size.
+ That is sizeof long. */
static bool
pid_memory_read (Dwfl *dwfl, Dwarf_Addr addr, Dwarf_Word *result, void *arg)
{
struct __libdwfl_pid_arg *pid_arg = arg;
pid_t tid = pid_arg->tid_attached;
assert (tid > 0);
+
+#ifdef HAVE_PROCESS_VM_READV
+ if (read_cached_memory (pid_arg, addr, result))
+ return true;
+#endif
+
Dwfl_Process *process = dwfl->process;
if (ebl_get_elfclass (process->ebl) == ELFCLASS64)
{
{
struct __libdwfl_pid_arg *pid_arg = dwfl_arg;
elf_end (pid_arg->elf);
+ free (pid_arg->mem_cache);
close (pid_arg->elf_fd);
closedir (pid_arg->dir);
free (pid_arg);
pid_t tid = INTUSE(dwfl_thread_tid) (thread);
assert (pid_arg->tid_attached == tid);
pid_arg->tid_attached = 0;
+ clear_cached_memory (pid_arg);
if (! pid_arg->assume_ptrace_stopped)
__libdwfl_ptrace_detach (tid, pid_arg->tid_was_stopped);
}
pid_arg->dir = dir;
pid_arg->elf = elf;
pid_arg->elf_fd = elf_fd;
+ pid_arg->mem_cache = NULL;
pid_arg->tid_attached = 0;
pid_arg->assume_ptrace_stopped = assume_ptrace_stopped;
if (! INTUSE(dwfl_attach_state) (dwfl, elf, pid, &pid_thread_callbacks,