diff options
Diffstat (limited to 'bfd/bfd.c')
-rw-r--r-- | bfd/bfd.c | 130 |
1 files changed, 130 insertions, 0 deletions
@@ -1392,3 +1392,133 @@ bfd_alt_mach_code (abfd, alternative) return false; } + +/* +CODE_FRAGMENT + +.struct bfd_preserve +.{ +. PTR marker; +. PTR tdata; +. flagword flags; +. const struct bfd_arch_info *arch_info; +. struct sec *sections; +. struct sec **section_tail; +. unsigned int section_count; +. struct bfd_hash_table section_htab; +.}; +. +*/ + +/* +FUNCTION + bfd_preserve_save + +SYNOPSIS + 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. + +*/ + +boolean +bfd_preserve_save (abfd, preserve) + 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_tail = abfd->section_tail; + preserve->section_count = abfd->section_count; + preserve->section_htab = abfd->section_htab; + + if (! bfd_hash_table_init (&abfd->section_htab, bfd_section_hash_newfunc)) + return false; + + abfd->tdata.any = NULL; + abfd->arch_info = &bfd_default_arch_struct; + abfd->flags = 0; + + abfd->sections = NULL; + abfd->section_tail = &abfd->sections; + 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 (abfd, preserve) + 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_tail = preserve->section_tail; + 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 (abfd, preserve) + 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); +} |