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