+/* When defaulting arch/mach, decode apuinfo to find a better match. */
+
+bfd_boolean
+_bfd_elf_ppc_set_arch (bfd *abfd)
+{
+ unsigned long mach = 0;
+ asection *s;
+ unsigned char *contents;
+
+ if (abfd->arch_info->bits_per_word == 32
+ && bfd_big_endian (abfd))
+ {
+
+ for (s = abfd->sections; s != NULL; s = s->next)
+ if ((elf_section_data (s)->this_hdr.sh_flags & SHF_PPC_VLE) != 0)
+ break;
+ if (s != NULL)
+ mach = bfd_mach_ppc_vle;
+ }
+
+ if (mach == 0)
+ {
+ s = bfd_get_section_by_name (abfd, APUINFO_SECTION_NAME);
+ if (s != NULL && bfd_malloc_and_get_section (abfd, s, &contents))
+ {
+ unsigned int apuinfo_size = bfd_get_32 (abfd, contents + 4);
+ unsigned int i;
+
+ for (i = 20; i < apuinfo_size + 20 && i + 4 <= s->size; i += 4)
+ {
+ unsigned int val = bfd_get_32 (abfd, contents + i);
+ switch (val >> 16)
+ {
+ case PPC_APUINFO_PMR:
+ case PPC_APUINFO_RFMCI:
+ if (mach == 0)
+ mach = bfd_mach_ppc_titan;
+ break;
+
+ case PPC_APUINFO_ISEL:
+ case PPC_APUINFO_CACHELCK:
+ if (mach == bfd_mach_ppc_titan)
+ mach = bfd_mach_ppc_e500mc;
+ break;
+
+ case PPC_APUINFO_SPE:
+ case PPC_APUINFO_EFS:
+ case PPC_APUINFO_BRLOCK:
+ if (mach != bfd_mach_ppc_vle)
+ mach = bfd_mach_ppc_e500;
+
+ case PPC_APUINFO_VLE:
+ mach = bfd_mach_ppc_vle;
+ break;
+
+ default:
+ mach = -1ul;
+ }
+ }
+ free (contents);
+ }
+ }
+
+ if (mach != 0 && mach != -1ul)
+ {
+ const bfd_arch_info_type *arch;
+
+ for (arch = abfd->arch_info->next; arch; arch = arch->next)
+ if (arch->mach == mach)
+ {
+ abfd->arch_info = arch;
+ break;
+ }
+ }
+ return TRUE;
+}
+