Coverage Report

Created: 2023-08-28 06:31

/src/binutils-gdb/bfd/bfdio.c
Line
Count
Source (jump to first uncovered line)
1
/* Low-level I/O routines for BFDs.
2
3
   Copyright (C) 1990-2023 Free Software Foundation, Inc.
4
5
   Written by Cygnus Support.
6
7
   This file is part of BFD, the Binary File Descriptor library.
8
9
   This program is free software; you can redistribute it and/or modify
10
   it under the terms of the GNU General Public License as published by
11
   the Free Software Foundation; either version 3 of the License, or
12
   (at your option) any later version.
13
14
   This program is distributed in the hope that it will be useful,
15
   but WITHOUT ANY WARRANTY; without even the implied warranty of
16
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
   GNU General Public License for more details.
18
19
   You should have received a copy of the GNU General Public License
20
   along with this program; if not, write to the Free Software
21
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
22
   MA 02110-1301, USA.  */
23
24
#include "sysdep.h"
25
#include <limits.h>
26
#include "bfd.h"
27
#include "libbfd.h"
28
#include "aout/ar.h"
29
#if defined (_WIN32)
30
#include <windows.h>
31
#include <locale.h>
32
#endif
33
34
#ifndef S_IXUSR
35
#define S_IXUSR 0100    /* Execute by owner.  */
36
#endif
37
#ifndef S_IXGRP
38
#define S_IXGRP 0010    /* Execute by group.  */
39
#endif
40
#ifndef S_IXOTH
41
#define S_IXOTH 0001    /* Execute by others.  */
42
#endif
43
44
#ifndef FD_CLOEXEC
45
#define FD_CLOEXEC 1
46
#endif
47
48
file_ptr
49
_bfd_real_ftell (FILE *file)
50
5.36M
{
51
5.36M
#if defined (HAVE_FTELLO64)
52
5.36M
  return ftello64 (file);
53
#elif defined (HAVE_FTELLO)
54
  return ftello (file);
55
#else
56
  return ftell (file);
57
#endif
58
5.36M
}
59
60
int
61
_bfd_real_fseek (FILE *file, file_ptr offset, int whence)
62
492M
{
63
492M
#if defined (HAVE_FSEEKO64)
64
492M
  return fseeko64 (file, offset, whence);
65
#elif defined (HAVE_FSEEKO)
66
  return fseeko (file, offset, whence);
67
#else
68
  return fseek (file, offset, whence);
69
#endif
70
492M
}
71
72
/* Mark FILE as close-on-exec.  Return FILE.  FILE may be NULL, in
73
   which case nothing is done.  */
