diff options
author | Nick Clifton <nickc@redhat.com> | 2002-12-03 18:24:33 +0000 |
---|---|---|
committer | Nick Clifton <nickc@redhat.com> | 2002-12-03 18:24:33 +0000 |
commit | e1a9cb8e15a2f05592910ee3e27dacf7fbee68b0 (patch) | |
tree | c4886077fcbfbe0e648140c236aa9ffa1c40b817 /bfd | |
parent | a823923bf657b448ef2ef71ab7b8fad2f31cd818 (diff) | |
download | gdb-e1a9cb8e15a2f05592910ee3e27dacf7fbee68b0.zip gdb-e1a9cb8e15a2f05592910ee3e27dacf7fbee68b0.tar.gz gdb-e1a9cb8e15a2f05592910ee3e27dacf7fbee68b0.tar.bz2 |
Fix the merging of .PPC.EMB.apuinfo sections. Add a test to make sure that
the fix continues to work.
Diffstat (limited to 'bfd')
-rw-r--r-- | bfd/ChangeLog | 20 | ||||
-rw-r--r-- | bfd/elf32-ppc.c | 300 |
2 files changed, 320 insertions, 0 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 57d7ee9..c16c741 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,23 @@ +2002-12-03 Nick Clifton <nickc@redhat.com> + + * elf32-ppc.c (apuinfo_list_init): New function. + (apuinfo_list_add): New function: Add a value to the list. + (apuinfo_list_length): New function: Return the number of + values on the list. + (apuinfo_list_element): New function: Return a value on the + list. + (apuinfo_list_finish): New function: Free the resources used + by the list. + (ppc_elf_begin_write_processing): New function. Scan the + input bfds for apuinfo sections. + (ppc_elf_write_section): New function: Delay the creation of + the contents of an apuinfo section in an output bfd. + (ppc_elf_final_write_processing): New function. Create the + contents of an apuinfo section in an output bfd. + (elf_backend_begin_write_processing): Define. + (elf_backend_final_write_processing): Define. + (elf_backend_write_section): Define. + 2002-12-03 Richard Henderson <rth@redhat.com> * cpu-ia64-opc.c (elf64_ia64_operands): Add ldxmov entry. diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c index 0c33a90..c117f54 100644 --- a/bfd/elf32-ppc.c +++ b/bfd/elf32-ppc.c @@ -3783,6 +3783,303 @@ ppc_elf_grok_psinfo (abfd, note) return TRUE; } +/* Very simple linked list structure for recording apuinfo values. */ +typedef struct apuinfo_list +{ + struct apuinfo_list * next; + unsigned long value; +} +apuinfo_list; + +static apuinfo_list * head; + +static void apuinfo_list_init PARAMS ((void)); +static void apuinfo_list_add PARAMS ((unsigned long)); +static unsigned apuinfo_list_length PARAMS ((void)); +static unsigned long apuinfo_list_element PARAMS ((unsigned long)); +static void apuinfo_list_finish PARAMS ((void)); + +extern void ppc_elf_begin_write_processing + PARAMS ((bfd *, struct bfd_link_info *)); +extern void ppc_elf_final_write_processing + PARAMS ((bfd *, bfd_boolean)); +extern bfd_boolean ppc_elf_write_section + PARAMS ((bfd *, asection *, bfd_byte *)); + + + +static void +apuinfo_list_init PARAMS ((void)) +{ + head = NULL; +} + +static void +apuinfo_list_add (value) + unsigned long value; +{ + apuinfo_list * entry = head; + + while (entry != NULL) + { + if (entry->value == value) + return; + entry = entry->next; + } + + entry = bfd_malloc (sizeof (* entry)); + if (entry == NULL) + return; + + entry->value = value; + entry->next = head; + head = entry; +} + +static unsigned +apuinfo_list_length PARAMS ((void)) +{ + apuinfo_list * entry; + unsigned long count; + + for (entry = head, count = 0; + entry; + entry = entry->next) + ++ count; + + return count; +} + +static inline unsigned long +apuinfo_list_element (number) + unsigned long number; +{ + apuinfo_list * entry; + + for (entry = head; + entry && number --; + entry = entry->next) + ; + + return entry ? entry->value : 0; +} + +static void +apuinfo_list_finish PARAMS ((void)) +{ + apuinfo_list * entry; + + for (entry = head; entry;) + { + apuinfo_list * next = entry->next; + free (entry); + entry = next; + } + + head = NULL; +} + +#define APUINFO_SECTION_NAME ".PPC.EMB.apuinfo" +#define APUINFO_LABEL "APUinfo" + +/* Scan the input BFDs and create a linked list of + the APUinfo values that will need to be emitted. */ + +void +ppc_elf_begin_write_processing (abfd, link_info) + bfd *abfd; + struct bfd_link_info *link_info; +{ + bfd * ibfd; + asection * asec; + char * buffer; + unsigned num_input_sections; + bfd_size_type output_section_size; + unsigned i; + unsigned num_entries; + unsigned long offset; + unsigned long length; + const char * error_message = NULL; + + /* Scan the input bfds, looking for apuinfo sections. */ + num_input_sections = 0; + output_section_size = 0; + + for (ibfd = link_info->input_bfds; ibfd; ibfd = ibfd->link_next) + { + asec = bfd_get_section_by_name (ibfd, APUINFO_SECTION_NAME); + if (asec) + { + ++ num_input_sections; + output_section_size += asec->_raw_size; + } + } + + /* We need at least one input sections + in order to make merging worthwhile. */ + if (num_input_sections < 1) + return; + + /* Just make sure that the output section exists as well. */ + asec = bfd_get_section_by_name (abfd, APUINFO_SECTION_NAME); + if (asec == NULL) + return; + + /* Allocate a buffer for the contents of the input sections. */ + buffer = bfd_malloc (output_section_size); + if (buffer == NULL) + return; + + offset = 0; + apuinfo_list_init (); + + /* Read in the input sections contents. */ + for (ibfd = link_info->input_bfds; ibfd; ibfd = ibfd->link_next) + { + unsigned long datum; + char * ptr; + + + asec = bfd_get_section_by_name (ibfd, APUINFO_SECTION_NAME); + if (asec == NULL) + continue; + + length = asec->_raw_size; + if (length < 24) + { + error_message = _("corrupt or empty %s section in %s"); + goto fail; + } + + if (bfd_seek (ibfd, asec->filepos, SEEK_SET) != 0 + || (bfd_bread (buffer + offset, length, ibfd) != length)) + { + error_message = _("unable to read in %s section from %s"); + goto fail; + } + + /* Process the contents of the section. */ + ptr = buffer + offset; + error_message = _("corrupt %s section in %s"); + + /* Verify the contents of the header. Note - we have to + extract the values this way in order to allow for a + host whose endian-ness is different from the target. */ + datum = bfd_get_32 (ibfd, ptr); + if (datum != sizeof APUINFO_LABEL) + goto fail; + + datum = bfd_get_32 (ibfd, ptr + 8); + if (datum != 0x2) + goto fail; + + if (strcmp (ptr + 12, APUINFO_LABEL) != 0) + goto fail; + + /* Get the number of apuinfo entries. */ + datum = bfd_get_32 (ibfd, ptr + 4); + if ((datum * 4 + 20) != length) + goto fail; + + /* Make sure that we do not run off the end of the section. */ + if (offset + length > output_section_size) + goto fail; + + /* Scan the apuinfo section, building a list of apuinfo numbers. */ + for (i = 0; i < datum; i++) + apuinfo_list_add (bfd_get_32 (ibfd, ptr + 20 + (i * 4))); + + /* Update the offset. */ + offset += length; + } + + error_message = NULL; + + /* Compute the size of the output section. */ + num_entries = apuinfo_list_length (); + output_section_size = 20 + num_entries * 4; + + asec = bfd_get_section_by_name (abfd, APUINFO_SECTION_NAME); + + if (! bfd_set_section_size (abfd, asec, output_section_size)) + ibfd = abfd, + error_message = _("warning: unable to set size of %s section in %s"); + + fail: + free (buffer); + + if (error_message) + _bfd_error_handler (error_message, APUINFO_SECTION_NAME, + bfd_archive_filename (ibfd)); +} + + +/* Prevent the output section from accumulating the input sections' + contents. We have already stored this in our linked list structure. */ + +bfd_boolean +ppc_elf_write_section (abfd, asec, contents) + bfd * abfd ATTRIBUTE_UNUSED; + asection * asec; + bfd_byte * contents ATTRIBUTE_UNUSED; +{ + return strcmp (asec->name, APUINFO_SECTION_NAME) == 0; +} + + +/* Finally we can generate the output section. */ + +void +ppc_elf_final_write_processing (abfd, linker) + bfd * abfd; + bfd_boolean linker ATTRIBUTE_UNUSED; +{ + bfd_byte * buffer; + asection * asec; + unsigned i; + unsigned num_entries; + bfd_size_type length; + + asec = bfd_get_section_by_name (abfd, APUINFO_SECTION_NAME); + if (asec == NULL) + return; + + length = asec->_raw_size; + if (length < 20) + return; + + buffer = bfd_malloc (length); + if (buffer == NULL) + { + _bfd_error_handler (_("failed to allocate space for new APUinfo section.")); + return; + } + + /* Create the apuinfo header. */ + num_entries = apuinfo_list_length (); + bfd_put_32 (abfd, sizeof APUINFO_LABEL, buffer); + bfd_put_32 (abfd, num_entries, buffer + 4); + bfd_put_32 (abfd, 0x2, buffer + 8); + strcpy (buffer + 12, APUINFO_LABEL); + + length = 20; + for (i = 0; i < num_entries; i++) + { + bfd_put_32 (abfd, apuinfo_list_element (i), buffer + length); + length += 4; + } + + if (length != asec->_raw_size) + _bfd_error_handler (_("failed to compute new APUinfo section.")); + + if (! bfd_set_section_contents (abfd, asec, buffer, (file_ptr) 0, length)) + _bfd_error_handler (_("failed to install new APUinfo section.")); + + free (buffer); + + apuinfo_list_finish (); +} + #define TARGET_LITTLE_SYM bfd_elf32_powerpcle_vec #define TARGET_LITTLE_NAME "elf32-powerpcle" #define TARGET_BIG_SYM bfd_elf32_powerpc_vec @@ -3832,5 +4129,8 @@ ppc_elf_grok_psinfo (abfd, note) #define elf_backend_grok_prstatus ppc_elf_grok_prstatus #define elf_backend_grok_psinfo ppc_elf_grok_psinfo #define elf_backend_reloc_type_class ppc_elf_reloc_type_class +#define elf_backend_begin_write_processing ppc_elf_begin_write_processing +#define elf_backend_final_write_processing ppc_elf_final_write_processing +#define elf_backend_write_section ppc_elf_write_section #include "elf32-target.h" |