#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
/* List of symbols to strip, keep, localize, keep-global, weaken,
or redefine. */
static struct symlist *strip_specific_list = NULL;
+static struct symlist *strip_unneeded_list = NULL;
static struct symlist *keep_specific_list = NULL;
static struct symlist *localize_specific_list = NULL;
static struct symlist *keepglobal_specific_list = NULL;
OPTION_SREC_LEN,
OPTION_SREC_FORCES3,
OPTION_STRIP_SYMBOLS,
+ OPTION_STRIP_UNNEEDED_SYMBOL,
+ OPTION_STRIP_UNNEEDED_SYMBOLS,
OPTION_KEEP_SYMBOLS,
OPTION_LOCALIZE_SYMBOLS,
OPTION_KEEPGLOBAL_SYMBOLS,
{"strip-all", no_argument, 0, 'S'},
{"strip-debug", no_argument, 0, 'g'},
{"strip-unneeded", no_argument, 0, OPTION_STRIP_UNNEEDED},
+ {"strip-unneeded-symbol", required_argument, 0, OPTION_STRIP_UNNEEDED_SYMBOL},
+ {"strip-unneeded-symbols", required_argument, 0, OPTION_STRIP_UNNEEDED_SYMBOLS},
{"strip-symbol", required_argument, 0, 'N'},
{"strip-symbols", required_argument, 0, OPTION_STRIP_SYMBOLS},
{"target", required_argument, 0, 'F'},
/* Forward declarations. */
static void setup_section (bfd *, asection *, void *);
+static void setup_bfd_headers (bfd *, bfd *);
static void copy_section (bfd *, asection *, void *);
static void get_sections (bfd *, asection *, void *);
static int compare_section_lma (const void *, const void *);
-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\
+ --strip-unneeded-symbol <name>\n\
+ Do not copy symbol <name> unless needed by\n\
+ relocations\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\
+ -w --wildcard Permit wildcard in symbol comparison\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\
--srec-len <number> Restrict the length of generated Srecords\n\
--srec-forceS3 Restrict the type of generated Srecords to S3\n\
--strip-symbols <file> -N for all symbols listed in <file>\n\
+ --strip-unneeded-symbols <file>\n\
+ --strip-unneeded-symbol for all symbols listed\n\
+ in <file>\n\
--keep-symbols <file> -K for all symbols listed in <file>\n\
--localize-symbols <file> -L for all symbols listed in <file>\n\
--keep-global-symbols <file> -G for all symbols listed in <file>\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\
+ -w --wildcard Permit wildcard in symbol comparison\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\
;
if (! IS_LINE_TERMINATOR (* extra))
- non_fatal (_("Ignoring rubbish found on line %d of %s"),
- line_count, filename);
+ non_fatal (_("%s:%d: Ignoring rubbish found on this line"),
+ filename, line_count);
}
* name_end = '\0';
return FALSE;
}
- return strip_symbols == STRIP_NONDEBUG ? TRUE : FALSE;
+ return FALSE;
}
/* Choose which symbol entries to copy; put the result in OSYMS.
keep = (strip_symbols != STRIP_DEBUG
&& strip_symbols != STRIP_UNNEEDED
&& ! convert_debugging);
- else if (bfd_get_section (sym)->comdat)
+ else if (bfd_coff_get_comdat_section (abfd, bfd_get_section (sym)))
/* COMDAT sections store special information in local
symbols, so we cannot risk stripping any of them. */
keep = 1;
if (keep && is_specified_symbol (name, strip_specific_list))
keep = 0;
+ if (keep
+ && !(flags & BSF_KEEP)
+ && is_specified_symbol (name, strip_unneeded_list))
+ keep = 0;
if (!keep && is_specified_symbol (name, keep_specific_list))
keep = 1;
if (keep && is_strip_section (abfd, bfd_get_section (sym)))
continue;
}
else
- fatal (_("%s: garbage at end of line %d"), filename, lineno);
+ fatal (_("%s:%d: garbage found at end of line"), filename, lineno);
comment:
if (len != 0 && (outsym_off == 0 || outsym_off == len))
- fatal (_("%s: missing new symbol name at line %d"), filename, lineno);
+ fatal (_("%s:%d: missing new symbol name"), filename, lineno);
buf[len++] = '\0';
/* Eat the rest of the line and finish it. */
}
if (len != 0)
- fatal (_("%s: premature end of file at line %d"), filename, lineno);
+ fatal (_("%s:%d: premature end of file"), filename, lineno);
free (buf);
}
-/* 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"),
if (!bfd_set_start_address (obfd, start)
|| !bfd_set_file_flags (obfd, flags))
- RETURN_NONFATAL (bfd_get_filename (ibfd));
+ {
+ bfd_nonfatal (bfd_get_filename (ibfd));
+ return FALSE;
+ }
}
/* Copy architecture of input file to output file. */
non_fatal (_("Warning: Output file cannot represent architecture %s"),
bfd_printable_arch_mach (bfd_get_arch (ibfd),
bfd_get_mach (ibfd)));
- status = 1;
- return;
+ 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);
any output is done. Thus, we traverse all sections multiple times. */
bfd_map_over_sections (ibfd, setup_section, obfd);
+ setup_bfd_headers (ibfd, obfd);
+
if (add_sections != NULL)
{
struct section_add *padd;
{
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;
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
{
return old_name;
}
+/* Once each of the sections is copied, we may still need to do some
+ finalization work for private section headers. Do that here. */
+
+static void
+setup_bfd_headers (bfd *ibfd, bfd *obfd)
+{
+ const char *err;
+
+ /* Allow the BFD backend to copy any private data it understands
+ from the input section to the output section. */
+ if (! bfd_copy_private_header_data (ibfd, obfd))
+ {
+ err = _("private header data");
+ goto loser;
+ }
+
+ /* All went well. */
+ return;
+
+loser:
+ non_fatal (_("%s: error in %s: %s"),
+ bfd_get_filename (ibfd),
+ err, bfd_errmsg (bfd_get_error ()));
+ status = 1;
+}
+
/* Create a section in OBFD with the same
name and attributes as ISECTION in IBFD. */
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");
return;
osection = isection->output_section;
- size = bfd_get_section_size_before_reloc (isection);
+ size = bfd_get_section_size (isection);
if (size == 0 || osection == 0)
return;
}
bfd_set_reloc (obfd, osection, relcount == 0 ? NULL : relpp, relcount);
+ if (relcount == 0)
+ free (relpp);
}
- isection->_cooked_size = isection->_raw_size;
- isection->reloc_done = TRUE;
-
if (bfd_get_section_flags (ibfd, isection) & SEC_HAS_CONTENTS
&& bfd_get_section_flags (obfd, osection) & SEC_HAS_CONTENTS)
{
if (copy_byte >= 0)
{
/* Keep only every `copy_byte'th byte in MEMHUNK. */
- char *from = memhunk + copy_byte;
+ char *from = (char *) memhunk + copy_byte;
char *to = memhunk;
- char *end = memhunk + size;
+ char *end = (char *) memhunk + size;
for (; from < end; from += interleave)
*to++ = *from;
return -1;
/* Sort sections with the same LMA by size. */
- if ((*sec1)->_raw_size > (*sec2)->_raw_size)
+ if (bfd_get_section_size (*sec1) > bfd_get_section_size (*sec2))
return 1;
- else if ((*sec1)->_raw_size < (*sec2)->_raw_size)
+ else if (bfd_get_section_size (*sec1) < bfd_get_section_size (*sec2))
return -1;
return 0;
add_specific_symbol (optarg, &strip_specific_list);
break;
+ case OPTION_STRIP_UNNEEDED_SYMBOL:
+ add_specific_symbol (optarg, &strip_unneeded_list);
+ break;
+
case 'L':
add_specific_symbol (optarg, &localize_specific_list);
break;
add_specific_symbols (optarg, &strip_specific_list);
break;
+ case OPTION_STRIP_UNNEEDED_SYMBOLS:
+ add_specific_symbols (optarg, &strip_unneeded_list);
+ break;
+
case OPTION_KEEP_SYMBOLS:
add_specific_symbols (optarg, &keep_specific_list);
break;