Coverage Report

Created: 2023-08-28 06:23

/src/binutils-gdb/binutils/bucomm.c
Line
Count
Source (jump to first uncovered line)
1
/* bucomm.c -- Bin Utils COMmon code.
2
   Copyright (C) 1991-2023 Free Software Foundation, Inc.
3
4
   This file is part of GNU Binutils.
5
6
   This program is free software; you can redistribute it and/or modify
7
   it under the terms of the GNU General Public License as published by
8
   the Free Software Foundation; either version 3 of the License, or
9
   (at your option) any later version.
10
11
   This program is distributed in the hope that it will be useful,
12
   but WITHOUT ANY WARRANTY; without even the implied warranty of
13
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
   GNU General Public License for more details.
15
16
   You should have received a copy of the GNU General Public License
17
   along with this program; if not, write to the Free Software
18
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
19
   02110-1301, USA.  */
20

21
/* We might put this in a library someday so it could be dynamically
22
   loaded, but for now it's not necessary.  */
23
24
#include "sysdep.h"
25
#include "bfd.h"
26
#include "libiberty.h"
27
#include "filenames.h"
28
#include <time.h>
29
#include <assert.h>
30
#include "bucomm.h"
31

32
/* Error reporting.  */
33
34
char *program_name;
35
36
void
37
bfd_nonfatal (const char *string)
38
0
{
39
0
  const char *errmsg;
40
0
  enum bfd_error err = bfd_get_error ();
41
42
0
  if (err == bfd_error_no_error)
43
0
    errmsg = _("cause of error unknown");
44
0
  else
45
0
    errmsg = bfd_errmsg (err);
46
0
  fflush (stdout);
47
0
  if (string)
48
0
    fprintf (stderr, "%s: %s: %s\n", program_name, string, errmsg);
49
0
  else
50
0
    fprintf (stderr, "%s: %s\n", program_name, errmsg);
51
0
}
52
53
/* Issue a non fatal error message.  FILENAME, or if NULL then BFD,
54
   are used to indicate the problematic file.  SECTION, if non NULL,
55
   is used to provide a section name.  If FORMAT is non-null, then it
56
   is used to print additional information via vfprintf.  Finally the
57
   bfd error message is printed.  In summary, error messages are of
58
   one of the following forms:
59
60
   PROGRAM: file: bfd-error-message
61
   PROGRAM: file[section]: bfd-error-message
62
   PROGRAM: file: printf-message: bfd-error-message
63
   PROGRAM: file[section]: printf-message: bfd-error-message.  */
64
65
void
66
bfd_nonfatal_message (const char *filename,
67
          const bfd *abfd,
68
          const asection *section,
69
          const char *format, ...)
70
0
{
71
0
  const char *errmsg;
72
0
  const char *section_name;
73
0
  enum bfd_error err = bfd_get_error ();
74
75
0
  if (err == bfd_error_no_error)
76
0
    errmsg = _("cause of error unknown");
77
0
  else
78
0
    errmsg = bfd_errmsg (err);
79
0
  fflush (stdout);
80
0
  section_name = NULL;
81
0
  fprintf (stderr, "%s", program_name);
82
83
0
  if (abfd)
84
0
    {
85
0
      if (!filename)
86
0
  filename = bfd_get_archive_filename (abfd);
87
0
      if (section)
88
0
  section_name = bfd_section_name (section);
89
0
    }
90
0
  if (section_name)
91
0
    fprintf (stderr, ": %s[%s]", filename, section_name);
92
0
  else
93
0
    fprintf (stderr, ": %s", filename);
94
95
0
  if (format)
96
0
    {
97
0
      va_list args;
98
0
      va_start (args, format);
99
0
      fprintf (stderr, ": ");
100
0
      vfprintf (stderr, format, args);
101
0
      va_end (args);
102
0
    }
103
0
  fprintf (stderr, ": %s\n", errmsg);
104
0
}
105
106
void
107
bfd_fatal (const char *string)
108
0
{
109
0
  bfd_nonfatal (string);
110
0
  xexit (1);
111
0
}
112
113
void
114
report (const char * format, va_list args)
115
0
{
116
0
  fflush (stdout);
117
0
  fprintf (stderr, "%s: ", program_name);
118
0
  vfprintf (stderr, format, args);
119
0
  putc ('\n', stderr);
120
0
}
121
122
void
123
fatal (const char *format, ...)
124
0
{
125
0
  va_list args;
126
127
0
  va_start (args, format);
128
129
0
  report (format, args);
130
0
  va_end (args);
131
0
  xexit (1);
132
0
}
133
134
void
135
non_fatal (const char *format, ...)
136
0
{
137
0
  va_list args;
138
139
0
  va_start (args, format);
140
141
0
  report (format, args);
142
0
  va_end (args);
143
0
}
144
145
/* Like xmalloc except that ABFD's objalloc memory is returned.
146
   Use objalloc_free_block to free this memory and all more recently
147
   allocated, or more usually, leave it to bfd_close to free.  */
