* Makefile.in (clean): Remove $(DEMANGLER_PROG).1. From Ronald
[binutils-gdb.git] / binutils / objdump.c
index 64cba4744801cd302412bf44ea514f10a35622be..46783a0c3de8b0f3acbe5c41040a78879602bf20 100644 (file)
@@ -21,6 +21,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #include "getopt.h"
 #include "progress.h"
 #include "bucomm.h"
+#include <sys/types.h>
 #include <stdio.h>
 #include <ctype.h>
 #include "dis-asm.h"
@@ -57,6 +58,8 @@ boolean disassemble_all;      /* -D */
 boolean formats_info;          /* -i */
 char *only;                    /* -j secname */
 int wide_output;               /* -w */
+bfd_vma start_address = (bfd_vma) -1; /* --start-address */
+bfd_vma stop_address = (bfd_vma) -1;  /* --stop-address */
 
 /* Extra info to pass to the disassembler address printing function.  */
 struct objdump_disasm_info {
@@ -109,6 +112,9 @@ dump_symbols PARAMS ((bfd *abfd, boolean dynamic));
 static void
 display_bfd PARAMS ((bfd *abfd));
 
+static void
+objdump_print_value PARAMS ((bfd_vma, FILE *));
+
 static void
 objdump_print_address PARAMS ((bfd_vma, struct disassemble_info *));
 
@@ -129,12 +135,18 @@ Usage: %s [-ahifdDprRtTxsSlw] [-b bfdname] [-m machine] [-j section-name]\n\
   fprintf (stream, "\
        [--architecture=machine] [--reloc] [--full-contents] [--stabs]\n\
        [--syms] [--all-headers] [--dynamic-syms] [--dynamic-reloc]\n\
-       [--wide] [--version] [--help] [--private-headers] objfile...\n\
+       [--wide] [--version] [--help] [--private-headers]\n\
+       [--start-address=addr] [--stop-address=addr] objfile...\n\
 at least one option besides -l (--line-numbers) must be given\n");
   list_supported_targets (program_name, stream);
   exit (status);
 }
 
+/* 150 isn't special; it's just an arbitrary non-ASCII char value.  */
+
+#define OPTION_START_ADDRESS (150)
+#define OPTION_STOP_ADDRESS (OPTION_START_ADDRESS + 1)
+
 static struct option long_options[]=
 {
   {"all-headers", no_argument, NULL, 'x'},
@@ -156,9 +168,11 @@ static struct option long_options[]=
   {"section-headers", no_argument, NULL, 'h'},
   {"source", no_argument, NULL, 'S'},
   {"stabs", no_argument, &dump_stab_section_info, 1},
+  {"start-address", required_argument, NULL, OPTION_START_ADDRESS},
+  {"stop-address", required_argument, NULL, OPTION_STOP_ADDRESS},
   {"syms", no_argument, NULL, 't'},
   {"target", required_argument, NULL, 'b'},
-  {"version", no_argument, &show_version,    1},
+  {"version", no_argument, &show_version, 1},
   {"wide", no_argument, &wide_output, 'w'},
   {0, no_argument, 0, 0}
 };
@@ -222,6 +236,7 @@ slurp_symtab (abfd)
   if (!(bfd_get_file_flags (abfd) & HAS_SYMS))
     {
       printf ("No symbols in \"%s\".\n", bfd_get_filename (abfd));
+      symcount = 0;
       return NULL;
     }
 
@@ -258,6 +273,7 @@ slurp_dynamic_symtab (abfd)
        {
          fprintf (stderr, "%s: %s: not a dynamic object\n",
                   program_name, bfd_get_filename (abfd));
+         dynsymcount = 0;
          return NULL;
        }
 
