summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJose E. Marchesi <[email protected]>2015-10-09 12:35:27 +0200
committerMark Wielaard <[email protected]>2015-10-09 15:42:34 +0200
commitf17d101232d6d40e192e61441aa02a12ee8cf9b8 (patch)
treee8eee39052fc32f43be1e94d9800d79f04c42d08
parent57fa86e08bdd901c0b42cc97947e620334f6ef68 (diff)
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 <[email protected]>
-rw-r--r--libdwfl/ChangeLog5
-rw-r--r--libdwfl/linux-proc-maps.c15
2 files changed, 16 insertions, 4 deletions
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index ee41405e..211f9ecd 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,8 @@
+2015-10-09 Jose E. Marchesi <[email protected]>
+
+ * linux-proc-maps.c (read_proc_memory): Use seek+read instead of
+ pread, as the later doesn't accept negative offsets.
+
2015-10-07 Mark Wielaard <[email protected]>
* dwfl_module_getdwarf.c (MAX): Removed.
diff --git a/libdwfl/linux-proc-maps.c b/libdwfl/linux-proc-maps.c
index d0858342..2a65db2e 100644
--- a/libdwfl/linux-proc-maps.c
+++ b/libdwfl/linux-proc-maps.c
@@ -315,10 +315,17 @@ 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);
- /* Some kernels don't actually let us do this read, ignore those errors. */
- if (nread < 0 && (errno == EINVAL || errno == EPERM))
- return 0;
+
+ /* 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 -1;
+
+ ssize_t nread = read (fd, data, maxread);
+
if (nread > 0 && (size_t) nread < minread)
nread = 0;
return nread;