diff --git a/binutils/ChangeLog b/binutils/ChangeLog index 71dd6e2fb25..f9fb74689f1 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,16 @@ +2017-03-14 Nick Clifton + + * readelf.c (print_gnu_build_attribute_description): Move symbol + printing code to... + (print_symbol_for_build_attribute): New function. ...here. + Add to find the best symbol to associate with an OPEN note. + Add code to cache the symbol table and string table, so that they + are not loaded every time a note is displayed. + * testsuite/binutils-all/note-2-32.s: Add a function symbol. + * testsuite/binutils-all/note-2-64.s: Likewise. + * testsuite/binutils-all/note-2-32.d: Update expected note output. + * testsuite/binutils-all/note-2-64.d: Likewise. + 2017-03-13 Alan Modra Taeung Song diff --git a/binutils/readelf.c b/binutils/readelf.c index a10ba19b5bb..34781ae8663 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -16598,24 +16598,145 @@ print_ia64_vms_note (Elf_Internal_Note * pnote) return TRUE; } +/* Print the name of the symbol associated with a build attribute + that is attached to address OFFSET. */ + +static bfd_boolean +print_symbol_for_build_attribute (FILE * file, + unsigned long offset, + bfd_boolean is_open_attr) +{ + static FILE * saved_file = 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 (saved_file == NULL || file != saved_file) + { + Elf_Internal_Shdr * symsec; + + /* Load the symbol and string sections. */ + for (symsec = section_headers; + symsec < section_headers + elf_header.e_shnum; + symsec ++) + { + if (symsec->sh_type == SHT_SYMTAB) + { + symtab = GET_ELF_SYMBOLS (file, symsec, & nsyms); + + if (symsec->sh_link < elf_header.e_shnum) + { + Elf_Internal_Shdr * strtab_sec = section_headers + symsec->sh_link; + + strtab = (char *) get_data (NULL, file, strtab_sec->sh_offset, + 1, strtab_sec->sh_size, + _("string table")); + strtablen = strtab != NULL ? strtab_sec->sh_size : 0; + } + } + } + saved_file = file; + } + + if (symtab == NULL || strtab == NULL) + { + printf ("\n"); + return FALSE; + } + + /* 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; + + 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_FILE: + saved_sym = sym; + /* We can stop searching now. */ + sym = symtab + nsyms; + continue; + + case STT_OBJECT: + saved_sym = sym; + 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; + } + } + + printf (" (%s: %s)\n", + is_open_attr ? _("file") : _("func"), + saved_sym ? strtab + saved_sym->st_name : _(")")); + return TRUE; +} + static bfd_boolean print_gnu_build_attribute_description (Elf_Internal_Note * pnote, - FILE * file, - Elf_Internal_Shdr * section ATTRIBUTE_UNUSED) + FILE * file) { static unsigned long global_offset = 0; - unsigned long i; - unsigned long strtab_size = 0; - char * strtab = NULL; - Elf_Internal_Sym * symtab = NULL; - unsigned long nsyms = 0; - Elf_Internal_Shdr * symsec = NULL; - unsigned int desc_size = is_32bit_elf ? 4 : 8; + unsigned long offset; + unsigned int desc_size = is_32bit_elf ? 4 : 8; + bfd_boolean is_open_attr = pnote->type == NT_GNU_BUILD_ATTRIBUTE_OPEN; - if (pnote->descsz == 0) + if (pnote->descsz == 0) { - printf (_(" Applies from offset %#lx\n"), global_offset); - return TRUE; + if (is_open_attr) + { + printf (_(" Applies from offset %#lx\n"), global_offset); + return TRUE; + } + else + { + printf (_(" Applies to func at %#lx"), global_offset); + return print_symbol_for_build_attribute (file, global_offset, is_open_attr); + } } if (pnote->descsz != desc_size) @@ -16625,88 +16746,19 @@ print_gnu_build_attribute_description (Elf_Internal_Note * pnote, return FALSE; } - /* Load the symbols. */ - for (symsec = section_headers; - symsec < section_headers + elf_header.e_shnum; - symsec ++) + offset = byte_get ((unsigned char *) pnote->descdata, desc_size); + + if (is_open_attr) { - if (symsec->sh_type == SHT_SYMTAB) - { - symtab = GET_ELF_SYMBOLS (file, symsec, & nsyms); - - if (symsec->sh_link < elf_header.e_shnum) - { - Elf_Internal_Shdr * strtab_sec = section_headers + symsec->sh_link; - - strtab = (char *) get_data (NULL, file, strtab_sec->sh_offset, - 1, strtab_sec->sh_size, - _("string table")); - strtab_size = strtab != NULL ? strtab_sec->sh_size : 0; - } - } + printf (_(" Applies from offset %#lx"), offset); + global_offset = offset; + } + else + { + printf (_(" Applies to func at %#lx"), offset); } - printf (_(" Applies from offset")); - - for (i = 0; i < pnote->descsz; i += desc_size) - { - Elf_Internal_Sym * saved_sym = NULL; - Elf_Internal_Sym * sym; - unsigned long offset; - - offset = byte_get ((unsigned char *) pnote->descdata + i, desc_size); - - if (i + desc_size == pnote->descsz) - printf (_(" %#lx"), offset); - else - printf (_(" %#lx, "), offset); - - if (pnote->type == NT_GNU_BUILD_ATTRIBUTE_OPEN) - global_offset = offset; - - if (symtab == NULL || strtab == NULL) - continue; - - /* Find a symbol whose value matches offset. */ - for (sym = symtab; sym < symtab + nsyms; sym ++) - if (sym->st_value == offset) - { - if (sym->st_name < strtab_size) - { - if (strtab[sym->st_name] == 0) - continue; - - if (pnote->type == NT_GNU_BUILD_ATTRIBUTE_OPEN) - { - /* For OPEN attributes we prefer GLOBAL symbols, if there - is one that matches. But keep a record of a matching - LOCAL symbol, just in case that is all that we can find. */ - if (ELF_ST_BIND (sym->st_info) == STB_LOCAL) - { - saved_sym = sym; - continue; - } - printf (_(" (file: %s)"), strtab + sym->st_name); - } - else if (ELF_ST_TYPE (sym->st_info) != STT_FUNC) - continue; - else - printf (_(" (function: %s)"), strtab + sym->st_name); - break; - } - } - - if (sym == symtab + nsyms) - { - if (saved_sym) - printf (_(" (file: %s)"), strtab + saved_sym->st_name); - else - printf (_(" ()")); - } - } - - printf ("\n"); - return TRUE; + return print_symbol_for_build_attribute (file, offset, is_open_attr); } static bfd_boolean @@ -16893,8 +16945,7 @@ print_gnu_build_attribute_name (Elf_Internal_Note * pnote) static bfd_boolean process_note (Elf_Internal_Note * pnote, - FILE * file, - Elf_Internal_Shdr * section) + FILE * file) { const char * name = pnote->namesz ? pnote->namedata : "(NONE)"; const char * nt; @@ -16962,7 +17013,7 @@ process_note (Elf_Internal_Note * pnote, return print_core_note (pnote); else if (pnote->type == NT_GNU_BUILD_ATTRIBUTE_OPEN || pnote->type == NT_GNU_BUILD_ATTRIBUTE_FUNC) - return print_gnu_build_attribute_description (pnote, file, section); + return print_gnu_build_attribute_description (pnote, file); if (pnote->descsz) { @@ -17116,7 +17167,7 @@ process_notes_at (FILE * file, inote.namedata = temp; } - if (! process_note (& inote, file, section)) + if (! process_note (& inote, file)) res = FALSE; if (temp != NULL) diff --git a/binutils/testsuite/binutils-all/note-2-32.d b/binutils/testsuite/binutils-all/note-2-32.d index 0c0974c0bc9..8deb7f6c93d 100644 --- a/binutils/testsuite/binutils-all/note-2-32.d +++ b/binutils/testsuite/binutils-all/note-2-32.d @@ -13,5 +13,5 @@ [ ]+\*0x0[ ]+0x00000000[ ]+NT_GNU_BUILD_ATTRIBUTE_OPEN[ ]+Applies from offset 0x100 [ ]+\$1[ ]+0x00000004[ ]+NT_GNU_BUILD_ATTRIBUTE_OPEN[ ]+Applies from offset 0x10. \(file: note2.s\) [ ]+!false[ ]+0x00000000[ ]+NT_GNU_BUILD_ATTRIBUTE_OPEN[ ]+Applies from offset 0x10. -[ ]+\*pic[ ]+0x00000000[ ]+NT_GNU_BUILD_ATTRIBUTE_FUNC[ ]+Applies from offset 0x10. +[ ]+\*pic[ ]+0x00000000[ ]+NT_GNU_BUILD_ATTRIBUTE_FUNC[ ]+Applies to func at 0x10. \(func: func1\) #... diff --git a/binutils/testsuite/binutils-all/note-2-32.s b/binutils/testsuite/binutils-all/note-2-32.s index 8d9f53a3a0f..da3b08536ad 100644 --- a/binutils/testsuite/binutils-all/note-2-32.s +++ b/binutils/testsuite/binutils-all/note-2-32.s @@ -39,6 +39,8 @@ note1.s: .global note2.s note2.s: + .type func1, STT_FUNC +func1: .word 0x100 .pushsection .gnu.build.attributes, "0x100000", %note diff --git a/binutils/testsuite/binutils-all/note-2-64.d b/binutils/testsuite/binutils-all/note-2-64.d index 3dd4582011d..85358213a2c 100644 --- a/binutils/testsuite/binutils-all/note-2-64.d +++ b/binutils/testsuite/binutils-all/note-2-64.d @@ -13,5 +13,5 @@ [ ]+\*0x0[ ]+0x00000000[ ]+NT_GNU_BUILD_ATTRIBUTE_OPEN[ ]+Applies from offset 0x100 [ ]+\$1[ ]+0x00000008[ ]+NT_GNU_BUILD_ATTRIBUTE_OPEN[ ]+Applies from offset 0x10. \(file: note2.s\) [ ]+!false[ ]+0x00000000[ ]+NT_GNU_BUILD_ATTRIBUTE_OPEN[ ]+Applies from offset 0x10. -[ ]+\*pic[ ]+0x00000000[ ]+NT_GNU_BUILD_ATTRIBUTE_FUNC[ ]+Applies from offset 0x10. +[ ]+\*pic[ ]+0x00000000[ ]+NT_GNU_BUILD_ATTRIBUTE_FUNC[ ]+Applies to func at 0x10. \(func: func1\) #... diff --git a/binutils/testsuite/binutils-all/note-2-64.s b/binutils/testsuite/binutils-all/note-2-64.s index 51317c84fc4..fcd61d03370 100644 --- a/binutils/testsuite/binutils-all/note-2-64.s +++ b/binutils/testsuite/binutils-all/note-2-64.s @@ -39,8 +39,11 @@ note1.s: .global note2.s note2.s: + .global func1 + .type func1, STT_FUNC +func1: .word 0x100 - + .pushsection .gnu.build.attributes, "0x100000", %note .dc.l 4 .dc.l 8