@@ -314,6 +330,9 @@ compare_symbols (ap, bp)
 {
   const asymbol *a = *(const asymbol **)ap;
   const asymbol *b = *(const asymbol **)bp;
+  const char *an, *bn;
+  size_t anl, bnl;
+  boolean af, bf;
 
   if (bfd_asymbol_value (a) > bfd_asymbol_value (b))
     return 1;
@@ -324,6 +343,44 @@ compare_symbols (ap, bp)
     return 1;
   else if (a->section < b->section)
     return -1;
+
+  an = bfd_asymbol_name (a);
+  bn = bfd_asymbol_name (b);
+  anl = strlen (an);
+  bnl = strlen (bn);
+
+  /* The symbols gnu_compiled and gcc2_compiled convey no real
+     information, so put them after other symbols with the same value.  */
+
+  af = (strstr (an, "gnu_compiled") != NULL
+       || strstr (an, "gcc2_compiled") != NULL);
+  bf = (strstr (bn, "gnu_compiled") != NULL
+       || strstr (bn, "gcc2_compiled") != NULL);
+
+  if (af && ! bf)
+    return 1;
+  if (! af && bf)
+    return -1;
+
+  /* We use a heuristic for the file name, to try to sort it after
+     more useful symbols.  It may not work on non Unix systems, but it
+     doesn't really matter; the only difference is precisely which
+     symbol names get printed.  */
+
+#define file_symbol(s, sn, snl)                        \
+  (((s)->flags & BSF_FILE) != 0                        \
+   || ((sn)[(snl) - 2] == '.'                  \
+       && ((sn)[(snl) - 1] == 'o'              \
+          || (sn)[(snl) - 1] == 'a')))
+
+  af = file_symbol (a, an, anl);
+  bf = file_symbol (b, bn, bnl);
+
+  if (af && ! bf)
+    return 1;
+  if (! af && bf)
+    return -1;
+
   return 0;
 }
 
@@ -352,6 +409,22 @@ compare_relocs (ap, bp)
     return 0;
 }
 
+/* Print VMA to STREAM with no leading zeroes.  */
+
+static void
+objdump_print_value (vma, stream)
+     bfd_vma vma;
+     FILE *stream;
+{
+  char buf[30];
+  char *p;
+
+  sprintf_vma (buf, vma);
+  for (p = buf; *p == '0'; ++p)
+    ;
+  fprintf (stream, "%s", p);
+}
+
 /* Print VMA symbolically to INFO if possible.  */
 
 static void
@@ -400,6 +473,10 @@ objdump_print_address (vma, info)
   /* The symbol we want is now in min, the low end of the range we
      were searching.  */
   thisplace = min;
