diff options
author | Nick Clifton <nickc@redhat.com> | 2016-04-29 09:24:42 +0100 |
---|---|---|
committer | Nick Clifton <nickc@redhat.com> | 2016-04-29 09:24:42 +0100 |
commit | 5522f910cb539905d6adfdceab208ddfa5e84557 (patch) | |
tree | 0e266a54bdd71c153b10e11319699d78350b6c33 /bfd/elf.c | |
parent | 2deb93c7a7708ed164e4b10afb9d6a885d4615c6 (diff) | |
download | gdb-5522f910cb539905d6adfdceab208ddfa5e84557.zip gdb-5522f910cb539905d6adfdceab208ddfa5e84557.tar.gz gdb-5522f910cb539905d6adfdceab208ddfa5e84557.tar.bz2 |
Enhance support for copying and stripping Solaris and ARM binaries.
PR 19938
bfd * elf-bfd.h (struct elf_backend_data): Rename
elf_backend_set_special_section_info_and_link to
elf_backend_copy_special_section_fields.
* elfxx-target.h: Likewise.
* elf.c (section_match): Ignore the SHF_INFO_LINK flag when
comparing section flags.
(copy_special_section_fields): New function.
(_bfd_elf_copy_private_bfd_data): Copy the EI_ABIVERSION field.
Perform two scans over special sections. The first one looks for
a direct mapping between the output section and an input section.
The second scan looks for a possible match based upon section
characteristics.
* elf32-arm.c (elf32_arm_copy_special_section_fields): New
function. Handle setting the sh_link field of SHT_ARM_EXIDX
sections.
* elf32-i386.c (elf32_i386_set_special_info_link): Rename to
elf32_i386_copy_solaris_special_section_fields.
* elf32-sparc.c (elf32_sparc_set_special_section_info_link):
Rename to elf32_sparc_copy_solaris_special_section_fields.
* elf64-x86-64.c (elf64_x86_64_set_special_info_link): Rename to
elf64_x86_64_copy_solaris_special_section_fields.
binutils* readelf.c (get_solaris_segment_type): New function.
(get_segment_type): Call it.
Diffstat (limited to 'bfd/elf.c')
-rw-r--r-- | bfd/elf.c | 268 |
1 files changed, 165 insertions, 103 deletions
@@ -1218,11 +1218,13 @@ bfd_elf_generic_reloc (bfd *abfd ATTRIBUTE_UNUSED, should be the same. */ static bfd_boolean -section_match (Elf_Internal_Shdr * a, Elf_Internal_Shdr * b) +section_match (const Elf_Internal_Shdr * a, + const Elf_Internal_Shdr * b) { return a->sh_type == b->sh_type - && a->sh_flags == b->sh_flags + && (a->sh_flags & ~ SHF_INFO_LINK) + == (b->sh_flags & ~ SHF_INFO_LINK) && a->sh_addralign == b->sh_addralign && a->sh_size == b->sh_size && a->sh_entsize == b->sh_entsize @@ -1236,7 +1238,7 @@ section_match (Elf_Internal_Shdr * a, Elf_Internal_Shdr * b) to be the correct section. */ static unsigned int -find_link (bfd * obfd, Elf_Internal_Shdr * iheader, unsigned int hint) +find_link (const bfd * obfd, const Elf_Internal_Shdr * iheader, const unsigned int hint) { Elf_Internal_Shdr ** oheaders = elf_elfsections (obfd); unsigned int i; @@ -1257,14 +1259,110 @@ find_link (bfd * obfd, Elf_Internal_Shdr * iheader, unsigned int hint) return SHN_UNDEF; } +/* PR 19938: Attempt to set the ELF section header fields of an OS or + Processor specific section, based upon a matching input section. + Returns TRUE upon success, FALSE otherwise. */ + +static bfd_boolean +copy_special_section_fields (const bfd *ibfd, + bfd *obfd, + const Elf_Internal_Shdr *iheader, + Elf_Internal_Shdr *oheader, + const unsigned int secnum) +{ + const struct elf_backend_data *bed = get_elf_backend_data (obfd); + const Elf_Internal_Shdr **iheaders = (const Elf_Internal_Shdr **) elf_elfsections (ibfd); + bfd_boolean changed = FALSE; + unsigned int sh_link; + + if (oheader->sh_type == SHT_NOBITS) + { + /* This is a feature for objcopy --only-keep-debug: + When a section's type is changed to NOBITS, we preserve + the sh_link and sh_info fields so that they can be + matched up with the original. + + Note: Strictly speaking these assignments are wrong. + The sh_link and sh_info fields should point to the + relevent sections in the output BFD, which may not be in + the same location as they were in the input BFD. But + the whole point of this action is to preserve the + original values of the sh_link and sh_info fields, so + that they can be matched up with the section headers in + the original file. So strictly speaking we may be + creating an invalid ELF file, but it is only for a file + that just contains debug info and only for sections + without any contents. */ + if (oheader->sh_link == 0) + oheader->sh_link = iheader->sh_link; + if (oheader->sh_info == 0) + oheader->sh_info = iheader->sh_info; + return TRUE; + } + + /* Allow the target a chance to decide how these fields should be set. */ + if (bed->elf_backend_copy_special_section_fields != NULL + && bed->elf_backend_copy_special_section_fields + (ibfd, obfd, iheader, oheader)) + return TRUE; + + /* We have an iheader which might match oheader, and which has non-zero + sh_info and/or sh_link fields. Attempt to follow those links and find + the section in the output bfd which corresponds to the linked section + in the input bfd. */ + if (iheader->sh_link != SHN_UNDEF) + { + sh_link = find_link (obfd, iheaders[iheader->sh_link], iheader->sh_link); + if (sh_link != SHN_UNDEF) + { + oheader->sh_link = sh_link; + changed = TRUE; + } + else + /* FIXME: Should we install iheader->sh_link + if we could not find a match ? */ + (* _bfd_error_handler) + (_("%B: Failed to find link section for section %d"), obfd, secnum); + } + + if (iheader->sh_info) + { + /* The sh_info field can hold arbitrary information, but if the + SHF_LINK_INFO flag is set then it should be interpreted as a + section index. */ + if (iheader->sh_flags & SHF_INFO_LINK) + { + sh_link = find_link (obfd, iheaders[iheader->sh_info], + iheader->sh_info); + if (sh_link != SHN_UNDEF) + oheader->sh_flags |= SHF_INFO_LINK; + } + else + /* No idea what it means - just copy it. */ + sh_link = iheader->sh_info; + + if (sh_link != SHN_UNDEF) + { + oheader->sh_info = sh_link; + changed = TRUE; + } + else + (* _bfd_error_handler) + (_("%B: Failed to find info section for section %d"), obfd, secnum); + } + + return changed; +} + /* Copy the program header and other data from one object module to another. */ bfd_boolean _bfd_elf_copy_private_bfd_data (bfd *ibfd, bfd *obfd) { - Elf_Internal_Shdr ** iheaders = elf_elfsections (ibfd); - Elf_Internal_Shdr ** oheaders = elf_elfsections (obfd); + const Elf_Internal_Shdr **iheaders = (const Elf_Internal_Shdr **) elf_elfsections (ibfd); + Elf_Internal_Shdr **oheaders = elf_elfsections (obfd); + const struct elf_backend_data *bed; unsigned int i; if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour @@ -1283,39 +1381,84 @@ _bfd_elf_copy_private_bfd_data (bfd *ibfd, bfd *obfd) elf_elfheader (obfd)->e_ident[EI_OSABI] = elf_elfheader (ibfd)->e_ident[EI_OSABI]; + /* If set, copy the EI_ABIVERSION field. */ + if (elf_elfheader (ibfd)->e_ident[EI_ABIVERSION]) + elf_elfheader (obfd)->e_ident[EI_ABIVERSION] + = elf_elfheader (ibfd)->e_ident[EI_ABIVERSION]; + /* Copy object attributes. */ _bfd_elf_copy_obj_attributes (ibfd, obfd); if (iheaders == NULL || oheaders == NULL) return TRUE; - /* Possibly copy the sh_info and sh_link fields. */ + bed = get_elf_backend_data (obfd); + + /* Possibly copy other fields in the section header. */ for (i = 1; i < elf_numsections (obfd); i++) { unsigned int j; Elf_Internal_Shdr * oheader = oheaders[i]; + /* Ignore ordinary sections. SHT_NOBITS sections are considered however + because of a special case need for generating separate debug info + files. See below for more details. */ if (oheader == NULL || (oheader->sh_type != SHT_NOBITS - && oheader->sh_type < SHT_LOOS) - || oheader->sh_size == 0 + && oheader->sh_type < SHT_LOOS)) + continue; + + /* Ignore empty sections, and sections whose + fields have already been initialised. */ + if (oheader->sh_size == 0 || (oheader->sh_info != 0 && oheader->sh_link != 0)) continue; /* Scan for the matching section in the input bfd. - FIXME: We could use something better than a linear scan here. + First we try for a direct mapping between the input and output sections. */ + for (j = 1; j < elf_numsections (ibfd); j++) + { + const Elf_Internal_Shdr * iheader = iheaders[j]; + + if (iheader == NULL) + continue; + + if (oheader->bfd_section != NULL + && iheader->bfd_section != NULL + && iheader->bfd_section->output_section != NULL + && iheader->bfd_section->output_section == oheader->bfd_section) + { + /* We have found a connection from the input section to the + output section. Attempt to copy the header fields. If + this fails then do not try any further sections - there + should only be a one-to-one mapping between input and output. */ + if (! copy_special_section_fields (ibfd, obfd, iheader, oheader, i)) + j = elf_numsections (ibfd); + break; + } + } + + if (j < elf_numsections (ibfd)) + continue; + + /* That failed. So try to deduce the corresponding input section. Unfortunately we cannot compare names as the output string table is empty, so instead we check size, address and type. */ for (j = 1; j < elf_numsections (ibfd); j++) { - Elf_Internal_Shdr * iheader = iheaders[j]; + const Elf_Internal_Shdr * iheader = iheaders[j]; + + if (iheader == NULL) + continue; - /* Since --only-keep-debug turns all non-debug sections into + /* Try matching fields in the input section's header. + Since --only-keep-debug turns all non-debug sections into SHT_NOBITS sections, the output SHT_NOBITS type matches any input type. */ if ((oheader->sh_type == SHT_NOBITS || iheader->sh_type == oheader->sh_type) - && iheader->sh_flags == oheader->sh_flags + && (iheader->sh_flags & ~ SHF_INFO_LINK) + == (oheader->sh_flags & ~ SHF_INFO_LINK) && iheader->sh_addralign == oheader->sh_addralign && iheader->sh_entsize == oheader->sh_entsize && iheader->sh_size == oheader->sh_size @@ -1323,99 +1466,18 @@ _bfd_elf_copy_private_bfd_data (bfd *ibfd, bfd *obfd) && (iheader->sh_info != oheader->sh_info || iheader->sh_link != oheader->sh_link)) { - /* PR 19938: Attempt to preserve the sh_link and sh_info fields - of OS and Processor specific sections. We try harder for - these sections, because this is not just about matching - stripped binaries to their originals. */ - if (oheader->sh_type >= SHT_LOOS) - { - const struct elf_backend_data *bed = get_elf_backend_data (obfd); - bfd_boolean changed = FALSE; - unsigned int sh_link; - - /* Allow the target a chance to decide how these fields should - be set. */ - if (bed->elf_backend_set_special_section_info_and_link != NULL - && bed->elf_backend_set_special_section_info_and_link - (ibfd, obfd, iheader, oheader)) - break; - - /* We have iheader which matches oheader, but which has - non-zero sh_info and/or sh_link fields. Attempt to - follow those links and find the section in the output - bfd which corresponds to the linked section in the input - bfd. */ - if (iheader->sh_link != SHN_UNDEF) - { - sh_link = find_link (obfd, - iheaders[iheader->sh_link], - iheader->sh_link); - if (sh_link != SHN_UNDEF) - { - oheader->sh_link = sh_link; - changed = TRUE; - } - else - /* FIXME: Should we install iheader->sh_link - if we could not find a match ? */ - (* _bfd_error_handler) - (_("%B: Failed to find link section for section %d"), - obfd, i); - } - - if (iheader->sh_info) - { - /* The sh_info field can hold arbitrary information, - but if the SHF_LINK_INFO flag is set then it - should be interpreted as a section index. */ - if (iheader->sh_flags & SHF_INFO_LINK) - sh_link = find_link (obfd, - iheaders[iheader->sh_info], - iheader->sh_info); - else - /* No idea what it means - just copy it. */ - sh_link = iheader->sh_info; - - if (sh_link != SHN_UNDEF) - { - oheader->sh_info = sh_link; - changed = TRUE; - } - else - (* _bfd_error_handler) - (_("%B: Failed to find info section for section %d"), - obfd, i); - } - - if (changed) - break; - } - else - { - /* This is an feature for objcopy --only-keep-debug: - When a section's type is changed to NOBITS, we preserve - the sh_link and sh_info fields so that they can be - matched up with the original. - - Note: Strictly speaking these assignments are wrong. - The sh_link and sh_info fields should point to the - relevent sections in the output BFD, which may not be in - the same location as they were in the input BFD. But - the whole point of this action is to preserve the - original values of the sh_link and sh_info fields, so - that they can be matched up with the section headers in - the original file. So strictly speaking we may be - creating an invalid ELF file, but it is only for a file - that just contains debug info and only for sections - without any contents. */ - if (oheader->sh_link == 0) - oheader->sh_link = iheader->sh_link; - if (oheader->sh_info == 0) - oheader->sh_info = iheader->sh_info; - break; - } + if (copy_special_section_fields (ibfd, obfd, iheader, oheader, i)) + break; } } + + if (j == elf_numsections (ibfd) && oheader->sh_type >= SHT_LOOS) + { + /* Final attempt. Call the backend copy function + with a NULL input section. */ + if (bed->elf_backend_copy_special_section_fields != NULL) + bed->elf_backend_copy_special_section_fields (ibfd, obfd, NULL, oheader); + } } return TRUE; |