diff options
| author | Xavier ASUS <xavi92psx@gmail.com> | 2019-10-18 00:31:54 +0200 |
|---|---|---|
| committer | Xavier ASUS <xavi92psx@gmail.com> | 2019-10-18 00:31:54 +0200 |
| commit | 268a53de823a6750d6256ee1fb1e7707b4b45740 (patch) | |
| tree | 42c1799a9a82b2f7d9790ee9fe181d72a7274751 /support/sdbinutils/binutils/bucomm.c | |
| download | sdcc-gas-268a53de823a6750d6256ee1fb1e7707b4b45740.tar.gz | |
sdcc-3.9.0 fork implementing GNU assembler syntax
This fork aims to provide better support for stm8-binutils
Diffstat (limited to 'support/sdbinutils/binutils/bucomm.c')
| -rw-r--r-- | support/sdbinutils/binutils/bucomm.c | 667 |
1 files changed, 667 insertions, 0 deletions
diff --git a/support/sdbinutils/binutils/bucomm.c b/support/sdbinutils/binutils/bucomm.c new file mode 100644 index 0000000..d3a8d2d --- /dev/null +++ b/support/sdbinutils/binutils/bucomm.c @@ -0,0 +1,667 @@ +/* bucomm.c -- Bin Utils COMmon code. + Copyright (C) 1991-2018 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + 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., 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 "filenames.h" + +#include <time.h> /* ctime, maybe time_t */ +#include <assert.h> +#include "bucomm.h" + +#ifndef HAVE_TIME_T_IN_TIME_H +#ifndef HAVE_TIME_T_IN_TYPES_H +typedef long time_t; +#endif +#endif + +/* Error reporting. */ + +char *program_name; + +void +bfd_nonfatal (const char *string) +{ + 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_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); +} + +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; + + va_start (args, format); + + report (format, args); + va_end (args); + xexit (1); +} + +void +non_fatal (const char *format, ...) +{ + va_list args; + + va_start (args, format); + + report (format, args); + va_end (args); +} + +/* Set the default BFD target based on the configured target. Doing + this permits the binutils to be configured for a particular target, + and linked against a shared BFD library which was configured for a + different target. */ + +void +set_default_bfd_target (void) +{ + /* The macro TARGET is defined by Makefile. */ + const char *target = TARGET; + + if (! bfd_set_default_target (target)) + 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 + bfd_get_error () == bfd_error_file_ambiguously_recognized, print + the possible matching targets. */ + +void +list_matching_formats (char **p) +{ + fflush (stdout); + fprintf (stderr, _("%s: Matching formats:"), program_name); + while (*p) + fprintf (stderr, " %s", *p++); + fputc ('\n', stderr); +} + +/* List the supported targets. */ + +void +list_supported_targets (const char *name, FILE *f) +{ + 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 architectures:")); + else + fprintf (f, _("%s: supported architectures:"), name); + + for (arch = arches = bfd_arch_list (); *arch; arch++) + fprintf (f, " %s", *arch); + fprintf (f, "\n"); + free (arches); +} + +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"); + } +} + +/* Data passed to do_display_target and other target iterators. */ + +struct display_target { + /* Temp file. */ + char *filename; + /* Return status. */ + int error; + /* Number of targets. */ + int count; + /* Size of info in bytes. */ + size_t alloc; + /* Per-target info. */ + struct { + /* Target name. */ + const char *name; + /* Non-zero if target/arch combination supported. */ + unsigned char arch[bfd_arch_last - bfd_arch_obscure - 1]; + } *info; +}; + +/* List the targets that BFD is configured to support, each followed + by its endianness and the architectures it supports. Also build + info about target/archs. */ + +static int +do_display_target (const bfd_target *targ, void *data) +{ + struct display_target *param = (struct display_target *) data; + bfd *abfd; + size_t amt; + + param->count += 1; + amt = param->count * sizeof (*param->info); + if (param->alloc < amt) + { + size_t size = ((param->count < 64 ? 64 : param->count) + * sizeof (*param->info) * 2); + param->info = xrealloc (param->info, size); + memset ((char *) param->info + param->alloc, 0, size - param->alloc); + param->alloc = size; + } + param->info[param->count - 1].name = targ->name; + + printf (_("%s\n (header %s, data %s)\n"), targ->name, + endian_string (targ->header_byteorder), + endian_string (targ->byteorder)); + + abfd = bfd_openw (param->filename, targ->name); + if (abfd == NULL) + { + bfd_nonfatal (param->filename); + param->error = 1; + } + else if (!bfd_set_format (abfd, bfd_object)) + { + if (bfd_get_error () != bfd_error_invalid_operation) + { + bfd_nonfatal (targ->name); + param->error = 1; + } + } + else + { + enum bfd_architecture a; + + for (a = bfd_arch_obscure + 1; a < bfd_arch_last; a++) + if (bfd_set_arch_mach (abfd, a, 0)) + { + printf (" %s\n", bfd_printable_arch_mach (a, 0)); + param->info[param->count - 1].arch[a - bfd_arch_obscure - 1] = 1; + } + } + if (abfd != NULL) + bfd_close_all_done (abfd); + + return param->error; +} + +static void +display_target_list (struct display_target *arg) +{ + arg->filename = make_temp_file (NULL); + arg->error = 0; + arg->count = 0; + arg->alloc = 0; + arg->info = NULL; + + bfd_iterate_over_targets (do_display_target, arg); + + unlink (arg->filename); + free (arg->filename); +} + +/* Calculate how many targets we can print across the page. */ + +static int +do_info_size (int targ, int width, const struct display_target *arg) +{ + while (targ < arg->count) + { + width -= strlen (arg->info[targ].name) + 1; + if (width < 0) + return targ; + ++targ; + } + return targ; +} + +/* Print header of target names. */ + +static void +do_info_header (int targ, int stop_targ, const struct display_target *arg) +{ + while (targ != stop_targ) + printf ("%s ", arg->info[targ++].name); +} + +/* Print a table row. */ + +static void +do_info_row (int targ, int stop_targ, enum bfd_architecture a, + const struct display_target *arg) +{ + while (targ != stop_targ) + { + if (arg->info[targ].arch[a - bfd_arch_obscure - 1]) + fputs (arg->info[targ].name, stdout); + else + { + int l = strlen (arg->info[targ].name); + while (l--) + putchar ('-'); + } + ++targ; + if (targ != stop_targ) + putchar (' '); + } +} + +/* Print tables of all the target-architecture combinations that + BFD has been configured to support. */ + +static void +display_target_tables (const struct display_target *arg) +{ + const char *columns; + int width, start_targ, stop_targ; + enum bfd_architecture arch; + int longest_arch = 0; + + for (arch = bfd_arch_obscure + 1; arch < bfd_arch_last; arch++) + { + const char *s = bfd_printable_arch_mach (arch, 0); + int len = strlen (s); + if (len > longest_arch) + longest_arch = len; + } + + width = 0; + columns = getenv ("COLUMNS"); + if (columns != NULL) + width = atoi (columns); + if (width == 0) + width = 80; + + for (start_targ = 0; start_targ < arg->count; start_targ = stop_targ) + { + stop_targ = do_info_size (start_targ, width - longest_arch - 1, arg); + + printf ("\n%*s", longest_arch + 1, " "); + do_info_header (start_targ, stop_targ, arg); + putchar ('\n'); + + for (arch = bfd_arch_obscure + 1; arch < bfd_arch_last; arch++) + { + if (strcmp (bfd_printable_arch_mach (arch, 0), "UNKNOWN!") != 0) + { + printf ("%*s ", longest_arch, + bfd_printable_arch_mach (arch, 0)); + + do_info_row (start_targ, stop_targ, arch, arg); + putchar ('\n'); + } + } + } +} + +int +display_info (void) +{ + struct display_target arg; + + printf (_("BFD header file version %s\n"), BFD_VERSION_STRING); + + display_target_list (&arg); + if (!arg.error) + display_target_tables (&arg); + + return arg.error; +} + +/* Display the archive header for an element as if it were an ls -l listing: + + Mode User\tGroup\tSize\tDate Name */ + +void +print_arelt_descr (FILE *file, bfd *abfd, bfd_boolean verbose) +{ + struct stat buf; + + if (verbose) + { + if (bfd_stat_arch_elt (abfd, &buf) == 0) + { + char modebuf[11]; + char timebuf[40]; + time_t when = buf.st_mtime; + const char *ctime_result = (const char *) ctime (&when); + bfd_size_type size; + + /* PR binutils/17605: Check for corrupt time values. */ + if (ctime_result == NULL) + sprintf (timebuf, _("<time data corrupt>")); + else + /* 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 %6" BFD_VMA_FMT "u %s ", modebuf + 1, + (long) buf.st_uid, (long) buf.st_gid, + size, timebuf); + } + } + + fprintf (file, "%s\n", bfd_get_filename (abfd)); +} + +/* Return a path for a new temporary file in the same directory + as file PATH. */ + +static char * +template_in_dir (const char *path) +{ +#define template "stXXXXXX" + const char *slash = strrchr (path, '/'); + char *tmpname; + 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) + { + 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 = (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 (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 (file_name == NULL) + return (off_t) -1; + + 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_ISDIR (statbuf.st_mode)) + non_fatal (_("Warning: '%s' is a directory"), file_name); + 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 == NULL + || bfd_is_thin_archive (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) + { + if (curr) + free (buf); + curr = needed + (needed >> 1); + buf = (char *) xmalloc (curr); + } + sprintf (buf, "%s(%s)", bfd_get_filename (abfd->my_archive), + bfd_get_filename (abfd)); + return buf; +} + +/* Returns TRUE iff PATHNAME, a filename of an archive member, + is valid for writing. For security reasons absolute paths + and paths containing /../ are not allowed. See PR 17533. */ + +bfd_boolean +is_valid_archive_path (char const * pathname) +{ + const char * n = pathname; + + if (IS_ABSOLUTE_PATH (n)) + return FALSE; + + while (*n) + { + if (*n == '.' && *++n == '.' && ( ! *++n || IS_DIR_SEPARATOR (*n))) + return FALSE; + + while (*n && ! IS_DIR_SEPARATOR (*n)) + n++; + while (IS_DIR_SEPARATOR (*n)) + n++; + } + + return TRUE; +} |