74
static FILE *
75
close_on_exec (FILE *file)
76
136k
{
77
136k
#if defined (HAVE_FILENO) && defined (F_GETFD)
78
136k
  if (file)
79
134k
    {
80
134k
      int fd = fileno (file);
81
134k
      int old = fcntl (fd, F_GETFD, 0);
82
134k
      if (old >= 0)
83
134k
  fcntl (fd, F_SETFD, old | FD_CLOEXEC);
84
134k
    }
85
136k
#endif
86
136k
  return file;
87
136k
}
88
89
FILE *
90
_bfd_real_fopen (const char *filename, const char *modes)
91
136k
{
92
#ifdef VMS
93
  char *vms_attr;
94
95
  /* On VMS, fopen allows file attributes as optional arguments.
96
     We need to use them but we'd better to use the common prototype.
97
     In fopen-vms.h, they are separated from the mode with a comma.
98
     Split here.  */
99
  vms_attr = strchr (modes, ',');
100
  if (vms_attr != NULL)
101
    {
102
      /* Attributes found.  Split.  */
103
      size_t modes_len = strlen (modes) + 1;
104
      char attrs[modes_len + 1];
105
      char *at[3];
106
      int i;
107
108
      memcpy (attrs, modes, modes_len);
109
      at[0] = attrs;
110
      for (i = 0; i < 2; i++)
111
  {
112
    at[i + 1] = strchr (at[i], ',');
113
    BFD_ASSERT (at[i + 1] != NULL);
114
    *(at[i + 1]++) = 0; /* Replace ',' with a nul, and skip it.  */
115
  }
116
      return close_on_exec (fopen (filename, at[0], at[1], at[2]));
117
    }
118
119
#elif defined (_WIN32)
120
  /* PR 25713: Handle extra long path names possibly containing '..' and '.'.  */
121
   wchar_t **     lpFilePart = {NULL};
122
   const wchar_t  prefix[] = L"\\\\?\\";
123
   const size_t   partPathLen = strlen (filename) + 1;
124
#ifdef __MINGW32__
125
#if !HAVE_DECL____LC_CODEPAGE_FUNC
126
/* This prototype was added to locale.h in version 9.0 of MinGW-w64.  */
127
   _CRTIMP unsigned int __cdecl ___lc_codepage_func (void);
128
#endif
129
   const unsigned int cp = ___lc_codepage_func ();
130
#else
131
   const unsigned int cp = CP_UTF8;
132
#endif
133
134
   /* Converting the partial path from ascii to unicode.
135
      1) Get the length: Calling with lpWideCharStr set to null returns the length.
136
      2) Convert the string: Calling with cbMultiByte set to -1 includes the terminating null.  */
137
   size_t         partPathWSize = MultiByteToWideChar (cp, 0, filename, -1, NULL, 0);
138
   wchar_t *      partPath = calloc (partPathWSize, sizeof(wchar_t));
139
   size_t         ix;
140
141
   MultiByteToWideChar (cp, 0, filename, -1, partPath, partPathWSize);
142
143
   /* Convert any UNIX style path separators into the DOS i.e. backslash separator.  */
144
   for (ix = 0; ix < partPathLen; ix++)
145
     if (IS_UNIX_DIR_SEPARATOR(filename[ix]))
146
       partPath[ix] = '\\';
147
148
   /* Getting the full path from the provided partial path.
149
      1) Get the length.
150
      2) Resolve the path.  */
151
   long       fullPathWSize = GetFullPathNameW (partPath, 0, NULL, lpFilePart);
152
   wchar_t *  fullPath = calloc (fullPathWSize + sizeof(prefix) + 1, sizeof(wchar_t));
153
154
   wcscpy (fullPath, prefix);
155
156
   int        prefixLen = sizeof(prefix) / sizeof(wchar_t);
157
158
   /* Do not add a prefix to the null device.  */
159
   if (stricmp (filename, "nul") == 0)
160
    prefixLen = 1;
161
162
   wchar_t *  fullPathOffset = fullPath + prefixLen - 1;
163
164
   GetFullPathNameW (partPath, fullPathWSize, fullPathOffset, lpFilePart);
165
   free (partPath);
166
167
   /* It is non-standard for modes to exceed 16 characters.  */
168
   wchar_t    modesW[16];
169
170
   MultiByteToWideChar (cp, 0, modes, -1, modesW, sizeof(modesW));
171
172
   FILE *     file = _wfopen (fullPath, modesW);
173
   free (fullPath);
174
175
   return close_on_exec (file);
176
177
#elif defined (HAVE_FOPEN64)
178
136k
  return close_on_exec (fopen64 (filename, modes));
179
180
#else
181
  return close_on_exec (fopen (filename, modes));
182
#endif
183
136k
}
184
185
/*
186
INTERNAL_DEFINITION
187
  struct bfd_iovec
188
189
DESCRIPTION
190
191
  The <<struct bfd_iovec>> contains the internal file I/O class.
192
  Each <<BFD>> has an instance of this class and all file I/O is
193
  routed through it (it is assumed that the instance implements
194
  all methods listed below).
195
196
.struct bfd_iovec
197
.{
198
.  {* To avoid problems with macros, a "b" rather than "f"
199
.     prefix is prepended to each method name.  *}
200
.  {* Attempt to read/write NBYTES on ABFD's IOSTREAM storing/fetching
201
.     bytes starting at PTR.  Return the number of bytes actually
202
.     transfered (a read past end-of-file returns less than NBYTES),
203
.     or -1 (setting <<bfd_error>>) if an error occurs.  *}
204
.  file_ptr (*bread) (struct bfd *abfd, void *ptr, file_ptr nbytes);
205
.  file_ptr (*bwrite) (struct bfd *abfd, const void *ptr,
206
.          file_ptr nbytes);
207
.  {* Return the current IOSTREAM file offset, or -1 (setting <<bfd_error>>
208
.     if an error occurs.  *}
209
.  file_ptr (*btell) (struct bfd *abfd);
210
.  {* For the following, on successful completion a value of 0 is returned.
211
.     Otherwise, a value of -1 is returned (and <<bfd_error>> is set).  *}
212
.  int (*bseek) (struct bfd *abfd, file_ptr offset, int whence);
213
.  int (*bclose) (struct bfd *abfd);
214
.  int (*bflush) (struct bfd *abfd);
215
.  int (*bstat) (struct bfd *abfd, struct stat *sb);
216
.  {* Mmap a part of the files. ADDR, LEN, PROT, FLAGS and OFFSET are the usual
217
.     mmap parameter, except that LEN and OFFSET do not need to be page
218
.     aligned.  Returns (void *)-1 on failure, mmapped address on success.
219
.     Also write in MAP_ADDR the address of the page aligned buffer and in
220
.     MAP_LEN the size mapped (a page multiple).  Use unmap with MAP_ADDR and
221
.     MAP_LEN to unmap.  *}
222
.  void *(*bmmap) (struct bfd *abfd, void *addr, bfd_size_type len,
223
.      int prot, int flags, file_ptr offset,
224
.      void **map_addr, bfd_size_type *map_len);
225
.};
226
227
.extern const struct bfd_iovec _bfd_memory_iovec;
228
.
229
*/
230
231
232
/*
233
FUNCTION
234
  bfd_read
235
236
SYNOPSIS
237
  bfd_size_type bfd_read (void *, bfd_size_type, bfd *)
238
        ATTRIBUTE_WARN_UNUSED_RESULT;
239
240
DESCRIPTION
241
  Attempt to read SIZE bytes from ABFD's iostream to PTR.
242
  Return the amount read.
243
*/
244
245
bfd_size_type
246
bfd_read (void *ptr, bfd_size_type size, bfd *abfd)
247
582M
{
248
582M
  file_ptr nread;
249
582M
  bfd *element_bfd = abfd;
250
582M
  ufile_ptr offset = 0;
251
252
1.07G
  while (abfd->my_archive != NULL
253
1.07G
   && !bfd_is_thin_archive (abfd->my_archive))
254
494M
    {
255
494M
      offset += abfd->origin;
256
494M
      abfd = abfd->my_archive;
257
494M
    }
258
582M
  offset += abfd->origin;
259
260
  /* If this is a non-thin archive element, don't read past the end of
261
     this element.  */
262
582M
  if (element_bfd->arelt_data != NULL
263
582M
      && element_bfd->my_archive != NULL
264
582M
      && !bfd_is_thin_archive (element_bfd->my_archive))
265
484M
    {
266
484M
      bfd_size_type maxbytes = arelt_size (element_bfd);
267
268
484M
      if (abfd->where < offset || abfd->where - offset >= maxbytes)
269
1.36M
  {
270
1.36M
    bfd_set_error (bfd_error_invalid_operation);
271
1.36M
    return -1;
272
1.36M
  }
273
483M
      if (abfd->where - offset + size > maxbytes)
274
3.26M
  size = maxbytes - (abfd->where - offset);
275
483M
    }
276
277
580M
  if (abfd->iovec == NULL)
278
0
    {
279
0
      bfd_set_error (bfd_error_invalid_operation);
280
0
      return -1;
281
0
    }
282
283
580M
  if (abfd->last_io == bfd_io_write)
284
0
    {
285
0
      abfd->last_io = bfd_io_force;
286
0
      if (bfd_seek (abfd, 0, SEEK_CUR) != 0)
287
0
  return -1;
288
0
    }
289
580M
  abfd->last_io = bfd_io_read;
290
291
580M
  nread = abfd->iovec->bread (abfd, ptr, size);
292
580M
  if (nread != -1)
293
580M
    abfd->where += nread;
294
295
580M
  return nread;
296
580M
}
297
298
/*
299
FUNCTION
300
  bfd_write
301
302
SYNOPSIS
303
  bfd_size_type bfd_write (const void *, bfd_size_type, bfd *)
304
        ATTRIBUTE_WARN_UNUSED_RESULT;
305
306
DESCRIPTION
307
  Attempt to write SIZE bytes to ABFD's iostream from PTR.
308
  Return the amount written.
309
*/
310
311
bfd_size_type
312
bfd_write (const void *ptr, bfd_size_type size, bfd *abfd)
313
60.9M
{
314
60.9M
  file_ptr nwrote;
315
316
60.9M
  while (abfd->my_archive != NULL
317
60.9M
   && !bfd_is_thin_archive (abfd->my_archive))
318
0
    abfd = abfd->my_archive;
319
320
60.9M
  if (abfd->iovec == NULL)
321
0
    {
322
0
      bfd_set_error (bfd_error_invalid_operation);
323
0
      return -1;
324
0
    }
325
326
60.9M
  if (abfd->last_io == bfd_io_read)
327
2
    {
328
2
      abfd->last_io = bfd_io_force;
329
2
      if (bfd_seek (abfd, 0, SEEK_CUR) != 0)
330
0
  return -1;
331
2
    }
332
60.9M
  abfd->last_io = bfd_io_write;
333
334
60.9M
  nwrote = abfd->iovec->bwrite (abfd, ptr, size);
335
60.9M
  if (nwrote != -1)
336
60.9M
    abfd->where += nwrote;
337
60.9M
  if ((bfd_size_type) nwrote != size)
338
0
    {
339
0
#ifdef ENOSPC
340
0
      errno = ENOSPC;
341
0
#endif
342
0
      bfd_set_error (bfd_error_system_call);
343
0
    }
344
60.9M
  return nwrote;
345
60.9M
}
346
347
/*
348
FUNCTION
349
  bfd_tell
350
351
SYNOPSIS
352
  file_ptr bfd_tell (bfd *) ATTRIBUTE_WARN_UNUSED_RESULT;
353
354
DESCRIPTION
355
  Return ABFD's iostream file position.
356
*/
357
358
file_ptr
359
bfd_tell (bfd *abfd)
360
5.36M
{
361
5.36M
  ufile_ptr offset = 0;
362
5.36M
  file_ptr ptr;
363
364
7.26M
  while (abfd->my_archive != NULL
365
7.26M
   && !bfd_is_thin_archive (abfd->my_archive))
366
1.89M
    {
367
1.89M
      offset += abfd->origin;
368
1.89M
      abfd = abfd->my_archive;
369
1.89M
    }
370
5.36M
  offset += abfd->origin;
371
372
5.36M
  if (abfd->iovec == NULL)
373
0
    return 0;
374
375
5.36M
  ptr = abfd->iovec->btell (abfd);
376
5.36M
  abfd->where = ptr;
377
5.36M
  return ptr - offset;
378
5.36M
}
379
380
/*
381
FUNCTION
382
  bfd_flush
383
384
SYNOPSIS
385
  int bfd_flush (bfd *);
386
387
DESCRIPTION
388
  Flush ABFD's iostream pending IO.
389
*/
390
391
int
392
bfd_flush (bfd *abfd)
393
1.86k
{
394
1.86k
  while (abfd->my_archive != NULL
395
1.86k
   && !bfd_is_thin_archive (abfd->my_archive))
396
0
    abfd = abfd->my_archive;
397
398
1.86k
  if (abfd->iovec == NULL)
399
0
    return 0;
400
401
1.86k
  return abfd->iovec->bflush (abfd);
402
1.86k
}
403
404
/*
405
FUNCTION
406
  bfd_stat
407
408
SYNOPSIS
409
  int bfd_stat (bfd *, struct stat *) ATTRIBUTE_WARN_UNUSED_RESULT;
410
411
DESCRIPTION
412
  Call fstat on ABFD's iostream.  Return 0 on success, and a
413
  negative value on failure.
414
*/
415
416
int
417
bfd_stat (bfd *abfd, struct stat *statbuf)
418
29.0M
{
419
29.0M
  int result;
420
421
32.1M
  while (abfd->my_archive != NULL
422
32.1M
   && !bfd_is_thin_archive (abfd->my_archive))
423
3.10M
    abfd = abfd->my_archive;
424
425
29.0M
  if (abfd->iovec == NULL)
426
0
    {
427
0
      bfd_set_error (bfd_error_invalid_operation);
428
0
      return -1;
429
0
    }
430
431
29.0M
  result = abfd->iovec->bstat (abfd, statbuf);
432
29.0M
  if (result < 0)
433
0
    bfd_set_error (bfd_error_system_call);
434
29.0M
  return result;
435
29.0M
}
436
437
/*
438
FUNCTION
439
  bfd_seek
440
441
SYNOPSIS
442
  int bfd_seek (bfd *, file_ptr, int) ATTRIBUTE_WARN_UNUSED_RESULT;
443
444
DESCRIPTION
445
  Call fseek on ABFD's iostream.  Return 0 on success, and a
446
  negative value on failure.
447
*/
448
449
int
450
bfd_seek (bfd *abfd, file_ptr position, int direction)
451
560M
{
452
560M
  int result;
453
560M
  ufile_ptr offset = 0;
454
455
1.05G
  while (abfd->my_archive != NULL
456
1.05G
   && !bfd_is_thin_archive (abfd->my_archive))
457
493M
    {
458
493M
      offset += abfd->origin;
459
493M
      abfd = abfd->my_archive;
460
493M
    }
461
560M
  offset += abfd->origin;
462
463
560M
  if (abfd->iovec == NULL)
464
0
    {
465
0
      bfd_set_error (bfd_error_invalid_operation);
466
0
      return -1;
467
0
    }
468
469
  /* For the time being, a BFD may not seek to it's end.  The problem
470
     is that we don't easily have a way to recognize the end of an
471
     element in an archive.  */
472
560M
  BFD_ASSERT (direction == SEEK_SET || direction == SEEK_CUR);
473
474
560M
  if (direction != SEEK_CUR)
475
551M
    position += offset;
476
477
560M
  if (((direction == SEEK_CUR && position == 0)
478
560M
       || (direction == SEEK_SET && (ufile_ptr) position == abfd->where))
479
560M
      && abfd->last_io != bfd_io_force)
480
68.2M
    return 0;
481
482
492M
  abfd->last_io = bfd_io_seek;
483
484
492M
  result = abfd->iovec->bseek (abfd, position, direction);
485
492M
  if (result != 0)
486
46.3k
    {
487
      /* An EINVAL error probably means that the file offset was
488
   absurd.  */
489
46.3k
      if (errno == EINVAL)
490
46.3k
  bfd_set_error (bfd_error_file_truncated);
491
0
      else
492
0
  bfd_set_error (bfd_error_system_call);
493
46.3k
    }
494
492M
  else
495
492M
    {
496
      /* Adjust `where' field.  */
497
492M
      if (direction == SEEK_CUR)
498
9.05M
  abfd->where += position;
499
482M
      else
500
482M
  abfd->where = position;
501
492M
    }
502
503
492M
  return result;
504
560M
}
505
506
/*
507
FUNCTION
508
  bfd_get_mtime
509
510
SYNOPSIS
511
  long bfd_get_mtime (bfd *abfd);
512
513
DESCRIPTION
514
  Return the file modification time (as read from the file system, or
515
  from the archive header for archive members).
516
517
*/
518
519
long
520
bfd_get_mtime (bfd *abfd)
521
0
{
522
0
  struct stat buf;
523
524
0
  if (abfd->mtime_set)
525
0
    return abfd->mtime;
526
527
0
  if (bfd_stat (abfd, &buf) != 0)
528
0
    return 0;
529
530
0
  abfd->mtime = buf.st_mtime;   /* Save value in case anyone wants it */
531
0
  return buf.st_mtime;
532
0
}
533
534
/*
535
FUNCTION
536
  bfd_get_size
537
538
SYNOPSIS
539
  ufile_ptr bfd_get_size (bfd *abfd);
540
541
DESCRIPTION
542
  Return the file size (as read from file system) for the file
543
  associated with BFD @var{abfd}.
544
545
  The initial motivation for, and use of, this routine is not
546
  so we can get the exact size of the object the BFD applies to, since
547
  that might not be generally possible (archive members for example).
548
  It would be ideal if someone could eventually modify
549
  it so that such results were guaranteed.
550
551
  Instead, we want to ask questions like "is this NNN byte sized
552
  object I'm about to try read from file offset YYY reasonable?"
553
  As as example of where we might do this, some object formats
554
  use string tables for which the first <<sizeof (long)>> bytes of the
555
  table contain the size of the table itself, including the size bytes.
556
  If an application tries to read what it thinks is one of these
557
  string tables, without some way to validate the size, and for
558
  some reason the size is wrong (byte swapping error, wrong location
559
  for the string table, etc.), the only clue is likely to be a read
560
  error when it tries to read the table, or a "virtual memory
561
  exhausted" error when it tries to allocate 15 bazillon bytes
562
  of space for the 15 bazillon byte table it is about to read.
563
  This function at least allows us to answer the question, "is the
564
  size reasonable?".
565
566
  A return value of zero indicates the file size is unknown.
567
*/
568
569
ufile_ptr
570
bfd_get_size (bfd *abfd)
571
76.4M
{
572
  /* A size of 0 means we haven't yet called bfd_stat.  A size of 1
573
     means we have a cached value of 0, ie. unknown.  */
574
76.4M
  if (abfd->size <= 1 || bfd_write_p (abfd))
575
25.7M
    {
576
25.7M
      struct stat buf;
577
578
25.7M
      if (abfd->size == 1 && !bfd_write_p (abfd))
579
398
  return 0;
580
581
25.7M
      if (bfd_stat (abfd, &buf) != 0
582
25.7M
    || buf.st_size == 0
583
25.7M
    || buf.st_size - (ufile_ptr) buf.st_size != 0)
584
2
  {
585
2
    abfd->size = 1;
586
2
    return 0;
587
2
  }
588
25.7M
      abfd->size = buf.st_size;
589
25.7M
    }
590
76.4M
  return abfd->size;
591
76.4M
}
592
593
/*
594
FUNCTION
595
  bfd_get_file_size
596
597
SYNOPSIS
598
  ufile_ptr bfd_get_file_size (bfd *abfd);
599
600
DESCRIPTION
601
  Return the file size (as read from file system) for the file
602
  associated with BFD @var{abfd}.  It supports both normal files
603
  and archive elements.
604
605
*/
606
607
ufile_ptr
608
bfd_get_file_size (bfd *abfd)
609
76.4M
{
610
76.4M
  ufile_ptr file_size, archive_size = (ufile_ptr) -1;
611
76.4M
  unsigned int compression_p2 = 0;
612
613
76.4M
  if (abfd->my_archive != NULL
614
76.4M
      && !bfd_is_thin_archive (abfd->my_archive))
615
65.1M
    {
616
65.1M
      struct areltdata *adata = (struct areltdata *) abfd->arelt_data;
617
65.1M
      if (adata != NULL)
618
65.1M
  {
619
65.1M
    archive_size = adata->parsed_size;
620
    /* If the archive is compressed, assume an element won't
621
       expand more than eight times file size.  */
622
65.1M
    if (adata->arch_header != NULL
623
65.1M
        && memcmp (((struct ar_hdr *) adata->arch_header)->ar_fmag,
624
65.1M
       "Z\012", 2) == 0)
625
2.60k
      compression_p2 = 3;
626
65.1M
    abfd = abfd->my_archive;
627
65.1M
  }
628
65.1M
    }
629
630
76.4M
  file_size = bfd_get_size (abfd) << compression_p2;
631
76.4M
  if (archive_size < file_size)
632
4.16M
    return archive_size;
633
72.2M
  return file_size;
634
76.4M
}
635
636
/*
637
FUNCTION
638
  bfd_mmap
639
640
SYNOPSIS
641
  void *bfd_mmap (bfd *abfd, void *addr, bfd_size_type len,
642
      int prot, int flags, file_ptr offset,
643
      void **map_addr, bfd_size_type *map_len)
644
      ATTRIBUTE_WARN_UNUSED_RESULT;
645
646
DESCRIPTION
647
  Return mmap()ed region of the file, if possible and implemented.
648
  LEN and OFFSET do not need to be page aligned.  The page aligned
649
  address and length are written to MAP_ADDR and MAP_LEN.
650
651
*/
652
653
void *
654
bfd_mmap (bfd *abfd, void *addr, bfd_size_type len,
655
    int prot, int flags, file_ptr offset,
656
    void **map_addr, bfd_size_type *map_len)
