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