| /* Generic BFD support for file formats. | |
| Copyright (C) 1990-2022 Free Software Foundation, Inc. | |
| Written by Cygnus Support. | |
| This file is part of BFD, the Binary File Descriptor library. | |
| 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 3 of the License, 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., 51 Franklin Street - Fifth Floor, Boston, | |
| MA 02110-1301, USA. */ | |
| /* | |
| SECTION | |
| File formats | |
| A format is a BFD concept of high level file contents type. The | |
| formats supported by BFD are: | |
| o <<bfd_object>> | |
| The BFD may contain data, symbols, relocations and debug info. | |
| o <<bfd_archive>> | |
| The BFD contains other BFDs and an optional index. | |
| o <<bfd_core>> | |
| The BFD contains the result of an executable core dump. | |
| SUBSECTION | |
| File format functions | |
| */ | |
| #include "sysdep.h" | |
| #include "bfd.h" | |
| #include "libbfd.h" | |
| /* IMPORT from targets.c. */ | |
| extern const size_t _bfd_target_vector_entries; | |
| /* | |
| FUNCTION | |
| bfd_check_format | |
| SYNOPSIS | |
| bool bfd_check_format (bfd *abfd, bfd_format format); | |
| DESCRIPTION | |
| Verify if the file attached to the BFD @var{abfd} is compatible | |
| with the format @var{format} (i.e., one of <<bfd_object>>, | |
| <<bfd_archive>> or <<bfd_core>>). | |
| If the BFD has been set to a specific target before the | |
| call, only the named target and format combination is | |
| checked. If the target has not been set, or has been set to | |
| <<default>>, then all the known target backends is | |
| interrogated to determine a match. If the default target | |
| matches, it is used. If not, exactly one target must recognize | |
| the file, or an error results. | |
| The function returns <<TRUE>> on success, otherwise <<FALSE>> | |
| with one of the following error codes: | |
| o <<bfd_error_invalid_operation>> - | |
| if <<format>> is not one of <<bfd_object>>, <<bfd_archive>> or | |
| <<bfd_core>>. | |
| o <<bfd_error_system_call>> - | |
| if an error occured during a read - even some file mismatches | |
| can cause bfd_error_system_calls. | |
| o <<file_not_recognised>> - | |
| none of the backends recognised the file format. | |
| o <<bfd_error_file_ambiguously_recognized>> - | |
| more than one backend recognised the file format. | |
| */ | |
| bool | |
| 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; | |
| unsigned int section_id; | |
| struct bfd_hash_table section_htab; | |
| const struct bfd_build_id *build_id; | |
| bfd_cleanup cleanup; | |
| }; | |
| /* 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 bool | |
| bfd_preserve_save (bfd *abfd, struct bfd_preserve *preserve, | |
| bfd_cleanup cleanup) | |
| { | |
| 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_id = _bfd_section_id; | |
| preserve->section_htab = abfd->section_htab; | |
| preserve->marker = bfd_alloc (abfd, 1); | |
| preserve->build_id = abfd->build_id; | |
| preserve->cleanup = cleanup; | |
| 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, unsigned int section_id, bfd_cleanup cleanup) | |
| { | |
| _bfd_section_id = section_id; | |
| if (cleanup) | |
| cleanup (abfd); | |
| abfd->tdata.any = NULL; | |
| abfd->arch_info = &bfd_default_arch_struct; | |
| abfd->flags &= BFD_FLAGS_SAVED; | |
| abfd->build_id = NULL; | |
| bfd_section_list_clear (abfd); | |
| } | |
| /* Restores bfd state saved by bfd_preserve_save. */ | |
| static bfd_cleanup | |
| 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_section_id = preserve->section_id; | |
| abfd->build_id = preserve->build_id; | |
| /* 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; | |
| return preserve->cleanup; | |
| } | |
| /* 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) | |
| { | |
| if (preserve->cleanup) | |
| { | |
| /* Run the cleanup, assuming that all it will need is the | |
| tdata at the time the cleanup was returned. */ | |
| void *tdata = abfd->tdata.any; | |
| abfd->tdata.any = preserve->tdata; | |
| preserve->cleanup (abfd); | |
| abfd->tdata.any = tdata; | |
| } | |
| /* 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 | |
| SYNOPSIS | |
| bool bfd_check_format_matches | |
| (bfd *abfd, bfd_format format, char ***matching); | |
| DESCRIPTION | |
| Like <<bfd_check_format>>, except when it returns FALSE with | |
| <<bfd_errno>> set to <<bfd_error_file_ambiguously_recognized>>. In that | |
| case, if @var{matching} is not NULL, it will be filled in with | |
| a NULL-terminated list of the names of the formats that matched, | |
| allocated with <<malloc>>. | |
| Then the user may choose a format and try again. | |
| When done with the list that @var{matching} points to, the caller | |
| should free it. | |
| */ | |
| bool | |
| bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching) | |
| { | |
| extern const bfd_target binary_vec; | |
| #if BFD_SUPPORTS_PLUGINS | |
| extern const bfd_target plugin_vec; | |
| #endif | |
| const bfd_target * const *target; | |
| const bfd_target **matching_vector = NULL; | |
| const bfd_target *save_targ, *right_targ, *ar_right_targ, *match_targ; | |
| int match_count, best_count, best_match; | |
| int ar_match_index; | |
| unsigned int initial_section_id = _bfd_section_id; | |
| struct bfd_preserve preserve, preserve_match; | |
| bfd_cleanup cleanup = NULL; | |
| if (matching != NULL) | |
| *matching = NULL; | |
| if (!bfd_read_p (abfd) | |
| || (unsigned int) abfd->format >= (unsigned int) bfd_type_end) | |
| { | |
| bfd_set_error (bfd_error_invalid_operation); | |
| return false; | |
| } | |
| if (abfd->format != bfd_unknown) | |
| return abfd->format == format; | |
| if (matching != NULL || *bfd_associated_vector != NULL) | |
| { | |
| size_t amt; | |
| amt = sizeof (*matching_vector) * 2 * _bfd_target_vector_entries; | |
| matching_vector = (const bfd_target **) bfd_malloc (amt); | |
| if (!matching_vector) | |
| return false; | |
| } | |
| /* Presume the answer is yes. */ | |
| abfd->format = format; | |
| save_targ = abfd->xvec; | |
| preserve_match.marker = NULL; | |
| if (!bfd_preserve_save (abfd, &preserve, NULL)) | |
| goto err_ret; | |
| /* If the target type was explicitly specified, just check that target. */ | |
| if (!abfd->target_defaulted) | |
| { | |
| if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) /* rewind! */ | |
| goto err_ret; | |
| cleanup = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd)); | |
| if (cleanup) | |
| goto ok_ret; | |
| /* For a long time the code has dropped through to check all | |
| targets if the specified target was wrong. I don't know why, | |
| and I'm reluctant to change it. However, in the case of an | |
| archive, it can cause problems. If the specified target does | |
| not permit archives (e.g., the binary target), then we should | |
| not allow some other target to recognize it as an archive, but | |
| should instead allow the specified target to recognize it as an | |
| object. When I first made this change, it broke the PE target, | |
| because the specified pei-i386 target did not recognize the | |
| actual pe-i386 archive. Since there may be other problems of | |
| this sort, I changed this test to check only for the binary | |
| target. */ | |
| if (format == bfd_archive && save_targ == &binary_vec) | |
| 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++) | |
| { | |
| void **high_water; | |
| /* The binary target matches anything, so don't return it when | |
| searching. Don't match the plugin target if we have another | |
| alternative since we want to properly set the input format | |
| before allowing a plugin to claim the file. Also, don't | |
| check the default target twice. */ | |
| if (*target == &binary_vec | |
| #if BFD_SUPPORTS_PLUGINS | |
| || (match_count != 0 && *target == &plugin_vec) | |
| #endif | |
| || (!abfd->target_defaulted && *target == save_targ)) | |
| continue; | |
| /* 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, initial_section_id, cleanup); | |
| /* Free bfd_alloc memory too. If we have matched and preserved | |
| a target then the high water mark is that much higher. */ | |
| if (preserve_match.marker) | |
| high_water = &preserve_match.marker; | |
| else | |
| high_water = &preserve.marker; | |
| bfd_release (abfd, *high_water); | |
| *high_water = bfd_alloc (abfd, 1); | |
| /* Change BFD's target temporarily. */ | |
| abfd->xvec = *target; | |
| if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) | |
| goto err_ret; | |
| cleanup = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd)); | |
| if (cleanup) | |
| { | |
| int match_priority = abfd->xvec->match_priority; | |
| #if BFD_SUPPORTS_PLUGINS | |
| /* If this object can be handled by a plugin, give that the | |
| lowest priority; objects both handled by a plugin and | |
| with an underlying object format will be claimed | |
| separately by the plugin. */ | |
| if (*target == &plugin_vec) | |
| match_priority = (*target)->match_priority; | |
| #endif | |
| if (abfd->format != bfd_archive | |
| || (bfd_has_map (abfd) | |
| && bfd_get_error () != bfd_error_wrong_object_format)) | |
| { | |
| /* If this is the default target, accept it, even if | |
| other targets might match. People who want those | |
| other targets have to set the GNUTARGET variable. */ | |
| if (abfd->xvec == bfd_default_vector[0]) | |
| goto ok_ret; | |
| if (matching_vector) | |
| matching_vector[match_count] = abfd->xvec; | |
| match_count++; | |
| if (match_priority < best_match) | |
| { | |
| best_match = match_priority; | |
| best_count = 0; | |
| } | |
| if (match_priority <= best_match) | |
| { | |
| /* This format checks out as ok! */ | |
| right_targ = abfd->xvec; | |
| best_count++; | |
| } | |
| } | |
| else | |
| { | |
| /* An archive with no armap or objects of the wrong | |
| type. We want this target to match if we get no | |
| better matches. */ | |
| if (ar_right_targ != bfd_default_vector[0]) | |
| ar_right_targ = *target; | |
| if (matching_vector) | |
| matching_vector[ar_match_index] = *target; | |
| ar_match_index++; | |
| } | |
| if (preserve_match.marker == NULL) | |
| { | |
| match_targ = abfd->xvec; | |
| if (!bfd_preserve_save (abfd, &preserve_match, cleanup)) | |
| goto err_ret; | |
| cleanup = NULL; | |
| } | |
| } | |
| } | |
| if (best_count == 1) | |
| match_count = 1; | |
| if (match_count == 0) | |
| { | |
| /* Try partial matches. */ | |
| right_targ = ar_right_targ; | |
| if (right_targ == bfd_default_vector[0]) | |
| { | |
| match_count = 1; | |
| } | |
| else | |
| { | |
| match_count = ar_match_index - _bfd_target_vector_entries; | |
| if (matching_vector && match_count > 1) | |
| memcpy (matching_vector, | |
| matching_vector + _bfd_target_vector_entries, | |
| sizeof (*matching_vector) * match_count); | |
| } | |
| } | |
| /* We have more than one equally good match. If any of the best | |
| matches is a target in config.bfd targ_defvec or targ_selvecs, | |
| choose it. */ | |
| if (match_count > 1) | |
| { | |
| const bfd_target * const *assoc = bfd_associated_vector; | |
| while ((right_targ = *assoc++) != NULL) | |
| { | |
| int i = match_count; | |
| while (--i >= 0) | |
| if (matching_vector[i] == right_targ | |
| && right_targ->match_priority <= best_match) | |
| break; | |
| if (i >= 0) | |
| { | |
| match_count = 1; | |
| break; | |
| } | |
| } | |
| } | |
| /* We still have more than one equally good match, and at least some | |
| of the targets support match priority. Choose the first of the | |
| best matches. */ | |
| if (matching_vector && match_count > 1 && best_count != match_count) | |
| { | |
| int i; | |
| for (i = 0; i < match_count; i++) | |
| { | |
| right_targ = matching_vector[i]; | |
| if (right_targ->match_priority <= best_match) | |
| break; | |
| } | |
| match_count = 1; | |
| } | |
| /* 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_match.marker != NULL) | |
| cleanup = bfd_preserve_restore (abfd, &preserve_match); | |
| if (match_count == 1) | |
| { | |
| abfd->xvec = right_targ; | |
| /* If we come out of the loop knowing that the last target that | |
| matched is the one we want, then ABFD should still be in a usable | |
| state (except possibly for XVEC). This is not just an | |
| optimisation. In the case of plugins a match against the | |
| plugin target can result in the bfd being changed such that | |
| it no longer matches the plugin target, nor will it match | |
| RIGHT_TARG again. */ | |
| if (match_targ != right_targ) | |
| { | |
| bfd_reinit (abfd, initial_section_id, cleanup); | |
| bfd_release (abfd, preserve.marker); | |
| if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) | |
| goto err_ret; | |
| cleanup = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd)); | |
| BFD_ASSERT (cleanup != NULL); | |
| } | |
| ok_ret: | |
| /* If the file was opened for update, then `output_has_begun' | |
| some time ago when the file was created. Do not recompute | |
| sections sizes or alignments in _bfd_set_section_contents. | |
| We can not set this flag until after checking the format, | |
| because it will interfere with creation of BFD sections. */ | |
| if (abfd->direction == both_direction) | |
| abfd->output_has_begun = true; | |
| free (matching_vector); | |
| if (preserve_match.marker != NULL) | |
| bfd_preserve_finish (abfd, &preserve_match); | |
| bfd_preserve_finish (abfd, &preserve); | |
| /* File position has moved, BTW. */ | |
| return true; | |
| } | |
| if (match_count == 0) | |
| { | |
| err_unrecog: | |
| bfd_set_error (bfd_error_file_not_recognized); | |
| err_ret: | |
| if (cleanup) | |
| cleanup (abfd); | |
| abfd->xvec = save_targ; | |
| abfd->format = bfd_unknown; | |
| free (matching_vector); | |
| if (preserve_match.marker != NULL) | |
| bfd_preserve_finish (abfd, &preserve_match); | |
| bfd_preserve_restore (abfd, &preserve); | |
| return false; | |
| } | |
| /* Restore original target type and format. */ | |
| abfd->xvec = save_targ; | |
| abfd->format = bfd_unknown; | |
| bfd_set_error (bfd_error_file_ambiguously_recognized); | |
| if (matching) | |
| { | |
| *matching = (char **) matching_vector; | |
| matching_vector[match_count] = NULL; | |
| /* Return target names. This is a little nasty. Maybe we | |
| should do another bfd_malloc? */ | |
| while (--match_count >= 0) | |
| { | |
| const char *name = matching_vector[match_count]->name; | |
| *(const char **) &matching_vector[match_count] = name; | |
| } | |
| } | |
| else | |
| free (matching_vector); | |
| if (cleanup) | |
| cleanup (abfd); | |
| if (preserve_match.marker != NULL) | |
| bfd_preserve_finish (abfd, &preserve_match); | |
| bfd_preserve_restore (abfd, &preserve); | |
| return false; | |
| } | |
| /* | |
| FUNCTION | |
| bfd_set_format | |
| SYNOPSIS | |
| bool bfd_set_format (bfd *abfd, bfd_format format); | |
| DESCRIPTION | |
| This function sets the file format of the BFD @var{abfd} to the | |
| format @var{format}. If the target set in the BFD does not | |
| support the format requested, the format is invalid, or the BFD | |
| is not open for writing, then an error occurs. | |
| */ | |
| bool | |
| bfd_set_format (bfd *abfd, bfd_format format) | |
| { | |
| if (bfd_read_p (abfd) | |
| || (unsigned int) abfd->format >= (unsigned int) bfd_type_end) | |
| { | |
| bfd_set_error (bfd_error_invalid_operation); | |
| return false; | |
| } | |
| if (abfd->format != bfd_unknown) | |
| return abfd->format == format; | |
| /* Presume the answer is yes. */ | |
| abfd->format = format; | |
| if (!BFD_SEND_FMT (abfd, _bfd_set_format, (abfd))) | |
| { | |
| abfd->format = bfd_unknown; | |
| return false; | |
| } | |
| return true; | |
| } | |
| /* | |
| FUNCTION | |
| bfd_format_string | |
| SYNOPSIS | |
| const char *bfd_format_string (bfd_format format); | |
| DESCRIPTION | |
| Return a pointer to a const string | |
| <<invalid>>, <<object>>, <<archive>>, <<core>>, or <<unknown>>, | |
| depending upon the value of @var{format}. | |
| */ | |
| const char * | |
| bfd_format_string (bfd_format format) | |
| { | |
| if (((int) format < (int) bfd_unknown) | |
| || ((int) format >= (int) bfd_type_end)) | |
| return "invalid"; | |
| switch (format) | |
| { | |
| case bfd_object: | |
| return "object"; /* Linker/assembler/compiler output. */ | |
| case bfd_archive: | |
| return "archive"; /* Object archive file. */ | |
| case bfd_core: | |
| return "core"; /* Core dump. */ | |
| default: | |
| return "unknown"; | |
| } | |
| } |