148
149
void *
150
bfd_xalloc (bfd *abfd, size_t size)
151
0
{
152
0
  void *ret = bfd_alloc (abfd, size);
153
0
  if (ret == NULL)
154
0
    bfd_fatal (NULL);
155
0
  return ret;
156
0
}
157
158
/* Set the default BFD target based on the configured target.  Doing
159
   this permits the binutils to be configured for a particular target,
160
   and linked against a shared BFD library which was configured for a
161
   different target.  */
162
163
void
164
set_default_bfd_target (void)
165
0
{
166
  /* The macro TARGET is defined by Makefile.  */
167
0
  const char *target = TARGET;
168
169
0
  if (! bfd_set_default_target (target))
170
0
    fatal (_("can't set BFD default target to `%s': %s"),
171
0
     target, bfd_errmsg (bfd_get_error ()));
172
0
}
173
174
/* After a FALSE return from bfd_check_format_matches with
175
   bfd_get_error () == bfd_error_file_ambiguously_recognized, print
176
   the possible matching targets and free the list of targets.  */
177
178
void
179
list_matching_formats (char **matching)
180
0
{
181
0
  fflush (stdout);
182
0
  fprintf (stderr, _("%s: Matching formats:"), program_name);
183
0
  char **p = matching;
184
0
  while (*p)
185
0
    fprintf (stderr, " %s", *p++);
186
0
  free (matching);
187
0
  fputc ('\n', stderr);
188
0
}
189
190
/* List the supported targets.  */
191
192
void
193
list_supported_targets (const char *name, FILE *f)
194
0
{
195
0
  int t;
196
0
  const char **targ_names;
197
198
0
  if (name == NULL)
199
0
    fprintf (f, _("Supported targets:"));
200
0
  else
201
0
    fprintf (f, _("%s: supported targets:"), name);
202
203
0
  targ_names = bfd_target_list ();
204
0
  for (t = 0; targ_names[t] != NULL; t++)
205
0
    fprintf (f, " %s", targ_names[t]);
206
0
  fprintf (f, "\n");
207
0
  free (targ_names);
208
0
}
209
210
/* List the supported architectures.  */
211
212
void
213
list_supported_architectures (const char *name, FILE *f)
214
0
{
215
0
  const char ** arch;
216
0
  const char ** arches;
217
218
0
  if (name == NULL)
219
0
    fprintf (f, _("Supported architectures:"));
220
0
  else
221
0
    fprintf (f, _("%s: supported architectures:"), name);
222
223
0
  for (arch = arches = bfd_arch_list (); *arch; arch++)
224
0
    fprintf (f, " %s", *arch);
225
0
  fprintf (f, "\n");
226
0
  free (arches);
227
0
}
228

229
static const char *
230
endian_string (enum bfd_endian endian)
231
0
{
232
0
  switch (endian)
233
0
    {
234
0
    case BFD_ENDIAN_BIG: return _("big endian");
235
0
    case BFD_ENDIAN_LITTLE: return _("little endian");
236
0
    default: return _("endianness unknown");
237
0
    }
238
0
}
239
240
/* Data passed to do_display_target and other target iterators.  */
241
242
struct display_target {
243
  /* Temp file.  */
244
  char *filename;
245
  /* Return status.  */
246
  int error;
247
  /* Number of targets.  */
248
  int count;
249
  /* Size of info in bytes.  */
250
  size_t alloc;
251
  /* Per-target info.  */
252
  struct {
253
    /* Target name.  */
254
    const char *name;
255
    /* Non-zero if target/arch combination supported.  */
256
    unsigned char arch[bfd_arch_last - bfd_arch_obscure - 1];
257
  } *info;
258
};
259
260
/* List the targets that BFD is configured to support, each followed
261
   by its endianness and the architectures it supports.  Also build
262
   info about target/archs.  */
