+#endif
+ case NT_VMS_IMGNAM:
+ printf (_(" Image name: %s\n"), pnote->descdata);
+ break;
+ case NT_VMS_GSTNAM:
+ printf (_(" Global symbol table name: %s\n"), pnote->descdata);
+ break;
+ case NT_VMS_IMGID:
+ printf (_(" Image id: %s\n"), pnote->descdata);
+ break;
+ case NT_VMS_LINKID:
+ printf (_(" Linker id: %s\n"), pnote->descdata);
+ break;
+ default:
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/* Find the symbol associated with a build attribute that is attached
+ to address OFFSET. If PNAME is non-NULL then store the name of
+ the symbol (if found) in the provided pointer, Returns NULL if a
+ symbol could not be found. */
+
+static Elf_Internal_Sym *
+get_symbol_for_build_attribute (Filedata * filedata,
+ unsigned long offset,
+ bfd_boolean is_open_attr,
+ const char ** pname)
+{
+ static Filedata * saved_filedata = NULL;
+ static char * strtab;
+ static unsigned long strtablen;
+ static Elf_Internal_Sym * symtab;
+ static unsigned long nsyms;
+ Elf_Internal_Sym * saved_sym = NULL;
+ Elf_Internal_Sym * sym;
+
+ if (filedata->section_headers != NULL
+ && (saved_filedata == NULL || filedata != saved_filedata))
+ {
+ Elf_Internal_Shdr * symsec;
+
+ /* Load the symbol and string sections. */
+ for (symsec = filedata->section_headers;
+ symsec < filedata->section_headers + filedata->file_header.e_shnum;
+ symsec ++)
+ {
+ if (symsec->sh_type == SHT_SYMTAB)
+ {
+ symtab = GET_ELF_SYMBOLS (filedata, symsec, & nsyms);
+
+ if (symsec->sh_link < filedata->file_header.e_shnum)
+ {
+ Elf_Internal_Shdr * strtab_sec = filedata->section_headers + symsec->sh_link;
+
+ strtab = (char *) get_data (NULL, filedata, strtab_sec->sh_offset,
+ 1, strtab_sec->sh_size,
+ _("string table"));
+ strtablen = strtab != NULL ? strtab_sec->sh_size : 0;
+ }
+ }
+ }
+ saved_filedata = filedata;
+ }
+
+ if (symtab == NULL || strtab == NULL)
+ return NULL;
+
+ /* Find a symbol whose value matches offset. */
+ for (sym = symtab; sym < symtab + nsyms; sym ++)
+ if (sym->st_value == offset)
+ {
+ if (sym->st_name >= strtablen)
+ /* Huh ? This should not happen. */
+ continue;
+
+ if (strtab[sym->st_name] == 0)
+ continue;
+
+ /* The AArch64 and ARM architectures define mapping symbols
+ (eg $d, $x, $t) which we want to ignore. */
+ if (strtab[sym->st_name] == '$'
+ && strtab[sym->st_name + 1] != 0
+ && strtab[sym->st_name + 2] == 0)
+ continue;
+
+ if (is_open_attr)
+ {
+ /* For OPEN attributes we prefer GLOBAL over LOCAL symbols
+ and FILE or OBJECT symbols over NOTYPE symbols. We skip
+ FUNC symbols entirely. */
+ switch (ELF_ST_TYPE (sym->st_info))
+ {
+ case STT_OBJECT:
+ case STT_FILE:
+ saved_sym = sym;
+ if (sym->st_size)
+ {
+ /* If the symbol has a size associated
+ with it then we can stop searching. */
+ sym = symtab + nsyms;
+ }
+ continue;
+
+ case STT_FUNC:
+ /* Ignore function symbols. */
+ continue;
+
+ default:
+ break;
+ }
+
+ switch (ELF_ST_BIND (sym->st_info))
+ {
+ case STB_GLOBAL:
+ if (saved_sym == NULL
+ || ELF_ST_TYPE (saved_sym->st_info) != STT_OBJECT)
+ saved_sym = sym;
+ break;
+
+ case STB_LOCAL:
+ if (saved_sym == NULL)
+ saved_sym = sym;
+ break;
+
+ default:
+ break;
+ }
+ }
+ else
+ {
+ if (ELF_ST_TYPE (sym->st_info) != STT_FUNC)
+ continue;
+
+ saved_sym = sym;
+ break;
+ }
+ }
+
+ if (saved_sym && pname)
+ * pname = strtab + saved_sym->st_name;
+
+ return saved_sym;
+}
+
+/* Returns true iff addr1 and addr2 are in the same section. */
+
+static bfd_boolean
+same_section (Filedata * filedata, unsigned long addr1, unsigned long addr2)
+{
+ Elf_Internal_Shdr * a1;
+ Elf_Internal_Shdr * a2;
+
+ a1 = find_section_by_address (filedata, addr1);
+ a2 = find_section_by_address (filedata, addr2);
+
+ return a1 == a2 && a1 != NULL;
+}
+
+static bfd_boolean
+print_gnu_build_attribute_description (Elf_Internal_Note * pnote,
+ Filedata * filedata)
+{
+ static unsigned long global_offset = 0;
+ static unsigned long global_end = 0;
+ static unsigned long func_offset = 0;
+ static unsigned long func_end = 0;
+
+ Elf_Internal_Sym * sym;
+ const char * name;
+ unsigned long start;
+ unsigned long end;
+ bfd_boolean is_open_attr = pnote->type == NT_GNU_BUILD_ATTRIBUTE_OPEN;
+
+ switch (pnote->descsz)
+ {
+ case 0:
+ /* A zero-length description means that the range of
+ the previous note of the same type should be used. */
+ if (is_open_attr)
+ {
+ if (global_end > global_offset)
+ printf (_(" Applies to region from %#lx to %#lx\n"),
+ global_offset, global_end);
+ else
+ printf (_(" Applies to region from %#lx\n"), global_offset);
+ }
+ else
+ {
+ if (func_end > func_offset)
+ printf (_(" Applies to region from %#lx to %#lx\n"), func_offset, func_end);
+ else
+ printf (_(" Applies to region from %#lx\n"), func_offset);
+ }
+ return TRUE;
+
+ case 4:
+ start = byte_get ((unsigned char *) pnote->descdata, 4);
+ end = 0;
+ break;
+
+ case 8:
+ if (is_32bit_elf)
+ {
+ /* FIXME: We should check that version 3+ notes are being used here... */
+ start = byte_get ((unsigned char *) pnote->descdata, 4);
+ end = byte_get ((unsigned char *) pnote->descdata + 4, 4);
+ }
+ else
+ {
+ start = byte_get ((unsigned char *) pnote->descdata, 8);
+ end = 0;
+ }
+ break;
+
+ case 16:
+ start = byte_get ((unsigned char *) pnote->descdata, 8);
+ end = byte_get ((unsigned char *) pnote->descdata + 8, 8);
+ break;
+
+ default:
+ error (_(" <invalid description size: %lx>\n"), pnote->descsz);
+ printf (_(" <invalid descsz>"));
+ return FALSE;
+ }
+
+ name = NULL;
+ sym = get_symbol_for_build_attribute (filedata, start, is_open_attr, & name);
+ /* As of version 5 of the annobin plugin, filename symbols are biased by 2
+ in order to avoid them being confused with the start address of the
+ first function in the file... */
+ if (sym == NULL && is_open_attr)
+ sym = get_symbol_for_build_attribute (filedata, start + 2, is_open_attr,
+ & name);
+
+ if (end == 0 && sym != NULL && sym->st_size > 0)
+ end = start + sym->st_size;
+
+ if (is_open_attr)
+ {
+ /* FIXME: Need to properly allow for section alignment.
+ 16 is just the alignment used on x86_64. */
+ if (global_end > 0
+ && start > BFD_ALIGN (global_end, 16)
+ /* Build notes are not guaranteed to be organised in order of
+ increasing address, but we should find the all of the notes
+ for one section in the same place. */
+ && same_section (filedata, start, global_end))
+ warn (_("Gap in build notes detected from %#lx to %#lx\n"),
+ global_end + 1, start - 1);
+
+ printf (_(" Applies to region from %#lx"), start);
+ global_offset = start;
+
+ if (end)
+ {
+ printf (_(" to %#lx"), end);
+ global_end = end;
+ }
+ }
+ else
+ {
+ printf (_(" Applies to region from %#lx"), start);
+ func_offset = start;
+
+ if (end)
+ {
+ printf (_(" to %#lx"), end);
+ func_end = end;
+ }
+ }
+
+ if (sym && name)
+ printf (_(" (%s)"), name);
+
+ printf ("\n");
+ return TRUE;
+}
+
+static bfd_boolean
+print_gnu_build_attribute_name (Elf_Internal_Note * pnote)
+{
+ static const char string_expected [2] = { GNU_BUILD_ATTRIBUTE_TYPE_STRING, 0 };
+ static const char number_expected [2] = { GNU_BUILD_ATTRIBUTE_TYPE_NUMERIC, 0 };
+ static const char bool_expected [3] = { GNU_BUILD_ATTRIBUTE_TYPE_BOOL_TRUE, GNU_BUILD_ATTRIBUTE_TYPE_BOOL_FALSE, 0 };
+ char name_type;
+ char name_attribute;
+ const char * expected_types;
+ const char * name = pnote->namedata;
+ const char * text;
+ signed int left;
+
+ if (name == NULL || pnote->namesz < 2)
+ {
+ error (_("corrupt name field in GNU build attribute note: size = %ld\n"), pnote->namesz);
+ print_symbol (-20, _(" <corrupt name>"));
+ return FALSE;
+ }
+
+ if (do_wide)
+ left = 28;
+ else
+ left = 20;
+
+ /* Version 2 of the spec adds a "GA" prefix to the name field. */
+ if (name[0] == 'G' && name[1] == 'A')
+ {
+ if (pnote->namesz < 4)
+ {
+ error (_("corrupt name field in GNU build attribute note: size = %ld\n"), pnote->namesz);
+ print_symbol (-20, _(" <corrupt name>"));
+ return FALSE;
+ }
+
+ printf ("GA");
+ name += 2;
+ left -= 2;
+ }
+
+ switch ((name_type = * name))
+ {
+ case GNU_BUILD_ATTRIBUTE_TYPE_NUMERIC:
+ case GNU_BUILD_ATTRIBUTE_TYPE_STRING:
+ case GNU_BUILD_ATTRIBUTE_TYPE_BOOL_TRUE:
+ case GNU_BUILD_ATTRIBUTE_TYPE_BOOL_FALSE:
+ printf ("%c", * name);
+ left --;
+ break;
+ default:
+ error (_("unrecognised attribute type in name field: %d\n"), name_type);
+ print_symbol (-20, _("<unknown name type>"));
+ return FALSE;
+ }
+
+ ++ name;
+ text = NULL;
+
+ switch ((name_attribute = * name))
+ {
+ case GNU_BUILD_ATTRIBUTE_VERSION:
+ text = _("<version>");
+ expected_types = string_expected;
+ ++ name;
+ break;
+ case GNU_BUILD_ATTRIBUTE_STACK_PROT:
+ text = _("<stack prot>");
+ expected_types = "!+*";
+ ++ name;