Commit: objdump --show-all-symbols: show extra symbols matching referenced addresses

Message ID 87r0fmn79q.fsf@redhat.com
State New
Headers
Series Commit: objdump --show-all-symbols: show extra symbols matching referenced addresses |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_binutils_build--master-arm warning Patch is already merged
linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 warning Patch is already merged

Commit Message

Nick Clifton April 3, 2024, 9:08 a.m. UTC
  Hi Guys,

  Objcopy's --show-all-symbols option displays all the symbols matching
  an address that is being disassembled.  But currently it does not show
  any extra symbols that might match an address that is referenced by an
  instruction.  For example:

    $ objdump --disassemble=abort /lib64/libc.so.6 --show-all-symbols
    [...]
    269bb:	e8 40 6f 0b 00       	call   dd900 <_exit>

  I am applying the attached patch to fix this omission.  Given the
  example above the output now looks like:

    $ objdump --disassemble=abort /lib64/libc.so.6 --show-all-symbols --wide
    [...]
    269bb:	e8 40 6f 0b 00       	call   dd900 <_exit>, <_Exit>, <__GI__exit>

  Without the --wide option, the extra symbols are displayed on a new
  line:
  
    $ objdump --disassemble=abort /lib64/libc.so.6 --show-all-symbols --wide
    [...]
    269bb:	e8 40 6f 0b 00       	call   dd900 <_exit>,
	<_Exit>, <__GI__exit>

  As an addition, if the first symbol that matches the address is an
  absolute location obtained from a relocation, then the patch will
  decode the location and display any symbols that match.  This is
  particularly helpful when displaying branches into the PLT.

  Before patch:

    $ objdump --disassemble=__gconv_alias_compare /lib64/libc.so.6 --show-all-symbols --wide
    [...]
    28f2a:	e9 31 d8 ff ff      jmp    26760 <*ABS*+0xa4450@plt>

  After patch:
  
    $ objdump --disassemble=__gconv_alias_compare /lib64/libc.so.6 --show-all-symbols --wide
    [...]
    28f2a:	e9 31 d8 ff ff     jmp    26760 <*ABS*+0xa4450@plt>, <strcmp_ifunc>, <strcmp>, <__GI_strcmp>

Cheers
  Nick
  

Comments

Andreas Schwab April 3, 2024, 9:17 a.m. UTC | #1
On Apr 03 2024, Nick Clifton wrote:

> +  /* If we found an absolute symbol in the reloc (ie: "*ABS*+0x....")

Is the addend always formatted as an unsigned number?
  
Nick Clifton April 3, 2024, 9:37 a.m. UTC | #2
Hi Andreas,

>> +  /* If we found an absolute symbol in the reloc (ie: "*ABS*+0x....")
> 
> Is the addend always formatted as an unsigned number?

Err, yes ?

To be honest I am not 100% sure.  Possibly on architectures with a signed
address space there could be a negative value in the relocation symbol.
If that is the case then I can update the patch to handle such values, but
without a reproducer I am reluctant to make any changes.

Cheers
   Nick
  
Andreas Schwab April 3, 2024, 9:46 a.m. UTC | #3
On Apr 03 2024, Nick Clifton wrote:

> Hi Andreas,
>
>>> +  /* If we found an absolute symbol in the reloc (ie: "*ABS*+0x....")
>> Is the addend always formatted as an unsigned number?
>
> Err, yes ?
>
> To be honest I am not 100% sure.  Possibly on architectures with a signed
> address space there could be a negative value in the relocation symbol.

Nothing stops the object from using addresses from the upper end of the
address space.

$ tail -1 /proc/self/maps
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0                  [vsyscall]
  
Nick Clifton April 3, 2024, 9:55 a.m. UTC | #4
Hi Andreas,

>>>> +  /* If we found an absolute symbol in the reloc (ie: "*ABS*+0x....")
>>> Is the addend always formatted as an unsigned number?
>>
>> Err, yes ?
>>
>> To be honest I am not 100% sure.  Possibly on architectures with a signed
>> address space there could be a negative value in the relocation symbol.
> 
> Nothing stops the object from using addresses from the upper end of the
> address space.
> 
> $ tail -1 /proc/self/maps
> ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0                  [vsyscall]

Right, but if the address space itself is unsigned then any relocations
against locations in the upper end of the space will themselves be
unsigned.  Full of f's and looking like a negative number, but actually
a large, positive, unsigned number.

But hey, I have only just written this code, so I am quite willing to
believe that there are bugs in it.  Do you know of an example of a
relocation against an upper end address that I could use to investigate
further ?

Cheers
   Nick
  

Patch

diff --git a/binutils/objdump.c b/binutils/objdump.c
index 68da543e905..6396174d50f 100644
--- a/binutils/objdump.c
+++ b/binutils/objdump.c
@@ -1652,6 +1652,42 @@  objdump_print_addr_with_sym (bfd *abfd, asection *sec, asymbol *sym,
 			      (long int)(sec->filepos + (vma - sec->vma)));
 }
 
+/* Displays all symbols in the sorted symbol table starting at PLACE
+   which match the address VMA.  Assumes that show_all_symbols == true.  */
+
+static void
+display_extra_syms (long place,
+		    bfd_vma vma,
+		    struct disassemble_info *inf)
+{
+  struct objdump_disasm_info *aux = (struct objdump_disasm_info *) inf->application_data;
+
+  if (place == 0)
+    return;
+
+  bool first = true;
+
+  for (; place < sorted_symcount; place++)
+    {
+      asymbol *sym = sorted_syms[place];
+		  
+      if (bfd_asymbol_value (sym) != vma)
+	break;
+
+      if (! inf->symbol_is_valid (sym, inf))
+	continue;
+
+      if (first && ! do_wide)
+	inf->fprintf_styled_func (inf->stream, dis_style_immediate, ",\n\t<");
+      else  
+	inf->fprintf_styled_func (inf->stream, dis_style_immediate, ", <");
+
+      objdump_print_symname (aux->abfd, inf, sym);
+      inf->fprintf_styled_func (inf->stream, dis_style_immediate, ">");
+      first = false;
+    }
+}
+		    
 /* Print an address (VMA), symbolically if possible.
    If SKIP_ZEROES is TRUE, don't output leading zeroes.  */
 
@@ -1663,6 +1699,7 @@  objdump_print_addr (bfd_vma vma,
   struct objdump_disasm_info *aux;
   asymbol *sym = NULL;
   bool skip_find = false;
+  long place = 0;
 
   aux = (struct objdump_disasm_info *) inf->application_data;
 
@@ -1696,10 +1733,34 @@  objdump_print_addr (bfd_vma vma,
     }
 
   if (!skip_find)
-    sym = find_symbol_for_address (vma, inf, NULL);
+    sym = find_symbol_for_address (vma, inf, &place);
 
   objdump_print_addr_with_sym (aux->abfd, inf->section, sym, vma, inf,
 			       skip_zeroes);
+
+  /* If requested, display any extra symbols at this address.  */
+  if (sym == NULL || ! show_all_symbols)
+    return;
+
+  if (place)
+    display_extra_syms (place + 1, vma, inf);
+    
+  /* If we found an absolute symbol in the reloc (ie: "*ABS*+0x....")
+     and there is a valid symbol at the address contained in the absolute symbol
+     then display any extra symbols that match this address.  This helps
+     particularly with relocations for PLT entries.  */
+  if (startswith (sym->name, BFD_ABS_SECTION_NAME "+"))
+    {
+      bfd_vma addr = strtoul (sym->name + strlen (BFD_ABS_SECTION_NAME "+"), NULL, 0);
+
+      if (addr && addr != vma)
+	{
+	  sym = find_symbol_for_address (addr, inf, &place);
+
+	  if (sym)
+	    display_extra_syms (place, addr, inf);
+	}
+    }
 }
 
 /* Print VMA to INFO.  This function is passed to the disassembler