263
264
static int
265
do_display_target (const bfd_target *targ, void *data)
266
0
{
267
0
  struct display_target *param = (struct display_target *) data;
268
0
  bfd *abfd;
269
0
  size_t amt;
270
271
0
  param->count += 1;
272
0
  amt = param->count * sizeof (*param->info);
273
0
  if (param->alloc < amt)
274
0
    {
275
0
      size_t size = ((param->count < 64 ? 64 : param->count)
276
0
         * sizeof (*param->info) * 2);
277
0
      param->info = xrealloc (param->info, size);
278
0
      memset ((char *) param->info + param->alloc, 0, size - param->alloc);
279
0
      param->alloc = size;
280
0
    }
281
0
  param->info[param->count - 1].name = targ->name;
282
283
0
  printf (_("%s\n (header %s, data %s)\n"), targ->name,
284
0
    endian_string (targ->header_byteorder),
285
0
    endian_string (targ->byteorder));
286
287
0
  abfd = bfd_openw (param->filename, targ->name);
288
0
  if (abfd == NULL)
289
0
    {
290
0
      bfd_nonfatal (param->filename);
291
0
      param->error = 1;
292
0
    }
293
0
  else if (!bfd_set_format (abfd, bfd_object))
294
0
    {
295
0
      if (bfd_get_error () != bfd_error_invalid_operation)
296
0
  {
297
0
    bfd_nonfatal (targ->name);
298
0
    param->error = 1;
299
0
  }
300
0
    }
301
0
  else
302
0
    {
303
0
      enum bfd_architecture a;
304
305
0
      for (a = bfd_arch_obscure + 1; a < bfd_arch_last; a++)
306
0
  if (bfd_set_arch_mach (abfd, a, 0))
307
0
    {
308
0
      printf ("  %s\n", bfd_printable_arch_mach (a, 0));
309
0
      param->info[param->count - 1].arch[a - bfd_arch_obscure - 1] = 1;
310
0
    }
311
0
    }
312
0
  if (abfd != NULL)
313
0
    bfd_close_all_done (abfd);
314
315
0
  return param->error;
316
0
}
317
318
static void
319
display_target_list (struct display_target *arg)
320
0
{
321
0
  arg->filename = make_temp_file (NULL);
322
0
  arg->error = 0;
323
0
  arg->count = 0;
324
0
  arg->alloc = 0;
325
0
  arg->info = NULL;
326
327
0
  bfd_iterate_over_targets (do_display_target, arg);
328
329
0
  unlink (arg->filename);
330
0
  free (arg->filename);
331
0
}
332
333
/* Calculate how many targets we can print across the page.  */
334
335
static int
336
do_info_size (int targ, int width, const struct display_target *arg)
337
0
{
338
0
  while (targ < arg->count)
339
0
    {
340
0
      width -= strlen (arg->info[targ].name) + 1;
341
0
      if (width < 0)
342
0
  return targ;
343
0
      ++targ;
344
0
    }
345
0
  return targ;
346
0
}
347
348
/* Print header of target names.  */
349
350
static void
351
do_info_header (int targ, int stop_targ, const struct display_target *arg)
352
0
{
353
0
  while (targ != stop_targ)
354
0
    printf ("%s ", arg->info[targ++].name);
355
0
}
356
357
/* Print a table row.  */
358
359
static void
360
do_info_row (int targ, int stop_targ, enum bfd_architecture a,
361
       const struct display_target *arg)