657
0
{
658
0
  while (abfd->my_archive != NULL
659
0
   && !bfd_is_thin_archive (abfd->my_archive))
660
0
    {
661
0
      offset += abfd->origin;
662
0
      abfd = abfd->my_archive;
663
0
    }
664
0
  offset += abfd->origin;
665
666
0
  if (abfd->iovec == NULL)
667
0
    {
668
0
      bfd_set_error (bfd_error_invalid_operation);
669
0
      return (void *) -1;
670
0
    }
671
672
0
  return abfd->iovec->bmmap (abfd, addr, len, prot, flags, offset,
673
0
           map_addr, map_len);
674
0
}
675
676
/* Memory file I/O operations.  */
677
678
static file_ptr
679
memory_bread (bfd *abfd, void *ptr, file_ptr size)
680
0
{
681
0
  struct bfd_in_memory *bim;
682
0
  bfd_size_type get;
683
684
0
  bim = (struct bfd_in_memory *) abfd->iostream;
685
0
  get = size;
686
0
  if (abfd->where + get > bim->size)
687
0
    {
688
0
      if (bim->size < (bfd_size_type) abfd->where)
689
0
  get = 0;
690
0
      else
691
0
  get = bim->size - abfd->where;
692
0
      bfd_set_error (bfd_error_file_truncated);
693
0
    }
694
0
  memcpy (ptr, bim->buffer + abfd->where, (size_t) get);
695
0
  return get;
696
0
}
697
698
static file_ptr
699
memory_bwrite (bfd *abfd, const void *ptr, file_ptr size)
700
317
{
701
317
  struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream;
702
703
317
  if (abfd->where + size > bim->size)
704
317
    {
705
317
      bfd_size_type newsize, oldsize;
706
707
317
      oldsize = (bim->size + 127) & ~(bfd_size_type) 127;
708
317
      bim->size = abfd->where + size;
709
      /* Round up to cut down on memory fragmentation */
710
317
      newsize = (bim->size + 127) & ~(bfd_size_type) 127;
711
317
      if (newsize > oldsize)
712
317
  {
713
317
    bim->buffer = (bfd_byte *) bfd_realloc_or_free (bim->buffer, newsize);
714
317
    if (bim->buffer == NULL)
715
0
      {
716
0
        bim->size = 0;
717
0
        return 0;
718
0
      }
719
317
    if (newsize > bim->size)
720
66
      memset (bim->buffer + bim->size, 0, newsize - bim->size);
721
317
  }
722
317
    }
723
317
  memcpy (bim->buffer + abfd->where, ptr, (size_t) size);
724
317
  return size;
725
317
}
726
727
static file_ptr
728
memory_btell (bfd *abfd)
729
0
{
730
0
  return abfd->where;
731
0
}
732
733
static int
734
memory_bseek (bfd *abfd, file_ptr position, int direction)
735
0
{
736
0
  file_ptr nwhere;
737
0
  struct bfd_in_memory *bim;
738
739
0
  bim = (struct bfd_in_memory *) abfd->iostream;
740
741
0
  if (direction == SEEK_SET)
742
0
    nwhere = position;
743
0
  else
744
0
    nwhere = abfd->where + position;
745
746
0
  if (nwhere < 0)
747
0
    {
748
0
      abfd->where = 0;
749
0
      errno = EINVAL;
750
0
      return -1;
751
0
    }
752
753
0
  if ((bfd_size_type)nwhere > bim->size)
754
0
    {
755
0
      if (abfd->direction == write_direction
756
0
    || abfd->direction == both_direction)
757
0
  {
758
0
    bfd_size_type newsize, oldsize;
759
760
0
    oldsize = (bim->size + 127) & ~(bfd_size_type) 127;
761
0
    bim->size = nwhere;
762
    /* Round up to cut down on memory fragmentation */
763
0
    newsize = (bim->size + 127) & ~(bfd_size_type) 127;
764
0
    if (newsize > oldsize)
765
0
      {
766
0
        bim->buffer = (bfd_byte *) bfd_realloc_or_free (bim->buffer, newsize);
767
0
        if (bim->buffer == NULL)
768
0
    {
769
0
      errno = EINVAL;
770
0
      bim->size = 0;
771
0
      return -1;
772
0
    }
773
0
        memset (bim->buffer + oldsize, 0, newsize - oldsize);
774
0
      }
775
0
  }
776
0
      else
777
0
  {
778
0
    abfd->where = bim->size;
779
0
    errno = EINVAL;
780
0
    bfd_set_error (bfd_error_file_truncated);
781
0
    return -1;
782
0
  }
783
0
    }
784
0
  return 0;
785
0
}
786
787
static int
788
memory_bclose (struct bfd *abfd)
789
16.2k
{
790
16.2k
  struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream;
791
792
16.2k
  free (bim->buffer);
793
16.2k
  free (bim);
794
16.2k
  abfd->iostream = NULL;
795
796
16.2k
  return 0;
797
16.2k
}
798
799
static int
800
memory_bflush (bfd *abfd ATTRIBUTE_UNUSED)
801
0
{
802
0
  return 0;
803
0
}
804
805
static int
806
memory_bstat (bfd *abfd, struct stat *statbuf)
807
10
{
808
10
  struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream;
809
810
10
  memset (statbuf, 0, sizeof (*statbuf));
811
10
  statbuf->st_size = bim->size;
812
813
10
  return 0;
814
10
}
815
816
static void *
817
memory_bmmap (bfd *abfd ATTRIBUTE_UNUSED, void *addr ATTRIBUTE_UNUSED,
818
        bfd_size_type len ATTRIBUTE_UNUSED, int prot ATTRIBUTE_UNUSED,
819
        int flags ATTRIBUTE_UNUSED, file_ptr offset ATTRIBUTE_UNUSED,
820
        void **map_addr ATTRIBUTE_UNUSED,
821
        bfd_size_type *map_len ATTRIBUTE_UNUSED)
822
0
{
823
0
  return (void *)-1;
824
0
}
825
826
const struct bfd_iovec _bfd_memory_iovec =
827
{
828
  &memory_bread, &memory_bwrite, &memory_btell, &memory_bseek,
829
  &memory_bclose, &memory_bflush, &memory_bstat, &memory_bmmap
830
};