X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=binutils%2Far.c;h=85b342a6502768be49dd2b97362dde96957a6099;hb=refs%2Fheads%2Fconcurrent-displaced-stepping-2020-04-01;hp=9a6946eb0dcf9e84300de16df614df7e4e96cf5e;hpb=b34976b65aea8f33690229600bbf4527ec3118e1;p=deliverable%2Fbinutils-gdb.git diff --git a/binutils/ar.c b/binutils/ar.c index 9a6946eb0d..85b342a650 100644 --- a/binutils/ar.c +++ b/binutils/ar.c @@ -1,13 +1,11 @@ /* ar.c - Archive modify and extract. - Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, - 2001, 2002 - Free Software Foundation, Inc. + Copyright (C) 1991-2020 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, @@ -17,95 +15,55 @@ 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. */ /* - Bugs: should use getopt the way tar does (complete w/optional -) and - should have long options too. GNU ar used to check file against filesystem - in quick_update and replace operations (would check mtime). Doesn't warn - when name truncated. No way to specify pos_end. Error messages should be - more consistant. */ + Bugs: GNU ar used to check file against filesystem in quick_update and + replace operations (would check mtime). Doesn't warn when name truncated. + No way to specify pos_end. Error messages should be more consistent. */ +#include "sysdep.h" #include "bfd.h" #include "libiberty.h" #include "progress.h" -#include "bucomm.h" +#include "getopt.h" #include "aout/ar.h" -#include "libbfd.h" +#include "bucomm.h" #include "arsup.h" #include "filenames.h" #include "binemul.h" -#include +#include "plugin-api.h" +#include "plugin.h" +#include "ansidecl.h" #ifdef __GO32___ -#define EXT_NAME_LEN 3 /* bufflen of addition to name if it's MS-DOS */ +#define EXT_NAME_LEN 3 /* Bufflen of addition to name if it's MS-DOS. */ #else -#define EXT_NAME_LEN 6 /* ditto for *NIX */ -#endif - -/* We need to open files in binary modes on system where that makes a - difference. */ -#ifndef O_BINARY -#define O_BINARY 0 -#endif - -#define BUFSIZE 8192 - -/* Kludge declaration from BFD! This is ugly! FIXME! XXX */ - -struct ar_hdr * - bfd_special_undocumented_glue PARAMS ((bfd * abfd, const char *filename)); - -/* Static declarations */ - -static void -mri_emul PARAMS ((void)); - -static const char * -normalize PARAMS ((const char *, bfd *)); - -static void -remove_output PARAMS ((void)); - -static void -map_over_members PARAMS ((bfd *, void (*)(bfd *), char **, int)); - -static void -print_contents PARAMS ((bfd * member)); - -static void -delete_members PARAMS ((bfd *, char **files_to_delete)); - -#if 0 -static void -do_quick_append PARAMS ((const char *archive_filename, - char **files_to_append)); +#define EXT_NAME_LEN 6 /* Ditto for *NIX. */ #endif -static void -move_members PARAMS ((bfd *, char **files_to_move)); - -static void -replace_members PARAMS ((bfd *, char **files_to_replace, bfd_boolean quick)); - -static void -print_descr PARAMS ((bfd * abfd)); - -static void -write_archive PARAMS ((bfd *)); - -static void -ranlib_only PARAMS ((const char *archname)); - -static void -ranlib_touch PARAMS ((const char *archname)); - -static void -usage PARAMS ((int)); +/* Static declarations. */ + +static void mri_emul (void); +static const char *normalize (const char *, bfd *); +static void remove_output (void); +static void map_over_members (bfd *, void (*)(bfd *), char **, int); +static void print_contents (bfd * member); +static void delete_members (bfd *, char **files_to_delete); + +static void move_members (bfd *, char **files_to_move); +static void replace_members + (bfd *, char **files_to_replace, bfd_boolean quick); +static void print_descr (bfd * abfd); +static void write_archive (bfd *); +static int ranlib_only (const char *archname); +static int ranlib_touch (const char *archname); +static void usage (int); -/** Globals and flags */ +/** Globals and flags. */ -int mri_mode; +static int mri_mode; /* This flag distinguishes between ar and ranlib: 1 means this is 'ranlib'; 0 means this is 'ar'. @@ -118,6 +76,9 @@ int silent_create = 0; /* Nonzero means describe each action performed. */ int verbose = 0; +/* Nonzero means display offsets of files in the archive. */ +int display_offsets = 0; + /* Nonzero means preserve dates of members when extracting them. */ int preserve_dates = 0; @@ -127,13 +88,18 @@ int newer_only = 0; /* Controls the writing of an archive symbol table (in BSD: a __.SYMDEF member). -1 means we've been explicitly asked to not write a symbol table; - +1 means we've been explictly asked to write it; + +1 means we've been explicitly asked to write it; 0 is the default. Traditionally, the default in BSD has been to not write the table. However, for POSIX.2 compliance the default is now to write a symbol table if any of the members are object files. */ int write_armap = 0; +/* Operate in deterministic mode: write zero for timestamps, uids, + and gids for archive members and the archive symbol table, and write + consistent file modes. */ +int deterministic = -1; /* Determinism indeterminate. */ + /* Nonzero means it's the name of an existing member; position new or moved files with respect to this one. */ char *posname = NULL; @@ -147,8 +113,14 @@ enum pos pos_default, pos_before, pos_after, pos_end } postype = pos_default; +enum operations + { + none = 0, del, replace, print_table, + print_files, extract, move, quick_append + } operation = none; + static bfd ** -get_pos_bfd PARAMS ((bfd **, enum pos, const char *)); +get_pos_bfd (bfd **, enum pos, const char *); /* For extract/delete only. If COUNTED_NAME_MODE is TRUE, we only extract the COUNTED_NAME_COUNTER instance of that name. */ @@ -163,10 +135,44 @@ static bfd_boolean ar_truncate = FALSE; program. */ static bfd_boolean full_pathname = FALSE; +/* Whether to create a "thin" archive (symbol index only -- no files). */ +static bfd_boolean make_thin_archive = FALSE; + +static int show_version = 0; + +static int show_help = 0; + +#if BFD_SUPPORTS_PLUGINS +static const char *plugin_target = "plugin"; +#else +static const char *plugin_target = NULL; +#endif + +static const char *target = NULL; + +enum long_option_numbers +{ + OPTION_PLUGIN = 201, + OPTION_TARGET, + OPTION_OUTPUT +}; + +static const char * output_dir = NULL; + +static struct option long_options[] = +{ + {"help", no_argument, &show_help, 1}, + {"plugin", required_argument, NULL, OPTION_PLUGIN}, + {"target", required_argument, NULL, OPTION_TARGET}, + {"version", no_argument, &show_version, 1}, + {"output", required_argument, NULL, OPTION_OUTPUT}, + {NULL, no_argument, NULL, 0} +}; + int interactive = 0; static void -mri_emul () +mri_emul (void) { interactive = isatty (fileno (stdin)); yyparse (); @@ -177,18 +183,14 @@ mri_emul () whose name matches one in FILES. */ static void -map_over_members (arch, function, files, count) - bfd *arch; - void (*function) PARAMS ((bfd *)); - char **files; - int count; +map_over_members (bfd *arch, void (*function)(bfd *), char **files, int count) { bfd *head; int match_count; if (count == 0) { - for (head = arch->next; head; head = head->next) + for (head = arch->archive_next; head; head = head->archive_next) { PROGRESS (1); function (head); @@ -202,23 +204,43 @@ map_over_members (arch, function, files, count) mapping over each file each time -- we want to hack multiple references. */ + for (head = arch->archive_next; head; head = head->archive_next) + head->archive_pass = 0; + for (; count > 0; files++, count--) { bfd_boolean found = FALSE; match_count = 0; - for (head = arch->next; head; head = head->next) + for (head = arch->archive_next; head; head = head->archive_next) { + const char * filename; + PROGRESS (1); - if (head->filename == NULL) + /* PR binutils/15796: Once an archive element has been matched + do not match it again. If the user provides multiple same-named + parameters on the command line their intent is to match multiple + same-named entries in the archive, not the same entry multiple + times. */ + if (head->archive_pass) + continue; + + filename = bfd_get_filename (head); + if (filename == NULL) { /* Some archive formats don't get the filenames filled in until the elements are opened. */ struct stat buf; bfd_stat_arch_elt (head, &buf); } - if ((head->filename != NULL) && - (!FILENAME_CMP (normalize (*files, arch), head->filename))) + else if (bfd_is_thin_archive (arch)) + { + /* Thin archives store full pathnames. Need to normalize. */ + filename = normalize (filename, arch); + } + + if (filename != NULL + && !FILENAME_CMP (normalize (*files, arch), filename)) { ++match_count; if (counted_name_mode @@ -231,8 +253,16 @@ map_over_members (arch, function, files, count) found = TRUE; function (head); + head->archive_pass = 1; + /* PR binutils/15796: Once a file has been matched, do not + match any more same-named files in the archive. If the + user does want to match multiple same-name files in an + archive they should provide multiple same-name parameters + to the ar command. */ + break; } } + if (!found) /* xgettext:c-format */ fprintf (stderr, _("no entry %s in archive\n"), *files); @@ -242,58 +272,117 @@ map_over_members (arch, function, files, count) bfd_boolean operation_alters_arch = FALSE; static void -usage (help) - int help; +usage (int help) { FILE *s; +#if BFD_SUPPORTS_PLUGINS + /* xgettext:c-format */ + const char *command_line + = _("Usage: %s [emulation options] [-]{dmpqrstx}[abcDfilMNoOPsSTuvV]" + " [--plugin ] [member-name] [count] archive-file file...\n"); + +#else + /* xgettext:c-format */ + const char *command_line + = _("Usage: %s [emulation options] [-]{dmpqrstx}[abcDfilMNoOPsSTuvV]" + " [member-name] [count] archive-file file...\n"); +#endif s = help ? stdout : stderr; - if (! is_ranlib) + fprintf (s, command_line, program_name); + + /* xgettext:c-format */ + fprintf (s, _(" %s -M [ - read options from \n")); + fprintf (s, _(" --target=BFDNAME - specify the target object format as BFDNAME\n")); + fprintf (s, _(" --output=DIRNAME - specify the output directory for extraction operations\n")); +#if BFD_SUPPORTS_PLUGINS + fprintf (s, _(" optional:\n")); + fprintf (s, _(" --plugin

