This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RFC: Add --dump-function to objdump


Hi,

I need to find in which section a function is defined as well as what
relocations are in the function.  I come up with a new --dump-function
 option to objdump:

[hjl@gnu-6 binutils]$ ./objdump --dump-function  _start /tmp/sort3.o

/tmp/sort3.o:     file format elf64-x86-64

Function `_start' defined in section `.text' with relocations:
 R_X86_64_64       .text.func2
 R_X86_64_64       .text.func2
[hjl@gnu-6 binutils]$ 

Is this a useful addition?

Thanks.

H.J.
---
diff --git a/binutils/objdump.c b/binutils/objdump.c
index 413de56..850dbea 100644
--- a/binutils/objdump.c
+++ b/binutils/objdump.c
@@ -116,6 +116,7 @@ static bfd_boolean display_file_offsets;/* -F */
 static const char *prefix;		/* --prefix */
 static int prefix_strip;		/* --prefix-strip */
 static size_t prefix_length;
+static const char *dump_function;	/* --dump-function */
 
 /* A structure to record the sections mentioned in -j switches.  */
 struct only
@@ -256,6 +257,7 @@ usage (FILE *stream, int status)
       --insn-width=WIDTH         Display WIDTH bytes on a single line for -d\n\
       --adjust-vma=OFFSET        Add OFFSET to all displayed section addresses\n\
       --special-syms             Include special symbols in symbol dumps\n\
+      --dump-function=NAME       Display section and relocations for function NAME\n\
       --prefix=PREFIX            Add PREFIX to absolute paths for -S\n\
       --prefix-strip=LEVEL       Strip initial directory names for -S\n"));
       fprintf (stream, _("\
@@ -295,7 +297,8 @@ enum option_values
     OPTION_ADJUST_VMA,
     OPTION_DWARF_DEPTH,
     OPTION_DWARF_CHECK,
-    OPTION_DWARF_START
+    OPTION_DWARF_START,
+    OPTION_DUMP_FUNCTION
   };
 
 static struct option long_options[]=
@@ -347,6 +350,7 @@ static struct option long_options[]=
   {"dwarf-depth",      required_argument, 0, OPTION_DWARF_DEPTH},
   {"dwarf-start",      required_argument, 0, OPTION_DWARF_START},
   {"dwarf-check",      no_argument, 0, OPTION_DWARF_CHECK},
+  {"dump-function", required_argument, NULL, OPTION_DUMP_FUNCTION},
   {0, no_argument, 0, 0}
 };
 
@@ -3160,6 +3164,309 @@ dump_dynamic_relocs (bfd *abfd)
     }
 }
 
