Update gdb.base/default.exp for GDB 10
[deliverable/binutils-gdb.git] / bfd / elf-attrs.c
index d1a64f4bed93c1a61baaef840540e1b715bcfd6a..bfe135e7fbb6179b6d4c28436f31dcbd4a36de01 100644 (file)
@@ -1,12 +1,11 @@
 /* ELF attributes support (based on ARM EABI attributes).
 /* ELF attributes support (based on ARM EABI attributes).
-   Copyright 2005, 2006, 2007
-   Free Software Foundation, Inc.
+   Copyright (C) 2005-2019 Free Software Foundation, Inc.
 
    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
 
    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 2 of the License, or
+   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,
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
@@ -16,7 +15,8 @@
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
 
    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.  */
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
 
 #include "sysdep.h"
 #include "bfd.h"
 
 #include "sysdep.h"
 #include "bfd.h"
@@ -42,9 +42,13 @@ uleb128_size (unsigned int i)
 static bfd_boolean
 is_default_attr (obj_attribute *attr)
 {
 static bfd_boolean
 is_default_attr (obj_attribute *attr)
 {
-  if ((attr->type & 1) && attr->i != 0)
+  if (ATTR_TYPE_HAS_ERROR (attr->type))
+    return TRUE;
+  if (ATTR_TYPE_HAS_INT_VAL (attr->type) && attr->i != 0)
     return FALSE;
     return FALSE;
-  if ((attr->type & 2) && attr->s && *attr->s)
+  if (ATTR_TYPE_HAS_STR_VAL (attr->type) && attr->s && *attr->s)
+    return FALSE;
+  if (ATTR_TYPE_HAS_NO_DEFAULT (attr->type))
     return FALSE;
 
   return TRUE;
     return FALSE;
 
   return TRUE;
@@ -52,7 +56,7 @@ is_default_attr (obj_attribute *attr)
 
 /* Return the size of a single attribute.  */
 static bfd_vma
 
 /* Return the size of a single attribute.  */
 static bfd_vma
-obj_attr_size (int tag, obj_attribute *attr)
+obj_attr_size (unsigned int tag, obj_attribute *attr)
 {
   bfd_vma size;
 
 {
   bfd_vma size;
 
@@ -60,9 +64,9 @@ obj_attr_size (int tag, obj_attribute *attr)
     return 0;
 
   size = uleb128_size (tag);
     return 0;
 
   size = uleb128_size (tag);
-  if (attr->type & 1)
+  if (ATTR_TYPE_HAS_INT_VAL (attr->type))
     size += uleb128_size (attr->i);
     size += uleb128_size (attr->i);
-  if (attr->type & 2)
+  if (ATTR_TYPE_HAS_STR_VAL (attr->type))
     size += strlen ((char *)attr->s) + 1;
   return size;
 }
     size += strlen ((char *)attr->s) + 1;
   return size;
 }
@@ -93,7 +97,7 @@ vendor_obj_attr_size (bfd *abfd, int vendor)
 
   attr = elf_known_obj_attributes (abfd)[vendor];
   size = 0;
 
   attr = elf_known_obj_attributes (abfd)[vendor];
   size = 0;
-  for (i = 4; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++)
+  for (i = LEAST_KNOWN_OBJ_ATTRIBUTE; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++)
     size += obj_attr_size (i, &attr[i]);
 
   for (list = elf_other_obj_attributes (abfd)[vendor];
     size += obj_attr_size (i, &attr[i]);
 
   for (list = elf_other_obj_attributes (abfd)[vendor];
@@ -102,7 +106,7 @@ vendor_obj_attr_size (bfd *abfd, int vendor)
     size += obj_attr_size (list->tag, &list->attr);
 
   /* <size> <vendor_name> NUL 0x1 <size> */
     size += obj_attr_size (list->tag, &list->attr);
 
   /* <size> <vendor_name> NUL 0x1 <size> */
-  return ((size || vendor == OBJ_ATTR_PROC)
+  return (size
          ? size + 10 + strlen (vendor_name)
          : 0);
 }
          ? size + 10 + strlen (vendor_name)
          : 0);
 }
@@ -141,16 +145,16 @@ write_uleb128 (bfd_byte *p, unsigned int val)
 /* Write attribute ATTR to butter P, and return a pointer to the following
    byte.  */
 static bfd_byte *
 /* Write attribute ATTR to butter P, and return a pointer to the following
    byte.  */
 static bfd_byte *
-write_obj_attribute (bfd_byte *p, int tag, obj_attribute *attr)
+write_obj_attribute (bfd_byte *p, unsigned int tag, obj_attribute *attr)
 {
   /* Suppress default entries.  */
   if (is_default_attr (attr))
     return p;
 
   p = write_uleb128 (p, tag);
 {
   /* Suppress default entries.  */
   if (is_default_attr (attr))
     return p;
 
   p = write_uleb128 (p, tag);
-  if (attr->type & 1)
+  if (ATTR_TYPE_HAS_INT_VAL (attr->type))
     p = write_uleb128 (p, attr->i);
     p = write_uleb128 (p, attr->i);
-  if (attr->type & 2)
+  if (ATTR_TYPE_HAS_STR_VAL (attr->type))
     {
       int len;
 
     {
       int len;
 
@@ -185,8 +189,13 @@ vendor_set_obj_attr_contents (bfd *abfd, bfd_byte *contents, bfd_vma size,
   p += 4;
 
   attr = elf_known_obj_attributes (abfd)[vendor];
   p += 4;
 
   attr = elf_known_obj_attributes (abfd)[vendor];
-  for (i = 4; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++)
-    p = write_obj_attribute (p, i, &attr[i]);
+  for (i = LEAST_KNOWN_OBJ_ATTRIBUTE; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++)
+    {
+      unsigned int tag = i;
+      if (get_elf_backend_data (abfd)->obj_attrs_order)
+       tag = get_elf_backend_data (abfd)->obj_attrs_order (i);
+      p = write_obj_attribute (p, tag, &attr[tag]);
+    }
 
   for (list = elf_other_obj_attributes (abfd)[vendor];
        list;
 
   for (list = elf_other_obj_attributes (abfd)[vendor];
        list;
@@ -220,7 +229,7 @@ bfd_elf_set_obj_attr_contents (bfd *abfd, bfd_byte *contents, bfd_vma size)
 
 /* Allocate/find an object attribute.  */
 static obj_attribute *
 
 /* Allocate/find an object attribute.  */
 static obj_attribute *
-elf_new_obj_attr (bfd *abfd, int vendor, int tag)
+elf_new_obj_attr (bfd *abfd, int vendor, unsigned int tag)
 {
   obj_attribute *attr;
   obj_attribute_list *list;
 {
   obj_attribute *attr;
   obj_attribute_list *list;
@@ -230,7 +239,7 @@ elf_new_obj_attr (bfd *abfd, int vendor, int tag)
 
   if (tag < NUM_KNOWN_OBJ_ATTRIBUTES)
     {
 
   if (tag < NUM_KNOWN_OBJ_ATTRIBUTES)
     {
-      /* Knwon tags are preallocated.  */
+      /* Known tags are preallocated.  */
       attr = &elf_known_obj_attributes (abfd)[vendor][tag];
     }
   else
       attr = &elf_known_obj_attributes (abfd)[vendor][tag];
     }
   else
@@ -258,13 +267,13 @@ elf_new_obj_attr (bfd *abfd, int vendor, int tag)
 
 /* Return the value of an integer object attribute.  */
 int
 
 /* Return the value of an integer object attribute.  */
 int
-bfd_elf_get_obj_attr_int (bfd *abfd, int vendor, int tag)
+bfd_elf_get_obj_attr_int (bfd *abfd, int vendor, unsigned int tag)
 {
   obj_attribute_list *p;
 
   if (tag < NUM_KNOWN_OBJ_ATTRIBUTES)
     {
 {
   obj_attribute_list *p;
 
   if (tag < NUM_KNOWN_OBJ_ATTRIBUTES)
     {
-      /* Knwon tags are preallocated.  */
+      /* Known tags are preallocated.  */
       return elf_known_obj_attributes (abfd)[vendor][tag].i;
     }
   else
       return elf_known_obj_attributes (abfd)[vendor][tag].i;
     }
   else
@@ -284,12 +293,12 @@ bfd_elf_get_obj_attr_int (bfd *abfd, int vendor, int tag)
 
 /* Add an integer object attribute.  */
 void
 
 /* Add an integer object attribute.  */
 void
-bfd_elf_add_obj_attr_int (bfd *abfd, int vendor, int tag, unsigned int i)
+bfd_elf_add_obj_attr_int (bfd *abfd, int vendor, unsigned int tag, unsigned int i)
 {
   obj_attribute *attr;
 
   attr = elf_new_obj_attr (abfd, vendor, tag);
 {
   obj_attribute *attr;
 
   attr = elf_new_obj_attr (abfd, vendor, tag);
-  attr->type = 1;
+  attr->type = _bfd_elf_obj_attrs_arg_type (abfd, vendor, tag);
   attr->i = i;
 }
 
   attr->i = i;
 }
 
@@ -299,53 +308,35 @@ _bfd_elf_attr_strdup (bfd *abfd, const char * s)
 {
   char * p;
   int len;
 {
   char * p;
   int len;
-  
+
   len = strlen (s) + 1;
   p = (char *) bfd_alloc (abfd, len);
   len = strlen (s) + 1;
   p = (char *) bfd_alloc (abfd, len);
-  return memcpy (p, s, len);
+  return (char *) memcpy (p, s, len);
 }
 
 /* Add a string object attribute.  */
 void
 }
 
 /* Add a string object attribute.  */
 void
-bfd_elf_add_obj_attr_string (bfd *abfd, int vendor, int tag, const char *s)
+bfd_elf_add_obj_attr_string (bfd *abfd, int vendor, unsigned int tag, const char *s)
 {
   obj_attribute *attr;
 
   attr = elf_new_obj_attr (abfd, vendor, tag);
 {
   obj_attribute *attr;
 
   attr = elf_new_obj_attr (abfd, vendor, tag);
-  attr->type = 2;
+  attr->type = _bfd_elf_obj_attrs_arg_type (abfd, vendor, tag);
   attr->s = _bfd_elf_attr_strdup (abfd, s);
 }
 
   attr->s = _bfd_elf_attr_strdup (abfd, s);
 }
 
-/* Add a Tag_compatibility object attribute.  */
+/* Add a int+string object attribute.  */
 void
 void
-bfd_elf_add_obj_attr_compat (bfd *abfd, int vendor, unsigned int i,
-                            const char *s)
+bfd_elf_add_obj_attr_int_string (bfd *abfd, int vendor,
+                                unsigned int tag,
+                                unsigned int i, const char *s)
 {
 {
-  obj_attribute_list *list;
-  obj_attribute_list *p;
-  obj_attribute_list **lastp;
-
-  list = (obj_attribute_list *)
-    bfd_alloc (abfd, sizeof (obj_attribute_list));
-  memset (list, 0, sizeof (obj_attribute_list));
-  list->tag = Tag_compatibility;
-  list->attr.type = 3;
-  list->attr.i = i;
-  list->attr.s = _bfd_elf_attr_strdup (abfd, s);
+  obj_attribute *attr;
 
 
-  lastp = &elf_other_obj_attributes (abfd)[vendor];
-  for (p = *lastp; p; p = p->next)
-    {
-      int cmp;
-      if (p->tag != Tag_compatibility)
-       break;
-      cmp = strcmp(s, p->attr.s);
-      if (cmp < 0 || (cmp == 0 && i < p->attr.i))
-       break;
-      lastp = &p->next;
-    }
-  list->next = *lastp;
-  *lastp = list;
+  attr = elf_new_obj_attr (abfd, vendor, tag);
+  attr->type = _bfd_elf_obj_attrs_arg_type (abfd, vendor, tag);
+  attr->i = i;
+  attr->s = _bfd_elf_attr_strdup (abfd, s);
 }
 
 /* Copy the object attributes from IBFD to OBFD.  */
 }
 
 /* Copy the object attributes from IBFD to OBFD.  */
@@ -358,11 +349,17 @@ _bfd_elf_copy_obj_attributes (bfd *ibfd, bfd *obfd)
   int i;
   int vendor;
 
   int i;
   int vendor;
 
+  if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+    return;
+
   for (vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; vendor++)
     {
   for (vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; vendor++)
     {
-      in_attr = &elf_known_obj_attributes (ibfd)[vendor][4];
-      out_attr = &elf_known_obj_attributes (obfd)[vendor][4];
-      for (i = 4; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++)
+      in_attr
+       = &elf_known_obj_attributes (ibfd)[vendor][LEAST_KNOWN_OBJ_ATTRIBUTE];
+      out_attr
+       = &elf_known_obj_attributes (obfd)[vendor][LEAST_KNOWN_OBJ_ATTRIBUTE];
+      for (i = LEAST_KNOWN_OBJ_ATTRIBUTE; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++)
        {
          out_attr->type = in_attr->type;
          out_attr->i = in_attr->i;
        {
          out_attr->type = in_attr->type;
          out_attr->i = in_attr->i;
@@ -377,18 +374,18 @@ _bfd_elf_copy_obj_attributes (bfd *ibfd, bfd *obfd)
           list = list->next)
        {
          in_attr = &list->attr;
           list = list->next)
        {
          in_attr = &list->attr;
-         switch (in_attr->type)
+         switch (in_attr->type & (ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_STR_VAL))
            {
            {
-           case 1:
+           case ATTR_TYPE_FLAG_INT_VAL:
              bfd_elf_add_obj_attr_int (obfd, vendor, list->tag, in_attr->i);
              break;
              bfd_elf_add_obj_attr_int (obfd, vendor, list->tag, in_attr->i);
              break;
-           case 2:
+           case ATTR_TYPE_FLAG_STR_VAL:
              bfd_elf_add_obj_attr_string (obfd, vendor, list->tag,
                                           in_attr->s);
              break;
              bfd_elf_add_obj_attr_string (obfd, vendor, list->tag,
                                           in_attr->s);
              break;
-           case 3:
-             bfd_elf_add_obj_attr_compat (obfd, vendor, in_attr->i,
-                                          in_attr->s);
+           case ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_STR_VAL:
+             bfd_elf_add_obj_attr_int_string (obfd, vendor, list->tag,
+                                              in_attr->i, in_attr->s);
              break;
            default:
              abort ();
              break;
            default:
              abort ();
@@ -400,7 +397,7 @@ _bfd_elf_copy_obj_attributes (bfd *ibfd, bfd *obfd)
 /* Determine whether a GNU object attribute tag takes an integer, a
    string or both.  */
 static int
 /* Determine whether a GNU object attribute tag takes an integer, a
    string or both.  */
 static int
-gnu_obj_attrs_arg_type (int tag)
+gnu_obj_attrs_arg_type (unsigned int tag)
 {
   /* Except for Tag_compatibility, for GNU attributes we follow the
      same rule ARM ones > 32 follow: odd-numbered tags take strings
 {
   /* Except for Tag_compatibility, for GNU attributes we follow the
      same rule ARM ones > 32 follow: odd-numbered tags take strings
@@ -415,7 +412,7 @@ gnu_obj_attrs_arg_type (int tag)
 
 /* Determine what arguments an attribute tag takes.  */
 int
 
 /* Determine what arguments an attribute tag takes.  */
 int
-_bfd_elf_obj_attrs_arg_type (bfd *abfd, int vendor, int tag)
+_bfd_elf_obj_attrs_arg_type (bfd *abfd, int vendor, unsigned int tag)
 {
   switch (vendor)
     {
 {
   switch (vendor)
     {
@@ -436,10 +433,23 @@ _bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr)
 {
   bfd_byte *contents;
   bfd_byte *p;
 {
   bfd_byte *contents;
   bfd_byte *p;
+  bfd_byte *p_end;
   bfd_vma len;
   bfd_vma len;
-  const char *std_section;
+  const char *std_sec;
+
+  /* PR 17512: file: 2844a11d.  */
+  if (hdr->sh_size == 0)
+    return;
+  if (hdr->sh_size > bfd_get_file_size (abfd))
+    {
+      /* xgettext:c-format */
+      _bfd_error_handler (_("%pB: error: attribute section '%pA' too big: %#llx"),
+                         abfd, hdr->bfd_section, (long long) hdr->sh_size);
+      bfd_set_error (bfd_error_invalid_operation);
+      return;
+    }
 
 
-  contents = bfd_malloc (hdr->sh_size);
+  contents = (bfd_byte *) bfd_malloc (hdr->sh_size + 1);
   if (!contents)
     return;
   if (!bfd_get_section_contents (abfd, hdr->bfd_section, contents, 0,
   if (!contents)
     return;
   if (!bfd_get_section_contents (abfd, hdr->bfd_section, contents, 0,
@@ -448,27 +458,44 @@ _bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr)
       free (contents);
       return;
     }
       free (contents);
       return;
     }
+  /* Ensure that the buffer is NUL terminated.  */
+  contents[hdr->sh_size] = 0;
   p = contents;
   p = contents;
-  std_section = get_elf_backend_data (abfd)->obj_attrs_vendor;
+  p_end = p + hdr->sh_size;
+  std_sec = get_elf_backend_data (abfd)->obj_attrs_vendor;
+
   if (*(p++) == 'A')
     {
       len = hdr->sh_size - 1;
   if (*(p++) == 'A')
     {
       len = hdr->sh_size - 1;
-      while (len > 0)
+
+      while (len > 0 && p < p_end - 4)
        {
        {
-         int namelen;
+         unsigned namelen;
          bfd_vma section_len;
          int vendor;
 
          section_len = bfd_get_32 (abfd, p);
          p += 4;
          bfd_vma section_len;
          int vendor;
 
          section_len = bfd_get_32 (abfd, p);
          p += 4;
+         if (section_len == 0)
+           break;
          if (section_len > len)
            section_len = len;
          len -= section_len;
          if (section_len > len)
            section_len = len;
          len -= section_len;
-         namelen = strlen ((char *)p) + 1;
-         section_len -= namelen + 4;
-         if (std_section && strcmp ((char *)p, std_section) == 0)
+         if (section_len <= 4)
+           {
+             _bfd_error_handler
+               (_("%pB: error: attribute section length too small: %" PRId64),
+                abfd, (int64_t) section_len);
+             break;
+           }
+         section_len -= 4;
+         namelen = strnlen ((char *) p, section_len) + 1;
+         if (namelen == 0 || namelen >= section_len)
+           break;
+         section_len -= namelen;
+         if (std_sec && strcmp ((char *) p, std_sec) == 0)
            vendor = OBJ_ATTR_PROC;
            vendor = OBJ_ATTR_PROC;
-         else if (strcmp ((char *)p, "gnu") == 0)
+         else if (strcmp ((char *) p, "gnu") == 0)
            vendor = OBJ_ATTR_GNU;
          else
            {
            vendor = OBJ_ATTR_GNU;
          else
            {
@@ -478,23 +505,31 @@ _bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr)
            }
 
          p += namelen;
            }
 
          p += namelen;
-         while (section_len > 0)
+         while (section_len > 0 && p < p_end)
            {
            {
-             int tag;
+             unsigned int tag;
              unsigned int n;
              unsigned int val;
              bfd_vma subsection_len;
              bfd_byte *end;
 
              unsigned int n;
              unsigned int val;
              bfd_vma subsection_len;
              bfd_byte *end;
 
-             tag = read_unsigned_leb128 (abfd, p, &n);
+             tag = _bfd_safe_read_leb128 (abfd, p, &n, FALSE, p_end);
              p += n;
              p += n;
-             subsection_len = bfd_get_32 (abfd, p);
+             if (p < p_end - 4)
+               subsection_len = bfd_get_32 (abfd, p);
+             else
+               subsection_len = 0;
              p += 4;
              p += 4;
+             if (subsection_len == 0)
+               break;
              if (subsection_len > section_len)
                subsection_len = section_len;
              section_len -= subsection_len;
              subsection_len -= n + 4;
              end = p + subsection_len;
              if (subsection_len > section_len)
                subsection_len = section_len;
              section_len -= subsection_len;
              subsection_len -= n + 4;
              end = p + subsection_len;
+             /* PR 17512: file: 0e8c0c90.  */
+             if (end > p_end)
+               end = p_end;
              switch (tag)
                {
                case Tag_File:
              switch (tag)
                {
                case Tag_File:
@@ -502,25 +537,25 @@ _bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr)
                    {
                      int type;
 
                    {
                      int type;
 
-                     tag = read_unsigned_leb128 (abfd, p, &n);
+                     tag = _bfd_safe_read_leb128 (abfd, p, &n, FALSE, end);
                      p += n;
                      type = _bfd_elf_obj_attrs_arg_type (abfd, vendor, tag);
                      p += n;
                      type = _bfd_elf_obj_attrs_arg_type (abfd, vendor, tag);
-                     switch (type)
+                     switch (type & (ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_STR_VAL))
                        {
                        {
-                       case 3:
-                         val = read_unsigned_leb128 (abfd, p, &n);
+                       case ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_STR_VAL:
+                         val = _bfd_safe_read_leb128 (abfd, p, &n, FALSE, end);
                          p += n;
                          p += n;
-                         bfd_elf_add_obj_attr_compat (abfd, vendor, val,
-                                                      (char *)p);
+                         bfd_elf_add_obj_attr_int_string (abfd, vendor, tag,
+                                                          val, (char *) p);
                          p += strlen ((char *)p) + 1;
                          break;
                          p += strlen ((char *)p) + 1;
                          break;
-                       case 2:
+                       case ATTR_TYPE_FLAG_STR_VAL:
                          bfd_elf_add_obj_attr_string (abfd, vendor, tag,
                          bfd_elf_add_obj_attr_string (abfd, vendor, tag,
-                                                      (char *)p);
+                                                      (char *) p);
                          p += strlen ((char *)p) + 1;
                          break;
                          p += strlen ((char *)p) + 1;
                          break;
-                       case 1:
-                         val = read_unsigned_leb128 (abfd, p, &n);
+                       case ATTR_TYPE_FLAG_INT_VAL:
+                         val = _bfd_safe_read_leb128 (abfd, p, &n, FALSE, end);
                          p += n;
                          bfd_elf_add_obj_attr_int (abfd, vendor, tag, val);
                          break;
                          p += n;
                          bfd_elf_add_obj_attr_int (abfd, vendor, tag, val);
                          break;
@@ -556,73 +591,156 @@ _bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr)
    attributes.  */
 
 bfd_boolean
    attributes.  */
 
 bfd_boolean
-_bfd_elf_merge_object_attributes (bfd *ibfd, bfd *obfd)
+_bfd_elf_merge_object_attributes (bfd *ibfd, struct bfd_link_info *info)
 {
 {
+  bfd *obfd = info->output_bfd;
   obj_attribute *in_attr;
   obj_attribute *out_attr;
   obj_attribute *in_attr;
   obj_attribute *out_attr;
-  obj_attribute_list *in_list;
-  obj_attribute_list *out_list;
   int vendor;
 
   /* The only common attribute is currently Tag_compatibility,
      accepted in both processor and "gnu" sections.  */
   for (vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; vendor++)
     {
   int vendor;
 
   /* The only common attribute is currently Tag_compatibility,
      accepted in both processor and "gnu" sections.  */
   for (vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; vendor++)
     {
-      in_list = elf_other_obj_attributes (ibfd)[vendor];
-      out_list = elf_other_obj_attributes (ibfd)[vendor];
-      while (in_list && in_list->tag == Tag_compatibility)
+      /* Handle Tag_compatibility.  The tags are only compatible if the flags
+        are identical and, if the flags are '1', the strings are identical.
+        If the flags are non-zero, then we can only use the string "gnu".  */
+      in_attr = &elf_known_obj_attributes (ibfd)[vendor][Tag_compatibility];
+      out_attr = &elf_known_obj_attributes (obfd)[vendor][Tag_compatibility];
+
+      if (in_attr->i > 0 && strcmp (in_attr->s, "gnu") != 0)
        {
        {
-         in_attr = &in_list->attr;
-         if (in_attr->i == 0)
-           continue;
-         if (in_attr->i == 1 && strcmp (in_attr->s, "gnu") != 0)
-           {
-             _bfd_error_handler
-               (_("ERROR: %B: Must be processed by '%s' toolchain"),
+         _bfd_error_handler
+           /* xgettext:c-format */
+               (_("error: %pB: object has vendor-specific contents that "
+                  "must be processed by the '%s' toolchain"),
                 ibfd, in_attr->s);
                 ibfd, in_attr->s);
-             return FALSE;
-           }
-         if (!out_list || out_list->tag != Tag_compatibility
-             || strcmp (in_attr->s, out_list->attr.s) != 0)
+         return FALSE;
+       }
+
+      if (in_attr->i != out_attr->i
+         || (in_attr->i != 0 && strcmp (in_attr->s, out_attr->s) != 0))
+       {
+         /* xgettext:c-format */
+         _bfd_error_handler (_("error: %pB: object tag '%d, %s' is "
+                               "incompatible with tag '%d, %s'"),
+                             ibfd,
+                             in_attr->i, in_attr->s ? in_attr->s : "",
+                             out_attr->i, out_attr->s ? out_attr->s : "");
+         return FALSE;
+       }
+    }
+
+  return TRUE;
+}
+
+/* Merge an unknown processor-specific attribute TAG, within the range
+   of known attributes, from IBFD into OBFD; return TRUE if the link
+   is OK, FALSE if it must fail.  */
+
+bfd_boolean
+_bfd_elf_merge_unknown_attribute_low (bfd *ibfd, bfd *obfd, int tag)
+{
+  obj_attribute *in_attr;
+  obj_attribute *out_attr;
+  bfd *err_bfd = NULL;
+  bfd_boolean result = TRUE;
+
+  in_attr = elf_known_obj_attributes_proc (ibfd);
+  out_attr = elf_known_obj_attributes_proc (obfd);
+
+  if (out_attr[tag].i != 0 || out_attr[tag].s != NULL)
+    err_bfd = obfd;
+  else if (in_attr[tag].i != 0 || in_attr[tag].s != NULL)
+    err_bfd = ibfd;
+
+  if (err_bfd != NULL)
+    result
+      = get_elf_backend_data (err_bfd)->obj_attrs_handle_unknown (err_bfd, tag);
+
+  /* Only pass on attributes that match in both inputs.  */
+  if (in_attr[tag].i != out_attr[tag].i
+      || (in_attr[tag].s == NULL) != (out_attr[tag].s == NULL)
+      || (in_attr[tag].s != NULL && out_attr[tag].s != NULL
+         && strcmp (in_attr[tag].s, out_attr[tag].s) != 0))
+    {
+      out_attr[tag].i = 0;
+      out_attr[tag].s = NULL;
+    }
+
+  return result;
+}
+
+/* Merge the lists of unknown processor-specific attributes, outside
+   the known range, from IBFD into OBFD; return TRUE if the link is
+   OK, FALSE if it must fail.  */
+
+bfd_boolean
+_bfd_elf_merge_unknown_attribute_list (bfd *ibfd, bfd *obfd)
+{
+  obj_attribute_list *in_list;
+  obj_attribute_list *out_list;
+  obj_attribute_list **out_listp;
+  bfd_boolean result = TRUE;
+
+  in_list = elf_other_obj_attributes_proc (ibfd);
+  out_listp = &elf_other_obj_attributes_proc (obfd);
+  out_list = *out_listp;
+
+  for (; in_list || out_list; )
+    {
+      bfd *err_bfd = NULL;
+      unsigned int err_tag = 0;
+
+      /* The tags for each list are in numerical order.  */
+      /* If the tags are equal, then merge.  */
+      if (out_list && (!in_list || in_list->tag > out_list->tag))
+       {
+         /* This attribute only exists in obfd.  We can't merge, and we don't
+            know what the tag means, so delete it.  */
+         err_bfd = obfd;
+         err_tag = out_list->tag;
+         *out_listp = out_list->next;
+         out_list = *out_listp;
+       }
+      else if (in_list && (!out_list || in_list->tag < out_list->tag))
+       {
+         /* This attribute only exists in ibfd. We can't merge, and we don't
+            know what the tag means, so ignore it.  */
+         err_bfd = ibfd;
+         err_tag = in_list->tag;
+         in_list = in_list->next;
+       }
+      else /* The tags are equal.  */
+       {
+         /* As present, all attributes in the list are unknown, and
+            therefore can't be merged meaningfully.  */
+         err_bfd = obfd;
+         err_tag = out_list->tag;
+
+         /*  Only pass on attributes that match in both inputs.  */
+         if (in_list->attr.i != out_list->attr.i
+             || (in_list->attr.s == NULL) != (out_list->attr.s == NULL)
+             || (in_list->attr.s && out_list->attr.s
+                 && strcmp (in_list->attr.s, out_list->attr.s) != 0))
            {
            {
-             /* Add this compatibility tag to the output.  */
-             bfd_elf_add_proc_attr_compat (obfd, in_attr->i, in_attr->s);
-             continue;
+             /* No match.  Delete the attribute.  */
+             *out_listp = out_list->next;
+             out_list = *out_listp;
            }
            }
-         out_attr = &out_list->attr;
-         /* Check all the input tags with the same identifier.  */
-         for (;;)
+         else
            {
            {
-             if (out_list->tag != Tag_compatibility
-                 || in_attr->i != out_attr->i
-                 || strcmp (in_attr->s, out_attr->s) != 0)
-               {
-                 _bfd_error_handler
-                   (_("ERROR: %B: Incompatible object tag '%s':%d"),
-                    ibfd, in_attr->s, in_attr->i);
-                 return FALSE;
-               }
-             in_list = in_list->next;
-             if (in_list->tag != Tag_compatibility
-                 || strcmp (in_attr->s, in_list->attr.s) != 0)
-               break;
-             in_attr = &in_list->attr;
+             /* Matched.  Keep the attribute and move to the next.  */
              out_list = out_list->next;
              out_list = out_list->next;
-             if (out_list)
-               out_attr = &out_list->attr;
-           }
-
-         /* Check the output doesn't have extra tags with this identifier.  */
-         if (out_list && out_list->tag == Tag_compatibility
-             && strcmp (in_attr->s, out_list->attr.s) == 0)
-           {
-             _bfd_error_handler
-               (_("ERROR: %B: Incompatible object tag '%s':%d"),
-                ibfd, in_attr->s, out_list->attr.i);
-             return FALSE;
+             in_list = in_list->next;
            }
        }
            }
        }
+
+      if (err_bfd)
+       result = result
+         && get_elf_backend_data (err_bfd)->obj_attrs_handle_unknown (err_bfd,
+                                                                      err_tag);
     }
 
     }
 
-  return TRUE;
+  return result;
 }
 }
This page took 0.034756 seconds and 4 git commands to generate.