- load the specified plugin\n")); +#endif + + ar_emul_usage (s); - list_supported_targets (program_name, stderr); + list_supported_targets (program_name, s); - if (help) + if (REPORT_BUGS_TO[0] && help) + fprintf (s, _("Report bugs to %s\n"), REPORT_BUGS_TO); + + xexit (help ? 0 : 1); +} + +static void +ranlib_usage (int help) +{ + FILE *s; + + s = help ? stdout : stderr; + + /* xgettext:c-format */ + fprintf (s, _("Usage: %s [options] archive\n"), program_name); + fprintf (s, _(" Generate an index to speed access to archives\n")); + fprintf (s, _(" The options are:\n\ + @ Read options from \n")); +#if BFD_SUPPORTS_PLUGINS + fprintf (s, _("\ + --plugin Load the specified plugin\n")); +#endif + if (DEFAULT_AR_DETERMINISTIC) + fprintf (s, _("\ + -D Use zero for symbol map timestamp (default)\n\ + -U Use an actual symbol map timestamp\n")); + else + fprintf (s, _("\ + -D Use zero for symbol map timestamp\n\ + -U Use actual symbol map timestamp (default)\n")); + fprintf (s, _("\ + -t Update the archive's symbol map timestamp\n\ + -h --help Print this help message\n\ + -v --version Print version information\n")); + + list_supported_targets (program_name, s); + + if (REPORT_BUGS_TO[0] && help) fprintf (s, _("Report bugs to %s\n"), REPORT_BUGS_TO); xexit (help ? 0 : 1); @@ -303,30 +392,14 @@ usage (help) name which we will use in an archive. */ static const char * -normalize (file, abfd) - const char *file; - bfd *abfd; +normalize (const char *file, bfd *abfd) { const char *filename; if (full_pathname) return file; - filename = strrchr (file, '/'); -#ifdef HAVE_DOS_BASED_FILE_SYSTEM - { - /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */ - char *bslash = strrchr (file, '\\'); - if (filename == NULL || (bslash != NULL && bslash > filename)) - filename = bslash; - if (filename == NULL && file[0] != '\0' && file[1] == ':') - filename = file + 1; - } -#endif - if (filename != (char *) NULL) - filename++; - else - filename = file; + filename = lbasename (file); if (ar_truncate && abfd != NULL @@ -351,40 +424,292 @@ static FILE *output_file = NULL; static bfd *output_bfd = NULL; static void -remove_output () +remove_output (void) { if (output_filename != NULL) { - if (output_bfd != NULL && output_bfd->iostream != NULL) - fclose ((FILE *) (output_bfd->iostream)); + if (output_bfd != NULL) + bfd_cache_close (output_bfd); if (output_file != NULL) fclose (output_file); - unlink (output_filename); + unlink_if_ordinary (output_filename); } } -/* The option parsing should be in its own function. - It will be when I have getopt working. */ +static char ** +decode_options (int argc, char **argv) +{ + int c; -int main PARAMS ((int, char **)); + /* Convert old-style ar call by exploding option element and rearranging + options accordingly. */ -int -main (argc, argv) - int argc; - char **argv; + restart: + if (argc > 1 && argv[1][0] != '-') + { + int new_argc; /* argc value for rearranged arguments */ + char **new_argv; /* argv value for rearranged arguments */ + char *const *in; /* cursor into original argv */ + char **out; /* cursor into rearranged argv */ + const char *letter; /* cursor into old option letters */ + char buffer[3]; /* constructed option buffer */ + + /* Initialize a constructed option. */ + + buffer[0] = '-'; + buffer[2] = '\0'; + + /* Allocate a new argument array, and copy program name in it. */ + + new_argc = argc - 1 + strlen (argv[1]); + new_argv = xmalloc ((new_argc + 1) * sizeof (*argv)); + in = argv; + out = new_argv; + *out++ = *in++; + + /* Copy each old letter option as a separate option. */ + + for (letter = *in++; *letter; letter++) + { + buffer[1] = *letter; + *out++ = xstrdup (buffer); + } + + /* Copy all remaining options. */ + + while (in < argv + argc) + *out++ = *in++; + *out = NULL; + + /* Replace the old option list by the new one. */ + + argc = new_argc; + argv = new_argv; + } + + while ((c = getopt_long (argc, argv, "hdmpqrtxlcoOVsSuvabiMNfPTDU", + long_options, NULL)) != EOF) + { + switch (c) + { + case 'd': + case 'm': + case 'p': + case 'q': + case 'r': + case 't': + case 'x': + if (operation != none) + fatal (_("two different operation options specified")); + break; + } + + switch (c) + { + case 'h': + show_help = 1; + break; + case 'd': + operation = del; + operation_alters_arch = TRUE; + break; + case 'm': + operation = move; + operation_alters_arch = TRUE; + break; + case 'p': + operation = print_files; + break; + case 'q': + operation = quick_append; + operation_alters_arch = TRUE; + break; + case 'r': + operation = replace; + operation_alters_arch = TRUE; + break; + case 't': + operation = print_table; + break; + case 'x': + operation = extract; + break; + case 'l': + break; + case 'c': + silent_create = 1; + break; + case 'o': + preserve_dates = 1; + break; + case 'O': + display_offsets = 1; + break; + case 'V': + show_version = TRUE; + break; + case 's': + write_armap = 1; + break; + case 'S': + write_armap = -1; + break; + case 'u': + newer_only = 1; + break; + case 'v': + verbose = 1; + break; + case 'a': + postype = pos_after; + break; + case 'b': + postype = pos_before; + break; + case 'i': + postype = pos_before; + break; + case 'M': + mri_mode = 1; + break; + case 'N': + counted_name_mode = TRUE; + break; + case 'f': + ar_truncate = TRUE; + break; + case 'P': + full_pathname = TRUE; + break; + case 'T': + make_thin_archive = TRUE; + break; + case 'D': + deterministic = TRUE; + break; + case 'U': + deterministic = FALSE; + break; + case OPTION_PLUGIN: +#if BFD_SUPPORTS_PLUGINS + bfd_plugin_set_plugin (optarg); +#else + fprintf (stderr, _("sorry - this program has been built without plugin support\n")); + xexit (1); +#endif + break; + case OPTION_TARGET: + target = optarg; + break; + case OPTION_OUTPUT: + output_dir = optarg; + break; + case 0: /* A long option that just sets a flag. */ + break; + default: + usage (0); + } + } + + /* PR 13256: Allow for the possibility that the first command line option + started with a dash (eg --plugin) but then the following option(s) are + old style, non-dash-prefixed versions. */ + if (operation == none && write_armap != 1 && !mri_mode + && optind > 0 && optind < argc) + { + argv += (optind - 1); + argc -= (optind - 1); + optind = 0; + goto restart; + } + + return &argv[optind]; +} + +/* If neither -D nor -U was specified explicitly, + then use the configured default. */ +static void +default_deterministic (void) +{ + if (deterministic < 0) + deterministic = DEFAULT_AR_DETERMINISTIC; +} + +static void +ranlib_main (int argc, char **argv) { - char *arg_ptr; - char c; - enum + int arg_index, status = 0; + bfd_boolean touch = FALSE; + int c; + + while ((c = getopt_long (argc, argv, "DhHUvVt", long_options, NULL)) != EOF) { - none = 0, delete, replace, print_table, - print_files, extract, move, quick_append - } operation = none; + switch (c) + { + case 'D': + deterministic = TRUE; + break; + case 'U': + deterministic = FALSE; + break; + case 'h': + case 'H': + show_help = 1; + break; + case 't': + touch = TRUE; + break; + case 'v': + case 'V': + show_version = 1; + break; + + /* PR binutils/13493: Support plugins. */ + case OPTION_PLUGIN: +#if BFD_SUPPORTS_PLUGINS + bfd_plugin_set_plugin (optarg); +#else + fprintf (stderr, _("sorry - this program has been built without plugin support\n")); + xexit (1); +#endif + break; + } + } + + if (argc < 2) + ranlib_usage (0); + + if (show_help) + ranlib_usage (1); + + if (show_version) + print_version ("ranlib"); + + default_deterministic (); + + arg_index = optind; + + while (arg_index < argc) + { + if (! touch) + status |= ranlib_only (argv[arg_index]); + else + status |= ranlib_touch (argv[arg_index]); + ++arg_index; + } + + xexit (status); +} + +int main (int, char **); + +int +main (int argc, char **argv) +{ int arg_index; char **files; int file_count; char *inarch_filename; - int show_version; int i; #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES) @@ -398,26 +723,17 @@ main (argc, argv) program_name = argv[0]; xmalloc_set_program_name (program_name); + bfd_set_error_program_name (program_name); +#if BFD_SUPPORTS_PLUGINS + bfd_plugin_set_program_name (program_name); +#endif + + expandargv (&argc, &argv); if (is_ranlib < 0) { - char *temp; - - temp = strrchr (program_name, '/'); -#ifdef HAVE_DOS_BASED_FILE_SYSTEM - { - /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */ - char *bslash = strrchr (program_name, '\\'); - if (temp == NULL || (bslash != NULL && bslash > temp)) - temp = bslash; - if (temp == NULL && program_name[0] != '\0' && program_name[1] == ':') - temp = program_name + 1; - } -#endif - if (temp == NULL) - temp = program_name; - else - ++temp; + const char *temp = lbasename (program_name); + if (strlen (temp) >= 6 && FILENAME_CMP (temp + strlen (temp) - 6, "ranlib") == 0) is_ranlib = 1; @@ -425,26 +741,12 @@ main (argc, argv) is_ranlib = 0; } - if (argc > 1 && argv[1][0] == '-') - { - if (strcmp (argv[1], "--help") == 0) - usage (1); - else if (strcmp (argv[1], "--version") == 0) - { - if (is_ranlib) - print_version ("ranlib"); - else - print_version ("ar"); - } - } - START_PROGRESS (program_name, 0); - bfd_init (); + if (bfd_init () != BFD_INIT_MAGIC) + fatal (_("fatal error: libbfd ABI mismatch")); set_default_bfd_target (); - show_version = 0; - xatexit (remove_output); for (i = 1; i < argc; i++) @@ -454,155 +756,40 @@ main (argc, argv) argc -= (i - 1); if (is_ranlib) - { - bfd_boolean touch = FALSE; - - if (argc < 2 - || strcmp (argv[1], "--help") == 0 - || strcmp (argv[1], "-h") == 0 - || strcmp (argv[1], "-H") == 0) - usage (0); - if (strcmp (argv[1], "-V") == 0 - || strcmp (argv[1], "-v") == 0 - || strncmp (argv[1], "--v", 3) == 0) - print_version ("ranlib"); - arg_index = 1; - if (strcmp (argv[1], "-t") == 0) - { - ++arg_index; - touch = TRUE; - } - while (arg_index < argc) - { - if (! touch) - ranlib_only (argv[arg_index]); - else - ranlib_touch (argv[arg_index]); - ++arg_index; - } - xexit (0); - } - - if (argc == 2 && strcmp (argv[1], "-M") == 0) - { - mri_emul (); - xexit (0); - } + ranlib_main (argc, argv); if (argc < 2) usage (0); - arg_ptr = argv[1]; + argv = decode_options (argc, argv); - if (*arg_ptr == '-') - ++arg_ptr; /* compatibility */ - - while ((c = *arg_ptr++) != '\0') - { - switch (c) - { - case 'd': - case 'm': - case 'p': - case 'q': - case 'r': - case 't': - case 'x': - if (operation != none) - fatal (_("two different operation options specified")); - switch (c) - { - case 'd': - operation = delete; - operation_alters_arch = TRUE; - break; - case 'm': - operation = move; - operation_alters_arch = TRUE; - break; - case 'p': - operation = print_files; - break; - case 'q': - operation = quick_append; - operation_alters_arch = TRUE; - break; - case 'r': - operation = replace; - operation_alters_arch = TRUE; - break; - case 't': - operation = print_table; - break; - case 'x': - operation = extract; - break; - } - case 'l': - break; - case 'c': - silent_create = 1; - break; - case 'o': - preserve_dates = 1; - break; - case 'V': - show_version = TRUE; - break; - case 's': - write_armap = 1; - break; - case 'S': - write_armap = -1; - break; - case 'u': - newer_only = 1; - break; - case 'v': - verbose = 1; - break; - case 'a': - postype = pos_after; - break; - case 'b': - postype = pos_before; - break; - case 'i': - postype = pos_before; - break; - case 'M': - mri_mode = 1; - break; - case 'N': - counted_name_mode = TRUE; - break; - case 'f': - ar_truncate = TRUE; - break; - case 'P': - full_pathname = TRUE; - break; - default: - /* xgettext:c-format */ - non_fatal (_("illegal option -- %c"), c); - usage (0); - } - } + if (show_help) + usage (1); if (show_version) print_version ("ar"); - if (argc < 3) - usage (0); + arg_index = 0; if (mri_mode) { + default_deterministic (); mri_emul (); } else { bfd *arch; + /* Fail if no files are specified on the command line. + (But not for MRI mode which allows for reading arguments + and filenames from stdin). */ + if (argv[arg_index] == NULL) + usage (0); + + /* We don't use do_quick_append any more. Too many systems + expect ar to always rebuild the symbol table even when q is + used. */ + /* We can't write an armap when using ar q, so just do ar r instead. */ if (operation == quick_append && write_armap) @@ -610,10 +797,7 @@ main (argc, argv) if ((operation == none || operation == print_table) && write_armap == 1) - { - ranlib_only (argv[2]); - xexit (0); - } + xexit (ranlib_only (argv[arg_index])); if (operation == none) fatal (_("no operation specified")); @@ -621,61 +805,48 @@ main (argc, argv) if (newer_only && operation != replace) fatal (_("`u' is only meaningful with the `r' option.")); - arg_index = 2; + if (newer_only && deterministic > 0) + fatal (_("`u' is not meaningful with the `D' option.")); + + if (newer_only && deterministic < 0 && DEFAULT_AR_DETERMINISTIC) + non_fatal (_("\ +`u' modifier ignored since `D' is the default (see `U')")); + + default_deterministic (); if (postype != pos_default) - posname = argv[arg_index++]; + { + posname = argv[arg_index++]; + if (posname == NULL) + fatal (_("missing position arg.")); + } if (counted_name_mode) { - if (operation != extract && operation != delete) - fatal (_("`N' is only meaningful with the `x' and `d' options.")); + if (operation != extract && operation != del) + fatal (_("`N' is only meaningful with the `x' and `d' options.")); + if (argv[arg_index] == NULL) + fatal (_("`N' missing value.")); counted_name_counter = atoi (argv[arg_index++]); if (counted_name_counter <= 0) fatal (_("Value for `N' must be positive.")); } inarch_filename = argv[arg_index++]; + if (inarch_filename == NULL) + usage (0); - files = arg_index < argc ? argv + arg_index : NULL; - file_count = argc - arg_index; - -#if 0 - /* We don't use do_quick_append any more. Too many systems - expect ar to always rebuild the symbol table even when q is - used. */ - - /* We can't do a quick append if we need to construct an - extended name table, because do_quick_append won't be able to - rebuild the name table. Unfortunately, at this point we - don't actually know the maximum name length permitted by this - object file format. So, we guess. FIXME. */ - if (operation == quick_append && ! ar_truncate) - { - char **chk; - - for (chk = files; chk != NULL && *chk != '\0'; chk++) - { - if (strlen (normalize (*chk, (bfd *) NULL)) > 14) - { - operation = replace; - break; - } - } - } + for (file_count = 0; argv[arg_index + file_count] != NULL; file_count++) + continue; - if (operation == quick_append) - { - /* Note that quick appending to a non-existent archive creates it, - even if there are no files to append. */ - do_quick_append (inarch_filename, files); - xexit (0); - } -#endif + files = (file_count > 0) ? argv + arg_index : NULL; arch = open_inarch (inarch_filename, files == NULL ? (char *) NULL : files[0]); + if (operation == extract && bfd_is_thin_archive (arch)) + fatal (_("`x' cannot be used on thin archives.")); + switch (operation) { case print_table: @@ -690,7 +861,7 @@ main (argc, argv) map_over_members (arch, extract_file, files, file_count); break; - case delete: + case del: if (files != NULL) delete_members (arch, files); else @@ -698,11 +869,17 @@ main (argc, argv) break; case move: - if (files != NULL) - move_members (arch, files); - else - output_filename = NULL; - break; + /* PR 12558: Creating and moving at the same time does + not make sense. Just create the archive instead. */ + if (! silent_create) + { + if (files != NULL) + move_members (arch, files); + else + output_filename = NULL; + break; + } + /* Fall through. */ case replace: case quick_append: @@ -726,11 +903,8 @@ main (argc, argv) } bfd * -open_inarch (archive_filename, file) - const char *archive_filename; - const char *file; +open_inarch (const char *archive_filename, const char *file) { - const char *target; bfd **last_one; bfd *next_one; struct stat sbuf; @@ -739,7 +913,8 @@ open_inarch (archive_filename, file) bfd_set_error (bfd_error_no_error); - target = NULL; + if (target == NULL) + target = plugin_target; if (stat (archive_filename, &sbuf) != 0) { @@ -750,8 +925,8 @@ open_inarch (archive_filename, file) stat() works just fine in v2.x, so I think this should be removed. For now, I enable it for DJGPP v2. -- EZ. */ -/* KLUDGE ALERT! Temporary fix until I figger why - stat() is wrong ... think it's buried in GO32's IDT - Jax */ + /* KLUDGE ALERT! Temporary fix until I figger why + stat() is wrong ... think it's buried in GO32's IDT - Jax */ if (errno != ENOENT) bfd_fatal (archive_filename); #endif @@ -764,13 +939,13 @@ open_inarch (archive_filename, file) return NULL; } - /* Try to figure out the target to use for the archive from the - first object on the list. */ - if (file != NULL) + /* If the target isn't set, try to figure out the target to use + for the archive from the first object on the list. */ + if (target == NULL && file != NULL) { bfd *obj; - obj = bfd_openr (file, NULL); + obj = bfd_openr (file, target); if (obj != NULL) { if (bfd_check_format (obj, bfd_object)) @@ -785,6 +960,8 @@ open_inarch (archive_filename, file) || ! bfd_set_format (arch, bfd_archive) || ! bfd_close (arch)) bfd_fatal (archive_filename); + else if (!silent_create) + non_fatal (_("creating %s"), archive_filename); /* If we die creating a new archive, don't leave it around. */ output_filename = archive_filename; @@ -808,7 +985,26 @@ open_inarch (archive_filename, file) xexit (1); } - last_one = &(arch->next); + if ((operation == replace || operation == quick_append) + && bfd_openr_next_archived_file (arch, NULL) != NULL) + { + /* PR 15140: Catch attempts to convert a normal + archive into a thin archive or vice versa. */ + if (make_thin_archive && ! bfd_is_thin_archive (arch)) + { + fatal (_("Cannot convert existing library %s to thin format"), + bfd_get_filename (arch)); + goto bloser; + } + else if (! make_thin_archive && bfd_is_thin_archive (arch)) + { + fatal (_("Cannot convert existing thin library %s to normal format"), + bfd_get_filename (arch)); + goto bloser; + } + } + + last_one = &(arch->archive_next); /* Read all the contents right away, regardless. */ for (next_one = bfd_openr_next_archived_file (arch, NULL); next_one; @@ -816,7 +1012,7 @@ open_inarch (archive_filename, file) { PROGRESS (1); *last_one = next_one; - last_one = &next_one->next; + last_one = &next_one->archive_next; } *last_one = (bfd *) NULL; if (bfd_get_error () != bfd_error_no_more_archived_files) @@ -825,43 +1021,94 @@ open_inarch (archive_filename, file) } static void -print_contents (abfd) - bfd *abfd; +print_contents (bfd *abfd) { - int ncopied = 0; - char *cbuf = xmalloc (BUFSIZE); + bfd_size_type ncopied = 0; + bfd_size_type size; + char *cbuf = (char *) xmalloc (BUFSIZE); struct stat buf; - long size; + if (bfd_stat_arch_elt (abfd, &buf) != 0) /* xgettext:c-format */ fatal (_("internal stat error on %s"), bfd_get_filename (abfd)); if (verbose) - /* xgettext:c-format */ - printf (_("\n\n\n"), bfd_get_filename (abfd)); + printf ("\n<%s>\n\n", bfd_get_filename (abfd)); bfd_seek (abfd, (file_ptr) 0, SEEK_SET); size = buf.st_size; while (ncopied < size) { + bfd_size_type nread; + bfd_size_type tocopy = size - ncopied; - int nread; - int tocopy = size - ncopied; if (tocopy > BUFSIZE) tocopy = BUFSIZE; - nread = bfd_bread (cbuf, (bfd_size_type) tocopy, abfd); + nread = bfd_bread (cbuf, tocopy, abfd); if (nread != tocopy) /* xgettext:c-format */ fatal (_("%s is not a valid archive"), - bfd_get_filename (bfd_my_archive (abfd))); - fwrite (cbuf, 1, nread, stdout); + bfd_get_filename (abfd->my_archive)); + + /* fwrite in mingw32 may return int instead of bfd_size_type. Cast the + return value to bfd_size_type to avoid comparison between signed and + unsigned values. */ + if ((bfd_size_type) fwrite (cbuf, 1, nread, stdout) != nread) + fatal ("stdout: %s", strerror (errno)); ncopied += tocopy; } free (cbuf); } + +static FILE * open_output_file (bfd *) ATTRIBUTE_RETURNS_NONNULL; + +static FILE * +open_output_file (bfd * abfd) +{ + output_filename = bfd_get_filename (abfd); + + /* PR binutils/17533: Do not allow directory traversal + outside of the current directory tree - unless the + user has explicitly specified an output directory. */ + if (! is_valid_archive_path (output_filename)) + { + char * base = (char *) lbasename (output_filename); + + non_fatal (_("illegal output pathname for archive member: %s, using '%s' instead"), + output_filename, base); + output_filename = base; + } + + if (output_dir) + { + size_t len = strlen (output_dir); + + if (len > 0) + { + /* FIXME: There is a memory leak here, but it is not serious. */ + if (IS_DIR_SEPARATOR (output_dir [len - 1])) + output_filename = concat (output_dir, output_filename, NULL); + else + output_filename = concat (output_dir, "/", output_filename, NULL); + } + } + + if (verbose) + printf ("x - %s\n", output_filename); + + FILE * ostream = fopen (output_filename, FOPEN_WB); + if (ostream == NULL) + { + perror (output_filename); + xexit (1); + } + + return ostream; +} + /* Extract a member of the archive into its own file. We defer opening the new file until after we have read a BUFSIZ chunk of the @@ -873,14 +1120,9 @@ print_contents (abfd) Gilmore */ void -extract_file (abfd) - bfd *abfd; +extract_file (bfd *abfd) { - FILE *ostream; - char *cbuf = xmalloc (BUFSIZE); - int nread, tocopy; - long ncopied = 0; - long size; + bfd_size_type size; struct stat buf; if (bfd_stat_arch_elt (abfd, &buf) != 0) @@ -888,209 +1130,79 @@ extract_file (abfd) fatal (_("internal stat error on %s"), bfd_get_filename (abfd)); size = buf.st_size; - if (size < 0) - /* xgettext:c-format */ - fatal (_("stat returns negative size for %s"), bfd_get_filename (abfd)); - - if (verbose) - printf ("x - %s\n", bfd_get_filename (abfd)); - bfd_seek (abfd, (file_ptr) 0, SEEK_SET); - ostream = NULL; + output_file = NULL; if (size == 0) { - /* Seems like an abstraction violation, eh? Well it's OK! */ - output_filename = bfd_get_filename (abfd); - - ostream = fopen (bfd_get_filename (abfd), FOPEN_WB); - if (ostream == NULL) - { - perror (bfd_get_filename (abfd)); - xexit (1); - } - - output_file = ostream; + output_file = open_output_file (abfd); } else - while (ncopied < size) - { - tocopy = size - ncopied; - if (tocopy > BUFSIZE) - tocopy = BUFSIZE; - - nread = bfd_bread (cbuf, (bfd_size_type) tocopy, abfd); - if (nread != tocopy) - /* xgettext:c-format */ - fatal (_("%s is not a valid archive"), - bfd_get_filename (bfd_my_archive (abfd))); - - /* See comment above; this saves disk arm motion */ - if (ostream == NULL) - { - /* Seems like an abstraction violation, eh? Well it's OK! */ - output_filename = bfd_get_filename (abfd); - - ostream = fopen (bfd_get_filename (abfd), FOPEN_WB); - if (ostream == NULL) - { - perror (bfd_get_filename (abfd)); - xexit (1); - } - - output_file = ostream; - } - fwrite (cbuf, 1, nread, ostream); - ncopied += tocopy; - } - - if (ostream != NULL) - fclose (ostream); - - output_file = NULL; - output_filename = NULL; - - chmod (bfd_get_filename (abfd), buf.st_mode); - - if (preserve_dates) - set_times (bfd_get_filename (abfd), &buf); - - free (cbuf); -} - -#if 0 - -/* We don't use this anymore. Too many systems expect ar to rebuild - the symbol table even when q is used. */ - -/* Just do it quickly; don't worry about dups, armap, or anything like that */ - -static void -do_quick_append (archive_filename, files_to_append) - const char *archive_filename; - char **files_to_append; -{ - FILE *ofile, *ifile; - char *buf = xmalloc (BUFSIZE); - long tocopy, thistime; - bfd *temp; - struct stat sbuf; - bfd_boolean newfile = FALSE; - bfd_set_error (bfd_error_no_error); - - if (stat (archive_filename, &sbuf) != 0) { + bfd_size_type ncopied = 0; + char *cbuf = (char *) xmalloc (BUFSIZE); -#if !defined(__GO32__) || defined(__DJGPP__) + while (ncopied < size) + { + bfd_size_type nread, tocopy; - /* FIXME: I don't understand why this fragment was ifndef'ed - away for __GO32__; perhaps it was in the days of DJGPP v1.x. - stat() works just fine in v2.x, so I think this should be - removed. For now, I enable it for DJGPP v2. + tocopy = size - ncopied; + if (tocopy > BUFSIZE) + tocopy = BUFSIZE; - (And yes, I know this is all unused, but somebody, someday, - might wish to resurrect this again... -- EZ. */ + nread = bfd_bread (cbuf, tocopy, abfd); + if (nread != tocopy) + /* xgettext:c-format */ + fatal (_("%s is not a valid archive"), + bfd_get_filename (abfd->my_archive)); -/* KLUDGE ALERT! Temporary fix until I figger why - stat() is wrong ... think it's buried in GO32's IDT - Jax */ + /* See comment above; this saves disk arm motion. */ + if (output_file == NULL) + output_file = open_output_file (abfd); - if (errno != ENOENT) - bfd_fatal (archive_filename); -#endif + /* fwrite in mingw32 may return int instead of bfd_size_type. Cast + the return value to bfd_size_type to avoid comparison between + signed and unsigned values. */ + if ((bfd_size_type) fwrite (cbuf, 1, nread, output_file) != nread) + fatal ("%s: %s", output_filename, strerror (errno)); - newfile = TRUE; - } + ncopied += tocopy; + } - ofile = fopen (archive_filename, FOPEN_AUB); - if (ofile == NULL) - { - perror (program_name); - xexit (1); + free (cbuf); } - temp = bfd_openr (archive_filename, NULL); - if (temp == NULL) - { - bfd_fatal (archive_filename); - } - if (!newfile) - { - if (!bfd_check_format (temp, bfd_archive)) - /* xgettext:c-format */ - fatal (_("%s is not an archive"), archive_filename); - } - else - { - fwrite (ARMAG, 1, SARMAG, ofile); - if (!silent_create) - /* xgettext:c-format */ - non_fatal (_("creating %s"), archive_filename); - } + fclose (output_file); - if (ar_truncate) - temp->flags |= BFD_TRADITIONAL_FORMAT; + output_file = NULL; - /* assume it's an achive, go straight to the end, sans $200 */ - fseek (ofile, 0, 2); + chmod (output_filename, buf.st_mode); - for (; files_to_append && *files_to_append; ++files_to_append) + if (preserve_dates) { - struct ar_hdr *hdr = bfd_special_undocumented_glue (temp, *files_to_append); - if (hdr == NULL) - { - bfd_fatal (*files_to_append); - } - - BFD_SEND (temp, _bfd_truncate_arname, (temp, *files_to_append, (char *) hdr)); - - ifile = fopen (*files_to_append, FOPEN_RB); - if (ifile == NULL) - { - bfd_nonfatal (*files_to_append); - } - - if (stat (*files_to_append, &sbuf) != 0) - { - bfd_nonfatal (*files_to_append); - } - - tocopy = sbuf.st_size; - - /* XXX should do error-checking! */ - fwrite (hdr, 1, sizeof (struct ar_hdr), ofile); - - while (tocopy > 0) - { - thistime = tocopy; - if (thistime > BUFSIZE) - thistime = BUFSIZE; - fread (buf, 1, thistime, ifile); - fwrite (buf, 1, thistime, ofile); - tocopy -= thistime; - } - fclose (ifile); - if ((sbuf.st_size % 2) == 1) - putc ('\012', ofile); + /* Set access time to modification time. Only st_mtime is + initialized by bfd_stat_arch_elt. */ + buf.st_atime = buf.st_mtime; + set_times (output_filename, &buf); } - fclose (ofile); - bfd_close (temp); - free (buf); -} -#endif /* 0 */ + output_filename = NULL; +} static void -write_archive (iarch) - bfd *iarch; +write_archive (bfd *iarch) { bfd *obfd; char *old_name, *new_name; - bfd *contents_head = iarch->next; + bfd *contents_head = iarch->archive_next; - old_name = xmalloc (strlen (bfd_get_filename (iarch)) + 1); + old_name = (char *) xmalloc (strlen (bfd_get_filename (iarch)) + 1); strcpy (old_name, bfd_get_filename (iarch)); new_name = make_tempname (old_name); + if (new_name == NULL) + bfd_fatal (_("could not create temporary file whilst writing archive")); + output_filename = new_name; obfd = bfd_openw (new_name, bfd_get_target (iarch)); @@ -1113,6 +1225,15 @@ write_archive (iarch) obfd->flags |= BFD_TRADITIONAL_FORMAT; } + if (deterministic) + obfd->flags |= BFD_DETERMINISTIC_OUTPUT; + + if (full_pathname) + obfd->flags |= BFD_ARCHIVE_FULL_PATH; + + if (make_thin_archive || bfd_is_thin_archive (iarch)) + bfd_set_thin_archive (obfd, TRUE); + if (!bfd_set_archive_head (obfd, contents_head)) bfd_fatal (old_name); @@ -1127,6 +1248,8 @@ write_archive (iarch) if (smart_rename (new_name, old_name, 0) != 0) xexit (1); + free (old_name); + free (new_name); } /* Return a pointer to the pointer to the entry which should be rplacd'd @@ -1134,10 +1257,7 @@ write_archive (iarch) and should be a pos value. */ static bfd ** -get_pos_bfd (contents, default_pos, default_posname) - bfd **contents; - enum pos default_pos; - const char *default_posname; +get_pos_bfd (bfd **contents, enum pos default_pos, const char *default_posname) { bfd **after_bfd = contents; enum pos realpos; @@ -1157,15 +1277,15 @@ get_pos_bfd (contents, default_pos, default_posname) if (realpos == pos_end) { while (*after_bfd) - after_bfd = &((*after_bfd)->next); + after_bfd = &((*after_bfd)->archive_next); } else { - for (; *after_bfd; after_bfd = &(*after_bfd)->next) - if (FILENAME_CMP ((*after_bfd)->filename, realposname) == 0) + for (; *after_bfd; after_bfd = &(*after_bfd)->archive_next) + if (FILENAME_CMP (bfd_get_filename (*after_bfd), realposname) == 0) { if (realpos == pos_after) - after_bfd = &(*after_bfd)->next; + after_bfd = &(*after_bfd)->archive_next; break; } } @@ -1173,9 +1293,7 @@ get_pos_bfd (contents, default_pos, default_posname) } static void -delete_members (arch, files_to_delete) - bfd *arch; - char **files_to_delete; +delete_members (bfd *arch, char **files_to_delete) { bfd **current_ptr_ptr; bfd_boolean found; @@ -1199,11 +1317,11 @@ delete_members (arch, files_to_delete) found = FALSE; match_count = 0; - current_ptr_ptr = &(arch->next); + current_ptr_ptr = &(arch->archive_next); while (*current_ptr_ptr) { if (FILENAME_CMP (normalize (*files_to_delete, arch), - (*current_ptr_ptr)->filename) == 0) + bfd_get_filename (*current_ptr_ptr)) == 0) { ++match_count; if (counted_name_mode @@ -1219,12 +1337,12 @@ delete_members (arch, files_to_delete) if (verbose) printf ("d - %s\n", *files_to_delete); - *current_ptr_ptr = ((*current_ptr_ptr)->next); + *current_ptr_ptr = ((*current_ptr_ptr)->archive_next); goto next_file; } } - current_ptr_ptr = &((*current_ptr_ptr)->next); + current_ptr_ptr = &((*current_ptr_ptr)->archive_next); } if (verbose && !found) @@ -1246,32 +1364,30 @@ delete_members (arch, files_to_delete) /* Reposition existing members within an archive */ static void -move_members (arch, files_to_move) - bfd *arch; - char **files_to_move; +move_members (bfd *arch, char **files_to_move) { bfd **after_bfd; /* New entries go after this one */ bfd **current_ptr_ptr; /* cdr pointer into contents */ for (; *files_to_move; ++files_to_move) { - current_ptr_ptr = &(arch->next); + current_ptr_ptr = &(arch->archive_next); while (*current_ptr_ptr) { bfd *current_ptr = *current_ptr_ptr; if (FILENAME_CMP (normalize (*files_to_move, arch), - current_ptr->filename) == 0) + bfd_get_filename (current_ptr)) == 0) { /* Move this file to the end of the list - first cut from where it is. */ - bfd *link; - *current_ptr_ptr = current_ptr->next; + bfd *link_bfd; + *current_ptr_ptr = current_ptr->archive_next; /* Now glue to end */ - after_bfd = get_pos_bfd (&arch->next, pos_end, NULL); - link = *after_bfd; + after_bfd = get_pos_bfd (&arch->archive_next, pos_end, NULL); + link_bfd = *after_bfd; *after_bfd = current_ptr; - current_ptr->next = link; + current_ptr->archive_next = link_bfd; if (verbose) printf ("m - %s\n", *files_to_move); @@ -1279,10 +1395,11 @@ move_members (arch, files_to_move) goto next_file; } - current_ptr_ptr = &((*current_ptr_ptr)->next); + current_ptr_ptr = &((*current_ptr_ptr)->archive_next); } /* xgettext:c-format */ - fatal (_("no entry %s in archive %s!"), *files_to_move, arch->filename); + fatal (_("no entry %s in archive %s!"), *files_to_move, + bfd_get_filename (arch)); next_file:; } @@ -1293,13 +1410,10 @@ move_members (arch, files_to_move) /* Ought to default to replacing in place, but this is existing practice! */ static void -replace_members (arch, files_to_move, quick) - bfd *arch; - char **files_to_move; - bfd_boolean quick; +replace_members (bfd *arch, char **files_to_move, bfd_boolean quick) { bfd_boolean changed = FALSE; - bfd **after_bfd; /* New entries go after this one */ + bfd **after_bfd; /* New entries go after this one. */ bfd *current; bfd **current_ptr; @@ -1307,7 +1421,7 @@ replace_members (arch, files_to_move, quick) { if (! quick) { - current_ptr = &arch->next; + current_ptr = &arch->archive_next; while (*current_ptr) { current = *current_ptr; @@ -1315,7 +1429,7 @@ replace_members (arch, files_to_move, quick) /* For compatibility with existing ar programs, we permit the same file to be added multiple times. */ if (FILENAME_CMP (normalize (*files_to_move, arch), - normalize (current->filename, arch)) == 0 + normalize (bfd_get_filename (current), arch)) == 0 && current->arelt_data != NULL) { if (newer_only) @@ -1331,31 +1445,33 @@ replace_members (arch, files_to_move, quick) if (bfd_stat_arch_elt (current, &asbuf) != 0) /* xgettext:c-format */ fatal (_("internal stat error on %s"), - current->filename); + bfd_get_filename (current)); if (fsbuf.st_mtime <= asbuf.st_mtime) goto next_file; } - after_bfd = get_pos_bfd (&arch->next, pos_after, - current->filename); + after_bfd = get_pos_bfd (&arch->archive_next, pos_after, + bfd_get_filename (current)); if (ar_emul_replace (after_bfd, *files_to_move, - verbose)) + target, verbose)) { /* Snip out this entry from the chain. */ - *current_ptr = (*current_ptr)->next; + *current_ptr = (*current_ptr)->archive_next; changed = TRUE; } goto next_file; } - current_ptr = &(current->next); + current_ptr = &(current->archive_next); } } /* Add to the end of the archive. */ - after_bfd = get_pos_bfd (&arch->next, pos_end, NULL); - if (ar_emul_append (after_bfd, *files_to_move, verbose)) + after_bfd = get_pos_bfd (&arch->archive_next, pos_end, NULL); + + if (ar_emul_append (after_bfd, *files_to_move, target, + verbose, make_thin_archive)) changed = TRUE; next_file:; @@ -1369,24 +1485,25 @@ replace_members (arch, files_to_move, quick) output_filename = NULL; } -static void -ranlib_only (archname) - const char *archname; +static int +ranlib_only (const char *archname) { bfd *arch; + if (get_file_size (archname) < 1) + return 1; write_armap = 1; arch = open_inarch (archname, (char *) NULL); if (arch == NULL) xexit (1); write_archive (arch); + return 0; } /* Update the timestamp of the symbol map of an archive. */ -static void -ranlib_touch (archname) - const char *archname; +static int +ranlib_touch (const char *archname) { #ifdef __GO32__ /* I don't think updating works on go32. */ @@ -1396,6 +1513,8 @@ ranlib_touch (archname) bfd *arch; char **matching; + if (get_file_size (archname) < 1) + return 1; f = open (archname, O_RDWR | O_BINARY, 0); if (f < 0) { @@ -1421,18 +1540,21 @@ ranlib_touch (archname) /* xgettext:c-format */ fatal (_("%s: no archive map to update"), archname); + if (deterministic) + arch->flags |= BFD_DETERMINISTIC_OUTPUT; + bfd_update_armap_timestamp (arch); if (! bfd_close (arch)) bfd_fatal (archname); #endif + return 0; } /* Things which are interesting to map over all or some of the files: */ static void -print_descr (abfd) - bfd *abfd; +print_descr (bfd *abfd) { - print_arelt_descr (stdout, abfd, verbose); + print_arelt_descr (stdout, abfd, verbose, display_offsets); }