362
0
{
363
0
  while (targ != stop_targ)
364
0
    {
365
0
      if (arg->info[targ].arch[a - bfd_arch_obscure - 1])
366
0
  fputs (arg->info[targ].name, stdout);
367
0
      else
368
0
  {
369
0
    int l = strlen (arg->info[targ].name);
370
0
    while (l--)
371
0
      putchar ('-');
372
0
  }
373
0
      ++targ;
374
0
      if (targ != stop_targ)
375
0
  putchar (' ');
376
0
    }
377
0
}
378
379
/* Print tables of all the target-architecture combinations that
380
   BFD has been configured to support.  */
381
382
static void
383
display_target_tables (const struct display_target *arg)
384
0
{
385
0
  const char *columns;
386
0
  int width, start_targ, stop_targ;
387
0
  enum bfd_architecture arch;
388
0
  int longest_arch = 0;
389
390
0
  for (arch = bfd_arch_obscure + 1; arch < bfd_arch_last; arch++)
391
0
    {
392
0
      const char *s = bfd_printable_arch_mach (arch, 0);
393
0
      int len = strlen (s);
394
0
      if (len > longest_arch)
395
0
  longest_arch = len;
396
0
    }
397
398
0
  width = 0;
399
0
  columns = getenv ("COLUMNS");
400
0
  if (columns != NULL)
401
0
    width = atoi (columns);
402
0
  if (width == 0)
403
0
    width = 80;
404
405
0
  for (start_targ = 0; start_targ < arg->count; start_targ = stop_targ)
406
0
    {
407
0
      stop_targ = do_info_size (start_targ, width - longest_arch - 1, arg);
408
409
0
      printf ("\n%*s", longest_arch + 1, " ");
410
0
      do_info_header (start_targ, stop_targ, arg);
411
0
      putchar ('\n');
412
413
0
      for (arch = bfd_arch_obscure + 1; arch < bfd_arch_last; arch++)
414
0
  {
415
0
    if (strcmp (bfd_printable_arch_mach (arch, 0), "UNKNOWN!") != 0)
416
0
      {
417
0
        printf ("%*s ", longest_arch,
418
0
          bfd_printable_arch_mach (arch, 0));
419
420
0
        do_info_row (start_targ, stop_targ, arch, arg);
421
0
        putchar ('\n');
422
0
      }
423
0
  }
424
0
    }
425
0
}
426
427
int
428
display_info (void)
429
0
{
430
0
  struct display_target arg;
431
432
0
  printf (_("BFD header file version %s\n"), BFD_VERSION_STRING);
433
434
0
  display_target_list (&arg);
435
0
  if (!arg.error)
436
0
    display_target_tables (&arg);
437
438
0
  return arg.error;
439
0
}
440

441
/* Display the archive header for an element as if it were an ls -l listing:
442
443
   Mode       User\tGroup\tSize\tDate               Name */
444
445
void
446
print_arelt_descr (FILE *file, bfd *abfd, bool verbose, bool offsets)
447
0
{
448
0
  struct stat buf;
449
450
0
  if (verbose)
451
0
    {
452
0
      if (bfd_stat_arch_elt (abfd, &buf) == 0)
453
0
  {
454
0
    char modebuf[11];
455
0
    char timebuf[40];
456
0
    time_t when = buf.st_mtime;
457
0
    const char *ctime_result = (const char *) ctime (&when);
458
459
    /* PR binutils/17605: Check for corrupt time values.  */
460
0
    if (ctime_result == NULL)
461
0
      sprintf (timebuf, _("<time data corrupt>"));
462
0
    else
463
      /* POSIX format:  skip weekday and seconds from ctime output.  */
464
0
      sprintf (timebuf, "%.12s %.4s", ctime_result + 4, ctime_result + 20);
465
466
0
    mode_string (buf.st_mode, modebuf);
467
0
    modebuf[10] = '\0';
468
    /* POSIX 1003.2/D11 says to skip first character (entry type).  */
469
0
    fprintf (file, "%s %ld/%ld %6" PRIu64 " %s ", modebuf + 1,
470
0
       (long) buf.st_uid, (long) buf.st_gid,
471
0
       (uint64_t) buf.st_size, timebuf);
472
0
  }
473
0
    }
474
475
0
  fprintf (file, "%s", bfd_get_filename (abfd));
476
477
0
  if (offsets)
478
0
    {
479
0
      if (bfd_is_thin_archive (abfd) && abfd->proxy_origin)
480
0
        fprintf (file, " 0x%lx", (unsigned long) abfd->proxy_origin);
481
0
      else if (!bfd_is_thin_archive (abfd) && abfd->origin)
482
0
        fprintf (file, " 0x%lx", (unsigned long) abfd->origin);
483
0
    }
484
485
0
  fprintf (file, "\n");
486
0
}
487
488
/* Return a path for a new temporary file in the same directory
489
   as file PATH.  */
