aboutsummaryrefslogtreecommitdiff
path: root/binutils/strip.c
diff options
context:
space:
mode:
Diffstat (limited to 'binutils/strip.c')
-rwxr-xr-xbinutils/strip.c364
1 files changed, 364 insertions, 0 deletions
diff --git a/binutils/strip.c b/binutils/strip.c
new file mode 100755
index 0000000..cd0f3af
--- /dev/null
+++ b/binutils/strip.c
@@ -0,0 +1,364 @@
+/*** strip.c -- strip certain symbols from a rel file.
+ Copyright (C) 1986, 1990 Free Software Foundation, Inc.
+
+ 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* BUGS: When there's not enough memory, this should do the copy
+ in pieces rather than just fail as it does now */
+
+#include "sysdep.h"
+#include "bfd.h"
+
+#include "getopt.h"
+
+
+
+#include <signal.h>
+
+/* Various program options */
+
+int show_version = 0;
+
+/* Which symbols to remove. */
+enum strip_action {
+ strip_undef,
+ strip_all, /* strip all symbols */
+ strip_debug, /* strip all debugger symbols */
+} strip_symbols;
+
+/* Which local symbols to remove. */
+enum {
+ locals_undef,
+ locals_start_L, /* discard locals starting with L */
+ locals_all, /* discard all locals */
+} discard_locals;
+
+extern char *mktemp();
+
+/* IMPORTS */
+extern char *program_version;
+extern char *program_name;
+extern char *target;
+extern char *xmalloc();
+
+PROTO(static boolean, strip_file, (char *filetostrip));
+PROTO(static void, copy_sections, (bfd *ibfd, sec_ptr isection, bfd *obfd));
+PROTO(static void, setup_sections, (bfd *ibfd, sec_ptr isection, bfd *obfd));
+
+/** main, etc */
+
+static void
+usage ()
+{
+ fprintf (stderr, "strip %s\nUsage: %s [-gsxSX] files ...\n",
+ program_version, program_name);
+ exit (1);
+}
+
+struct option long_options[] = {{"strip-all", 0, 0, 's'},
+ {"strip-debug", 0, 0, 'S'},
+ {"discard-all", 0, 0, 'x'},
+ {"discard-locals", 0, 0, 'X'},
+ {0, 0, 0, 0}
+ };
+
+int
+main (argc, argv)
+ char **argv;
+ int argc;
+{
+ int ind;
+ int c;
+ program_name = argv[0];
+
+ strip_symbols = strip_undef; /* default is to strip everything. */
+ discard_locals = locals_undef;
+
+ while ((c = getopt_long (argc, argv, "gsST:xX", long_options, &ind)) != EOF) {
+ switch (c) {
+ case 0:
+ break;
+ case 's':
+ strip_symbols = strip_all;
+ break;
+ case 'g':
+ case 'S':
+ strip_symbols = strip_debug;
+ break;
+ case 'T':
+ target = optarg;
+ break;
+ case 'x':
+ discard_locals = locals_all;
+ break;
+ case 'X':
+ discard_locals = locals_start_L;
+ break;
+ default:
+ usage ();
+ }
+ }
+
+ /* Default is to strip all symbols: */
+ if (strip_symbols == strip_undef && discard_locals == locals_undef) {
+ strip_symbols = strip_all;
+ }
+
+ /* OK, all options now parsed. If no filename specified, do a.out. */
+ if (optind == argc) return !strip_file ("a.out");
+
+ /* We were given several filenames to do: */
+ while (optind < argc)
+ if (!strip_file (argv[optind++])) return 1;
+
+ return 0;
+}
+
+/** Hack signals */
+
+/* Why does strip need to do this, and anyway, if it does shouldn't this be
+ handled by bfd? */
+
+static int delayed_signal;
+
+static int sigint_handled = 0;
+static int sighup_handled = 0;
+static int sigterm_handled = 0;
+
+void
+delay_signal (signo)
+ int signo;
+{
+ delayed_signal = signo;
+ signal (signo, delay_signal);
+}
+
+/* Effectively defer handling of asynchronous kill signals. */
+void
+handle_sigs () /* puff puff */
+{
+ delayed_signal = 0;
+
+ if (signal (SIGINT, SIG_IGN) != SIG_IGN) {
+ sigint_handled = 1;
+ signal (SIGINT, delay_signal);
+ }
+
+ if (signal (SIGHUP, SIG_IGN) != SIG_IGN) {
+ sighup_handled = 1;
+ signal (SIGHUP, delay_signal);
+ }
+
+ if (signal (SIGTERM, SIG_IGN) != SIG_IGN) {
+ sigterm_handled = 1;
+ signal (SIGTERM, delay_signal);
+ }
+
+ return;
+}
+
+/* Effectively undefer handling. */
+void
+unhandle_sigs () /* put them down */
+{
+ if (sigint_handled) signal (SIGINT, SIG_DFL);
+
+ if (sighup_handled) signal (SIGHUP, SIG_DFL);
+
+ if (sigterm_handled) signal (SIGTERM, SIG_DFL);
+
+ /* Handle any signal that came in while they were deferred. */
+ if (delayed_signal)
+ kill (getpid (), delayed_signal);
+
+ return;
+}
+
+
+static boolean
+strip_file (filetostrip)
+ char *filetostrip;
+{
+ static char template[] = "stXXXXXX";
+ char *slash;
+ char *tmpname;
+ bfd *ibfd;
+ bfd *obfd;
+
+ ibfd = bfd_openr (filetostrip, target);
+
+ if (ibfd == NULL) bfd_fatal (filetostrip);
+
+ handle_sigs (); /* light up */
+
+ if (!bfd_check_format (ibfd, bfd_object)) {
+ fprintf (stderr, "Can't strip %s file %s.\n",
+ bfd_format_string (bfd_get_format (ibfd)), filetostrip);
+ exit (1);
+ }
+
+ slash = strrchr( filetostrip, '/' );
+ if ( slash ){
+ *slash = 0;
+ tmpname = xmalloc( strlen(filetostrip) + sizeof(template) + 1 );
+ strcpy( tmpname, filetostrip );
+ strcat( tmpname, "/" );
+ strcat( tmpname, template );
+ mktemp( tmpname );
+ *slash = '/';
+ } else {
+ tmpname = xmalloc( sizeof(template) );
+ strcpy( tmpname, template );
+ mktemp( tmpname );
+ }
+
+ obfd = bfd_openw (mktemp(tmpname), (target ? target : bfd_get_target (ibfd)));
+ if (obfd == NULL) bfd_fatal (tmpname);
+
+ if (!bfd_set_format (obfd, bfd_get_format (ibfd)))
+ bfd_fatal (tmpname);
+
+
+ if ((bfd_set_start_address (obfd, bfd_get_start_address (ibfd)) == false) ||
+ (bfd_set_file_flags (obfd, (bfd_get_file_flags (ibfd) &
+ ~(HAS_LINENO | HAS_DEBUG | HAS_SYMS |
+ HAS_LOCALS))) == false) ||
+ bfd_set_start_address (obfd, bfd_get_start_address (ibfd)) == false)
+ bfd_fatal (bfd_get_filename (ibfd));
+
+ /* Copy architecture of input file to output file */
+ if (!bfd_set_arch_mach (obfd, bfd_get_architecture (ibfd),
+ bfd_get_machine (ibfd))) {
+ fprintf(stderr, "Output file cannot represent architecture %s",
+ bfd_printable_arch_mach (bfd_get_architecture(ibfd),
+ bfd_get_machine (ibfd)));
+ }
+
+
+ /* bfd mandates that all output sections be created and sizes set before
+ any output is done. Thus, we traverse all sections twice. */
+ bfd_map_over_sections (ibfd, setup_sections, (void *)obfd);
+ bfd_map_over_sections (ibfd, copy_sections, (void *)obfd);
+
+ if (!bfd_close (obfd)) bfd_fatal (filetostrip);
+ if (!bfd_close (ibfd)) bfd_fatal (filetostrip);
+
+ rename(tmpname, filetostrip);
+ free(tmpname);
+
+ unhandle_sigs();
+
+ return true;
+}
+
+/** Actually do the work */
+static void
+setup_sections (ibfd, isection, obfd)
+ bfd *ibfd;
+ sec_ptr isection;
+ bfd *obfd;
+{
+ sec_ptr osection;
+ char *err;
+
+ osection = bfd_make_section (obfd, bfd_section_name (ibfd, isection));
+ if (osection == NULL) {
+ err = "making";
+ goto loser;
+ }
+
+ if (!bfd_set_section_size(obfd, osection, bfd_section_size(ibfd, isection))) {
+ err = "size";
+ goto loser;
+ }
+
+ if (!bfd_set_section_vma (obfd, osection, bfd_section_vma (ibfd, isection))) {
+ err = "vma";
+ goto loser;
+ }
+
+ if (bfd_set_section_alignment (obfd, osection,
+ bfd_section_alignment (ibfd, isection))
+ != true) {
+ err = "alignment";
+ goto loser;
+ } /* on error, I presume. */
+
+ if (!bfd_set_section_flags (obfd, osection,
+ bfd_get_section_flags (ibfd, isection))) {
+ err = "flags";
+ goto loser;
+ }
+
+ /* All went well */
+ return;
+
+ loser:
+ fprintf (stderr, "%s: file \"%s\", section \"%s\": error in %s: %s\n",
+ program_name,
+ bfd_get_filename (ibfd), bfd_section_name (ibfd, isection),
+ err, bfd_errmsg (bfd_error));
+ exit (1);
+}
+
+static void
+copy_sections (ibfd, isection, obfd)
+ bfd *ibfd;
+ sec_ptr isection;
+ bfd *obfd;
+{
+ static unsigned char *memhunk = NULL;
+ static unsigned memhunksize = 0;
+
+ sec_ptr osection;
+ unsigned long size;
+ flagword iflg;
+ unsigned char *temp;
+
+ osection = bfd_get_section_by_name (obfd, bfd_section_name (ibfd, isection));
+
+ size = bfd_section_size (ibfd, isection);
+ iflg = bfd_get_section_flags (ibfd, isection);
+
+ /* either:
+ we don't need any memory because there's nothing in this section,
+ we had no memory so we got some,
+ we had some memory but not enough so we got more,
+ or we fail to allocat. */
+
+ if (size == 0)
+ return;
+
+ if ((iflg & SEC_HAS_CONTENTS) == 0)
+ return;
+
+ if (memhunk == NULL) {
+ memhunk = (unsigned char *) xmalloc (size);
+ memhunksize = size;
+ }
+
+ if (size > memhunksize) {
+ temp = (unsigned char *) xrealloc ((char *) memhunk, size);
+ memhunksize = size;
+ memhunk = temp;
+ }
+
+ /* now we have enough memory, just do it: */
+ if (!bfd_get_section_contents (ibfd, isection, memhunk, 0, size))
+ bfd_fatal (bfd_get_filename (ibfd));
+
+ if (!bfd_set_section_contents (obfd, osection, memhunk, 0, size))
+ bfd_fatal (bfd_get_filename (obfd));
+}