xref: /dragonfly/contrib/binutils-2.27/bfd/bfdio.c (revision a9fa9459)
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