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