129615Sjmg/* bucomm.c -- Bin Utils COMmon code.
229615Sjmg   Copyright 1991, 1992, 1993, 1994, 1995, 1997, 1998, 2000, 2001, 2002, 2003
329615Sjmg   Free Software Foundation, Inc.
429615Sjmg
529615Sjmg   This file is part of GNU Binutils.
629615Sjmg
729615Sjmg   This program is free software; you can redistribute it and/or modify
829615Sjmg   it under the terms of the GNU General Public License as published by
929615Sjmg   the Free Software Foundation; either version 2 of the License, or
1029615Sjmg   (at your option) any later version.
1129615Sjmg
1229615Sjmg   This program is distributed in the hope that it will be useful,
1329615Sjmg   but WITHOUT ANY WARRANTY; without even the implied warranty of
1429615Sjmg   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1529615Sjmg   GNU General Public License for more details.
1629615Sjmg
1729615Sjmg   You should have received a copy of the GNU General Public License
1829615Sjmg   along with this program; if not, write to the Free Software
1929615Sjmg   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
2029615Sjmg   02110-1301, USA.  */
2129615Sjmg
2229615Sjmg/* We might put this in a library someday so it could be dynamically
2329615Sjmg   loaded, but for now it's not necessary.  */
2429615Sjmg
2529615Sjmg#include "bfd.h"
2629615Sjmg#include "bfdver.h"
27124125Scharnier#include "libiberty.h"
28124125Scharnier#include "bucomm.h"
29124125Scharnier#include "filenames.h"
3029615Sjmg#include "libbfd.h"
3129615Sjmg
32124125Scharnier#include <sys/stat.h>
3329615Sjmg#include <time.h>		/* ctime, maybe time_t */
3429615Sjmg#include <assert.h>
3529615Sjmg
3629615Sjmg#ifndef HAVE_TIME_T_IN_TIME_H
3729615Sjmg#ifndef HAVE_TIME_T_IN_TYPES_H
3829615Sjmgtypedef long time_t;
3929615Sjmg#endif
4029615Sjmg#endif
4150786Speter
4229615Sjmgstatic const char * endian_string (enum bfd_endian);
4329615Sjmgstatic int display_target_list (void);
4429615Sjmgstatic int display_info_table (int, int);
4529615Sjmgstatic int display_target_tables (void);
4629615Sjmg
4729615Sjmg/* Error reporting.  */
4829615Sjmg
4929615Sjmgchar *program_name;
5029615Sjmg
5129615Sjmgvoid
5229615Sjmgbfd_nonfatal (const char *string)
5329615Sjmg{
5429615Sjmg  const char *errmsg = bfd_errmsg (bfd_get_error ());
5529615Sjmg
5639144Seivind  if (string)
5729615Sjmg    fprintf (stderr, "%s: %s: %s\n", program_name, string, errmsg);
5829615Sjmg  else
5929615Sjmg    fprintf (stderr, "%s: %s\n", program_name, errmsg);
6029615Sjmg}
6129615Sjmg
6229615Sjmgvoid
6329615Sjmgbfd_fatal (const char *string)
6429615Sjmg{
6529615Sjmg  bfd_nonfatal (string);
6629615Sjmg  xexit (1);
6731135Sjmg}
6829615Sjmg
6929615Sjmgvoid
7029615Sjmgreport (const char * format, va_list args)
7129615Sjmg{
7229615Sjmg  fprintf (stderr, "%s: ", program_name);
7329615Sjmg  vfprintf (stderr, format, args);
7429615Sjmg  putc ('\n', stderr);
7529615Sjmg}
7629615Sjmg
7729615Sjmgvoid
7829615Sjmgfatal VPARAMS ((const char *format, ...))
7929615Sjmg{
8029615Sjmg  VA_OPEN (args, format);
8129615Sjmg  VA_FIXEDARG (args, const char *, format);
8229615Sjmg
8329615Sjmg  report (format, args);
8429615Sjmg  VA_CLOSE (args);
8529615Sjmg  xexit (1);
8629615Sjmg}
8729615Sjmg
8829615Sjmgvoid
8929615Sjmgnon_fatal VPARAMS ((const char *format, ...))
9029615Sjmg{
9129615Sjmg  VA_OPEN (args, format);
9229615Sjmg  VA_FIXEDARG (args, const char *, format);
9329615Sjmg
9429615Sjmg  report (format, args);
9529615Sjmg  VA_CLOSE (args);
9629615Sjmg}
9729615Sjmg
9829615Sjmg/* Set the default BFD target based on the configured target.  Doing
9929615Sjmg   this permits the binutils to be configured for a particular target,
10029615Sjmg   and linked against a shared BFD library which was configured for a
10129615Sjmg   different target.  */
10229615Sjmg
10329615Sjmgvoid
10429615Sjmgset_default_bfd_target (void)
10529615Sjmg{
10629615Sjmg  /* The macro TARGET is defined by Makefile.  */
10729615Sjmg  const char *target = TARGET;
10829615Sjmg
10929615Sjmg  if (! bfd_set_default_target (target))
11029615Sjmg    fatal (_("can't set BFD default target to `%s': %s"),
11129615Sjmg	   target, bfd_errmsg (bfd_get_error ()));
11229615Sjmg}
11329615Sjmg
11429615Sjmg/* After a FALSE return from bfd_check_format_matches with
11529615Sjmg   bfd_get_error () == bfd_error_file_ambiguously_recognized, print
11629615Sjmg   the possible matching targets.  */
11750786Speter
11829615Sjmgvoid
11929615Sjmglist_matching_formats (char **p)
12029615Sjmg{
12129615Sjmg  fprintf (stderr, _("%s: Matching formats:"), program_name);
12229615Sjmg  while (*p)
12329615Sjmg    fprintf (stderr, " %s", *p++);
12429615Sjmg  fputc ('\n', stderr);
12529615Sjmg}
12629615Sjmg
12729615Sjmg/* List the supported targets.  */
12829615Sjmg
12929615Sjmgvoid
13029615Sjmglist_supported_targets (const char *name, FILE *f)
13129615Sjmg{
13229615Sjmg  int t;
13329615Sjmg  const char **targ_names = bfd_target_list ();
13429615Sjmg
13529615Sjmg  if (name == NULL)
13629615Sjmg    fprintf (f, _("Supported targets:"));
13729615Sjmg  else
13829615Sjmg    fprintf (f, _("%s: supported targets:"), name);
13929615Sjmg
14029615Sjmg  for (t = 0; targ_names[t] != NULL; t++)
14129615Sjmg    fprintf (f, " %s", targ_names[t]);
14229615Sjmg  fprintf (f, "\n");
14329615Sjmg  free (targ_names);
14429615Sjmg}
14529615Sjmg
14629615Sjmg/* List the supported architectures.  */
14729615Sjmg
14829615Sjmgvoid
14929615Sjmglist_supported_architectures (const char *name, FILE *f)
15029615Sjmg{
15129615Sjmg  const char **arch;
15229615Sjmg
15329615Sjmg  if (name == NULL)
15429615Sjmg    fprintf (f, _("Supported architectures:"));
15529615Sjmg  else
15629615Sjmg    fprintf (f, _("%s: supported architectures:"), name);
15729615Sjmg
15829615Sjmg  for (arch = bfd_arch_list (); *arch; arch++)
15929615Sjmg    fprintf (f, " %s", *arch);
16029615Sjmg  fprintf (f, "\n");
16129615Sjmg}
16229615Sjmg
16329615Sjmg/* The length of the longest architecture name + 1.  */
16429615Sjmg#define LONGEST_ARCH sizeof ("powerpc:common")
16529615Sjmg
16629615Sjmgstatic const char *
16729615Sjmgendian_string (enum bfd_endian endian)
16829615Sjmg{
16929615Sjmg  switch (endian)
17029615Sjmg    {
17129615Sjmg    case BFD_ENDIAN_BIG: return "big endian";
17229615Sjmg    case BFD_ENDIAN_LITTLE: return "little endian";
17329615Sjmg    default: return "endianness unknown";
17450786Speter    }
17529615Sjmg}
17629615Sjmg
17729615Sjmg/* List the targets that BFD is configured to support, each followed
17829615Sjmg   by its endianness and the architectures it supports.  */
17929615Sjmg
18029615Sjmgstatic int
18129615Sjmgdisplay_target_list (void)
18229615Sjmg{
18329615Sjmg  char *dummy_name;
18450786Speter  int t;
18529615Sjmg  int ret = 1;
18629615Sjmg
18729615Sjmg  dummy_name = make_temp_file (NULL);
18829615Sjmg  for (t = 0; bfd_target_vector[t]; t++)
18929615Sjmg    {
19029615Sjmg      const bfd_target *p = bfd_target_vector[t];
19129615Sjmg      bfd *abfd = bfd_openw (dummy_name, p->name);
19229615Sjmg      enum bfd_architecture a;
19329615Sjmg
19429615Sjmg      printf ("%s\n (header %s, data %s)\n", p->name,
19529615Sjmg	      endian_string (p->header_byteorder),
19629615Sjmg	      endian_string (p->byteorder));
19729615Sjmg
19829615Sjmg      if (abfd == NULL)
19929615Sjmg	{
20029615Sjmg          bfd_nonfatal (dummy_name);
20129615Sjmg          ret = 0;
20229615Sjmg	  continue;
20329615Sjmg	}
20429615Sjmg
20529615Sjmg      if (! bfd_set_format (abfd, bfd_object))
20629615Sjmg	{
20729615Sjmg	  if (bfd_get_error () != bfd_error_invalid_operation)
20829615Sjmg            {
20929615Sjmg	      bfd_nonfatal (p->name);
21029615Sjmg              ret = 0;
21129615Sjmg            }
21229615Sjmg	  bfd_close_all_done (abfd);
21329615Sjmg	  continue;
21429615Sjmg	}
21529615Sjmg
21629615Sjmg      for (a = bfd_arch_obscure + 1; a < bfd_arch_last; a++)
21729615Sjmg	if (bfd_set_arch_mach (abfd, (enum bfd_architecture) a, 0))
21829615Sjmg	  printf ("  %s\n",
21929615Sjmg		  bfd_printable_arch_mach ((enum bfd_architecture) a, 0));
22029615Sjmg      bfd_close_all_done (abfd);
22129615Sjmg    }
22229615Sjmg  unlink (dummy_name);
22329615Sjmg  free (dummy_name);
22429615Sjmg
22529615Sjmg  return ret;
22629615Sjmg}
22729615Sjmg
22829615Sjmg/* Print a table showing which architectures are supported for entries
22929615Sjmg   FIRST through LAST-1 of bfd_target_vector (targets across,
23029615Sjmg   architectures down).  */
23129615Sjmg
23229615Sjmgstatic int
23329615Sjmgdisplay_info_table (int first, int last)
23429615Sjmg{
23529615Sjmg  int t;
23629615Sjmg  int ret = 1;
23729615Sjmg  char *dummy_name;
23829615Sjmg  enum bfd_architecture a;
23929615Sjmg
24029615Sjmg  /* Print heading of target names.  */
24129615Sjmg  printf ("\n%*s", (int) LONGEST_ARCH, " ");
24229615Sjmg  for (t = first; t < last && bfd_target_vector[t]; t++)
24329615Sjmg    printf ("%s ", bfd_target_vector[t]->name);
24429615Sjmg  putchar ('\n');
24529615Sjmg
24629615Sjmg  dummy_name = make_temp_file (NULL);
24729615Sjmg  for (a = bfd_arch_obscure + 1; a < bfd_arch_last; a++)
24829615Sjmg    if (strcmp (bfd_printable_arch_mach (a, 0), "UNKNOWN!") != 0)
24929615Sjmg      {
25029615Sjmg	printf ("%*s ", (int) LONGEST_ARCH - 1,
25129615Sjmg		bfd_printable_arch_mach (a, 0));
25229615Sjmg	for (t = first; t < last && bfd_target_vector[t]; t++)
25329615Sjmg	  {
25429615Sjmg	    const bfd_target *p = bfd_target_vector[t];
25529615Sjmg	    bfd_boolean ok = TRUE;
25629615Sjmg	    bfd *abfd = bfd_openw (dummy_name, p->name);
25729615Sjmg
25829615Sjmg	    if (abfd == NULL)
25929615Sjmg	      {
26029615Sjmg		bfd_nonfatal (p->name);
26129615Sjmg                ret = 0;
26229615Sjmg		ok = FALSE;
26329615Sjmg	      }
26429615Sjmg
26529615Sjmg	    if (ok)
26629615Sjmg	      {
26729615Sjmg		if (! bfd_set_format (abfd, bfd_object))
26829615Sjmg		  {
26929615Sjmg		    if (bfd_get_error () != bfd_error_invalid_operation)
27029615Sjmg                      {
27129615Sjmg		        bfd_nonfatal (p->name);
27229615Sjmg                        ret = 0;
27329615Sjmg                      }
27429615Sjmg		    ok = FALSE;
27529615Sjmg		  }
27629615Sjmg	      }
27729615Sjmg
27829615Sjmg	    if (ok)
27929615Sjmg	      {
28029615Sjmg		if (! bfd_set_arch_mach (abfd, a, 0))
28129615Sjmg		  ok = FALSE;
28229615Sjmg	      }
28329615Sjmg
28429615Sjmg	    if (ok)
28529615Sjmg	      printf ("%s ", p->name);
28629615Sjmg	    else
28729615Sjmg	      {
28829615Sjmg		int l = strlen (p->name);
28929615Sjmg		while (l--)
29029615Sjmg		  putchar ('-');
29129615Sjmg		putchar (' ');
29229615Sjmg	      }
29329615Sjmg	    if (abfd != NULL)
29429615Sjmg	      bfd_close_all_done (abfd);
29529615Sjmg	  }
29629615Sjmg	putchar ('\n');
29729615Sjmg      }
29829615Sjmg  unlink (dummy_name);
29929615Sjmg  free (dummy_name);
30029615Sjmg
30129615Sjmg  return ret;
30229615Sjmg}
30329615Sjmg
30429615Sjmg/* Print tables of all the target-architecture combinations that
30529615Sjmg   BFD has been configured to support.  */
30629615Sjmg
30729615Sjmgstatic int
30850786Speterdisplay_target_tables (void)
30929615Sjmg{
31029615Sjmg  int t;
31129615Sjmg  int columns;
31250786Speter  int ret = 1;
31329615Sjmg  char *colum;
31429615Sjmg
31529615Sjmg  columns = 0;
31629615Sjmg  colum = getenv ("COLUMNS");
31729615Sjmg  if (colum != NULL)
31829615Sjmg    columns = atoi (colum);
31929615Sjmg  if (columns == 0)
32029615Sjmg    columns = 80;
32129615Sjmg
32229615Sjmg  t = 0;
32329615Sjmg  while (bfd_target_vector[t] != NULL)
32429615Sjmg    {
32529615Sjmg      int oldt = t, wid;
32629615Sjmg
32729615Sjmg      wid = LONGEST_ARCH + strlen (bfd_target_vector[t]->name) + 1;
32829615Sjmg      ++t;
32929615Sjmg      while (wid < columns && bfd_target_vector[t] != NULL)
33029615Sjmg	{
33129615Sjmg	  int newwid;
33250786Speter
33329615Sjmg	  newwid = wid + strlen (bfd_target_vector[t]->name) + 1;
33429615Sjmg	  if (newwid >= columns)
33529615Sjmg	    break;
33629615Sjmg	  wid = newwid;
33729615Sjmg	  ++t;
33829615Sjmg	}
33929615Sjmg      if (! display_info_table (oldt, t))
34050786Speter        ret = 0;
34129615Sjmg    }
34229615Sjmg
34329615Sjmg  return ret;
34429615Sjmg}
34529615Sjmg
34629615Sjmgint
34729615Sjmgdisplay_info (void)
34829615Sjmg{
34929615Sjmg  printf (_("BFD header file version %s\n"), BFD_VERSION_STRING);
35029615Sjmg  if (! display_target_list () || ! display_target_tables ())
35129615Sjmg    return 1;
35229615Sjmg  else
35329615Sjmg    return 0;
35429615Sjmg}
35529615Sjmg
35629615Sjmg/* Display the archive header for an element as if it were an ls -l listing:
35729615Sjmg
35829615Sjmg   Mode       User\tGroup\tSize\tDate               Name */
35929615Sjmg
36029615Sjmgvoid
36129615Sjmgprint_arelt_descr (FILE *file, bfd *abfd, bfd_boolean verbose)
36250786Speter{
36329615Sjmg  struct stat buf;
36429615Sjmg
36529615Sjmg  if (verbose)
36629615Sjmg    {
36729615Sjmg      if (bfd_stat_arch_elt (abfd, &buf) == 0)
36829615Sjmg	{
36929615Sjmg	  char modebuf[11];
37050786Speter	  char timebuf[40];
37129615Sjmg	  time_t when = buf.st_mtime;
37229615Sjmg	  const char *ctime_result = (const char *) ctime (&when);
37329615Sjmg
37429615Sjmg	  /* POSIX format:  skip weekday and seconds from ctime output.  */
37529615Sjmg	  sprintf (timebuf, "%.12s %.4s", ctime_result + 4, ctime_result + 20);
37629615Sjmg
37729615Sjmg	  mode_string (buf.st_mode, modebuf);
37829615Sjmg	  modebuf[10] = '\0';
37929615Sjmg	  /* POSIX 1003.2/D11 says to skip first character (entry type).  */
38029615Sjmg	  fprintf (file, "%s %ld/%ld %6ld %s ", modebuf + 1,
38129615Sjmg		   (long) buf.st_uid, (long) buf.st_gid,
38229615Sjmg		   (long) buf.st_size, timebuf);
38329615Sjmg	}
38429615Sjmg    }
38529615Sjmg
38650786Speter  fprintf (file, "%s\n", bfd_get_filename (abfd));
38729615Sjmg}
38829615Sjmg
38950786Speter/* Return the name of a temporary file in the same directory as FILENAME.  */
39029615Sjmg
39129615Sjmgchar *
39229615Sjmgmake_tempname (char *filename, int isdir)
39329615Sjmg{
39429615Sjmg  static char template[] = "stXXXXXX";
39529615Sjmg  char *tmpname;
39629615Sjmg  char *slash = strrchr (filename, '/');
39729615Sjmg  char c = '/';
39829615Sjmg
39950786Speter#ifdef HAVE_DOS_BASED_FILE_SYSTEM
40029615Sjmg  {
40129615Sjmg    /* We could have foo/bar\\baz, or foo\\bar, or d:bar.  */
40229615Sjmg    char *bslash = strrchr (filename, '\\');
40329615Sjmg    if (slash == NULL || (bslash != NULL && bslash > slash))
40429615Sjmg      slash = bslash;
40550786Speter    if (slash == NULL && filename[0] != '\0' && filename[1] == ':')
40629615Sjmg      slash = filename + 1;
40729615Sjmg  }
40829615Sjmg#endif
40950786Speter
41029615Sjmg  if (slash != (char *) NULL)
41129615Sjmg    {
41250786Speter      c = *slash;
41329615Sjmg      *slash = 0;
41429615Sjmg      tmpname = xmalloc (strlen (filename) + sizeof (template) + 2);
41529615Sjmg      strcpy (tmpname, filename);
41629615Sjmg#ifdef HAVE_DOS_BASED_FILE_SYSTEM
41729615Sjmg      /* If tmpname is "X:", appending a slash will make it a root
41829615Sjmg	 directory on drive X, which is NOT the same as the current
41929615Sjmg	 directory on drive X.  */
42029615Sjmg      if (tmpname[1] == ':' && tmpname[2] == '\0')
42129615Sjmg	strcat (tmpname, ".");
42229615Sjmg#endif
42329615Sjmg      strcat (tmpname, "/");
42429615Sjmg      strcat (tmpname, template);
42529615Sjmg    }
42629615Sjmg  else
42729615Sjmg    {
42829615Sjmg      tmpname = xmalloc (sizeof (template));
42950786Speter      strcpy (tmpname, template);
43029615Sjmg    }
43129615Sjmg
43229615Sjmg  if (isdir)
43329615Sjmg    {
43429615Sjmg      if (mkdtemp (tmpname) == (char *) NULL)
43529615Sjmg      tmpname = NULL;
43629615Sjmg    }
43729615Sjmg  else
43829615Sjmg    {
43929615Sjmg      int fd;
44050786Speter
44129615Sjmg      fd = mkstemp (tmpname);
44229615Sjmg      if (fd == -1)
44329615Sjmg      tmpname = NULL;
44429615Sjmg      else
44529615Sjmg      close (fd);
44629615Sjmg    }
44729615Sjmg  if (slash != (char *) NULL)
44829615Sjmg    *slash = c;
44950786Speter
45029615Sjmg  return tmpname;
45129615Sjmg}
45250786Speter
45329615Sjmg/* Parse a string into a VMA, with a fatal error if it can't be
45429615Sjmg   parsed.  */
45550786Speter
45629615Sjmgbfd_vma
45729615Sjmgparse_vma (const char *s, const char *arg)
45850786Speter{
45929615Sjmg  bfd_vma ret;
46029615Sjmg  const char *end;
46150786Speter
46250786Speter  ret = bfd_scan_vma (s, &end, 0);
46329615Sjmg
46429615Sjmg  if (*end != '\0')
46550786Speter    fatal (_("%s: bad number: %s"), arg, s);
46629615Sjmg
46729615Sjmg  return ret;
46829615Sjmg}
46929615Sjmg
47029615Sjmg/* Returns the size of the named file.  If the file does not
47129615Sjmg   exist, or if it is not a real file, then a suitable non-fatal
47229615Sjmg   error message is printed and zero is returned.  */
47329615Sjmg
47429615Sjmgoff_t
47529615Sjmgget_file_size (const char * file_name)
47629615Sjmg{
47729615Sjmg  struct stat statbuf;
47829615Sjmg
47929615Sjmg  if (stat (file_name, &statbuf) < 0)
48029615Sjmg    {
48129615Sjmg      if (errno == ENOENT)
48229615Sjmg	non_fatal (_("'%s': No such file"), file_name);
48329615Sjmg      else
48429615Sjmg	non_fatal (_("Warning: could not locate '%s'.  reason: %s"),
48529615Sjmg		   file_name, strerror (errno));
48629615Sjmg    }
48729615Sjmg  else if (! S_ISREG (statbuf.st_mode))
48850786Speter    non_fatal (_("Warning: '%s' is not an ordinary file"), file_name);
48950786Speter  else
49029615Sjmg    return statbuf.st_size;
49129615Sjmg
49229615Sjmg  return 0;
49329615Sjmg}
49429615Sjmg
49529615Sjmg/* Return the filename in a static buffer.  */
49639144Seivind
49729615Sjmgconst char *
49829615Sjmgbfd_get_archive_filename (bfd *abfd)
49939144Seivind{
50039144Seivind  static size_t curr = 0;
50129615Sjmg  static char *buf;
50229615Sjmg  size_t needed;
50339144Seivind
50429615Sjmg  assert (abfd != NULL);
50529615Sjmg
50629615Sjmg  if (!abfd->my_archive)
50729615Sjmg    return bfd_get_filename (abfd);
50846422Sluoqi
50946422Sluoqi  needed = (strlen (bfd_get_filename (abfd->my_archive))
51029615Sjmg	    + strlen (bfd_get_filename (abfd)) + 3);
51146422Sluoqi  if (needed > curr)
51229615Sjmg    {
51329615Sjmg      if (curr)
51429615Sjmg	free (buf);
51529615Sjmg      curr = needed + (needed >> 1);
51629615Sjmg      buf = bfd_malloc (curr);
51739144Seivind      /* If we can't malloc, fail safe by returning just the file name.
51829615Sjmg	 This function is only used when building error messages.  */
51929615Sjmg      if (!buf)
52029615Sjmg	{
52129615Sjmg	  curr = 0;
52229615Sjmg	  return bfd_get_filename (abfd);
52350786Speter	}
52429615Sjmg    }
52529615Sjmg  sprintf (buf, "%s(%s)", bfd_get_filename (abfd->my_archive),
52629615Sjmg	   bfd_get_filename (abfd));
52729615Sjmg  return buf;
52829615Sjmg}
52929615Sjmg