static const char *lookup_sym_redefinition PARAMS((const char *)); static void redefine_list_append PARAMS ((const char *, const char *));  #define RETURN_NONFATAL(s) {bfd_nonfatal (s); status = 1; return;}  static asymbol **isympp = NULL;	 static asymbol **osympp = NULL;	   static int copy_byte = -1; static int interleave = 4;  static boolean verbose;		 static boolean preserve_dates;	 static int status = 0;		  enum strip_action { STRIP_UNDEF, STRIP_NONE,			 STRIP_DEBUG,		 STRIP_UNNEEDED,		 STRIP_ALL			 };   static enum strip_action strip_symbols;  enum locals_action { LOCALS_UNDEF, LOCALS_START_L,		 LOCALS_ALL			 };   static enum locals_action discard_locals;   enum change_action { CHANGE_IGNORE, CHANGE_MODIFY, CHANGE_SET };   struct section_list { struct section_list * next;       const char *          name;       boolean               used;       boolean               remove;     boolean		copy;       enum change_action    change_vma; bfd_vma 		vma_val;    enum change_action    change_lma; bfd_vma 		lma_val;    boolean 		set_flags;  flagword 		flags;      };  static struct section_list *change_sections; static boolean sections_removed; static boolean sections_copied;   static bfd_vma change_start = 0; static boolean set_start_set = false; static bfd_vma set_start;   static bfd_vma change_section_address = 0;   static boolean gap_fill_set = false; static bfd_byte gap_fill = 0;   static boolean pad_to_set = false; static bfd_vma pad_to;    struct section_add {  struct section_add *next;  const char *name;  const char *filename;  size_t size;  bfd_byte *contents;  asection *section; };  static struct section_add *add_sections;    static boolean convert_debugging = false;    static boolean change_leading_char = false;    static boolean remove_leading_char = false;    static struct symlist *strip_specific_list = NULL; static struct symlist *keep_specific_list = NULL; static struct symlist *localize_specific_list = NULL; static struct symlist *keepglobal_specific_list = NULL; static struct symlist *weaken_specific_list = NULL; static struct redefine_node *redefine_sym_list = NULL;    static boolean weaken = false;    #define OPTION_ADD_SECTION 150 #define OPTION_CHANGE_ADDRESSES (OPTION_ADD_SECTION + 1) #define OPTION_CHANGE_LEADING_CHAR (OPTION_CHANGE_ADDRESSES + 1) #define OPTION_CHANGE_START (OPTION_CHANGE_LEADING_CHAR + 1) #define OPTION_CHANGE_SECTION_ADDRESS (OPTION_CHANGE_START + 1) #define OPTION_CHANGE_SECTION_LMA (OPTION_CHANGE_SECTION_ADDRESS + 1) #define OPTION_CHANGE_SECTION_VMA (OPTION_CHANGE_SECTION_LMA + 1) #define OPTION_CHANGE_WARNINGS (OPTION_CHANGE_SECTION_VMA + 1) #define OPTION_DEBUGGING (OPTION_CHANGE_WARNINGS + 1) #define OPTION_GAP_FILL (OPTION_DEBUGGING + 1) #define OPTION_NO_CHANGE_WARNINGS (OPTION_GAP_FILL + 1) #define OPTION_PAD_TO (OPTION_NO_CHANGE_WARNINGS + 1) #define OPTION_REMOVE_LEADING_CHAR (OPTION_PAD_TO + 1) #define OPTION_SET_SECTION_FLAGS (OPTION_REMOVE_LEADING_CHAR + 1) #define OPTION_SET_START (OPTION_SET_SECTION_FLAGS + 1) #define OPTION_STRIP_UNNEEDED (OPTION_SET_START + 1) #define OPTION_WEAKEN (OPTION_STRIP_UNNEEDED + 1) #define OPTION_REDEFINE_SYM (OPTION_WEAKEN + 1) #define OPTION_SREC_LEN (OPTION_REDEFINE_SYM + 1) #define OPTION_SREC_FORCES3 (OPTION_SREC_LEN + 1) #define OPTION_STRIP_SYMBOLS (OPTION_SREC_FORCES3 + 1) #define OPTION_KEEP_SYMBOLS (OPTION_STRIP_SYMBOLS + 1) #define OPTION_LOCALIZE_SYMBOLS (OPTION_KEEP_SYMBOLS + 1) #define OPTION_KEEPGLOBAL_SYMBOLS (OPTION_LOCALIZE_SYMBOLS + 1) #define OPTION_WEAKEN_SYMBOLS (OPTION_KEEPGLOBAL_SYMBOLS + 1)    static struct option strip_options[] = { {"discard-all", no_argument, 0, 'x'}, {"discard-locals", no_argument, 0, 'X'}, {"format", required_argument, 0, 'F'},  {"help", no_argument, 0, 'h'}, {"input-format", required_argument, 0, 'I'},  {"input-target", required_argument, 0, 'I'}, {"keep-symbol", required_argument, 0, 'K'}, {"output-format", required_argument, 0, 'O'},	 {"output-target", required_argument, 0, 'O'}, {"preserve-dates", no_argument, 0, 'p'}, {"remove-section", required_argument, 0, 'R'}, {"strip-all", no_argument, 0, 's'}, {"strip-debug", no_argument, 0, 'S'}, {"strip-unneeded", no_argument, 0, OPTION_STRIP_UNNEEDED}, {"strip-symbol", required_argument, 0, 'N'}, {"target", required_argument, 0, 'F'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, no_argument, 0, 0} };    static struct option copy_options[] = { {"add-section", required_argument, 0, OPTION_ADD_SECTION}, {"adjust-start", required_argument, 0, OPTION_CHANGE_START}, {"adjust-vma", required_argument, 0, OPTION_CHANGE_ADDRESSES}, {"adjust-section-vma", required_argument, 0, OPTION_CHANGE_SECTION_ADDRESS}, {"adjust-warnings", no_argument, 0, OPTION_CHANGE_WARNINGS}, {"byte", required_argument, 0, 'b'}, {"change-addresses", required_argument, 0, OPTION_CHANGE_ADDRESSES}, {"change-leading-char", no_argument, 0, OPTION_CHANGE_LEADING_CHAR}, {"change-section-address", required_argument, 0, OPTION_CHANGE_SECTION_ADDRESS}, {"change-section-lma", required_argument, 0, OPTION_CHANGE_SECTION_LMA}, {"change-section-vma", required_argument, 0, OPTION_CHANGE_SECTION_VMA}, {"change-start", required_argument, 0, OPTION_CHANGE_START}, {"change-warnings", no_argument, 0, OPTION_CHANGE_WARNINGS}, {"debugging", no_argument, 0, OPTION_DEBUGGING}, {"discard-all", no_argument, 0, 'x'}, {"discard-locals", no_argument, 0, 'X'}, {"only-section", required_argument, 0, 'j'}, {"format", required_argument, 0, 'F'},  {"gap-fill", required_argument, 0, OPTION_GAP_FILL}, {"help", no_argument, 0, 'h'}, {"input-format", required_argument, 0, 'I'},  {"input-target", required_argument, 0, 'I'}, {"interleave", required_argument, 0, 'i'}, {"keep-symbol", required_argument, 0, 'K'}, {"no-adjust-warnings", no_argument, 0, OPTION_NO_CHANGE_WARNINGS}, {"no-change-warnings", no_argument, 0, OPTION_NO_CHANGE_WARNINGS}, {"output-format", required_argument, 0, 'O'},	 {"output-target", required_argument, 0, 'O'}, {"pad-to", required_argument, 0, OPTION_PAD_TO}, {"preserve-dates", no_argument, 0, 'p'}, {"localize-symbol", required_argument, 0, 'L'}, {"keep-global-symbol", required_argument, 0, 'G'}, {"remove-leading-char", no_argument, 0, OPTION_REMOVE_LEADING_CHAR}, {"remove-section", required_argument, 0, 'R'}, {"set-section-flags", required_argument, 0, OPTION_SET_SECTION_FLAGS}, {"set-start", required_argument, 0, OPTION_SET_START}, {"strip-all", no_argument, 0, 'S'}, {"strip-debug", no_argument, 0, 'g'}, {"strip-unneeded", no_argument, 0, OPTION_STRIP_UNNEEDED}, {"strip-symbol", required_argument, 0, 'N'}, {"target", required_argument, 0, 'F'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {"weaken", no_argument, 0, OPTION_WEAKEN}, {"weaken-symbol", required_argument, 0, 'W'}, {"redefine-sym", required_argument, 0, OPTION_REDEFINE_SYM}, {"srec-len", required_argument, 0, OPTION_SREC_LEN}, {"srec-forceS3", no_argument, 0, OPTION_SREC_FORCES3}, {"keep-symbols", required_argument, 0, OPTION_KEEP_SYMBOLS}, {"strip-symbols", required_argument, 0, OPTION_STRIP_SYMBOLS}, {"keep-global-symbols", required_argument, 0, OPTION_KEEPGLOBAL_SYMBOLS}, {"localize-symbols", required_argument, 0, OPTION_LOCALIZE_SYMBOLS}, {"weaken-symbols", required_argument, 0, OPTION_WEAKEN_SYMBOLS}, {0, no_argument, 0, 0} };   extern char *program_name;   extern int is_strip;   extern unsigned int Chunk;   extern boolean S3Forced;  static void copy_usage (stream, exit_status) FILE *stream; int exit_status; { fprintf (stream, _("Usage: %s <switches> in-file [out-file]\n"), program_name); fprintf (stream, _(" The switches are:\n")); fprintf (stream, _("\ -I --input-target <bfdname>      Assume input file is in format <bfdname>\n\ -O --output-target <bfdname>     Create an output file in format <bfdname>\n\ -F --target <bfdname>            Set both input and output format to <bfdname>\n\ --debugging                   Convert debugging information, if possible\n\ -p --preserve-dates              Copy modified/access timestamps to the output\n\ -j --only-section <name>         Only copy section <name> into the output\n\ -R --remove-section <name>       Remove section <name> from the output\n\ -S --strip-all                   Remove all symbol and relocation information\n\ -g --strip-debug                 Remove all debugging symbols\n\ --strip-unneeded              Remove all symbols not needed by relocations\n\ -N --strip-symbol <name>         Do not copy symbol <name>\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\ -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\ -b --byte <num>                  Select byte <num> in every interleaved block\n\ --gap-fill <val>              Fill gaps between sections with <val>\n\ --pad-to <addr>               Pad the last section up to address <addr>\n\ --set-start <addr>            Set the start address to <addr>\n\ {--change-start|--adjust-start} <incr>\n\ Add <incr> to the start address\n\ {--change-addresses|--adjust-vma} <incr>\n\ Add <incr> to LMA, VMA and start addresses\n\ {--change-section-address|--adjust-section-vma} <name>{=|+|-}<val>\n\ Change LMA and VMA of section <name> by <val>\n\ --change-section-lma <name>{=|+|-}<val>\n\ Change the LMA of section <name> by <val>\n\ --change-section-vma <name>{=|+|-}<val>\n\ Change the VMA of section <name> by <val>\n\ {--[no-]change-warnings|--[no-]adjust-warnings}\n\ Warn if a named section does not exist\n\ --set-section-flags <name>=<flags>\n\ Set section <name>'s properties to <flags>\n\ --add-section <name>=<file>   Add section <name> found in <file> to output\n\ --change-leading-char         Force output format's leading character style\n\ --remove-leading-char         Remove leading character from global symbols\n\ --redefine-sym <old>=<new>    Redefine symbol name <old> to <new>\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\ --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\ --weaken-symbols <file>       -W for all symbols listed in <file>\n\ -v --verbose                     List all object files modified\n\ -V --version                     Display this program's version number\n\ -h --help                        Display this output\n\ ")); list_supported_targets (program_name, stream); if (exit_status == 0) fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO); exit (exit_status); }  static void strip_usage (stream, exit_status) FILE *stream; int exit_status; { fprintf (stream, _("Usage: %s <switches> in-file(s)\n"), program_name); fprintf (stream, _(" The switches are:\n")); fprintf (stream, _("\ -I --input-target <bfdname>      Assume input file is in format <bfdname>\n\ -O --output-target <bfdname>     Create an output file in format <bfdname>\n\ -F --target <bfdname>            Set both input and output format to <bfdname>\n\ -p --preserve-dates              Copy modified/access timestamps to the output\n\ -R --remove-section <name>       Remove section <name> from the output\n\ -s --strip-all                   Remove all symbol and relocation information\n\ -g -S --strip-debug              Remove all debugging symbols\n\ --strip-unneeded              Remove all symbols not needed by relocations\n\ -N --strip-symbol <name>         Do not copy symbol <name>\n\ -K --keep-symbol <name>          Only copy symbol <name>\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\ -V --version                     Display this program's version number\n\ -h --help                        Display this output\n\ -o <file>                        Place stripped output into <file>\n\ "));  list_supported_targets (program_name, stream); if (exit_status == 0) fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO); exit (exit_status); }    static flagword parse_flags (s) const char *s; { flagword ret; const char *snext; int len;  ret = SEC_NO_FLAGS;  do { snext = strchr (s, ','); if (snext == NULL) len = strlen (s); else { len = snext - s; ++snext; }  if (0) ; #define PARSE_FLAG(fname,fval) \ else if (strncasecmp (fname, s, len) == 0) ret |= fval PARSE_FLAG ("alloc", SEC_ALLOC); PARSE_FLAG ("load", SEC_LOAD); PARSE_FLAG ("noload", SEC_NEVER_LOAD); PARSE_FLAG ("readonly", SEC_READONLY); PARSE_FLAG ("debug", SEC_DEBUGGING); PARSE_FLAG ("code", SEC_CODE); PARSE_FLAG ("data", SEC_DATA); PARSE_FLAG ("rom", SEC_ROM); PARSE_FLAG ("share", SEC_SHARED); PARSE_FLAG ("contents", SEC_HAS_CONTENTS); #undef PARSE_FLAG else { char *copy;  copy = xmalloc (len + 1); strncpy (copy, s, len); copy[len] = '\0'; non_fatal (_("unrecognized section flag `%s'"), copy); fatal (_("supported flags: %s"), "alloc, load, noload, readonly, debug, code, data, rom, share, contents"); }  s = snext; } while (s != NULL);  return ret; }    static struct section_list * find_section_list (name, add) const char *name; boolean add; { register struct section_list *p;  for (p = change_sections; p != NULL; p = p->next) if (strcmp (p->name, name) == 0) return p;  if (! add) return NULL;  p = (struct section_list *) xmalloc (sizeof (struct section_list)); p->name = name; p->used = false; p->remove = false; p->copy = false; p->change_vma = CHANGE_IGNORE; p->change_lma = CHANGE_IGNORE; p->vma_val = 0; p->lma_val = 0; p->set_flags = false; p->flags = 0;  p->next = change_sections; change_sections = p;  return p; }    static void add_specific_symbol (name, list) const char *name; struct symlist **list; { struct symlist *tmp_list;  tmp_list = (struct symlist *) xmalloc (sizeof (struct symlist)); tmp_list->name = name; tmp_list->next = *list; *list = tmp_list; }    #define IS_WHITESPACE(c)      ((c) == ' ' || (c) == '\t') #define IS_LINE_TERMINATOR(c) ((c) == '\n' || (c) == '\r' || (c) == '\0')  static void add_specific_symbols (filename, list) const char *filename; struct symlist **list; { struct stat st; 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) return;  buffer = (char *) xmalloc (st.st_size + 2); f = fopen (filename, FOPEN_RT); if (f == NULL) fatal (_("cannot open: %s: %s"), filename, strerror (errno));  if (fread (buffer, 1, st.st_size, f) == 0 || ferror (f)) fatal (_("%s: fread failed"), filename);  fclose (f); buffer [st.st_size] = '\n'; buffer [st.st_size + 1] = '\0';  line_count = 1;  for (line = buffer; * line != '\0'; line ++) { char * eol; char * name; char * name_end; int finished = false;  for (eol = line;; eol ++) { switch (* eol) { case '\n': * eol = '\0';  if (eol[1] == '\r') ++ eol; finished = true; break;  case '\r': * eol = '\0';  if (eol[1] == '\n') ++ eol; finished = true; break;  case 0: finished = true; break;  case '#':  * eol = '\0'; break;  default: break; }  if (finished) break; }   for (name = line; IS_WHITESPACE (* name); name ++) ; for (name_end = name; (! IS_WHITESPACE (* name_end)) && (! IS_LINE_TERMINATOR (* name_end)); name_end ++) ;  if (! IS_LINE_TERMINATOR (* name_end)) { char * extra;  for (extra = name_end + 1; IS_WHITESPACE (* extra); extra ++) ;  if (! IS_LINE_TERMINATOR (* extra)) non_fatal (_("Ignoring rubbish found on line %d of %s"), line_count, filename); }  * name_end = '\0';  if (name_end > name) add_specific_symbol (name, list);   line = eol; line_count ++; } }    static boolean is_specified_symbol (name, list) const char *name; struct symlist *list; { struct symlist *tmp_list;  for (tmp_list = list; tmp_list; tmp_list = tmp_list->next) { if (strcmp (name, tmp_list->name) == 0) return true; } return false; }    static boolean is_strip_section (abfd, sec) bfd *abfd ATTRIBUTE_UNUSED; asection *sec; { struct section_list *p;  if ((bfd_get_section_flags (abfd, sec) & SEC_DEBUGGING) != 0 && (strip_symbols == STRIP_DEBUG || strip_symbols == STRIP_UNNEEDED || strip_symbols == STRIP_ALL || discard_locals == LOCALS_ALL || convert_debugging)) return true;  if (! sections_removed && ! sections_copied) return false;  p = find_section_list (bfd_get_section_name (abfd, sec), false); if (sections_removed && p != NULL && p->remove) return true; if (sections_copied && (p == NULL || ! p->copy)) return true; return false; }    static unsigned int filter_symbols (abfd, obfd, osyms, isyms, symcount) bfd *abfd; bfd *obfd; asymbol **osyms, **isyms; long symcount; { register asymbol **from = isyms, **to = osyms; long src_count = 0, dst_count = 0; int relocatable = (abfd->flags & (HAS_RELOC | EXEC_P | DYNAMIC)) == HAS_RELOC;  for (; src_count < symcount; src_count++) { asymbol *sym = from[src_count]; flagword flags = sym->flags; const char *name = bfd_asymbol_name (sym); int keep;  if (redefine_sym_list) { const char *old_name, *new_name;  old_name = bfd_asymbol_name (sym); new_name = lookup_sym_redefinition (old_name); name = bfd_asymbol_name (sym) = new_name; }  if (change_leading_char && (bfd_get_symbol_leading_char (abfd) != bfd_get_symbol_leading_char (obfd)) && (bfd_get_symbol_leading_char (abfd) == '\0' || (name[0] == bfd_get_symbol_leading_char (abfd)))) { if (bfd_get_symbol_leading_char (obfd) == '\0') name = bfd_asymbol_name (sym) = name + 1; else { char *n;  n = xmalloc (strlen (name) + 2); n[0] = bfd_get_symbol_leading_char (obfd); if (bfd_get_symbol_leading_char (abfd) == '\0') strcpy (n + 1, name); else strcpy (n + 1, name + 1); name = bfd_asymbol_name (sym) = n; } }  if (remove_leading_char && ((flags & BSF_GLOBAL) != 0 || (flags & BSF_WEAK) != 0 || bfd_is_und_section (bfd_get_section (sym)) || bfd_is_com_section (bfd_get_section (sym))) && name[0] == bfd_get_symbol_leading_char (abfd)) name = bfd_asymbol_name (sym) = name + 1;  if (strip_symbols == STRIP_ALL) keep = 0; else if ((flags & BSF_KEEP) != 0		 || ((flags & BSF_SECTION_SYM) != 0 && ((*bfd_get_section (sym)->symbol_ptr_ptr)->flags & BSF_KEEP) != 0)) keep = 1; else if (relocatable			 && (flags & (BSF_GLOBAL | BSF_WEAK)) != 0) keep = 1; else if (bfd_decode_symclass (sym) == 'I')  keep = 1; else if ((flags & BSF_GLOBAL) != 0	 || (flags & BSF_WEAK) != 0 || bfd_is_und_section (bfd_get_section (sym)) || bfd_is_com_section (bfd_get_section (sym))) keep = strip_symbols != STRIP_UNNEEDED; else if ((flags & BSF_DEBUGGING) != 0)	 keep = (strip_symbols != STRIP_DEBUG && strip_symbols != STRIP_UNNEEDED && ! convert_debugging); else			 keep = (strip_symbols != STRIP_UNNEEDED && (discard_locals != LOCALS_ALL && (discard_locals != LOCALS_START_L || ! bfd_is_local_label (abfd, sym))));  if (keep && is_specified_symbol (name, strip_specific_list)) keep = 0; if (!keep && is_specified_symbol (name, keep_specific_list)) keep = 1; if (keep && is_strip_section (abfd, bfd_get_section (sym))) keep = 0;  if (keep && (flags & BSF_GLOBAL) != 0 && (weaken || is_specified_symbol (name, weaken_specific_list))) { sym->flags &=~ BSF_GLOBAL; sym->flags |= BSF_WEAK; } if (keep && (flags & (BSF_GLOBAL | BSF_WEAK)) && (is_specified_symbol (name, localize_specific_list) || (keepglobal_specific_list != NULL && ! is_specified_symbol (name, keepglobal_specific_list)))) { sym->flags &= ~(BSF_GLOBAL | BSF_WEAK); sym->flags |= BSF_LOCAL; }  if (keep) to[dst_count++] = sym; }  to[dst_count] = NULL;  return dst_count; }  static const char *
lookup_sym_redefinition (source)     const char *source;{  const char *result;  struct redefine_node *list;  result = source;  for (list = redefine_sym_list; list != NULL; list = list->next)    {      if (strcmp (source, list->source) == 0)	{	  result = list->target;	  break;	}    }  return result;}