Beispiel #1
0
bfd_boolean
ar_emul_default_create (bfd **abfd_out, char *archive_file_name,
			char *file_name)
{
  char *target = NULL;

  /* Try to figure out the target to use for the archive from the
     first object on the list.  */
  if (file_name != NULL)
    {
      bfd *obj;

      obj = bfd_openr (file_name, NULL);
      if (obj != NULL)
	{
	  if (bfd_check_format (obj, bfd_object))
	    target = bfd_get_target (obj);
	  (void) bfd_close (obj);
	}
    }

  /* Create an empty archive.  */
  *abfd_out = bfd_openw (archive_file_name, target);
  if (*abfd_out == NULL
      || ! bfd_set_format (*abfd_out, bfd_archive)
      || ! bfd_close (*abfd_out))
    bfd_fatal (archive_file_name);

  return TRUE;
}
Beispiel #2
0
static bfd *
bfd_openw_with_cleanup(const char *filename, const char *target,
                       const char *mode)
{
  bfd *obfd;

  if (*mode == 'w')	/* Write: create new file */
    {
      obfd = bfd_openw(filename, target);
      if (obfd == NULL)
	error(_("Failed to open %s: %s."), filename,
	      bfd_errmsg(bfd_get_error()));
      make_cleanup_bfd_close(obfd);
      if (!bfd_set_format(obfd, bfd_object))
	error(_("bfd_openw_with_cleanup: %s."), bfd_errmsg(bfd_get_error()));
    }
  else if (*mode == 'a')	/* Append to existing file */
    {	/* FIXME: does NOT work... */
      error(_("bfd_openw does not work with append."));
    }
  else
    error(_("bfd_openw_with_cleanup: unknown mode %s."), mode);

  return obfd;
}
Beispiel #3
0
bfd *
create_gcore_bfd (char *filename)
{
  bfd *obfd = gdb_bfd_openw (filename, default_gcore_target ());

  if (!obfd)
    error (_("Failed to open '%s' for output."), filename);
  bfd_set_format (obfd, bfd_core);
  bfd_set_arch_mach (obfd, default_gcore_arch (), default_gcore_mach ());
  return obfd;
}
Beispiel #4
0
void
output_file_create (char *name)
{
  if (name[0] == '-' && name[1] == '\0')
    as_fatal (_("can't open a bfd on stdout %s"), name);

  else if (!(stdoutput = bfd_openw (name, TARGET_FORMAT)))
    {
      bfd_error_type err = bfd_get_error ();

      if (err == bfd_error_invalid_target)
	as_fatal (_("selected target format '%s' unknown"), TARGET_FORMAT);
      else
	as_fatal (_("can't create %s: %s"), name, bfd_errmsg (err));
    }

  bfd_set_format (stdoutput, bfd_object);
  bfd_set_arch_mach (stdoutput, TARGET_ARCH, TARGET_MACH);
  if (flag_traditional_format)
    stdoutput->flags |= BFD_TRADITIONAL_FORMAT;
}
Beispiel #5
0
static void
gcore_command (char *args, int from_tty)
{
  struct cleanup *old_chain;
  char *corefilename, corefilename_buffer[40];
  asection *note_sec = NULL;
  bfd *obfd;
  void *note_data = NULL;
  int note_size = 0;

  /* No use generating a corefile without a target process.  */
  if (!target_has_execution)
    noprocess ();

  if (args && *args)
    corefilename = args;
  else
    {
      /* Default corefile name is "core.PID".  */
      sprintf (corefilename_buffer, "core.%d", PIDGET (inferior_ptid));
      corefilename = corefilename_buffer;
    }

  if (info_verbose)
    fprintf_filtered (gdb_stdout,
		      "Opening corefile '%s' for output.\n", corefilename);

  /* Open the output file.  */
  obfd = bfd_openw (corefilename, default_gcore_target ());
  if (!obfd)
    error (_("Failed to open '%s' for output."), corefilename);

  /* Need a cleanup that will close the file (FIXME: delete it?).  */
  old_chain = make_cleanup_bfd_close (obfd);

  bfd_set_format (obfd, bfd_core);
  bfd_set_arch_mach (obfd, default_gcore_arch (), default_gcore_mach ());

  /* An external target method must build the notes section.  */
  note_data = target_make_corefile_notes (obfd, &note_size);

  /* Create the note section.  */
  if (note_data != NULL && note_size != 0)
    {
      note_sec = bfd_make_section_anyway_with_flags (obfd, "note0",
						     SEC_HAS_CONTENTS
						     | SEC_READONLY
						     | SEC_ALLOC);
      if (note_sec == NULL)
	error (_("Failed to create 'note' section for corefile: %s"),
	       bfd_errmsg (bfd_get_error ()));

      bfd_set_section_vma (obfd, note_sec, 0);
      bfd_set_section_alignment (obfd, note_sec, 0);
      bfd_set_section_size (obfd, note_sec, note_size);
    }

  /* Now create the memory/load sections.  */
  if (gcore_memory_sections (obfd) == 0)
    error (_("gcore: failed to get corefile memory sections from target."));

  /* Write out the contents of the note section.  */
  if (note_data != NULL && note_size != 0)
    {
      if (!bfd_set_section_contents (obfd, note_sec, note_data, 0, note_size))
	warning (_("writing note section (%s)"), bfd_errmsg (bfd_get_error ()));
    }

  /* Succeeded.  */
  fprintf_filtered (gdb_stdout, "Saved corefile %s\n", corefilename);

  /* Clean-ups will close the output file and free malloc memory.  */
  do_cleanups (old_chain);
  return;
}
Beispiel #6
0
void replace_hello(const char *input_path, const char *output_path)
{
    bfd_init();

    bfd *ibfd = bfd_openr(input_path, NULL);

    if (ibfd == NULL)
        errx(1, bfd_errmsg(bfd_get_error()));

    if (!bfd_check_format(ibfd, bfd_object)) {
        bfd_close_all_done(ibfd);
        errx(1, "Input file is not a valid object file.");
    }

    bfd *obfd = bfd_openw(output_path, bfd_get_target(ibfd));

    if (obfd == NULL) {
        bfd_close_all_done(ibfd);
        errx(1, bfd_errmsg(bfd_get_error()));
    }

    if (!bfd_set_format(obfd, bfd_get_format(ibfd))) {
        bfd_close_all_done(ibfd);
        bfd_close_all_done(obfd);
        errx(1, "Setting obfd format failed: %s\n", bfd_errmsg(bfd_get_error()));
    }

    bfd_set_arch_info(obfd, bfd_get_arch_info(ibfd));

    // Create sections for .data
    asection *section = bfd_get_section_by_name(ibfd, ".data");
    while (section != NULL) {
        if (section->flags & SEC_HAS_CONTENTS) {
            char *section_contents = (char *)malloc(section->size);
            bfd_get_section_contents(ibfd, section, section_contents, 0, section->size);

            char *hello_pos = (char *)memmem(section_contents, section->size, "hello", 5);
            if (hello_pos != NULL) {
                if (bfd_make_section_anyway_with_flags(obfd, ".data", section->flags) == NULL) {
                    free(section_contents);
                    bfd_close_all_done(ibfd);
                    bfd_close_all_done(obfd);
                    errx(1, bfd_errmsg(bfd_get_error()));
                }
            }

            free(section_contents);
        }

        section = bfd_get_next_section_by_name(ibfd, section);
    }

    asection *comment_section = bfd_make_section_anyway_with_flags(obfd, ".comment.my_objcopy", SEC_HAS_CONTENTS);
    if (comment_section == NULL) {
        bfd_close_all_done(ibfd);
        bfd_close_all_done(obfd);
        errx(1, bfd_errmsg(bfd_get_error()));
    }

    if (!bfd_set_section_size(obfd, comment_section, 3)) {
        bfd_close_all_done(ibfd);
        bfd_close_all_done(obfd);
        errx(1, bfd_errmsg(bfd_get_error()));
    }

    if (!bfd_set_section_contents(obfd, comment_section, "moo", 0, 3)) {
        bfd_close_all_done(ibfd);
        bfd_close_all_done(obfd);
        errx(1, bfd_errmsg(bfd_get_error()));
    }

    // section = bfd_get_section_by_name(ibfd, ".data");
    // asection *osection = bfd_get_section_by_name(obfd, ".data");
    // if (osection == NULL) {
    // 	bfd_close_all_done(ibfd);
    // 	bfd_close_all_done(obfd);
    // 	errx(1, bfd_errmsg(bfd_get_error()));
    // }
    // while (section != NULL) {
    // 	if (section->flags & SEC_HAS_CONTENTS) {
    // 		char *section_contents = (char *)malloc(section->size);
    // 		bfd_get_section_contents(ibfd, section, section_contents, 0, section->size);
    //
    // 		char *hello_pos = (char *)memmem(section_contents, section->size, "hello", 5);
    // 		if (hello_pos != NULL) {
    // 			hello_pos[1] = 'o';
    // 			hello_pos[4] = 'a';
    // 			if (bfd_set_section_contents(obfd, osection, section_contents, 0, section->size)) {
    // 				free(section_contents);
    // 				bfd_close_all_done(ibfd);
    // 				bfd_close_all_done(obfd);
    // 				errx(1, bfd_errmsg(bfd_get_error()));
    // 			}
    // 		}
    //
    // 		free(section_contents);
    // 		osection = bfd_get_next_section_by_name(obfd, osection);
    // 	}
    //
    // 	section = bfd_get_next_section_by_name(ibfd, section);
    // }

    if (!bfd_close(obfd))
        errx(1, "Closing obfd failed: %s\n", bfd_errmsg(bfd_get_error()));

    if (!bfd_close(ibfd))
        errx(1, "Closing ibfd failed: %s\n", bfd_errmsg(bfd_get_error()));
}
Beispiel #7
0
static void emit_so_bfd(const Chunk *base, uint64_t textOffs, uint64_t textLen,
                        std::vector<MethBlock> &blocks,
                        std::vector<DebugInfo> &debugInfos)
{
    bfd_init();

    bfd *abfd = bfd_openw("jit.o",
#ifdef __MACH__
                          "mach-o-i386"
#else
                          "elf32-i386"
#endif
)                          ;

    bfd_set_format(abfd, bfd_object);
#ifdef __MACH__
    bfd_set_arch_mach(abfd, bfd_arch_i386, bfd_mach_i386_i386);
#else
    bfd_set_arch_mach(abfd, bfd_arch_i386, bfd_mach_i386_i386);
#endif

    asection *textSection = bfd_make_section(abfd, ".text");

    bfd_set_section_flags(
            abfd, textSection,
            SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE | SEC_HAS_CONTENTS);
#ifdef __MACH__
    bfd_set_section_size(abfd, textSection, textLen);
    // for mach-o, the .o we generate is linked into a .dylib
    // so just set the alignment to make sure things end up
    // in the right place after link
    textSection->alignment_power = l2(textOffs);

    static const uint64_t textAdj = 0;
#else
    bfd_set_section_size(abfd, textSection, textLen + textOffs);

    // for linux (and oprofile) the generated object is used
    // directly, so just offset the symbols
    uint64_t textAdj = textOffs;
#endif

    asymbol **symbols = (asymbol **) malloc(
            sizeof(asymbol *) * (6 + blocks.size()));
    uint64_t start = ((uint64_t *) base->data)[0] + textOffs;

    int n = 0;
    std::map<std::string, int> namesSeen;

    std::vector<MethBlock>::const_iterator i, e;

    symbols[n++] = make_glob_symbol(abfd, "__jitStart", textSection, textAdj);
    symbols[n++] = make_glob_symbol(abfd, "_jitStart", textSection, textAdj);

    for (i = blocks.begin(), e = blocks.end(); i != e; i++, n++) {
        std::string name = i->name();
        int seen = namesSeen[name]++;

        if (seen) {
            char buf[16];

            sprintf(buf, " (%d)", seen);
            name += buf;
        }
        symbols[n] = make_glob_symbol(abfd, name.c_str(), textSection,
                                      i->start() - start + textAdj);
    }
    symbols[n++] = make_glob_symbol(abfd, "__jitUnused", textSection,
                                    blocks.back().end() - start + textAdj);
    symbols[n++] = make_glob_symbol(abfd, "_jitUnused", textSection,
                                    blocks.back().end() - start + textAdj);
    symbols[n++] = make_glob_symbol(abfd, "__jitEnd", textSection,
                                    textLen + textAdj);
    symbols[n++] = make_glob_symbol(abfd, "_jitEnd", textSection,
                                    textLen + textAdj);

    bfd_set_symtab(abfd, symbols, n);

    for (i = blocks.begin(), e = blocks.end(); i != e; i++, n++)
        if (i->codeBytes())
            bfd_set_section_contents(abfd, textSection, i->codeBytes(),
                                     i->start() - start, i->codeLen());

    bfd_close(abfd);

    for (int n = 0; n < blocks.size(); n++)
        free((void *) symbols[n]->name);
    free(symbols);
}
static int printStackTrace(JNIEnv *env, jobject sobj, StackTrace tr) {
  bfd *abfd;
  long storage_needed;
  asymbol **symbol_table;
  symtab_entry *symtab;
  long number_of_symbols;
  long number_of_text_symbols;
  long i, j;
  StackTrace curr;
    
  bfd_init();
  abfd = bfd_openr(name_of_binary, "default");
  bfd_set_format(abfd, bfd_object);
  
  if (!bfd_check_format(abfd, bfd_object)) {
    printf("Error(1) in printStackTrace\n"); return(1);
  }
  
  storage_needed = bfd_get_symtab_upper_bound(abfd);
    
  if (storage_needed < 0) {
    printf("Error(2) in printStackTrace\n"); return(2);
  }
  if (storage_needed == 0) {
    printf("Error(3) no symbols\n"); return(3);
  }

  symbol_table = (asymbol **) xmalloc (storage_needed);
  number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table);

  if (number_of_symbols < 0) {
    printf("Error(4) in printStackTrace\n"); return(4);
  } 

  /* count number of symbols in text segment */
  for (i = number_of_text_symbols = 0; i < number_of_symbols; i++)
    if (bfd_decode_symclass(symbol_table[i]) == 'T') 
      number_of_text_symbols++;

  if (number_of_text_symbols < 0) {
    printf("Error(5) in printStackTrace\n"); return(5);
  }
  if (number_of_text_symbols == 0) {
    printf("Error(6) No symbols in text segment.\n"); return(6);
  }

  symtab = (symtab_entry *) 
    malloc(number_of_text_symbols * sizeof(symtab_entry));
  
  for (i = j = 0; i < number_of_symbols; i++) {
    symbol_info si;
    bfd_symbol_info(symbol_table[i], &si);
    if (bfd_decode_symclass(symbol_table[i]) == 'T') {
      if (j >= number_of_text_symbols) {
	printf("Error(7) in printStackTrace\n"); return(7);
      }
      (symtab+j)->value = (unsigned long)si.value;
      (symtab+j)->name  = si.name;
      j++;
    }
  }

  qsort(symtab, number_of_text_symbols, sizeof(symtab_entry),
	compare_symtab_entry);
  
  curr = tr;

  while(curr != NULL) {
    symtab_entry *found = 
      bsearch_symtab((symvalue)curr->retaddr, symtab, number_of_text_symbols);
    printItem(env, sobj, found, curr);
    curr = curr->next;
  }

  /* clean up */
  free(symtab);
  bfd_close(abfd);
  return(0);
}
main (int argc, char **argv) {
    bfd *ibfd, *obfd;
    asection *p;
    static asymbol **osympp, **delsympp;
    long symsize, symcount, delsymcount;
    int i;
    int c;
    int idx;
    struct add_reloc_struct *new_reloc;
    struct change_reloc_struct *new_change;
    struct delete_reloc_struct *new_delete;
    struct modify_byte_struct *new_modify;
    struct globalize_sym_struct *new_globalize;

    while ((c = getopt (argc, argv, "a:d:c:m:G:")) != -1) {
	switch (c) {
	    case 'a':
		/* check to see if we have two args: name and loc */
		if ((index(optarg, ',') == NULL) ||
		    (index(optarg, ',') != rindex(optarg, ','))) {
		    fprintf(stderr, "usage: -a argument should be <symbolname>,<location>, not \"%s\"\n", optarg);
		    exit(1);
		}
		/* record the add reloc command in the global array */
		new_reloc = (add_reloc_struct *)malloc(sizeof(add_reloc_struct));
		new_reloc->symbol_name = strndup(optarg, (index(optarg, ',') - optarg));
		new_reloc->loc = strtol(index(optarg, ',') + 1, NULL, 0);
		if (errno == EINVAL) {
		    fprintf(stderr, "the value %s is not a valid location for the add command\n", index(optarg, ',') + 1);
		    exit(1);
		}
		new_reloc->next = additional_relocs;
		additional_relocs = new_reloc;
		break;

	    case 'c':
		/* check to see if we have two args */
		if ((index(optarg, ',') == NULL) ||
		    (index(optarg, ',') != rindex(optarg, ','))) {
		    fprintf(stderr, "usage: -c argument should be <symbolname>,<symbolname>, not \"%s\"\n", optarg);
		    exit(1);
		}
		new_change = (change_reloc_struct *)malloc(sizeof(change_reloc_struct));
		new_change->old_symbol_name = strndup(optarg, strlen(optarg) - strlen(index(optarg, ',')));
		new_change->new_symbol_name = strdup(index(optarg, ',') + 1);
		new_change->next = change_relocs;
		change_relocs = new_change;
		break;

	    case 'd':
		new_delete = (delete_reloc_struct *)malloc(sizeof(delete_reloc_struct));
		new_delete->symbol_name = strdup(optarg);
		new_delete->next = delete_relocs;
		delete_relocs = new_delete;
		break;

	    case 'm':
		if ((index(optarg, '=') == NULL) ||
		    (index(optarg, '=') != rindex(optarg, '='))) {
		    fprintf(stderr, "usage: -m argument should be <location>=<value>, not \"%s\"\n", optarg);
		    exit(1);
		}
		new_modify = (modify_byte_struct *)malloc(sizeof(modify_byte_struct));
		new_modify->location = strtol(optarg, NULL, 0);
		new_modify->value = strtol(index(optarg, '=') + 1, NULL, 0);
		if (new_modify->value > 0xff) {
		    fprintf(stderr, "requested modify value %lx for location %lx exceeds 0xff\n",
			    new_modify->value, new_modify->location);
		    exit(1);
		}
		new_modify->next = modify_bytes;
		modify_bytes = new_modify;
		break;

	    case 'G':
		new_globalize = (globalize_sym_struct *)malloc(sizeof(globalize_sym_struct));
		new_globalize->symbol_name = strdup(optarg);
		new_globalize->next = globalize_syms;
		globalize_syms = new_globalize;
		break;

	    default:
		fprintf(stderr, "unrecognized argument character |%c|\n", c);
	}
    }

    if ((argc - optind) != 2) {
	fprintf(stderr, "usage: fixup_relocs [-a newsymbol,location] [-c oldsymbol,newsymbol] [-d symbol] infile.o outfile.o\n");
	exit(1);
    }

    ibfd = bfd_openr(argv[optind], NULL);
    if (ibfd == NULL) {
	bfd_perror("while opening input object file");
	exit(1);
    }

    /* if I don't do "check_format", there's no data in the bfd object.  wtf? */
    if (!bfd_check_format(ibfd, bfd_object)) {
	fprintf(stderr, "input file %s seems to NOT be an object file! exiting.\n", argv[optind]);
	exit(1);
    }

    obfd = bfd_openw(argv[optind+1], bfd_get_target(ibfd));
    if (obfd == NULL) {
	bfd_perror("while opening output object file");
	exit(1);
    }

    if (!bfd_set_format(obfd, bfd_get_format(ibfd))) {
	bfd_perror("while setting output object file format");
    }

    /* copy a bunch of necessary global stuff */
    bfd_set_start_address(obfd, bfd_get_start_address(ibfd));
    bfd_set_file_flags(obfd, bfd_get_file_flags(ibfd));
    bfd_set_arch_mach(obfd, bfd_get_arch(ibfd), bfd_get_mach(ibfd));
    /* BOZO objcopy sets format again at this point.  why? */

    bfd_map_over_sections (ibfd, setup_section, obfd);

    setup_bfd_headers (ibfd, obfd);

    /* Symbol filtering must happen after the output sections
       have been created, but before their contents are set.  */
    symsize = bfd_get_symtab_upper_bound (ibfd);
    if (symsize < 0) {
	fprintf(stderr, "problem processing %s\n", bfd_get_filename (ibfd));
	return FALSE;
    }

    /* count the added relocations so we can put extra space in the output symbol table for them */
    int reloc_add_cnt, reloc_delete_cnt;
    reloc_add_cnt = 0;
    reloc_delete_cnt = 0;
    for (new_reloc = additional_relocs; new_reloc != NULL; new_reloc = new_reloc->next) {
	reloc_add_cnt++;
    }
    /* the "change" symbols might also not be in the symbol table yet */
    for (new_change = change_relocs; new_change != NULL; new_change = new_change->next) {
	reloc_add_cnt++;
	/* the old symbol may be deleted, also */
	reloc_delete_cnt++;
    }
    for (new_delete = delete_relocs; new_delete != NULL; new_delete = new_delete->next) {
	reloc_delete_cnt++;
    }

    /* filter symbol table in two steps: */
    /* 1) move symbols bound for deletion to the end of the output symbol table array */
    /* 2) truncate the table at the first of those */
    /* this makes it possible to do the reloc processing with the symbol table intact, */
    /* and remove the deleted symbols afterwards, without corrupting the reloc data structures */
    isympp = malloc (symsize);
    osympp = malloc (symsize + reloc_add_cnt * sizeof(asymbol *));
    delsympp = malloc (reloc_delete_cnt * sizeof(asymbol *));
    symcount = bfd_canonicalize_symtab (ibfd, isympp);

    if (symcount < 0) {
	fprintf(stderr, "problem processing %s\n", bfd_get_filename (ibfd));
	return FALSE;
    }

    /* remove any undefined symbols whose relocation entries were deleted or changed */
    int osym_idx, delsym_idx;
    osym_idx = delsym_idx = 0;
    delsymcount = 0;
    for (i = 0; i < symcount; i++) {
	if ((is_delete_reloc(bfd_asymbol_name(isympp[i]), delete_relocs) ||
	     (find_change_reloc(bfd_asymbol_name(isympp[i]), change_relocs) != NULL)) &&
	    (isympp[i]->section != NULL) &&
	    (strcmp(isympp[i]->section->name, BFD_UND_SECTION_NAME) == 0)) {
	    delsympp[delsym_idx++] = isympp[i];
	}
	else {
	    if (is_globalize_sym(bfd_asymbol_name(isympp[i]), globalize_syms)) {
		isympp[i]->flags = BSF_GLOBAL;
	    }
	    osympp[osym_idx++] = isympp[i];
	}
    }
    symcount = osym_idx;
    delsymcount = delsym_idx;
    osympp[symcount] = NULL;

    /* add the symbols for additional relocs to the table */
    int added_symbol_cnt = 0;
    for (new_reloc = additional_relocs; new_reloc != NULL; new_reloc = new_reloc->next) {
	if (find_symbol(osympp, new_reloc->symbol_name) < 0) {
	    /* not yet present, so add it */
	    asymbol *new_sym;
	    new_sym = bfd_make_empty_symbol(obfd);
	    new_sym->name = strdup(new_reloc->symbol_name);
	    new_sym->section = bfd_get_section_by_name (obfd, ".text");
	    new_sym->value = new_reloc->loc;
	    new_sym->flags = BSF_GLOBAL;
	    osympp[symcount + added_symbol_cnt++] = new_sym;
	    osympp[symcount + added_symbol_cnt] = NULL;
	}
    }

    /* do the same for changed relocs */
    for (new_change = change_relocs; new_change != NULL; new_change = new_change->next) {
	if (find_symbol(osympp, new_change->new_symbol_name) < 0) {
	    /* not yet present, so add it */
	    /* since this is a name change, we will reuse the existing address (value field of reloc) */
	    int old_symbol_idx;
	    if ((old_symbol_idx = find_symbol(isympp, new_change->old_symbol_name)) < 0) {
		fprintf(stderr, "change command old symbol name %s not found in symbol table! Exiting.\n", new_change->old_symbol_name);
		exit(1);
	    }
	    asymbol *new_sym;
	    new_sym = bfd_make_empty_symbol(obfd);
	    new_sym->name = strdup(new_change->new_symbol_name);
	    new_sym->section = bfd_und_section_ptr;
	    new_sym->value = isympp[old_symbol_idx]->value;
	    new_sym->flags = BSF_GLOBAL;
	    fprintf(stderr, "adding new symbol %s for change reloc command\n", new_sym->name);
	    osympp[symcount + added_symbol_cnt++] = new_sym;
	    osympp[symcount + added_symbol_cnt] = NULL;
	}
    }

    /* append the soon-to-be deleted symbols to the end of the output symbol table */
    for (i = 0; i < delsymcount; i++) {
	osympp[symcount + added_symbol_cnt + i] = delsympp[i];
    }
    osympp[symcount + added_symbol_cnt + delsymcount] = NULL;

    bfd_set_symtab (obfd, osympp, symcount + added_symbol_cnt + delsymcount);

    /* This has to happen after the symbol table has been set.  */
    bfd_map_over_sections (ibfd, copy_section_relocs_edit, obfd);

    /* now truncate the symbol table to eliminate the deleted symbols */
    osympp[symcount + added_symbol_cnt] = NULL;

    bfd_set_symtab (obfd, osympp, symcount + added_symbol_cnt);
    
    /* now that we've set the relocs and cleaned the symtab, can call this */
    bfd_map_over_sections (ibfd, copy_section_data, obfd);

    bfd_close(obfd);
    bfd_close(ibfd);

    return 0;

}
int main(int argc, char * argv[])
{
        bfd *                bfd_in;
        bfd *                bfd_out;
        char *               filename_in;
        char *               filename_out;

        log_init(PROGRAM_NAME, LOG_MESSAGE);
        atexit(log_fini);

        filename_in  = NULL;
        filename_out = NULL;

        int c;
        // int digit_optind = 0;
        while (1) {
                // int this_option_optind = optind ? optind : 1;
                int option_index       = 0;

                static struct option long_options[] = {
                        { "input",        1, 0, 'i' },
                        { "output",       1, 0, 'o' },

                        { "debug",        0, 0, 'd' },
                        { "verbose",      0, 0, 'v' },
                        { "version",      0, 0, 'V' },
                        { "help",         0, 0, 'h' },
                        { 0,              0, 0, 0   }
                };
                c = getopt_long(argc, argv, "i:o:dvVh",
                                long_options, &option_index);
                if (c == -1) {
                        break;
                }

                debug("Handling option character '%c'\n", c);

                switch (c) {
                        case 'i':
                                filename_in = optarg;
                                break;
                        case 'o':
                                filename_out = optarg;
                                break;
                        case 'd':
                                log_level(LOG_DEBUG);
                                break;
                        case 'v':
                                log_level(LOG_VERBOSE);
                                break;
                        case 'V':
                                version(PROGRAM_NAME);
                                return 0;
                        case 'h':
                                help();
                                return 0;
                        case '?':
                                hint(PROGRAM_NAME, "Unrecognized option");
                                return 1;
                        default:
                                BUG();
                                return 1;
                }
        }

        if (!filename_in) {
                fatal("Missing input filename\n");
                exit(EXIT_FAILURE);
        }
        if (!filename_out) {
                fatal("Missing output filename\n");
                exit(EXIT_FAILURE);
        }
        /* XXX FIXME: Use stat instead of strcmp */
        if (!strcmp(filename_in, filename_out)) {
                fatal("Input and output are the same file\n");
                exit(EXIT_FAILURE);
        }

        bfd_init();

        debug("Reading input file %s\n", filename_in);
        bfd_in = bfd_openr(filename_in, NULL);
        if (!bfd_in) {
                fatal("Cannot open input file %s (%s)\n",
                      filename_in, BFD_strerror());
                exit(EXIT_FAILURE);
        }
        if (!bfd_check_format(bfd_in, bfd_object)) {
                fatal("Wrong input file format (not an object)\n");
                exit(EXIT_FAILURE);
        }

        bfd_out = bfd_openw(filename_out, NULL);
        if (!bfd_out) {
                fatal("Cannot open output file %s (%s)\n",
                      filename_out, BFD_strerror());
                exit(EXIT_FAILURE);
        }

        debug("Generating output file %s\n", filename_out);
        bfd_set_format(bfd_out, bfd_get_format(bfd_in));

        if (bfd_copy_private_bfd_data(bfd_in, bfd_out) == FALSE) {
                fatal("Cannot copy private bfd data (%s)\n",
                      BFD_strerror());
                exit(EXIT_FAILURE);
        }
        if (bfd_copy_private_header_data(bfd_in, bfd_out) == FALSE) {
                fatal("Cannot copy private header data (%s)\n",
                      BFD_strerror());
                exit(EXIT_FAILURE);
        }

        bfd_close(bfd_in);
        bfd_close(bfd_out);

        exit(EXIT_SUCCESS);
}