+/* Sort symbols by section.  */
+
+static int
+compare_symbols_by_section (const void *ap, const void *bp)
+{
+  const asymbol *a = * (const asymbol **) ap;
+  const asymbol *b = * (const asymbol **) bp;
+  if (a->section == b->section)
+    return a->value - b->value;
+  return a->section - b->section;
+}
+
+static void
+dump_reloc_function (bfd *abfd, asymbol *sym, arelent **relpp,
+		     long relcount)
+{
+  arelent **p;
+  char *last_filename, *last_functionname;
+  unsigned int last_line;
+  unsigned int last_discriminator;
+  bfd_vma size;
+  bfd_vma start, stop;
+  asection *sec = sym->section;;
+
+  printf (_(" with relocations:\n"));
+
+  if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
+    size = ((elf_symbol_type *) sym)->internal_elf_sym.st_size;
+  else
+    size = 0;
+
+  if (size == 0)
+    {
+      long s_symcount;
+      long count;
+      asymbol **s_syms;
+      asymbol **current;
+
+      /* We make a copy of syms to sort.  We don't want to sort syms
+	 because that will screw up the relocs.  */
+      s_symcount = symcount;
+      s_syms = (asymbol **) xmalloc (symcount * sizeof (asymbol *));
+      memcpy (s_syms, syms, symcount * sizeof (asymbol *));
+
+      s_symcount = remove_useless_symbols (s_syms, s_symcount);
+
+      /* Sort the symbols into section and value order.  */
+      qsort (s_syms, s_symcount, sizeof (asymbol *),
+	     compare_symbols_by_section);
+
+      /* Find the symbol.  */
+      current = s_syms;
+      for (count = 0; count < s_symcount; count++)
+	{
+	  if (sec == (*current)->section
+	      && sym->value == (*current)->value)
+	    break;
+	  current++;
+	}
+
+      if (count == s_symcount)
+	bfd_fatal (bfd_get_filename (abfd));
+
+      /* Find the next symbol in the same section with a higher value.  */
+      for (; count < symcount; count++)
+	{
+	  if (sec != (*current)->section
+	      || sym->value != (*current)->value)
+	    break;
+	  current++;
+	}
+
+      if (count == s_symcount
+	  || sec != (*current)->section)
+	size = bfd_get_section_size (sec);
+      else
+	size = (*current)->value - sym->value;
+
+      if (size == 0)
+	bfd_fatal (bfd_get_filename (abfd));
+
+      free (s_syms);
+    }
+
+  start = bfd_get_section_vma (abfd, sec) + sym->value;
+  stop = start + size;
+
+  /* Sort relocations by address.  */
+  qsort (relpp, relcount, sizeof (arelent **), compare_relocs);
+
+  last_filename = NULL;
+  last_functionname = NULL;
+  last_line = 0;
+  last_discriminator = 0;
+
+  for (p = relpp; relcount && *p != NULL; p++, relcount--)
+    {
+      arelent *q = *p;
+      const char *filename, *functionname;
+      unsigned int linenumber;
+      unsigned int discriminator;
+      const char *sym_name;
+      const char *section_name;
+      bfd_vma addend2 = 0;
+
+      if (q->address < start)
+	continue;
+      if (q->address >= stop)
+	break;
+
+      if (with_line_numbers
+	  && sec != NULL
+	  && bfd_find_nearest_line_discriminator (abfd, sec, syms, q->address,
+                                                  &filename, &functionname,
+                                                  &linenumber, &discriminator))
+	{
+	  if (functionname != NULL
+	      && (last_functionname == NULL
+		  || strcmp (functionname, last_functionname) != 0))
+	    {
+	      printf ("%s():\n", functionname);
+	      if (last_functionname != NULL)
+		free (last_functionname);
+	      last_functionname = xstrdup (functionname);
+	    }
+
+	  if (linenumber > 0
+	      && (linenumber != last_line
+		  || (filename != NULL
+		      && last_filename != NULL
+		      && filename_cmp (filename, last_filename) != 0)
+                  || (discriminator != last_discriminator)))
+	    {
+              if (discriminator > 0)
+                printf ("%s:%u\n", filename == NULL ? "???" : filename, linenumber);
+              else
+                printf ("%s:%u (discriminator %u)\n", filename == NULL ? "???" : filename,
+                        linenumber, discriminator);
+	      last_line = linenumber;
+	      last_discriminator = discriminator;
+	      if (last_filename != NULL)
+		free (last_filename);
+	      if (filename == NULL)
+		last_filename = NULL;
+	      else
+		last_filename = xstrdup (filename);
+	    }
+	}
+
+      if (q->sym_ptr_ptr && *q->sym_ptr_ptr)
+	{
+	  sym_name = (*(q->sym_ptr_ptr))->name;
+	  section_name = (*(q->sym_ptr_ptr))->section->name;
+	}
+      else
+	{
+	  sym_name = NULL;
+	  section_name = NULL;
+	}
+
+      if (wide_output)
+	bfd_printf_vma (abfd, q->address);
+
+      if (q->howto == NULL)
+	printf (" *unknown*         ");
+      else if (q->howto->name)
+	{
+	  const char *name = q->howto->name;
+
+	  /* R_SPARC_OLO10 relocations contain two addends.
+	     But because 'arelent' lacks enough storage to
+	     store them both, the 64-bit ELF Sparc backend
+	     records this as two relocations.  One R_SPARC_LO10
+	     and one R_SPARC_13, both pointing to the same
+	     address.  This is merely so that we have some
+	     place to store both addend fields.
+
+	     Undo this transformation, otherwise the output
+	     will be confusing.  */
+	  if (abfd->xvec->flavour == bfd_target_elf_flavour
+	      && elf_tdata(abfd)->elf_header->e_machine == EM_SPARCV9
+	      && relcount > 1
+	      && !strcmp (q->howto->name, "R_SPARC_LO10"))
+	    {
+	      arelent *q2 = *(p + 1);
+	      if (q2 != NULL
+		  && q2->howto
+		  && q->address == q2->address
+		  && !strcmp (q2->howto->name, "R_SPARC_13"))
+		{
+		  name = "R_SPARC_OLO10";
+		  addend2 = q2->addend;
+		  p++;
+		}
+	    }
+	  printf (" %-16s  ", name);
+	}
+      else
+	printf (" %-16d  ", q->howto->type);
+
+      if (sym_name)
+	{
+	  objdump_print_symname (abfd, NULL, *q->sym_ptr_ptr);
+	}
+      else
+	{
+	  if (section_name == NULL)
+	    section_name = "*unknown*";
+	  printf ("[%s]", section_name);
+	}
+
+      if (wide_output)
+	{
+	  if (q->addend)
+	    {
+	      bfd_signed_vma addend = q->addend;
+	      if (addend < 0)
+		{
+		  printf ("-0x");
+		  addend = -addend;
+		}
+	      else
+		printf ("+0x");
+	      bfd_printf_vma (abfd, addend);
+	    }
+	  if (addend2)
+	    {
+	      printf ("+0x");
+	      bfd_printf_vma (abfd, addend2);
+	    }
+	}
+
+      printf ("\n");
+    }
+
+  if (last_filename != NULL)
+    free (last_filename);
+  if (last_functionname != NULL)
+    free (last_functionname);
+}
+
+static void
+dump_relocs_in_function (bfd *abfd, asymbol *sym)
+{
+  arelent **relpp;
+  long relcount;
+  long relsize;
+  asection *section = sym->section;;
+
+  if ((section->flags & SEC_RELOC) == 0)
+    {
+      printf ("\n");
+      return;
+    }
+
+  relsize = bfd_get_reloc_upper_bound (abfd, section);
+  if (relsize < 0)
+    bfd_fatal (bfd_get_filename (abfd));
+
+  if (relsize == 0)
+    {
+      printf ("\n");
+      return;
+    }
+
+  relpp = (arelent **) xmalloc (relsize);
+  relcount = bfd_canonicalize_reloc (abfd, section, relpp, syms);
+
+  if (relcount < 0)
+    bfd_fatal (bfd_get_filename (abfd));
+  else if (relcount == 0)
+    return;
+
+  dump_reloc_function (abfd, sym, relpp, relcount);
+  free (relpp);
+}
+
+static void
+dump_function_info (bfd *abfd)
+{
+  asymbol **current = syms;
+  long count;
+
+  for (count = 0; count < symcount; count++)
+    {
+      const char *name = (*current)->name;
+      if (strcmp (name, dump_function) == 0)
+	{
+	  asection *sec = (*current)->section;
+	  if (!bfd_is_und_section (sec)
+	      && ((sec->flags & (SEC_CODE | SEC_HAS_CONTENTS))
+		  == (SEC_CODE | SEC_HAS_CONTENTS)))
+	    {
+	      printf (_("Function `%s' defined in section `%s'"),
+		      dump_function, (*current)->section->name);
+	      dump_relocs_in_function (abfd, *current);
+	    }
+	  return;
+	}
+      current++;
+    }
+}
+
 /* Creates a table of paths, to search for source files.  */
 
 static void
@@ -3222,6 +3529,7 @@ dump_bfd (bfd *abfd)
   if (dump_symtab
       || dump_reloc_info
       || disassemble
+      || dump_function
       || dump_debugging
       || dump_dwarf_section_info)
     syms = slurp_symtab (abfd);
@@ -3256,6 +3564,8 @@ dump_bfd (bfd *abfd)
     dump_data (abfd);
   if (disassemble)
     disassemble_data (abfd);
+  if (dump_function)
+    dump_function_info (abfd);
 
   if (dump_debugging)
     {
@@ -3637,6 +3947,10 @@ main (int argc, char **argv)
 	case OPTION_DWARF_CHECK:
 	  dwarf_check = TRUE;
 	  break;
+	case OPTION_DUMP_FUNCTION:
+	  dump_function = optarg;
+	  seenflag = TRUE;
+	  break;
 	case 'G':
 	  dump_stab_section_info = TRUE;
 	  seenflag = TRUE;


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]