Module Name:    src
Committed By:   yamt
Date:           Sun Oct 31 05:03:12 UTC 2010

Modified Files:
        src/external/bsd/libelf/dist: _libelf.h elf_begin.c elf_end.c

Log Message:
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.


To generate a diff of this commit:
cvs rdiff -u -r1.5 -r1.6 src/external/bsd/libelf/dist/_libelf.h
cvs rdiff -u -r1.6 -r1.7 src/external/bsd/libelf/dist/elf_begin.c
cvs rdiff -u -r1.2 -r1.3 src/external/bsd/libelf/dist/elf_end.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/external/bsd/libelf/dist/_libelf.h
diff -u src/external/bsd/libelf/dist/_libelf.h:1.5 src/external/bsd/libelf/dist/_libelf.h:1.6
--- src/external/bsd/libelf/dist/_libelf.h:1.5	Tue Mar  2 21:08:36 2010
+++ src/external/bsd/libelf/dist/_libelf.h	Sun Oct 31 05:03:12 2010
@@ -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 */

Index: src/external/bsd/libelf/dist/elf_begin.c
diff -u src/external/bsd/libelf/dist/elf_begin.c:1.6 src/external/bsd/libelf/dist/elf_begin.c:1.7
--- src/external/bsd/libelf/dist/elf_begin.c:1.6	Mon Feb 22 10:59:08 2010
+++ src/external/bsd/libelf/dist/elf_begin.c	Sun Oct 31 05:03:12 2010
@@ -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);
-		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;
 

Index: src/external/bsd/libelf/dist/elf_end.c
diff -u src/external/bsd/libelf/dist/elf_end.c:1.2 src/external/bsd/libelf/dist/elf_end.c:1.3
--- src/external/bsd/libelf/dist/elf_end.c:1.2	Mon Feb 22 10:48:32 2010
+++ src/external/bsd/libelf/dist/elf_end.c	Sun Oct 31 05:03:12 2010
@@ -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)

Reply via email to