summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoryamt <yamt@NetBSD.org>2010-10-31 05:03:12 +0000
committeryamt <yamt@NetBSD.org>2010-10-31 05:03:12 +0000
commitd76c56428e53704fdb4feadfac1ac3dbf256bca9 (patch)
tree1c674ef94020c49351e267fff8ca892224f81a6c
parent8b0659e73124bebd60b6c3364f18c74c6d66497a (diff)
fall back to malloc+pread when stat+malloc doesn't seem to work.
it allows libelf work on /dev/ksyms. XXX the name of the flag is a bit confusing and i think it's better to rename MALLOCED to DATA_MALLOCED or such. but i don't think it's worth increasing the diff against the upstream for it.
-rw-r--r--external/bsd/libelf/dist/_libelf.h3
-rw-r--r--external/bsd/libelf/dist/elf_begin.c77
-rw-r--r--external/bsd/libelf/dist/elf_end.c4
3 files changed, 75 insertions, 9 deletions
diff --git a/external/bsd/libelf/dist/_libelf.h b/external/bsd/libelf/dist/_libelf.h
index 21753200e35..8013ea29f70 100644
--- a/external/bsd/libelf/dist/_libelf.h
+++ b/external/bsd/libelf/dist/_libelf.h
@@ -1,4 +1,4 @@
-/* $NetBSD: _libelf.h,v 1.5 2010/03/02 21:08:36 darran Exp $ */
+/* $NetBSD: _libelf.h,v 1.6 2010/10/31 05:03:12 yamt Exp $ */
/*-
* Copyright (c) 2006 Joseph Koshy
@@ -75,6 +75,7 @@ extern struct _libelf_globals _libelf;
#define LIBELF_F_MALLOCED 0x010000 /* whether data was malloc'ed */
#define LIBELF_F_MMAP 0x020000 /* whether e_rawfile was mmap'ed */
#define LIBELF_F_SHDRS_LOADED 0x040000 /* whether all shdrs were read in */
+#define LIBELF_F_MALLOC 0x080000 /* whether e_rawfile was mmap'ed */
struct _Elf {
int e_activations; /* activation count */
diff --git a/external/bsd/libelf/dist/elf_begin.c b/external/bsd/libelf/dist/elf_begin.c
index 0f572783c57..f078d6c86d9 100644
--- a/external/bsd/libelf/dist/elf_begin.c
+++ b/external/bsd/libelf/dist/elf_begin.c
@@ -1,4 +1,4 @@
-/* $NetBSD: elf_begin.c,v 1.6 2010/02/22 10:59:08 darran Exp $ */
+/* $NetBSD: elf_begin.c,v 1.7 2010/10/31 05:03:12 yamt Exp $ */
/*-
* Copyright (c) 2006 Joseph Koshy
@@ -41,6 +41,9 @@
#include <err.h>
#include <errno.h>
#include <libelf.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <unistd.h>
#include "_libelf.h"
@@ -49,7 +52,9 @@ _libelf_open_object(int fd, Elf_Cmd c)
{
Elf *e;
void *m;
+ void *p; /* malloc'ed pointer */
struct stat sb;
+ size_t objsize;
/*
* 'Raw' files are always mapped with 'PROT_READ'. At
@@ -63,18 +68,76 @@ _libelf_open_object(int fd, Elf_Cmd c)
}
m = NULL;
- if ((m = mmap(NULL, (size_t) sb.st_size, PROT_READ, MAP_PRIVATE, fd,
+ p = NULL;
+ if (sb.st_size == 0) {
+ /*
+ * Might be a special device like /dev/ksyms. Try read(2)ing.
+ */
+ goto doread;
+ }
+ objsize = (size_t) sb.st_size;
+ if ((m = mmap(NULL, objsize, PROT_READ, MAP_PRIVATE, fd,
(off_t) 0)) == MAP_FAILED) {
- LIBELF_SET_ERROR(IO, errno);
- return (NULL);
+ size_t bufsize;
+
+ if (errno != EINVAL) {
+ LIBELF_SET_ERROR(IO, errno);
+ return (NULL);
+ }
+doread:
+ /*
+ * Fall back to malloc+read.
+ */
+ bufsize = 1024 * 1024;
+ while (/*CONSTCOND*/true) {
+ void *newp = realloc(p, bufsize);
+ ssize_t rsz;
+
+ if (newp == NULL) {
+ free(p);
+ LIBELF_SET_ERROR(RESOURCE, 0);
+ return (NULL);
+ }
+ p = newp;
+ rsz = pread(fd, p, bufsize, 0);
+ if (rsz == -1) {
+ free(p);
+ LIBELF_SET_ERROR(IO, errno);
+ return (NULL);
+ } else if ((size_t) rsz > bufsize) {
+ free(p);
+ LIBELF_SET_ERROR(IO, EIO); /* XXX */
+ return (NULL);
+ } else if ((size_t) rsz < bufsize) {
+ /*
+ * try to shrink the buffer.
+ */
+ newp = realloc(p, (size_t) rsz);
+ if (newp != NULL) {
+ p = newp;
+ }
+ break;
+ }
+ bufsize *= 2;
+ }
+ m = p;
+ objsize = bufsize;
}
- if ((e = elf_memory(m, (size_t) sb.st_size)) == NULL) {
- (void) munmap(m, (size_t) sb.st_size);
+ if ((e = elf_memory(m, objsize)) == NULL) {
+ if (p != NULL) {
+ free(p);
+ } else {
+ (void) munmap(m, objsize);
+ }
return (NULL);
}
- e->e_flags |= LIBELF_F_MMAP;
+ if (p != NULL) {
+ e->e_flags |= LIBELF_F_MALLOC;
+ } else {
+ e->e_flags |= LIBELF_F_MMAP;
+ }
e->e_fd = fd;
e->e_cmd = c;
diff --git a/external/bsd/libelf/dist/elf_end.c b/external/bsd/libelf/dist/elf_end.c
index 916cf40549b..74354c83cce 100644
--- a/external/bsd/libelf/dist/elf_end.c
+++ b/external/bsd/libelf/dist/elf_end.c
@@ -1,4 +1,4 @@
-/* $NetBSD: elf_end.c,v 1.2 2010/02/22 10:48:32 darran Exp $ */
+/* $NetBSD: elf_end.c,v 1.3 2010/10/31 05:03:12 yamt Exp $ */
/*-
* Copyright (c) 2006 Joseph Koshy
@@ -82,6 +82,8 @@ elf_end(Elf *e)
if (e->e_flags & LIBELF_F_MMAP)
(void) munmap(e->e_rawfile, e->e_rawsize);
+ if (e->e_flags & LIBELF_F_MALLOC)
+ (void) free(e->e_rawfile);
sv = e;
if ((e = e->e_parent) != NULL)