+  while (thisplace > 0
+        && (bfd_asymbol_value (sorted_syms[thisplace])
+            == bfd_asymbol_value (sorted_syms[thisplace - 1])))
+    --thisplace;
 
   {
     /* If this symbol isn't global, search for one with the same value
@@ -449,7 +526,7 @@ objdump_print_address (vma, info)
            || ((aux->abfd->flags & HAS_RELOC) != 0
                && vma >= bfd_get_section_vma (aux->abfd, aux->sec)
                && vma < (bfd_get_section_vma (aux->abfd, aux->sec)
-                         + bfd_get_section_size_before_reloc (aux->sec)))))
+                         + bfd_section_size (aux->abfd, aux->sec)))))
       {
        for (i = thisplace + 1; i < sorted_symcount; i++)
          {
@@ -460,7 +537,11 @@ objdump_print_address (vma, info)
        --i;
        for (; i >= 0; i--)
          {
-           if (sorted_syms[i]->section == aux->sec)
+           if (sorted_syms[i]->section == aux->sec
+               && (i == 0
+                   || sorted_syms[i - 1]->section != aux->sec
+                   || (bfd_asymbol_value (sorted_syms[i])
+                       != bfd_asymbol_value (sorted_syms[i - 1]))))
              {
                thisplace = i;
                break;
@@ -480,25 +561,47 @@ objdump_print_address (vma, info)
                  }
              }
          }
+
+       if (sorted_syms[thisplace]->section != aux->sec
+           && (aux->require_sec
+               || ((aux->abfd->flags & HAS_RELOC) != 0
+                   && vma >= bfd_get_section_vma (aux->abfd, aux->sec)
+                   && vma < (bfd_get_section_vma (aux->abfd, aux->sec)
+                             + bfd_section_size (aux->abfd, aux->sec)))))
+         {
+           bfd_vma secaddr;
+
+           fprintf (info->stream, " <%s",
+                    bfd_get_section_name (aux->abfd, aux->sec));
+           secaddr = bfd_get_section_vma (aux->abfd, aux->sec);
+           if (vma < secaddr)
+             {
+               fprintf (info->stream, "-");
+               objdump_print_value (secaddr - vma, info->stream);
+             }
+           else if (vma > secaddr)
+             {
+               fprintf (info->stream, "+");
+               objdump_print_value (vma - secaddr, info->stream);
+             }
+           fprintf (info->stream, ">");
+           return;
+         }
       }
   }
 
   fprintf (info->stream, " <%s", sorted_syms[thisplace]->name);
   if (bfd_asymbol_value (sorted_syms[thisplace]) > vma)
     {
-      char buf[30], *p = buf;
-      sprintf_vma (buf, bfd_asymbol_value (sorted_syms[thisplace]) - vma);
-      while (*p == '0')
-       p++;
-      fprintf (info->stream, "-%s", p);
+      fprintf (info->stream, "-");
+      objdump_print_value (bfd_asymbol_value (sorted_syms[thisplace]) - vma,
+                          info->stream);
     }
   else if (vma > bfd_asymbol_value (sorted_syms[thisplace]))
     {
-      char buf[30], *p = buf;
-      sprintf_vma (buf, vma - bfd_asymbol_value (sorted_syms[thisplace]));
-      while (*p == '0')
-       p++;
-      fprintf (info->stream, "+%s", p);
+      fprintf (info->stream, "+");
+      objdump_print_value (vma - bfd_asymbol_value (sorted_syms[thisplace]),
+                          info->stream);
     }
   fprintf (info->stream, ">");
 }
@@ -707,7 +810,6 @@ disassemble_data (abfd)
      bfd *abfd;
 {
   long i;
-  unsigned int (*print) () = 0; /* Old style */
   disassembler_ftype disassemble_fn = 0; /* New style */
   struct disassemble_info disasm_info;
   struct objdump_disasm_info aux;
@@ -735,7 +837,7 @@ disassemble_data (abfd)
 
   if (machine != (char *) NULL)
     {
-      bfd_arch_info_type *info = bfd_scan_arch (machine);
+      const bfd_arch_info_type *info = bfd_scan_arch (machine);
       if (info == NULL)
        {
          fprintf (stderr, "%s: Can't use supplied machine %s\n",
@@ -746,22 +848,13 @@ disassemble_data (abfd)
       abfd->arch_info = info;
     }
 
-  /* See if we can disassemble using bfd.  */
-
-  if (abfd->arch_info->disassemble)
+  disassemble_fn = disassembler (abfd);
+  if (!disassemble_fn)
     {
-      print = abfd->arch_info->disassemble;
-    }
-  else
-    {
-      disassemble_fn = disassembler (abfd);
-      if (!disassemble_fn)
-       {
-         fprintf (stderr, "%s: Can't disassemble for architecture %s\n",
-                  program_name,
-                  bfd_printable_arch_mach (bfd_get_arch (abfd), 0));
-         exit (1);
-       }
+      fprintf (stderr, "%s: Can't disassemble for architecture %s\n",
+              program_name,
+              bfd_printable_arch_mach (bfd_get_arch (abfd), 0));
+      exit (1);
     }
 
   for (section = abfd->sections;
@@ -773,6 +866,7 @@ disassemble_data (abfd)
       arelent **relbuf = NULL;
       arelent **relpp = NULL;
       arelent **relppend = NULL;
+      long stop;
 
       if ((section->flags & SEC_LOAD) == 0
          || (! disassemble_all
@@ -822,8 +916,23 @@ disassemble_data (abfd)
       disasm_info.buffer = data;
       disasm_info.buffer_vma = section->vma;
       disasm_info.buffer_length = datasize;
-      i = 0;
-      while (i < disasm_info.buffer_length)
+      if (start_address == (bfd_vma) -1
+         || start_address < disasm_info.buffer_vma)
+       i = 0;
+      else
+       i = start_address - disasm_info.buffer_vma;
+      if (stop_address == (bfd_vma) -1)
+       stop = datasize;
+      else
+       {
+         if (stop_address < disasm_info.buffer_vma)
+           stop = 0;
+         else
+           stop = stop_address - disasm_info.buffer_vma;
+         if (stop > disasm_info.buffer_length)
+           stop = disasm_info.buffer_length;
+       }
+      while (i < stop)
        {
          int bytes;
          boolean need_nl = false;
@@ -848,18 +957,10 @@ disassemble_data (abfd)
              aux.require_sec = false;
              putchar (' ');
 
-             if (disassemble_fn)
-               {
-                 /* New style */
-                 bytes = (*disassemble_fn) (section->vma + i, &disasm_info);
-                 if (bytes < 0)
-                   break;
-               }
-             else
-               {
-                 /* Old style */
-                 bytes = print (section->vma + i, data + i, stdout);
-               }
+             bytes = (*disassemble_fn) (section->vma + i, &disasm_info);
+             if (bytes < 0)
+               break;
+
              if (!wide_output)
                putchar ('\n');
              else
@@ -923,6 +1024,7 @@ disassemble_data (abfd)
       if (relbuf != NULL)
        free (relbuf);
     }
+  free (sorted_syms);
 }
 \f
 
@@ -1219,6 +1321,16 @@ display_bfd (abfd)
     dump_data (abfd);
   if (disassemble)
     disassemble_data (abfd);
+  if (syms)
+    {
+      free (syms);
+      syms = NULL;
+    }
+  if (dynsyms)
+    {
+      free (dynsyms);
+      dynsyms = NULL;
+    }
 }
 
 static void
@@ -1280,6 +1392,7 @@ dump_data (abfd)
   bfd_byte *data = 0;
   bfd_size_type datasize = 0;
   bfd_size_type i;
+  bfd_size_type start, stop;
 
   for (section = abfd->sections; section != NULL; section =
        section->next)
@@ -1301,14 +1414,30 @@ dump_data (abfd)
 
              bfd_get_section_contents (abfd, section, (PTR) data, 0, bfd_section_size (abfd, section));
 
-             for (i = 0; i < bfd_section_size (abfd, section); i += onaline)
+             if (start_address == (bfd_vma) -1
+                 || start_address < section->vma)
+               start = 0;
+             else
+               start = start_address - section->vma;
+             if (stop_address == (bfd_vma) -1)
+               stop = bfd_section_size (abfd, section);
+             else
+               {
+                 if (stop_address < section->vma)
+                   stop = 0;
+                 else
+                   stop = stop_address - section->vma;
+                 if (stop > bfd_section_size (abfd, section))
+                   stop = bfd_section_size (abfd, section);
+               }
+             for (i = start; i < stop; i += onaline)
                {
                  bfd_size_type j;
 
                  printf (" %04lx ", (unsigned long int) (i + section->vma));
                  for (j = i; j < i + onaline; j++)
                    {
-                     if (j < bfd_section_size (abfd, section))
+                     if (j < stop)
                        printf ("%02x", (unsigned) (data[j]));
                      else
                        printf ("  ");
@@ -1319,7 +1448,7 @@ dump_data (abfd)
                  printf (" ");
                  for (j = i; j < i + onaline; j++)
                    {
-                     if (j >= bfd_section_size (abfd, section))
+                     if (j >= stop)
                        printf (" ");
                      else
                        printf ("%c", isprint (data[j]) ? data[j] : '.');
@@ -1405,12 +1534,12 @@ dump_relocs (abfd)
       else if ((a->flags & SEC_RELOC) == 0)
        continue;
 
-      printf ("RELOCATION RECORDS FOR [%s]:", a->name);
-
       relsize = bfd_get_reloc_upper_bound (abfd, a);
       if (relsize < 0)
        bfd_fatal (bfd_get_filename (abfd));
 
+      printf ("RELOCATION RECORDS FOR [%s]:", a->name);
+
       if (relsize == 0)
        {
          printf (" (none)\n\n");
@@ -1444,12 +1573,12 @@ dump_dynamic_relocs (abfd)
   arelent **relpp;
   long relcount;
 
-  printf ("DYNAMIC RELOCATION RECORDS");
-
   relsize = bfd_get_dynamic_reloc_upper_bound (abfd);
   if (relsize < 0)
     bfd_fatal (bfd_get_filename (abfd));
 
+  printf ("DYNAMIC RELOCATION RECORDS");
+
   if (relsize == 0)
     {
       printf (" (none)\n\n");
@@ -1500,6 +1629,13 @@ dump_reloc_set (abfd, relpp, relcount)
       CONST char *sym_name;
       CONST char *section_name;
 
+      if (start_address != (bfd_vma) -1
+         && q->address < start_address)
+       continue;
+      if (stop_address != (bfd_vma) -1
+         && q->address > stop_address)
+       continue;
+
       if (q->sym_ptr_ptr && *q->sym_ptr_ptr)
        {
          sym_name = (*(q->sym_ptr_ptr))->name;
@@ -1723,7 +1859,8 @@ main (argc, argv)
                           (int *) 0))
         != EOF)
     {
-      seenflag = true;
+      if (c != 'l' && c != OPTION_START_ADDRESS && c != OPTION_STOP_ADDRESS)
+       seenflag = true;
       switch (c)
        {
        case 0:
@@ -1796,6 +1933,12 @@ main (argc, argv)
        case 'w':
          wide_output = 1;
          break;
+       case OPTION_START_ADDRESS:
+         start_address = parse_vma (optarg, "--start-address");
+         break;
+       case OPTION_STOP_ADDRESS:
+         stop_address = parse_vma (optarg, "--stop-address");
+         break;
        default:
          usage (stderr, 1);
        }