490
491
static char *
492
template_in_dir (const char *path)
493
0
{
494
0
#define template "stXXXXXX"
495
0
  const char *slash = strrchr (path, '/');
496
0
  char *tmpname;
497
0
  size_t len;
498
499
#ifdef HAVE_DOS_BASED_FILE_SYSTEM
500
  {
501
    /* We could have foo/bar\\baz, or foo\\bar, or d:bar.  */
502
    char *bslash = strrchr (path, '\\');
503
504
    if (slash == NULL || (bslash != NULL && bslash > slash))
505
      slash = bslash;
506
    if (slash == NULL && path[0] != '\0' && path[1] == ':')
507
      slash = path + 1;
508
  }
509
#endif
510
511
0
  if (slash != (char *) NULL)
512
0
    {
513
0
      len = slash - path;
514
0
      tmpname = (char *) xmalloc (len + sizeof (template) + 2);
515
0
      memcpy (tmpname, path, len);
516
517
#ifdef HAVE_DOS_BASED_FILE_SYSTEM
518
      /* If tmpname is "X:", appending a slash will make it a root
519
   directory on drive X, which is NOT the same as the current
520
   directory on drive X.  */
521
      if (len == 2 && tmpname[1] == ':')
522
  tmpname[len++] = '.';
523
#endif
524
0
      tmpname[len++] = '/';
525
0
    }
526
0
  else
527
0
    {
528
0
      tmpname = (char *) xmalloc (sizeof (template));
529
0
      len = 0;
530
0
    }
531
532
0
  memcpy (tmpname + len, template, sizeof (template));
533
0
  return tmpname;
534
0
#undef template
535
0
}
536
537
/* Return the name of a created temporary file in the same directory
538
   as FILENAME.  */
539
540
char *
541
make_tempname (const char *filename, int *ofd)
542
0
{
543
0
  char *tmpname = template_in_dir (filename);
544
0
  int fd;
545
546
0
#ifdef HAVE_MKSTEMP
547
0
  fd = mkstemp (tmpname);
548
#else
549
  tmpname = mktemp (tmpname);
550
  if (tmpname == NULL)
551
    fd = -1;
552
  else
553
    fd = open (tmpname, O_RDWR | O_CREAT | O_EXCL, 0600);
554
#endif
555
0
  if (fd == -1)
556
0
    {
557
0
      free (tmpname);
558
0
      bfd_set_error (bfd_error_system_call);
559
0
      return NULL;
560
0
    }
561
0
  *ofd = fd;
562
0
  return tmpname;
563
0
}
564
565
/* Return the name of a created temporary directory inside the
566
   directory containing FILENAME.  */
567
568
char *
569
make_tempdir (const char *filename)
570
0
{
571
0
  char *tmpname = template_in_dir (filename);
572
0
  char *ret;
573
574
0
#ifdef HAVE_MKDTEMP
575
0
  ret = mkdtemp (tmpname);
576
#else
577
  ret = mktemp (tmpname);
578
#if defined (_WIN32) && !defined (__CYGWIN32__)
579
  if (mkdir (tmpname) != 0)
580
    ret = NULL;
581
#else
582
  if (mkdir (tmpname, 0700) != 0)
583
    ret = NULL;
584
#endif
585
#endif
586
0
  if (ret == NULL)
587
0
    {
588
0
      free (tmpname);
589
0
      bfd_set_error (bfd_error_system_call);
590
0
    }
591
0
  return ret;
592
0
}
593
594
/* Parse a string into a VMA, with a fatal error if it can't be
595
   parsed.  */
