This is the mail archive of the
elfutils-devel@sourceware.org
mailing list for the elfutils project.
[PATCH 5/5] Use seek+read instead of pread to read from /dev/$$/mem files.
- From: Jose E. Marchesi <jose dot marchesi at oracle dot com>
- To: elfutils-devel at lists dot fedorahosted dot org
- Date: Mon, 05 Oct 2015 17:36:34 +0200
- Subject: [PATCH 5/5] Use seek+read instead of pread to read from /dev/$$/mem files.
pread[64] always returns EINVAL when negative offsets are used.
read+seek allows us to read in-memory vdso objects mapped high in the
address space.
Signed-off-by: Jose E. Marchesi <jose.marchesi@oracle.com>
---
libdwfl/ChangeLog | 5 +++++
libdwfl/linux-proc-maps.c | 14 ++++++++++++--
2 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index ed1156e..355c750 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,8 @@
+2015-10-05 Jose E. Marchesi <jose.marchesi@oracle.com>
+
+ * linux-proc-maps.c (read_proc_memory): Use seek+read instead of
+ pread, as the later doesn't accept negative offsets.
+
2015-09-18 Chih-Hung Hsieh <chh@google.com>
* relocate.c (relocate_section): Move nested function "relocate"
diff --git a/libdwfl/linux-proc-maps.c b/libdwfl/linux-proc-maps.c
index d085834..83b90db 100644
--- a/libdwfl/linux-proc-maps.c
+++ b/libdwfl/linux-proc-maps.c
@@ -315,9 +315,19 @@ read_proc_memory (void *arg, void *data, GElf_Addr address,
size_t minread, size_t maxread)
{
const int fd = *(const int *) arg;
- ssize_t nread = pread64 (fd, data, maxread, (off64_t) address);
+
+ /* This code relies on the fact the Linux kernel accepts negative
+ offsets when seeking /dev/$$/mem files, as a special case. In
+ particular pread[64] cannot be used here, because it will always
+ return EINVAL when passed a negative offset. */
+
+ if (lseek (fd, (off64_t) address, SEEK_SET) == -1)
+ return 0;
+
+ ssize_t nread = read (fd, data, maxread);
+
/* Some kernels don't actually let us do this read, ignore those errors. */
- if (nread < 0 && (errno == EINVAL || errno == EPERM))
+ if (nread < 0)
return 0;
if (nread > 0 && (size_t) nread < minread)
nread = 0;
--
2.3.4