/* objcopy.c -- copy object file from input to output, optionally massaging it.
Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
- 2001, 2002, 2003
+ 2001, 2002, 2003, 2004
Free Software Foundation, Inc.
This file is part of GNU Binutils.
#include "libiberty.h"
#include "budbg.h"
#include "filenames.h"
+#include "fnmatch.h"
+#include "elf-bfd.h"
#include <sys/stat.h>
/* A list of symbols to explicitly strip out, or to keep. A linked
/* Use alternate machine code? */
static int use_alt_mach_code = 0;
+/* Output BFD flags user wants to set or clear */
+static flagword bfd_flags_to_set;
+static flagword bfd_flags_to_clear;
+
/* List of sections to add. */
struct section_add
{
/* Whether to remove the leading character from global symbol names. */
static bfd_boolean remove_leading_char = FALSE;
+/* Whether to permit wildcard in symbol comparison. */
+static bfd_boolean wildcard = FALSE;
+
/* List of symbols to strip, keep, localize, keep-global, weaken,
or redefine. */
static struct symlist *strip_specific_list = NULL;
OPTION_PREFIX_ALLOC_SECTIONS,
OPTION_FORMATS_INFO,
OPTION_ADD_GNU_DEBUGLINK,
- OPTION_ONLY_KEEP_DEBUG
+ OPTION_ONLY_KEEP_DEBUG,
+ OPTION_READONLY_TEXT,
+ OPTION_WRITABLE_TEXT,
+ OPTION_PURE,
+ OPTION_IMPURE
};
/* Options to handle if running as "strip". */
{"target", required_argument, 0, 'F'},
{"verbose", no_argument, 0, 'v'},
{"version", no_argument, 0, 'V'},
+ {"wildcard", no_argument, 0, 'w'},
{0, no_argument, 0, 0}
};
{"format", required_argument, 0, 'F'}, /* Obsolete */
{"gap-fill", required_argument, 0, OPTION_GAP_FILL},
{"help", no_argument, 0, 'h'},
+ {"impure", no_argument, 0, OPTION_IMPURE},
{"info", no_argument, 0, OPTION_FORMATS_INFO},
{"input-format", required_argument, 0, 'I'}, /* Obsolete */
{"input-target", required_argument, 0, 'I'},
{"prefix-sections", required_argument, 0, OPTION_PREFIX_SECTIONS},
{"prefix-alloc-sections", required_argument, 0, OPTION_PREFIX_ALLOC_SECTIONS},
{"preserve-dates", no_argument, 0, 'p'},
+ {"pure", no_argument, 0, OPTION_PURE},
+ {"readonly-text", no_argument, 0, OPTION_READONLY_TEXT},
{"redefine-sym", required_argument, 0, OPTION_REDEFINE_SYM},
{"redefine-syms", required_argument, 0, OPTION_REDEFINE_SYMS},
{"remove-leading-char", no_argument, 0, OPTION_REMOVE_LEADING_CHAR},
{"weaken", no_argument, 0, OPTION_WEAKEN},
{"weaken-symbol", required_argument, 0, 'W'},
{"weaken-symbols", required_argument, 0, OPTION_WEAKEN_SYMBOLS},
+ {"wildcard", no_argument, 0, 'w'},
+ {"writable-text", no_argument, 0, OPTION_WRITABLE_TEXT},
{0, no_argument, 0, 0}
};
-g --strip-debug Remove all debugging symbols & sections\n\
--strip-unneeded Remove all symbols not needed by relocations\n\
-N --strip-symbol <name> Do not copy symbol <name>\n\
+ --only-keep-debug Strip everything but the debug information\n\
-K --keep-symbol <name> Only copy symbol <name>\n\
-L --localize-symbol <name> Force symbol <name> to be marked as a local\n\
-G --keep-global-symbol <name> Localize all symbols except <name>\n\
-W --weaken-symbol <name> Force symbol <name> to be marked as a weak\n\
--weaken Force all global symbols to be marked as weak\n\
+ -w --wildcard Permit wildcard in symbol comparasion\n\
-x --discard-all Remove all non-global symbols\n\
-X --discard-locals Remove any compiler-generated symbols\n\
-i --interleave <number> Only copy one out of every <number> bytes\n\
--keep-global-symbols <file> -G for all symbols listed in <file>\n\
--weaken-symbols <file> -W for all symbols listed in <file>\n\
--alt-machine-code <index> Use alternate machine code for output\n\
+ --writable-text Mark the output text as writable\n\
+ --readonly-text Make the output text write protected\n\
+ --pure Mark the output file as demand paged\n\
+ --impure Mark the output file as impure\n\
--prefix-symbols <prefix> Add <prefix> to start of every symbol name\n\
--prefix-sections <prefix> Add <prefix> to start of every section name\n\
--prefix-alloc-sections <prefix>\n\
-s --strip-all Remove all symbol and relocation information\n\
-g -S -d --strip-debug Remove all debugging symbols & sections\n\
--strip-unneeded Remove all symbols not needed by relocations\n\
+ --only-keep-debug Strip everything but the debug information\n\
-N --strip-symbol=<name> Do not copy symbol <name>\n\
-K --keep-symbol=<name> Only copy symbol <name>\n\
+ -w --wildcard Permit wildcard in symbol comparasion\n\
-x --discard-all Remove all non-global symbols\n\
-X --discard-locals Remove any compiler-generated symbols\n\
-v --verbose List all object files modified\n\
static void
add_specific_symbols (const char *filename, struct symlist **list)
{
- struct stat st;
+ off_t size;
FILE * f;
char * line;
char * buffer;
unsigned int line_count;
- if (stat (filename, & st) < 0)
- fatal (_("cannot stat: %s: %s"), filename, strerror (errno));
- if (st.st_size == 0)
+ size = get_file_size (filename);
+ if (size == 0)
return;
- buffer = xmalloc (st.st_size + 2);
+ buffer = xmalloc (size + 2);
f = fopen (filename, FOPEN_RT);
if (f == NULL)
- fatal (_("cannot open: %s: %s"), filename, strerror (errno));
+ fatal (_("cannot open '%s': %s"), filename, strerror (errno));
- if (fread (buffer, 1, st.st_size, f) == 0 || ferror (f))
+ if (fread (buffer, 1, size, f) == 0 || ferror (f))
fatal (_("%s: fread failed"), filename);
fclose (f);
- buffer [st.st_size] = '\n';
- buffer [st.st_size + 1] = '\0';
+ buffer [size] = '\n';
+ buffer [size + 1] = '\0';
line_count = 1;
{
struct symlist *tmp_list;
- for (tmp_list = list; tmp_list; tmp_list = tmp_list->next)
- if (strcmp (name, tmp_list->name) == 0)
- return TRUE;
+ if (wildcard)
+ {
+ for (tmp_list = list; tmp_list; tmp_list = tmp_list->next)
+ if (*(tmp_list->name) != '!')
+ {
+ if (!fnmatch (tmp_list->name, name, 0))
+ return TRUE;
+ }
+ else
+ {
+ if (fnmatch (tmp_list->name + 1, name, 0))
+ return TRUE;
+ }
+ }
+ else
+ {
+ for (tmp_list = list; tmp_list; tmp_list = tmp_list->next)
+ if (strcmp (name, tmp_list->name) == 0)
+ return TRUE;
+ }
return FALSE;
}
return FALSE;
}
- return strip_symbols == STRIP_NONDEBUG ? TRUE : FALSE;
+ return FALSE;
}
/* Choose which symbol entries to copy; put the result in OSYMS.
free (buf);
}
-/* Keep only every `copy_byte'th byte in MEMHUNK, which is *SIZE bytes long.
- Adjust *SIZE. */
-
-static void
-filter_bytes (char *memhunk, bfd_size_type *size)
-{
- char *from = memhunk + copy_byte, *to = memhunk, *end = memhunk + *size;
-
- for (; from < end; from += interleave)
- *to++ = *from;
-
- if (*size % interleave > (bfd_size_type) copy_byte)
- *size = (*size / interleave) + 1;
- else
- *size /= interleave;
-}
-
-/* Copy object file IBFD onto OBFD. */
+/* Copy object file IBFD onto OBFD.
+ Returns TRUE upon success, FALSE otherwise. */
-static void
+static bfd_boolean
copy_object (bfd *ibfd, bfd *obfd)
{
bfd_vma start;
if (ibfd->xvec->byteorder != obfd->xvec->byteorder
&& ibfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN
&& obfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN)
- {
- fatal (_("Unable to change endianness of input file(s)"));
- return;
- }
+ fatal (_("Unable to change endianness of input file(s)"));
if (!bfd_set_format (obfd, bfd_get_format (ibfd)))
- RETURN_NONFATAL (bfd_get_filename (obfd));
+ {
+ bfd_nonfatal (bfd_get_filename (obfd));
+ return FALSE;
+ }
if (verbose)
printf (_("copy from %s(%s) to %s(%s)\n"),
need to be set for a core file. */
if (bfd_get_format (obfd) != bfd_core)
{
+ flagword flags;
+
+ flags = bfd_get_file_flags (ibfd);
+ flags |= bfd_flags_to_set;
+ flags &= ~bfd_flags_to_clear;
+ flags &= bfd_applicable_file_flags (obfd);
+
if (!bfd_set_start_address (obfd, start)
- || !bfd_set_file_flags (obfd,
- (bfd_get_file_flags (ibfd)
- & bfd_applicable_file_flags (obfd))))
- RETURN_NONFATAL (bfd_get_filename (ibfd));
+ || !bfd_set_file_flags (obfd, flags))
+ {
+ bfd_nonfatal (bfd_get_filename (ibfd));
+ return FALSE;
+ }
}
/* Copy architecture of input file to output file. */
if (!bfd_set_arch_mach (obfd, iarch, imach)
&& (ibfd->target_defaulted
|| bfd_get_arch (ibfd) != bfd_get_arch (obfd)))
- non_fatal (_("Warning: Output file cannot represent architecture %s"),
- bfd_printable_arch_mach (bfd_get_arch (ibfd),
- bfd_get_mach (ibfd)));
+ {
+ if (bfd_get_arch (ibfd) == bfd_arch_unknown)
+ fatal (_("Unable to recognise the format of the input file %s"),
+ bfd_get_filename (ibfd));
+ else
+ {
+ non_fatal (_("Warning: Output file cannot represent architecture %s"),
+ bfd_printable_arch_mach (bfd_get_arch (ibfd),
+ bfd_get_mach (ibfd)));
+ return FALSE;
+ }
+ }
if (!bfd_set_format (obfd, bfd_get_format (ibfd)))
- RETURN_NONFATAL (bfd_get_filename (ibfd));
+ {
+ bfd_nonfatal (bfd_get_filename (ibfd));
+ return FALSE;
+ }
if (isympp)
free (isympp);
{
non_fatal (_("can't create section `%s': %s"),
padd->name, bfd_errmsg (bfd_get_error ()));
- status = 1;
- return;
+ return FALSE;
}
if (! bfd_set_section_size (obfd, padd->section, padd->size))
- RETURN_NONFATAL (bfd_get_filename (obfd));
+ {
+ bfd_nonfatal (bfd_get_filename (obfd));
+ return FALSE;
+ }
pset = find_section_list (padd->name, FALSE);
if (pset != NULL)
flags = SEC_HAS_CONTENTS | SEC_READONLY | SEC_DATA;
if (! bfd_set_section_flags (obfd, padd->section, flags))
- RETURN_NONFATAL (bfd_get_filename (obfd));
+ {
+ bfd_nonfatal (bfd_get_filename (obfd));
+ return FALSE;
+ }
if (pset != NULL)
{
if (pset->change_vma != CHANGE_IGNORE)
if (! bfd_set_section_vma (obfd, padd->section,
pset->vma_val))
- RETURN_NONFATAL (bfd_get_filename (obfd));
+ {
+ bfd_nonfatal (bfd_get_filename (obfd));
+ return FALSE;
+ }
if (pset->change_lma != CHANGE_IGNORE)
{
padd->section->lma = pset->lma_val;
-
+
if (! bfd_set_section_alignment
(obfd, padd->section,
bfd_section_alignment (obfd, padd->section)))
- RETURN_NONFATAL (bfd_get_filename (obfd));
+ {
+ bfd_nonfatal (bfd_get_filename (obfd));
+ return FALSE;
+ }
}
}
}
(obfd, gnu_debuglink_filename);
if (gnu_debuglink_section == NULL)
- RETURN_NONFATAL (gnu_debuglink_filename);
+ {
+ bfd_nonfatal (gnu_debuglink_filename);
+ return FALSE;
+ }
+ }
+
+ if (bfd_count_sections (obfd) == 0)
+ {
+ non_fatal (_("there are no sections to be copied!"));
+ return FALSE;
}
if (gap_fill_set || pad_to_set)
dhandle = NULL;
symsize = bfd_get_symtab_upper_bound (ibfd);
if (symsize < 0)
- RETURN_NONFATAL (bfd_get_filename (ibfd));
+ {
+ bfd_nonfatal (bfd_get_filename (ibfd));
+ return FALSE;
+ }
osympp = isympp = xmalloc (symsize);
symcount = bfd_canonicalize_symtab (ibfd, isympp);
if (symcount < 0)
- RETURN_NONFATAL (bfd_get_filename (ibfd));
+ {
+ bfd_nonfatal (bfd_get_filename (ibfd));
+ return FALSE;
+ }
if (convert_debugging)
dhandle = read_debugging_info (ibfd, isympp, symcount);
if (! write_debugging_info (obfd, dhandle, &symcount, &osympp))
{
status = 1;
- return;
+ return FALSE;
}
}
{
if (! bfd_set_section_contents (obfd, padd->section, padd->contents,
0, padd->size))
- RETURN_NONFATAL (bfd_get_filename (obfd));
+ {
+ bfd_nonfatal (bfd_get_filename (obfd));
+ return FALSE;
+ }
}
}
{
if (! bfd_fill_in_gnu_debuglink_section
(obfd, gnu_debuglink_section, gnu_debuglink_filename))
- RETURN_NONFATAL (gnu_debuglink_filename);
+ {
+ bfd_nonfatal (gnu_debuglink_filename);
+ return FALSE;
+ }
}
if (gap_fill_set || pad_to_set)
if (! bfd_set_section_contents (obfd, osections[i], buf,
off, now))
- RETURN_NONFATAL (bfd_get_filename (obfd));
+ {
+ bfd_nonfatal (bfd_get_filename (obfd));
+ return FALSE;
+ }
left -= now;
off += now;
non_fatal (_("%s: error copying private BFD data: %s"),
bfd_get_filename (obfd),
bfd_errmsg (bfd_get_error ()));
- status = 1;
- return;
+ return FALSE;
}
/* Switch to the alternate machine code. We have to do this at the
very end, because we only initialize the header when we create
the first section. */
- if (use_alt_mach_code != 0)
- {
- if (!bfd_alt_mach_code (obfd, use_alt_mach_code))
- non_fatal (_("unknown alternate machine code, ignored"));
- }
+ if (use_alt_mach_code != 0
+ && ! bfd_alt_mach_code (obfd, use_alt_mach_code))
+ non_fatal (_("unknown alternate machine code, ignored"));
+
+ return TRUE;
}
#undef MKDIR
bfd *last_element;
struct stat buf;
int stat_status = 0;
+ bfd_boolean delete = TRUE;
/* Create an output file for this member. */
output_name = concat (dir, "/",
RETURN_NONFATAL (output_name);
if (bfd_check_format (this_element, bfd_object))
- copy_object (this_element, output_bfd);
+ delete = ! copy_object (this_element, output_bfd);
if (!bfd_close (output_bfd))
{
status = 1;
}
- if (preserve_dates && stat_status == 0)
- set_times (output_name, &buf);
+ if (delete)
+ {
+ unlink (output_name);
+ status = 1;
+ }
+ else
+ {
+ if (preserve_dates && stat_status == 0)
+ set_times (output_name, &buf);
- /* Open the newly output file and attach to our list. */
- output_bfd = bfd_openr (output_name, output_target);
+ /* Open the newly output file and attach to our list. */
+ output_bfd = bfd_openr (output_name, output_target);
- l->obfd = output_bfd;
+ l->obfd = output_bfd;
- *ptr = output_bfd;
- ptr = &output_bfd->next;
+ *ptr = output_bfd;
+ ptr = &output_bfd->next;
- last_element = this_element;
+ last_element = this_element;
- this_element = bfd_openr_next_archived_file (ibfd, last_element);
+ this_element = bfd_openr_next_archived_file (ibfd, last_element);
- bfd_close (last_element);
+ bfd_close (last_element);
+ }
}
*ptr = NULL;
char **obj_matching;
char **core_matching;
+ if (get_file_size (input_filename) < 1)
+ {
+ status = 1;
+ return;
+ }
+
/* To allow us to do "strip *" without dying on the first
non-object file, failures are nonfatal. */
ibfd = bfd_openr (input_filename, input_target);
else if (bfd_check_format_matches (ibfd, bfd_object, &obj_matching))
{
bfd *obfd;
+ bfd_boolean delete;
do_copy:
+
/* bfd_get_target does not return the correct value until
bfd_check_format succeeds. */
if (output_target == NULL)
if (obfd == NULL)
RETURN_NONFATAL (output_filename);
- copy_object (ibfd, obfd);
+ delete = ! copy_object (ibfd, obfd);
if (!bfd_close (obfd))
RETURN_NONFATAL (output_filename);
if (!bfd_close (ibfd))
RETURN_NONFATAL (input_filename);
+
+ if (delete)
+ {
+ unlink (output_filename);
+ status = 1;
+ }
}
else
{
if (p != NULL && p->set_flags)
flags = p->flags | (flags & (SEC_HAS_CONTENTS | SEC_RELOC));
+ else if (strip_symbols == STRIP_NONDEBUG && (flags & SEC_ALLOC) != 0)
+ {
+ flags &= ~(SEC_HAS_CONTENTS | SEC_LOAD);
+ if (obfd->xvec->flavour == bfd_target_elf_flavour)
+ elf_section_type (osection) = SHT_NOBITS;
+ }
+
if (!bfd_set_section_flags (obfd, osection, flags))
{
err = _("flags");
}
bfd_set_reloc (obfd, osection, relcount == 0 ? NULL : relpp, relcount);
+ if (relcount == 0)
+ free (relpp);
}
isection->_cooked_size = isection->_raw_size;
RETURN_NONFATAL (bfd_get_filename (ibfd));
if (copy_byte >= 0)
- filter_bytes (memhunk, &size);
+ {
+ /* Keep only every `copy_byte'th byte in MEMHUNK. */
+ char *from = (char *) memhunk + copy_byte;
+ char *to = memhunk;
+ char *end = (char *) memhunk + size;
+
+ for (; from < end; from += interleave)
+ *to++ = *from;
+
+ size = (size + interleave - 1 - copy_byte) / interleave;
+ osection->lma /= interleave;
+ }
if (!bfd_set_section_contents (obfd, osection, memhunk, 0, size))
RETURN_NONFATAL (bfd_get_filename (obfd));
struct section_list *p;
char *output_file = NULL;
- while ((c = getopt_long (argc, argv, "I:O:F:K:N:R:o:sSpdgxXHhVv",
+ while ((c = getopt_long (argc, argv, "I:O:F:K:N:R:o:sSpdgxXHhVvw",
strip_options, (int *) 0)) != EOF)
{
switch (c)
case 0:
/* We've been given a long option. */
break;
+ case 'w':
+ wildcard = TRUE;
+ break;
case 'H':
case 'h':
strip_usage (stdout, 0);
struct stat statbuf;
char *tmpname;
+ if (get_file_size (argv[i]) < 1)
+ continue;
+
if (preserve_dates)
- {
- if (stat (argv[i], &statbuf) < 0)
- {
- non_fatal (_("%s: cannot stat: %s"), argv[i], strerror (errno));
- continue;
- }
- }
+ /* No need to check the return value of stat().
+ It has already been checked in get_file_size(). */
+ stat (argv[i], &statbuf);
if (output_file != NULL)
tmpname = output_file;
struct section_list *p;
struct stat statbuf;
- while ((c = getopt_long (argc, argv, "b:B:i:I:j:K:N:s:O:d:F:L:G:R:SpgxXHhVvW:",
+ while ((c = getopt_long (argc, argv, "b:B:i:I:j:K:N:s:O:d:F:L:G:R:SpgxXHhVvW:w",
copy_options, (int *) 0)) != EOF)
{
switch (c)
preserve_dates = TRUE;
break;
+ case 'w':
+ wildcard = TRUE;
+ break;
+
case 'x':
discard_locals = LOCALS_ALL;
break;
case OPTION_ADD_SECTION:
{
const char *s;
- struct stat st;
+ off_t size;
struct section_add *pa;
int len;
char *name;
if (s == NULL)
fatal (_("bad format for %s"), "--add-section");
- if (stat (s + 1, & st) < 0)
- fatal (_("cannot stat: %s: %s"), s + 1, strerror (errno));
+ size = get_file_size (s + 1);
+ if (size < 1)
+ break;
pa = xmalloc (sizeof (struct section_add));
pa->name = name;
pa->filename = s + 1;
+ pa->size = size;
+ pa->contents = xmalloc (size);
- pa->size = st.st_size;
-
- pa->contents = xmalloc (pa->size);
f = fopen (pa->filename, FOPEN_RB);
if (f == NULL)
prefix_alloc_sections_string = optarg;
break;
+ case OPTION_READONLY_TEXT:
+ bfd_flags_to_set |= WP_TEXT;
+ bfd_flags_to_clear &= ~WP_TEXT;
+ break;
+
+ case OPTION_WRITABLE_TEXT:
+ bfd_flags_to_clear |= WP_TEXT;
+ bfd_flags_to_set &= ~WP_TEXT;
+ break;
+
+ case OPTION_PURE:
+ bfd_flags_to_set |= D_PAGED;
+ bfd_flags_to_clear &= ~D_PAGED;
+ break;
+
+ case OPTION_IMPURE:
+ bfd_flags_to_clear |= D_PAGED;
+ bfd_flags_to_set &= ~D_PAGED;
+ break;
+
case 0:
/* We've been given a long option. */
break;
if (preserve_dates)
if (stat (input_filename, & statbuf) < 0)
- fatal (_("Cannot stat: %s: %s"), input_filename, strerror (errno));
+ fatal (_("warning: could not locate '%s'. System error message: %s"),
+ input_filename, strerror (errno));
/* If there is no destination file, or the source and destination files
are the same, then create a temp and rename the result into the input. */