1*a9fa9459Szrj /* Low-level I/O routines for BFDs.
2*a9fa9459Szrj
3*a9fa9459Szrj Copyright (C) 1990-2016 Free Software Foundation, Inc.
4*a9fa9459Szrj
5*a9fa9459Szrj Written by Cygnus Support.
6*a9fa9459Szrj
7*a9fa9459Szrj This file is part of BFD, the Binary File Descriptor library.
8*a9fa9459Szrj
9*a9fa9459Szrj This program is free software; you can redistribute it and/or modify
10*a9fa9459Szrj it under the terms of the GNU General Public License as published by
11*a9fa9459Szrj the Free Software Foundation; either version 3 of the License, or
12*a9fa9459Szrj (at your option) any later version.
13*a9fa9459Szrj
14*a9fa9459Szrj This program is distributed in the hope that it will be useful,
15*a9fa9459Szrj but WITHOUT ANY WARRANTY; without even the implied warranty of
16*a9fa9459Szrj MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17*a9fa9459Szrj GNU General Public License for more details.
18*a9fa9459Szrj
19*a9fa9459Szrj You should have received a copy of the GNU General Public License
20*a9fa9459Szrj along with this program; if not, write to the Free Software
21*a9fa9459Szrj Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
22*a9fa9459Szrj MA 02110-1301, USA. */
23*a9fa9459Szrj
24*a9fa9459Szrj #include "sysdep.h"
25*a9fa9459Szrj #include <limits.h>
26*a9fa9459Szrj #include "bfd.h"
27*a9fa9459Szrj #include "libbfd.h"
28*a9fa9459Szrj
29*a9fa9459Szrj #ifndef S_IXUSR
30*a9fa9459Szrj #define S_IXUSR 0100 /* Execute by owner. */
31*a9fa9459Szrj #endif
32*a9fa9459Szrj #ifndef S_IXGRP
33*a9fa9459Szrj #define S_IXGRP 0010 /* Execute by group. */
34*a9fa9459Szrj #endif
35*a9fa9459Szrj #ifndef S_IXOTH
36*a9fa9459Szrj #define S_IXOTH 0001 /* Execute by others. */
37*a9fa9459Szrj #endif
38*a9fa9459Szrj
39*a9fa9459Szrj #ifndef FD_CLOEXEC
40*a9fa9459Szrj #define FD_CLOEXEC 1
41*a9fa9459Szrj #endif
42*a9fa9459Szrj
43*a9fa9459Szrj file_ptr
real_ftell(FILE * file)44*a9fa9459Szrj real_ftell (FILE *file)
45*a9fa9459Szrj {
46*a9fa9459Szrj #if defined (HAVE_FTELLO64)
47*a9fa9459Szrj return ftello64 (file);
48*a9fa9459Szrj #elif defined (HAVE_FTELLO)
49*a9fa9459Szrj return ftello (file);
50*a9fa9459Szrj #else
51*a9fa9459Szrj return ftell (file);
52*a9fa9459Szrj #endif
53*a9fa9459Szrj }
54*a9fa9459Szrj
55*a9fa9459Szrj int
real_fseek(FILE * file,file_ptr offset,int whence)56*a9fa9459Szrj real_fseek (FILE *file, file_ptr offset, int whence)
57*a9fa9459Szrj {
58*a9fa9459Szrj #if defined (HAVE_FSEEKO64)
59*a9fa9459Szrj return fseeko64 (file, offset, whence);
60*a9fa9459Szrj #elif defined (HAVE_FSEEKO)
61*a9fa9459Szrj return fseeko (file, offset, whence);
62*a9fa9459Szrj #else
63*a9fa9459Szrj return fseek (file, offset, whence);
64*a9fa9459Szrj #endif
65*a9fa9459Szrj }
66*a9fa9459Szrj
67*a9fa9459Szrj /* Mark FILE as close-on-exec. Return FILE. FILE may be NULL, in
68*a9fa9459Szrj which case nothing is done. */
69*a9fa9459Szrj static FILE *
close_on_exec(FILE * file)70*a9fa9459Szrj close_on_exec (FILE *file)
71*a9fa9459Szrj {
72*a9fa9459Szrj #if defined (HAVE_FILENO) && defined (F_GETFD)
73*a9fa9459Szrj if (file)
74*a9fa9459Szrj {
75*a9fa9459Szrj int fd = fileno (file);
76*a9fa9459Szrj int old = fcntl (fd, F_GETFD, 0);
77*a9fa9459Szrj if (old >= 0)
78*a9fa9459Szrj fcntl (fd, F_SETFD, old | FD_CLOEXEC);
79*a9fa9459Szrj }
80*a9fa9459Szrj #endif
81*a9fa9459Szrj return file;
82*a9fa9459Szrj }
83*a9fa9459Szrj
84*a9fa9459Szrj FILE *
real_fopen(const char * filename,const char * modes)85*a9fa9459Szrj real_fopen (const char *filename, const char *modes)
86*a9fa9459Szrj {
87*a9fa9459Szrj #ifdef VMS
88*a9fa9459Szrj char *vms_attr;
89*a9fa9459Szrj
90*a9fa9459Szrj /* On VMS, fopen allows file attributes as optional arguments.
91*a9fa9459Szrj We need to use them but we'd better to use the common prototype.
92*a9fa9459Szrj In fopen-vms.h, they are separated from the mode with a comma.
93*a9fa9459Szrj Split here. */
94*a9fa9459Szrj vms_attr = strchr (modes, ',');
95*a9fa9459Szrj if (vms_attr == NULL)
96*a9fa9459Szrj {
97*a9fa9459Szrj /* No attributes. */
98*a9fa9459Szrj return close_on_exec (fopen (filename, modes));
99*a9fa9459Szrj }
100*a9fa9459Szrj else
101*a9fa9459Szrj {
102*a9fa9459Szrj /* Attributes found. Split. */
103*a9fa9459Szrj size_t modes_len = strlen (modes) + 1;
104*a9fa9459Szrj char attrs[modes_len + 1];
105*a9fa9459Szrj char *at[3];
106*a9fa9459Szrj int i;
107*a9fa9459Szrj
108*a9fa9459Szrj memcpy (attrs, modes, modes_len);
109*a9fa9459Szrj at[0] = attrs;
110*a9fa9459Szrj for (i = 0; i < 2; i++)
111*a9fa9459Szrj {
112*a9fa9459Szrj at[i + 1] = strchr (at[i], ',');
113*a9fa9459Szrj BFD_ASSERT (at[i + 1] != NULL);
114*a9fa9459Szrj *(at[i + 1]++) = 0; /* Replace ',' with a nul, and skip it. */
115*a9fa9459Szrj }
116*a9fa9459Szrj return close_on_exec (fopen (filename, at[0], at[1], at[2]));
117*a9fa9459Szrj }
118*a9fa9459Szrj #else /* !VMS */
119*a9fa9459Szrj #if defined (HAVE_FOPEN64)
120*a9fa9459Szrj return close_on_exec (fopen64 (filename, modes));
121*a9fa9459Szrj #else
122*a9fa9459Szrj return close_on_exec (fopen (filename, modes));
123*a9fa9459Szrj #endif
124*a9fa9459Szrj #endif /* !VMS */
125*a9fa9459Szrj }
126*a9fa9459Szrj
127*a9fa9459Szrj /*
128*a9fa9459Szrj INTERNAL_DEFINITION
129*a9fa9459Szrj struct bfd_iovec
130*a9fa9459Szrj
131*a9fa9459Szrj DESCRIPTION
132*a9fa9459Szrj
133*a9fa9459Szrj The <<struct bfd_iovec>> contains the internal file I/O class.
134*a9fa9459Szrj Each <<BFD>> has an instance of this class and all file I/O is
135*a9fa9459Szrj routed through it (it is assumed that the instance implements
136*a9fa9459Szrj all methods listed below).
137*a9fa9459Szrj
138*a9fa9459Szrj .struct bfd_iovec
139*a9fa9459Szrj .{
140*a9fa9459Szrj . {* To avoid problems with macros, a "b" rather than "f"
141*a9fa9459Szrj . prefix is prepended to each method name. *}
142*a9fa9459Szrj . {* Attempt to read/write NBYTES on ABFD's IOSTREAM storing/fetching
143*a9fa9459Szrj . bytes starting at PTR. Return the number of bytes actually
144*a9fa9459Szrj . transfered (a read past end-of-file returns less than NBYTES),
145*a9fa9459Szrj . or -1 (setting <<bfd_error>>) if an error occurs. *}
146*a9fa9459Szrj . file_ptr (*bread) (struct bfd *abfd, void *ptr, file_ptr nbytes);
147*a9fa9459Szrj . file_ptr (*bwrite) (struct bfd *abfd, const void *ptr,
148*a9fa9459Szrj . file_ptr nbytes);
149*a9fa9459Szrj . {* Return the current IOSTREAM file offset, or -1 (setting <<bfd_error>>
150*a9fa9459Szrj . if an error occurs. *}
151*a9fa9459Szrj . file_ptr (*btell) (struct bfd *abfd);
152*a9fa9459Szrj . {* For the following, on successful completion a value of 0 is returned.
153*a9fa9459Szrj . Otherwise, a value of -1 is returned (and <<bfd_error>> is set). *}
154*a9fa9459Szrj . int (*bseek) (struct bfd *abfd, file_ptr offset, int whence);
155*a9fa9459Szrj . int (*bclose) (struct bfd *abfd);
156*a9fa9459Szrj . int (*bflush) (struct bfd *abfd);
157*a9fa9459Szrj . int (*bstat) (struct bfd *abfd, struct stat *sb);
158*a9fa9459Szrj . {* Mmap a part of the files. ADDR, LEN, PROT, FLAGS and OFFSET are the usual
159*a9fa9459Szrj . mmap parameter, except that LEN and OFFSET do not need to be page
160*a9fa9459Szrj . aligned. Returns (void *)-1 on failure, mmapped address on success.
161*a9fa9459Szrj . Also write in MAP_ADDR the address of the page aligned buffer and in
162*a9fa9459Szrj . MAP_LEN the size mapped (a page multiple). Use unmap with MAP_ADDR and
163*a9fa9459Szrj . MAP_LEN to unmap. *}
164*a9fa9459Szrj . void *(*bmmap) (struct bfd *abfd, void *addr, bfd_size_type len,
165*a9fa9459Szrj . int prot, int flags, file_ptr offset,
166*a9fa9459Szrj . void **map_addr, bfd_size_type *map_len);
167*a9fa9459Szrj .};
168*a9fa9459Szrj
169*a9fa9459Szrj .extern const struct bfd_iovec _bfd_memory_iovec;
170*a9fa9459Szrj
171*a9fa9459Szrj */
172*a9fa9459Szrj
173*a9fa9459Szrj
174*a9fa9459Szrj /* Return value is amount read. */
175*a9fa9459Szrj
176*a9fa9459Szrj bfd_size_type
bfd_bread(void * ptr,bfd_size_type size,bfd * abfd)177*a9fa9459Szrj bfd_bread (void *ptr, bfd_size_type size, bfd *abfd)
178*a9fa9459Szrj {
179*a9fa9459Szrj size_t nread;
180*a9fa9459Szrj
181*a9fa9459Szrj /* If this is an archive element, don't read past the end of
182*a9fa9459Szrj this element. */
183*a9fa9459Szrj if (abfd->arelt_data != NULL)
184*a9fa9459Szrj {
185*a9fa9459Szrj bfd_size_type maxbytes = arelt_size (abfd);
186*a9fa9459Szrj
187*a9fa9459Szrj if (abfd->where + size > maxbytes)
188*a9fa9459Szrj {
189*a9fa9459Szrj if (abfd->where >= maxbytes)
190*a9fa9459Szrj return 0;
191*a9fa9459Szrj size = maxbytes - abfd->where;
192*a9fa9459Szrj }
193*a9fa9459Szrj }
194*a9fa9459Szrj
195*a9fa9459Szrj if (abfd->iovec)
196*a9fa9459Szrj nread = abfd->iovec->bread (abfd, ptr, size);
197*a9fa9459Szrj else
198*a9fa9459Szrj nread = 0;
199*a9fa9459Szrj if (nread != (size_t) -1)
200*a9fa9459Szrj abfd->where += nread;
201*a9fa9459Szrj
202*a9fa9459Szrj return nread;
203*a9fa9459Szrj }
204*a9fa9459Szrj
205*a9fa9459Szrj bfd_size_type
bfd_bwrite(const void * ptr,bfd_size_type size,bfd * abfd)206*a9fa9459Szrj bfd_bwrite (const void *ptr, bfd_size_type size, bfd *abfd)
207*a9fa9459Szrj {
208*a9fa9459Szrj size_t nwrote;
209*a9fa9459Szrj
210*a9fa9459Szrj if (abfd->iovec)
211*a9fa9459Szrj nwrote = abfd->iovec->bwrite (abfd, ptr, size);
212*a9fa9459Szrj else
213*a9fa9459Szrj nwrote = 0;
214*a9fa9459Szrj
215*a9fa9459Szrj if (nwrote != (size_t) -1)
216*a9fa9459Szrj abfd->where += nwrote;
217*a9fa9459Szrj if (nwrote != size)
218*a9fa9459Szrj {
219*a9fa9459Szrj #ifdef ENOSPC
220*a9fa9459Szrj errno = ENOSPC;
221*a9fa9459Szrj #endif
222*a9fa9459Szrj bfd_set_error (bfd_error_system_call);
223*a9fa9459Szrj }
224*a9fa9459Szrj return nwrote;
225*a9fa9459Szrj }
226*a9fa9459Szrj
227*a9fa9459Szrj file_ptr
bfd_tell(bfd * abfd)228*a9fa9459Szrj bfd_tell (bfd *abfd)
229*a9fa9459Szrj {
230*a9fa9459Szrj file_ptr ptr;
231*a9fa9459Szrj
232*a9fa9459Szrj if (abfd->iovec)
233*a9fa9459Szrj {
234*a9fa9459Szrj bfd *parent_bfd = abfd;
235*a9fa9459Szrj ptr = abfd->iovec->btell (abfd);
236*a9fa9459Szrj
237*a9fa9459Szrj while (parent_bfd->my_archive != NULL
238*a9fa9459Szrj && !bfd_is_thin_archive (parent_bfd->my_archive))
239*a9fa9459Szrj {
240*a9fa9459Szrj ptr -= parent_bfd->origin;
241*a9fa9459Szrj parent_bfd = parent_bfd->my_archive;
242*a9fa9459Szrj }
243*a9fa9459Szrj }
244*a9fa9459Szrj else
245*a9fa9459Szrj ptr = 0;
246*a9fa9459Szrj
247*a9fa9459Szrj abfd->where = ptr;
248*a9fa9459Szrj return ptr;
249*a9fa9459Szrj }
250*a9fa9459Szrj
251*a9fa9459Szrj int
bfd_flush(bfd * abfd)252*a9fa9459Szrj bfd_flush (bfd *abfd)
253*a9fa9459Szrj {
254*a9fa9459Szrj if (abfd->iovec)
255*a9fa9459Szrj return abfd->iovec->bflush (abfd);
256*a9fa9459Szrj return 0;
257*a9fa9459Szrj }
258*a9fa9459Szrj
259*a9fa9459Szrj /* Returns 0 for success, negative value for failure (in which case
260*a9fa9459Szrj bfd_get_error can retrieve the error code). */
261*a9fa9459Szrj int
bfd_stat(bfd * abfd,struct stat * statbuf)262*a9fa9459Szrj bfd_stat (bfd *abfd, struct stat *statbuf)
263*a9fa9459Szrj {
264*a9fa9459Szrj int result;
265*a9fa9459Szrj
266*a9fa9459Szrj if (abfd->iovec)
267*a9fa9459Szrj result = abfd->iovec->bstat (abfd, statbuf);
268*a9fa9459Szrj else
269*a9fa9459Szrj result = -1;
270*a9fa9459Szrj
271*a9fa9459Szrj if (result < 0)
272*a9fa9459Szrj bfd_set_error (bfd_error_system_call);
273*a9fa9459Szrj return result;
274*a9fa9459Szrj }
275*a9fa9459Szrj
276*a9fa9459Szrj /* Returns 0 for success, nonzero for failure (in which case bfd_get_error
277*a9fa9459Szrj can retrieve the error code). */
278*a9fa9459Szrj
279*a9fa9459Szrj int
bfd_seek(bfd * abfd,file_ptr position,int direction)280*a9fa9459Szrj bfd_seek (bfd *abfd, file_ptr position, int direction)
281*a9fa9459Szrj {
282*a9fa9459Szrj int result;
283*a9fa9459Szrj file_ptr file_position;
284*a9fa9459Szrj /* For the time being, a BFD may not seek to it's end. The problem
285*a9fa9459Szrj is that we don't easily have a way to recognize the end of an
286*a9fa9459Szrj element in an archive. */
287*a9fa9459Szrj
288*a9fa9459Szrj BFD_ASSERT (direction == SEEK_SET || direction == SEEK_CUR);
289*a9fa9459Szrj
290*a9fa9459Szrj if (direction == SEEK_CUR && position == 0)
291*a9fa9459Szrj return 0;
292*a9fa9459Szrj
293*a9fa9459Szrj if (abfd->my_archive == NULL || bfd_is_thin_archive (abfd->my_archive))
294*a9fa9459Szrj {
295*a9fa9459Szrj if (direction == SEEK_SET && (bfd_vma) position == abfd->where)
296*a9fa9459Szrj return 0;
297*a9fa9459Szrj }
298*a9fa9459Szrj else
299*a9fa9459Szrj {
300*a9fa9459Szrj /* We need something smarter to optimize access to archives.
301*a9fa9459Szrj Currently, anything inside an archive is read via the file
302*a9fa9459Szrj handle for the archive. Which means that a bfd_seek on one
303*a9fa9459Szrj component affects the `current position' in the archive, as
304*a9fa9459Szrj well as in any other component.
305*a9fa9459Szrj
306*a9fa9459Szrj It might be sufficient to put a spike through the cache
307*a9fa9459Szrj abstraction, and look to the archive for the file position,
308*a9fa9459Szrj but I think we should try for something cleaner.
309*a9fa9459Szrj
310*a9fa9459Szrj In the meantime, no optimization for archives. */
311*a9fa9459Szrj }
312*a9fa9459Szrj
313*a9fa9459Szrj file_position = position;
314*a9fa9459Szrj if (direction == SEEK_SET)
315*a9fa9459Szrj {
316*a9fa9459Szrj bfd *parent_bfd = abfd;
317*a9fa9459Szrj
318*a9fa9459Szrj while (parent_bfd->my_archive != NULL
319*a9fa9459Szrj && !bfd_is_thin_archive (parent_bfd->my_archive))
320*a9fa9459Szrj {
321*a9fa9459Szrj file_position += parent_bfd->origin;
322*a9fa9459Szrj parent_bfd = parent_bfd->my_archive;
323*a9fa9459Szrj }
324*a9fa9459Szrj }
325*a9fa9459Szrj
326*a9fa9459Szrj if (abfd->iovec)
327*a9fa9459Szrj result = abfd->iovec->bseek (abfd, file_position, direction);
328*a9fa9459Szrj else
329*a9fa9459Szrj result = -1;
330*a9fa9459Szrj
331*a9fa9459Szrj if (result != 0)
332*a9fa9459Szrj {
333*a9fa9459Szrj int hold_errno = errno;
334*a9fa9459Szrj
335*a9fa9459Szrj /* Force redetermination of `where' field. */
336*a9fa9459Szrj bfd_tell (abfd);
337*a9fa9459Szrj
338*a9fa9459Szrj /* An EINVAL error probably means that the file offset was
339*a9fa9459Szrj absurd. */
340*a9fa9459Szrj if (hold_errno == EINVAL)
341*a9fa9459Szrj bfd_set_error (bfd_error_file_truncated);
342*a9fa9459Szrj else
343*a9fa9459Szrj {
344*a9fa9459Szrj bfd_set_error (bfd_error_system_call);
345*a9fa9459Szrj errno = hold_errno;
346*a9fa9459Szrj }
347*a9fa9459Szrj }
348*a9fa9459Szrj else
349*a9fa9459Szrj {
350*a9fa9459Szrj /* Adjust `where' field. */
351*a9fa9459Szrj if (direction == SEEK_SET)
352*a9fa9459Szrj abfd->where = position;
353*a9fa9459Szrj else
354*a9fa9459Szrj abfd->where += position;
355*a9fa9459Szrj }
356*a9fa9459Szrj return result;
357*a9fa9459Szrj }
358*a9fa9459Szrj
359*a9fa9459Szrj /*
360*a9fa9459Szrj FUNCTION
361*a9fa9459Szrj bfd_get_mtime
362*a9fa9459Szrj
363*a9fa9459Szrj SYNOPSIS
364*a9fa9459Szrj long bfd_get_mtime (bfd *abfd);
365*a9fa9459Szrj
366*a9fa9459Szrj DESCRIPTION
367*a9fa9459Szrj Return the file modification time (as read from the file system, or
368*a9fa9459Szrj from the archive header for archive members).
369*a9fa9459Szrj
370*a9fa9459Szrj */
371*a9fa9459Szrj
372*a9fa9459Szrj long
bfd_get_mtime(bfd * abfd)373*a9fa9459Szrj bfd_get_mtime (bfd *abfd)
374*a9fa9459Szrj {
375*a9fa9459Szrj struct stat buf;
376*a9fa9459Szrj
377*a9fa9459Szrj if (abfd->mtime_set)
378*a9fa9459Szrj return abfd->mtime;
379*a9fa9459Szrj
380*a9fa9459Szrj if (abfd->iovec == NULL)
381*a9fa9459Szrj return 0;
382*a9fa9459Szrj
383*a9fa9459Szrj if (abfd->iovec->bstat (abfd, &buf) != 0)
384*a9fa9459Szrj return 0;
385*a9fa9459Szrj
386*a9fa9459Szrj abfd->mtime = buf.st_mtime; /* Save value in case anyone wants it */
387*a9fa9459Szrj return buf.st_mtime;
388*a9fa9459Szrj }
389*a9fa9459Szrj
390*a9fa9459Szrj /*
391*a9fa9459Szrj FUNCTION
392*a9fa9459Szrj bfd_get_size
393*a9fa9459Szrj
394*a9fa9459Szrj SYNOPSIS
395*a9fa9459Szrj file_ptr bfd_get_size (bfd *abfd);
396*a9fa9459Szrj
397*a9fa9459Szrj DESCRIPTION
398*a9fa9459Szrj Return the file size (as read from file system) for the file
399*a9fa9459Szrj associated with BFD @var{abfd}.
400*a9fa9459Szrj
401*a9fa9459Szrj The initial motivation for, and use of, this routine is not
402*a9fa9459Szrj so we can get the exact size of the object the BFD applies to, since
403*a9fa9459Szrj that might not be generally possible (archive members for example).
404*a9fa9459Szrj It would be ideal if someone could eventually modify
405*a9fa9459Szrj it so that such results were guaranteed.
406*a9fa9459Szrj
407*a9fa9459Szrj Instead, we want to ask questions like "is this NNN byte sized
408*a9fa9459Szrj object I'm about to try read from file offset YYY reasonable?"
409*a9fa9459Szrj As as example of where we might do this, some object formats
410*a9fa9459Szrj use string tables for which the first <<sizeof (long)>> bytes of the
411*a9fa9459Szrj table contain the size of the table itself, including the size bytes.
412*a9fa9459Szrj If an application tries to read what it thinks is one of these
413*a9fa9459Szrj string tables, without some way to validate the size, and for
414*a9fa9459Szrj some reason the size is wrong (byte swapping error, wrong location
415*a9fa9459Szrj for the string table, etc.), the only clue is likely to be a read
416*a9fa9459Szrj error when it tries to read the table, or a "virtual memory
417*a9fa9459Szrj exhausted" error when it tries to allocate 15 bazillon bytes
418*a9fa9459Szrj of space for the 15 bazillon byte table it is about to read.
419*a9fa9459Szrj This function at least allows us to answer the question, "is the
420*a9fa9459Szrj size reasonable?".
421*a9fa9459Szrj */
422*a9fa9459Szrj
423*a9fa9459Szrj file_ptr
bfd_get_size(bfd * abfd)424*a9fa9459Szrj bfd_get_size (bfd *abfd)
425*a9fa9459Szrj {
426*a9fa9459Szrj struct stat buf;
427*a9fa9459Szrj
428*a9fa9459Szrj if (abfd->iovec == NULL)
429*a9fa9459Szrj return 0;
430*a9fa9459Szrj
431*a9fa9459Szrj if (abfd->iovec->bstat (abfd, &buf) != 0)
432*a9fa9459Szrj return 0;
433*a9fa9459Szrj
434*a9fa9459Szrj return buf.st_size;
435*a9fa9459Szrj }
436*a9fa9459Szrj
437*a9fa9459Szrj
438*a9fa9459Szrj /*
439*a9fa9459Szrj FUNCTION
440*a9fa9459Szrj bfd_mmap
441*a9fa9459Szrj
442*a9fa9459Szrj SYNOPSIS
443*a9fa9459Szrj void *bfd_mmap (bfd *abfd, void *addr, bfd_size_type len,
444*a9fa9459Szrj int prot, int flags, file_ptr offset,
445*a9fa9459Szrj void **map_addr, bfd_size_type *map_len);
446*a9fa9459Szrj
447*a9fa9459Szrj DESCRIPTION
448*a9fa9459Szrj Return mmap()ed region of the file, if possible and implemented.
449*a9fa9459Szrj LEN and OFFSET do not need to be page aligned. The page aligned
450*a9fa9459Szrj address and length are written to MAP_ADDR and MAP_LEN.
451*a9fa9459Szrj
452*a9fa9459Szrj */
453*a9fa9459Szrj
454*a9fa9459Szrj void *
bfd_mmap(bfd * abfd,void * addr,bfd_size_type len,int prot,int flags,file_ptr offset,void ** map_addr,bfd_size_type * map_len)455*a9fa9459Szrj bfd_mmap (bfd *abfd, void *addr, bfd_size_type len,
456*a9fa9459Szrj int prot, int flags, file_ptr offset,
457*a9fa9459Szrj void **map_addr, bfd_size_type *map_len)
458*a9fa9459Szrj {
459*a9fa9459Szrj void *ret = (void *)-1;
460*a9fa9459Szrj
461*a9fa9459Szrj if (abfd->iovec == NULL)
462*a9fa9459Szrj return ret;
463*a9fa9459Szrj
464*a9fa9459Szrj return abfd->iovec->bmmap (abfd, addr, len, prot, flags, offset,
465*a9fa9459Szrj map_addr, map_len);
466*a9fa9459Szrj }
467*a9fa9459Szrj
468*a9fa9459Szrj /* Memory file I/O operations. */
469*a9fa9459Szrj
470*a9fa9459Szrj static file_ptr
memory_bread(bfd * abfd,void * ptr,file_ptr size)471*a9fa9459Szrj memory_bread (bfd *abfd, void *ptr, file_ptr size)
472*a9fa9459Szrj {
473*a9fa9459Szrj struct bfd_in_memory *bim;
474*a9fa9459Szrj bfd_size_type get;
475*a9fa9459Szrj
476*a9fa9459Szrj bim = (struct bfd_in_memory *) abfd->iostream;
477*a9fa9459Szrj get = size;
478*a9fa9459Szrj if (abfd->where + get > bim->size)
479*a9fa9459Szrj {
480*a9fa9459Szrj if (bim->size < (bfd_size_type) abfd->where)
481*a9fa9459Szrj get = 0;
482*a9fa9459Szrj else
483*a9fa9459Szrj get = bim->size - abfd->where;
484*a9fa9459Szrj bfd_set_error (bfd_error_file_truncated);
485*a9fa9459Szrj }
486*a9fa9459Szrj memcpy (ptr, bim->buffer + abfd->where, (size_t) get);
487*a9fa9459Szrj return get;
488*a9fa9459Szrj }
489*a9fa9459Szrj
490*a9fa9459Szrj static file_ptr
memory_bwrite(bfd * abfd,const void * ptr,file_ptr size)491*a9fa9459Szrj memory_bwrite (bfd *abfd, const void *ptr, file_ptr size)
492*a9fa9459Szrj {
493*a9fa9459Szrj struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream;
494*a9fa9459Szrj
495*a9fa9459Szrj if (abfd->where + size > bim->size)
496*a9fa9459Szrj {
497*a9fa9459Szrj bfd_size_type newsize, oldsize;
498*a9fa9459Szrj
499*a9fa9459Szrj oldsize = (bim->size + 127) & ~(bfd_size_type) 127;
500*a9fa9459Szrj bim->size = abfd->where + size;
501*a9fa9459Szrj /* Round up to cut down on memory fragmentation */
502*a9fa9459Szrj newsize = (bim->size + 127) & ~(bfd_size_type) 127;
503*a9fa9459Szrj if (newsize > oldsize)
504*a9fa9459Szrj {
505*a9fa9459Szrj bim->buffer = (bfd_byte *) bfd_realloc_or_free (bim->buffer, newsize);
506*a9fa9459Szrj if (bim->buffer == NULL)
507*a9fa9459Szrj {
508*a9fa9459Szrj bim->size = 0;
509*a9fa9459Szrj return 0;
510*a9fa9459Szrj }
511*a9fa9459Szrj if (newsize > bim->size)
512*a9fa9459Szrj memset (bim->buffer + bim->size, 0, newsize - bim->size);
513*a9fa9459Szrj }
514*a9fa9459Szrj }
515*a9fa9459Szrj memcpy (bim->buffer + abfd->where, ptr, (size_t) size);
516*a9fa9459Szrj return size;
517*a9fa9459Szrj }
518*a9fa9459Szrj
519*a9fa9459Szrj static file_ptr
memory_btell(bfd * abfd)520*a9fa9459Szrj memory_btell (bfd *abfd)
521*a9fa9459Szrj {
522*a9fa9459Szrj return abfd->where;
523*a9fa9459Szrj }
524*a9fa9459Szrj
525*a9fa9459Szrj static int
memory_bseek(bfd * abfd,file_ptr position,int direction)526*a9fa9459Szrj memory_bseek (bfd *abfd, file_ptr position, int direction)
527*a9fa9459Szrj {
528*a9fa9459Szrj file_ptr nwhere;
529*a9fa9459Szrj struct bfd_in_memory *bim;
530*a9fa9459Szrj
531*a9fa9459Szrj bim = (struct bfd_in_memory *) abfd->iostream;
532*a9fa9459Szrj
533*a9fa9459Szrj if (direction == SEEK_SET)
534*a9fa9459Szrj nwhere = position;
535*a9fa9459Szrj else
536*a9fa9459Szrj nwhere = abfd->where + position;
537*a9fa9459Szrj
538*a9fa9459Szrj if (nwhere < 0)
539*a9fa9459Szrj {
540*a9fa9459Szrj abfd->where = 0;
541*a9fa9459Szrj errno = EINVAL;
542*a9fa9459Szrj return -1;
543*a9fa9459Szrj }
544*a9fa9459Szrj
545*a9fa9459Szrj if ((bfd_size_type)nwhere > bim->size)
546*a9fa9459Szrj {
547*a9fa9459Szrj if (abfd->direction == write_direction
548*a9fa9459Szrj || abfd->direction == both_direction)
549*a9fa9459Szrj {
550*a9fa9459Szrj bfd_size_type newsize, oldsize;
551*a9fa9459Szrj
552*a9fa9459Szrj oldsize = (bim->size + 127) & ~(bfd_size_type) 127;
553*a9fa9459Szrj bim->size = nwhere;
554*a9fa9459Szrj /* Round up to cut down on memory fragmentation */
555*a9fa9459Szrj newsize = (bim->size + 127) & ~(bfd_size_type) 127;
556*a9fa9459Szrj if (newsize > oldsize)
557*a9fa9459Szrj {
558*a9fa9459Szrj bim->buffer = (bfd_byte *) bfd_realloc_or_free (bim->buffer, newsize);
559*a9fa9459Szrj if (bim->buffer == NULL)
560*a9fa9459Szrj {
561*a9fa9459Szrj errno = EINVAL;
562*a9fa9459Szrj bim->size = 0;
563*a9fa9459Szrj return -1;
564*a9fa9459Szrj }
565*a9fa9459Szrj memset (bim->buffer + oldsize, 0, newsize - oldsize);
566*a9fa9459Szrj }
567*a9fa9459Szrj }
568*a9fa9459Szrj else
569*a9fa9459Szrj {
570*a9fa9459Szrj abfd->where = bim->size;
571*a9fa9459Szrj errno = EINVAL;
572*a9fa9459Szrj bfd_set_error (bfd_error_file_truncated);
573*a9fa9459Szrj return -1;
574*a9fa9459Szrj }
575*a9fa9459Szrj }
576*a9fa9459Szrj return 0;
577*a9fa9459Szrj }
578*a9fa9459Szrj
579*a9fa9459Szrj static int
memory_bclose(struct bfd * abfd)580*a9fa9459Szrj memory_bclose (struct bfd *abfd)
581*a9fa9459Szrj {
582*a9fa9459Szrj struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream;
583*a9fa9459Szrj
584*a9fa9459Szrj if (bim->buffer != NULL)
585*a9fa9459Szrj free (bim->buffer);
586*a9fa9459Szrj free (bim);
587*a9fa9459Szrj abfd->iostream = NULL;
588*a9fa9459Szrj
589*a9fa9459Szrj return 0;
590*a9fa9459Szrj }
591*a9fa9459Szrj
592*a9fa9459Szrj static int
memory_bflush(bfd * abfd ATTRIBUTE_UNUSED)593*a9fa9459Szrj memory_bflush (bfd *abfd ATTRIBUTE_UNUSED)
594*a9fa9459Szrj {
595*a9fa9459Szrj return 0;
596*a9fa9459Szrj }
597*a9fa9459Szrj
598*a9fa9459Szrj static int
memory_bstat(bfd * abfd,struct stat * statbuf)599*a9fa9459Szrj memory_bstat (bfd *abfd, struct stat *statbuf)
600*a9fa9459Szrj {
601*a9fa9459Szrj struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream;
602*a9fa9459Szrj
603*a9fa9459Szrj memset (statbuf, 0, sizeof (*statbuf));
604*a9fa9459Szrj statbuf->st_size = bim->size;
605*a9fa9459Szrj
606*a9fa9459Szrj return 0;
607*a9fa9459Szrj }
608*a9fa9459Szrj
609*a9fa9459Szrj static void *
memory_bmmap(bfd * abfd ATTRIBUTE_UNUSED,void * addr ATTRIBUTE_UNUSED,bfd_size_type len ATTRIBUTE_UNUSED,int prot ATTRIBUTE_UNUSED,int flags ATTRIBUTE_UNUSED,file_ptr offset ATTRIBUTE_UNUSED,void ** map_addr ATTRIBUTE_UNUSED,bfd_size_type * map_len ATTRIBUTE_UNUSED)610*a9fa9459Szrj memory_bmmap (bfd *abfd ATTRIBUTE_UNUSED, void *addr ATTRIBUTE_UNUSED,
611*a9fa9459Szrj bfd_size_type len ATTRIBUTE_UNUSED, int prot ATTRIBUTE_UNUSED,
612*a9fa9459Szrj int flags ATTRIBUTE_UNUSED, file_ptr offset ATTRIBUTE_UNUSED,
613*a9fa9459Szrj void **map_addr ATTRIBUTE_UNUSED,
614*a9fa9459Szrj bfd_size_type *map_len ATTRIBUTE_UNUSED)
615*a9fa9459Szrj {
616*a9fa9459Szrj return (void *)-1;
617*a9fa9459Szrj }
618*a9fa9459Szrj
619*a9fa9459Szrj const struct bfd_iovec _bfd_memory_iovec =
620*a9fa9459Szrj {
621*a9fa9459Szrj &memory_bread, &memory_bwrite, &memory_btell, &memory_bseek,
622*a9fa9459Szrj &memory_bclose, &memory_bflush, &memory_bstat, &memory_bmmap
623*a9fa9459Szrj };
624