(root)/
binutils-2.41/
binutils/
bucomm.c
       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  {
      39    const char *errmsg;
      40    enum bfd_error err = bfd_get_error ();
      41  
      42    if (err == bfd_error_no_error)
      43      errmsg = _("cause of error unknown");
      44    else
      45      errmsg = bfd_errmsg (err);
      46    fflush (stdout);
      47    if (string)
      48      fprintf (stderr, "%s: %s: %s\n", program_name, string, errmsg);
      49    else
      50      fprintf (stderr, "%s: %s\n", program_name, errmsg);
      51  }
      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  {
      71    const char *errmsg;
      72    const char *section_name;
      73    enum bfd_error err = bfd_get_error ();
      74  
      75    if (err == bfd_error_no_error)
      76      errmsg = _("cause of error unknown");
      77    else
      78      errmsg = bfd_errmsg (err);
      79    fflush (stdout);
      80    section_name = NULL;
      81    fprintf (stderr, "%s", program_name);
      82  
      83    if (abfd)
      84      {
      85        if (!filename)
      86  	filename = bfd_get_archive_filename (abfd);
      87        if (section)
      88  	section_name = bfd_section_name (section);
      89      }
      90    if (section_name)
      91      fprintf (stderr, ": %s[%s]", filename, section_name);
      92    else
      93      fprintf (stderr, ": %s", filename);
      94  
      95    if (format)
      96      {
      97        va_list args;
      98        va_start (args, format);
      99        fprintf (stderr, ": ");
     100        vfprintf (stderr, format, args);
     101        va_end (args);
     102      }
     103    fprintf (stderr, ": %s\n", errmsg);
     104  }
     105  
     106  void
     107  bfd_fatal (const char *string)
     108  {
     109    bfd_nonfatal (string);
     110    xexit (1);
     111  }
     112  
     113  void
     114  report (const char * format, va_list args)
     115  {
     116    fflush (stdout);
     117    fprintf (stderr, "%s: ", program_name);
     118    vfprintf (stderr, format, args);
     119    putc ('\n', stderr);
     120  }
     121  
     122  void
     123  fatal (const char *format, ...)
     124  {
     125    va_list args;
     126  
     127    va_start (args, format);
     128  
     129    report (format, args);
     130    va_end (args);
     131    xexit (1);
     132  }
     133  
     134  void
     135  non_fatal (const char *format, ...)
     136  {
     137    va_list args;
     138  
     139    va_start (args, format);
     140  
     141    report (format, args);
     142    va_end (args);
     143  }
     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  {
     152    void *ret = bfd_alloc (abfd, size);
     153    if (ret == NULL)
     154      bfd_fatal (NULL);
     155    return ret;
     156  }
     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  {
     166    /* The macro TARGET is defined by Makefile.  */
     167    const char *target = TARGET;
     168  
     169    if (! bfd_set_default_target (target))
     170      fatal (_("can't set BFD default target to `%s': %s"),
     171  	   target, bfd_errmsg (bfd_get_error ()));
     172  }
     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  {
     181    fflush (stdout);
     182    fprintf (stderr, _("%s: Matching formats:"), program_name);
     183    char **p = matching;
     184    while (*p)
     185      fprintf (stderr, " %s", *p++);
     186    free (matching);
     187    fputc ('\n', stderr);
     188  }
     189  
     190  /* List the supported targets.  */
     191  
     192  void
     193  list_supported_targets (const char *name, FILE *f)
     194  {
     195    int t;
     196    const char **targ_names;
     197  
     198    if (name == NULL)
     199      fprintf (f, _("Supported targets:"));
     200    else
     201      fprintf (f, _("%s: supported targets:"), name);
     202  
     203    targ_names = bfd_target_list ();
     204    for (t = 0; targ_names[t] != NULL; t++)
     205      fprintf (f, " %s", targ_names[t]);
     206    fprintf (f, "\n");
     207    free (targ_names);
     208  }
     209  
     210  /* List the supported architectures.  */
     211  
     212  void
     213  list_supported_architectures (const char *name, FILE *f)
     214  {
     215    const char ** arch;
     216    const char ** arches;
     217  
     218    if (name == NULL)
     219      fprintf (f, _("Supported architectures:"));
     220    else
     221      fprintf (f, _("%s: supported architectures:"), name);
     222  
     223    for (arch = arches = bfd_arch_list (); *arch; arch++)
     224      fprintf (f, " %s", *arch);
     225    fprintf (f, "\n");
     226    free (arches);
     227  }
     228  
     229  static const char *
     230  endian_string (enum bfd_endian endian)
     231  {
     232    switch (endian)
     233      {
     234      case BFD_ENDIAN_BIG: return _("big endian");
     235      case BFD_ENDIAN_LITTLE: return _("little endian");
     236      default: return _("endianness unknown");
     237      }
     238  }
     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  {
     267    struct display_target *param = (struct display_target *) data;
     268    bfd *abfd;
     269    size_t amt;
     270  
     271    param->count += 1;
     272    amt = param->count * sizeof (*param->info);
     273    if (param->alloc < amt)
     274      {
     275        size_t size = ((param->count < 64 ? 64 : param->count)
     276  		     * sizeof (*param->info) * 2);
     277        param->info = xrealloc (param->info, size);
     278        memset ((char *) param->info + param->alloc, 0, size - param->alloc);
     279        param->alloc = size;
     280      }
     281    param->info[param->count - 1].name = targ->name;
     282  
     283    printf (_("%s\n (header %s, data %s)\n"), targ->name,
     284  	  endian_string (targ->header_byteorder),
     285  	  endian_string (targ->byteorder));
     286  
     287    abfd = bfd_openw (param->filename, targ->name);
     288    if (abfd == NULL)
     289      {
     290        bfd_nonfatal (param->filename);
     291        param->error = 1;
     292      }
     293    else if (!bfd_set_format (abfd, bfd_object))
     294      {
     295        if (bfd_get_error () != bfd_error_invalid_operation)
     296  	{
     297  	  bfd_nonfatal (targ->name);
     298  	  param->error = 1;
     299  	}
     300      }
     301    else
     302      {
     303        enum bfd_architecture a;
     304  
     305        for (a = bfd_arch_obscure + 1; a < bfd_arch_last; a++)
     306  	if (bfd_set_arch_mach (abfd, a, 0))
     307  	  {
     308  	    printf ("  %s\n", bfd_printable_arch_mach (a, 0));
     309  	    param->info[param->count - 1].arch[a - bfd_arch_obscure - 1] = 1;
     310  	  }
     311      }
     312    if (abfd != NULL)
     313      bfd_close_all_done (abfd);
     314  
     315    return param->error;
     316  }
     317  
     318  static void
     319  display_target_list (struct display_target *arg)
     320  {
     321    arg->filename = make_temp_file (NULL);
     322    arg->error = 0;
     323    arg->count = 0;
     324    arg->alloc = 0;
     325    arg->info = NULL;
     326  
     327    bfd_iterate_over_targets (do_display_target, arg);
     328  
     329    unlink (arg->filename);
     330    free (arg->filename);
     331  }
     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  {
     338    while (targ < arg->count)
     339      {
     340        width -= strlen (arg->info[targ].name) + 1;
     341        if (width < 0)
     342  	return targ;
     343        ++targ;
     344      }
     345    return targ;
     346  }
     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  {
     353    while (targ != stop_targ)
     354      printf ("%s ", arg->info[targ++].name);
     355  }
     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  {
     363    while (targ != stop_targ)
     364      {
     365        if (arg->info[targ].arch[a - bfd_arch_obscure - 1])
     366  	fputs (arg->info[targ].name, stdout);
     367        else
     368  	{
     369  	  int l = strlen (arg->info[targ].name);
     370  	  while (l--)
     371  	    putchar ('-');
     372  	}
     373        ++targ;
     374        if (targ != stop_targ)
     375  	putchar (' ');
     376      }
     377  }
     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  {
     385    const char *columns;
     386    int width, start_targ, stop_targ;
     387    enum bfd_architecture arch;
     388    int longest_arch = 0;
     389  
     390    for (arch = bfd_arch_obscure + 1; arch < bfd_arch_last; arch++)
     391      {
     392        const char *s = bfd_printable_arch_mach (arch, 0);
     393        int len = strlen (s);
     394        if (len > longest_arch)
     395  	longest_arch = len;
     396      }
     397  
     398    width = 0;
     399    columns = getenv ("COLUMNS");
     400    if (columns != NULL)
     401      width = atoi (columns);
     402    if (width == 0)
     403      width = 80;
     404  
     405    for (start_targ = 0; start_targ < arg->count; start_targ = stop_targ)
     406      {
     407        stop_targ = do_info_size (start_targ, width - longest_arch - 1, arg);
     408  
     409        printf ("\n%*s", longest_arch + 1, " ");
     410        do_info_header (start_targ, stop_targ, arg);
     411        putchar ('\n');
     412  
     413        for (arch = bfd_arch_obscure + 1; arch < bfd_arch_last; arch++)
     414  	{
     415  	  if (strcmp (bfd_printable_arch_mach (arch, 0), "UNKNOWN!") != 0)
     416  	    {
     417  	      printf ("%*s ", longest_arch,
     418  		      bfd_printable_arch_mach (arch, 0));
     419  
     420  	      do_info_row (start_targ, stop_targ, arch, arg);
     421  	      putchar ('\n');
     422  	    }
     423  	}
     424      }
     425  }
     426  
     427  int
     428  display_info (void)
     429  {
     430    struct display_target arg;
     431  
     432    printf (_("BFD header file version %s\n"), BFD_VERSION_STRING);
     433  
     434    display_target_list (&arg);
     435    if (!arg.error)
     436      display_target_tables (&arg);
     437  
     438    return arg.error;
     439  }
     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  {
     448    struct stat buf;
     449  
     450    if (verbose)
     451      {
     452        if (bfd_stat_arch_elt (abfd, &buf) == 0)
     453  	{
     454  	  char modebuf[11];
     455  	  char timebuf[40];
     456  	  time_t when = buf.st_mtime;
     457  	  const char *ctime_result = (const char *) ctime (&when);
     458  
     459  	  /* PR binutils/17605: Check for corrupt time values.  */
     460  	  if (ctime_result == NULL)
     461  	    sprintf (timebuf, _("<time data corrupt>"));
     462  	  else
     463  	    /* POSIX format:  skip weekday and seconds from ctime output.  */
     464  	    sprintf (timebuf, "%.12s %.4s", ctime_result + 4, ctime_result + 20);
     465  
     466  	  mode_string (buf.st_mode, modebuf);
     467  	  modebuf[10] = '\0';
     468  	  /* POSIX 1003.2/D11 says to skip first character (entry type).  */
     469  	  fprintf (file, "%s %ld/%ld %6" PRIu64 " %s ", modebuf + 1,
     470  		   (long) buf.st_uid, (long) buf.st_gid,
     471  		   (uint64_t) buf.st_size, timebuf);
     472  	}
     473      }
     474  
     475    fprintf (file, "%s", bfd_get_filename (abfd));
     476  
     477    if (offsets)
     478      {
     479        if (bfd_is_thin_archive (abfd) && abfd->proxy_origin)
     480          fprintf (file, " 0x%lx", (unsigned long) abfd->proxy_origin);
     481        else if (!bfd_is_thin_archive (abfd) && abfd->origin)
     482          fprintf (file, " 0x%lx", (unsigned long) abfd->origin);
     483      }
     484  
     485    fprintf (file, "\n");
     486  }
     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  {
     494  #define template "stXXXXXX"
     495    const char *slash = strrchr (path, '/');
     496    char *tmpname;
     497    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    if (slash != (char *) NULL)
     512      {
     513        len = slash - path;
     514        tmpname = (char *) xmalloc (len + sizeof (template) + 2);
     515        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        tmpname[len++] = '/';
     525      }
     526    else
     527      {
     528        tmpname = (char *) xmalloc (sizeof (template));
     529        len = 0;
     530      }
     531  
     532    memcpy (tmpname + len, template, sizeof (template));
     533    return tmpname;
     534  #undef template
     535  }
     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  {
     543    char *tmpname = template_in_dir (filename);
     544    int fd;
     545  
     546  #ifdef HAVE_MKSTEMP
     547    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    if (fd == -1)
     556      {
     557        free (tmpname);
     558        bfd_set_error (bfd_error_system_call);
     559        return NULL;
     560      }
     561    *ofd = fd;
     562    return tmpname;
     563  }
     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  {
     571    char *tmpname = template_in_dir (filename);
     572    char *ret;
     573  
     574  #ifdef HAVE_MKDTEMP
     575    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    if (ret == NULL)
     587      {
     588        free (tmpname);
     589        bfd_set_error (bfd_error_system_call);
     590      }
     591    return ret;
     592  }
     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  {
     600    bfd_vma ret;
     601    const char *end;
     602  
     603    ret = bfd_scan_vma (s, &end, 0);
     604  
     605    if (*end != '\0')
     606      fatal (_("%s: bad number: %s"), arg, s);
     607  
     608    return ret;
     609  }
     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  {
     618    struct stat statbuf;
     619  
     620    if (file_name == NULL)
     621      return (off_t) -1;
     622  
     623    if (stat (file_name, &statbuf) < 0)
     624      {
     625        if (errno == ENOENT)
     626  	non_fatal (_("'%s': No such file"), file_name);
     627        else
     628  	non_fatal (_("Warning: could not locate '%s'.  reason: %s"),
     629  		   file_name, strerror (errno));
     630      }
     631    else if (S_ISDIR (statbuf.st_mode))
     632      non_fatal (_("Warning: '%s' is a directory"), file_name);
     633    else if (! S_ISREG (statbuf.st_mode))
     634      non_fatal (_("Warning: '%s' is not an ordinary file"), file_name);
     635    else if (statbuf.st_size < 0)
     636      non_fatal (_("Warning: '%s' has negative size, probably it is too large"),
     637                 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    else
     654      return statbuf.st_size;
     655  
     656    return (off_t) -1;
     657  }
     658  
     659  /* Return the filename in a static buffer.  */
     660  
     661  const char *
     662  bfd_get_archive_filename (const bfd *abfd)
     663  {
     664    static size_t curr = 0;
     665    static char *buf;
     666    size_t needed;
     667  
     668    assert (abfd != NULL);
     669  
     670    if (abfd->my_archive == NULL
     671        || bfd_is_thin_archive (abfd->my_archive))
     672      return bfd_get_filename (abfd);
     673  
     674    needed = (strlen (bfd_get_filename (abfd->my_archive))
     675  	    + strlen (bfd_get_filename (abfd)) + 3);
     676    if (needed > curr)
     677      {
     678        if (curr)
     679  	free (buf);
     680        curr = needed + (needed >> 1);
     681        buf = (char *) xmalloc (curr);
     682      }
     683    sprintf (buf, "%s(%s)", bfd_get_filename (abfd->my_archive),
     684  	   bfd_get_filename (abfd));
     685    return buf;
     686  }
     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  {
     695    const char * n = pathname;
     696  
     697    if (IS_ABSOLUTE_PATH (n))
     698      return false;
     699  
     700    while (*n)
     701      {
     702        if (*n == '.' && *++n == '.' && ( ! *++n || IS_DIR_SEPARATOR (*n)))
     703  	return false;
     704  
     705        while (*n && ! IS_DIR_SEPARATOR (*n))
     706  	n++;
     707        while (IS_DIR_SEPARATOR (*n))
     708  	n++;
     709      }
     710  
     711    return true;
     712  }