diff --git a/bfd/ChangeLog b/bfd/ChangeLog index e36a37c3e4..b746060c39 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,21 @@ +2013-01-26 Alan Modra + + * bfd.c (struct bfd_preserve, bfd_preserve_save, bfd_preserve_restore, + bfd_preserve_finish): Move to.. + * format.c: ..here, splitting out.. + (bfd_reinit): ..this. New function. + (bfd_check_format_matches): Use bfd_preserve_save/restore to + keep bfd state for a match. + * elfcode.h (elf_object_p): Don't use bfd_preserve_save/restore. + * elfcore.h (elf_core_file_p): Likewise. + * mach-o.c (bfd_mach_o_header_p): Likewise. + * pef.c (bfd_pef_object_p, bfd_pef_xlib_object_p): Likewise. + * xsym.c (bfd_sym_object_p): Likewise. + * mmo.c (mmo_scan): Clear abfd->symcount. + * opncls.c (_bfd_new_bfd): Use a smaller section hash table. + * section.c (bfd_section_list_clear): Clear section_htab.count. + * bfd-in2.h: Regenerate. + 2013-01-25 Michael Schewe * elf32-h8300.c (elf32_h8_relax_section): When checking for a diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 489c3b5d22..5b04176342 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -6247,24 +6247,6 @@ extern bfd_byte *bfd_get_relocated_section_contents bfd_boolean bfd_alt_mach_code (bfd *abfd, int alternative); -struct bfd_preserve -{ - void *marker; - void *tdata; - flagword flags; - const struct bfd_arch_info *arch_info; - struct bfd_section *sections; - struct bfd_section *section_last; - unsigned int section_count; - struct bfd_hash_table section_htab; -}; - -bfd_boolean bfd_preserve_save (bfd *, struct bfd_preserve *); - -void bfd_preserve_restore (bfd *, struct bfd_preserve *); - -void bfd_preserve_finish (bfd *, struct bfd_preserve *); - bfd_vma bfd_emul_get_maxpagesize (const char *); void bfd_emul_set_maxpagesize (const char *, bfd_vma); diff --git a/bfd/bfd.c b/bfd/bfd.c index eed1896085..cf50b70923 100644 --- a/bfd/bfd.c +++ b/bfd/bfd.c @@ -1686,128 +1686,6 @@ bfd_alt_mach_code (bfd *abfd, int alternative) return FALSE; } -/* -CODE_FRAGMENT - -.struct bfd_preserve -.{ -. void *marker; -. void *tdata; -. flagword flags; -. const struct bfd_arch_info *arch_info; -. struct bfd_section *sections; -. struct bfd_section *section_last; -. unsigned int section_count; -. struct bfd_hash_table section_htab; -.}; -. -*/ - -/* -FUNCTION - bfd_preserve_save - -SYNOPSIS - bfd_boolean bfd_preserve_save (bfd *, struct bfd_preserve *); - -DESCRIPTION - When testing an object for compatibility with a particular - target back-end, the back-end object_p function needs to set - up certain fields in the bfd on successfully recognizing the - object. This typically happens in a piecemeal fashion, with - failures possible at many points. On failure, the bfd is - supposed to be restored to its initial state, which is - virtually impossible. However, restoring a subset of the bfd - state works in practice. This function stores the subset and - reinitializes the bfd. - -*/ - -bfd_boolean -bfd_preserve_save (bfd *abfd, struct bfd_preserve *preserve) -{ - preserve->tdata = abfd->tdata.any; - preserve->arch_info = abfd->arch_info; - preserve->flags = abfd->flags; - preserve->sections = abfd->sections; - preserve->section_last = abfd->section_last; - preserve->section_count = abfd->section_count; - preserve->section_htab = abfd->section_htab; - - if (! bfd_hash_table_init (&abfd->section_htab, bfd_section_hash_newfunc, - sizeof (struct section_hash_entry))) - return FALSE; - - abfd->tdata.any = NULL; - abfd->arch_info = &bfd_default_arch_struct; - abfd->flags &= BFD_FLAGS_SAVED; - abfd->sections = NULL; - abfd->section_last = NULL; - abfd->section_count = 0; - - return TRUE; -} - -/* -FUNCTION - bfd_preserve_restore - -SYNOPSIS - void bfd_preserve_restore (bfd *, struct bfd_preserve *); - -DESCRIPTION - This function restores bfd state saved by bfd_preserve_save. - If MARKER is non-NULL in struct bfd_preserve then that block - and all subsequently bfd_alloc'd memory is freed. - -*/ - -void -bfd_preserve_restore (bfd *abfd, struct bfd_preserve *preserve) -{ - bfd_hash_table_free (&abfd->section_htab); - - abfd->tdata.any = preserve->tdata; - abfd->arch_info = preserve->arch_info; - abfd->flags = preserve->flags; - abfd->section_htab = preserve->section_htab; - abfd->sections = preserve->sections; - abfd->section_last = preserve->section_last; - abfd->section_count = preserve->section_count; - - /* bfd_release frees all memory more recently bfd_alloc'd than - its arg, as well as its arg. */ - if (preserve->marker != NULL) - { - bfd_release (abfd, preserve->marker); - preserve->marker = NULL; - } -} - -/* -FUNCTION - bfd_preserve_finish - -SYNOPSIS - void bfd_preserve_finish (bfd *, struct bfd_preserve *); - -DESCRIPTION - This function should be called when the bfd state saved by - bfd_preserve_save is no longer needed. ie. when the back-end - object_p function returns with success. - -*/ - -void -bfd_preserve_finish (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_preserve *preserve) -{ - /* It would be nice to be able to free more memory here, eg. old - tdata, but that's not possible since these blocks are sitting - inside bfd_alloc'd memory. The section hash is on a separate - objalloc. */ - bfd_hash_table_free (&preserve->section_htab); -} - /* FUNCTION bfd_emul_get_maxpagesize diff --git a/bfd/elfcode.h b/bfd/elfcode.h index 30bda73d86..298ba3526d 100644 --- a/bfd/elfcode.h +++ b/bfd/elfcode.h @@ -495,13 +495,10 @@ elf_object_p (bfd *abfd) Elf_Internal_Shdr *i_shdrp; /* Section header table, internal form */ unsigned int shindex; const struct elf_backend_data *ebd; - struct bfd_preserve preserve; asection *s; bfd_size_type amt; const bfd_target *target; - preserve.marker = NULL; - /* Read in the ELF header in external format. */ if (bfd_bread (&x_ehdr, sizeof (x_ehdr), abfd) != sizeof (x_ehdr)) @@ -539,9 +536,6 @@ elf_object_p (bfd *abfd) goto got_wrong_format_error; } - if (!bfd_preserve_save (abfd, &preserve)) - goto got_no_match; - target = abfd->xvec; /* Allocate an instance of the elf_obj_tdata structure and hook it up to @@ -549,7 +543,6 @@ elf_object_p (bfd *abfd) if (! (*target->_bfd_set_format[bfd_object]) (abfd)) goto got_no_match; - preserve.marker = elf_tdata (abfd); /* Now that we know the byte order, swap in the rest of the header */ i_ehdrp = elf_elfheader (abfd); @@ -842,25 +835,12 @@ elf_object_p (bfd *abfd) s->flags |= SEC_DEBUGGING; } } - - bfd_preserve_finish (abfd, &preserve); return target; got_wrong_format_error: - /* There is way too much undoing of half-known state here. The caller, - bfd_check_format_matches, really shouldn't iterate on live bfd's to - check match/no-match like it does. We have to rely on that a call to - bfd_default_set_arch_mach with the previously known mach, undoes what - was done by the first bfd_default_set_arch_mach (with mach 0) here. - For this to work, only elf-data and the mach may be changed by the - target-specific elf_backend_object_p function. Note that saving the - whole bfd here and restoring it would be even worse; the first thing - you notice is that the cached bfd file position gets out of sync. */ bfd_set_error (bfd_error_wrong_format); got_no_match: - if (preserve.marker != NULL) - bfd_preserve_restore (abfd, &preserve); return NULL; } diff --git a/bfd/elfcore.h b/bfd/elfcore.h index 3d7d59fa91..8d5ec6d5a2 100644 --- a/bfd/elfcore.h +++ b/bfd/elfcore.h @@ -84,11 +84,8 @@ elf_core_file_p (bfd *abfd) Elf_Internal_Phdr *i_phdrp; /* Elf program header, internal form. */ unsigned int phindex; const struct elf_backend_data *ebd; - struct bfd_preserve preserve; bfd_size_type amt; - preserve.marker = NULL; - /* Read in the ELF header in external format. */ if (bfd_bread (&x_ehdr, sizeof (x_ehdr), abfd) != sizeof (x_ehdr)) { @@ -123,13 +120,9 @@ elf_core_file_p (bfd *abfd) goto wrong; } - if (!bfd_preserve_save (abfd, &preserve)) - goto fail; - /* Give abfd an elf_obj_tdata. */ if (! (*abfd->xvec->_bfd_set_format[bfd_core]) (abfd)) goto fail; - preserve.marker = elf_tdata (abfd); /* Swap in the rest of the header, now that we have the byte order. */ i_ehdrp = elf_elfheader (abfd); @@ -318,24 +311,10 @@ elf_core_file_p (bfd *abfd) /* Save the entry point from the ELF header. */ bfd_get_start_address (abfd) = i_ehdrp->e_entry; - - bfd_preserve_finish (abfd, &preserve); return abfd->xvec; wrong: - /* There is way too much undoing of half-known state here. The caller, - bfd_check_format_matches, really shouldn't iterate on live bfd's to - check match/no-match like it does. We have to rely on that a call to - bfd_default_set_arch_mach with the previously known mach, undoes what - was done by the first bfd_default_set_arch_mach (with mach 0) here. - For this to work, only elf-data and the mach may be changed by the - target-specific elf_backend_object_p function. Note that saving the - whole bfd here and restoring it would be even worse; the first thing - you notice is that the cached bfd file position gets out of sync. */ bfd_set_error (bfd_error_wrong_format); - fail: - if (preserve.marker != NULL) - bfd_preserve_restore (abfd, &preserve); return NULL; } diff --git a/bfd/format.c b/bfd/format.c index 66b9051efe..36eeb85e19 100644 --- a/bfd/format.c +++ b/bfd/format.c @@ -95,6 +95,91 @@ bfd_check_format (bfd *abfd, bfd_format format) return bfd_check_format_matches (abfd, format, NULL); } +struct bfd_preserve +{ + void *marker; + void *tdata; + flagword flags; + const struct bfd_arch_info *arch_info; + struct bfd_section *sections; + struct bfd_section *section_last; + unsigned int section_count; + struct bfd_hash_table section_htab; +}; + +/* When testing an object for compatibility with a particular target + back-end, the back-end object_p function needs to set up certain + fields in the bfd on successfully recognizing the object. This + typically happens in a piecemeal fashion, with failures possible at + many points. On failure, the bfd is supposed to be restored to its + initial state, which is virtually impossible. However, restoring a + subset of the bfd state works in practice. This function stores + the subset. */ + +static bfd_boolean +bfd_preserve_save (bfd *abfd, struct bfd_preserve *preserve) +{ + preserve->tdata = abfd->tdata.any; + preserve->arch_info = abfd->arch_info; + preserve->flags = abfd->flags; + preserve->sections = abfd->sections; + preserve->section_last = abfd->section_last; + preserve->section_count = abfd->section_count; + preserve->section_htab = abfd->section_htab; + preserve->marker = bfd_alloc (abfd, 1); + if (preserve->marker == NULL) + return FALSE; + + return bfd_hash_table_init (&abfd->section_htab, bfd_section_hash_newfunc, + sizeof (struct section_hash_entry)); +} + +/* Clear out a subset of BFD state. */ + +static void +bfd_reinit (bfd *abfd) +{ + abfd->tdata.any = NULL; + abfd->arch_info = &bfd_default_arch_struct; + abfd->flags &= BFD_FLAGS_SAVED; + bfd_section_list_clear (abfd); +} + +/* Restores bfd state saved by bfd_preserve_save. */ + +static void +bfd_preserve_restore (bfd *abfd, struct bfd_preserve *preserve) +{ + bfd_hash_table_free (&abfd->section_htab); + + abfd->tdata.any = preserve->tdata; + abfd->arch_info = preserve->arch_info; + abfd->flags = preserve->flags; + abfd->section_htab = preserve->section_htab; + abfd->sections = preserve->sections; + abfd->section_last = preserve->section_last; + abfd->section_count = preserve->section_count; + + /* bfd_release frees all memory more recently bfd_alloc'd than + its arg, as well as its arg. */ + bfd_release (abfd, preserve->marker); + preserve->marker = NULL; +} + +/* Called when the bfd state saved by bfd_preserve_save is no longer + needed. */ + +static void +bfd_preserve_finish (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_preserve *preserve) +{ + /* It would be nice to be able to free more memory here, eg. old + tdata, but that's not possible since these blocks are sitting + inside bfd_alloc'd memory. The section hash is on a separate + objalloc. */ + bfd_hash_table_free (&preserve->section_htab); + preserve->marker = NULL; +} + /* FUNCTION bfd_check_format_matches @@ -124,6 +209,7 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching) const bfd_target *save_targ, *right_targ, *ar_right_targ, *match_targ; int match_count, best_count, best_match; int ar_match_index; + struct bfd_preserve preserve; if (matching != NULL) *matching = NULL; @@ -138,12 +224,6 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching) if (abfd->format != bfd_unknown) return abfd->format == format; - /* Since the target type was defaulted, check them - all in the hope that one will be uniquely recognized. */ - save_targ = abfd->xvec; - match_count = 0; - ar_match_index = _bfd_target_vector_entries; - if (matching != NULL || *bfd_associated_vector != NULL) { bfd_size_type amt; @@ -154,14 +234,10 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching) return FALSE; } - right_targ = 0; - ar_right_targ = 0; - match_targ = 0; - best_match = 256; - best_count = 0; - /* Presume the answer is yes. */ abfd->format = format; + save_targ = abfd->xvec; + preserve.marker = NULL; /* If the target type was explicitly specified, just check that target. */ if (!abfd->target_defaulted) @@ -190,6 +266,16 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching) goto err_unrecog; } + /* Since the target type was defaulted, check them all in the hope + that one will be uniquely recognized. */ + right_targ = NULL; + ar_right_targ = NULL; + match_targ = NULL; + best_match = 256; + best_count = 0; + match_count = 0; + ar_match_index = _bfd_target_vector_entries; + for (target = bfd_target_vector; *target != NULL; target++) { const bfd_target *temp; @@ -201,7 +287,13 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching) || (*target)->match_priority > best_match) continue; - abfd->xvec = *target; /* Change BFD's target temporarily. */ + /* If we already tried a match, the bfd is modified and may + have sections attached, which will confuse the next + _bfd_check_format call. */ + bfd_reinit (abfd); + + /* Change BFD's target temporarily. */ + abfd->xvec = *target; if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) goto err_ret; @@ -214,7 +306,11 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching) temp = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd)); if (temp) - match_targ = temp; + { + match_targ = temp; + if (preserve.marker != NULL) + bfd_preserve_finish (abfd, &preserve); + } if (temp && (abfd->format != bfd_archive || bfd_has_map (abfd))) { @@ -253,6 +349,9 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching) } else if (err != bfd_error_wrong_format) goto err_ret; + + if (temp && !bfd_preserve_save (abfd, &preserve)) + goto err_ret; } if (best_count == 1) @@ -298,6 +397,13 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching) } } + /* There is way too much undoing of half-known state here. We + really shouldn't iterate on live bfd's. Note that saving the + whole bfd and restoring it would be even worse; the first thing + you notice is that the cached bfd file position gets out of sync. */ + if (preserve.marker != NULL) + bfd_preserve_restore (abfd, &preserve); + if (match_count == 1) { abfd->xvec = right_targ; @@ -306,9 +412,11 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching) state (except possibly for XVEC). */ if (match_targ != right_targ) { + bfd_reinit (abfd); if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) goto err_ret; match_targ = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd)); + BFD_ASSERT (match_targ != NULL); } ok_ret: @@ -322,7 +430,9 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching) if (matching_vector) free (matching_vector); - return TRUE; /* File position has moved, BTW. */ + + /* File position has moved, BTW. */ + return TRUE; } if (match_count == 0) @@ -334,11 +444,14 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching) abfd->format = bfd_unknown; if (matching_vector) free (matching_vector); + if (preserve.marker != NULL) + bfd_preserve_restore (abfd, &preserve); return FALSE; } - abfd->xvec = save_targ; /* Restore original target type. */ - abfd->format = bfd_unknown; /* Restore original format. */ + /* Restore original target type and format. */ + abfd->xvec = save_targ; + abfd->format = bfd_unknown; bfd_set_error (bfd_error_file_ambiguously_recognized); if (matching) diff --git a/bfd/mach-o.c b/bfd/mach-o.c index c853ba117f..7f4b968c9c 100644 --- a/bfd/mach-o.c +++ b/bfd/mach-o.c @@ -4177,10 +4177,9 @@ bfd_mach_o_header_p (bfd *abfd, bfd_mach_o_filetype filetype, bfd_mach_o_cpu_type cputype) { - struct bfd_preserve preserve; bfd_mach_o_header header; + bfd_mach_o_data_struct *mdata; - preserve.marker = NULL; if (!bfd_mach_o_read_header (abfd, &header)) goto wrong; @@ -4226,24 +4225,19 @@ bfd_mach_o_header_p (bfd *abfd, } } - preserve.marker = bfd_zalloc (abfd, sizeof (bfd_mach_o_data_struct)); - if (preserve.marker == NULL - || !bfd_preserve_save (abfd, &preserve)) + mdata = (bfd_mach_o_data_struct *) bfd_zalloc (abfd, sizeof (*mdata)); + if (mdata == NULL) goto fail; - if (!bfd_mach_o_scan (abfd, &header, - (bfd_mach_o_data_struct *) preserve.marker)) + if (!bfd_mach_o_scan (abfd, &header, mdata)) goto wrong; - bfd_preserve_finish (abfd, &preserve); return abfd->xvec; wrong: bfd_set_error (bfd_error_wrong_format); fail: - if (preserve.marker != NULL) - bfd_preserve_restore (abfd, &preserve); return NULL; } diff --git a/bfd/mmo.c b/bfd/mmo.c index 7c82c61e35..bebf05ac28 100644 --- a/bfd/mmo.c +++ b/bfd/mmo.c @@ -1536,6 +1536,7 @@ mmo_scan (bfd *abfd) long stab_loc = -1; char *file_names[256]; + abfd->symcount = 0; memset (file_names, 0, sizeof (file_names)); if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) diff --git a/bfd/opncls.c b/bfd/opncls.c index c18d08af38..6d61191a96 100644 --- a/bfd/opncls.c +++ b/bfd/opncls.c @@ -86,7 +86,7 @@ _bfd_new_bfd (void) nbfd->iostream = NULL; nbfd->where = 0; if (!bfd_hash_table_init_n (& nbfd->section_htab, bfd_section_hash_newfunc, - sizeof (struct section_hash_entry), 251)) + sizeof (struct section_hash_entry), 13)) { free (nbfd); return NULL; diff --git a/bfd/pef.c b/bfd/pef.c index ca4c4548a9..6c52e0f359 100644 --- a/bfd/pef.c +++ b/bfd/pef.c @@ -583,34 +583,28 @@ bfd_pef_read_header (bfd *abfd, bfd_pef_header *header) static const bfd_target * bfd_pef_object_p (bfd *abfd) { - struct bfd_preserve preserve; bfd_pef_header header; + bfd_pef_data_struct *mdata; - preserve.marker = NULL; if (bfd_pef_read_header (abfd, &header) != 0) goto wrong; if (header.tag1 != BFD_PEF_TAG1 || header.tag2 != BFD_PEF_TAG2) goto wrong; - preserve.marker = bfd_zalloc (abfd, sizeof (bfd_pef_data_struct)); - if (preserve.marker == NULL - || !bfd_preserve_save (abfd, &preserve)) + mdata = (bfd_pef_data_struct *) bfd_zalloc (abfd, sizeof (*mdata)); + if (mdata == NULL) goto fail; - if (bfd_pef_scan (abfd, &header, - (bfd_pef_data_struct *) preserve.marker) != 0) + if (bfd_pef_scan (abfd, &header, mdata)) goto wrong; - bfd_preserve_finish (abfd, &preserve); return abfd->xvec; wrong: bfd_set_error (bfd_error_wrong_format); fail: - if (preserve.marker != NULL) - bfd_preserve_restore (abfd, &preserve); return NULL; } @@ -1124,7 +1118,6 @@ bfd_pef_xlib_scan (bfd *abfd, bfd_pef_xlib_header *header) static const bfd_target * bfd_pef_xlib_object_p (bfd *abfd) { - struct bfd_preserve preserve; bfd_pef_xlib_header header; if (bfd_pef_xlib_read_header (abfd, &header) != 0) @@ -1141,20 +1134,12 @@ bfd_pef_xlib_object_p (bfd *abfd) return NULL; } - if (! bfd_preserve_save (abfd, &preserve)) - { - bfd_set_error (bfd_error_wrong_format); - return NULL; - } - if (bfd_pef_xlib_scan (abfd, &header) != 0) { - bfd_preserve_restore (abfd, &preserve); bfd_set_error (bfd_error_wrong_format); return NULL; } - bfd_preserve_finish (abfd, &preserve); return abfd->xvec; } diff --git a/bfd/section.c b/bfd/section.c index b58cdfa630..fb19d8cc3a 100644 --- a/bfd/section.c +++ b/bfd/section.c @@ -835,6 +835,7 @@ bfd_section_list_clear (bfd *abfd) abfd->section_count = 0; memset (abfd->section_htab.table, 0, abfd->section_htab.size * sizeof (struct bfd_hash_entry *)); + abfd->section_htab.count = 0; } /* diff --git a/bfd/xsym.c b/bfd/xsym.c index e0819a9b1a..5000f83195 100644 --- a/bfd/xsym.c +++ b/bfd/xsym.c @@ -2249,32 +2249,26 @@ bfd_sym_scan (bfd *abfd, bfd_sym_version version, bfd_sym_data_struct *mdata) const bfd_target * bfd_sym_object_p (bfd *abfd) { - struct bfd_preserve preserve; bfd_sym_version version = -1; + bfd_sym_data_struct *mdata; - preserve.marker = NULL; bfd_seek (abfd, 0, SEEK_SET); if (bfd_sym_read_version (abfd, &version) != 0) goto wrong; - preserve.marker = bfd_alloc (abfd, sizeof (bfd_sym_data_struct)); - if (preserve.marker == NULL - || ! bfd_preserve_save (abfd, &preserve)) + mdata = (bfd_sym_data_struct *) bfd_alloc (abfd, sizeof (*mdata)); + if (mdata == NULL) goto fail; - if (bfd_sym_scan (abfd, version, - (bfd_sym_data_struct *) preserve.marker) != 0) + if (bfd_sym_scan (abfd, version, mdata) != 0) goto wrong; - bfd_preserve_finish (abfd, &preserve); return abfd->xvec; wrong: bfd_set_error (bfd_error_wrong_format); fail: - if (preserve.marker != NULL) - bfd_preserve_restore (abfd, &preserve); return NULL; }