X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=binutils%2Fbucomm.c;h=fd73070623f740245ea3a990b796360a31f64f86;hb=4b95cf5c0c75d6efc1b2f96af72317aecca079f1;hp=6b4223c2b9fb47551b75772f06f060f09c382ef2;hpb=fa0cd59bc68a9257b6f8df708b223b9dcf961657;p=binutils-gdb.git diff --git a/binutils/bucomm.c b/binutils/bucomm.c index 6b4223c2b9f..fd73070623f 100644 --- a/binutils/bucomm.c +++ b/binutils/bucomm.c @@ -1,11 +1,11 @@ /* bucomm.c -- Bin Utils COMmon code. - Copyright (C) 1991, 92, 93, 94, 95, 1997 Free Software Foundation, Inc. + Copyright (C) 1991-2014 Free Software Foundation, Inc. This file is part of GNU Binutils. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -15,18 +15,21 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - 02111-1307, USA. */ + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, USA. */ /* We might put this in a library someday so it could be dynamically loaded, but for now it's not necessary. */ +#include "sysdep.h" #include "bfd.h" #include "libiberty.h" -#include "bucomm.h" +#include "filenames.h" +#include "libbfd.h" -#include #include /* ctime, maybe time_t */ +#include +#include "bucomm.h" #ifndef HAVE_TIME_T_IN_TIME_H #ifndef HAVE_TIME_T_IN_TYPES_H @@ -34,68 +37,115 @@ typedef long time_t; #endif #endif -#ifdef ANSI_PROTOTYPES -#include -#else -#include -#endif - -char *target = NULL; /* default as late as possible */ +static const char * endian_string (enum bfd_endian); +static int display_target_list (void); +static int display_info_table (int, int); +static int display_target_tables (void); -/* Error reporting */ +/* Error reporting. */ char *program_name; void -bfd_nonfatal (string) - CONST char *string; +bfd_nonfatal (const char *string) { - CONST char *errmsg = bfd_errmsg (bfd_get_error ()); + const char *errmsg; + errmsg = bfd_errmsg (bfd_get_error ()); + fflush (stdout); if (string) fprintf (stderr, "%s: %s: %s\n", program_name, string, errmsg); else fprintf (stderr, "%s: %s\n", program_name, errmsg); } +/* Issue a non fatal error message. FILENAME, or if NULL then BFD, + are used to indicate the problematic file. SECTION, if non NULL, + is used to provide a section name. If FORMAT is non-null, then it + is used to print additional information via vfprintf. Finally the + bfd error message is printed. In summary, error messages are of + one of the following forms: + + PROGRAM:file: bfd-error-message + PROGRAM:file[section]: bfd-error-message + PROGRAM:file: printf-message: bfd-error-message + PROGRAM:file[section]: printf-message: bfd-error-message. */ + void -bfd_fatal (string) - CONST char *string; +bfd_nonfatal_message (const char *filename, + const bfd *abfd, + const asection *section, + const char *format, ...) +{ + const char *errmsg; + const char *section_name; + va_list args; + + errmsg = bfd_errmsg (bfd_get_error ()); + fflush (stdout); + section_name = NULL; + va_start (args, format); + fprintf (stderr, "%s", program_name); + + if (abfd) + { + if (!filename) + filename = bfd_get_archive_filename (abfd); + if (section) + section_name = bfd_get_section_name (abfd, section); + } + if (section_name) + fprintf (stderr, ":%s[%s]", filename, section_name); + else + fprintf (stderr, ":%s", filename); + + if (format) + { + fprintf (stderr, ": "); + vfprintf (stderr, format, args); + } + fprintf (stderr, ": %s\n", errmsg); + va_end (args); +} + +void +bfd_fatal (const char *string) { bfd_nonfatal (string); xexit (1); } -#ifdef ANSI_PROTOTYPES +void +report (const char * format, va_list args) +{ + fflush (stdout); + fprintf (stderr, "%s: ", program_name); + vfprintf (stderr, format, args); + putc ('\n', stderr); +} + void fatal (const char *format, ...) { va_list args; - fprintf (stderr, "%s: ", program_name); va_start (args, format); - vfprintf (stderr, format, args); + + report (format, args); va_end (args); - putc ('\n', stderr); xexit (1); } -#else -void -fatal (va_alist) - va_dcl + +void +non_fatal (const char *format, ...) { - char *Format; va_list args; - fprintf (stderr, "%s: ", program_name); - va_start (args); - Format = va_arg (args, char *); - vfprintf (stderr, Format, args); + va_start (args, format); + + report (format, args); va_end (args); - putc ('\n', stderr); - xexit (1); } -#endif /* Set the default BFD target based on the configured target. Doing this permits the binutils to be configured for a particular target, @@ -103,52 +153,261 @@ fatal (va_alist) different target. */ void -set_default_bfd_target () +set_default_bfd_target (void) { /* The macro TARGET is defined by Makefile. */ const char *target = TARGET; if (! bfd_set_default_target (target)) - { - char *errmsg; - - errmsg = (char *) xmalloc (100 + strlen (target)); - sprintf (errmsg, "can't set BFD default target to `%s'", target); - bfd_fatal (errmsg); - } + fatal (_("can't set BFD default target to `%s': %s"), + target, bfd_errmsg (bfd_get_error ())); } -/* After a false return from bfd_check_format_matches with +/* After a FALSE return from bfd_check_format_matches with bfd_get_error () == bfd_error_file_ambiguously_recognized, print the possible matching targets. */ void -list_matching_formats (p) - char **p; +list_matching_formats (char **p) { - fprintf(stderr, "%s: Matching formats:", program_name); + fflush (stdout); + fprintf (stderr, _("%s: Matching formats:"), program_name); while (*p) - fprintf(stderr, " %s", *p++); - fprintf(stderr, "\n"); + fprintf (stderr, " %s", *p++); + fputc ('\n', stderr); } /* List the supported targets. */ void -list_supported_targets (name, f) - const char *name; - FILE *f; +list_supported_targets (const char *name, FILE *f) { - extern bfd_target *bfd_target_vector[]; int t; + const char **targ_names; + + if (name == NULL) + fprintf (f, _("Supported targets:")); + else + fprintf (f, _("%s: supported targets:"), name); + + targ_names = bfd_target_list (); + for (t = 0; targ_names[t] != NULL; t++) + fprintf (f, " %s", targ_names[t]); + fprintf (f, "\n"); + free (targ_names); +} + +/* List the supported architectures. */ + +void +list_supported_architectures (const char *name, FILE *f) +{ + const char ** arch; + const char ** arches; if (name == NULL) - fprintf (f, "Supported targets:"); + fprintf (f, _("Supported architectures:")); else - fprintf (f, "%s: supported targets:", name); - for (t = 0; bfd_target_vector[t] != NULL; t++) - fprintf (f, " %s", bfd_target_vector[t]->name); + fprintf (f, _("%s: supported architectures:"), name); + + for (arch = arches = bfd_arch_list (); *arch; arch++) + fprintf (f, " %s", *arch); fprintf (f, "\n"); + free (arches); +} + +/* The length of the longest architecture name + 1. */ +#define LONGEST_ARCH sizeof ("powerpc:common") + +static const char * +endian_string (enum bfd_endian endian) +{ + switch (endian) + { + case BFD_ENDIAN_BIG: return _("big endian"); + case BFD_ENDIAN_LITTLE: return _("little endian"); + default: return _("endianness unknown"); + } +} + +/* List the targets that BFD is configured to support, each followed + by its endianness and the architectures it supports. */ + +static int +display_target_list (void) +{ + char *dummy_name; + int t; + int ret = 1; + + dummy_name = make_temp_file (NULL); + for (t = 0; bfd_target_vector[t]; t++) + { + const bfd_target *p = bfd_target_vector[t]; + bfd *abfd = bfd_openw (dummy_name, p->name); + int a; + + printf (_("%s\n (header %s, data %s)\n"), p->name, + endian_string (p->header_byteorder), + endian_string (p->byteorder)); + + if (abfd == NULL) + { + bfd_nonfatal (dummy_name); + ret = 0; + continue; + } + + if (! bfd_set_format (abfd, bfd_object)) + { + if (bfd_get_error () != bfd_error_invalid_operation) + { + bfd_nonfatal (p->name); + ret = 0; + } + bfd_close_all_done (abfd); + continue; + } + + for (a = bfd_arch_obscure + 1; a < bfd_arch_last; a++) + if (bfd_set_arch_mach (abfd, (enum bfd_architecture) a, 0)) + printf (" %s\n", + bfd_printable_arch_mach ((enum bfd_architecture) a, 0)); + bfd_close_all_done (abfd); + } + unlink (dummy_name); + free (dummy_name); + + return ret; +} + +/* Print a table showing which architectures are supported for entries + FIRST through LAST-1 of bfd_target_vector (targets across, + architectures down). */ + +static int +display_info_table (int first, int last) +{ + int t; + int ret = 1; + char *dummy_name; + int a; + + /* Print heading of target names. */ + printf ("\n%*s", (int) LONGEST_ARCH, " "); + for (t = first; t < last && bfd_target_vector[t]; t++) + printf ("%s ", bfd_target_vector[t]->name); + putchar ('\n'); + + dummy_name = make_temp_file (NULL); + for (a = bfd_arch_obscure + 1; a < bfd_arch_last; a++) + if (strcmp (bfd_printable_arch_mach ((enum bfd_architecture) a, 0), + "UNKNOWN!") != 0) + { + printf ("%*s ", (int) LONGEST_ARCH - 1, + bfd_printable_arch_mach ((enum bfd_architecture) a, 0)); + for (t = first; t < last && bfd_target_vector[t]; t++) + { + const bfd_target *p = bfd_target_vector[t]; + bfd_boolean ok = TRUE; + bfd *abfd = bfd_openw (dummy_name, p->name); + + if (abfd == NULL) + { + bfd_nonfatal (p->name); + ret = 0; + ok = FALSE; + } + + if (ok) + { + if (! bfd_set_format (abfd, bfd_object)) + { + if (bfd_get_error () != bfd_error_invalid_operation) + { + bfd_nonfatal (p->name); + ret = 0; + } + ok = FALSE; + } + } + + if (ok) + { + if (! bfd_set_arch_mach (abfd, (enum bfd_architecture) a, 0)) + ok = FALSE; + } + + if (ok) + printf ("%s ", p->name); + else + { + int l = strlen (p->name); + while (l--) + putchar ('-'); + putchar (' '); + } + if (abfd != NULL) + bfd_close_all_done (abfd); + } + putchar ('\n'); + } + unlink (dummy_name); + free (dummy_name); + + return ret; +} + +/* Print tables of all the target-architecture combinations that + BFD has been configured to support. */ + +static int +display_target_tables (void) +{ + int t; + int columns; + int ret = 1; + char *colum; + + columns = 0; + colum = getenv ("COLUMNS"); + if (colum != NULL) + columns = atoi (colum); + if (columns == 0) + columns = 80; + + t = 0; + while (bfd_target_vector[t] != NULL) + { + int oldt = t, wid; + + wid = LONGEST_ARCH + strlen (bfd_target_vector[t]->name) + 1; + ++t; + while (wid < columns && bfd_target_vector[t] != NULL) + { + int newwid; + + newwid = wid + strlen (bfd_target_vector[t]->name) + 1; + if (newwid >= columns) + break; + wid = newwid; + ++t; + } + if (! display_info_table (oldt, t)) + ret = 0; + } + + return ret; +} + +int +display_info (void) +{ + printf (_("BFD header file version %s\n"), BFD_VERSION_STRING); + if (! display_target_list () || ! display_target_tables ()) + return 1; + else + return 0; } /* Display the archive header for an element as if it were an ls -l listing: @@ -156,10 +415,7 @@ list_supported_targets (name, f) Mode User\tGroup\tSize\tDate Name */ void -print_arelt_descr (file, abfd, verbose) - FILE *file; - bfd *abfd; - boolean verbose; +print_arelt_descr (FILE *file, bfd *abfd, bfd_boolean verbose) { struct stat buf; @@ -170,76 +426,201 @@ print_arelt_descr (file, abfd, verbose) char modebuf[11]; char timebuf[40]; time_t when = buf.st_mtime; - CONST char *ctime_result = (CONST char *) ctime (&when); + const char *ctime_result = (const char *) ctime (&when); + bfd_size_type size; /* POSIX format: skip weekday and seconds from ctime output. */ sprintf (timebuf, "%.12s %.4s", ctime_result + 4, ctime_result + 20); mode_string (buf.st_mode, modebuf); modebuf[10] = '\0'; + size = buf.st_size; /* POSIX 1003.2/D11 says to skip first character (entry type). */ - fprintf (file, "%s %ld/%ld %6ld %s ", modebuf + 1, + fprintf (file, "%s %ld/%ld %6" BFD_VMA_FMT "u %s ", modebuf + 1, (long) buf.st_uid, (long) buf.st_gid, - (long) buf.st_size, timebuf); + size, timebuf); } } fprintf (file, "%s\n", bfd_get_filename (abfd)); } -/* Return the name of a temporary file in the same directory as FILENAME. */ +/* Return a path for a new temporary file in the same directory + as file PATH. */ -char * -make_tempname (filename) - char *filename; +static char * +template_in_dir (const char *path) { - static char template[] = "stXXXXXX"; +#define template "stXXXXXX" + const char *slash = strrchr (path, '/'); char *tmpname; - char *slash = strrchr (filename, '/'); - -#if defined (__DJGPP__) || defined (__GO32__) || defined (_WIN32) - if (slash == NULL) - slash = strrchr (filename, '\\'); + size_t len; + +#ifdef HAVE_DOS_BASED_FILE_SYSTEM + { + /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */ + char *bslash = strrchr (path, '\\'); + + if (slash == NULL || (bslash != NULL && bslash > slash)) + slash = bslash; + if (slash == NULL && path[0] != '\0' && path[1] == ':') + slash = path + 1; + } #endif if (slash != (char *) NULL) { - char c; - - c = *slash; - *slash = 0; - tmpname = xmalloc (strlen (filename) + sizeof (template) + 1); - strcpy (tmpname, filename); - strcat (tmpname, "/"); - strcat (tmpname, template); - mktemp (tmpname); - *slash = c; + len = slash - path; + tmpname = (char *) xmalloc (len + sizeof (template) + 2); + memcpy (tmpname, path, len); + +#ifdef HAVE_DOS_BASED_FILE_SYSTEM + /* If tmpname is "X:", appending a slash will make it a root + directory on drive X, which is NOT the same as the current + directory on drive X. */ + if (len == 2 && tmpname[1] == ':') + tmpname[len++] = '.'; +#endif + tmpname[len++] = '/'; } else { - tmpname = xmalloc (sizeof (template)); - strcpy (tmpname, template); - mktemp (tmpname); + tmpname = (char *) xmalloc (sizeof (template)); + len = 0; } + + memcpy (tmpname + len, template, sizeof (template)); return tmpname; +#undef template +} + +/* Return the name of a created temporary file in the same directory + as FILENAME. */ + +char * +make_tempname (char *filename) +{ + char *tmpname = template_in_dir (filename); + int fd; + +#ifdef HAVE_MKSTEMP + fd = mkstemp (tmpname); +#else + tmpname = mktemp (tmpname); + if (tmpname == NULL) + return NULL; + fd = open (tmpname, O_RDWR | O_CREAT | O_EXCL, 0600); +#endif + if (fd == -1) + { + free (tmpname); + return NULL; + } + close (fd); + return tmpname; +} + +/* Return the name of a created temporary directory inside the + directory containing FILENAME. */ + +char * +make_tempdir (char *filename) +{ + char *tmpname = template_in_dir (filename); + +#ifdef HAVE_MKDTEMP + return mkdtemp (tmpname); +#else + tmpname = mktemp (tmpname); + if (tmpname == NULL) + return NULL; +#if defined (_WIN32) && !defined (__CYGWIN32__) + if (mkdir (tmpname) != 0) + return NULL; +#else + if (mkdir (tmpname, 0700) != 0) + return NULL; +#endif + return tmpname; +#endif } /* Parse a string into a VMA, with a fatal error if it can't be parsed. */ bfd_vma -parse_vma (s, arg) - const char *s; - const char *arg; +parse_vma (const char *s, const char *arg) { bfd_vma ret; const char *end; ret = bfd_scan_vma (s, &end, 0); + if (*end != '\0') + fatal (_("%s: bad number: %s"), arg, s); + + return ret; +} + +/* Returns the size of the named file. If the file does not + exist, or if it is not a real file, then a suitable non-fatal + error message is printed and (off_t) -1 is returned. */ + +off_t +get_file_size (const char * file_name) +{ + struct stat statbuf; + + if (stat (file_name, &statbuf) < 0) + { + if (errno == ENOENT) + non_fatal (_("'%s': No such file"), file_name); + else + non_fatal (_("Warning: could not locate '%s'. reason: %s"), + file_name, strerror (errno)); + } + else if (! S_ISREG (statbuf.st_mode)) + non_fatal (_("Warning: '%s' is not an ordinary file"), file_name); + else if (statbuf.st_size < 0) + non_fatal (_("Warning: '%s' has negative size, probably it is too large"), + file_name); + else + return statbuf.st_size; + + return (off_t) -1; +} + +/* Return the filename in a static buffer. */ + +const char * +bfd_get_archive_filename (const bfd *abfd) +{ + static size_t curr = 0; + static char *buf; + size_t needed; + + assert (abfd != NULL); + + if (!abfd->my_archive) + return bfd_get_filename (abfd); + + needed = (strlen (bfd_get_filename (abfd->my_archive)) + + strlen (bfd_get_filename (abfd)) + 3); + if (needed > curr) { - fprintf (stderr, "%s: %s: bad number: %s\n", program_name, arg, s); - exit (1); + if (curr) + free (buf); + curr = needed + (needed >> 1); + buf = (char *) bfd_malloc (curr); + /* If we can't malloc, fail safe by returning just the file name. + This function is only used when building error messages. */ + if (!buf) + { + curr = 0; + return bfd_get_filename (abfd); + } } - return ret; + sprintf (buf, "%s(%s)", bfd_get_filename (abfd->my_archive), + bfd_get_filename (abfd)); + return buf; }