xref: /minix3/external/bsd/elftoolchain/dist/libelf/libelf_open.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: libelf_open.c,v 1.2 2014/03/09 16:58:04 christos Exp $	*/
2*0a6a1f1dSLionel Sambuc 
3*0a6a1f1dSLionel Sambuc /*-
4*0a6a1f1dSLionel Sambuc  * Copyright (c) 2006,2008-2011 Joseph Koshy
5*0a6a1f1dSLionel Sambuc  * All rights reserved.
6*0a6a1f1dSLionel Sambuc  *
7*0a6a1f1dSLionel Sambuc  * Redistribution and use in source and binary forms, with or without
8*0a6a1f1dSLionel Sambuc  * modification, are permitted provided that the following conditions
9*0a6a1f1dSLionel Sambuc  * are met:
10*0a6a1f1dSLionel Sambuc  * 1. Redistributions of source code must retain the above copyright
11*0a6a1f1dSLionel Sambuc  *    notice, this list of conditions and the following disclaimer.
12*0a6a1f1dSLionel Sambuc  * 2. Redistributions in binary form must reproduce the above copyright
13*0a6a1f1dSLionel Sambuc  *    notice, this list of conditions and the following disclaimer in the
14*0a6a1f1dSLionel Sambuc  *    documentation and/or other materials provided with the distribution.
15*0a6a1f1dSLionel Sambuc  *
16*0a6a1f1dSLionel Sambuc  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17*0a6a1f1dSLionel Sambuc  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*0a6a1f1dSLionel Sambuc  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*0a6a1f1dSLionel Sambuc  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20*0a6a1f1dSLionel Sambuc  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21*0a6a1f1dSLionel Sambuc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22*0a6a1f1dSLionel Sambuc  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23*0a6a1f1dSLionel Sambuc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24*0a6a1f1dSLionel Sambuc  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25*0a6a1f1dSLionel Sambuc  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*0a6a1f1dSLionel Sambuc  * SUCH DAMAGE.
27*0a6a1f1dSLionel Sambuc  */
28*0a6a1f1dSLionel Sambuc 
29*0a6a1f1dSLionel Sambuc #if HAVE_NBTOOL_CONFIG_H
30*0a6a1f1dSLionel Sambuc # include "nbtool_config.h"
31*0a6a1f1dSLionel Sambuc #endif
32*0a6a1f1dSLionel Sambuc 
33*0a6a1f1dSLionel Sambuc #include <sys/types.h>
34*0a6a1f1dSLionel Sambuc #include <sys/stat.h>
35*0a6a1f1dSLionel Sambuc 
36*0a6a1f1dSLionel Sambuc #include <assert.h>
37*0a6a1f1dSLionel Sambuc #include <errno.h>
38*0a6a1f1dSLionel Sambuc #include <libelf.h>
39*0a6a1f1dSLionel Sambuc #include <stdlib.h>
40*0a6a1f1dSLionel Sambuc #include <unistd.h>
41*0a6a1f1dSLionel Sambuc 
42*0a6a1f1dSLionel Sambuc #include "_libelf.h"
43*0a6a1f1dSLionel Sambuc 
44*0a6a1f1dSLionel Sambuc #if	ELFTC_HAVE_MMAP
45*0a6a1f1dSLionel Sambuc #include <sys/mman.h>
46*0a6a1f1dSLionel Sambuc #endif
47*0a6a1f1dSLionel Sambuc 
48*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: libelf_open.c,v 1.2 2014/03/09 16:58:04 christos Exp $");
49*0a6a1f1dSLionel Sambuc ELFTC_VCSID("Id: libelf_open.c 2932 2013-03-30 01:26:04Z jkoshy ");
50*0a6a1f1dSLionel Sambuc 
51*0a6a1f1dSLionel Sambuc #define	_LIBELF_INITSIZE	(64*1024)
52*0a6a1f1dSLionel Sambuc 
53*0a6a1f1dSLionel Sambuc /*
54*0a6a1f1dSLionel Sambuc  * Read from a device file, pipe or socket.
55*0a6a1f1dSLionel Sambuc  */
56*0a6a1f1dSLionel Sambuc static void *
_libelf_read_special_file(int fd,size_t * fsz)57*0a6a1f1dSLionel Sambuc _libelf_read_special_file(int fd, size_t *fsz)
58*0a6a1f1dSLionel Sambuc {
59*0a6a1f1dSLionel Sambuc 	ssize_t readsz;
60*0a6a1f1dSLionel Sambuc 	size_t bufsz, datasz;
61*0a6a1f1dSLionel Sambuc 	unsigned char *buf, *t;
62*0a6a1f1dSLionel Sambuc 
63*0a6a1f1dSLionel Sambuc 	datasz = 0;
64*0a6a1f1dSLionel Sambuc 	readsz = 0;
65*0a6a1f1dSLionel Sambuc 	bufsz = _LIBELF_INITSIZE;
66*0a6a1f1dSLionel Sambuc 	if ((buf = malloc(bufsz)) == NULL)
67*0a6a1f1dSLionel Sambuc 		goto resourceerror;
68*0a6a1f1dSLionel Sambuc 
69*0a6a1f1dSLionel Sambuc 	/*
70*0a6a1f1dSLionel Sambuc 	 * Read data from the file descriptor till we reach EOF, or
71*0a6a1f1dSLionel Sambuc 	 * till an error is encountered.
72*0a6a1f1dSLionel Sambuc 	 */
73*0a6a1f1dSLionel Sambuc 	do {
74*0a6a1f1dSLionel Sambuc 		/* Check if we need to expand the data buffer. */
75*0a6a1f1dSLionel Sambuc 		if (datasz == bufsz) {
76*0a6a1f1dSLionel Sambuc 			bufsz *= 2;
77*0a6a1f1dSLionel Sambuc 			if ((t = realloc(buf, bufsz)) == NULL)
78*0a6a1f1dSLionel Sambuc 				goto resourceerror;
79*0a6a1f1dSLionel Sambuc 			buf = t;
80*0a6a1f1dSLionel Sambuc 		}
81*0a6a1f1dSLionel Sambuc 
82*0a6a1f1dSLionel Sambuc 		do {
83*0a6a1f1dSLionel Sambuc 			readsz = bufsz - datasz;
84*0a6a1f1dSLionel Sambuc 			t = buf + datasz;
85*0a6a1f1dSLionel Sambuc 			if ((readsz = read(fd, t, readsz)) <= 0)
86*0a6a1f1dSLionel Sambuc 				break;
87*0a6a1f1dSLionel Sambuc 			datasz += readsz;
88*0a6a1f1dSLionel Sambuc 		} while (datasz < bufsz);
89*0a6a1f1dSLionel Sambuc 
90*0a6a1f1dSLionel Sambuc 	} while (readsz > 0);
91*0a6a1f1dSLionel Sambuc 
92*0a6a1f1dSLionel Sambuc 	if (readsz < 0) {
93*0a6a1f1dSLionel Sambuc 		LIBELF_SET_ERROR(IO, errno);
94*0a6a1f1dSLionel Sambuc 		goto error;
95*0a6a1f1dSLionel Sambuc 	}
96*0a6a1f1dSLionel Sambuc 
97*0a6a1f1dSLionel Sambuc 	assert(readsz == 0);
98*0a6a1f1dSLionel Sambuc 
99*0a6a1f1dSLionel Sambuc 	/*
100*0a6a1f1dSLionel Sambuc 	 * Free up extra buffer space.
101*0a6a1f1dSLionel Sambuc 	 */
102*0a6a1f1dSLionel Sambuc 	if (bufsz > datasz) {
103*0a6a1f1dSLionel Sambuc 		if (datasz > 0) {
104*0a6a1f1dSLionel Sambuc 			if ((t = realloc(buf, datasz)) == NULL)
105*0a6a1f1dSLionel Sambuc 				goto resourceerror;
106*0a6a1f1dSLionel Sambuc 			buf = t;
107*0a6a1f1dSLionel Sambuc 		} else {	/* Zero bytes read. */
108*0a6a1f1dSLionel Sambuc 			LIBELF_SET_ERROR(ARGUMENT, 0);
109*0a6a1f1dSLionel Sambuc 			free(buf);
110*0a6a1f1dSLionel Sambuc 			buf = NULL;
111*0a6a1f1dSLionel Sambuc 		}
112*0a6a1f1dSLionel Sambuc 	}
113*0a6a1f1dSLionel Sambuc 
114*0a6a1f1dSLionel Sambuc 	*fsz = datasz;
115*0a6a1f1dSLionel Sambuc 	return (buf);
116*0a6a1f1dSLionel Sambuc 
117*0a6a1f1dSLionel Sambuc resourceerror:
118*0a6a1f1dSLionel Sambuc 	LIBELF_SET_ERROR(RESOURCE, 0);
119*0a6a1f1dSLionel Sambuc error:
120*0a6a1f1dSLionel Sambuc 	if (buf != NULL)
121*0a6a1f1dSLionel Sambuc 		free(buf);
122*0a6a1f1dSLionel Sambuc 	return (NULL);
123*0a6a1f1dSLionel Sambuc }
124*0a6a1f1dSLionel Sambuc 
125*0a6a1f1dSLionel Sambuc /*
126*0a6a1f1dSLionel Sambuc  * Read the contents of the file referenced by the file descriptor
127*0a6a1f1dSLionel Sambuc  * 'fd'.
128*0a6a1f1dSLionel Sambuc  */
129*0a6a1f1dSLionel Sambuc 
130*0a6a1f1dSLionel Sambuc Elf *
_libelf_open_object(int fd,Elf_Cmd c,int reporterror)131*0a6a1f1dSLionel Sambuc _libelf_open_object(int fd, Elf_Cmd c, int reporterror)
132*0a6a1f1dSLionel Sambuc {
133*0a6a1f1dSLionel Sambuc 	Elf *e;
134*0a6a1f1dSLionel Sambuc 	void *m;
135*0a6a1f1dSLionel Sambuc 	mode_t mode;
136*0a6a1f1dSLionel Sambuc 	size_t fsize;
137*0a6a1f1dSLionel Sambuc 	struct stat sb;
138*0a6a1f1dSLionel Sambuc 	unsigned int flags;
139*0a6a1f1dSLionel Sambuc 
140*0a6a1f1dSLionel Sambuc 	assert(c == ELF_C_READ || c == ELF_C_RDWR || c == ELF_C_WRITE);
141*0a6a1f1dSLionel Sambuc 
142*0a6a1f1dSLionel Sambuc 	if (fstat(fd, &sb) < 0) {
143*0a6a1f1dSLionel Sambuc 		LIBELF_SET_ERROR(IO, errno);
144*0a6a1f1dSLionel Sambuc 		return (NULL);
145*0a6a1f1dSLionel Sambuc 	}
146*0a6a1f1dSLionel Sambuc 
147*0a6a1f1dSLionel Sambuc 	mode = sb.st_mode;
148*0a6a1f1dSLionel Sambuc 	fsize = (size_t) sb.st_size;
149*0a6a1f1dSLionel Sambuc 
150*0a6a1f1dSLionel Sambuc 	/*
151*0a6a1f1dSLionel Sambuc 	 * Reject unsupported file types.
152*0a6a1f1dSLionel Sambuc 	 */
153*0a6a1f1dSLionel Sambuc 	if (!S_ISREG(mode) && !S_ISCHR(mode) && !S_ISFIFO(mode) &&
154*0a6a1f1dSLionel Sambuc 	    !S_ISSOCK(mode)) {
155*0a6a1f1dSLionel Sambuc 		LIBELF_SET_ERROR(ARGUMENT, 0);
156*0a6a1f1dSLionel Sambuc 		return (NULL);
157*0a6a1f1dSLionel Sambuc 	}
158*0a6a1f1dSLionel Sambuc 
159*0a6a1f1dSLionel Sambuc 	/*
160*0a6a1f1dSLionel Sambuc 	 * For ELF_C_WRITE mode, allocate and return a descriptor.
161*0a6a1f1dSLionel Sambuc 	 */
162*0a6a1f1dSLionel Sambuc 	if (c == ELF_C_WRITE) {
163*0a6a1f1dSLionel Sambuc 		if ((e = _libelf_allocate_elf()) != NULL) {
164*0a6a1f1dSLionel Sambuc 			_libelf_init_elf(e, ELF_K_ELF);
165*0a6a1f1dSLionel Sambuc 			e->e_byteorder = _libelf_host_byteorder();
166*0a6a1f1dSLionel Sambuc 			e->e_fd = fd;
167*0a6a1f1dSLionel Sambuc 			e->e_cmd = c;
168*0a6a1f1dSLionel Sambuc 			if (!S_ISREG(mode))
169*0a6a1f1dSLionel Sambuc 				e->e_flags |= LIBELF_F_SPECIAL_FILE;
170*0a6a1f1dSLionel Sambuc 		}
171*0a6a1f1dSLionel Sambuc 
172*0a6a1f1dSLionel Sambuc 		return (e);
173*0a6a1f1dSLionel Sambuc 	}
174*0a6a1f1dSLionel Sambuc 
175*0a6a1f1dSLionel Sambuc 
176*0a6a1f1dSLionel Sambuc 	/*
177*0a6a1f1dSLionel Sambuc 	 * ELF_C_READ and ELF_C_RDWR mode.
178*0a6a1f1dSLionel Sambuc 	 */
179*0a6a1f1dSLionel Sambuc 	m = NULL;
180*0a6a1f1dSLionel Sambuc 	flags = 0;
181*0a6a1f1dSLionel Sambuc 	if (S_ISREG(mode)) {
182*0a6a1f1dSLionel Sambuc 
183*0a6a1f1dSLionel Sambuc 		/*
184*0a6a1f1dSLionel Sambuc 		 * Reject zero length files.
185*0a6a1f1dSLionel Sambuc 		 */
186*0a6a1f1dSLionel Sambuc 		if (fsize == 0) {
187*0a6a1f1dSLionel Sambuc 			LIBELF_SET_ERROR(ARGUMENT, 0);
188*0a6a1f1dSLionel Sambuc 			return (NULL);
189*0a6a1f1dSLionel Sambuc 		}
190*0a6a1f1dSLionel Sambuc 
191*0a6a1f1dSLionel Sambuc #if	ELFTC_HAVE_MMAP
192*0a6a1f1dSLionel Sambuc 		/*
193*0a6a1f1dSLionel Sambuc 		 * Always map regular files in with 'PROT_READ'
194*0a6a1f1dSLionel Sambuc 		 * permissions.
195*0a6a1f1dSLionel Sambuc 		 *
196*0a6a1f1dSLionel Sambuc 		 * For objects opened in ELF_C_RDWR mode, when
197*0a6a1f1dSLionel Sambuc 		 * elf_update(3) is called, we remove this mapping,
198*0a6a1f1dSLionel Sambuc 		 * write file data out using write(2), and map the new
199*0a6a1f1dSLionel Sambuc 		 * contents back.
200*0a6a1f1dSLionel Sambuc 		 */
201*0a6a1f1dSLionel Sambuc 		m = mmap(NULL, fsize, PROT_READ, MAP_PRIVATE, fd, (off_t) 0);
202*0a6a1f1dSLionel Sambuc 
203*0a6a1f1dSLionel Sambuc 		if (m == MAP_FAILED)
204*0a6a1f1dSLionel Sambuc 			m = NULL;
205*0a6a1f1dSLionel Sambuc 		else
206*0a6a1f1dSLionel Sambuc 			flags = LIBELF_F_RAWFILE_MMAP;
207*0a6a1f1dSLionel Sambuc #endif
208*0a6a1f1dSLionel Sambuc 
209*0a6a1f1dSLionel Sambuc 		/*
210*0a6a1f1dSLionel Sambuc 		 * Fallback to a read() if the call to mmap() failed,
211*0a6a1f1dSLionel Sambuc 		 * or if mmap() is not available.
212*0a6a1f1dSLionel Sambuc 		 */
213*0a6a1f1dSLionel Sambuc 		if (m == NULL) {
214*0a6a1f1dSLionel Sambuc 			if ((m = malloc(fsize)) == NULL) {
215*0a6a1f1dSLionel Sambuc 				LIBELF_SET_ERROR(RESOURCE, 0);
216*0a6a1f1dSLionel Sambuc 				return (NULL);
217*0a6a1f1dSLionel Sambuc 			}
218*0a6a1f1dSLionel Sambuc 
219*0a6a1f1dSLionel Sambuc 			if (read(fd, m, fsize) != (ssize_t) fsize) {
220*0a6a1f1dSLionel Sambuc 				LIBELF_SET_ERROR(IO, errno);
221*0a6a1f1dSLionel Sambuc 				free(m);
222*0a6a1f1dSLionel Sambuc 				return (NULL);
223*0a6a1f1dSLionel Sambuc 			}
224*0a6a1f1dSLionel Sambuc 
225*0a6a1f1dSLionel Sambuc 			flags = LIBELF_F_RAWFILE_MALLOC;
226*0a6a1f1dSLionel Sambuc 		}
227*0a6a1f1dSLionel Sambuc 	} else if ((m = _libelf_read_special_file(fd, &fsize)) != NULL)
228*0a6a1f1dSLionel Sambuc 		flags = LIBELF_F_RAWFILE_MALLOC | LIBELF_F_SPECIAL_FILE;
229*0a6a1f1dSLionel Sambuc 	else
230*0a6a1f1dSLionel Sambuc 		return (NULL);
231*0a6a1f1dSLionel Sambuc 
232*0a6a1f1dSLionel Sambuc 	if ((e = _libelf_memory(m, fsize, reporterror)) == NULL) {
233*0a6a1f1dSLionel Sambuc 		assert((flags & LIBELF_F_RAWFILE_MALLOC) ||
234*0a6a1f1dSLionel Sambuc 		    (flags & LIBELF_F_RAWFILE_MMAP));
235*0a6a1f1dSLionel Sambuc 		if (flags & LIBELF_F_RAWFILE_MALLOC)
236*0a6a1f1dSLionel Sambuc 			free(m);
237*0a6a1f1dSLionel Sambuc #if	ELFTC_HAVE_MMAP
238*0a6a1f1dSLionel Sambuc 		else
239*0a6a1f1dSLionel Sambuc 			(void) munmap(m, fsize);
240*0a6a1f1dSLionel Sambuc #endif
241*0a6a1f1dSLionel Sambuc 		return (NULL);
242*0a6a1f1dSLionel Sambuc 	}
243*0a6a1f1dSLionel Sambuc 
244*0a6a1f1dSLionel Sambuc 	/* ar(1) archives aren't supported in RDWR mode. */
245*0a6a1f1dSLionel Sambuc 	if (c == ELF_C_RDWR && e->e_kind == ELF_K_AR) {
246*0a6a1f1dSLionel Sambuc 		(void) elf_end(e);
247*0a6a1f1dSLionel Sambuc 		LIBELF_SET_ERROR(ARGUMENT, 0);
248*0a6a1f1dSLionel Sambuc 		return (NULL);
249*0a6a1f1dSLionel Sambuc 	}
250*0a6a1f1dSLionel Sambuc 
251*0a6a1f1dSLionel Sambuc 	e->e_flags |= flags;
252*0a6a1f1dSLionel Sambuc 	e->e_fd = fd;
253*0a6a1f1dSLionel Sambuc 	e->e_cmd = c;
254*0a6a1f1dSLionel Sambuc 
255*0a6a1f1dSLionel Sambuc 	return (e);
256*0a6a1f1dSLionel Sambuc }
257