596
597
bfd_vma
598
parse_vma (const char *s, const char *arg)
599
0
{
600
0
  bfd_vma ret;
601
0
  const char *end;
602
603
0
  ret = bfd_scan_vma (s, &end, 0);
604
605
0
  if (*end != '\0')
606
0
    fatal (_("%s: bad number: %s"), arg, s);
607
608
0
  return ret;
609
0
}
610
611
/* Returns the size of the named file.  If the file does not
612
   exist, or if it is not a real file, then a suitable non-fatal
613
   error message is printed and (off_t) -1 is returned.  */
614
615
off_t
616
get_file_size (const char * file_name)
617
0
{
618
0
  struct stat statbuf;
619
620
0
  if (file_name == NULL)
621
0
    return (off_t) -1;
622
623
0
  if (stat (file_name, &statbuf) < 0)
624
0
    {
625
0
      if (errno == ENOENT)
626
0
  non_fatal (_("'%s': No such file"), file_name);
627
0
      else
628
0
  non_fatal (_("Warning: could not locate '%s'.  reason: %s"),
629
0
       file_name, strerror (errno));
630
0
    }
631
0
  else if (S_ISDIR (statbuf.st_mode))
632
0
    non_fatal (_("Warning: '%s' is a directory"), file_name);
633
0
  else if (! S_ISREG (statbuf.st_mode))
634
0
    non_fatal (_("Warning: '%s' is not an ordinary file"), file_name);
635
0
  else if (statbuf.st_size < 0)
636
0
    non_fatal (_("Warning: '%s' has negative size, probably it is too large"),
637
0
               file_name);
638
#if defined (_WIN32) && !defined (__CYGWIN__)
639
  else if (statbuf.st_size == 0)
640
    {
641
      /* MS-Windows 'stat' reports the null device as a regular file;
642
   fix that.  */
643
      int fd = open (file_name, O_RDONLY | O_BINARY);
644
      if (isatty (fd))
645
  {
646
    close (fd);
647
    non_fatal (_("Warning: '%s' is not an ordinary file"),
648
         /* libtool wants to see /dev/null in the output.  */
649
         strcasecmp (file_name, "nul") ? file_name : "/dev/null");
650
  }
651
    }
652
#endif
653
0
  else
654
0
    return statbuf.st_size;
655
656
0
  return (off_t) -1;
657
0
}
658
659
/* Return the filename in a static buffer.  */
660
661
const char *
662
bfd_get_archive_filename (const bfd *abfd)
663
0
{
664
0
  static size_t curr = 0;
665
0
  static char *buf;
666
0
  size_t needed;
667
668
0
  assert (abfd != NULL);
669
670
0
  if (abfd->my_archive == NULL
671
0
      || bfd_is_thin_archive (abfd->my_archive))
672
0
    return bfd_get_filename (abfd);
673
674
0
  needed = (strlen (bfd_get_filename (abfd->my_archive))
675
0
      + strlen (bfd_get_filename (abfd)) + 3);
676
0
  if (needed > curr)
677
0
    {
678
0
      if (curr)
679
0
  free (buf);
680
0
      curr = needed + (needed >> 1);
681
0
      buf = (char *) xmalloc (curr);
682
0
    }
683
0
  sprintf (buf, "%s(%s)", bfd_get_filename (abfd->my_archive),
684
0
     bfd_get_filename (abfd));
685
0
  return buf;
686
0
}
687
688
/* Returns TRUE iff PATHNAME, a filename of an archive member,
689
   is valid for writing.  For security reasons absolute paths
690
   and paths containing /../ are not allowed.  See PR 17533.  */
691
692
bool
693
is_valid_archive_path (char const * pathname)
694
0
{
695
0
  const char * n = pathname;
696
697
0
  if (IS_ABSOLUTE_PATH (n))
698
0
    return false;
699
700
0
  while (*n)
701
0
    {
702
0
      if (*n == '.' && *++n == '.' && ( ! *++n || IS_DIR_SEPARATOR (*n)))
703
0
  return false;
704
705
0
      while (*n && ! IS_DIR_SEPARATOR (*n))
706
0
  n++;
707
0
      while (IS_DIR_SEPARATOR (*n))
708
0
  n++;
709
0
    }
710
711
0
  return true;
712
0
}