Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/external/bsd/libelf/dist fall back to malloc+pread when stat...



details:   https://anonhg.NetBSD.org/src/rev/0b8fff7d1d44
branches:  trunk
changeset: 758281:0b8fff7d1d44
user:      yamt <yamt%NetBSD.org@localhost>
date:      Sun Oct 31 05:03:12 2010 +0000

description:
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.

diffstat:

 external/bsd/libelf/dist/_libelf.h   |   3 +-
 external/bsd/libelf/dist/elf_begin.c |  79 ++++++++++++++++++++++++++++++++---
 external/bsd/libelf/dist/elf_end.c   |   4 +-
 3 files changed, 76 insertions(+), 10 deletions(-)

diffs (148 lines):

diff -r 7c9df2c27b60 -r 0b8fff7d1d44 external/bsd/libelf/dist/_libelf.h
--- a/external/bsd/libelf/dist/_libelf.h        Sun Oct 31 04:51:19 2010 +0000
+++ b/external/bsd/libelf/dist/_libelf.h        Sun Oct 31 05:03:12 2010 +0000
@@ -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 @@
 #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 -r 7c9df2c27b60 -r 0b8fff7d1d44 external/bsd/libelf/dist/elf_begin.c
--- a/external/bsd/libelf/dist/elf_begin.c      Sun Oct 31 04:51:19 2010 +0000
+++ b/external/bsd/libelf/dist/elf_begin.c      Sun Oct 31 05:03:12 2010 +0000
@@ -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 @@
 {
        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 @@
        }
 
        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);
+               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, objsize)) == NULL) {
+               if (p != NULL) {
+                       free(p);
+               } else {
+                       (void) munmap(m, objsize);
+               }
                return (NULL);
        }
 
-       if ((e = elf_memory(m, (size_t) sb.st_size)) == NULL) {
-               (void) munmap(m, (size_t) sb.st_size);
-               return (NULL);
+       if (p != NULL) {
+               e->e_flags |= LIBELF_F_MALLOC;
+       } else {
+               e->e_flags |= LIBELF_F_MMAP;
        }
-
-       e->e_flags |= LIBELF_F_MMAP;
        e->e_fd = fd;
        e->e_cmd = c;
 
diff -r 7c9df2c27b60 -r 0b8fff7d1d44 external/bsd/libelf/dist/elf_end.c
--- a/external/bsd/libelf/dist/elf_end.c        Sun Oct 31 04:51:19 2010 +0000
+++ b/external/bsd/libelf/dist/elf_end.c        Sun Oct 31 05:03:12 2010 +0000
@@ -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 @@
 
                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)



Home | Main Index | Thread Index | Old Index